diff options
author | John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com> | 2018-11-01 17:33:50 +0100 |
---|---|---|
committer | John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com> | 2018-11-01 17:33:58 +0100 |
commit | 98f30c2dab24f0ab80015ef7849a7d8875651f6f (patch) | |
tree | 9de386977ed99c6627410de53d0cfdfaccf4616c /core/js | |
parent | abed75e5cbd200169a236f3b586553e5d9ed0452 (diff) | |
parent | 7246f2ace50e41f68433cd89755413b512fa7909 (diff) | |
download | nextcloud-server-98f30c2dab24f0ab80015ef7849a7d8875651f6f.tar.gz nextcloud-server-98f30c2dab24f0ab80015ef7849a7d8875651f6f.zip |
Merge branch 'addressbook-uid-check-migration' of https://github.com/nextcloud/server into addressbook-uid-check-migration
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
Diffstat (limited to 'core/js')
-rw-r--r-- | core/js/share/sharedialoglinkshareview_popover_menu.handlebars | 10 | ||||
-rw-r--r-- | core/js/sharedialoglinkshareview.js | 22 | ||||
-rw-r--r-- | core/js/sharedialogshareelistview.js | 4 | ||||
-rw-r--r-- | core/js/sharedialogview.js | 110 | ||||
-rw-r--r-- | core/js/shareitemmodel.js | 11 | ||||
-rw-r--r-- | core/js/sharetemplates.js | 53 | ||||
-rw-r--r-- | core/js/tests/specs/sharedialoglinkshareview.js | 94 | ||||
-rw-r--r-- | core/js/tests/specs/sharedialogshareelistview.js | 31 | ||||
-rw-r--r-- | core/js/tests/specs/shareitemmodelSpec.js | 13 |
9 files changed, 313 insertions, 35 deletions
diff --git a/core/js/share/sharedialoglinkshareview_popover_menu.handlebars b/core/js/share/sharedialoglinkshareview_popover_menu.handlebars index 412ed8efca0..baee3aa6630 100644 --- a/core/js/share/sharedialoglinkshareview_popover_menu.handlebars +++ b/core/js/share/sharedialoglinkshareview_popover_menu.handlebars @@ -11,6 +11,16 @@ <input id="linkText-{{cid}}" class="linkText" type="text" readonly="readonly" value="{{shareLinkURL}}" /> </span> </li> + {{#if showHideDownloadCheckbox}} + <li> + <span class="shareOption menuitem"> + <span class="icon-loading-small hidden"></span> + <input type="checkbox" name="hideDownload" id="sharingDialogHideDownload-{{cid}}" class="checkbox hideDownloadCheckbox" + {{#if hideDownload}}checked="checked"{{/if}} /> + <label for="sharingDialogHideDownload-{{cid}}">{{hideDownloadLabel}}</label> + </span> + </li> + {{/if}} {{#if publicUpload}} <li> <span class="shareOption menuitem"> diff --git a/core/js/sharedialoglinkshareview.js b/core/js/sharedialoglinkshareview.js index aac4843c8e0..7603b058a96 100644 --- a/core/js/sharedialoglinkshareview.js +++ b/core/js/sharedialoglinkshareview.js @@ -47,6 +47,8 @@ 'change .linkCheckbox': 'onLinkCheckBoxChange', // open menu 'click .share-menu .icon-more': 'onToggleMenu', + // hide download + 'change .hideDownloadCheckbox': 'onHideDownloadChange', // password 'focusout input.linkPassText': 'onPasswordEntered', 'keyup input.linkPassText': 'onPasswordKeyUp', @@ -179,6 +181,20 @@ $el.select(); }, + onHideDownloadChange: function() { + var $checkbox = this.$('.hideDownloadCheckbox'); + $checkbox.siblings('.icon-loading-small').removeClass('hidden').addClass('inlineblock'); + + var hideDownload = false; + if($checkbox.is(':checked')) { + hideDownload = true; + } + + this.model.saveLinkShare({ + hideDownload: hideDownload + }); + }, + onShowPasswordClick: function() { this.$el.find('.linkPass').slideToggle(OC.menuSpeed); this.$el.find('.linkPassMenu').toggleClass('hidden'); @@ -401,6 +417,9 @@ 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 @@ -464,6 +483,9 @@ 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, 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/sharedialogview.js b/core/js/sharedialogview.js index 9c648357e61..082bf9571d7 100644 --- a/core/js/sharedialogview.js +++ b/core/js/sharedialogview.js @@ -312,6 +312,41 @@ var suggestions = exactMatches.concat(users).concat(groups).concat(remotes).concat(remoteGroups).concat(emails).concat(circles).concat(rooms).concat(lookup); + function dynamicSort(property) { + return function (a,b) { + var aProperty = ''; + var bProperty = ''; + if (typeof a[property] !== 'undefined') { + aProperty = a[property]; + } + if (typeof b[property] !== 'undefined') { + bProperty = b[property]; + } + return (aProperty < bProperty) ? -1 : (aProperty > bProperty) ? 1 : 0; + } + } + + /** + * Sort share entries by uuid to properly group them + */ + var grouped = suggestions.sort(dynamicSort('uuid')); + + var previousUuid = null; + var groupedLength = grouped.length; + var result = []; + /** + * build the result array that only contains all contact entries from + * merged contacts, if the search term matches its contact name + */ + for (i = 0; i < groupedLength; i++) { + if (typeof grouped[i].uuid !== 'undefined' && grouped[i].uuid === previousUuid) { + grouped[i].merged = true; + } + if (searchTerm === grouped[i].name || typeof grouped[i].merged === 'undefined') { + result.push(grouped[i]); + } + previousUuid = grouped[i].uuid; + } var moreResultsAvailable = ( oc_config['sharing.maxAutocompleteResults'] > 0 @@ -328,7 +363,7 @@ ) ); - deferred.resolve(suggestions, exactMatches, moreResultsAvailable); + deferred.resolve(result, exactMatches, moreResultsAvailable); } else { deferred.reject(result.ocs.meta.message); } @@ -441,33 +476,72 @@ }, autocompleteRenderItem: function(ul, item) { - + var icon = 'icon-user'; var text = item.label; + if (typeof item.name !== 'undefined') { + text = item.name; + } 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 description = ''; + var getTranslatedType = function(type) { + switch (type) { + case 'HOME': + return t('core', 'Home'); + case 'WORK': + return t('core', 'Home'); + case 'OTHER': + return t('core', 'Other'); + default: + return type; + } + }; + if (typeof item.type !== 'undefined' && item.type !== null) { + description = getTranslatedType(item.type); } var insert = $("<div class='share-autocomplete-item'/>"); - var avatar = $("<div class='avatardiv'></div>").appendTo(insert); - if (item.value.shareType === OC.Share.SHARE_TYPE_USER || item.value.shareType === OC.Share.SHARE_TYPE_CIRCLE) { - avatar.avatar(item.value.shareWith, 32, undefined, undefined, undefined, item.label); + if (item.merged) { + insert.addClass('merged'); + text = item.value.shareWith; } else { - avatar.imageplaceholder(text, undefined, 32); + var avatar = $("<div class='avatardiv'></div>").appendTo(insert); + if (item.value.shareType === OC.Share.SHARE_TYPE_USER || item.value.shareType === OC.Share.SHARE_TYPE_CIRCLE) { + avatar.avatar(item.value.shareWith, 32, undefined, undefined, undefined, item.label); + } else { + if (typeof item.uuid === 'undefined') { + item.uuid = text; + } + avatar.imageplaceholder(item.uuid, text, 32); + } + description = item.value.shareWith; + } + if (description !== '') { + insert.addClass('with-description'); } $("<div class='autocomplete-item-text'></div>") - .text(text) + .html( + text.replace( + new RegExp(this.term, "gi"), + "<span class='ui-state-highlight'>$&</span>") + + '<span class="autocomplete-item-details">' + description + '</span>' + ) .appendTo(insert); insert.attr('title', item.value.shareWith); + insert.append('<span class="icon '+icon+'" title="' + text + '"></span>'); insert = $("<a>") .append(insert); return $("<li>") @@ -479,6 +553,20 @@ _onSelectRecipient: function(e, s) { var self = this; + if (e.keyCode == 9) { + e.preventDefault(); + if (typeof s.item.name !== 'undefined') { + e.target.value = s.item.name; + } else { + e.target.value = s.item.label; + } + setTimeout(function() { + $(e.target).attr('disabled', false) + .autocomplete('search', $(e.target).val()); + }, 0); + return false; + } + e.preventDefault(); // Ensure that the keydown handler for the input field is not // called; otherwise it would try to add the recipient again, which diff --git a/core/js/shareitemmodel.js b/core/js/shareitemmodel.js index f4a3caf1370..84715ec87c1 100644 --- a/core/js/shareitemmodel.js +++ b/core/js/shareitemmodel.js @@ -18,6 +18,7 @@ * @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 @@ -136,6 +137,7 @@ call = this.updateShare(shareId, attributes, options); } else { attributes = _.defaults(attributes, { + hideDownload: false, password: '', passwordChanged: false, permissions: OC.PERMISSION_READ, @@ -614,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 ''; } @@ -866,6 +874,9 @@ isLinkShare: true, id: share.id, token: share.token, + // 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, diff --git a/core/js/sharetemplates.js b/core/js/sharetemplates.js index efdd3ff6606..0c1fee37455 100644 --- a/core/js/sharetemplates.js +++ b/core/js/sharetemplates.js @@ -61,6 +61,20 @@ templates['sharedialoglinkshareview'] = template({"1":function(container,depth0, templates['sharedialoglinkshareview_popover_menu'] = template({"1":function(container,depth0,helpers,partials,data) { var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; + return " <li>\n <span class=\"shareOption menuitem\">\n <span class=\"icon-loading-small hidden\"></span>\n <input type=\"checkbox\" name=\"hideDownload\" id=\"sharingDialogHideDownload-" + + alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper))) + + "\" class=\"checkbox hideDownloadCheckbox\"\n " + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hideDownload : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + " />\n <label for=\"sharingDialogHideDownload-" + + alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper))) + + "\">" + + alias4(((helper = (helper = helpers.hideDownloadLabel || (depth0 != null ? depth0.hideDownloadLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"hideDownloadLabel","hash":{},"data":data}) : helper))) + + "</label>\n </span>\n </li>\n"; +},"2":function(container,depth0,helpers,partials,data) { + return "checked=\"checked\""; +},"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 " <li>\n <span class=\"shareOption menuitem\">\n <span class=\"icon-loading-small hidden\"></span>\n <input type=\"radio\" name=\"publicUpload\" value=\"" + alias4(((helper = (helper = helpers.publicUploadRValue || (depth0 != null ? depth0.publicUploadRValue : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"publicUploadRValue","hash":{},"data":data}) : helper))) + "\" id=\"sharingDialogAllowPublicUpload-r-" @@ -92,7 +106,7 @@ templates['sharedialoglinkshareview_popover_menu'] = template({"1":function(cont + "\">" + alias4(((helper = (helper = helpers.publicUploadWLabel || (depth0 != null ? depth0.publicUploadWLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"publicUploadWLabel","hash":{},"data":data}) : helper))) + "</label>\n </span>\n </li>\n"; -},"3":function(container,depth0,helpers,partials,data) { +},"6":function(container,depth0,helpers,partials,data) { var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; return " <li id=\"allowPublicEditingWrapper\">\n <span class=\"shareOption menuitem\">\n <span class=\"icon-loading-small hidden\"></span>\n <input type=\"checkbox\" name=\"allowPublicEditing\" id=\"sharingDialogAllowPublicEditing-" @@ -104,41 +118,39 @@ templates['sharedialoglinkshareview_popover_menu'] = template({"1":function(cont + "\">" + alias4(((helper = (helper = helpers.publicEditingLabel || (depth0 != null ? depth0.publicEditingLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"publicEditingLabel","hash":{},"data":data}) : helper))) + "</label>\n </span>\n </li>\n"; -},"5":function(container,depth0,helpers,partials,data) { +},"8":function(container,depth0,helpers,partials,data) { var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; return " <li>\n <span class=\"shareOption menuitem\">\n <input type=\"checkbox\" name=\"showPassword\" id=\"showPassword-" + alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper))) + "\" class=\"checkbox showPasswordCheckbox\"\n " - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.isPasswordSet : depth0),{"name":"if","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.isPasswordSet : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + " " - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.isPasswordEnforced : depth0),{"name":"if","hash":{},"fn":container.program(8, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.isPasswordEnforced : depth0),{"name":"if","hash":{},"fn":container.program(9, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + " value=\"1\" />\n <label for=\"showPassword-" + alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper))) + "\">" + alias4(((helper = (helper = helpers.enablePasswordLabel || (depth0 != null ? depth0.enablePasswordLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"enablePasswordLabel","hash":{},"data":data}) : helper))) + "</label>\n </span>\n </li>\n <li class=\"" - + ((stack1 = helpers.unless.call(alias1,(depth0 != null ? depth0.isPasswordSet : depth0),{"name":"unless","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.unless.call(alias1,(depth0 != null ? depth0.isPasswordSet : depth0),{"name":"unless","hash":{},"fn":container.program(11, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + " linkPassMenu\">\n <span class=\"shareOption menuitem icon-share-pass\">\n <input id=\"linkPassText-" + alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper))) + "\" class=\"linkPassText\" type=\"password\" placeholder=\"" + alias4(((helper = (helper = helpers.passwordPlaceholder || (depth0 != null ? depth0.passwordPlaceholder : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"passwordPlaceholder","hash":{},"data":data}) : helper))) + "\" autocomplete=\"new-password\" />\n <span class=\"icon icon-loading-small hidden\"></span>\n </span>\n </li>\n"; -},"6":function(container,depth0,helpers,partials,data) { - return "checked=\"checked\""; -},"8":function(container,depth0,helpers,partials,data) { +},"9":function(container,depth0,helpers,partials,data) { return "disabled=\"disabled\""; -},"10":function(container,depth0,helpers,partials,data) { +},"11":function(container,depth0,helpers,partials,data) { return "hidden"; -},"12":function(container,depth0,helpers,partials,data) { +},"13":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))); -},"14":function(container,depth0,helpers,partials,data) { +},"15":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))); -},"16":function(container,depth0,helpers,partials,data) { +},"17":function(container,depth0,helpers,partials,data) { var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; return " <li>\n <a href=\"#\" class=\"shareOption menuitem pop-up\" data-url=\"" @@ -162,21 +174,22 @@ templates['sharedialoglinkshareview_popover_menu'] = template({"1":function(cont + "\" class=\"linkText\" type=\"text\" readonly=\"readonly\" value=\"" + 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 </span>\n </li>\n" - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.publicUpload : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.publicEditing : depth0),{"name":"if","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.showPasswordCheckBox : depth0),{"name":"if","hash":{},"fn":container.program(5, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.showHideDownloadCheckbox : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.publicUpload : depth0),{"name":"if","hash":{},"fn":container.program(4, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.publicEditing : depth0),{"name":"if","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.showPasswordCheckBox : depth0),{"name":"if","hash":{},"fn":container.program(8, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + " <li>\n <span class=\"shareOption menuitem\">\n <input id=\"expireDate-" + alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper))) + "\" type=\"checkbox\" name=\"expirationDate\" class=\"expireDate checkbox\"\n " - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hasExpireDate : depth0),{"name":"if","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hasExpireDate : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + " " - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.isExpirationEnforced : depth0),{"name":"if","hash":{},"fn":container.program(8, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.isExpirationEnforced : depth0),{"name":"if","hash":{},"fn":container.program(9, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "\" />\n <label for=\"expireDate-" + alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper))) + "\">" + alias4(((helper = (helper = helpers.expireDateLabel || (depth0 != null ? depth0.expireDateLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"expireDateLabel","hash":{},"data":data}) : helper))) + "</label>\n </span>\n </li>\n <li class=\"" - + ((stack1 = helpers.unless.call(alias1,(depth0 != null ? depth0.hasExpireDate : depth0),{"name":"unless","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.unless.call(alias1,(depth0 != null ? depth0.hasExpireDate : depth0),{"name":"unless","hash":{},"fn":container.program(11, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "\">\n <span class=\"menuitem icon-expiredate expirationDateContainer-" + alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper))) + "\">\n <label for=\"expirationDatePicker-" @@ -190,7 +203,7 @@ templates['sharedialoglinkshareview_popover_menu'] = template({"1":function(cont + "\" class=\"datepicker\" type=\"text\" placeholder=\"" + alias4(((helper = (helper = helpers.expirationDatePlaceholder || (depth0 != null ? depth0.expirationDatePlaceholder : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"expirationDatePlaceholder","hash":{},"data":data}) : helper))) + "\" value=\"" - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hasExpireDate : depth0),{"name":"if","hash":{},"fn":container.program(12, data, 0),"inverse":container.program(14, data, 0),"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hasExpireDate : depth0),{"name":"if","hash":{},"fn":container.program(13, data, 0),"inverse":container.program(15, data, 0),"data":data})) != null ? stack1 : "") + "\" />\n </span>\n </li>\n <li>\n <a href=\"#\" class=\"share-add\">\n <span class=\"icon-loading-small hidden\"></span>\n <span class=\"icon icon-edit\"></span>\n <span>" + 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))) + "</span>\n <input type=\"button\" class=\"share-note-delete icon-delete\">\n </a>\n </li>\n <li class=\"share-note-form share-note-link hidden\">\n <span class=\"menuitem icon-note\">\n <textarea class=\"share-note\">" @@ -198,7 +211,7 @@ templates['sharedialoglinkshareview_popover_menu'] = template({"1":function(cont + "</textarea>\n <input type=\"submit\" class=\"icon-confirm share-note-submit\" value=\"\" id=\"add-note-" + alias4(((helper = (helper = helpers.shareId || (depth0 != null ? depth0.shareId : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"shareId","hash":{},"data":data}) : helper))) + "\" />\n </span>\n </li>\n" - + ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.social : depth0),{"name":"each","hash":{},"fn":container.program(16, 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(17, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + " </ul>\n</div>\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/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, 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, |