Migrate link shares to array

Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
This commit is contained in:
John Molakvoæ (skjnldsv) 2018-10-29 13:58:14 +01:00 committed by Daniel Calviño Sánchez
parent feb9f72e8b
commit 1bd6d39b39
8 changed files with 389 additions and 242 deletions

View File

@ -194,30 +194,28 @@
display: flex;
align-items: center;
white-space: nowrap;
// can edit label
> .shareOption > label {
padding: 13px;
padding-right: 0;
// icons
> .icon:not(.hidden),
.share-menu > .icon:not(.hidden) {
padding: 14px;
height: 44px;
width: 44px;
opacity: .5;
display: block;
cursor: pointer;
&:hover,
&:focus,
&:active {
opacity: .7;;
}
}
// more menu
> .share-menu {
position: relative;
display: block;
.icon-more {
padding: 14px;
height: 44px;
width: 44px;
opacity: .5;
display: block;
cursor: pointer;
}
&:hover,
&:focus,
&:active {
.icon-more {
opacity: .7;;
}
}
}
}
.username {

View File

@ -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;

View File

@ -1,14 +1,19 @@
{{#if shareAllowed}}
<ul id="shareLink" class="shareWithList">
<li data-share-id="{{cid}}">
<div class="avatar icon-public-white"></div><span class="username" title="{{linkShareLabel}}">{{linkShareLabel}}</span>
<span class="sharingOptionsGroup">
<span class="shareOption">
<span class="icon-loading-small hidden"></span>
<input id="linkCheckbox-{{cid}}" {{#if isLinkShare}}checked="checked"{{/if}} type="checkbox" name="linkCheckbox" class="linkCheckbox permissions checkbox">
<label for="linkCheckbox-{{cid}}">{{linkShareEnableLabel}}</label>
{{#if nolinkShares}}
<li>
<div class="avatar icon-public-white"></div>
<span class="username">{{newShareLabel}}</span>
<span class="sharingOptionsGroup">
<span class="icon icon-add new-share" title="{{newShareTitle}}"></span>
<span class="icon icon-loading-small hidden"></span>
</span>
{{#if showMenu}}
</li>
{{/if}}
{{#each linkShares}}
<li data-share-id="{{cid}}">
<div class="avatar icon-public-white"></div><span class="username" title="{{linkShareLabel}}">{{linkShareLabel}}</span>
<span class="sharingOptionsGroup">
<div class="share-menu" tabindex="0"><span class="icon icon-more"></span>
{{#if showPending}}
{{{pendingPopoverMenu}}}
@ -16,9 +21,9 @@
{{{popoverMenu}}}
{{/if}}
</div>
{{/if}}
</span>
</li>
</span>
</li>
{{/each}}
</ul>
{{else}}
{{#if noSharingPlaceholder}}<input id="shareWith-{{cid}}" class="shareWithField" type="text" placeholder="{{noSharingPlaceholder}}" disabled="disabled"/>{{/if}}

View File

@ -6,6 +6,13 @@
<span>{{copyLabel}}</span>
</a>
</li>
<li>
<a href="#" class="new-share">
<span class="icon-loading-small hidden"></span>
<span class="icon icon-add"></span>
<span>{{newShareTitle}}</span>
</a>
</li>
<li class="hidden linkTextMenu">
<span class="menuitem icon-link-text">
<input id="linkText-{{cid}}" class="linkText" type="text" readonly="readonly" value="{{shareLinkURL}}" />
@ -70,14 +77,15 @@
<li>
<span class="shareOption menuitem">
<input id="expireDate-{{cid}}" type="checkbox" name="expirationDate" class="expireDate checkbox"
{{#if hasExpireDate}}checked="checked"{{/if}} {{#if isExpirationEnforced}}disabled="disabled"{{/if}}" />
{{#if hasExpireDate}}checked="checked"{{/if}} {{#if isExpirationEnforced}}disabled="disabled"{{/if}} />
<label for="expireDate-{{cid}}">{{expireDateLabel}}</label>
</span>
</li>
<li class="{{#unless hasExpireDate}}hidden{{/unless}}">
<span class="menuitem icon-expiredate expirationDateContainer-{{cid}}">
<label for="expirationDatePicker-{{cid}}" class="hidden-visually" value="{{expirationDate}}">{{expirationLabel}}</label>
<input id="expirationDatePicker-{{cid}}" class="datepicker" type="text" placeholder="{{expirationDatePlaceholder}}" value="{{#if hasExpireDate}}{{expireDate}}{{else}}{{defaultExpireDate}}{{/if}}" />
<input id="expirationDatePicker-{{cid}}" class="datepicker" type="text" placeholder="{{expirationDatePlaceholder}}"
value="{{#if hasExpireDate}}{{expireDate}}{{else}}{{defaultExpireDate}}{{/if}}" data-max-date="{{maxDate}}" />
</span>
</li>
<li>
@ -88,7 +96,7 @@
<input type="button" class="share-note-delete icon-delete">
</a>
</li>
<li class="share-note-form share-note-link hidden">
<li class="share-note-form share-note-link {{#unless hasNote}}hidden{{/unless}}">
<span class="menuitem icon-note">
<textarea class="share-note">{{shareNote}}</textarea>
<input type="submit" class="icon-confirm share-note-submit" value="" id="add-note-{{shareId}}" />
@ -102,5 +110,8 @@
</a>
</li>
{{/each}}
<li>
<a href="#" class="unshare"><span class="icon-loading-small hidden"></span><span class="icon icon-delete"></span><span>{{unshareLabel}}</span></a>
</li>
</ul>
</div>

View File

@ -15,7 +15,7 @@
</div>
</span>
</li>
{{/each}}
{{/each}}
{{#each linkReshares}}
<li data-share-id="{{shareId}}" data-share-type="{{shareType}}">
<div class="avatar" data-username="{{shareInitiator}}"></div>

View File

@ -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;
}
// hide all icons and show loading
this.$el.find('.icon').addClass('hidden');
$loading.removeClass('hidden');
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()
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');
}
} else {
if (this.model.get('linkShare').isLinkShare) {
$loading.removeClass('hidden');
this.model.removeLinkShare();
} else {
this.showPending = false;
this.render()
}
}
})
},
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;

View File

@ -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);

View File

@ -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 "<ul id=\"shareLink\" class=\"shareWithList\">\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 : "")
+ "</ul>\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 " <li>\n <div class=\"avatar icon-public-white\"></div>\n <span class=\"username\">"
+ 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)))
+ "</span>\n <span class=\"sharingOptionsGroup\">\n <span class=\"icon icon-add new-share\" title=\""
+ 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)))
+ "\"></span>\n <span class=\"icon icon-loading-small hidden\"></span>\n </span>\n </li>\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 "<ul id=\"shareLink\" class=\"shareWithList\">\n <li data-share-id=\""
return " <li data-share-id=\""
+ 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 <div class=\"avatar icon-public-white\"></div><span class=\"username\" title=\""
+ "\">\n <div class=\"avatar icon-public-white\"></div><span class=\"username\" title=\""
+ 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)))
+ "\">"
+ 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)))
+ "</span>\n <span class=\"sharingOptionsGroup\">\n <span class=\"shareOption\">\n <span class=\"icon-loading-small hidden\"></span>\n <input id=\"linkCheckbox-"
+ 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)))
+ "\" "
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.isLinkShare : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ " type=\"checkbox\" name=\"linkCheckbox\" class=\"linkCheckbox permissions checkbox\">\n <label for=\"linkCheckbox-"
+ 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.linkShareEnableLabel || (depth0 != null ? depth0.linkShareEnableLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"linkShareEnableLabel","hash":{},"data":data}) : helper)))
+ "</label>\n </span>\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 : "")
+ " </span>\n </li>\n</ul>\n";
},"2":function(container,depth0,helpers,partials,data) {
return "checked=\"checked\"";
},"4":function(container,depth0,helpers,partials,data) {
var stack1;
return " <div class=\"share-menu\" tabindex=\"0\"><span class=\"icon icon-more\"></span>\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 : "")
+ " </div>\n";
+ "</span>\n <span class=\"sharingOptionsGroup\">\n <div class=\"share-menu\" tabindex=\"0\"><span class=\"icon icon-more\"></span>\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 : "")
+ " </div>\n </span>\n </li>\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 <span class=\"icon icon-clippy\" ></span>\n <span>"
+ 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)))
+ "</span>\n </a>\n </li>\n <li>\n <a href=\"#\" class=\"new-share\">\n <span class=\"icon-loading-small hidden\"></span>\n <span class=\"icon icon-add\"></span>\n <span>"
+ 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)))
+ "</span>\n </a>\n </li>\n <li class=\"hidden linkTextMenu\">\n <span class=\"menuitem icon-link-text\">\n <input id=\"linkText-"
+ 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=\"linkText\" type=\"text\" readonly=\"readonly\" value=\""
@ -184,7 +185,7 @@ templates['sharedialoglinkshareview_popover_menu'] = template({"1":function(cont
+ ((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(9, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ "\" />\n <label for=\"expireDate-"
+ " />\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)))
@ -202,17 +203,23 @@ templates['sharedialoglinkshareview_popover_menu'] = template({"1":function(cont
+ 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=\"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=\""
+ "\"\n value=\""
+ ((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 : "")
+ "\" data-max-date=\""
+ alias4(((helper = (helper = helpers.maxDate || (depth0 != null ? depth0.maxDate : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"maxDate","hash":{},"data":data}) : helper)))
+ "\" />\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\">"
+ "</span>\n <input type=\"button\" class=\"share-note-delete icon-delete\">\n </a>\n </li>\n <li class=\"share-note-form share-note-link "
+ ((stack1 = helpers.unless.call(alias1,(depth0 != null ? depth0.hasNote : depth0),{"name":"unless","hash":{},"fn":container.program(11, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ "\">\n <span class=\"menuitem icon-note\">\n <textarea class=\"share-note\">"
+ alias4(((helper = (helper = helpers.shareNote || (depth0 != null ? depth0.shareNote : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"shareNote","hash":{},"data":data}) : helper)))
+ "</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(17, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ " </ul>\n</div>\n";
+ " <li>\n <a href=\"#\" class=\"unshare\"><span class=\"icon-loading-small hidden\"></span><span class=\"icon icon-delete\"></span><span>"
+ 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)))
+ "</span></a>\n </li>\n </ul>\n</div>\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;