2015-07-30 22:07:41 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2015
|
|
|
|
*
|
|
|
|
* This file is licensed under the Affero General Public License version 3
|
|
|
|
* or later.
|
|
|
|
*
|
|
|
|
* See the COPYING-README file.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-08-19 19:03:25 +00:00
|
|
|
/* globals Handlebars */
|
|
|
|
|
2015-07-30 22:07:41 +00:00
|
|
|
(function() {
|
|
|
|
if(!OC.Share) {
|
|
|
|
OC.Share = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
var TEMPLATE_BASE =
|
2015-09-28 13:57:57 +00:00
|
|
|
'<div class="resharerInfoView subView"></div>' +
|
2015-09-15 13:29:30 +00:00
|
|
|
'{{#if isSharingAllowed}}' +
|
2015-10-16 08:54:45 +00:00
|
|
|
'<label for="shareWith-{{cid}}" class="hidden-visually">{{shareLabel}}</label>' +
|
2015-08-07 22:23:06 +00:00
|
|
|
'<div class="oneline">' +
|
2015-10-16 08:54:45 +00:00
|
|
|
' <input id="shareWith-{{cid}}" class="shareWithField" type="text" placeholder="{{sharePlaceholder}}" />' +
|
2015-08-07 22:23:06 +00:00
|
|
|
' <span class="shareWithLoading icon-loading-small hidden"></span>'+
|
2017-11-16 16:27:20 +00:00
|
|
|
' <span class="shareWithConfirm icon icon-confirm"></span>' +
|
2015-09-15 14:14:29 +00:00
|
|
|
'</div>' +
|
2015-09-15 13:29:30 +00:00
|
|
|
'{{/if}}' +
|
2015-09-28 13:57:57 +00:00
|
|
|
'<div class="shareeListView subView"></div>' +
|
|
|
|
'<div class="linkShareView subView"></div>' +
|
|
|
|
'<div class="expirationView subView"></div>' +
|
|
|
|
'<div class="loading hidden" style="height: 50px"></div>';
|
2015-07-30 22:07:41 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @class OCA.Share.ShareDialogView
|
2015-08-07 22:23:06 +00:00
|
|
|
* @member {OC.Share.ShareItemModel} model
|
|
|
|
* @member {jQuery} $el
|
|
|
|
* @memberof OCA.Sharing
|
2015-07-30 22:07:41 +00:00
|
|
|
* @classdesc
|
|
|
|
*
|
|
|
|
* Represents the GUI of the share dialogue
|
|
|
|
*
|
|
|
|
*/
|
2015-08-07 22:23:06 +00:00
|
|
|
var ShareDialogView = OC.Backbone.View.extend({
|
|
|
|
/** @type {Object} **/
|
2015-07-30 22:07:41 +00:00
|
|
|
_templates: {},
|
|
|
|
|
2015-08-07 22:23:06 +00:00
|
|
|
/** @type {boolean} **/
|
2015-07-30 22:07:41 +00:00
|
|
|
_showLink: true,
|
|
|
|
|
2015-08-07 22:23:06 +00:00
|
|
|
/** @type {string} **/
|
|
|
|
tagName: 'div',
|
|
|
|
|
2015-08-13 00:38:14 +00:00
|
|
|
/** @type {OC.Share.ShareConfigModel} **/
|
|
|
|
configModel: undefined,
|
|
|
|
|
2015-08-18 22:04:16 +00:00
|
|
|
/** @type {object} **/
|
|
|
|
resharerInfoView: undefined,
|
|
|
|
|
2015-08-21 13:40:50 +00:00
|
|
|
/** @type {object} **/
|
|
|
|
linkShareView: undefined,
|
|
|
|
|
2015-08-21 17:35:13 +00:00
|
|
|
/** @type {object} **/
|
|
|
|
expirationView: undefined,
|
|
|
|
|
2015-09-01 10:43:04 +00:00
|
|
|
/** @type {object} **/
|
|
|
|
shareeListView: undefined,
|
|
|
|
|
2018-03-20 12:14:26 +00:00
|
|
|
/** @type {object} **/
|
|
|
|
_lastSuggestions: undefined,
|
|
|
|
|
2018-03-20 15:58:04 +00:00
|
|
|
/** @type {int} **/
|
|
|
|
_pendingOperationsCount: 0,
|
|
|
|
|
2016-02-12 09:25:42 +00:00
|
|
|
events: {
|
2017-08-15 11:36:51 +00:00
|
|
|
'focus .shareWithField': 'onShareWithFieldFocus',
|
2018-03-19 17:54:27 +00:00
|
|
|
'input .shareWithField': 'onShareWithFieldChanged',
|
|
|
|
'click .shareWithConfirm': '_confirmShare'
|
2016-02-12 09:25:42 +00:00
|
|
|
},
|
|
|
|
|
2015-08-13 00:38:14 +00:00
|
|
|
initialize: function(options) {
|
2015-08-11 20:36:28 +00:00
|
|
|
var view = this;
|
|
|
|
|
|
|
|
this.model.on('fetchError', function() {
|
|
|
|
OC.Notification.showTemporary(t('core', 'Share details could not be loaded for this item.'));
|
|
|
|
});
|
2015-08-13 00:38:14 +00:00
|
|
|
|
|
|
|
if(!_.isUndefined(options.configModel)) {
|
|
|
|
this.configModel = options.configModel;
|
|
|
|
} else {
|
2015-08-24 21:20:01 +00:00
|
|
|
throw 'missing OC.Share.ShareConfigModel';
|
2015-08-13 00:38:14 +00:00
|
|
|
}
|
2015-08-18 22:04:16 +00:00
|
|
|
|
2015-09-12 12:21:14 +00:00
|
|
|
this.configModel.on('change:isRemoteShareAllowed', function() {
|
|
|
|
view.render();
|
|
|
|
});
|
2015-09-15 13:29:30 +00:00
|
|
|
this.model.on('change:permissions', function() {
|
|
|
|
view.render();
|
|
|
|
});
|
2015-09-12 12:21:14 +00:00
|
|
|
|
2015-09-28 13:57:57 +00:00
|
|
|
this.model.on('request', this._onRequest, this);
|
|
|
|
this.model.on('sync', this._onEndRequest, this);
|
|
|
|
|
2015-08-18 22:04:16 +00:00
|
|
|
var subViewOptions = {
|
|
|
|
model: this.model,
|
|
|
|
configModel: this.configModel
|
|
|
|
};
|
|
|
|
|
2015-08-21 18:05:50 +00:00
|
|
|
var subViews = {
|
|
|
|
resharerInfoView: 'ShareDialogResharerInfoView',
|
|
|
|
linkShareView: 'ShareDialogLinkShareView',
|
2015-08-25 14:07:14 +00:00
|
|
|
expirationView: 'ShareDialogExpirationView',
|
2016-11-02 10:37:25 +00:00
|
|
|
shareeListView: 'ShareDialogShareeListView'
|
2015-08-21 18:05:50 +00:00
|
|
|
};
|
2015-08-21 17:35:13 +00:00
|
|
|
|
2015-08-21 18:05:50 +00:00
|
|
|
for(var name in subViews) {
|
|
|
|
var className = subViews[name];
|
|
|
|
this[name] = _.isUndefined(options[name])
|
|
|
|
? new OC.Share[className](subViewOptions)
|
|
|
|
: options[name];
|
|
|
|
}
|
2015-09-05 00:02:55 +00:00
|
|
|
|
2016-02-12 09:25:42 +00:00
|
|
|
_.bindAll(this,
|
|
|
|
'autocompleteHandler',
|
|
|
|
'_onSelectRecipient',
|
2017-08-15 11:36:51 +00:00
|
|
|
'onShareWithFieldChanged',
|
|
|
|
'onShareWithFieldFocus'
|
2016-02-12 09:25:42 +00:00
|
|
|
);
|
2017-02-24 14:45:47 +00:00
|
|
|
|
2017-04-28 07:48:33 +00:00
|
|
|
OC.Plugins.attach('OC.Share.ShareDialogView', this);
|
2016-02-12 09:25:42 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
onShareWithFieldChanged: function() {
|
|
|
|
var $el = this.$el.find('.shareWithField');
|
|
|
|
if ($el.val().length < 2) {
|
|
|
|
$el.removeClass('error').tooltip('hide');
|
|
|
|
}
|
2015-09-05 00:02:55 +00:00
|
|
|
},
|
|
|
|
|
2017-08-15 11:36:51 +00:00
|
|
|
/* trigger search after the field was re-selected */
|
|
|
|
onShareWithFieldFocus: function() {
|
|
|
|
this.$el.find('.shareWithField').autocomplete("search");
|
|
|
|
},
|
|
|
|
|
2018-03-16 16:19:47 +00:00
|
|
|
_getSuggestions: function(searchTerm, perPage, model) {
|
2018-03-20 12:14:26 +00:00
|
|
|
if (this._lastSuggestions &&
|
|
|
|
this._lastSuggestions.searchTerm === searchTerm &&
|
|
|
|
this._lastSuggestions.perPage === perPage &&
|
|
|
|
this._lastSuggestions.model === model) {
|
|
|
|
return this._lastSuggestions.promise;
|
|
|
|
}
|
|
|
|
|
2018-03-16 16:19:47 +00:00
|
|
|
var deferred = $.Deferred();
|
2017-02-21 23:07:07 +00:00
|
|
|
|
2015-12-23 09:16:57 +00:00
|
|
|
$.get(
|
|
|
|
OC.linkToOCS('apps/files_sharing/api/v1') + 'sharees',
|
|
|
|
{
|
|
|
|
format: 'json',
|
2018-03-16 16:19:47 +00:00
|
|
|
search: searchTerm,
|
2017-02-21 23:07:07 +00:00
|
|
|
perPage: perPage,
|
2018-03-16 16:19:47 +00:00
|
|
|
itemType: model.get('itemType')
|
2015-12-23 09:16:57 +00:00
|
|
|
},
|
|
|
|
function (result) {
|
2016-08-19 19:03:25 +00:00
|
|
|
if (result.ocs.meta.statuscode === 100) {
|
2018-03-19 15:57:16 +00:00
|
|
|
var filter = function(users, groups, remotes, emails, circles) {
|
Return also exact matches besides all suggestions
"_getSuggestions" returned all the suggestions from the server, which
are composed by exact matches and partial matches. Now the exact matches
are also returned on their own parameter. This will be used by the
button to confirm a share.
Note that until now the order of the suggestions was "exact users,
partial users, exact groups, partial groups, exact..."; this commit also
changes that order to become "exact users, exact groups, exact...,
partial users, partial groups, partial...". This is not a problem, as
the suggestions were used in the autocomplete dropdown, and this new
order is arguably better than the old one, as all exact matches appear
now at the beginning.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-19 16:16:11 +00:00
|
|
|
if (typeof(emails) === 'undefined') {
|
|
|
|
emails = [];
|
|
|
|
}
|
|
|
|
if (typeof(circles) === 'undefined') {
|
|
|
|
circles = [];
|
|
|
|
}
|
|
|
|
|
2018-03-19 15:57:16 +00:00
|
|
|
var usersLength;
|
|
|
|
var groupsLength;
|
|
|
|
var remotesLength;
|
|
|
|
var emailsLength;
|
|
|
|
var circlesLength;
|
|
|
|
|
|
|
|
var i, j;
|
2015-12-23 09:16:57 +00:00
|
|
|
|
2018-03-19 15:57:16 +00:00
|
|
|
//Filter out the current user
|
2015-12-23 09:38:53 +00:00
|
|
|
usersLength = users.length;
|
2018-03-19 15:57:16 +00:00
|
|
|
for (i = 0; i < usersLength; i++) {
|
|
|
|
if (users[i].value.shareWith === OC.currentUser) {
|
2015-12-23 09:38:53 +00:00
|
|
|
users.splice(i, 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-12-23 09:16:57 +00:00
|
|
|
|
2018-03-19 15:57:16 +00:00
|
|
|
// Filter out the owner of the share
|
|
|
|
if (model.hasReshare()) {
|
2015-12-23 09:16:57 +00:00
|
|
|
usersLength = users.length;
|
2018-03-19 15:57:16 +00:00
|
|
|
for (i = 0 ; i < usersLength; i++) {
|
|
|
|
if (users[i].value.shareWith === model.getReshareOwner()) {
|
|
|
|
users.splice(i, 1);
|
2015-12-23 09:16:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-03-19 15:57:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var shares = model.get('shares');
|
|
|
|
var sharesLength = shares.length;
|
|
|
|
|
|
|
|
// Now filter out all sharees that are already shared with
|
|
|
|
for (i = 0; i < sharesLength; i++) {
|
|
|
|
var share = shares[i];
|
|
|
|
|
|
|
|
if (share.share_type === OC.Share.SHARE_TYPE_USER) {
|
|
|
|
usersLength = users.length;
|
|
|
|
for (j = 0; j < usersLength; j++) {
|
|
|
|
if (users[j].value.shareWith === share.share_with) {
|
|
|
|
users.splice(j, 1);
|
|
|
|
break;
|
|
|
|
}
|
2015-12-23 09:16:57 +00:00
|
|
|
}
|
2018-03-19 15:57:16 +00:00
|
|
|
} else if (share.share_type === OC.Share.SHARE_TYPE_GROUP) {
|
|
|
|
groupsLength = groups.length;
|
|
|
|
for (j = 0; j < groupsLength; j++) {
|
|
|
|
if (groups[j].value.shareWith === share.share_with) {
|
|
|
|
groups.splice(j, 1);
|
|
|
|
break;
|
|
|
|
}
|
2015-12-23 09:16:57 +00:00
|
|
|
}
|
2018-03-19 15:57:16 +00:00
|
|
|
} else if (share.share_type === OC.Share.SHARE_TYPE_REMOTE) {
|
|
|
|
remotesLength = remotes.length;
|
|
|
|
for (j = 0; j < remotesLength; j++) {
|
|
|
|
if (remotes[j].value.shareWith === share.share_with) {
|
|
|
|
remotes.splice(j, 1);
|
|
|
|
break;
|
|
|
|
}
|
2016-07-29 13:38:31 +00:00
|
|
|
}
|
2018-03-19 15:57:16 +00:00
|
|
|
} else if (share.share_type === OC.Share.SHARE_TYPE_EMAIL) {
|
|
|
|
emailsLength = emails.length;
|
|
|
|
for (j = 0; j < emailsLength; j++) {
|
|
|
|
if (emails[j].value.shareWith === share.share_with) {
|
|
|
|
emails.splice(j, 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (share.share_type === OC.Share.SHARE_TYPE_CIRCLE) {
|
|
|
|
circlesLength = circles.length;
|
|
|
|
for (j = 0; j < circlesLength; j++) {
|
|
|
|
if (circles[j].value.shareWith === share.share_with) {
|
|
|
|
circles.splice(j, 1);
|
|
|
|
break;
|
|
|
|
}
|
2017-03-17 19:48:33 +00:00
|
|
|
}
|
|
|
|
}
|
2015-12-23 09:16:57 +00:00
|
|
|
}
|
2018-03-19 15:57:16 +00:00
|
|
|
};
|
|
|
|
|
Return also exact matches besides all suggestions
"_getSuggestions" returned all the suggestions from the server, which
are composed by exact matches and partial matches. Now the exact matches
are also returned on their own parameter. This will be used by the
button to confirm a share.
Note that until now the order of the suggestions was "exact users,
partial users, exact groups, partial groups, exact..."; this commit also
changes that order to become "exact users, exact groups, exact...,
partial users, partial groups, partial...". This is not a problem, as
the suggestions were used in the autocomplete dropdown, and this new
order is arguably better than the old one, as all exact matches appear
now at the beginning.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-19 16:16:11 +00:00
|
|
|
filter(
|
|
|
|
result.ocs.data.exact.users,
|
|
|
|
result.ocs.data.exact.groups,
|
|
|
|
result.ocs.data.exact.remotes,
|
|
|
|
result.ocs.data.exact.emails,
|
|
|
|
result.ocs.data.exact.circles
|
|
|
|
);
|
|
|
|
|
|
|
|
var exactUsers = result.ocs.data.exact.users;
|
|
|
|
var exactGroups = result.ocs.data.exact.groups;
|
|
|
|
var exactRemotes = result.ocs.data.exact.remotes;
|
|
|
|
var exactEmails = [];
|
|
|
|
if (typeof(result.ocs.data.emails) !== 'undefined') {
|
|
|
|
exactEmails = result.ocs.data.exact.emails;
|
|
|
|
}
|
|
|
|
var exactCircles = [];
|
|
|
|
if (typeof(result.ocs.data.circles) !== 'undefined') {
|
|
|
|
exactCircles = result.ocs.data.exact.circles;
|
|
|
|
}
|
|
|
|
|
|
|
|
var exactMatches = exactUsers.concat(exactGroups).concat(exactRemotes).concat(exactEmails).concat(exactCircles);
|
|
|
|
|
|
|
|
filter(
|
|
|
|
result.ocs.data.users,
|
|
|
|
result.ocs.data.groups,
|
|
|
|
result.ocs.data.remotes,
|
|
|
|
result.ocs.data.emails,
|
|
|
|
result.ocs.data.circles
|
|
|
|
);
|
|
|
|
|
|
|
|
var users = result.ocs.data.users;
|
|
|
|
var groups = result.ocs.data.groups;
|
|
|
|
var remotes = result.ocs.data.remotes;
|
|
|
|
var lookup = result.ocs.data.lookup;
|
|
|
|
var emails = [];
|
|
|
|
if (typeof(result.ocs.data.emails) !== 'undefined') {
|
|
|
|
emails = result.ocs.data.emails;
|
|
|
|
}
|
|
|
|
var circles = [];
|
|
|
|
if (typeof(result.ocs.data.circles) !== 'undefined') {
|
|
|
|
circles = result.ocs.data.circles;
|
|
|
|
}
|
2015-12-23 09:16:57 +00:00
|
|
|
|
Return also exact matches besides all suggestions
"_getSuggestions" returned all the suggestions from the server, which
are composed by exact matches and partial matches. Now the exact matches
are also returned on their own parameter. This will be used by the
button to confirm a share.
Note that until now the order of the suggestions was "exact users,
partial users, exact groups, partial groups, exact..."; this commit also
changes that order to become "exact users, exact groups, exact...,
partial users, partial groups, partial...". This is not a problem, as
the suggestions were used in the autocomplete dropdown, and this new
order is arguably better than the old one, as all exact matches appear
now at the beginning.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-19 16:16:11 +00:00
|
|
|
var suggestions = exactMatches.concat(users).concat(groups).concat(remotes).concat(emails).concat(circles).concat(lookup);
|
2015-12-23 09:16:57 +00:00
|
|
|
|
Return also exact matches besides all suggestions
"_getSuggestions" returned all the suggestions from the server, which
are composed by exact matches and partial matches. Now the exact matches
are also returned on their own parameter. This will be used by the
button to confirm a share.
Note that until now the order of the suggestions was "exact users,
partial users, exact groups, partial groups, exact..."; this commit also
changes that order to become "exact users, exact groups, exact...,
partial users, partial groups, partial...". This is not a problem, as
the suggestions were used in the autocomplete dropdown, and this new
order is arguably better than the old one, as all exact matches appear
now at the beginning.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-19 16:16:11 +00:00
|
|
|
deferred.resolve(suggestions, exactMatches);
|
2018-03-16 16:19:47 +00:00
|
|
|
} else {
|
2018-03-19 14:36:08 +00:00
|
|
|
deferred.reject(result.ocs.meta.message);
|
2018-03-16 16:19:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
).fail(function() {
|
|
|
|
deferred.reject();
|
|
|
|
});
|
2017-02-21 23:07:07 +00:00
|
|
|
|
2018-03-20 12:14:26 +00:00
|
|
|
this._lastSuggestions = {
|
|
|
|
searchTerm: searchTerm,
|
|
|
|
perPage: perPage,
|
|
|
|
model: model,
|
|
|
|
promise: deferred.promise()
|
|
|
|
};
|
|
|
|
|
|
|
|
return this._lastSuggestions.promise;
|
2018-03-16 16:19:47 +00:00
|
|
|
},
|
2017-02-21 23:07:07 +00:00
|
|
|
|
2018-03-16 16:19:47 +00:00
|
|
|
autocompleteHandler: function (search, response) {
|
|
|
|
var $shareWithField = $('.shareWithField'),
|
|
|
|
view = this,
|
|
|
|
$loading = this.$el.find('.shareWithLoading'),
|
|
|
|
$confirm = this.$el.find('.shareWithConfirm');
|
2017-02-21 23:22:06 +00:00
|
|
|
|
2018-03-16 16:19:47 +00:00
|
|
|
var count = oc_config['sharing.minSearchStringLength'];
|
|
|
|
if (search.term.trim().length < count) {
|
|
|
|
var title = n('core',
|
|
|
|
'At least {count} character is needed for autocompletion',
|
|
|
|
'At least {count} characters are needed for autocompletion',
|
|
|
|
count,
|
|
|
|
{ count: count }
|
|
|
|
);
|
|
|
|
$shareWithField.addClass('error')
|
|
|
|
.attr('data-original-title', title)
|
|
|
|
.tooltip('hide')
|
|
|
|
.tooltip({
|
|
|
|
placement: 'bottom',
|
|
|
|
trigger: 'manual'
|
|
|
|
})
|
|
|
|
.tooltip('fixTitle')
|
|
|
|
.tooltip('show');
|
|
|
|
response();
|
|
|
|
return;
|
|
|
|
}
|
2017-02-21 23:07:07 +00:00
|
|
|
|
2018-03-16 16:19:47 +00:00
|
|
|
$loading.removeClass('hidden');
|
|
|
|
$loading.addClass('inlineblock');
|
|
|
|
$confirm.addClass('hidden');
|
2018-03-20 15:58:04 +00:00
|
|
|
this._pendingOperationsCount++;
|
2018-03-16 16:19:47 +00:00
|
|
|
|
|
|
|
$shareWithField.removeClass('error')
|
|
|
|
.tooltip('hide');
|
|
|
|
|
|
|
|
var perPage = 200;
|
|
|
|
this._getSuggestions(
|
|
|
|
search.term.trim(),
|
|
|
|
perPage,
|
|
|
|
view.model
|
|
|
|
).done(function(suggestions) {
|
2018-03-20 15:58:04 +00:00
|
|
|
view._pendingOperationsCount--;
|
|
|
|
if (view._pendingOperationsCount === 0) {
|
|
|
|
$loading.addClass('hidden');
|
|
|
|
$loading.removeClass('inlineblock');
|
|
|
|
$confirm.removeClass('hidden');
|
|
|
|
}
|
2018-03-16 16:19:47 +00:00
|
|
|
|
2018-03-19 14:36:08 +00:00
|
|
|
if (suggestions.length > 0) {
|
2018-03-16 16:19:47 +00:00
|
|
|
$shareWithField
|
|
|
|
.autocomplete("option", "autoFocus", true);
|
|
|
|
|
|
|
|
response(suggestions);
|
|
|
|
|
|
|
|
// show a notice that the list is truncated
|
|
|
|
// this is the case if one of the search results is at least as long as the max result config option
|
|
|
|
if(oc_config['sharing.maxAutocompleteResults'] > 0 &&
|
|
|
|
Math.min(perPage, oc_config['sharing.maxAutocompleteResults'])
|
|
|
|
<= Math.max(users.length, groups.length, remotes.length, emails.length, lookup.length)) {
|
|
|
|
|
|
|
|
var message = t('core', 'This list is maybe truncated - please refine your search term to see more results.');
|
|
|
|
$('.ui-autocomplete').append('<li class="autocomplete-note">' + message + '</li>');
|
2015-12-23 09:16:57 +00:00
|
|
|
}
|
2018-03-16 16:19:47 +00:00
|
|
|
|
2018-03-19 14:36:08 +00:00
|
|
|
} else {
|
2018-03-16 16:19:47 +00:00
|
|
|
var title = t('core', 'No users or groups found for {search}', {search: $shareWithField.val()});
|
|
|
|
if (!view.configModel.get('allowGroupSharing')) {
|
|
|
|
title = t('core', 'No users found for {search}', {search: $('.shareWithField').val()});
|
|
|
|
}
|
|
|
|
$shareWithField.addClass('error')
|
|
|
|
.attr('data-original-title', title)
|
|
|
|
.tooltip('hide')
|
|
|
|
.tooltip({
|
|
|
|
placement: 'bottom',
|
|
|
|
trigger: 'manual'
|
|
|
|
})
|
|
|
|
.tooltip('fixTitle')
|
|
|
|
.tooltip('show');
|
|
|
|
response();
|
2015-09-05 00:02:55 +00:00
|
|
|
}
|
2018-03-19 14:36:08 +00:00
|
|
|
}).fail(function(message) {
|
2018-03-20 15:58:04 +00:00
|
|
|
view._pendingOperationsCount--;
|
|
|
|
if (view._pendingOperationsCount === 0) {
|
|
|
|
$loading.addClass('hidden');
|
|
|
|
$loading.removeClass('inlineblock');
|
|
|
|
$confirm.removeClass('hidden');
|
|
|
|
}
|
2018-03-19 14:36:08 +00:00
|
|
|
|
|
|
|
if (message) {
|
|
|
|
OC.Notification.showTemporary(t('core', 'An error occurred ("{message}"). Please try again', { message: message }));
|
|
|
|
} else {
|
|
|
|
OC.Notification.showTemporary(t('core', 'An error occurred. Please try again'));
|
|
|
|
}
|
2015-09-05 00:02:55 +00:00
|
|
|
});
|
2015-08-11 20:36:28 +00:00
|
|
|
},
|
|
|
|
|
2015-09-12 10:17:15 +00:00
|
|
|
autocompleteRenderItem: function(ul, item) {
|
2016-10-06 15:12:10 +00:00
|
|
|
|
2015-09-12 10:17:15 +00:00
|
|
|
var text = item.label;
|
|
|
|
if (item.value.shareType === OC.Share.SHARE_TYPE_GROUP) {
|
2016-11-23 14:22:36 +00:00
|
|
|
text = t('core', '{sharee} (group)', { sharee: text }, undefined, { escape: false });
|
2015-09-12 10:17:15 +00:00
|
|
|
} else if (item.value.shareType === OC.Share.SHARE_TYPE_REMOTE) {
|
2016-11-23 14:22:36 +00:00
|
|
|
text = t('core', '{sharee} (remote)', { sharee: text }, undefined, { escape: false });
|
2016-07-29 13:37:08 +00:00
|
|
|
} else if (item.value.shareType === OC.Share.SHARE_TYPE_EMAIL) {
|
2016-11-23 14:22:36 +00:00
|
|
|
text = t('core', '{sharee} (email)', { sharee: text }, undefined, { escape: false });
|
2017-03-17 19:48:33 +00:00
|
|
|
} 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});
|
2015-09-12 10:17:15 +00:00
|
|
|
}
|
2016-10-06 15:12:10 +00:00
|
|
|
var insert = $("<div class='share-autocomplete-item'/>");
|
|
|
|
var avatar = $("<div class='avatardiv'></div>").appendTo(insert);
|
2018-03-16 03:28:54 +00:00
|
|
|
if (item.value.shareType === OC.Share.SHARE_TYPE_USER || item.value.shareType === OC.Share.SHARE_TYPE_CIRCLE) {
|
2016-10-06 15:12:10 +00:00
|
|
|
avatar.avatar(item.value.shareWith, 32, undefined, undefined, undefined, item.label);
|
|
|
|
} else {
|
|
|
|
avatar.imageplaceholder(text, undefined, 32);
|
2015-09-12 10:17:15 +00:00
|
|
|
}
|
2016-10-06 15:12:10 +00:00
|
|
|
|
|
|
|
$("<div class='autocomplete-item-text'></div>")
|
|
|
|
.text(text)
|
|
|
|
.appendTo(insert);
|
|
|
|
insert.attr('title', item.value.shareWith);
|
|
|
|
insert = $("<a>")
|
|
|
|
.append(insert);
|
2015-09-12 10:17:15 +00:00
|
|
|
return $("<li>")
|
|
|
|
.addClass((item.value.shareType === OC.Share.SHARE_TYPE_GROUP) ? 'group' : 'user')
|
|
|
|
.append(insert)
|
|
|
|
.appendTo(ul);
|
|
|
|
},
|
|
|
|
|
2015-09-14 15:47:47 +00:00
|
|
|
_onSelectRecipient: function(e, s) {
|
2018-03-20 15:58:04 +00:00
|
|
|
var self = this;
|
|
|
|
|
2015-09-14 15:47:47 +00:00
|
|
|
e.preventDefault();
|
2018-03-20 11:02:49 +00:00
|
|
|
// Ensure that the keydown handler for the input field is not
|
|
|
|
// called; otherwise it would try to add the recipient again, which
|
|
|
|
// would fail.
|
|
|
|
e.stopImmediatePropagation();
|
2016-02-12 13:01:15 +00:00
|
|
|
$(e.target).attr('disabled', true)
|
|
|
|
.val(s.item.label);
|
2018-03-20 15:58:04 +00:00
|
|
|
|
2016-02-12 13:01:15 +00:00
|
|
|
var $loading = this.$el.find('.shareWithLoading');
|
2017-11-16 16:27:20 +00:00
|
|
|
var $confirm = this.$el.find('.shareWithConfirm');
|
2018-03-20 15:58:04 +00:00
|
|
|
|
|
|
|
$loading.removeClass('hidden');
|
|
|
|
$loading.addClass('inlineblock');
|
2017-11-16 16:27:20 +00:00
|
|
|
$confirm.addClass('hidden');
|
2018-03-20 15:58:04 +00:00
|
|
|
this._pendingOperationsCount++;
|
2016-02-12 13:01:15 +00:00
|
|
|
|
|
|
|
this.model.addShare(s.item.value, {success: function() {
|
2018-03-21 02:57:14 +00:00
|
|
|
// Adding a share changes the suggestions.
|
|
|
|
self._lastSuggestions = undefined;
|
|
|
|
|
2016-02-12 13:01:15 +00:00
|
|
|
$(e.target).val('')
|
|
|
|
.attr('disabled', false);
|
2018-03-20 15:58:04 +00:00
|
|
|
|
|
|
|
self._pendingOperationsCount--;
|
|
|
|
if (self._pendingOperationsCount === 0) {
|
|
|
|
$loading.addClass('hidden');
|
|
|
|
$loading.removeClass('inlineblock');
|
|
|
|
$confirm.removeClass('hidden');
|
|
|
|
}
|
2016-02-16 18:40:44 +00:00
|
|
|
}, error: function(obj, msg) {
|
|
|
|
OC.Notification.showTemporary(msg);
|
2016-02-17 08:19:21 +00:00
|
|
|
$(e.target).attr('disabled', false)
|
|
|
|
.autocomplete('search', $(e.target).val());
|
2018-03-20 15:58:04 +00:00
|
|
|
|
|
|
|
self._pendingOperationsCount--;
|
|
|
|
if (self._pendingOperationsCount === 0) {
|
|
|
|
$loading.addClass('hidden');
|
|
|
|
$loading.removeClass('inlineblock');
|
|
|
|
$confirm.removeClass('hidden');
|
|
|
|
}
|
2016-02-12 13:01:15 +00:00
|
|
|
}});
|
2015-09-14 15:47:47 +00:00
|
|
|
},
|
|
|
|
|
2018-03-19 17:54:27 +00:00
|
|
|
_confirmShare: function() {
|
|
|
|
var self = this;
|
|
|
|
var $shareWithField = $('.shareWithField');
|
|
|
|
var $loading = this.$el.find('.shareWithLoading');
|
|
|
|
var $confirm = this.$el.find('.shareWithConfirm');
|
|
|
|
|
|
|
|
$loading.removeClass('hidden');
|
|
|
|
$loading.addClass('inlineblock');
|
|
|
|
$confirm.addClass('hidden');
|
2018-03-20 15:58:04 +00:00
|
|
|
this._pendingOperationsCount++;
|
2018-03-19 17:54:27 +00:00
|
|
|
|
|
|
|
$shareWithField.prop('disabled', true);
|
|
|
|
|
2018-03-20 11:02:49 +00:00
|
|
|
// Disabling the autocompletion does not clear its search timeout;
|
|
|
|
// removing the focus from the input field does, but only if the
|
|
|
|
// autocompletion is not disabled when the field loses the focus.
|
|
|
|
// Thus, the field has to be disabled before disabling the
|
|
|
|
// autocompletion to prevent an old pending search result from
|
|
|
|
// appearing once the field is enabled again.
|
|
|
|
$shareWithField.autocomplete('close');
|
|
|
|
$shareWithField.autocomplete('disable');
|
|
|
|
|
2018-03-20 12:44:28 +00:00
|
|
|
var restoreUI = function() {
|
2018-03-20 15:58:04 +00:00
|
|
|
self._pendingOperationsCount--;
|
|
|
|
if (self._pendingOperationsCount === 0) {
|
|
|
|
$loading.addClass('hidden');
|
|
|
|
$loading.removeClass('inlineblock');
|
|
|
|
$confirm.removeClass('hidden');
|
|
|
|
}
|
2018-03-20 12:44:28 +00:00
|
|
|
|
|
|
|
$shareWithField.prop('disabled', false);
|
|
|
|
$shareWithField.focus();
|
|
|
|
};
|
|
|
|
|
2018-03-19 17:54:27 +00:00
|
|
|
var perPage = 200;
|
|
|
|
var onlyExactMatches = true;
|
|
|
|
this._getSuggestions(
|
|
|
|
$shareWithField.val(),
|
|
|
|
perPage,
|
|
|
|
this.model,
|
|
|
|
onlyExactMatches
|
|
|
|
).done(function(suggestions, exactMatches) {
|
|
|
|
if (suggestions.length === 0) {
|
2018-03-20 12:44:28 +00:00
|
|
|
restoreUI();
|
2018-03-19 17:54:27 +00:00
|
|
|
|
2018-03-20 11:02:49 +00:00
|
|
|
$shareWithField.autocomplete('enable');
|
|
|
|
|
2018-03-19 17:54:27 +00:00
|
|
|
// There is no need to show an error message here; it will
|
|
|
|
// be automatically shown when the autocomplete is activated
|
|
|
|
// again (due to the focus on the field) and it finds no
|
|
|
|
// matches.
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (exactMatches.length !== 1) {
|
2018-03-20 12:44:28 +00:00
|
|
|
restoreUI();
|
2018-03-19 17:54:27 +00:00
|
|
|
|
2018-03-20 11:02:49 +00:00
|
|
|
$shareWithField.autocomplete('enable');
|
|
|
|
|
2018-03-19 17:54:27 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var actionSuccess = function() {
|
2018-03-21 02:57:14 +00:00
|
|
|
// Adding a share changes the suggestions.
|
|
|
|
self._lastSuggestions = undefined;
|
|
|
|
|
2018-03-19 17:54:27 +00:00
|
|
|
$shareWithField.val('');
|
2018-03-20 12:44:28 +00:00
|
|
|
|
|
|
|
restoreUI();
|
2018-03-20 11:02:49 +00:00
|
|
|
|
|
|
|
$shareWithField.autocomplete('enable');
|
2018-03-19 17:54:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
var actionError = function(obj, msg) {
|
2018-03-20 12:44:28 +00:00
|
|
|
restoreUI();
|
2018-03-19 17:54:27 +00:00
|
|
|
|
2018-03-20 11:02:49 +00:00
|
|
|
$shareWithField.autocomplete('enable');
|
|
|
|
|
2018-03-19 17:54:27 +00:00
|
|
|
OC.Notification.showTemporary(msg);
|
|
|
|
};
|
|
|
|
|
|
|
|
self.model.addShare(exactMatches[0].value, {
|
|
|
|
success: actionSuccess,
|
|
|
|
error: actionError
|
|
|
|
});
|
|
|
|
}).fail(function(message) {
|
2018-03-20 12:44:28 +00:00
|
|
|
restoreUI();
|
2018-03-19 17:54:27 +00:00
|
|
|
|
2018-03-20 11:02:49 +00:00
|
|
|
$shareWithField.autocomplete('enable');
|
|
|
|
|
2018-03-19 17:54:27 +00:00
|
|
|
// There is no need to show an error message here; it will be
|
|
|
|
// automatically shown when the autocomplete is activated again
|
|
|
|
// (due to the focus on the field) and getting the suggestions
|
|
|
|
// fail.
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2015-09-28 13:57:57 +00:00
|
|
|
_toggleLoading: function(state) {
|
|
|
|
this._loading = state;
|
|
|
|
this.$el.find('.subView').toggleClass('hidden', state);
|
|
|
|
this.$el.find('.loading').toggleClass('hidden', !state);
|
|
|
|
},
|
|
|
|
|
|
|
|
_onRequest: function() {
|
|
|
|
// only show the loading spinner for the first request (for now)
|
|
|
|
if (!this._loadingOnce) {
|
|
|
|
this._toggleLoading(true);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
_onEndRequest: function() {
|
2015-10-02 14:35:33 +00:00
|
|
|
var self = this;
|
2015-09-28 13:57:57 +00:00
|
|
|
this._toggleLoading(false);
|
2015-10-02 14:35:33 +00:00
|
|
|
if (!this._loadingOnce) {
|
|
|
|
this._loadingOnce = true;
|
|
|
|
// the first time, focus on the share field after the spinner disappeared
|
2017-02-15 12:50:53 +00:00
|
|
|
if (!OC.Util.isIE()) {
|
|
|
|
_.defer(function () {
|
|
|
|
self.$('.shareWithField').focus();
|
|
|
|
});
|
|
|
|
}
|
2015-10-02 14:35:33 +00:00
|
|
|
}
|
2015-09-28 13:57:57 +00:00
|
|
|
},
|
|
|
|
|
2015-07-30 22:07:41 +00:00
|
|
|
render: function() {
|
2018-03-20 11:02:49 +00:00
|
|
|
var self = this;
|
2015-07-30 22:07:41 +00:00
|
|
|
var baseTemplate = this._getTemplate('base', TEMPLATE_BASE);
|
|
|
|
|
2015-08-07 22:23:06 +00:00
|
|
|
this.$el.html(baseTemplate({
|
2015-10-16 08:54:45 +00:00
|
|
|
cid: this.cid,
|
2015-07-30 22:07:41 +00:00
|
|
|
shareLabel: t('core', 'Share'),
|
|
|
|
sharePlaceholder: this._renderSharePlaceholderPart(),
|
2015-09-15 13:29:30 +00:00
|
|
|
isSharingAllowed: this.model.sharePermissionPossible()
|
2015-07-30 22:07:41 +00:00
|
|
|
}));
|
|
|
|
|
2015-10-16 08:54:45 +00:00
|
|
|
var $shareField = this.$el.find('.shareWithField');
|
2015-09-15 13:29:30 +00:00
|
|
|
if ($shareField.length) {
|
2018-03-20 11:02:49 +00:00
|
|
|
var shareFieldKeydownHandler = function(event) {
|
|
|
|
if (event.keyCode !== 13) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
self._confirmShare();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2015-09-15 13:29:30 +00:00
|
|
|
$shareField.autocomplete({
|
2016-02-16 15:23:09 +00:00
|
|
|
minLength: 1,
|
2015-09-15 13:29:30 +00:00
|
|
|
delay: 750,
|
2015-09-22 15:16:20 +00:00
|
|
|
focus: function(event) {
|
|
|
|
event.preventDefault();
|
|
|
|
},
|
2015-09-15 13:29:30 +00:00
|
|
|
source: this.autocompleteHandler,
|
|
|
|
select: this._onSelectRecipient
|
|
|
|
}).data('ui-autocomplete')._renderItem = this.autocompleteRenderItem;
|
2018-03-20 11:02:49 +00:00
|
|
|
|
|
|
|
$shareField.on('keydown', null, shareFieldKeydownHandler);
|
2015-09-15 13:29:30 +00:00
|
|
|
}
|
2015-09-05 00:02:55 +00:00
|
|
|
|
2015-08-21 17:35:13 +00:00
|
|
|
this.resharerInfoView.$el = this.$el.find('.resharerInfoView');
|
2015-08-21 13:00:15 +00:00
|
|
|
this.resharerInfoView.render();
|
|
|
|
|
2015-08-21 18:29:12 +00:00
|
|
|
this.linkShareView.$el = this.$el.find('.linkShareView');
|
|
|
|
this.linkShareView.render();
|
|
|
|
|
2015-08-21 17:35:13 +00:00
|
|
|
this.expirationView.$el = this.$el.find('.expirationView');
|
|
|
|
this.expirationView.render();
|
|
|
|
|
2015-08-25 14:07:14 +00:00
|
|
|
this.shareeListView.$el = this.$el.find('.shareeListView');
|
2015-09-01 10:43:04 +00:00
|
|
|
this.shareeListView.render();
|
2015-08-25 14:07:14 +00:00
|
|
|
|
2015-08-18 15:23:32 +00:00
|
|
|
this.$el.find('.hasTooltip').tooltip();
|
|
|
|
|
2015-08-07 22:23:06 +00:00
|
|
|
return this;
|
2015-07-30 22:07:41 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* sets whether share by link should be displayed or not. Default is
|
|
|
|
* true.
|
|
|
|
*
|
|
|
|
* @param {bool} showLink
|
|
|
|
*/
|
|
|
|
setShowLink: function(showLink) {
|
|
|
|
this._showLink = (typeof showLink === 'boolean') ? showLink : true;
|
2015-08-21 13:40:50 +00:00
|
|
|
this.linkShareView.showLink = this._showLink;
|
2015-07-30 22:07:41 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
_renderSharePlaceholderPart: function () {
|
2016-10-31 10:52:00 +00:00
|
|
|
var allowRemoteSharing = this.configModel.get('isRemoteShareAllowed');
|
|
|
|
var allowMailSharing = this.configModel.get('isMailShareAllowed');
|
2016-03-21 18:47:10 +00:00
|
|
|
|
2017-04-18 10:08:35 +00:00
|
|
|
if (!allowRemoteSharing && allowMailSharing) {
|
|
|
|
return t('core', 'Name or email address...');
|
2016-10-31 10:52:00 +00:00
|
|
|
}
|
2017-04-18 10:08:35 +00:00
|
|
|
if (allowRemoteSharing && !allowMailSharing) {
|
|
|
|
return t('core', 'Name or federated cloud ID...');
|
2016-10-31 10:52:00 +00:00
|
|
|
}
|
2017-04-18 10:08:35 +00:00
|
|
|
if (allowRemoteSharing && allowMailSharing) {
|
|
|
|
return t('core', 'Name, federated cloud ID or email address...');
|
2015-07-30 22:07:41 +00:00
|
|
|
}
|
2016-03-21 18:47:10 +00:00
|
|
|
|
2017-04-18 10:08:35 +00:00
|
|
|
return t('core', 'Name...');
|
2015-07-30 22:07:41 +00:00
|
|
|
},
|
|
|
|
|
2015-08-10 19:46:46 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {string} key - an identifier for the template
|
|
|
|
* @param {string} template - the HTML to be compiled by Handlebars
|
|
|
|
* @returns {Function} from Handlebars
|
|
|
|
* @private
|
|
|
|
*/
|
2015-07-30 22:07:41 +00:00
|
|
|
_getTemplate: function (key, template) {
|
|
|
|
if (!this._templates[key]) {
|
|
|
|
this._templates[key] = Handlebars.compile(template);
|
|
|
|
}
|
|
|
|
return this._templates[key];
|
|
|
|
},
|
|
|
|
|
2015-08-07 22:23:06 +00:00
|
|
|
});
|
2015-07-30 22:07:41 +00:00
|
|
|
|
|
|
|
OC.Share.ShareDialogView = ShareDialogView;
|
|
|
|
|
|
|
|
})();
|