Add expiration date handling in share tab

This commit is contained in:
Vincent Petry 2015-09-14 12:48:01 +02:00
parent c2ff2ca982
commit 8194d092e7
4 changed files with 147 additions and 25 deletions

View File

@ -126,6 +126,14 @@ a.unshare {
margin-right: 0; margin-right: 0;
} }
.shareTabView .error {
color: #e9322d;
border-color: #e9322d;
-webkit-box-shadow: 0 0 6px #f8b9b7;
-moz-box-shadow: 0 0 6px #f8b9b7;
box-shadow: 0 0 6px #f8b9b7;
}
#link #showPassword img { #link #showPassword img {
padding-left:5px; padding-left:5px;
width:12px; width:12px;

View File

@ -19,13 +19,13 @@
// in the LinkShareView to ease reusing it in future. Then, // in the LinkShareView to ease reusing it in future. Then,
// modifications (getting rid of IDs) are still necessary. // modifications (getting rid of IDs) are still necessary.
'{{#if isLinkShare}}' + '{{#if isLinkShare}}' +
'<input type="checkbox" name="expirationCheckbox" id="expirationCheckbox" value="1" ' + '<input type="checkbox" name="expirationCheckbox" class="expirationCheckbox" id="expirationCheckbox" value="1" ' +
'{{#if isExpirationSet}}checked="checked"{{/if}} {{#if disableCheckbox}}disabled="disabled"{{/if}} />' + '{{#if isExpirationSet}}checked="checked"{{/if}} {{#if disableCheckbox}}disabled="disabled"{{/if}} />' +
'<label for="expirationCheckbox">{{setExpirationLabel}}</label>' + '<label for="expirationCheckbox">{{setExpirationLabel}}</label>' +
' {{#if isExpirationSet}}' + '<div class="expirationDateContainer {{#unless isExpirationSet}}hidden{{/unless}}">' +
'<label for="expirationDate" class="hidden-visually" value="{{expirationDate}}">{{expirationLabel}}</label>' + ' <label for="expirationDate" class="hidden-visually" value="{{expirationDate}}">{{expirationLabel}}</label>' +
'<input id="expirationDate" class="datepicker" type="text" placeholder="{{expirationDatePlaceholder}}" value="{{expirationValue}}" />' + ' <input id="expirationDate" class="datepicker" type="text" placeholder="{{expirationDatePlaceholder}}" value="{{expirationValue}}" />' +
' {{/if}}' + '</div>' +
' {{#if isExpirationEnforced}}' + ' {{#if isExpirationEnforced}}' +
// originally the expire message was shown when a default date was set, however it never had text // originally the expire message was shown when a default date was set, however it never had text
'<em id="defaultExpireMessage">{{defaultExpireMessage}}</em>' + '<em id="defaultExpireMessage">{{defaultExpireMessage}}</em>' +
@ -58,6 +58,11 @@
className: 'hidden', className: 'hidden',
events: {
'change .expirationCheckbox': '_onToggleExpiration',
'change .datepicker': '_onChangeExpirationDate'
},
initialize: function(options) { initialize: function(options) {
if(!_.isUndefined(options.configModel)) { if(!_.isUndefined(options.configModel)) {
this.configModel = options.configModel; this.configModel = options.configModel;
@ -79,6 +84,38 @@
}); });
}, },
_onToggleExpiration: function(event) {
var $checkbox = $(event.target);
var state = $checkbox.prop('checked');
// TODO: slide animation
this.$el.find('.expirationDateContainer').toggleClass('hidden', !state);
if (!state) {
// discard expiration date
this.model.setExpirationDate('');
this.model.saveLinkShare();
}
},
_onChangeExpirationDate: function(event) {
var $target = $(event.target);
$target.tooltip('hide');
$target.removeClass('error');
this.model.setExpirationDate($target.val());
this.model.saveLinkShare(null, {
error: function(model, message) {
if (!message) {
$target.attr('title', t('core', 'Error setting expiration date'));
} else {
$target.attr('title', message);
}
$target.tooltip({gravity: 'n'});
$target.tooltip('show');
$target.addClass('error');
}
});
},
render: function() { render: function() {
var defaultExpireMessage = ''; var defaultExpireMessage = '';
var defaultExpireDays = this.configModel.get('defaultExpireDate'); var defaultExpireDays = this.configModel.get('defaultExpireDate');
@ -136,6 +173,8 @@
this.$el.find('.datepicker').datepicker({dateFormat : 'dd-mm-yy'}); this.$el.find('.datepicker').datepicker({dateFormat : 'dd-mm-yy'});
this.delegateEvents();
return this; return this;
}, },

View File

@ -108,7 +108,8 @@
if($checkBox.is(':checked')) { if($checkBox.is(':checked')) {
if(this.configModel.get('enforcePasswordForPublicLink') === false) { if(this.configModel.get('enforcePasswordForPublicLink') === false) {
$loading.removeClass('hidden'); $loading.removeClass('hidden');
this.model.addLinkShare(); // this will create it
this.model.saveLinkShare();
} else { } else {
this.$el.find('#linkPass').slideToggle(OC.menuSpeed); this.$el.find('#linkPass').slideToggle(OC.menuSpeed);
// TODO drop with IE8 drop // TODO drop with IE8 drop
@ -131,7 +132,8 @@
onShowPasswordClick: function() { onShowPasswordClick: function() {
this.$el.find('#linkPass').slideToggle(OC.menuSpeed); this.$el.find('#linkPass').slideToggle(OC.menuSpeed);
if(!this.$el.find('#showPassword').is(':checked')) { if(!this.$el.find('#showPassword').is(':checked')) {
this.model.addLinkShare({password: ''}); this.model.setPassword('');
this.model.saveLinkShare();
} else { } else {
this.$el.find('#linkPassText').focus(); this.$el.find('#linkPassText').focus();
} }
@ -147,13 +149,15 @@
.removeClass('hidden') .removeClass('hidden')
.addClass('inlineblock'); .addClass('inlineblock');
this.model.addLinkShare({password: password}); this.model.setPassword(password);
this.model.saveLinkShare();
}, },
onAllowPublicUploadChange: function() { onAllowPublicUploadChange: function() {
this.$el.find('#sharingDialogAllowPublicUpload') this.$el.find('#sharingDialogAllowPublicUpload')
.siblings('.icon-loading-small').removeClass('hidden').addClass('inlineblock'); .siblings('.icon-loading-small').removeClass('hidden').addClass('inlineblock');
this.model.setPublicUpload(this.$el.find('#sharingDialogAllowPublicUpload').is(':checked')); this.model.setPublicUpload(this.$el.find('#sharingDialogAllowPublicUpload').is(':checked'));
this.model.saveLinkShare();
}, },
render: function() { render: function() {
@ -205,6 +209,7 @@
mailButtonText: t('core', 'Send') mailButtonText: t('core', 'Send')
})); }));
// TODO: move this to delegate events instead
this.$el.find('#linkCheckbox').change(this.onLinkCheckBoxChange); this.$el.find('#linkCheckbox').change(this.onLinkCheckBoxChange);
this.$el.find('#sharingDialogAllowPublicUpload').change(this.onAllowPublicUploadChange); this.$el.find('#sharingDialogAllowPublicUpload').change(this.onAllowPublicUploadChange);
this.$el.find('#linkText').click(this.onLinkTextClick); this.$el.find('#linkText').click(this.onLinkTextClick);

View File

@ -70,6 +70,9 @@
* Represents the GUI of the share dialogue * Represents the GUI of the share dialogue
* *
* // FIXME: use OC Share API once #17143 is done * // FIXME: use OC Share API once #17143 is done
*
* // TODO: this really should be a collection of share item models instead,
* where the link share is one of them
*/ */
var ShareItemModel = OC.Backbone.Model.extend({ var ShareItemModel = OC.Backbone.Model.extend({
initialize: function(attributes, options) { initialize: function(attributes, options) {
@ -90,47 +93,114 @@
linkShare: {} linkShare: {}
}, },
addLinkShare: function(options) { /**
* Saves the current link share information.
*
* This will trigger an ajax call and refetch the model afterwards.
*
* TODO: this should be a separate model
*/
saveLinkShare: function(attributes, options) {
var model = this; var model = this;
var expiration = this.configModel.getDefaultExpirationDateString();
var itemType = this.get('itemType'); var itemType = this.get('itemType');
var itemSource = this.get('itemSource'); var itemSource = this.get('itemSource');
var options = options || {}; // TODO: use backbone's default value mechanism once this is a separate model
var requiredOptions = [ var requiredAttributes = [
{ name: 'password', defaultValue: '' }, { name: 'password', defaultValue: '' },
{ name: 'permissions', defaultValue: OC.PERMISSION_READ } { name: 'permissions', defaultValue: OC.PERMISSION_READ },
{ name: 'expiration', defaultValue: this.configModel.getDefaultExpirationDateString() }
]; ];
_.each(requiredOptions, function(option) {
attributes = attributes || {};
// get attributes from the model and fill in with default values
_.each(requiredAttributes, function(attribute) {
// a provided options overrides a present value of the link // a provided options overrides a present value of the link
// share. If neither is given, the default value is used. // share. If neither is given, the default value is used.
if(_.isUndefined(options[option.name])) { if(_.isUndefined(attribute[attribute.name])) {
options[option.name] = option.defaultValue; attributes[attribute.name] = attribute.defaultValue;
var currentValue = model.get('linkShare')[option.name]; var currentValue = model.get('linkShare')[attribute.name];
if(!_.isUndefined(currentValue)) { if(!_.isUndefined(currentValue)) {
options[option.name] = currentValue; attributes[attribute.name] = currentValue;
} }
} }
}); });
OC.Share.share(itemType, itemSource, OC.Share.SHARE_TYPE_LINK, options.password, options.permissions, this.fileInfoModel.get('name'), expiration, function(data) { OC.Share.share(
model.fetch(); itemType,
//FIXME: updateIcon belongs to view itemSource,
OC.Share.updateIcon(itemType, itemSource); OC.Share.SHARE_TYPE_LINK,
}); attributes.password,
attributes.permissions,
this.fileInfoModel.get('name'),
attributes.expiration,
function(result) {
if (!result || result.status !== 'success') {
model.fetch({
success: function() {
if (options && _.isFunction(options.success)) {
options.success(model);
}
}
});
} else {
if (options && _.isFunction(options.error)) {
options.error(model);
}
}
//FIXME: updateIcon belongs to view
OC.Share.updateIcon(itemType, itemSource);
},
function(result) {
var msg = t('core', 'Error');
if (result.data && result.data.message) {
msg = result.data.message;
}
if (options && _.isFunction(options.error)) {
options.error(model, msg);
} else {
OC.dialogs.alert(msg, t('core', 'Error while sharing'));
}
}
);
}, },
removeLinkShare: function() { removeLinkShare: function() {
this.removeShare(OC.Share.SHARE_TYPE_LINK, ''); this.removeShare(OC.Share.SHARE_TYPE_LINK, '');
}, },
/**
* Sets the public upload flag
*
* @param {bool} allow whether public upload is allowed
*/
setPublicUpload: function(allow) { setPublicUpload: function(allow) {
var permissions = OC.PERMISSION_READ; var permissions = OC.PERMISSION_READ;
if(allow) { if(allow) {
permissions = OC.PERMISSION_UPDATE + OC.PERMISSION_CREATE + OC.PERMISSION_READ; permissions = OC.PERMISSION_UPDATE | OC.PERMISSION_CREATE | OC.PERMISSION_READ;
} }
this.addLinkShare({permissions: permissions}); this.get('linkShare').permissions = permissions;
},
/**
* Sets the expiration date of the public link
*
* @param {string} expiration expiration date
*/
setExpirationDate: function(expiration) {
this.get('linkShare').expiration = expiration;
},
/**
* Set password of the public link share
*
* @param {string} password
*/
setPassword: function(password) {
this.get('linkShare').password = password;
}, },
addShare: function(event, selected, options) { addShare: function(event, selected, options) {