server/apps/files_sharing/js/public.js
Daniel Calviño Sánchez 372e7acfaf Fix closing menu on second click in sharing page
When a "mouseup" event was triggered on any element except on the share
menu or its descendants the share menu was closed. The share menu toggle
is not a descendant of the share menu, so clicking on it when the share
menu was shown closed it by removing its "open" CSS class. However, once
that happened the click event was then handled by the share menu toggle,
which toggled the "open" CSS class in the share menu and thus added it
again. So, from the user point of view, nothing happened when clicking
on the share menu toggle if the share menu was open.

Now a "mouseup" event on the share menu toggle no longer closes the
share menu, and thus toggling the "open" CSS class when handling the
"click" event works as expected.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2017-12-21 12:37:35 +01:00

446 lines
13 KiB
JavaScript

/*
* Copyright (c) 2014
* @copyright Copyright (c) 2016, Björn Schießle <bjoern@schiessle.org>
*
* This file is licensed under the Affero General Public License version 3
* or later.
*
* See the COPYING-README file.
*
*/
/* global FileActions, Files, FileList */
/* global dragOptions, folderDropOptions */
if (!OCA.Sharing) {
OCA.Sharing = {};
}
if (!OCA.Files) {
OCA.Files = {};
}
/**
* @namespace
*/
OCA.Sharing.PublicApp = {
_initialized: false,
/**
* Initializes the public share app.
*
* @param $el container
*/
initialize: function ($el) {
var self = this;
var fileActions;
if (this._initialized) {
return;
}
fileActions = new OCA.Files.FileActions();
// default actions
fileActions.registerDefaultActions();
// legacy actions
fileActions.merge(window.FileActions);
// regular actions
fileActions.merge(OCA.Files.fileActions);
// in case apps would decide to register file actions later,
// replace the global object with this one
OCA.Files.fileActions = fileActions;
this._initialized = true;
this.initialDir = $('#dir').val();
var token = $('#sharingToken').val();
// file list mode ?
if ($el.find('#filestable').length) {
var filesClient = new OC.Files.Client({
host: OC.getHost(),
port: OC.getPort(),
userName: token,
// note: password not be required, the endpoint
// will recognize previous validation from the session
root: OC.getRootPath() + '/public.php/webdav',
useHTTPS: OC.getProtocol() === 'https'
});
this.fileList = new OCA.Files.FileList(
$el,
{
id: 'files.public',
scrollContainer: $('#content-wrapper'),
dragOptions: dragOptions,
folderDropOptions: folderDropOptions,
fileActions: fileActions,
detailsViewEnabled: false,
filesClient: filesClient,
enableUpload: true
}
);
this.files = OCA.Files.Files;
this.files.initialize();
// TODO: move to PublicFileList.initialize() once
// the code was split into a separate class
OC.Plugins.attach('OCA.Sharing.PublicFileList', this.fileList);
}
var mimetype = $('#mimetype').val();
var mimetypeIcon = $('#mimetypeIcon').val();
mimetypeIcon = mimetypeIcon.substring(0, mimetypeIcon.length - 3);
mimetypeIcon = mimetypeIcon + 'svg';
var previewSupported = $('#previewSupported').val();
if (typeof FileActions !== 'undefined') {
// Show file preview if previewer is available, images are already handled by the template
if (mimetype.substr(0, mimetype.indexOf('/')) !== 'image' && $('.publicpreview').length === 0) {
// Trigger default action if not download TODO
var action = FileActions.getDefault(mimetype, 'file', OC.PERMISSION_READ);
if (typeof action !== 'undefined') {
action($('#filename').val());
}
}
}
// dynamically load image previews
var bottomMargin = 350;
var previewWidth = $(window).width();
var previewHeight = $(window).height() - bottomMargin;
previewHeight = Math.max(200, previewHeight);
var params = {
x: Math.ceil(previewWidth * window.devicePixelRatio),
y: Math.ceil(previewHeight * window.devicePixelRatio),
a: 'true',
file: encodeURIComponent(this.initialDir + $('#filename').val()),
t: token,
scalingup: 0
};
var imgcontainer = $('<a href="' + $('#previewURL').val()
+ '" target="_blank"><img class="publicpreview" alt=""></a>');
var img = imgcontainer.find('.publicpreview');
img.css({
'max-width': previewWidth,
'max-height': previewHeight
});
var fileSize = parseInt($('#filesize').val(), 10);
var maxGifSize = parseInt($('#maxSizeAnimateGif').val(), 10);
if (mimetype === 'image/gif' &&
(maxGifSize === -1 || fileSize <= (maxGifSize * 1024 * 1024))) {
img.attr('src', $('#downloadURL').val());
imgcontainer.appendTo('#imgframe');
} else if (mimetype.substr(0, mimetype.indexOf('/')) === 'text' && window.btoa) {
// Undocumented Url to public WebDAV endpoint
var url = parent.location.protocol + '//' + location.host + OC.linkTo('', 'public.php/webdav');
$.ajax({
url: url,
headers: {
Authorization: 'Basic ' + btoa(token + ':'),
Range: 'bytes=0-1000'
}
}).then(function (data) {
self._showTextPreview(data, previewHeight);
});
} else if ((previewSupported === 'true' && mimetype.substr(0, mimetype.indexOf('/')) !== 'video') ||
mimetype.substr(0, mimetype.indexOf('/')) === 'image' &&
mimetype !== 'image/svg+xml') {
img.attr('src', OC.filePath('files_sharing', 'ajax', 'publicpreview.php') + '?' + OC.buildQueryString(params));
imgcontainer.appendTo('#imgframe');
} else if (mimetype.substr(0, mimetype.indexOf('/')) !== 'video') {
img.attr('src', OC.Util.replaceSVGIcon(mimetypeIcon));
img.attr('width', 128);
imgcontainer.appendTo('#imgframe');
}
else if (previewSupported === 'true') {
$('#imgframe > video').attr('poster', OC.filePath('files_sharing', 'ajax', 'publicpreview.php') + '?' + OC.buildQueryString(params));
}
if (this.fileList) {
// TODO: move this to a separate PublicFileList class that extends OCA.Files.FileList (+ unit tests)
this.fileList.getDownloadUrl = function (filename, dir, isDir) {
var path = dir || this.getCurrentDirectory();
if (_.isArray(filename)) {
filename = JSON.stringify(filename);
}
var params = {
path: path
};
if (filename) {
params.files = filename;
}
return OC.generateUrl('/s/' + token + '/download') + '?' + OC.buildQueryString(params);
};
this.fileList.getUploadUrl = function(fileName, dir) {
if (_.isUndefined(dir)) {
dir = this.getCurrentDirectory();
}
var pathSections = dir.split('/');
if (!_.isUndefined(fileName)) {
pathSections.push(fileName);
}
var encodedPath = '';
_.each(pathSections, function(section) {
if (section !== '') {
encodedPath += '/' + encodeURIComponent(section);
}
});
var base = '';
if (!this._uploader.isXHRUpload()) {
// also add auth in URL due to POST workaround
base = OC.getProtocol() + '://' + token + '@' + OC.getHost() + (OC.getPort() ? ':' + OC.getPort() : '');
}
return base + OC.getRootPath() + '/public.php/webdav' + encodedPath;
};
this.fileList.getAjaxUrl = function (action, params) {
params = params || {};
params.t = token;
return OC.filePath('files_sharing', 'ajax', action + '.php') + '?' + OC.buildQueryString(params);
};
this.fileList.linkTo = function (dir) {
return OC.generateUrl('/s/' + token + '', {dir: dir});
};
this.fileList.generatePreviewUrl = function (urlSpec) {
urlSpec = urlSpec || {};
if (!urlSpec.x) {
urlSpec.x = 32;
}
if (!urlSpec.y) {
urlSpec.y = 32;
}
urlSpec.x *= window.devicePixelRatio;
urlSpec.y *= window.devicePixelRatio;
urlSpec.x = Math.ceil(urlSpec.x);
urlSpec.y = Math.ceil(urlSpec.y);
urlSpec.t = $('#dirToken').val();
return OC.generateUrl('/apps/files_sharing/ajax/publicpreview.php?') + $.param(urlSpec);
};
this.fileList.updateEmptyContent = function() {
this.$el.find('#emptycontent .uploadmessage').text(
t('files_sharing', 'You can upload into this folder')
);
OCA.Files.FileList.prototype.updateEmptyContent.apply(this, arguments);
};
this.fileList._uploader.on('fileuploadadd', function(e, data) {
if (!data.headers) {
data.headers = {};
}
data.headers.Authorization = 'Basic ' + btoa(token + ':');
});
// do not allow sharing from the public page
delete this.fileList.fileActions.actions.all.Share;
this.fileList.changeDirectory(this.initialDir || '/', false, true);
// URL history handling
this.fileList.$el.on('changeDirectory', _.bind(this._onDirectoryChanged, this));
OC.Util.History.addOnPopStateHandler(_.bind(this._onUrlChanged, this));
$('#download').click(function (e) {
e.preventDefault();
OC.redirect(FileList.getDownloadUrl());
});
}
$(document).on('click', '#directLink', function () {
$(this).focus();
$(this).select();
});
$('.save-form').submit(function (event) {
event.preventDefault();
var remote = $(this).find('#remote_address').val();
var token = $('#sharingToken').val();
var owner = $('#save').data('owner');
var ownerDisplayName = $('#save').data('owner-display-name');
var name = $('#save').data('name');
var isProtected = $('#save').data('protected') ? 1 : 0;
OCA.Sharing.PublicApp._createFederatedShare(remote, token, owner, ownerDisplayName, name, isProtected);
});
$('#remote_address').on("keyup paste", function() {
if ($(this).val() === '') {
$('#save-button-confirm').prop('disabled', true);
} else {
$('#save-button-confirm').prop('disabled', false);
}
});
$('#save #save-button').click(function () {
$(this).hide();
$('.save-form').css('display', 'inline');
$('#remote_address').focus();
});
// legacy
window.FileList = this.fileList;
},
_showTextPreview: function (data, previewHeight) {
var textDiv = $('<div/>').addClass('text-preview');
textDiv.text(data);
textDiv.appendTo('#imgframe');
var divHeight = textDiv.height();
if (data.length > 999) {
var ellipsis = $('<div/>').addClass('ellipsis');
ellipsis.html('(&#133;)');
ellipsis.appendTo('#imgframe');
}
if (divHeight > previewHeight) {
textDiv.height(previewHeight);
}
},
_onDirectoryChanged: function (e) {
OC.Util.History.pushState({
// arghhhh, why is this not called "dir" !?
path: e.dir
});
},
_onUrlChanged: function (params) {
this.fileList.changeDirectory(params.path || params.dir, false, true);
},
/**
* fall back to old behaviour where we redirect the user to his server to mount
* the public link instead of creating a dedicated federated share
*
* @param remote
* @param token
* @param owner
* @param ownerDisplayName
* @param name
* @param isProtected
* @private
*/
_legacyCreateFederatedShare: function (remote, token, owner, ownerDisplayName, name, isProtected) {
var location = window.location.protocol + '//' + window.location.host + OC.webroot;
if(remote.substr(-1) !== '/') {
remote += '/'
}
var url = remote + 'index.php/apps/files#' + 'remote=' + encodeURIComponent(location) // our location is the remote for the other server
+ "&token=" + encodeURIComponent(token) + "&owner=" + encodeURIComponent(owner) +"&ownerDisplayName=" + encodeURIComponent(ownerDisplayName) + "&name=" + encodeURIComponent(name) + "&protected=" + isProtected;
if (remote.indexOf('://') > 0) {
OC.redirect(url);
} else {
// if no protocol is specified, we automatically detect it by testing https and http
// this check needs to happen on the server due to the Content Security Policy directive
$.get(OC.generateUrl('apps/files_sharing/testremote'), {remote: remote}).then(function (protocol) {
if (protocol !== 'http' && protocol !== 'https') {
OC.dialogs.alert(t('files_sharing', 'No compatible server found at {remote}', {remote: remote}),
t('files_sharing', 'Invalid server URL'));
} else {
OC.redirect(protocol + '://' + url);
}
});
}
},
_createFederatedShare: function (remote, token, owner, ownerDisplayName, name, isProtected) {
var toggleLoading = function() {
var iconClass = $('#save-button-confirm').attr('class');
var loading = iconClass.indexOf('icon-loading-small') !== -1;
if(loading) {
$('#save-button-confirm')
.removeClass("icon-loading-small")
.addClass("icon-confirm");
}
else {
$('#save-button-confirm')
.removeClass("icon-confirm")
.addClass("icon-loading-small");
}
};
toggleLoading();
if (remote.indexOf('@') === -1) {
this._legacyCreateFederatedShare(remote, token, owner, ownerDisplayName, name, isProtected);
toggleLoading();
return;
}
$.post(
OC.generateUrl('/apps/federatedfilesharing/createFederatedShare'),
{
'shareWith': remote,
'token': token
}
).done(
function (data) {
var url = data.remoteUrl;
if (url.indexOf('://') > 0) {
OC.redirect(url);
} else {
OC.redirect('http://' + url);
}
}
).fail(
function (jqXHR) {
OC.dialogs.alert(JSON.parse(jqXHR.responseText).message,
t('files_sharing', 'Failed to add the public link to your Nextcloud'));
toggleLoading();
}
);
}
};
$(document).ready(function () {
// FIXME: replace with OC.Plugins.register()
if (window.TESTING) {
return;
}
var App = OCA.Sharing.PublicApp;
// defer app init, to give a chance to plugins to register file actions
_.defer(function () {
App.initialize($('#preview'));
});
if (window.Files) {
// HACK: for oc-dialogs previews that depends on Files:
Files.generatePreviewUrl = function (urlSpec) {
return App.fileList.generatePreviewUrl(urlSpec);
};
}
$('#share-menutoggle').click(function() {
$('#share-menu').toggleClass('open');
});
});
$(document).mouseup(function(e) {
var toggle = $('#share-menutoggle');
var container = $('#share-menu');
// if the target of the click isn't the menu toggle, nor a descendant of the
// menu toggle, nor the container nor a descendant of the container
if (!toggle.is(e.target) && toggle.has(e.target).length === 0 &&
!container.is(e.target) && container.has(e.target).length === 0) {
container.removeClass('open');
}
});