From 6dde7e1183f0f5210b9d6de1e36ea7e15e58348b Mon Sep 17 00:00:00 2001 From: Julius Härtl Date: Wed, 10 Oct 2018 14:58:58 +0200 Subject: Improve share select list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- core/js/sharedialogview.js | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'core/js') diff --git a/core/js/sharedialogview.js b/core/js/sharedialogview.js index 9c648357e61..c8d9822d256 100644 --- a/core/js/sharedialogview.js +++ b/core/js/sharedialogview.js @@ -442,19 +442,26 @@ autocompleteRenderItem: function(ul, item) { + var icon = 'icon-user'; var text = item.label; if (item.value.shareType === OC.Share.SHARE_TYPE_GROUP) { text = t('core', '{sharee} (group)', { sharee: text }, undefined, { escape: false }); + icon = 'icon-contacts-dark'; } else if (item.value.shareType === OC.Share.SHARE_TYPE_REMOTE) { text = t('core', '{sharee} (remote)', {sharee: text}, undefined, {escape: false}); + icon = 'icon-shared'; } else if (item.value.shareType === OC.Share.SHARE_TYPE_REMOTE_GROUP) { text = t('core', '{sharee} (remote group)', { sharee: text }, undefined, { escape: false }); + icon = 'icon-shared'; } else if (item.value.shareType === OC.Share.SHARE_TYPE_EMAIL) { text = t('core', '{sharee} (email)', { sharee: text }, undefined, { escape: false }); + icon = 'icon-mail'; } else if (item.value.shareType === OC.Share.SHARE_TYPE_CIRCLE) { text = t('core', '{sharee} ({type}, {owner})', {sharee: text, type: item.value.circleInfo, owner: item.value.circleOwner}, undefined, {escape: false}); + icon = 'icon-circle'; } else if (item.value.shareType === OC.Share.SHARE_TYPE_ROOM) { text = t('core', '{sharee} (conversation)', { sharee: text }, undefined, { escape: false }); + icon = 'icon-talk'; } var insert = $("\n"; },"useData":true}); templates['sharedialoglinkshareview_popover_menu_pending'] = template({"1":function(container,depth0,helpers,partials,data) { diff --git a/core/js/tests/specs/sharedialoglinkshareview.js b/core/js/tests/specs/sharedialoglinkshareview.js index 9d07dcb479d..d8dec3968e3 100644 --- a/core/js/tests/specs/sharedialoglinkshareview.js +++ b/core/js/tests/specs/sharedialoglinkshareview.js @@ -72,6 +72,100 @@ describe('OC.Share.ShareDialogLinkShareView', function () { configModel.isShareWithLinkAllowed.restore(); }); + describe('hide download', function () { + + var $hideDownloadCheckbox; + var $workingIcon; + + beforeEach(function () { + // Needed to render the view + configModel.isShareWithLinkAllowed.returns(true); + + // Setting the share also triggers the rendering + shareModel.set({ + linkShare: { + isLinkShare: true, + } + }); + + $hideDownloadCheckbox = view.$el.find('.hideDownloadCheckbox'); + $workingIcon = $hideDownloadCheckbox.prev('.icon-loading-small'); + + sinon.stub(shareModel, 'saveLinkShare'); + + expect($workingIcon.hasClass('hidden')).toBeTruthy(); + }); + + afterEach(function () { + shareModel.saveLinkShare.restore(); + }); + + it('is shown if the share is a file', function() { + expect($hideDownloadCheckbox.length).toBeTruthy(); + }); + + it('is not shown if the share is a folder', function() { + shareModel.fileInfoModel.set('mimetype', 'httpd/unix-directory'); + + // Setting the item type also triggers the rendering + shareModel.set({ + itemType: 'folder' + }); + + $hideDownloadCheckbox = view.$el.find('.hideDownloadCheckbox'); + + expect($hideDownloadCheckbox.length).toBeFalsy(); + }); + + it('checkbox is checked when the setting is enabled', function () { + shareModel.set({ + linkShare: { + isLinkShare: true, + hideDownload: true + } + }); + + $hideDownloadCheckbox = view.$el.find('.hideDownloadCheckbox'); + + expect($hideDownloadCheckbox.is(':checked')).toEqual(true); + }); + + it('checkbox is not checked when the setting is disabled', function () { + expect($hideDownloadCheckbox.is(':checked')).toEqual(false); + }); + + it('enables the setting if clicked when unchecked', function () { + // Simulate the click by checking the checkbox and then triggering + // the "change" event. + $hideDownloadCheckbox.prop('checked', true); + $hideDownloadCheckbox.change(); + + expect($workingIcon.hasClass('hidden')).toBeFalsy(); + expect(shareModel.saveLinkShare.withArgs({ hideDownload: true }).calledOnce).toBeTruthy(); + }); + + it('disables the setting if clicked when checked', function () { + shareModel.set({ + linkShare: { + isLinkShare: true, + hideDownload: true + } + }); + + $hideDownloadCheckbox = view.$el.find('.hideDownloadCheckbox'); + $workingIcon = $hideDownloadCheckbox.prev('.icon-loading-small'); + + // Simulate the click by unchecking the checkbox and then triggering + // the "change" event. + $hideDownloadCheckbox.prop('checked', false); + $hideDownloadCheckbox.change(); + + expect($workingIcon.hasClass('hidden')).toBeFalsy(); + expect(shareModel.saveLinkShare.withArgs({ hideDownload: false }).calledOnce).toBeTruthy(); + }); + + }); + describe('onPasswordEntered', function () { var $passwordText; diff --git a/core/js/tests/specs/shareitemmodelSpec.js b/core/js/tests/specs/shareitemmodelSpec.js index 2e89b2e3cda..a2eabbf4ae4 100644 --- a/core/js/tests/specs/shareitemmodelSpec.js +++ b/core/js/tests/specs/shareitemmodelSpec.js @@ -168,7 +168,8 @@ describe('OC.Share.ShareItemModel', function() { stime: 1403884258, storage: 1, token: 'tehtoken', - uid_owner: 'root' + uid_owner: 'root', + hide_download: 1 } ])); @@ -186,6 +187,7 @@ describe('OC.Share.ShareItemModel', function() { var linkShare = model.get('linkShare'); expect(linkShare.isLinkShare).toEqual(true); + expect(linkShare.hideDownload).toEqual(true); // TODO: check more attributes }); @@ -289,7 +291,8 @@ describe('OC.Share.ShareItemModel', function() { stime: 1403884258, storage: 1, token: 'tehtoken', - uid_owner: 'root' + uid_owner: 'root', + hide_download: 0 }, { displayname_owner: 'root', expiration: '2015-10-15 00:00:00', @@ -307,7 +310,8 @@ describe('OC.Share.ShareItemModel', function() { stime: 1403884509, storage: 1, token: 'anothertoken', - uid_owner: 'root' + uid_owner: 'root', + hide_download: 1 }] )); OC.currentUser = 'root'; @@ -320,6 +324,7 @@ describe('OC.Share.ShareItemModel', function() { var linkShare = model.get('linkShare'); expect(linkShare.isLinkShare).toEqual(true); expect(linkShare.token).toEqual('tehtoken'); + expect(linkShare.hideDownload).toEqual(false); // TODO: check child too }); @@ -579,6 +584,7 @@ describe('OC.Share.ShareItemModel', function() { expect(addShareStub.calledOnce).toEqual(true); expect(addShareStub.firstCall.args[0]).toEqual({ + hideDownload: false, password: '', passwordChanged: false, permissions: OC.PERMISSION_READ, @@ -603,6 +609,7 @@ describe('OC.Share.ShareItemModel', function() { expect(addShareStub.calledOnce).toEqual(true); expect(addShareStub.firstCall.args[0]).toEqual({ + hideDownload: false, password: '', passwordChanged: false, permissions: OC.PERMISSION_READ, -- cgit v1.2.3 From 2c990ade77f73ce4cde7ecd7cb4ef116e1b8cd8d Mon Sep 17 00:00:00 2001 From: Julius Härtl Date: Wed, 31 Oct 2018 11:23:23 +0100 Subject: Do not set indeterminate state for file shares MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- core/js/sharedialogshareelistview.js | 4 +++- core/js/shareitemmodel.js | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'core/js') diff --git a/core/js/sharedialogshareelistview.js b/core/js/sharedialogshareelistview.js index 93373a54435..94abf55a358 100644 --- a/core/js/sharedialogshareelistview.js +++ b/core/js/sharedialogshareelistview.js @@ -314,7 +314,9 @@ var $edit = _this.$('#canEdit-' + _this.cid + '-' + sharee.shareId); if($edit.length === 1) { $edit.prop('checked', sharee.editPermissionState === 'checked'); - $edit.prop('indeterminate', sharee.editPermissionState === 'indeterminate'); + if (sharee.isFolder) { + $edit.prop('indeterminate', sharee.editPermissionState === 'indeterminate'); + } } }); this.$('.popovermenu').on('afterHide', function() { diff --git a/core/js/shareitemmodel.js b/core/js/shareitemmodel.js index 3f92a8591e5..84715ec87c1 100644 --- a/core/js/shareitemmodel.js +++ b/core/js/shareitemmodel.js @@ -616,6 +616,12 @@ var hcp = this.hasCreatePermission(shareIndex); var hup = this.hasUpdatePermission(shareIndex); var hdp = this.hasDeletePermission(shareIndex); + if (this.isFile()) { + if (hcp || hup || hdp) { + return 'checked'; + } + return ''; + } if (!hcp && !hup && !hdp) { return ''; } -- cgit v1.2.3 From 95e34407bf07fbcb2d1a3d362e7685977f85f8d5 Mon Sep 17 00:00:00 2001 From: Julius Härtl Date: Wed, 31 Oct 2018 12:12:24 +0100 Subject: Add tests for edit permission state on file shares MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- core/js/tests/specs/sharedialogshareelistview.js | 31 ++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'core/js') diff --git a/core/js/tests/specs/sharedialogshareelistview.js b/core/js/tests/specs/sharedialogshareelistview.js index 8e34225d199..e51fc2df72d 100644 --- a/core/js/tests/specs/sharedialogshareelistview.js +++ b/core/js/tests/specs/sharedialogshareelistview.js @@ -90,6 +90,37 @@ describe('OC.Share.ShareDialogShareeListView', function () { }); describe('Sets correct initial checkbox state', function () { + + it('marks edit box as unchecked for file shares without edit permissions', function () { + shareModel.set('shares', [{ + id: 100, + item_source: 123, + permissions: 1, + share_type: OC.Share.SHARE_TYPE_USER, + share_with: 'user1', + share_with_displayname: 'User One', + uid_owner: oc_current_user, + itemType: 'file' + }]); + listView.render(); + expect(listView.$el.find("input[name='edit']").is(':not(:checked)')).toEqual(true); + }); + + it('marks edit box as checked for file shares', function () { + shareModel.set('shares', [{ + id: 100, + item_source: 123, + permissions: 1 | OC.PERMISSION_UPDATE, + share_type: OC.Share.SHARE_TYPE_USER, + share_with: 'user1', + share_with_displayname: 'User One', + uid_owner: oc_current_user, + itemType: 'file' + }]); + listView.render(); + expect(listView.$el.find("input[name='edit']").is(':checked')).toEqual(true); + }); + it('marks edit box as indeterminate when only some permissions are given', function () { shareModel.set('shares', [{ id: 100, -- cgit v1.2.3 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) --- apps/files_sharing/css/sharetabview.scss | 36 +- apps/files_sharing/js/share.js | 14 +- 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 +-- 8 files changed, 390 insertions(+), 243 deletions(-) (limited to 'core/js') diff --git a/apps/files_sharing/css/sharetabview.scss b/apps/files_sharing/css/sharetabview.scss index 0d277c58bd7..9611580baad 100644 --- a/apps/files_sharing/css/sharetabview.scss +++ b/apps/files_sharing/css/sharetabview.scss @@ -194,31 +194,29 @@ display: flex; align-items: center; white-space: nowrap; - // can edit label - > .shareOption > label { - padding: 13px; - padding-right: 0; - } - // more menu - > .share-menu { - position: relative; + + // icons + > .icon:not(.hidden), + .share-menu > .icon:not(.hidden) { + padding: 14px; + height: 44px; + width: 44px; + opacity: .5; display: block; - .icon-more { - padding: 14px; - height: 44px; - width: 44px; - opacity: .5; - display: block; - cursor: pointer; - } + cursor: pointer; + &:hover, &:focus, &:active { - .icon-more { - opacity: .7;; - } + opacity: .7;; } } + + // more menu + > .share-menu { + position: relative; + display: block; + } } .username { padding: 0 8px; diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js index 68529fd882f..b02c6e3d9ee 100644 --- a/apps/files_sharing/js/share.js +++ b/apps/files_sharing/js/share.js @@ -193,15 +193,15 @@ var $tr = fileList.findFileEl(fileInfoModel.get('name')); // We count email shares as link share - var hasLinkShare = shareModel.hasLinkShare(); + var hasLinkShares = shareModel.hasLinkShares(); shareModel.get('shares').forEach(function (share) { if (share.share_type === OC.Share.SHARE_TYPE_EMAIL) { - hasLinkShare = true; + hasLinkShares = true; } }); OCA.Sharing.Util._updateFileListDataAttributes(fileList, $tr, shareModel); - if (!OCA.Sharing.Util._updateFileActionIcon($tr, shareModel.hasUserShares(), hasLinkShare)) { + if (!OCA.Sharing.Util._updateFileActionIcon($tr, shareModel.hasUserShares(), hasLinkShares)) { // remove icon, if applicable OC.Share.markFileAsShared($tr, false, false); } @@ -249,15 +249,15 @@ * * @param $tr file element of the file to update * @param {boolean} hasUserShares true if a user share exists - * @param {boolean} hasLinkShare true if a link share exists + * @param {boolean} hasLinkShares true if a link share exists * * @return {boolean} true if the icon was set, false otherwise */ - _updateFileActionIcon: function($tr, hasUserShares, hasLinkShare) { + _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 || hasLinkShare || $tr.attr('data-share-recipient-data') || $tr.attr('data-share-owner')) { - OC.Share.markFileAsShared($tr, true, hasLinkShare); + if (hasUserShares || hasLinkShares || $tr.attr('data-share-recipient-data') || $tr.attr('data-share-owner')) { + OC.Share.markFileAsShared($tr, true, hasLinkShares); return true; } return false; 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
    • \n
      \n
      " + alias4(((helper = (helper = helpers.linkShareLabel || (depth0 != null ? depth0.linkShareLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"linkShareLabel","hash":{},"data":data}) : helper))) - + "\n \n \n \n \n \n \n" - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.showMenu : depth0),{"name":"if","hash":{},"fn":container.program(4, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") - + " \n
    • \n
    \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 From 376704e83413d093d596f1b9168daf24907189aa Mon Sep 17 00:00:00 2001 From: Daniel Calviño Sánchez Date: Mon, 15 Oct 2018 17:09:46 +0200 Subject: Add "Password protect by Talk" to the menu of link shares MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When Talk is enabled the menu for link shares now shows a checkbox to protect the password by Talk (that is, to show the "Request password by Talk" UI in the authentication page for the link share). Although in e-mail shares protecting the share with a password and protecting the password by Talk are mutually exclusive actions (as when the password is set it is sent to the sharee, so it must be set again when protecting it by Talk to be able to verify the identity of the sharee), in the case of link shares protecting the password by Talk is an additional step to protecting the share with a password (as just setting the password does not disclose it to anyone). As such, the checkbox is shown only when there is a password set for the link share (even if the field itself for the password is not shown, like when they are enforced in the settings). Note that the icon set for the field, "icon-passwordtalk", does not currently exist; it is the same used for e-mail shares, and it is needed simply to get the right padding in the menu. Signed-off-by: Daniel Calviño Sánchez --- ...haredialoglinkshareview_popover_menu.handlebars | 10 ++ core/js/sharedialoglinkshareview.js | 64 ++++++++++++ core/js/shareitemmodel.js | 5 +- core/js/sharetemplates.js | 29 ++++-- core/js/tests/specs/sharedialoglinkshareview.js | 113 +++++++++++++++++++++ core/js/tests/specs/shareitemmodelSpec.js | 13 ++- 6 files changed, 222 insertions(+), 12 deletions(-) (limited to 'core/js') diff --git a/core/js/share/sharedialoglinkshareview_popover_menu.handlebars b/core/js/share/sharedialoglinkshareview_popover_menu.handlebars index cc951ce047d..59312bc70b0 100644 --- a/core/js/share/sharedialoglinkshareview_popover_menu.handlebars +++ b/core/js/share/sharedialoglinkshareview_popover_menu.handlebars @@ -62,6 +62,16 @@ {{/if}} + {{#if showPasswordByTalkCheckBox}} +
  • + + + + + +
  • + {{/if}}
  • \n \n \n \n \n \n
  • \n"; },"15":function(container,depth0,helpers,partials,data) { + return "datepicker"; +},"17":function(container,depth0,helpers,partials,data) { var helper; return container.escapeExpression(((helper = (helper = helpers.expireDate || (depth0 != null ? depth0.expireDate : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"expireDate","hash":{},"data":data}) : helper))); -},"17":function(container,depth0,helpers,partials,data) { +},"19":function(container,depth0,helpers,partials,data) { var helper; return container.escapeExpression(((helper = (helper = helpers.defaultExpireDate || (depth0 != null ? depth0.defaultExpireDate : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"defaultExpireDate","hash":{},"data":data}) : helper))); -},"19":function(container,depth0,helpers,partials,data) { - return "readonly"; },"21":function(container,depth0,helpers,partials,data) { + return "readonly"; +},"23":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 \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" - + ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.social : depth0),{"name":"each","hash":{},"fn":container.program(21, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.social : depth0),{"name":"each","hash":{},"fn":container.program(23, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "
  • \n " + alias4(((helper = (helper = helpers.unshareLinkLabel || (depth0 != null ? depth0.unshareLinkLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"unshareLinkLabel","hash":{},"data":data}) : helper))) + "\n
  • \n
  • \n \n \n \n " diff --git a/core/js/tests/specs/sharedialoglinkshareview.js b/core/js/tests/specs/sharedialoglinkshareview.js index f5fe8725c03..c2d84fd2e87 100644 --- a/core/js/tests/specs/sharedialoglinkshareview.js +++ b/core/js/tests/specs/sharedialoglinkshareview.js @@ -235,4 +235,117 @@ describe('OC.Share.ShareDialogLinkShareView', function () { }); + describe('protect password by Talk', function () { + + var $passwordByTalkCheckbox; + var $workingIcon; + + beforeEach(function () { + // Needed to render the view + configModel.isShareWithLinkAllowed.returns(true); + + // "Enable" Talk + window.oc_appswebroots['spreed'] = window.oc_webroot + '/apps/files/'; + + shareModel.set({ + linkShares: [{ + id: 123, + password: 'password' + }] + }); + view.render(); + + $passwordByTalkCheckbox = view.$el.find('.passwordByTalkCheckbox'); + $workingIcon = $passwordByTalkCheckbox.prev('.icon-loading-small'); + + sinon.stub(shareModel, 'saveLinkShare'); + + expect($workingIcon.hasClass('hidden')).toBeTruthy(); + }); + + afterEach(function () { + shareModel.saveLinkShare.restore(); + }); + + it('is shown if Talk is enabled and there is a password set', function() { + expect($passwordByTalkCheckbox.length).toBeTruthy(); + }); + + it('is not shown if Talk is enabled but there is no password set', function() { + // Changing the password value also triggers the rendering + shareModel.set({ + linkShares: [{ + id: 123 + }] + }); + + $passwordByTalkCheckbox = view.$el.find('.passwordByTalkCheckbox'); + + expect($passwordByTalkCheckbox.length).toBeFalsy(); + }); + + it('is not shown if there is a password set but Talk is not enabled', function() { + // "Disable" Talk + delete window.oc_appswebroots['spreed']; + + view.render(); + + $passwordByTalkCheckbox = view.$el.find('.passwordByTalkCheckbox'); + + expect($passwordByTalkCheckbox.length).toBeFalsy(); + }); + + it('checkbox is checked when the setting is enabled', function () { + shareModel.set({ + linkShares: [{ + id: 123, + password: 'password', + sendPasswordByTalk: true + }] + }); + view.render(); + + $passwordByTalkCheckbox = view.$el.find('.passwordByTalkCheckbox'); + + expect($passwordByTalkCheckbox.is(':checked')).toEqual(true); + }); + + it('checkbox is not checked when the setting is disabled', function () { + expect($passwordByTalkCheckbox.is(':checked')).toEqual(false); + }); + + it('enables the setting if clicked when unchecked', function () { + // Simulate the click by checking the checkbox and then triggering + // the "change" event. + $passwordByTalkCheckbox.prop('checked', true); + $passwordByTalkCheckbox.change(); + + expect($workingIcon.hasClass('hidden')).toBeFalsy(); + expect(shareModel.saveLinkShare.withArgs({ sendPasswordByTalk: true, cid: 123 }).calledOnce).toBeTruthy(); + }); + + it('disables the setting if clicked when checked', function () { + shareModel.set({ + linkShares: [{ + id: 123, + password: 'password', + sendPasswordByTalk: true + }] + }); + view.render(); + + $passwordByTalkCheckbox = view.$el.find('.passwordByTalkCheckbox'); + $workingIcon = $passwordByTalkCheckbox.prev('.icon-loading-small'); + + // Simulate the click by unchecking the checkbox and then triggering + // the "change" event. + $passwordByTalkCheckbox.prop('checked', false); + $passwordByTalkCheckbox.change(); + + expect($workingIcon.hasClass('hidden')).toBeFalsy(); + expect(shareModel.saveLinkShare.withArgs({ sendPasswordByTalk: false, cid: 123 }).calledOnce).toBeTruthy(); + }); + + }); + }); diff --git a/core/js/tests/specs/shareitemmodelSpec.js b/core/js/tests/specs/shareitemmodelSpec.js index 3b4dc5a960f..e8016950094 100644 --- a/core/js/tests/specs/shareitemmodelSpec.js +++ b/core/js/tests/specs/shareitemmodelSpec.js @@ -169,7 +169,8 @@ describe('OC.Share.ShareItemModel', function() { storage: 1, token: 'tehtoken', uid_owner: 'root', - hide_download: 1 + hide_download: 1, + send_password_by_talk: true } ])); @@ -189,6 +190,7 @@ describe('OC.Share.ShareItemModel', function() { expect(linkShares.length).toEqual(1); var linkShare = linkShares[0]; expect(linkShare.hideDownload).toEqual(true); + expect(linkShare.sendPasswordByTalk).toEqual(true); // TODO: check more attributes }); @@ -293,7 +295,8 @@ describe('OC.Share.ShareItemModel', function() { storage: 1, token: 'tehtoken', uid_owner: 'root', - hide_download: 0 + hide_download: 0, + send_password_by_talk: false }, { displayname_owner: 'root', expiration: '2015-10-15 00:00:00', @@ -312,7 +315,8 @@ describe('OC.Share.ShareItemModel', function() { storage: 1, token: 'anothertoken', uid_owner: 'root', - hide_download: 1 + hide_download: 1, + send_password_by_talk: true }] )); OC.currentUser = 'root'; @@ -327,6 +331,7 @@ describe('OC.Share.ShareItemModel', function() { var linkShare = linkShares[0]; expect(linkShare.token).toEqual('tehtoken'); expect(linkShare.hideDownload).toEqual(false); + expect(linkShare.sendPasswordByTalk).toEqual(false); // TODO: check child too }); @@ -588,6 +593,7 @@ describe('OC.Share.ShareItemModel', function() { hideDownload: false, password: '', passwordChanged: false, + sendPasswordByTalk: false, permissions: OC.PERMISSION_READ, expireDate: '', shareType: OC.Share.SHARE_TYPE_LINK @@ -612,6 +618,7 @@ describe('OC.Share.ShareItemModel', function() { hideDownload: false, password: '', passwordChanged: false, + sendPasswordByTalk: false, permissions: OC.PERMISSION_READ, expireDate: '2015-07-24 00:00:00', shareType: OC.Share.SHARE_TYPE_LINK -- cgit v1.2.3 From a696c011c24b76b2590a9f45fc861e8b4a667b03 Mon Sep 17 00:00:00 2001 From: Julius Härtl Date: Mon, 27 Aug 2018 18:03:42 +0200 Subject: Fix app menu calculation for random size of the right header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- core/js/js.js | 9 +++++---- core/js/tests/specs/coreSpec.js | 4 ++++ 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'core/js') diff --git a/core/js/js.js b/core/js/js.js index fd6e0a68da5..026cc6bb0d6 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -1562,13 +1562,14 @@ function initCore() { var resizeMenu = function() { var appList = $('#appmenu li'); - var headerWidth = $('.header-left').outerWidth() - $('#nextcloud').outerWidth(); + var rightHeaderWidth = $('.header-right').outerWidth(); + var headerWidth = $('header').outerWidth(); var usePercentualAppMenuLimit = 0.33; var minAppsDesktop = 8; - var availableWidth = headerWidth - $(appList).width(); + var availableWidth = headerWidth - $('#nextcloud').outerWidth() - (rightHeaderWidth > 210 ? rightHeaderWidth : 210) var isMobile = $(window).width() < 768; if (!isMobile) { - availableWidth = headerWidth * usePercentualAppMenuLimit; + availableWidth = availableWidth * usePercentualAppMenuLimit; } var appCount = Math.floor((availableWidth / $(appList).width())); if (isMobile && appCount > minAppsDesktop) { @@ -1613,7 +1614,7 @@ function initCore() { } }; $(window).resize(resizeMenu); - resizeMenu(); + setTimeout(resizeMenu, 0); // just add snapper for logged in users if($('#app-navigation').length && !$('html').hasClass('lte9')) { diff --git a/core/js/tests/specs/coreSpec.js b/core/js/tests/specs/coreSpec.js index 67b7d77be6c..63c02048a34 100644 --- a/core/js/tests/specs/coreSpec.js +++ b/core/js/tests/specs/coreSpec.js @@ -573,6 +573,10 @@ describe('Core base tests', function() { }); it('Clicking menu toggle toggles navigation in', function() { window.initCore(); + // fore show more apps icon since otherwise it would be hidden since no icons are available + clock.tick(1 * 1000); + $('#more-apps').show(); + expect($navigation.is(':visible')).toEqual(false); $toggle.click(); clock.tick(1 * 1000); -- cgit v1.2.3