brouter-web/js/control/ShareRoute.js
2023-05-18 14:48:10 +02:00

150 lines
5.1 KiB
JavaScript

BR.ShareRoute = L.Class.extend({
/**
* Sharing via Mastodon is currently disabled by default, because
* the share intent fails when the current route URL is longer
* than the post character limit for that instance.
*/
options: {
services: {
mastodon: false,
},
shortcut: {
share_action: 65, // char code for 'a' ("action")
},
},
initialize: function () {
L.DomUtil.get('shareButton').onclick = L.bind(this.share, this);
L.DomEvent.addListener(document, 'keydown', this._keydownListener, this);
},
share: function (event) {
event.preventDefault();
this.services();
this.qrcode();
},
services: function () {
const self = this;
$('.share-copy-link').on('click', function () {
navigator.clipboard.writeText(self.getShareUrl());
});
$('a.share-service').each(function () {
$(this).attr('href', $(this).attr('href').replace('{url}', encodeURIComponent(self.getShareUrl())));
});
if (this.options.services.mastodon === true) {
$('.share-service-mastodon')
.removeAttr('hidden')
.on('click', function () {
let mastodonServer = window.prompt(
i18next.t('share.mastodon-enter-server-name'),
'mastodon.social'
);
if (mastodonServer.indexOf('http') !== 0) {
mastodonServer = 'https://' + mastodonServer;
}
window.open(mastodonServer + '/share?text=' + encodeURIComponent(self.getShareUrl()), '_blank');
});
}
},
/**
* Renders QR Code for the current route:
*
* - add query parameter `?export=dialog` to the current URL
* - displays QR Code for that URL in the dialog, size is automatically adjusted
* to the length of the URL
* - displays buttons to change the size of the QR Code (small, medium, large)
*/
qrcode: function () {
const exportUrl = this.createQrCodeUrl();
this.renderQrCode('share-qrcode-img', exportUrl, this.getQrCodeSizeForUrl(exportUrl));
$('.qrcode-size-button').on('click', { shareRoute: this, url: exportUrl }, function (event) {
event.data.shareRoute.renderQrCode('share-qrcode-img', event.data.url, $(this).data('qrcodeSize'));
});
},
getQrCodeSizeForUrl: function (url) {
if (url.length < 500) {
return 256;
}
if (url.length < 1700) {
return 384;
}
return 512;
},
renderQrCode: function (elementId, url, size) {
$('#share-qrcode-img').empty();
$('#qrcode-buttons').show();
$('#qrcode-msg-unknown-error').hide();
$('#qrcode-msg-too-long').hide();
try {
new QRCode(document.getElementById(elementId), {
text: url,
width: size,
height: size,
colorDark: '#000000',
colorLight: '#ffffff',
correctLevel: QRCode.CorrectLevel.M,
});
} catch (exception) {
$('#share-qrcode-img').empty();
$('#qrcode-buttons').hide();
if (exception.message === 'Too long data') {
$('#qrcode-msg-too-long').show();
return;
}
console.error('Cannot create QR Code', exception);
$('#qrcode-msg-unknown-error').show();
}
},
createQrCodeUrl: function () {
// We work on a copy of the current location instance to avoid
// reloading the page (which will happen when the `export` query
// parameter is added to the actual location object):
const exportLocation = new URL(document.location.href);
const searchParams = new URLSearchParams(exportLocation.search);
// We've to provide a value to the query parameter here, because
// URLSearchParams uses a list of tuples internally where the
// value part of such a tuple isn't optional. For now the value
// is 'dialog', but it's possible to add support for other values
// later, e.g. for starting a download directly after opening the link:
searchParams.set('export', 'dialog');
exportLocation.search = searchParams.toString();
return exportLocation.toString();
},
getShareUrl: function () {
const exportLocation = new URL(document.location.href);
const searchParams = new URLSearchParams(exportLocation.search);
searchParams.delete('export');
exportLocation.search = searchParams.toString();
return exportLocation.toString();
},
_keydownListener: function (event) {
if (
BR.Util.keyboardShortcutsAllowed(event) &&
event.keyCode === this.options.shortcut.share_action &&
!$('#shareButton').hasClass('disabled')
) {
$('#share-dialog').modal('show');
this.share(event);
}
},
});