From 1bd6d39b39dd527ad095510173e9012afaafd3b0 Mon Sep 17 00:00:00 2001 From: "John Molakvoæ (skjnldsv)" Date: Mon, 29 Oct 2018 13:58:14 +0100 Subject: Migrate link shares to array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: John Molakvoæ (skjnldsv) --- core/js/share/sharedialoglinkshareview.handlebars | 27 +- ...haredialoglinkshareview_popover_menu.handlebars | 17 +- core/js/share/sharedialogshareelistview.handlebars | 2 +- core/js/sharedialoglinkshareview.js | 421 ++++++++++++++------- core/js/shareitemmodel.js | 59 ++- core/js/sharetemplates.js | 57 +-- 6 files changed, 366 insertions(+), 217 deletions(-) (limited to 'core/js') diff --git a/core/js/share/sharedialoglinkshareview.handlebars b/core/js/share/sharedialoglinkshareview.handlebars index bc7051683a2..a8a6e795839 100644 --- a/core/js/share/sharedialoglinkshareview.handlebars +++ b/core/js/share/sharedialoglinkshareview.handlebars @@ -1,14 +1,19 @@ {{#if shareAllowed}} {{else}} {{#if noSharingPlaceholder}}{{/if}} diff --git a/core/js/share/sharedialoglinkshareview_popover_menu.handlebars b/core/js/share/sharedialoglinkshareview_popover_menu.handlebars index baee3aa6630..6f504811be4 100644 --- a/core/js/share/sharedialoglinkshareview_popover_menu.handlebars +++ b/core/js/share/sharedialoglinkshareview_popover_menu.handlebars @@ -6,6 +6,13 @@ {{copyLabel}} +
  • + + + + {{newShareTitle}} + +
  • + {{#if hasExpireDate}}checked="checked"{{/if}} {{#if isExpirationEnforced}}disabled="disabled"{{/if}} />
  • - +
  • @@ -88,7 +96,7 @@
  • - {{/each}} +
  • + {{unshareLabel}} +
  • diff --git a/core/js/share/sharedialogshareelistview.handlebars b/core/js/share/sharedialogshareelistview.handlebars index a95949c8157..dc2496daaa8 100644 --- a/core/js/share/sharedialogshareelistview.handlebars +++ b/core/js/share/sharedialogshareelistview.handlebars @@ -15,7 +15,7 @@ - {{/each}} + {{/each}} {{#each linkReshares}}
  • diff --git a/core/js/sharedialoglinkshareview.js b/core/js/sharedialoglinkshareview.js index 7603b058a96..6e3fce04dfe 100644 --- a/core/js/sharedialoglinkshareview.js +++ b/core/js/sharedialoglinkshareview.js @@ -43,8 +43,6 @@ showPending: false, events: { - // enable/disable - 'change .linkCheckbox': 'onLinkCheckBoxChange', // open menu 'click .share-menu .icon-more': 'onToggleMenu', // hide download @@ -67,7 +65,11 @@ // note 'click .share-add': 'showNoteForm', 'click .share-note-delete': 'deleteNote', - 'click .share-note-submit': 'updateNote' + 'click .share-note-submit': 'updateNote', + // remove + 'click .unshare': 'onUnshare', + // new share + 'click .new-share': 'newShare', }, initialize: function(options) { @@ -89,10 +91,6 @@ view.render(); }); - this.model.on('change:linkShare', function() { - view.render(); - }); - if(!_.isUndefined(options.configModel)) { this.configModel = options.configModel; } else { @@ -102,7 +100,6 @@ var clipboard = new Clipboard('.clipboardButton'); clipboard.on('success', function(e) { var $menu = $(e.trigger); - var $linkTextMenu = $menu.parent().next('li.linkTextMenu') $menu.tooltip('hide') .attr('data-original-title', t('core', 'Copied!')) @@ -143,46 +140,44 @@ }); }, - onLinkCheckBoxChange: function() { - var $checkBox = this.$el.find('.linkCheckbox'); - var $loading = $checkBox.siblings('.icon-loading-small'); + newShare: function() { + var self = this; + var $loading = this.$el.find('.icon-loading-small').eq(0); if(!$loading.hasClass('hidden')) { + // in process return false; } - - if($checkBox.is(':checked')) { - if(this.configModel.get('enforcePasswordForPublicLink') === false) { - $loading.removeClass('hidden'); - // this will create it - this.model.saveLinkShare(); - $('.share-menu .icon-more').click(); - $('.share-menu .icon-more + .popovermenu .clipboardButton').click(); - } else { - // force the rendering of the menu - this.showPending = true; - this.render() - $('.share-menu .icon-more').click(); - $('.share-menu .icon-more + .popovermenu input:eq(1)').focus() - } - } else { - if (this.model.get('linkShare').isLinkShare) { - $loading.removeClass('hidden'); - this.model.removeLinkShare(); - } else { - this.showPending = false; - this.render() + // hide all icons and show loading + this.$el.find('.icon').addClass('hidden'); + $loading.removeClass('hidden'); + + this.model.saveLinkShare({}, { + success: function() { + $loading.addClass('hidden'); + self.$el.find('.icon').removeClass('hidden'); + self.render(); + }, + error: function(obj, msg) { + OC.Notification.showTemporary(t('core', 'Unable to create a link share')); + $loading.addClass('hidden'); + self.$el.find('.icon').removeClass('hidden'); } - } + }) }, - onLinkTextClick: function() { - var $el = this.$el.find('.linkText'); + onLinkTextClick: function(event) { + var $element = $(event.target); + var $li = $element.closest('li[data-share-id]'); + var $el = $li.find('.linkText'); $el.focus(); $el.select(); }, - onHideDownloadChange: function() { - var $checkbox = this.$('.hideDownloadCheckbox'); + onHideDownloadChange: function(event) { + var $element = $(event.target); + var $li = $element.closest('li[data-share-id]'); + var shareId = $li.data('share-id'); + var $checkbox = $li.find('.hideDownloadCheckbox'); $checkbox.siblings('.icon-loading-small').removeClass('hidden').addClass('inlineblock'); var hideDownload = false; @@ -191,41 +186,57 @@ } this.model.saveLinkShare({ - hideDownload: hideDownload + hideDownload: hideDownload, + cid: shareId + }, { + success: function() { + $checkbox.siblings('.icon-loading-small').addClass('hidden').removeClass('inlineblock'); + }, + error: function(obj, msg) { + OC.Notification.showTemporary(t('core', 'Unable to toggle this option')); + $checkbox.siblings('.icon-loading-small').addClass('hidden').removeClass('inlineblock'); + } }); }, - onShowPasswordClick: function() { - this.$el.find('.linkPass').slideToggle(OC.menuSpeed); - this.$el.find('.linkPassMenu').toggleClass('hidden'); - if(!this.$el.find('.showPasswordCheckbox').is(':checked')) { + onShowPasswordClick: function(event) { + var $element = $(event.target); + var $li = $element.closest('li[data-share-id]'); + var shareId = $li.data('share-id'); + $li.find('.linkPass').slideToggle(OC.menuSpeed); + $li.find('.linkPassMenu').toggleClass('hidden'); + if(!$li.find('.showPasswordCheckbox').is(':checked')) { this.model.saveLinkShare({ - password: '' + password: '', + cid: shareId }); } else { if (!OC.Util.isIE()) { - this.$el.find('.linkPassText').focus(); + $li.find('.linkPassText').focus(); } } }, onPasswordKeyUp: function(event) { if(event.keyCode === 13) { - this.onPasswordEntered(); + this.onPasswordEntered(event); } }, - onPasswordEntered: function() { - var $loading = this.$el.find('.linkPassMenu .icon-loading-small'); + onPasswordEntered: function(event) { + var $element = $(event.target); + var $li = $element.closest('li[data-share-id]'); + var shareId = $li.data('share-id'); + var $loading = $li.find('.linkPassMenu .icon-loading-small'); if (!$loading.hasClass('hidden')) { // still in process return; } - var $input = this.$el.find('.linkPassText'); + var $input = $li.find('.linkPassText'); $input.removeClass('error'); var password = $input.val(); - if (this.$el.find('.linkPassText').attr('placeholder') === PASSWORD_PLACEHOLDER_MESSAGE_OPTIONAL) { + if ($li.find('.linkPassText').attr('placeholder') === PASSWORD_PLACEHOLDER_MESSAGE_OPTIONAL) { // in IE9 the password might be the placeholder due to bugs in the placeholders polyfill if(password === PASSWORD_PLACEHOLDER_MESSAGE_OPTIONAL) { @@ -244,7 +255,8 @@ .addClass('inlineblock'); this.model.saveLinkShare({ - password: password + password: password, + cid: shareId }, { complete: function(model) { $loading.removeClass('inlineblock').addClass('hidden'); @@ -260,8 +272,11 @@ }); }, - onAllowPublicEditingChange: function() { - var $checkbox = this.$('.publicEditingCheckbox'); + onAllowPublicEditingChange: function(event) { + var $element = $(event.target); + var $li = $element.closest('li[data-share-id]'); + var shareId = $li.data('share-id'); + var $checkbox = $li.find('.publicEditingCheckbox'); $checkbox.siblings('.icon-loading-small').removeClass('hidden').addClass('inlineblock'); var permissions = OC.PERMISSION_READ; @@ -270,15 +285,28 @@ } this.model.saveLinkShare({ - permissions: permissions + permissions: permissions, + cid: shareId + }, { + success: function() { + $checkbox.siblings('.icon-loading-small').addClass('hidden').removeClass('inlineblock'); + }, + error: function(obj, msg) { + OC.Notification.showTemporary(t('core', 'Unable to toggle this option')); + $checkbox.siblings('.icon-loading-small').addClass('hidden').removeClass('inlineblock'); + } }); }, - onPublicUploadChange: function(e) { - var permissions = e.currentTarget.value; + onPublicUploadChange: function(event) { + var $element = $(event.target); + var $li = $element.closest('li[data-share-id]'); + var shareId = $li.data('share-id'); + var permissions = event.currentTarget.value; this.model.saveLinkShare({ - permissions: permissions + permissions: permissions, + cid: shareId }); }, @@ -386,46 +414,21 @@ && this.model.createPermissionPossible() && this.configModel.isPublicUploadEnabled(); - var publicUploadRWChecked = ''; - var publicUploadRChecked = ''; - var publicUploadWChecked = ''; - - switch (this.model.linkSharePermissions()) { - case OC.PERMISSION_READ: - publicUploadRChecked = 'checked'; - break; - case OC.PERMISSION_CREATE: - publicUploadWChecked = 'checked'; - break; - case OC.PERMISSION_UPDATE | OC.PERMISSION_CREATE | OC.PERMISSION_READ | OC.PERMISSION_DELETE: - publicUploadRWChecked = 'checked'; - break; - } var publicEditingChecked = ''; if(this.model.isPublicEditingAllowed()) { publicEditingChecked = 'checked="checked"'; } - var isLinkShare = this.model.get('linkShare').isLinkShare; - var isPasswordSet = !!this.model.get('linkShare').password; var isPasswordEnforced = this.configModel.get('enforcePasswordForPublicLink'); var isPasswordEnabledByDefault = this.configModel.get('enableLinkPasswordByDefault') === true; - var showPasswordCheckBox = isLinkShare - && ( !this.configModel.get('enforcePasswordForPublicLink') - || !this.model.get('linkShare').password); var passwordPlaceholderInitial = this.configModel.get('enforcePasswordForPublicLink') ? PASSWORD_PLACEHOLDER_MESSAGE : PASSWORD_PLACEHOLDER_MESSAGE_OPTIONAL; - var showHideDownloadCheckbox = !this.model.isFolder(); - var hideDownload = this.model.get('linkShare').hideDownload; - var publicEditable = !this.model.isFolder() - && isLinkShare && this.model.updatePermissionPossible(); - var link = this.model.get('linkShare').link; var social = []; OC.Share.Social.Collection.each(function(model) { var url = model.get('url'); @@ -439,60 +442,28 @@ newWindow: model.get('newWindow') }); }); - - var defaultExpireDays = this.configModel.get('defaultExpireDate'); var isExpirationEnforced = this.configModel.get('isDefaultExpireDateEnforced'); - var hasExpireDate = !!this.model.get('linkShare').expiration || isExpirationEnforced; - - var expireDate; - if (hasExpireDate) { - expireDate = moment(this.model.get('linkShare').expiration, 'YYYY-MM-DD').format('DD-MM-YYYY'); - } - + // what if there is another date picker on that page? var minDate = new Date(); - var maxDate = null; // min date should always be the next day minDate.setDate(minDate.getDate()+1); - if(hasExpireDate) { - if(isExpirationEnforced) { - // TODO: hack: backend returns string instead of integer - var shareTime = this.model.get('linkShare').stime; - if (_.isNumber(shareTime)) { - shareTime = new Date(shareTime * 1000); - } - if (!shareTime) { - shareTime = new Date(); // now - } - shareTime = OC.Util.stripTime(shareTime).getTime(); - maxDate = new Date(shareTime + defaultExpireDays * 24 * 3600 * 1000); - } - } $.datepicker.setDefaults({ - minDate: minDate, - maxDate: maxDate + minDate: minDate }); this.$el.find('.datepicker').datepicker({dateFormat : 'dd-mm-yy'}); - var popover = this.popoverMenuTemplate({ - cid: this.model.get('linkShare').id, + var popoverBase = { copyLabel: t('core', 'Copy link'), social: social, - - shareLinkURL: this.model.get('linkShare').link, urlLabel: t('core', 'Link'), - showHideDownloadCheckbox: showHideDownloadCheckbox, - hideDownload: hideDownload, hideDownloadLabel: t('core', 'Hide download'), enablePasswordLabel: t('core', 'Password protect'), passwordLabel: t('core', 'Password'), - passwordPlaceholder: isPasswordSet ? PASSWORD_PLACEHOLDER : PASSWORD_PLACEHOLDER_MESSAGE, passwordPlaceholderInitial: passwordPlaceholderInitial, - isPasswordSet: isPasswordSet || isPasswordEnabledByDefault || isPasswordEnforced, - showPasswordCheckBox: showPasswordCheckBox, - publicUpload: publicUpload && isLinkShare, + publicUpload: publicUpload, publicEditing: publicEditable, publicEditingChecked: publicEditingChecked, publicEditingLabel: t('core', 'Allow editing'), @@ -504,41 +475,40 @@ publicUploadRWValue: OC.PERMISSION_UPDATE | OC.PERMISSION_CREATE | OC.PERMISSION_READ | OC.PERMISSION_DELETE, publicUploadRValue: OC.PERMISSION_READ, publicUploadWValue: OC.PERMISSION_CREATE, - publicUploadRWChecked: publicUploadRWChecked, - publicUploadRChecked: publicUploadRChecked, - publicUploadWChecked: publicUploadWChecked, expireDateLabel: t('core', 'Set expiration date'), expirationLabel: t('core', 'Expiration'), expirationDatePlaceholder: t('core', 'Expiration date'), - hasExpireDate: hasExpireDate, isExpirationEnforced: isExpirationEnforced, isPasswordEnforced: isPasswordEnforced, - expireDate: expireDate, defaultExpireDate: moment().add(1, 'day').format('DD-MM-YYYY'), // Can't expire today - shareNote: this.model.get('linkShare').note, addNoteLabel: t('core', 'Note to recipient'), - }); + unshareLabel: t('core', 'Unshare'), + newShareLabel: t('core', 'New share link'), + }; - var pendingPopover = this.pendingPopoverMenuTemplate({ - cid: this.model.get('linkShare').id, + var pendingPopoverBase = { enablePasswordLabel: t('core', 'Password protect'), passwordLabel: t('core', 'Password'), - passwordPlaceholder: isPasswordSet ? PASSWORD_PLACEHOLDER : PASSWORD_PLACEHOLDER_MESSAGE, passwordPlaceholderInitial: passwordPlaceholderInitial, - showPasswordCheckBox: showPasswordCheckBox, isPasswordEnforced: isPasswordEnforced, - }); + }; + + var linkShares = this.getShareeList(); + if(_.isArray(linkShares)) { + for (var i = 0; i < linkShares.length; i++) { + var popover = this.getPopoverObject(linkShares[i]) + var pendingPopover = this.getPendingPopoverObject(linkShares[i]) + linkShares[i].popoverMenu = this.popoverMenuTemplate(_.extend({}, popoverBase, popover)); + linkShares[i].pendingPopoverMenu = this.pendingPopoverMenuTemplate(_.extend({}, pendingPopoverBase, pendingPopover)); + } + } this.$el.html(linkShareTemplate({ - cid: this.model.get('linkShare').id, + linkShares: linkShares, shareAllowed: true, - isLinkShare: isLinkShare, - linkShareLabel: t('core', 'Share link'), - linkShareEnableLabel: t('core', 'Enable'), - popoverMenu: popover, - pendingPopoverMenu: pendingPopover, - showMenu: isLinkShare || this.showPending, - showPending: this.showPending && !isLinkShare + nolinkShares: linkShares.length === 0, + newShareLabel: t('core', 'Share link'), + newShareTitle: t('core', 'New share link'), })); this.delegateEvents(); @@ -555,9 +525,10 @@ var $element = $(event.target); var $li = $element.closest('li[data-share-id]'); var $menu = $li.find('.sharingOptionsGroup .popovermenu'); + var shareId = $li.data('share-id'); OC.showMenu(null, $menu); - this._menuOpen = $li.data('share-id'); + this._menuOpen = shareId; }, /** @@ -635,24 +606,188 @@ var $element = $(event.target); var li = $element.closest('li[data-share-id]'); var shareId = li.data('share-id'); + var maxDate = $element.data('max-date'); var expirationDatePicker = '#expirationDatePicker-' + shareId; var self = this; $(expirationDatePicker).datepicker({ dateFormat : 'dd-mm-yy', onSelect: function (expireDate) { - self.setExpirationDate(expireDate); - } + self.setExpirationDate(expireDate, shareId); + }, + maxDate: maxDate }); $(expirationDatePicker).datepicker('show'); $(expirationDatePicker).focus(); }, - setExpirationDate: function(expireDate) { - this.model.saveLinkShare({expireDate: expireDate}); + setExpirationDate: function(expireDate, shareId) { + this.model.saveLinkShare({expireDate: expireDate, cid: shareId}); }, + /** + * get an array of sharees' share properties + * + * @returns {Array} + */ + getShareeList: function() { + var shares = this.model.get('linkShares'); + + if(!this.model.hasLinkShares()) { + return []; + } + + var list = []; + for(var index = 0; index < shares.length; index++) { + var share = this.getShareeObject(index); + // first empty {} is necessary, otherwise we get in trouble + // with references + list.push(_.extend({}, share)); + } + + return list; + }, + + /** + * + * @param {OC.Share.Types.ShareInfo} shareInfo + * @returns {object} + */ + getShareeObject: function(shareIndex) { + var share = this.model.get('linkShares')[shareIndex]; + + return _.extend({}, share, { + cid: share.id, + shareAllowed: true, + linkShareLabel: share.label !== '' ? share.label : t('core', 'Share link'), + popoverMenu: {}, + pendingPopoverMenu: {}, + showPending: this.showPending + }) + }, + + getPopoverObject: function(share) { + var publicUploadRWChecked = ''; + var publicUploadRChecked = ''; + var publicUploadWChecked = ''; + + switch (this.model.linkSharePermissions(share.id)) { + case OC.PERMISSION_READ: + publicUploadRChecked = 'checked'; + break; + case OC.PERMISSION_CREATE: + publicUploadWChecked = 'checked'; + break; + case OC.PERMISSION_UPDATE | OC.PERMISSION_CREATE | OC.PERMISSION_READ | OC.PERMISSION_DELETE: + publicUploadRWChecked = 'checked'; + break; + } + + var isPasswordSet = !!share.password; + var isPasswordEnabledByDefault = this.configModel.get('enableLinkPasswordByDefault') === true; + var isPasswordEnforced = this.configModel.get('enforcePasswordForPublicLink'); + var showPasswordCheckBox = !this.configModel.get('enforcePasswordForPublicLink') || !share.password; + var isExpirationEnforced = this.configModel.get('isDefaultExpireDateEnforced'); + var defaultExpireDays = this.configModel.get('defaultExpireDate'); + var hasExpireDate = !!share.expiration || isExpirationEnforced; + var hasExpireDate = false; + + var expireDate; + if (hasExpireDate) { + expireDate = moment(share.expiration, 'YYYY-MM-DD').format('DD-MM-YYYY'); + } + + var showHideDownloadCheckbox = !this.model.isFolder(); + var hideDownload = share.hideDownload; + + var maxDate = null; + + if(hasExpireDate) { + if(isExpirationEnforced) { + // TODO: hack: backend returns string instead of integer + var shareTime = share.stime; + if (_.isNumber(shareTime)) { + shareTime = new Date(shareTime * 1000); + } + if (!shareTime) { + shareTime = new Date(); // now + } + shareTime = OC.Util.stripTime(shareTime).getTime(); + maxDate = new Date(shareTime + defaultExpireDays * 24 * 3600 * 1000); + } + } + + return { + cid: share.id, + shareLinkURL: share.url, + passwordPlaceholder: isPasswordSet ? PASSWORD_PLACEHOLDER : PASSWORD_PLACEHOLDER_MESSAGE, + isPasswordSet: isPasswordSet || isPasswordEnabledByDefault || isPasswordEnforced, + showPasswordCheckBox: showPasswordCheckBox, + publicUploadRWChecked: publicUploadRWChecked, + publicUploadRChecked: publicUploadRChecked, + publicUploadWChecked: publicUploadWChecked, + hasExpireDate: hasExpireDate, + expireDate: expireDate, + shareNote: share.note, + hasNote: share.note !== '', + maxDate: maxDate, + showHideDownloadCheckbox: showHideDownloadCheckbox, + hideDownload: hideDownload, + newShareTitle: t('core', 'New share link'), + } + }, + + getPendingPopoverObject: function(share) { + var isPasswordSet = !!share.password; + var showPasswordCheckBox = !this.configModel.get('enforcePasswordForPublicLink') || !share.password; + var isPasswordEnforced = this.configModel.get('enforcePasswordForPublicLink'); + + return { + cid: share.id, + enablePasswordLabel: t('core', 'Password protect'), + passwordLabel: t('core', 'Password'), + passwordPlaceholder: isPasswordSet ? PASSWORD_PLACEHOLDER : PASSWORD_PLACEHOLDER_MESSAGE, + showPasswordCheckBox: showPasswordCheckBox, + isPasswordEnforced: isPasswordEnforced, + } + + }, + + onUnshare: function(event) { + event.preventDefault(); + event.stopPropagation(); + var self = this; + var $element = $(event.target); + if (!$element.is('a')) { + $element = $element.closest('a'); + } + + var $loading = $element.find('.icon-loading-small').eq(0); + if(!$loading.hasClass('hidden')) { + // in process + return false; + } + $loading.removeClass('hidden'); + + var $li = $element.closest('li[data-share-id]'); + + var shareId = $li.data('share-id'); + + self.model.removeShare(shareId, { + success: function() { + $li.remove(); + self.render() + }, + error: function() { + $loading.addClass('hidden'); + OC.Notification.showTemporary(t('core', 'Could not unshare')); + } + }); + return false; + }, + + }); OC.Share.ShareDialogLinkShareView = ShareDialogLinkShareView; diff --git a/core/js/shareitemmodel.js b/core/js/shareitemmodel.js index 3f92a8591e5..ce7bc56ab8a 100644 --- a/core/js/shareitemmodel.js +++ b/core/js/shareitemmodel.js @@ -16,11 +16,9 @@ /** * @typedef {object} OC.Share.Types.LinkShareInfo - * @property {bool} isLinkShare * @property {string} token * @property {bool} hideDownload * @property {string|null} password - * @property {string} link * @property {number} permissions * @property {Date} expiration * @property {number} stime share time @@ -100,7 +98,7 @@ defaults: { allowPublicUploadStatus: false, permissions: 0, - linkShare: {} + linkShares: [] }, /** @@ -130,8 +128,11 @@ delete attributes.expiration; } - if (this.get('linkShare') && this.get('linkShare').isLinkShare) { - shareId = this.get('linkShare').id; + var linkShares = this.get('linkShares'); + var shareIndex = _.findIndex(linkShares, function(share) {return share.id === attributes.cid}) + + if (linkShares.length > 0 && shareIndex !== -1) { + shareId = linkShares[shareIndex].id; // note: update can only update a single value at a time call = this.updateShare(shareId, attributes, options); @@ -151,12 +152,6 @@ return call; }, - removeLinkShare: function() { - if (this.get('linkShare')) { - return this.removeShare(this.get('linkShare').id); - } - }, - addShare: function(attributes, options) { var shareType = attributes.shareType; attributes = _.extend({}, attributes); @@ -316,13 +311,13 @@ }, /** - * Returns whether this item has a link share + * Returns whether this item has link shares * * @return {bool} true if a link share exists, false otherwise */ - hasLinkShare: function() { - var linkShare = this.get('linkShare'); - if (linkShare && linkShare.isLinkShare) { + hasLinkShares: function() { + var linkShares = this.get('linkShares'); + if (linkShares && linkShares.length > 0) { return true; } return false; @@ -630,12 +625,16 @@ /** * @returns {int} */ - linkSharePermissions: function() { - if (!this.hasLinkShare()) { + linkSharePermissions: function(shareId) { + var linkShares = this.get('linkShares'); + var shareIndex = _.findIndex(linkShares, function(share) {return share.id === shareId}) + + if (!this.hasLinkShares()) { return -1; - } else { - return this.get('linkShare').permissions; + } else if (linkShares.length > 0 && shareIndex !== -1) { + return linkShares[shareIndex].permissions; } + return -1; }, _getUrl: function(base, params) { @@ -831,7 +830,7 @@ this._legacyFillCurrentShares(shares); - var linkShare = { isLinkShare: false }; + var linkShares = []; // filter out the share by link shares = _.reject(shares, /** @@ -844,7 +843,7 @@ || share.item_source === this.get('itemSource')); if (isShareLink) { - /* + /** * Ignore reshared link shares for now * FIXME: Find a way to display properly */ @@ -864,20 +863,12 @@ } else { link += OC.generateUrl('/s/') + share.token; } - linkShare = { - isLinkShare: true, - id: share.id, - token: share.token, + linkShares.push(_.extend({}, share, { // hide_download is returned as an int, so force it // to a boolean hideDownload: !!share.hide_download, - password: share.share_with, - link: link, - permissions: share.permissions, - // currently expiration is only effective for link shares. - expiration: share.expiration, - stime: share.stime - }; + password: share.share_with + })); return share; } @@ -888,7 +879,7 @@ return { reshare: data.reshare, shares: shares, - linkShare: linkShare, + linkShares: linkShares, permissions: permissions, allowPublicUploadStatus: allowPublicUploadStatus, allowPublicEditingStatus: allowPublicEditingStatus, @@ -924,7 +915,7 @@ getShareTypes: function() { var result; result = _.pluck(this.getSharesWithCurrentItem(), 'share_type'); - if (this.hasLinkShare()) { + if (this.hasLinkShares()) { result.push(OC.Share.SHARE_TYPE_LINK); } return _.uniq(result); diff --git a/core/js/sharetemplates.js b/core/js/sharetemplates.js index 0c1fee37455..dfda54a853e 100644 --- a/core/js/sharetemplates.js +++ b/core/js/sharetemplates.js @@ -1,33 +1,32 @@ (function() { var template = Handlebars.template, templates = OC.Share.Templates = OC.Share.Templates || {}; templates['sharedialoglinkshareview'] = template({"1":function(container,depth0,helpers,partials,data) { + var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {}); + + return "
      \n" + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.nolinkShares : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.linkShares : depth0),{"name":"each","hash":{},"fn":container.program(4, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + "
    \n"; +},"2":function(container,depth0,helpers,partials,data) { + var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; + + return "
  • \n
    \n " + + alias4(((helper = (helper = helpers.newShareLabel || (depth0 != null ? depth0.newShareLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"newShareLabel","hash":{},"data":data}) : helper))) + + "\n \n \n \n \n
  • \n"; +},"4":function(container,depth0,helpers,partials,data) { var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; - return "\n"; -},"2":function(container,depth0,helpers,partials,data) { - return "checked=\"checked\""; -},"4":function(container,depth0,helpers,partials,data) { - var stack1; - - return "
    \n" - + ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.showPending : depth0),{"name":"if","hash":{},"fn":container.program(5, data, 0),"inverse":container.program(7, data, 0),"data":data})) != null ? stack1 : "") - + "
    \n"; + + "\n \n
    \n" + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.showPending : depth0),{"name":"if","hash":{},"fn":container.program(5, data, 0),"inverse":container.program(7, data, 0),"data":data})) != null ? stack1 : "") + + "
    \n
    \n \n"; },"5":function(container,depth0,helpers,partials,data) { var stack1, helper; @@ -169,6 +168,8 @@ templates['sharedialoglinkshareview_popover_menu'] = template({"1":function(cont + alias4(((helper = (helper = helpers.shareLinkURL || (depth0 != null ? depth0.shareLinkURL : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"shareLinkURL","hash":{},"data":data}) : helper))) + "\">\n \n " + alias4(((helper = (helper = helpers.copyLabel || (depth0 != null ? depth0.copyLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"copyLabel","hash":{},"data":data}) : helper))) + + "\n \n \n
  • \n \n \n \n " + + alias4(((helper = (helper = helpers.newShareTitle || (depth0 != null ? depth0.newShareTitle : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"newShareTitle","hash":{},"data":data}) : helper))) + "\n \n
  • \n
  • \n \n \n \n
  • \n
  • \n \n \n \n " + alias4(((helper = (helper = helpers.addNoteLabel || (depth0 != null ? depth0.addNoteLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"addNoteLabel","hash":{},"data":data}) : helper))) - + "\n \n \n
  • \n
  • \n \n \n \n \n
  • \n" + ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.social : depth0),{"name":"each","hash":{},"fn":container.program(17, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") - + " \n\n"; + + "
  • \n " + + alias4(((helper = (helper = helpers.unshareLabel || (depth0 != null ? depth0.unshareLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"unshareLabel","hash":{},"data":data}) : helper))) + + "\n
  • \n \n\n"; },"useData":true}); templates['sharedialoglinkshareview_popover_menu_pending'] = template({"1":function(container,depth0,helpers,partials,data) { var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; -- cgit v1.2.3 From 106ed07d6ac306420d091b44ddc4427bd5cf228f Mon Sep 17 00:00:00 2001 From: "John Molakvoæ (skjnldsv)" Date: Wed, 31 Oct 2018 10:28:18 +0100 Subject: Copy link outside menu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: John Molakvoæ (skjnldsv) --- apps/files_sharing/css/sharetabview.scss | 7 ----- core/js/share/sharedialoglinkshareview.handlebars | 6 ++-- ...haredialoglinkshareview_popover_menu.handlebars | 16 ++++------ core/js/sharedialoglinkshareview.js | 34 +++++++++++++++------- core/js/sharetemplates.js | 22 +++++++------- 5 files changed, 43 insertions(+), 42 deletions(-) (limited to 'core/js') diff --git a/apps/files_sharing/css/sharetabview.scss b/apps/files_sharing/css/sharetabview.scss index 9611580baad..dd9dc70e239 100644 --- a/apps/files_sharing/css/sharetabview.scss +++ b/apps/files_sharing/css/sharetabview.scss @@ -51,7 +51,6 @@ top: 0px; } .shareWithConfirm, - .clipboardButton, .linkPass .icon-loading-small { position: absolute; right: 2px; @@ -74,12 +73,6 @@ .datepicker { margin-left: 35px; } - .clipboardButton { - position: relative; - top: initial; - right: initial; - padding: 0; - } .share-add { input.share-note-delete { display: none; diff --git a/core/js/share/sharedialoglinkshareview.handlebars b/core/js/share/sharedialoglinkshareview.handlebars index a8a6e795839..9b44596f7a3 100644 --- a/core/js/share/sharedialoglinkshareview.handlebars +++ b/core/js/share/sharedialoglinkshareview.handlebars @@ -5,7 +5,7 @@
    {{newShareLabel}} - + @@ -13,7 +13,9 @@ {{#each linkShares}}
  • {{linkShareLabel}} + +
  • \n
  • \n \n
    \n \n \n
    \n
    \n
  • \n"; + + "\" autocomplete=\"enforcedPassText\" minlength=\"" + + alias4(((helper = (helper = helpers.minPasswordLength || (depth0 != null ? depth0.minPasswordLength : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"minPasswordLength","hash":{},"data":data}) : helper))) + + "\" />\n \n \n \n \n"; },"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) { var stack1; -- cgit v1.2.3 From 876d6ec8e6b1e38215659fd606b7d7022bdb8460 Mon Sep 17 00:00:00 2001 From: "John Molakvoæ (skjnldsv)" Date: Thu, 1 Nov 2018 16:22:22 +0100 Subject: Fixed jsunit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: John Molakvoæ (skjnldsv) --- core/js/tests/specHelper.js | 2 + core/js/tests/specs/sharedialoglinkshareview.js | 46 +++++++++++----------- core/js/tests/specs/sharedialogshareelistview.js | 2 +- core/js/tests/specs/sharedialogviewSpec.js | 49 +++++++++++++----------- core/js/tests/specs/shareitemmodelSpec.js | 45 +++++++++++----------- 5 files changed, 75 insertions(+), 69 deletions(-) (limited to 'core/js') diff --git a/core/js/tests/specHelper.js b/core/js/tests/specHelper.js index f2fc2888448..45a0f04db00 100644 --- a/core/js/tests/specHelper.js +++ b/core/js/tests/specHelper.js @@ -103,6 +103,8 @@ window.oc_appconfig = { window.oc_defaults = { docPlaceholderUrl: 'https://docs.example.org/PLACEHOLDER' }; +window.oc_capabilities = { +} /* jshint camelcase: true */ diff --git a/core/js/tests/specs/sharedialoglinkshareview.js b/core/js/tests/specs/sharedialoglinkshareview.js index d8dec3968e3..f5fe8725c03 100644 --- a/core/js/tests/specs/sharedialoglinkshareview.js +++ b/core/js/tests/specs/sharedialoglinkshareview.js @@ -81,12 +81,12 @@ describe('OC.Share.ShareDialogLinkShareView', function () { // Needed to render the view configModel.isShareWithLinkAllowed.returns(true); - // Setting the share also triggers the rendering shareModel.set({ - linkShare: { - isLinkShare: true, - } + linkShares: [{ + id: 123 + }] }); + view.render(); $hideDownloadCheckbox = view.$el.find('.hideDownloadCheckbox'); $workingIcon = $hideDownloadCheckbox.prev('.icon-loading-small'); @@ -119,11 +119,12 @@ describe('OC.Share.ShareDialogLinkShareView', function () { it('checkbox is checked when the setting is enabled', function () { shareModel.set({ - linkShare: { - isLinkShare: true, + linkShares: [{ + id: 123, hideDownload: true - } + }] }); + view.render(); $hideDownloadCheckbox = view.$el.find('.hideDownloadCheckbox'); @@ -141,16 +142,17 @@ describe('OC.Share.ShareDialogLinkShareView', function () { $hideDownloadCheckbox.change(); expect($workingIcon.hasClass('hidden')).toBeFalsy(); - expect(shareModel.saveLinkShare.withArgs({ hideDownload: true }).calledOnce).toBeTruthy(); + expect(shareModel.saveLinkShare.withArgs({ hideDownload: true, cid: 123 }).calledOnce).toBeTruthy(); }); it('disables the setting if clicked when checked', function () { shareModel.set({ - linkShare: { - isLinkShare: true, + linkShares: [{ + id: 123, hideDownload: true - } + }] }); + view.render(); $hideDownloadCheckbox = view.$el.find('.hideDownloadCheckbox'); $workingIcon = $hideDownloadCheckbox.prev('.icon-loading-small'); @@ -161,7 +163,7 @@ describe('OC.Share.ShareDialogLinkShareView', function () { $hideDownloadCheckbox.change(); expect($workingIcon.hasClass('hidden')).toBeFalsy(); - expect(shareModel.saveLinkShare.withArgs({ hideDownload: false }).calledOnce).toBeTruthy(); + expect(shareModel.saveLinkShare.withArgs({ hideDownload: false, cid: 123 }).calledOnce).toBeTruthy(); }); }); @@ -176,13 +178,13 @@ describe('OC.Share.ShareDialogLinkShareView', function () { // Needed to render the view configModel.isShareWithLinkAllowed.returns(true); - // Setting the share also triggers the rendering shareModel.set({ - linkShare: { - isLinkShare: true, + linkShares: [{ + id: 123, password: 'password' - } + }] }); + view.render(); var $passwordDiv = view.$el.find('#linkPass'); $passwordText = view.$el.find('.linkPassText'); @@ -202,17 +204,17 @@ describe('OC.Share.ShareDialogLinkShareView', function () { }); it('shows the working icon when called', function () { - view.onPasswordEntered(); + view.onPasswordEntered({target: view.$el.find('.linkPassText')}); expect($workingIcon.hasClass('hidden')).toBeFalsy(); - expect(shareModel.saveLinkShare.withArgs({ password: 'myPassword' }).calledOnce).toBeTruthy(); + expect(shareModel.saveLinkShare.withArgs({ password: 'myPassword', cid: 123 }).calledOnce).toBeTruthy(); }); it('hides the working icon when saving the password succeeds', function () { - view.onPasswordEntered(); + view.onPasswordEntered({target: view.$el.find('.linkPassText')}); expect($workingIcon.hasClass('hidden')).toBeFalsy(); - expect(shareModel.saveLinkShare.withArgs({ password: 'myPassword' }).calledOnce).toBeTruthy(); + expect(shareModel.saveLinkShare.withArgs({ password: 'myPassword', cid: 123 }).calledOnce).toBeTruthy(); shareModel.saveLinkShare.yieldTo("complete", [shareModel]); @@ -220,10 +222,10 @@ describe('OC.Share.ShareDialogLinkShareView', function () { }); it('hides the working icon when saving the password fails', function () { - view.onPasswordEntered(); + view.onPasswordEntered({target: view.$el.find('.linkPassText')}); expect($workingIcon.hasClass('hidden')).toBeFalsy(); - expect(shareModel.saveLinkShare.withArgs({ password: 'myPassword' }).calledOnce).toBeTruthy(); + expect(shareModel.saveLinkShare.withArgs({ password: 'myPassword', cid: 123 }).calledOnce).toBeTruthy(); shareModel.saveLinkShare.yieldTo("complete", [shareModel]); shareModel.saveLinkShare.yieldTo("error", [shareModel, "The error message"]); diff --git a/core/js/tests/specs/sharedialogshareelistview.js b/core/js/tests/specs/sharedialogshareelistview.js index 8e34225d199..ce228deac0b 100644 --- a/core/js/tests/specs/sharedialogshareelistview.js +++ b/core/js/tests/specs/sharedialogshareelistview.js @@ -73,7 +73,7 @@ describe('OC.Share.ShareDialogShareeListView', function () { $('#testArea').append(listView.$el); shareModel.set({ - linkShare: {isLinkShare: false} + linkShares: [] }); oldCurrentUser = OC.currentUser; diff --git a/core/js/tests/specs/sharedialogviewSpec.js b/core/js/tests/specs/sharedialogviewSpec.js index efe50c415c8..8d5a2ae434d 100644 --- a/core/js/tests/specs/sharedialogviewSpec.js +++ b/core/js/tests/specs/sharedialogviewSpec.js @@ -89,7 +89,7 @@ describe('OC.Share.ShareDialogView', function() { // triggers rendering shareModel.set({ shares: [], - linkShare: {isLinkShare: false} + linkShares: [] }); autocompleteStub = sinon.stub($.fn, 'autocomplete').callsFake(function() { @@ -130,8 +130,10 @@ describe('OC.Share.ShareDialogView', function() { it('update password on focus out', function() { $('#allowShareWithLink').val('yes'); - dialog.model.set('linkShare', { - isLinkShare: true + dialog.model.set({ + linkShares: [{ + id: 123 + }] }); dialog.render(); @@ -143,20 +145,20 @@ describe('OC.Share.ShareDialogView', function() { expect(saveLinkShareStub.calledOnce).toEqual(true); expect(saveLinkShareStub.firstCall.args[0]).toEqual({ + cid: 123, password: 'foo' }); }); it('update password on enter', function() { $('#allowShareWithLink').val('yes'); - dialog.model.set('linkShare', { - isLinkShare: true + dialog.model.set({ + linkShares: [{ + id: 123 + }] }); dialog.render(); - // Toggle linkshare - dialog.$el.find('.linkCheckbox').click(); - // Enable password and enter password dialog.$el.find('[name=showPassword]').click(); dialog.$el.find('.linkPassText').focus(); @@ -165,47 +167,48 @@ describe('OC.Share.ShareDialogView', function() { expect(saveLinkShareStub.calledOnce).toEqual(true); expect(saveLinkShareStub.firstCall.args[0]).toEqual({ + cid: 123, password: 'foo' }); }); - it('shows share with link checkbox when allowed', function() { + it('shows add share with link button when allowed', function() { $('#allowShareWithLink').val('yes'); dialog.render(); - expect(dialog.$el.find('.linkCheckbox').length).toEqual(1); + expect(dialog.$el.find('.new-share').length).toEqual(1); }); - it('does not show share with link checkbox when not allowed', function() { + it('does not show add share with link button when not allowed', function() { $('#allowShareWithLink').val('no'); dialog.render(); - expect(dialog.$el.find('.linkCheckbox').length).toEqual(0); + expect(dialog.$el.find('.new-share').length).toEqual(0); expect(dialog.$el.find('.shareWithField').length).toEqual(1); }); it('shows populated link share when a link share exists', function() { // this is how the OC.Share class does it... var link = parent.location.protocol + '//' + location.host + - OC.generateUrl('/s/') + 'tehtoken'; - shareModel.set('linkShare', { - isLinkShare: true, - token: 'tehtoken', - link: link, - expiration: '', - permissions: OC.PERMISSION_READ, - stime: 1403884258, + OC.generateUrl('/s/') + 'thetoken'; + shareModel.set({ + linkShares: [{ + id: 123, + url: link + }] }); dialog.render(); - expect(dialog.$el.find('.linkCheckbox').prop('checked')).toEqual(true); + expect(dialog.$el.find('.share-menu .icon-more').length).toEqual(1); expect(dialog.$el.find('.linkText').val()).toEqual(link); }); it('autofocus link text when clicked', function() { $('#allowShareWithLink').val('yes'); - dialog.model.set('linkShare', { - isLinkShare: true + dialog.model.set({ + linkShares: [{ + id: 123 + }] }); dialog.render(); diff --git a/core/js/tests/specs/shareitemmodelSpec.js b/core/js/tests/specs/shareitemmodelSpec.js index a2eabbf4ae4..3b4dc5a960f 100644 --- a/core/js/tests/specs/shareitemmodelSpec.js +++ b/core/js/tests/specs/shareitemmodelSpec.js @@ -185,8 +185,9 @@ describe('OC.Share.ShareItemModel', function() { expect(shares[0].share_with).toEqual('user1'); expect(shares[0].share_with_displayname).toEqual('User One'); - var linkShare = model.get('linkShare'); - expect(linkShare.isLinkShare).toEqual(true); + var linkShares = model.get('linkShares'); + expect(linkShares.length).toEqual(1); + var linkShare = linkShares[0]; expect(linkShare.hideDownload).toEqual(true); // TODO: check more attributes @@ -268,8 +269,8 @@ describe('OC.Share.ShareItemModel', function() { // remaining share appears in this list expect(shares.length).toEqual(1); - var linkShare = model.get('linkShare'); - expect(linkShare.isLinkShare).toEqual(false); + var linkShares = model.get('linkShares'); + expect(linkShares.length).toEqual(0); }); it('parses correct link share when a nested link share exists along with parent one', function() { /* jshint camelcase: false */ @@ -321,8 +322,9 @@ describe('OC.Share.ShareItemModel', function() { // the parent share remains in the list expect(shares.length).toEqual(1); - var linkShare = model.get('linkShare'); - expect(linkShare.isLinkShare).toEqual(true); + var linkShares = model.get('linkShares'); + expect(linkShares.length).toEqual(1); + var linkShare = linkShares[0]; expect(linkShare.token).toEqual('tehtoken'); expect(linkShare.hideDownload).toEqual(false); @@ -575,9 +577,8 @@ describe('OC.Share.ShareItemModel', function() { it('creates a new share if no link share exists', function() { model.set({ - linkShare: { - isLinkShare: false - } + linkShares: [ + ] }); model.saveLinkShare(); @@ -600,9 +601,8 @@ describe('OC.Share.ShareItemModel', function() { defaultExpireDate: 7 }); model.set({ - linkShare: { - isLinkShare: false - } + linkShares: [ + ] }); model.saveLinkShare(); @@ -621,13 +621,13 @@ describe('OC.Share.ShareItemModel', function() { }); it('updates link share if it exists', function() { model.set({ - linkShare: { - isLinkShare: true, + linkShares: [{ id: 123 - } + }] }); model.saveLinkShare({ + cid: 123, password: 'test' }); @@ -635,20 +635,19 @@ describe('OC.Share.ShareItemModel', function() { expect(updateShareStub.calledOnce).toEqual(true); expect(updateShareStub.firstCall.args[0]).toEqual(123); expect(updateShareStub.firstCall.args[1]).toEqual({ + cid: 123, password: 'test' }); }); it('forwards error message on add', function() { var errorStub = sinon.stub(); model.set({ - linkShare: { - isLinkShare: false - } + linkShares: [ + ] }, { }); model.saveLinkShare({ - password: 'test' }, { error: errorStub }); @@ -661,14 +660,14 @@ describe('OC.Share.ShareItemModel', function() { it('forwards error message on update', function() { var errorStub = sinon.stub(); model.set({ - linkShare: { - isLinkShare: true, - id: '123' - } + linkShares: [{ + id: 123 + }] }, { }); model.saveLinkShare({ + cid: 123, password: 'test' }, { error: errorStub -- cgit v1.2.3