add event listener to textbox

This commit is contained in:
MoPaMo 2021-06-16 07:13:19 +02:00
parent 0aa27250a4
commit 8809ea6667

View file

@ -1,38 +1,38 @@
const $ = query => document.getElementById(query); const $ = (query) => document.getElementById(query);
const $$ = query => document.body.querySelector(query); const $$ = (query) => document.body.querySelector(query);
const isURL = text => /^((https?:\/\/|www)[^\s]+)/g.test(text.toLowerCase()); const isURL = (text) => /^((https?:\/\/|www)[^\s]+)/g.test(text.toLowerCase());
window.isDownloadSupported = (typeof document.createElement('a').download !== 'undefined'); window.isDownloadSupported =
window.isProductionEnvironment = !window.location.host.startsWith('localhost'); typeof document.createElement("a").download !== "undefined";
window.isProductionEnvironment = !window.location.host.startsWith("localhost");
window.iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; window.iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
// set display name // set display name
Events.on('display-name', e => { Events.on("display-name", (e) => {
const me = e.detail.message; const me = e.detail.message;
const $displayName = $('displayName') const $displayName = $("displayName");
$displayName.textContent = 'You are known as ' + me.displayName; $displayName.textContent = "You are known as " + me.displayName;
$displayName.title = me.deviceName; $displayName.title = me.deviceName;
}); });
class PeersUI { class PeersUI {
constructor() { constructor() {
Events.on('peer-joined', e => this._onPeerJoined(e.detail)); Events.on("peer-joined", (e) => this._onPeerJoined(e.detail));
Events.on('peer-left', e => this._onPeerLeft(e.detail)); Events.on("peer-left", (e) => this._onPeerLeft(e.detail));
Events.on('peers', e => this._onPeers(e.detail)); Events.on("peers", (e) => this._onPeers(e.detail));
Events.on('file-progress', e => this._onFileProgress(e.detail)); Events.on("file-progress", (e) => this._onFileProgress(e.detail));
Events.on('paste', e => this._onPaste(e)); Events.on("paste", (e) => this._onPaste(e));
} }
_onPeerJoined(peer) { _onPeerJoined(peer) {
if ($(peer.id)) return; // peer already exists if ($(peer.id)) return; // peer already exists
const peerUI = new PeerUI(peer); const peerUI = new PeerUI(peer);
$$('x-peers').appendChild(peerUI.$el); $$("x-peers").appendChild(peerUI.$el);
setTimeout(e => window.animateBackground(false), 1750); // Stop animation setTimeout((e) => window.animateBackground(false), 1750); // Stop animation
} }
_onPeers(peers) { _onPeers(peers) {
this._clearPeers(); this._clearPeers();
peers.forEach(peer => this._onPeerJoined(peer)); peers.forEach((peer) => this._onPeerJoined(peer));
} }
_onPeerLeft(peerId) { _onPeerLeft(peerId) {
@ -49,29 +49,30 @@ class PeersUI {
} }
_clearPeers() { _clearPeers() {
const $peers = $$('x-peers').innerHTML = ''; const $peers = ($$("x-peers").innerHTML = "");
} }
_onPaste(e) { _onPaste(e) {
const files = e.clipboardData.files || e.clipboardData.items const files =
.filter(i => i.type.indexOf('image') > -1) e.clipboardData.files ||
.map(i => i.getAsFile()); e.clipboardData.items
const peers = document.querySelectorAll('x-peer'); .filter((i) => i.type.indexOf("image") > -1)
.map((i) => i.getAsFile());
const peers = document.querySelectorAll("x-peer");
// send the pasted image content to the only peer if there is one // send the pasted image content to the only peer if there is one
// otherwise, select the peer somehow by notifying the client that // otherwise, select the peer somehow by notifying the client that
// "image data has been pasted, click the client to which to send it" // "image data has been pasted, click the client to which to send it"
// not implemented // not implemented
if (files.length > 0 && peers.length === 1) { if (files.length > 0 && peers.length === 1) {
Events.fire('files-selected', { Events.fire("files-selected", {
files: files, files: files,
to: $$('x-peer').id to: $$("x-peer").id,
}); });
} }
} }
} }
class PeerUI { class PeerUI {
html() { html() {
return ` return `
<label class="column center" title="Click to send files or right click to send a text"> <label class="column center" title="Click to send files or right click to send a text">
@ -86,7 +87,7 @@ class PeerUI {
<div class="name font-subheading"></div> <div class="name font-subheading"></div>
<div class="device-name font-body2"></div> <div class="device-name font-body2"></div>
<div class="status font-body2"></div> <div class="status font-body2"></div>
</label>` </label>`;
} }
constructor(peer) { constructor(peer) {
@ -96,29 +97,31 @@ class PeerUI {
} }
_initDom() { _initDom() {
const el = document.createElement('x-peer'); const el = document.createElement("x-peer");
el.id = this._peer.id; el.id = this._peer.id;
el.innerHTML = this.html(); el.innerHTML = this.html();
el.ui = this; el.ui = this;
el.querySelector('svg use').setAttribute('xlink:href', this._icon()); el.querySelector("svg use").setAttribute("xlink:href", this._icon());
el.querySelector('.name').textContent = this._displayName(); el.querySelector(".name").textContent = this._displayName();
el.querySelector('.device-name').textContent = this._deviceName(); el.querySelector(".device-name").textContent = this._deviceName();
this.$el = el; this.$el = el;
this.$progress = el.querySelector('.progress'); this.$progress = el.querySelector(".progress");
} }
_bindListeners(el) { _bindListeners(el) {
el.querySelector('input').addEventListener('change', e => this._onFilesSelected(e)); el.querySelector("input").addEventListener("change", (e) =>
el.addEventListener('drop', e => this._onDrop(e)); this._onFilesSelected(e)
el.addEventListener('dragend', e => this._onDragEnd(e)); );
el.addEventListener('dragleave', e => this._onDragEnd(e)); el.addEventListener("drop", (e) => this._onDrop(e));
el.addEventListener('dragover', e => this._onDragOver(e)); el.addEventListener("dragend", (e) => this._onDragEnd(e));
el.addEventListener('contextmenu', e => this._onRightClick(e)); el.addEventListener("dragleave", (e) => this._onDragEnd(e));
el.addEventListener('touchstart', e => this._onTouchStart(e)); el.addEventListener("dragover", (e) => this._onDragOver(e));
el.addEventListener('touchend', e => this._onTouchEnd(e)); el.addEventListener("contextmenu", (e) => this._onRightClick(e));
el.addEventListener("touchstart", (e) => this._onTouchStart(e));
el.addEventListener("touchend", (e) => this._onTouchEnd(e));
// prevent browser's default file drop behavior // prevent browser's default file drop behavior
Events.on('dragover', e => e.preventDefault()); Events.on("dragover", (e) => e.preventDefault());
Events.on('drop', e => e.preventDefault()); Events.on("drop", (e) => e.preventDefault());
} }
_displayName() { _displayName() {
@ -131,105 +134,109 @@ class PeerUI {
_icon() { _icon() {
const device = this._peer.name.device || this._peer.name; const device = this._peer.name.device || this._peer.name;
if (device.type === 'mobile') { if (device.type === "mobile") {
return '#phone-iphone'; return "#phone-iphone";
} }
if (device.type === 'tablet') { if (device.type === "tablet") {
return '#tablet-mac'; return "#tablet-mac";
} }
return '#desktop-mac'; return "#desktop-mac";
} }
_onFilesSelected(e) { _onFilesSelected(e) {
const $input = e.target; const $input = e.target;
const files = $input.files; const files = $input.files;
Events.fire('files-selected', { Events.fire("files-selected", {
files: files, files: files,
to: this._peer.id to: this._peer.id,
}); });
$input.value = null; // reset input $input.value = null; // reset input
} }
setProgress(progress) { setProgress(progress) {
if (progress > 0) { if (progress > 0) {
this.$el.setAttribute('transfer', '1'); this.$el.setAttribute("transfer", "1");
} }
if (progress > 0.5) { if (progress > 0.5) {
this.$progress.classList.add('over50'); this.$progress.classList.add("over50");
} else { } else {
this.$progress.classList.remove('over50'); this.$progress.classList.remove("over50");
} }
const degrees = `rotate(${360 * progress}deg)`; const degrees = `rotate(${360 * progress}deg)`;
this.$progress.style.setProperty('--progress', degrees); this.$progress.style.setProperty("--progress", degrees);
if (progress >= 1) { if (progress >= 1) {
this.setProgress(0); this.setProgress(0);
this.$el.removeAttribute('transfer'); this.$el.removeAttribute("transfer");
} }
} }
_onDrop(e) { _onDrop(e) {
e.preventDefault(); e.preventDefault();
const files = e.dataTransfer.files; const files = e.dataTransfer.files;
Events.fire('files-selected', { Events.fire("files-selected", {
files: files, files: files,
to: this._peer.id to: this._peer.id,
}); });
this._onDragEnd(); this._onDragEnd();
} }
_onDragOver() { _onDragOver() {
this.$el.setAttribute('drop', 1); this.$el.setAttribute("drop", 1);
} }
_onDragEnd() { _onDragEnd() {
this.$el.removeAttribute('drop'); this.$el.removeAttribute("drop");
} }
_onRightClick(e) { _onRightClick(e) {
e.preventDefault(); e.preventDefault();
Events.fire('text-recipient', this._peer.id); Events.fire("text-recipient", this._peer.id);
} }
_onTouchStart(e) { _onTouchStart(e) {
this._touchStart = Date.now(); this._touchStart = Date.now();
this._touchTimer = setTimeout(_ => this._onTouchEnd(), 610); this._touchTimer = setTimeout((_) => this._onTouchEnd(), 610);
} }
_onTouchEnd(e) { _onTouchEnd(e) {
if (Date.now() - this._touchStart < 500) { if (Date.now() - this._touchStart < 500) {
clearTimeout(this._touchTimer); clearTimeout(this._touchTimer);
} else { // this was a long tap } else {
// this was a long tap
if (e) e.preventDefault(); if (e) e.preventDefault();
Events.fire('text-recipient', this._peer.id); Events.fire("text-recipient", this._peer.id);
} }
} }
} }
class Dialog { class Dialog {
constructor(id) { constructor(id) {
this.$el = $(id); this.$el = $(id);
this.$el.querySelectorAll('[close]').forEach(el => el.addEventListener('click', e => this.hide())) this.$el.querySelectorAll("[close]").forEach((el) => {
this.$autoFocus = this.$el.querySelector('[autofocus]'); el.addEventListener("click", (e) => this.hide());
});
this.$el.querySelectorAll("[role=\"textbox\"]").forEach((el) => {
el.addEventListener("click", (e) => this.hide());
});
this.$autoFocus = this.$el.querySelector("[autofocus]");
} }
show() { show() {
this.$el.setAttribute('show', 1); this.$el.setAttribute("show", 1);
if (this.$autoFocus) this.$autoFocus.focus(); if (this.$autoFocus) this.$autoFocus.focus();
} }
hide() { hide() {
this.$el.removeAttribute('show'); this.$el.removeAttribute("show");
document.activeElement.blur(); document.activeElement.blur();
window.blur(); window.blur();
} }
} }
class ReceiveDialog extends Dialog { class ReceiveDialog extends Dialog {
constructor() { constructor() {
super('receiveDialog'); super("receiveDialog");
Events.on('file-received', e => { Events.on("file-received", (e) => {
this._nextFile(e.detail); this._nextFile(e.detail);
window.blop.play(); window.blop.play();
}); });
@ -245,78 +252,79 @@ class ReceiveDialog extends Dialog {
} }
_dequeueFile() { _dequeueFile() {
if (!this._filesQueue.length) { // nothing to do if (!this._filesQueue.length) {
// nothing to do
this._busy = false; this._busy = false;
return; return;
} }
// dequeue next file // dequeue next file
setTimeout(_ => { setTimeout((_) => {
this._busy = false; this._busy = false;
this._nextFile(); this._nextFile();
}, 300); }, 300);
} }
_displayFile(file) { _displayFile(file) {
const $a = this.$el.querySelector('#download'); const $a = this.$el.querySelector("#download");
const url = URL.createObjectURL(file.blob); const url = URL.createObjectURL(file.blob);
$a.href = url; $a.href = url;
$a.download = file.name; $a.download = file.name;
if(this._autoDownload()){ if (this._autoDownload()) {
$a.click() $a.click();
return return;
} }
if(file.mime.split('/')[0] === 'image'){ if (file.mime.split("/")[0] === "image") {
console.log('the file is image'); console.log("the file is image");
this.$el.querySelector('.preview').style.visibility = 'inherit'; this.$el.querySelector(".preview").style.visibility = "inherit";
this.$el.querySelector("#img-preview").src = url; this.$el.querySelector("#img-preview").src = url;
} }
this.$el.querySelector('#fileName').textContent = file.name; this.$el.querySelector("#fileName").textContent = file.name;
this.$el.querySelector('#fileSize').textContent = this._formatFileSize(file.size); this.$el.querySelector("#fileSize").textContent = this._formatFileSize(
file.size
);
this.show(); this.show();
if (window.isDownloadSupported) return; if (window.isDownloadSupported) return;
// fallback for iOS // fallback for iOS
$a.target = '_blank'; $a.target = "_blank";
const reader = new FileReader(); const reader = new FileReader();
reader.onload = e => $a.href = reader.result; reader.onload = (e) => ($a.href = reader.result);
reader.readAsDataURL(file.blob); reader.readAsDataURL(file.blob);
} }
_formatFileSize(bytes) { _formatFileSize(bytes) {
if (bytes >= 1e9) { if (bytes >= 1e9) {
return (Math.round(bytes / 1e8) / 10) + ' GB'; return Math.round(bytes / 1e8) / 10 + " GB";
} else if (bytes >= 1e6) { } else if (bytes >= 1e6) {
return (Math.round(bytes / 1e5) / 10) + ' MB'; return Math.round(bytes / 1e5) / 10 + " MB";
} else if (bytes > 1000) { } else if (bytes > 1000) {
return Math.round(bytes / 1000) + ' KB'; return Math.round(bytes / 1000) + " KB";
} else { } else {
return bytes + ' Bytes'; return bytes + " Bytes";
} }
} }
hide() { hide() {
this.$el.querySelector('.preview').style.visibility = 'hidden'; this.$el.querySelector(".preview").style.visibility = "hidden";
this.$el.querySelector("#img-preview").src = ""; this.$el.querySelector("#img-preview").src = "";
super.hide(); super.hide();
this._dequeueFile(); this._dequeueFile();
} }
_autoDownload() {
_autoDownload(){ return !this.$el.querySelector("#autoDownload").checked;
return !this.$el.querySelector('#autoDownload').checked
} }
} }
class SendTextDialog extends Dialog { class SendTextDialog extends Dialog {
constructor() { constructor() {
super('sendTextDialog'); super("sendTextDialog");
Events.on('text-recipient', e => this._onRecipient(e.detail)) Events.on("text-recipient", (e) => this._onRecipient(e.detail));
this.$text = this.$el.querySelector('#textInput'); this.$text = this.$el.querySelector("#textInput");
const button = this.$el.querySelector('form'); const button = this.$el.querySelector("form");
button.addEventListener('submit', e => this._send(e)); button.addEventListener("submit", (e) => this._send(e));
} }
_onRecipient(recipient) { _onRecipient(recipient) {
@ -330,40 +338,39 @@ class SendTextDialog extends Dialog {
range.selectNodeContents(this.$text); range.selectNodeContents(this.$text);
sel.removeAllRanges(); sel.removeAllRanges();
sel.addRange(range); sel.addRange(range);
} }
_handleShareTargetText() { _handleShareTargetText() {
if (!window.shareTargetText) return; if (!window.shareTargetText) return;
this.$text.textContent = window.shareTargetText; this.$text.textContent = window.shareTargetText;
window.shareTargetText = ''; window.shareTargetText = "";
} }
_send(e) { _send(e) {
e.preventDefault(); e.preventDefault();
Events.fire('send-text', { Events.fire("send-text", {
to: this._recipient, to: this._recipient,
text: this.$text.innerText text: this.$text.innerText,
}); });
} }
} }
class ReceiveTextDialog extends Dialog { class ReceiveTextDialog extends Dialog {
constructor() { constructor() {
super('receiveTextDialog'); super("receiveTextDialog");
Events.on('text-received', e => this._onText(e.detail)) Events.on("text-received", (e) => this._onText(e.detail));
this.$text = this.$el.querySelector('#text'); this.$text = this.$el.querySelector("#text");
const $copy = this.$el.querySelector('#copy'); const $copy = this.$el.querySelector("#copy");
copy.addEventListener('click', _ => this._onCopy()); copy.addEventListener("click", (_) => this._onCopy());
} }
_onText(e) { _onText(e) {
this.$text.innerHTML = ''; this.$text.innerHTML = "";
const text = e.text; const text = e.text;
if (isURL(text)) { if (isURL(text)) {
const $a = document.createElement('a'); const $a = document.createElement("a");
$a.href = text; $a.href = text;
$a.target = '_blank'; $a.target = "_blank";
$a.textContent = text; $a.textContent = text;
this.$text.appendChild($a); this.$text.appendChild($a);
} else { } else {
@ -375,56 +382,56 @@ class ReceiveTextDialog extends Dialog {
async _onCopy() { async _onCopy() {
await navigator.clipboard.writeText(this.$text.textContent); await navigator.clipboard.writeText(this.$text.textContent);
Events.fire('notify-user', 'Copied to clipboard'); Events.fire("notify-user", "Copied to clipboard");
} }
} }
class Toast extends Dialog { class Toast extends Dialog {
constructor() { constructor() {
super('toast'); super("toast");
Events.on('notify-user', e => this._onNotfiy(e.detail)); Events.on("notify-user", (e) => this._onNotfiy(e.detail));
} }
_onNotfiy(message) { _onNotfiy(message) {
this.$el.textContent = message; this.$el.textContent = message;
this.show(); this.show();
setTimeout(_ => this.hide(), 3000); setTimeout((_) => this.hide(), 3000);
} }
} }
class Notifications { class Notifications {
constructor() { constructor() {
// Check if the browser supports notifications // Check if the browser supports notifications
if (!('Notification' in window)) return; if (!("Notification" in window)) return;
// Check whether notification permissions have already been granted // Check whether notification permissions have already been granted
if (Notification.permission !== 'granted') { if (Notification.permission !== "granted") {
this.$button = $('notification'); this.$button = $("notification");
this.$button.removeAttribute('hidden'); this.$button.removeAttribute("hidden");
this.$button.addEventListener('click', e => this._requestPermission()); this.$button.addEventListener("click", (e) => this._requestPermission());
} }
Events.on('text-received', e => this._messageNotification(e.detail.text)); Events.on("text-received", (e) => this._messageNotification(e.detail.text));
Events.on('file-received', e => this._downloadNotification(e.detail.name)); Events.on("file-received", (e) =>
this._downloadNotification(e.detail.name)
);
} }
_requestPermission() { _requestPermission() {
Notification.requestPermission(permission => { Notification.requestPermission((permission) => {
if (permission !== 'granted') { if (permission !== "granted") {
Events.fire('notify-user', Notifications.PERMISSION_ERROR || 'Error'); Events.fire("notify-user", Notifications.PERMISSION_ERROR || "Error");
return; return;
} }
this._notify('Even more snappy sharing!'); this._notify("Even more snappy sharing!");
this.$button.setAttribute('hidden', 1); this.$button.setAttribute("hidden", 1);
}); });
} }
_notify(message, body, closeTimeout = 20000) { _notify(message, body, closeTimeout = 20000) {
const config = { const config = {
body: body, body: body,
icon: '/images/logo_transparent_128x128.png', icon: "/images/logo_transparent_128x128.png",
} };
let notification; let notification;
try { try {
notification = new Notification(message, config); notification = new Notification(message, config);
@ -436,7 +443,7 @@ class Notifications {
// Notification is persistent on Android. We have to close it manually // Notification is persistent on Android. We have to close it manually
if (closeTimeout) { if (closeTimeout) {
setTimeout(_ => notification.close(), closeTimeout); setTimeout((_) => notification.close(), closeTimeout);
} }
return notification; return notification;
@ -444,86 +451,91 @@ class Notifications {
_messageNotification(message) { _messageNotification(message) {
if (isURL(message)) { if (isURL(message)) {
const notification = this._notify(message, 'Click to open link'); const notification = this._notify(message, "Click to open link");
this._bind(notification, e => window.open(message, '_blank', null, true)); this._bind(notification, (e) =>
window.open(message, "_blank", null, true)
);
} else { } else {
const notification = this._notify(message, 'Click to copy text'); const notification = this._notify(message, "Click to copy text");
this._bind(notification, e => this._copyText(message, notification)); this._bind(notification, (e) => this._copyText(message, notification));
} }
} }
_downloadNotification(message) { _downloadNotification(message) {
const notification = this._notify(message, 'Click to download'); const notification = this._notify(message, "Click to download");
if (!window.isDownloadSupported) return; if (!window.isDownloadSupported) return;
this._bind(notification, e => this._download(notification)); this._bind(notification, (e) => this._download(notification));
} }
_download(notification) { _download(notification) {
document.querySelector('x-dialog [download]').click(); document.querySelector("x-dialog [download]").click();
notification.close(); notification.close();
} }
_copyText(message, notification) { _copyText(message, notification) {
notification.close(); notification.close();
if (!navigator.clipboard.writeText(message)) return; if (!navigator.clipboard.writeText(message)) return;
this._notify('Copied text to clipboard'); this._notify("Copied text to clipboard");
} }
_bind(notification, handler) { _bind(notification, handler) {
if (notification.then) { if (notification.then) {
notification.then(e => serviceWorker.getNotifications().then(notifications => { notification.then((e) =>
serviceWorker.addEventListener('notificationclick', handler); serviceWorker.getNotifications().then((notifications) => {
})); serviceWorker.addEventListener("notificationclick", handler);
})
);
} else { } else {
notification.onclick = handler; notification.onclick = handler;
} }
} }
} }
class NetworkStatusUI { class NetworkStatusUI {
constructor() { constructor() {
window.addEventListener('offline', e => this._showOfflineMessage(), false); window.addEventListener(
window.addEventListener('online', e => this._showOnlineMessage(), false); "offline",
(e) => this._showOfflineMessage(),
false
);
window.addEventListener("online", (e) => this._showOnlineMessage(), false);
if (!navigator.onLine) this._showOfflineMessage(); if (!navigator.onLine) this._showOfflineMessage();
} }
_showOfflineMessage() { _showOfflineMessage() {
Events.fire('notify-user', 'You are offline'); Events.fire("notify-user", "You are offline");
} }
_showOnlineMessage() { _showOnlineMessage() {
Events.fire('notify-user', 'You are back online'); Events.fire("notify-user", "You are back online");
} }
} }
class WebShareTargetUI { class WebShareTargetUI {
constructor() { constructor() {
const parsedUrl = new URL(window.location); const parsedUrl = new URL(window.location);
const title = parsedUrl.searchParams.get('title'); const title = parsedUrl.searchParams.get("title");
const text = parsedUrl.searchParams.get('text'); const text = parsedUrl.searchParams.get("text");
const url = parsedUrl.searchParams.get('url'); const url = parsedUrl.searchParams.get("url");
let shareTargetText = title ? title : ''; let shareTargetText = title ? title : "";
shareTargetText += text ? shareTargetText ? ' ' + text : text : ''; shareTargetText += text ? (shareTargetText ? " " + text : text) : "";
if(url) shareTargetText = url; // We share only the Link - no text. Because link-only text becomes clickable. if (url) shareTargetText = url; // We share only the Link - no text. Because link-only text becomes clickable.
if (!shareTargetText) return; if (!shareTargetText) return;
window.shareTargetText = shareTargetText; window.shareTargetText = shareTargetText;
history.pushState({}, 'URL Rewrite', '/'); history.pushState({}, "URL Rewrite", "/");
console.log('Shared Target Text:', '"' + shareTargetText + '"'); console.log("Shared Target Text:", '"' + shareTargetText + '"');
} }
} }
class Snapdrop { class Snapdrop {
constructor() { constructor() {
const server = new ServerConnection(); const server = new ServerConnection();
const peers = new PeersManager(server); const peers = new PeersManager(server);
const peersUI = new PeersUI(); const peersUI = new PeersUI();
Events.on('load', e => { Events.on("load", (e) => {
const receiveDialog = new ReceiveDialog(); const receiveDialog = new ReceiveDialog();
const sendTextDialog = new SendTextDialog(); const sendTextDialog = new SendTextDialog();
const receiveTextDialog = new ReceiveTextDialog(); const receiveTextDialog = new ReceiveTextDialog();
@ -537,39 +549,38 @@ class Snapdrop {
const snapdrop = new Snapdrop(); const snapdrop = new Snapdrop();
if ("serviceWorker" in navigator) {
navigator.serviceWorker
if ('serviceWorker' in navigator) { .register("/service-worker.js")
navigator.serviceWorker.register('/service-worker.js') .then((serviceWorker) => {
.then(serviceWorker => { console.log("Service Worker registered");
console.log('Service Worker registered'); window.serviceWorker = serviceWorker;
window.serviceWorker = serviceWorker
}); });
} }
window.addEventListener('beforeinstallprompt', e => { window.addEventListener("beforeinstallprompt", (e) => {
if (window.matchMedia('(display-mode: standalone)').matches) { if (window.matchMedia("(display-mode: standalone)").matches) {
// don't display install banner when installed // don't display install banner when installed
return e.preventDefault(); return e.preventDefault();
} else { } else {
const btn = document.querySelector('#install') const btn = document.querySelector("#install");
btn.hidden = false; btn.hidden = false;
btn.onclick = _ => e.prompt(); btn.onclick = (_) => e.prompt();
return e.preventDefault(); return e.preventDefault();
} }
}); });
// Background Animation // Background Animation
Events.on('load', () => { Events.on("load", () => {
let c = document.createElement('canvas'); let c = document.createElement("canvas");
document.body.appendChild(c); document.body.appendChild(c);
let style = c.style; let style = c.style;
style.width = '100%'; style.width = "100%";
style.position = 'absolute'; style.position = "absolute";
style.zIndex = -1; style.zIndex = -1;
style.top = 0; style.top = 0;
style.left = 0; style.left = 0;
let ctx = c.getContext('2d'); let ctx = c.getContext("2d");
let x0, y0, w, h, dw; let x0, y0, w, h, dw;
function init() { function init() {
@ -589,7 +600,7 @@ Events.on('load', () => {
function drawCircle(radius) { function drawCircle(radius) {
ctx.beginPath(); ctx.beginPath();
let color = Math.round(255 * (1 - radius / Math.max(w, h))); let color = Math.round(255 * (1 - radius / Math.max(w, h)));
ctx.strokeStyle = 'rgba(' + color + ',' + color + ',' + color + ',0.1)'; ctx.strokeStyle = "rgba(" + color + "," + color + "," + color + ",0.1)";
ctx.arc(x0, y0, radius, 0, 2 * Math.PI); ctx.arc(x0, y0, radius, 0, 2 * Math.PI);
ctx.stroke(); ctx.stroke();
ctx.lineWidth = 2; ctx.lineWidth = 2;
@ -600,7 +611,7 @@ Events.on('load', () => {
function drawCircles() { function drawCircles() {
ctx.clearRect(0, 0, w, h); ctx.clearRect(0, 0, w, h);
for (let i = 0; i < 8; i++) { for (let i = 0; i < 8; i++) {
drawCircle(dw * i + step % dw); drawCircle(dw * i + (step % dw));
} }
step += 1; step += 1;
} }
@ -609,13 +620,13 @@ Events.on('load', () => {
function animate() { function animate() {
if (loading || step % dw < dw - 5) { if (loading || step % dw < dw - 5) {
requestAnimationFrame(function() { requestAnimationFrame(function () {
drawCircles(); drawCircles();
animate(); animate();
}); });
} }
} }
window.animateBackground = function(l) { window.animateBackground = function (l) {
loading = l; loading = l;
animate(); animate();
}; };
@ -629,8 +640,9 @@ as the user has dismissed the permission prompt several times.
This can be reset in Page Info This can be reset in Page Info
which can be accessed by clicking the lock icon next to the URL.`; which can be accessed by clicking the lock icon next to the URL.`;
document.body.onclick = e => { // safari hack to fix audio document.body.onclick = (e) => {
// safari hack to fix audio
document.body.onclick = null; document.body.onclick = null;
if (!(/.*Version.*Safari.*/.test(navigator.userAgent))) return; if (!/.*Version.*Safari.*/.test(navigator.userAgent)) return;
blop.play(); blop.play();
} };