123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529 |
- /*
- * Copyright (c) 2015
- *
- * This file is licensed under the Affero General Public License version 3
- * or later.
- *
- * See the COPYING-README file.
- *
- */
- /* globals Handlebars */
- (function() {
- if(!OC.Share) {
- OC.Share = {};
- }
- var TEMPLATE_BASE =
- '<div class="resharerInfoView subView"></div>' +
- '{{#if isSharingAllowed}}' +
- '<label for="shareWith-{{cid}}" class="hidden-visually">{{shareLabel}}</label>' +
- '<div class="oneline">' +
- ' <input id="shareWith-{{cid}}" class="shareWithField" type="text" placeholder="{{sharePlaceholder}}" />' +
- ' <span class="shareWithLoading icon-loading-small hidden"></span>'+
- '{{{shareInfo}}}' +
- '</div>' +
- '{{/if}}' +
- '<div class="shareeListView subView"></div>' +
- '<div class="linkShareView subView"></div>' +
- '<div class="expirationView subView"></div>' +
- '<div class="loading hidden" style="height: 50px"></div>';
- var TEMPLATE_SHARE_INFO =
- '<span class="icon icon-info shareWithRemoteInfo hasTooltip" ' +
- 'title="{{tooltip}}"></span>';
- /**
- * @class OCA.Share.ShareDialogView
- * @member {OC.Share.ShareItemModel} model
- * @member {jQuery} $el
- * @memberof OCA.Sharing
- * @classdesc
- *
- * Represents the GUI of the share dialogue
- *
- */
- var ShareDialogView = OC.Backbone.View.extend({
- /** @type {Object} **/
- _templates: {},
- /** @type {boolean} **/
- _showLink: true,
- /** @type {string} **/
- tagName: 'div',
- /** @type {OC.Share.ShareConfigModel} **/
- configModel: undefined,
- /** @type {object} **/
- resharerInfoView: undefined,
- /** @type {object} **/
- linkShareView: undefined,
- /** @type {object} **/
- expirationView: undefined,
- /** @type {object} **/
- shareeListView: undefined,
- events: {
- 'focus .shareWithField': 'onShareWithFieldFocus',
- 'input .shareWithField': 'onShareWithFieldChanged'
- },
- initialize: function(options) {
- var view = this;
- this.model.on('fetchError', function() {
- OC.Notification.showTemporary(t('core', 'Share details could not be loaded for this item.'));
- });
- if(!_.isUndefined(options.configModel)) {
- this.configModel = options.configModel;
- } else {
- throw 'missing OC.Share.ShareConfigModel';
- }
- this.configModel.on('change:isRemoteShareAllowed', function() {
- view.render();
- });
- this.model.on('change:permissions', function() {
- view.render();
- });
- this.model.on('request', this._onRequest, this);
- this.model.on('sync', this._onEndRequest, this);
- var subViewOptions = {
- model: this.model,
- configModel: this.configModel
- };
- var subViews = {
- resharerInfoView: 'ShareDialogResharerInfoView',
- linkShareView: 'ShareDialogLinkShareView',
- expirationView: 'ShareDialogExpirationView',
- shareeListView: 'ShareDialogShareeListView'
- };
- for(var name in subViews) {
- var className = subViews[name];
- this[name] = _.isUndefined(options[name])
- ? new OC.Share[className](subViewOptions)
- : options[name];
- }
- _.bindAll(this,
- 'autocompleteHandler',
- '_onSelectRecipient',
- 'onShareWithFieldChanged',
- 'onShareWithFieldFocus'
- );
- OC.Plugins.attach('OC.Share.ShareDialogView', this);
- },
- onShareWithFieldChanged: function() {
- var $el = this.$el.find('.shareWithField');
- if ($el.val().length < 2) {
- $el.removeClass('error').tooltip('hide');
- }
- },
- /* trigger search after the field was re-selected */
- onShareWithFieldFocus: function() {
- this.$el.find('.shareWithField').autocomplete("search");
- },
- autocompleteHandler: function (search, response) {
- var $shareWithField = $('.shareWithField'),
- view = this,
- $loading = this.$el.find('.shareWithLoading'),
- $shareInfo = this.$el.find('.shareWithRemoteInfo');
- 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;
- }
- $loading.removeClass('hidden');
- $loading.addClass('inlineblock');
- $shareInfo.addClass('hidden');
- $shareWithField.removeClass('error')
- .tooltip('hide');
- var perPage = 200;
- $.get(
- OC.linkToOCS('apps/files_sharing/api/v1') + 'sharees',
- {
- format: 'json',
- search: search.term.trim(),
- perPage: perPage,
- itemType: view.model.get('itemType')
- },
- function (result) {
- $loading.addClass('hidden');
- $loading.removeClass('inlineblock');
- $shareInfo.removeClass('hidden');
- if (result.ocs.meta.statuscode === 100) {
- var users = result.ocs.data.exact.users.concat(result.ocs.data.users);
- var groups = result.ocs.data.exact.groups.concat(result.ocs.data.groups);
- var remotes = result.ocs.data.exact.remotes.concat(result.ocs.data.remotes);
- var lookup = result.ocs.data.lookup;
- var emails = [],
- circles = [];
- if (typeof(result.ocs.data.emails) !== 'undefined') {
- emails = result.ocs.data.exact.emails.concat(result.ocs.data.emails);
- }
- if (typeof(result.ocs.data.circles) !== 'undefined') {
- circles = result.ocs.data.exact.circles.concat(result.ocs.data.circles);
- }
- var usersLength;
- var groupsLength;
- var remotesLength;
- var emailsLength;
- var circlesLength;
- var i, j;
- //Filter out the current user
- usersLength = users.length;
- for (i = 0; i < usersLength; i++) {
- if (users[i].value.shareWith === OC.currentUser) {
- users.splice(i, 1);
- break;
- }
- }
- // Filter out the owner of the share
- if (view.model.hasReshare()) {
- usersLength = users.length;
- for (i = 0 ; i < usersLength; i++) {
- if (users[i].value.shareWith === view.model.getReshareOwner()) {
- users.splice(i, 1);
- break;
- }
- }
- }
- var shares = view.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;
- }
- }
- } 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;
- }
- }
- } 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;
- }
- }
- } 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;
- }
- }
- }
- }
- var suggestions = users.concat(groups).concat(remotes).concat(emails).concat(circles).concat(lookup);
- if (suggestions.length > 0) {
- $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>');
- }
- } else {
- 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();
- }
- } else {
- response();
- }
- }
- ).fail(function() {
- $loading.addClass('hidden');
- $loading.removeClass('inlineblock');
- $shareInfo.removeClass('hidden');
- OC.Notification.show(t('core', 'An error occurred. Please try again'));
- window.setTimeout(OC.Notification.hide, 5000);
- });
- },
- autocompleteRenderItem: function(ul, item) {
- var text = item.label;
- if (item.value.shareType === OC.Share.SHARE_TYPE_GROUP) {
- text = t('core', '{sharee} (group)', { sharee: text }, undefined, { escape: false });
- } else if (item.value.shareType === OC.Share.SHARE_TYPE_REMOTE) {
- text = t('core', '{sharee} (remote)', { sharee: text }, undefined, { escape: false });
- } else if (item.value.shareType === OC.Share.SHARE_TYPE_EMAIL) {
- text = t('core', '{sharee} (email)', { sharee: text }, undefined, { escape: false });
- } 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});
- }
- 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);
- } else {
- avatar.imageplaceholder(text, undefined, 32);
- }
- $("<div class='autocomplete-item-text'></div>")
- .text(text)
- .appendTo(insert);
- insert.attr('title', item.value.shareWith);
- insert = $("<a>")
- .append(insert);
- return $("<li>")
- .addClass((item.value.shareType === OC.Share.SHARE_TYPE_GROUP) ? 'group' : 'user')
- .append(insert)
- .appendTo(ul);
- },
- _onSelectRecipient: function(e, s) {
- e.preventDefault();
- $(e.target).attr('disabled', true)
- .val(s.item.label);
- var $loading = this.$el.find('.shareWithLoading');
- $loading.removeClass('hidden')
- .addClass('inlineblock');
- var $shareInfo = this.$el.find('.shareWithRemoteInfo');
- $shareInfo.addClass('hidden');
- this.model.addShare(s.item.value, {success: function() {
- $(e.target).val('')
- .attr('disabled', false);
- $loading.addClass('hidden')
- .removeClass('inlineblock');
- $shareInfo.removeClass('hidden');
- }, error: function(obj, msg) {
- OC.Notification.showTemporary(msg);
- $(e.target).attr('disabled', false)
- .autocomplete('search', $(e.target).val());
- $loading.addClass('hidden')
- .removeClass('inlineblock');
- $shareInfo.removeClass('hidden');
- }});
- },
- _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() {
- var self = this;
- this._toggleLoading(false);
- if (!this._loadingOnce) {
- this._loadingOnce = true;
- // the first time, focus on the share field after the spinner disappeared
- if (!OC.Util.isIE()) {
- _.defer(function () {
- self.$('.shareWithField').focus();
- });
- }
- }
- },
- render: function() {
- var baseTemplate = this._getTemplate('base', TEMPLATE_BASE);
- this.$el.html(baseTemplate({
- cid: this.cid,
- shareLabel: t('core', 'Share'),
- sharePlaceholder: this._renderSharePlaceholderPart(),
- shareInfo: this._renderShareInfoPart(),
- isSharingAllowed: this.model.sharePermissionPossible()
- }));
- var $shareField = this.$el.find('.shareWithField');
- if ($shareField.length) {
- $shareField.autocomplete({
- minLength: 1,
- delay: 750,
- focus: function(event) {
- event.preventDefault();
- },
- source: this.autocompleteHandler,
- select: this._onSelectRecipient
- }).data('ui-autocomplete')._renderItem = this.autocompleteRenderItem;
- }
- this.resharerInfoView.$el = this.$el.find('.resharerInfoView');
- this.resharerInfoView.render();
- this.linkShareView.$el = this.$el.find('.linkShareView');
- this.linkShareView.render();
- this.expirationView.$el = this.$el.find('.expirationView');
- this.expirationView.render();
- this.shareeListView.$el = this.$el.find('.shareeListView');
- this.shareeListView.render();
- this.$el.find('.hasTooltip').tooltip();
- return this;
- },
- /**
- * 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;
- this.linkShareView.showLink = this._showLink;
- },
- _renderShareInfoPart: function() {
- var shareInfo = '';
- var infoTemplate = this._getShareInfoTemplate();
- if(this.configModel.get('isMailShareAllowed') && this.configModel.get('isRemoteShareAllowed')) {
- shareInfo = infoTemplate({
- tooltip: t('core', 'Share with other people by entering a user or group, a federated cloud ID or an email address.')
- });
- } else if(this.configModel.get('isRemoteShareAllowed')) {
- shareInfo = infoTemplate({
- tooltip: t('core', 'Share with other people by entering a user or group or a federated cloud ID.')
- });
- } else if(this.configModel.get('isMailShareAllowed')) {
- shareInfo = infoTemplate({
- tooltip: t('core', 'Share with other people by entering a user or group or an email address.')
- });
- }
- return shareInfo;
- },
- _renderSharePlaceholderPart: function () {
- var allowRemoteSharing = this.configModel.get('isRemoteShareAllowed');
- var allowMailSharing = this.configModel.get('isMailShareAllowed');
- if (!allowRemoteSharing && allowMailSharing) {
- return t('core', 'Name or email address...');
- }
- if (allowRemoteSharing && !allowMailSharing) {
- return t('core', 'Name or federated cloud ID...');
- }
- if (allowRemoteSharing && allowMailSharing) {
- return t('core', 'Name, federated cloud ID or email address...');
- }
- return t('core', 'Name...');
- },
- /**
- *
- * @param {string} key - an identifier for the template
- * @param {string} template - the HTML to be compiled by Handlebars
- * @returns {Function} from Handlebars
- * @private
- */
- _getTemplate: function (key, template) {
- if (!this._templates[key]) {
- this._templates[key] = Handlebars.compile(template);
- }
- return this._templates[key];
- },
- /**
- * returns the info template for remote sharing
- *
- * @returns {Function}
- * @private
- */
- _getShareInfoTemplate: function() {
- return this._getTemplate('shareInfo', TEMPLATE_SHARE_INFO);
- }
- });
- OC.Share.ShareDialogView = ShareDialogView;
- })();
|