mirror of
https://github.com/schlagmichdoch/PairDrop.git
synced 2025-04-21 15:26:17 -04:00
Speed up initial load while still preventing css layout shift; Tidy up ui.js
This commit is contained in:
parent
2578803a78
commit
ed2f1b0c61
8 changed files with 353 additions and 312 deletions
|
@ -38,7 +38,7 @@
|
|||
</head>
|
||||
|
||||
<body translate="no">
|
||||
<header class="row-reverse">
|
||||
<header class="row-reverse opacity-0">
|
||||
<a href="#about" class="icon-button" data-i18n-key="header.about" data-i18n-attrs="title aria-label">
|
||||
<svg class="icon">
|
||||
<use xlink:href="#info-outline"></use>
|
||||
|
@ -96,11 +96,11 @@
|
|||
<div id="cancel-paste-mode" class="button" data-i18n-key="header.cancel-paste-mode" data-i18n-attrs="text" hidden></div>
|
||||
</header>
|
||||
<!-- Center -->
|
||||
<div id="center">
|
||||
<div id="center" class="opacity-0">
|
||||
<!-- Peers -->
|
||||
<div class="x-peers-filler"></div>
|
||||
<x-peers class="center"></x-peers>
|
||||
<x-no-peers data-i18n-key="instructions.no-peers" data-i18n-attrs="data-drop-bg">
|
||||
<x-no-peers class="no-animation-on-load" data-i18n-key="instructions.no-peers" data-i18n-attrs="data-drop-bg">
|
||||
<h2 data-i18n-key="instructions.no-peers-title" data-i18n-attrs="text"></h2>
|
||||
<div data-i18n-key="instructions.no-peers-subtitle" data-i18n-attrs="text"></div>
|
||||
</x-no-peers>
|
||||
|
@ -109,7 +109,7 @@
|
|||
</x-instructions>
|
||||
</div>
|
||||
<!-- Footer -->
|
||||
<footer class="column">
|
||||
<footer class="column opacity-0">
|
||||
<svg class="icon logo">
|
||||
<use xlink:href="#wifi-tethering"></use>
|
||||
</svg>
|
||||
|
@ -466,14 +466,14 @@
|
|||
</div>
|
||||
<!-- About Page -->
|
||||
<x-about id="about" class="full center column">
|
||||
<header class="row-reverse fade-in">
|
||||
<header class="row-reverse">
|
||||
<a href="#" class="close icon-button" data-i18n-key="about.close-about" data-i18n-attrs="aria-label">
|
||||
<svg class="icon">
|
||||
<use xlink:href="#close-icon"></use>
|
||||
</svg>
|
||||
</a>
|
||||
</header>
|
||||
<section class="center column fade-in">
|
||||
<section class="center column">
|
||||
<svg class="icon logo">
|
||||
<use xlink:href="#wifi-tethering"></use>
|
||||
</svg>
|
||||
|
@ -507,7 +507,7 @@
|
|||
</section>
|
||||
<x-background></x-background>
|
||||
</x-about>
|
||||
<canvas class="circles"></canvas>
|
||||
<canvas class="circles opacity-0"></canvas>
|
||||
<!-- SVG Icon Library -->
|
||||
<svg style="display: none;">
|
||||
<symbol id="wifi-tethering" viewBox="0 0 24 24">
|
||||
|
@ -587,7 +587,7 @@
|
|||
<script src="scripts/theme.js"></script>
|
||||
<script src="scripts/network.js"></script>
|
||||
<script src="scripts/ui.js"></script>
|
||||
<script src="scripts/util.js" async></script>
|
||||
<script src="scripts/util.js"></script>
|
||||
<script src="scripts/QRCode.min.js" async></script>
|
||||
<script src="scripts/zip.min.js" async></script>
|
||||
<script src="scripts/NoSleep.min.js" async></script>
|
||||
|
|
|
@ -36,27 +36,15 @@ class PeersUI {
|
|||
Events.on('drop', e => this._onDrop(e));
|
||||
Events.on('keydown', e => this._onKeyDown(e));
|
||||
|
||||
this.$header = document.querySelector('body > header')
|
||||
this.$xPeers = $$('x-peers');
|
||||
this.$xNoPeers = $$('x-no-peers');
|
||||
this.$xInstructions = $$('x-instructions');
|
||||
this.$center = $$('#center');
|
||||
this.$logo = $$('footer .icon.logo');
|
||||
this.$footer = $$('footer');
|
||||
this.$discoveryWrapper = $$('footer .discovery-wrapper');
|
||||
this.$knownAsWrapper = $$('footer .known-as-wrapper');
|
||||
|
||||
this.$header.style.opacity = "1";
|
||||
this.$xPeers.style.opacity = "1";
|
||||
this.$xNoPeers.style.opacity = "1";
|
||||
this.$xInstructions.style.opacity = "0.5";
|
||||
this.$center.style.opacity = "1";
|
||||
this.$logo.style.opacity = "1";
|
||||
this.$discoveryWrapper.style.opacity = "1";
|
||||
this.$knownAsWrapper.style.opacity = "1";
|
||||
|
||||
|
||||
Events.on('peer-added', _ => this.evaluateOverflowing());
|
||||
Events.on('bg-resize', _ => this.evaluateOverflowing());
|
||||
Events.on('peer-added', _ => this._evaluateOverflowing());
|
||||
Events.on('bg-resize', _ => this._evaluateOverflowing());
|
||||
|
||||
this.$displayName = $('display-name');
|
||||
|
||||
|
@ -75,11 +63,45 @@ class PeersUI {
|
|||
if (displayName) Events.fire('self-display-name-changed', displayName);
|
||||
});
|
||||
|
||||
Events.on('evaluate-footer-badges', _ => this._evaluateFooterBadges())
|
||||
|
||||
/* prevent animation on load */
|
||||
this.fadedIn = false;
|
||||
|
||||
this.$header = document.querySelector('header.opacity-0');
|
||||
Events.on('header-evaluated', () => this._fadeInHeader());
|
||||
}
|
||||
|
||||
_fadeInHeader() {
|
||||
//prevent flickering
|
||||
setTimeout(() => this.$header.classList.remove('opacity-0'), 50);
|
||||
}
|
||||
|
||||
_fadeInUI() {
|
||||
if (this.fadedIn) return;
|
||||
|
||||
this.fadedIn = true;
|
||||
|
||||
this.$center.classList.remove('opacity-0');
|
||||
this.$footer.classList.remove('opacity-0');
|
||||
|
||||
// Prevent flickering on load
|
||||
setTimeout(_ => {
|
||||
this.$xNoPeers.style.animationIterationCount = "1";
|
||||
}, 300);
|
||||
this.$xNoPeers.classList.remove('no-animation-on-load');
|
||||
}, 600);
|
||||
|
||||
Events.fire('ui-faded-in');
|
||||
}
|
||||
|
||||
_evaluateFooterBadges() {
|
||||
if (this.$discoveryWrapper.querySelectorAll('div:last-of-type > span[hidden]').length < 2) {
|
||||
this.$discoveryWrapper.classList.remove('row');
|
||||
this.$discoveryWrapper.classList.add('column');
|
||||
} else {
|
||||
this.$discoveryWrapper.classList.remove('column');
|
||||
this.$discoveryWrapper.classList.add('row');
|
||||
}
|
||||
Events.fire('redraw-canvas');
|
||||
this._fadeInUI();
|
||||
}
|
||||
|
||||
_insertDisplayName(displayName) {
|
||||
|
@ -162,6 +184,11 @@ class PeersUI {
|
|||
if (document.querySelectorAll('x-dialog[show]').length === 0 && window.pasteMode.activated && e.code === "Escape") {
|
||||
Events.fire('deactivate-paste-mode');
|
||||
}
|
||||
|
||||
// close About PairDrop page on Escape
|
||||
if (e.key === "Escape") {
|
||||
window.location.hash = '#';
|
||||
}
|
||||
}
|
||||
|
||||
_onPeerJoined(msg) {
|
||||
|
@ -207,7 +234,7 @@ class PeersUI {
|
|||
Object.keys(peer._roomIds).forEach(roomType => peerNode.classList.add(`type-${roomType}`));
|
||||
}
|
||||
|
||||
evaluateOverflowing() {
|
||||
_evaluateOverflowing() {
|
||||
if (this.$xPeers.clientHeight < this.$xPeers.scrollHeight) {
|
||||
this.$xPeers.classList.add('overflowing');
|
||||
} else {
|
||||
|
@ -223,7 +250,7 @@ class PeersUI {
|
|||
const $peer = $(peerId);
|
||||
if (!$peer) return;
|
||||
$peer.remove();
|
||||
this.evaluateOverflowing();
|
||||
this._evaluateOverflowing();
|
||||
}
|
||||
|
||||
_onRoomTypeRemoved(peerId, roomType) {
|
||||
|
@ -608,7 +635,6 @@ class Dialog {
|
|||
this.$el = $(id);
|
||||
this.$el.querySelectorAll('[close]').forEach(el => el.addEventListener('click', _ => this.hide()));
|
||||
this.$autoFocus = this.$el.querySelector('[autofocus]');
|
||||
this.$discoveryWrapper = $$('footer .discovery-wrapper');
|
||||
|
||||
Events.on('peer-disconnected', e => this._onPeerDisconnected(e.detail));
|
||||
}
|
||||
|
@ -629,7 +655,7 @@ class Dialog {
|
|||
window.blur();
|
||||
}
|
||||
document.title = 'PairDrop';
|
||||
document.changeFavicon("images/favicon-96x96.png");
|
||||
changeFavicon("images/favicon-96x96.png");
|
||||
this.correspondingPeerId = undefined;
|
||||
}
|
||||
|
||||
|
@ -639,17 +665,6 @@ class Dialog {
|
|||
Events.fire('notify-user', Localization.getTranslation("notifications.selected-peer-left"));
|
||||
}
|
||||
}
|
||||
|
||||
evaluateFooterBadges() {
|
||||
if (this.$discoveryWrapper.querySelectorAll('div:last-of-type > span[hidden]').length < 2) {
|
||||
this.$discoveryWrapper.classList.remove('row');
|
||||
this.$discoveryWrapper.classList.add('column');
|
||||
} else {
|
||||
this.$discoveryWrapper.classList.remove('column');
|
||||
this.$discoveryWrapper.classList.add('row');
|
||||
}
|
||||
Events.fire('bg-resize');
|
||||
}
|
||||
}
|
||||
|
||||
class LanguageSelectDialog extends Dialog {
|
||||
|
@ -929,7 +944,7 @@ class ReceiveFileDialog extends ReceiveDialog {
|
|||
document.title = files.length === 1
|
||||
? `${ Localization.getTranslation("document-titles.file-received") } - PairDrop`
|
||||
: `${ Localization.getTranslation("document-titles.file-received-plural", null, {count: files.length}) } - PairDrop`;
|
||||
document.changeFavicon("images/favicon-96x96-notification.png");
|
||||
changeFavicon("images/favicon-96x96-notification.png");
|
||||
|
||||
Events.fire('set-progress', {peerId: peerId, progress: 1, status: 'process'})
|
||||
this.show();
|
||||
|
@ -1026,7 +1041,7 @@ class ReceiveRequestDialog extends ReceiveDialog {
|
|||
this.$receiveTitle.innerText = transferRequestTitle;
|
||||
|
||||
document.title = `${transferRequestTitle} - PairDrop`;
|
||||
document.changeFavicon("images/favicon-96x96-notification.png");
|
||||
changeFavicon("images/favicon-96x96-notification.png");
|
||||
this.show();
|
||||
}
|
||||
|
||||
|
@ -1190,7 +1205,6 @@ class PairDeviceDialog extends Dialog {
|
|||
this.$closeBtn.addEventListener('click', _ => this._close());
|
||||
|
||||
Events.on('keydown', e => this._onKeyDown(e));
|
||||
Events.on('ws-connected', _ => this._onWsConnected());
|
||||
Events.on('ws-disconnected', _ => this.hide());
|
||||
Events.on('pair-device-initiated', e => this._onPairDeviceInitiated(e.detail));
|
||||
Events.on('pair-device-joined', e => this._onPairDeviceJoined(e.detail.peerId, e.detail.roomSecret));
|
||||
|
@ -1205,6 +1219,8 @@ class PairDeviceDialog extends Dialog {
|
|||
this.evaluateUrlAttributes();
|
||||
|
||||
this.pairPeer = {};
|
||||
|
||||
this._evaluateNumberRoomSecrets();
|
||||
}
|
||||
|
||||
_onKeyDown(e) {
|
||||
|
@ -1229,10 +1245,6 @@ class PairDeviceDialog extends Dialog {
|
|||
}
|
||||
}
|
||||
|
||||
_onWsConnected() {
|
||||
this._evaluateNumberRoomSecrets();
|
||||
}
|
||||
|
||||
_pairDeviceInitiate() {
|
||||
Events.fire('pair-device-initiate');
|
||||
}
|
||||
|
@ -1380,16 +1392,17 @@ class PairDeviceDialog extends Dialog {
|
|||
}
|
||||
|
||||
_evaluateNumberRoomSecrets() {
|
||||
PersistentStorage.getAllRoomSecrets().then(roomSecrets => {
|
||||
if (roomSecrets.length > 0) {
|
||||
this.$editPairedDevicesHeaderBtn.removeAttribute('hidden');
|
||||
this.$footerInstructionsPairedDevices.removeAttribute('hidden');
|
||||
} else {
|
||||
this.$editPairedDevicesHeaderBtn.setAttribute('hidden', '');
|
||||
this.$footerInstructionsPairedDevices.setAttribute('hidden', '');
|
||||
}
|
||||
super.evaluateFooterBadges();
|
||||
});
|
||||
PersistentStorage.getAllRoomSecrets()
|
||||
.then(roomSecrets => {
|
||||
if (roomSecrets.length > 0) {
|
||||
this.$editPairedDevicesHeaderBtn.removeAttribute('hidden');
|
||||
this.$footerInstructionsPairedDevices.removeAttribute('hidden');
|
||||
} else {
|
||||
this.$editPairedDevicesHeaderBtn.setAttribute('hidden', '');
|
||||
this.$footerInstructionsPairedDevices.setAttribute('hidden', '');
|
||||
}
|
||||
Events.fire('evaluate-footer-badges');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1397,10 +1410,10 @@ class EditPairedDevicesDialog extends Dialog {
|
|||
constructor() {
|
||||
super('edit-paired-devices-dialog');
|
||||
this.$pairedDevicesWrapper = this.$el.querySelector('.paired-devices-wrapper');
|
||||
this.$footerInstructionsPairedDevices = $$('.discovery-wrapper .badge-room-secret');
|
||||
this.$footerBadgePairedDevices = $$('.discovery-wrapper .badge-room-secret');
|
||||
|
||||
$('edit-paired-devices').addEventListener('click', _ => this._onEditPairedDevices());
|
||||
this.$footerInstructionsPairedDevices.addEventListener('click', _ => this._onEditPairedDevices());
|
||||
this.$footerBadgePairedDevices.addEventListener('click', _ => this._onEditPairedDevices());
|
||||
|
||||
Events.on('peer-display-name-changed', e => this._onPeerDisplayNameChanged(e));
|
||||
Events.on('keydown', e => this._onKeyDown(e));
|
||||
|
@ -1508,7 +1521,7 @@ class PublicRoomDialog extends Dialog {
|
|||
this.$leaveBtn = this.$el.querySelector('.leave-room');
|
||||
this.$joinSubmitBtn = this.$el.querySelector('button[type="submit"]');
|
||||
this.$headerBtnJoinPublicRoom = $('join-public-room');
|
||||
this.$footerInstructionsPublicRoomDevices = $$('.discovery-wrapper .badge-room-public-id');
|
||||
this.$footerBadgePublicRoomDevices = $$('.discovery-wrapper .badge-room-public-id');
|
||||
|
||||
|
||||
this.$form.addEventListener('submit', e => this._onSubmit(e));
|
||||
|
@ -1516,7 +1529,7 @@ class PublicRoomDialog extends Dialog {
|
|||
this.$leaveBtn.addEventListener('click', _ => this._leavePublicRoom())
|
||||
|
||||
this.$headerBtnJoinPublicRoom.addEventListener('click', _ => this._onHeaderBtnClick());
|
||||
this.$footerInstructionsPublicRoomDevices.addEventListener('click', _ => this._onHeaderBtnClick());
|
||||
this.$footerBadgePublicRoomDevices.addEventListener('click', _ => this._onHeaderBtnClick());
|
||||
|
||||
this.inputKeyContainer = new InputKeyContainer(
|
||||
this.$el.querySelector('.input-key-container'),
|
||||
|
@ -1598,12 +1611,12 @@ class PublicRoomDialog extends Dialog {
|
|||
setFooterBadge() {
|
||||
if (!this.roomId) return;
|
||||
|
||||
this.$footerInstructionsPublicRoomDevices.innerText = Localization.getTranslation("footer.public-room-devices", null, {
|
||||
this.$footerBadgePublicRoomDevices.innerText = Localization.getTranslation("footer.public-room-devices", null, {
|
||||
roomId: this.roomId.toUpperCase()
|
||||
});
|
||||
this.$footerInstructionsPublicRoomDevices.removeAttribute('hidden');
|
||||
this.$footerBadgePublicRoomDevices.removeAttribute('hidden');
|
||||
|
||||
super.evaluateFooterBadges();
|
||||
Events.fire('evaluate-footer-badges');
|
||||
}
|
||||
|
||||
_getShareRoomURL() {
|
||||
|
@ -1715,8 +1728,8 @@ class PublicRoomDialog extends Dialog {
|
|||
this.roomId = null;
|
||||
this.inputKeyContainer._cleanUp();
|
||||
sessionStorage.removeItem('public_room_id');
|
||||
this.$footerInstructionsPublicRoomDevices.setAttribute('hidden', '');
|
||||
super.evaluateFooterBadges();
|
||||
this.$footerBadgePublicRoomDevices.setAttribute('hidden', '');
|
||||
Events.fire('evaluate-footer-badges');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1847,7 +1860,7 @@ class ReceiveTextDialog extends Dialog {
|
|||
|
||||
this._setDocumentTitleMessages();
|
||||
|
||||
document.changeFavicon("images/favicon-96x96-notification.png");
|
||||
changeFavicon("images/favicon-96x96-notification.png");
|
||||
this.show();
|
||||
}
|
||||
|
||||
|
@ -2057,15 +2070,20 @@ class Notifications {
|
|||
|
||||
constructor() {
|
||||
// Check if the browser supports notifications
|
||||
if (!('Notification' in window)) return;
|
||||
if (!('Notification' in window)) {
|
||||
Events.fire('header-evaluated');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether notification permissions have already been granted
|
||||
if (Notification.permission !== 'granted') {
|
||||
this.$button = $('notification');
|
||||
this.$button.removeAttribute('hidden');
|
||||
this.$button.addEventListener('click', _ => this._requestPermission());
|
||||
this.$headerNotificationButton = $('notification');
|
||||
this.$headerNotificationButton.removeAttribute('hidden');
|
||||
this.$headerNotificationButton.addEventListener('click', _ => this._requestPermission());
|
||||
}
|
||||
|
||||
Events.fire('header-evaluated');
|
||||
|
||||
Events.on('text-received', e => this._messageNotification(e.detail.text, e.detail.peerId));
|
||||
Events.on('files-received', e => this._downloadNotification(e.detail.files));
|
||||
Events.on('files-transfer-request', e => this._requestNotification(e.detail.request, e.detail.peerId));
|
||||
|
@ -2078,7 +2096,7 @@ class Notifications {
|
|||
return;
|
||||
}
|
||||
Events.fire('notify-user', Localization.getTranslation("notifications.notifications-enabled"));
|
||||
this.$button.setAttribute('hidden', "");
|
||||
this.$headerNotificationButton.setAttribute('hidden', "");
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -2460,7 +2478,7 @@ class PersistentStorage {
|
|||
return(secrets);
|
||||
} catch (e) {
|
||||
this.logBrowserNotCapable();
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2678,12 +2696,71 @@ class BrowserTabsConnector {
|
|||
}
|
||||
}
|
||||
|
||||
class BackgroundCanvas {
|
||||
constructor() {
|
||||
this.c = $$('canvas');
|
||||
this.cCtx = this.c.getContext('2d');
|
||||
this.$footer = $$('footer');
|
||||
|
||||
Events.on('bg-resize', _ => this.init());
|
||||
Events.on('redraw-canvas', _ => this.init());
|
||||
Events.on('translation-loaded', _ => this.init());
|
||||
|
||||
//fade-in on load
|
||||
Events.on('ui-faded-in', _ => this._fadeIn());
|
||||
|
||||
window.onresize = _ => Events.fire('bg-resize');
|
||||
}
|
||||
|
||||
_fadeIn() {
|
||||
this.c.classList.remove('opacity-0');
|
||||
}
|
||||
|
||||
init() {
|
||||
let oldW = this.w;
|
||||
let oldH = this.h;
|
||||
let oldOffset = this.offset
|
||||
this.w = document.documentElement.clientWidth;
|
||||
this.h = document.documentElement.clientHeight;
|
||||
this.offset = this.$footer.offsetHeight - 27;
|
||||
if (this.h >= 800) this.offset += 10;
|
||||
|
||||
if (oldW === this.w && oldH === this.h && oldOffset === this.offset) return; // nothing has changed
|
||||
|
||||
this.c.width = this.w;
|
||||
this.c.height = this.h;
|
||||
this.x0 = this.w / 2;
|
||||
this.y0 = this.h - this.offset;
|
||||
this.dw = Math.round(Math.max(this.w, this.h, 1000) / 13);
|
||||
|
||||
this.drawCircles(this.cCtx);
|
||||
}
|
||||
|
||||
|
||||
drawCircle(ctx, radius) {
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = 2;
|
||||
let opacity = Math.max(0, 0.3 * (1 - 1 * radius / Math.max(this.w, this.h)));
|
||||
ctx.strokeStyle = `rgba(128, 128, 128, ${opacity})`;
|
||||
ctx.arc(this.x0, this.y0, radius, 0, 2 * Math.PI);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
drawCircles(ctx) {
|
||||
ctx.clearRect(0, 0, this.w, this.h);
|
||||
for (let i = 0; i < 13; i++) {
|
||||
this.drawCircle(ctx, this.dw * i + 33 + 66);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PairDrop {
|
||||
constructor() {
|
||||
Events.on('initial-translation-loaded', _ => {
|
||||
const server = new ServerConnection();
|
||||
const peers = new PeersManager(server);
|
||||
const peersUI = new PeersUI();
|
||||
const backgroundCanvas = new BackgroundCanvas();
|
||||
const languageSelectDialog = new LanguageSelectDialog();
|
||||
const receiveFileDialog = new ReceiveFileDialog();
|
||||
const receiveRequestDialog = new ReceiveRequestDialog();
|
||||
|
@ -2708,7 +2785,6 @@ const persistentStorage = new PersistentStorage();
|
|||
const pairDrop = new PairDrop();
|
||||
const localization = new Localization();
|
||||
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('/service-worker.js')
|
||||
.then(serviceWorker => {
|
||||
|
@ -2726,63 +2802,3 @@ window.addEventListener('beforeinstallprompt', e => {
|
|||
}
|
||||
return e.preventDefault();
|
||||
});
|
||||
|
||||
// Background Circles
|
||||
Events.on('load', () => {
|
||||
let c = $$('canvas');
|
||||
let cCtx = c.getContext('2d');
|
||||
let x0, y0, w, h, dw, offset;
|
||||
|
||||
function init() {
|
||||
let oldW = w;
|
||||
let oldH = h;
|
||||
let oldOffset = offset
|
||||
w = document.documentElement.clientWidth;
|
||||
h = document.documentElement.clientHeight;
|
||||
offset = $$('footer').offsetHeight - 27;
|
||||
if (h > 800) offset += 10;
|
||||
|
||||
if (oldW === w && oldH === h && oldOffset === offset) return; // nothing has changed
|
||||
|
||||
c.width = w;
|
||||
c.height = h;
|
||||
x0 = w / 2;
|
||||
y0 = h - offset;
|
||||
dw = Math.round(Math.max(w, h, 1000) / 13);
|
||||
|
||||
drawCircles(cCtx, dw);
|
||||
c.style.opacity = "1";
|
||||
}
|
||||
|
||||
Events.on('translation-loaded', _ => init());
|
||||
Events.on('bg-resize', _ => init());
|
||||
window.onresize = _ => Events.fire('bg-resize');
|
||||
|
||||
function drawCircle(ctx, radius) {
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = 2;
|
||||
let opacity = 0.3 * (1 - 1.2 * radius / Math.max(w, h));
|
||||
ctx.strokeStyle = `rgba(128, 128, 128, ${opacity})`;
|
||||
ctx.arc(x0, y0, radius, 0, 2 * Math.PI);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
function drawCircles(ctx, frame) {
|
||||
ctx.clearRect(0, 0, w, h);
|
||||
for (let i = 0; i < 13; i++) {
|
||||
drawCircle(ctx, dw * i + frame + 33);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.changeFavicon = function (src) {
|
||||
document.querySelector('[rel="icon"]').href = src;
|
||||
document.querySelector('[rel="shortcut icon"]').href = src;
|
||||
}
|
||||
|
||||
// close About PairDrop page on Escape
|
||||
window.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Escape") {
|
||||
window.location.hash = '#';
|
||||
}
|
||||
});
|
||||
|
|
|
@ -406,3 +406,8 @@ function onlyUnique (value, index, array) {
|
|||
function getUrlWithoutArguments() {
|
||||
return `${window.location.protocol}//${window.location.host}${window.location.pathname}`;
|
||||
}
|
||||
|
||||
function changeFavicon(src) {
|
||||
document.querySelector('[rel="icon"]').href = src;
|
||||
document.querySelector('[rel="shortcut icon"]').href = src;
|
||||
}
|
||||
|
|
|
@ -273,6 +273,9 @@ x-noscript {
|
|||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
#center {
|
||||
|
@ -417,10 +420,6 @@ x-no-peers {
|
|||
padding: 8px;
|
||||
height: 137px;
|
||||
text-align: center;
|
||||
animation: fade-in 600ms;
|
||||
animation-fill-mode: backwards;
|
||||
/* prevent flickering on load */
|
||||
animation-iteration-count: 0;
|
||||
}
|
||||
|
||||
x-no-peers h2,
|
||||
|
@ -613,7 +612,6 @@ footer .logo {
|
|||
margin-bottom: 8px;
|
||||
color: var(--primary-color);
|
||||
margin-top: -10px;
|
||||
animation: ease-in;
|
||||
}
|
||||
|
||||
.discovery-wrapper {
|
||||
|
@ -1228,22 +1226,23 @@ button::-moz-focus-inner {
|
|||
z-index: 1;
|
||||
}
|
||||
|
||||
#about:not(:target) header.fade-in {
|
||||
#about:not(:target) header {
|
||||
transition-delay: 400ms;
|
||||
}
|
||||
|
||||
#about:target header.fade-in {
|
||||
#about:target header {
|
||||
transition-delay: 100ms;
|
||||
}
|
||||
|
||||
#about .fade-in {
|
||||
#about > * {
|
||||
transition: opacity 300ms ease 300ms;
|
||||
will-change: opacity;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
#about:not(:target) .fade-in {
|
||||
opacity: 0 !important;
|
||||
#about:not(:target) > header,
|
||||
#about:not(:target) > section {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition-delay: 0s;
|
||||
}
|
||||
|
@ -1422,17 +1421,17 @@ x-peers:empty~x-instructions {
|
|||
|
||||
/* Prevent Cumulative Layout Shift */
|
||||
|
||||
body > header,
|
||||
canvas,
|
||||
#center,
|
||||
x-no-peers,
|
||||
x-peers,
|
||||
x-instructions,
|
||||
footer > .icon.logo,
|
||||
.discovery-wrapper,
|
||||
.known-as-wrapper {
|
||||
transition: opacity 0.5s ease 0.1s;
|
||||
opacity: 0; /* will be set to 1 after initial translation is loaded */
|
||||
.fade-in {
|
||||
animation: fade-in 600ms;
|
||||
animation-fill-mode: backwards;
|
||||
}
|
||||
|
||||
.no-animation-on-load {
|
||||
animation-iteration-count: 0;
|
||||
}
|
||||
|
||||
.opacity-0 {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* Responsive Styles */
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
</head>
|
||||
|
||||
<body translate="no">
|
||||
<header class="row-reverse">
|
||||
<header class="row-reverse opacity-0">
|
||||
<a href="#about" class="icon-button" data-i18n-key="header.about" data-i18n-attrs="title aria-label">
|
||||
<svg class="icon">
|
||||
<use xlink:href="#info-outline"></use>
|
||||
|
@ -96,11 +96,11 @@
|
|||
<div id="cancel-paste-mode" class="button" data-i18n-key="header.cancel-paste-mode" data-i18n-attrs="text" hidden></div>
|
||||
</header>
|
||||
<!-- Center -->
|
||||
<div id="center">
|
||||
<div id="center" class="opacity-0">
|
||||
<!-- Peers -->
|
||||
<div class="x-peers-filler"></div>
|
||||
<x-peers class="center"></x-peers>
|
||||
<x-no-peers data-i18n-key="instructions.no-peers" data-i18n-attrs="data-drop-bg">
|
||||
<x-no-peers class="no-animation-on-load" data-i18n-key="instructions.no-peers" data-i18n-attrs="data-drop-bg">
|
||||
<h2 data-i18n-key="instructions.no-peers-title" data-i18n-attrs="text"></h2>
|
||||
<div data-i18n-key="instructions.no-peers-subtitle" data-i18n-attrs="text"></div>
|
||||
</x-no-peers>
|
||||
|
@ -114,7 +114,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<!-- Footer -->
|
||||
<footer class="column">
|
||||
<footer class="column opacity-0">
|
||||
<svg class="icon logo">
|
||||
<use xlink:href="#wifi-tethering"></use>
|
||||
</svg>
|
||||
|
@ -471,14 +471,14 @@
|
|||
</div>
|
||||
<!-- About Page -->
|
||||
<x-about id="about" class="full center column">
|
||||
<header class="row-reverse fade-in">
|
||||
<header class="row-reverse">
|
||||
<a href="#" class="close icon-button" data-i18n-key="about.close-about" data-i18n-attrs="aria-label">
|
||||
<svg class="icon">
|
||||
<use xlink:href="#close-icon"></use>
|
||||
</svg>
|
||||
</a>
|
||||
</header>
|
||||
<section class="center column fade-in">
|
||||
<section class="center column">
|
||||
<svg class="icon logo">
|
||||
<use xlink:href="#wifi-tethering"></use>
|
||||
</svg>
|
||||
|
@ -512,7 +512,7 @@
|
|||
</section>
|
||||
<x-background></x-background>
|
||||
</x-about>
|
||||
<canvas class="circles"></canvas>
|
||||
<canvas class="circles opacity-0"></canvas>
|
||||
<!-- SVG Icon Library -->
|
||||
<svg style="display: none;">
|
||||
<symbol id="wifi-tethering" viewBox="0 0 24 24">
|
||||
|
@ -592,7 +592,7 @@
|
|||
<script src="scripts/theme.js"></script>
|
||||
<script src="scripts/network.js"></script>
|
||||
<script src="scripts/ui.js"></script>
|
||||
<script src="scripts/util.js" async></script>
|
||||
<script src="scripts/util.js"></script>
|
||||
<script src="scripts/QRCode.min.js" async></script>
|
||||
<script src="scripts/zip.min.js" async></script>
|
||||
<script src="scripts/NoSleep.min.js" async></script>
|
||||
|
|
|
@ -36,27 +36,15 @@ class PeersUI {
|
|||
Events.on('drop', e => this._onDrop(e));
|
||||
Events.on('keydown', e => this._onKeyDown(e));
|
||||
|
||||
this.$header = document.querySelector('body > header')
|
||||
this.$xPeers = $$('x-peers');
|
||||
this.$xNoPeers = $$('x-no-peers');
|
||||
this.$xInstructions = $$('x-instructions');
|
||||
this.$center = $$('#center');
|
||||
this.$logo = $$('footer .icon.logo');
|
||||
this.$footer = $$('footer');
|
||||
this.$discoveryWrapper = $$('footer .discovery-wrapper');
|
||||
this.$knownAsWrapper = $$('footer .known-as-wrapper');
|
||||
|
||||
this.$header.style.opacity = "1";
|
||||
this.$xPeers.style.opacity = "1";
|
||||
this.$xNoPeers.style.opacity = "1";
|
||||
this.$xInstructions.style.opacity = "0.5";
|
||||
this.$center.style.opacity = "1";
|
||||
this.$logo.style.opacity = "1";
|
||||
this.$discoveryWrapper.style.opacity = "1";
|
||||
this.$knownAsWrapper.style.opacity = "1";
|
||||
|
||||
|
||||
Events.on('peer-added', _ => this.evaluateOverflowing());
|
||||
Events.on('bg-resize', _ => this.evaluateOverflowing());
|
||||
Events.on('peer-added', _ => this._evaluateOverflowing());
|
||||
Events.on('bg-resize', _ => this._evaluateOverflowing());
|
||||
|
||||
this.$displayName = $('display-name');
|
||||
|
||||
|
@ -75,11 +63,45 @@ class PeersUI {
|
|||
if (displayName) Events.fire('self-display-name-changed', displayName);
|
||||
});
|
||||
|
||||
Events.on('evaluate-footer-badges', _ => this._evaluateFooterBadges())
|
||||
|
||||
/* prevent animation on load */
|
||||
this.fadedIn = false;
|
||||
|
||||
this.$header = document.querySelector('header.opacity-0');
|
||||
Events.on('header-evaluated', () => this._fadeInHeader());
|
||||
}
|
||||
|
||||
_fadeInHeader() {
|
||||
//prevent flickering
|
||||
setTimeout(() => this.$header.classList.remove('opacity-0'), 50);
|
||||
}
|
||||
|
||||
_fadeInUI() {
|
||||
if (this.fadedIn) return;
|
||||
|
||||
this.fadedIn = true;
|
||||
|
||||
this.$center.classList.remove('opacity-0');
|
||||
this.$footer.classList.remove('opacity-0');
|
||||
|
||||
// Prevent flickering on load
|
||||
setTimeout(_ => {
|
||||
this.$xNoPeers.style.animationIterationCount = "1";
|
||||
}, 300);
|
||||
this.$xNoPeers.classList.remove('no-animation-on-load');
|
||||
}, 600);
|
||||
|
||||
Events.fire('ui-faded-in');
|
||||
}
|
||||
|
||||
_evaluateFooterBadges() {
|
||||
if (this.$discoveryWrapper.querySelectorAll('div:last-of-type > span[hidden]').length < 2) {
|
||||
this.$discoveryWrapper.classList.remove('row');
|
||||
this.$discoveryWrapper.classList.add('column');
|
||||
} else {
|
||||
this.$discoveryWrapper.classList.remove('column');
|
||||
this.$discoveryWrapper.classList.add('row');
|
||||
}
|
||||
Events.fire('redraw-canvas');
|
||||
this._fadeInUI();
|
||||
}
|
||||
|
||||
_insertDisplayName(displayName) {
|
||||
|
@ -162,6 +184,11 @@ class PeersUI {
|
|||
if (document.querySelectorAll('x-dialog[show]').length === 0 && window.pasteMode.activated && e.code === "Escape") {
|
||||
Events.fire('deactivate-paste-mode');
|
||||
}
|
||||
|
||||
// close About PairDrop page on Escape
|
||||
if (e.key === "Escape") {
|
||||
window.location.hash = '#';
|
||||
}
|
||||
}
|
||||
|
||||
_onPeerJoined(msg) {
|
||||
|
@ -207,7 +234,7 @@ class PeersUI {
|
|||
Object.keys(peer._roomIds).forEach(roomType => peerNode.classList.add(`type-${roomType}`));
|
||||
}
|
||||
|
||||
evaluateOverflowing() {
|
||||
_evaluateOverflowing() {
|
||||
if (this.$xPeers.clientHeight < this.$xPeers.scrollHeight) {
|
||||
this.$xPeers.classList.add('overflowing');
|
||||
} else {
|
||||
|
@ -223,7 +250,7 @@ class PeersUI {
|
|||
const $peer = $(peerId);
|
||||
if (!$peer) return;
|
||||
$peer.remove();
|
||||
this.evaluateOverflowing();
|
||||
this._evaluateOverflowing();
|
||||
}
|
||||
|
||||
_onRoomTypeRemoved(peerId, roomType) {
|
||||
|
@ -610,7 +637,6 @@ class Dialog {
|
|||
this.$el = $(id);
|
||||
this.$el.querySelectorAll('[close]').forEach(el => el.addEventListener('click', _ => this.hide()));
|
||||
this.$autoFocus = this.$el.querySelector('[autofocus]');
|
||||
this.$discoveryWrapper = $$('footer .discovery-wrapper');
|
||||
|
||||
Events.on('peer-disconnected', e => this._onPeerDisconnected(e.detail));
|
||||
}
|
||||
|
@ -631,7 +657,7 @@ class Dialog {
|
|||
window.blur();
|
||||
}
|
||||
document.title = 'PairDrop';
|
||||
document.changeFavicon("images/favicon-96x96.png");
|
||||
changeFavicon("images/favicon-96x96.png");
|
||||
this.correspondingPeerId = undefined;
|
||||
}
|
||||
|
||||
|
@ -641,17 +667,6 @@ class Dialog {
|
|||
Events.fire('notify-user', Localization.getTranslation("notifications.selected-peer-left"));
|
||||
}
|
||||
}
|
||||
|
||||
evaluateFooterBadges() {
|
||||
if (this.$discoveryWrapper.querySelectorAll('div:last-of-type > span[hidden]').length < 2) {
|
||||
this.$discoveryWrapper.classList.remove('row');
|
||||
this.$discoveryWrapper.classList.add('column');
|
||||
} else {
|
||||
this.$discoveryWrapper.classList.remove('column');
|
||||
this.$discoveryWrapper.classList.add('row');
|
||||
}
|
||||
Events.fire('bg-resize');
|
||||
}
|
||||
}
|
||||
|
||||
class LanguageSelectDialog extends Dialog {
|
||||
|
@ -931,7 +946,7 @@ class ReceiveFileDialog extends ReceiveDialog {
|
|||
document.title = files.length === 1
|
||||
? `${ Localization.getTranslation("document-titles.file-received") } - PairDrop`
|
||||
: `${ Localization.getTranslation("document-titles.file-received-plural", null, {count: files.length}) } - PairDrop`;
|
||||
document.changeFavicon("images/favicon-96x96-notification.png");
|
||||
changeFavicon("images/favicon-96x96-notification.png");
|
||||
|
||||
Events.fire('set-progress', {peerId: peerId, progress: 1, status: 'process'})
|
||||
this.show();
|
||||
|
@ -1028,7 +1043,7 @@ class ReceiveRequestDialog extends ReceiveDialog {
|
|||
this.$receiveTitle.innerText = transferRequestTitle;
|
||||
|
||||
document.title = `${transferRequestTitle} - PairDrop`;
|
||||
document.changeFavicon("images/favicon-96x96-notification.png");
|
||||
changeFavicon("images/favicon-96x96-notification.png");
|
||||
this.show();
|
||||
}
|
||||
|
||||
|
@ -1192,7 +1207,6 @@ class PairDeviceDialog extends Dialog {
|
|||
this.$closeBtn.addEventListener('click', _ => this._close());
|
||||
|
||||
Events.on('keydown', e => this._onKeyDown(e));
|
||||
Events.on('ws-connected', _ => this._onWsConnected());
|
||||
Events.on('ws-disconnected', _ => this.hide());
|
||||
Events.on('pair-device-initiated', e => this._onPairDeviceInitiated(e.detail));
|
||||
Events.on('pair-device-joined', e => this._onPairDeviceJoined(e.detail.peerId, e.detail.roomSecret));
|
||||
|
@ -1207,6 +1221,8 @@ class PairDeviceDialog extends Dialog {
|
|||
this.evaluateUrlAttributes();
|
||||
|
||||
this.pairPeer = {};
|
||||
|
||||
this._evaluateNumberRoomSecrets();
|
||||
}
|
||||
|
||||
_onKeyDown(e) {
|
||||
|
@ -1231,10 +1247,6 @@ class PairDeviceDialog extends Dialog {
|
|||
}
|
||||
}
|
||||
|
||||
_onWsConnected() {
|
||||
this._evaluateNumberRoomSecrets();
|
||||
}
|
||||
|
||||
_pairDeviceInitiate() {
|
||||
Events.fire('pair-device-initiate');
|
||||
}
|
||||
|
@ -1382,16 +1394,17 @@ class PairDeviceDialog extends Dialog {
|
|||
}
|
||||
|
||||
_evaluateNumberRoomSecrets() {
|
||||
PersistentStorage.getAllRoomSecrets().then(roomSecrets => {
|
||||
if (roomSecrets.length > 0) {
|
||||
this.$editPairedDevicesHeaderBtn.removeAttribute('hidden');
|
||||
this.$footerInstructionsPairedDevices.removeAttribute('hidden');
|
||||
} else {
|
||||
this.$editPairedDevicesHeaderBtn.setAttribute('hidden', '');
|
||||
this.$footerInstructionsPairedDevices.setAttribute('hidden', '');
|
||||
}
|
||||
super.evaluateFooterBadges();
|
||||
});
|
||||
PersistentStorage.getAllRoomSecrets()
|
||||
.then(roomSecrets => {
|
||||
if (roomSecrets.length > 0) {
|
||||
this.$editPairedDevicesHeaderBtn.removeAttribute('hidden');
|
||||
this.$footerInstructionsPairedDevices.removeAttribute('hidden');
|
||||
} else {
|
||||
this.$editPairedDevicesHeaderBtn.setAttribute('hidden', '');
|
||||
this.$footerInstructionsPairedDevices.setAttribute('hidden', '');
|
||||
}
|
||||
Events.fire('evaluate-footer-badges');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1399,10 +1412,10 @@ class EditPairedDevicesDialog extends Dialog {
|
|||
constructor() {
|
||||
super('edit-paired-devices-dialog');
|
||||
this.$pairedDevicesWrapper = this.$el.querySelector('.paired-devices-wrapper');
|
||||
this.$footerInstructionsPairedDevices = $$('.discovery-wrapper .badge-room-secret');
|
||||
this.$footerBadgePairedDevices = $$('.discovery-wrapper .badge-room-secret');
|
||||
|
||||
$('edit-paired-devices').addEventListener('click', _ => this._onEditPairedDevices());
|
||||
this.$footerInstructionsPairedDevices.addEventListener('click', _ => this._onEditPairedDevices());
|
||||
this.$footerBadgePairedDevices.addEventListener('click', _ => this._onEditPairedDevices());
|
||||
|
||||
Events.on('peer-display-name-changed', e => this._onPeerDisplayNameChanged(e));
|
||||
Events.on('keydown', e => this._onKeyDown(e));
|
||||
|
@ -1510,7 +1523,7 @@ class PublicRoomDialog extends Dialog {
|
|||
this.$leaveBtn = this.$el.querySelector('.leave-room');
|
||||
this.$joinSubmitBtn = this.$el.querySelector('button[type="submit"]');
|
||||
this.$headerBtnJoinPublicRoom = $('join-public-room');
|
||||
this.$footerInstructionsPublicRoomDevices = $$('.discovery-wrapper .badge-room-public-id');
|
||||
this.$footerBadgePublicRoomDevices = $$('.discovery-wrapper .badge-room-public-id');
|
||||
|
||||
|
||||
this.$form.addEventListener('submit', e => this._onSubmit(e));
|
||||
|
@ -1518,7 +1531,7 @@ class PublicRoomDialog extends Dialog {
|
|||
this.$leaveBtn.addEventListener('click', _ => this._leavePublicRoom())
|
||||
|
||||
this.$headerBtnJoinPublicRoom.addEventListener('click', _ => this._onHeaderBtnClick());
|
||||
this.$footerInstructionsPublicRoomDevices.addEventListener('click', _ => this._onHeaderBtnClick());
|
||||
this.$footerBadgePublicRoomDevices.addEventListener('click', _ => this._onHeaderBtnClick());
|
||||
|
||||
this.inputKeyContainer = new InputKeyContainer(
|
||||
this.$el.querySelector('.input-key-container'),
|
||||
|
@ -1600,12 +1613,12 @@ class PublicRoomDialog extends Dialog {
|
|||
setFooterBadge() {
|
||||
if (!this.roomId) return;
|
||||
|
||||
this.$footerInstructionsPublicRoomDevices.innerText = Localization.getTranslation("footer.public-room-devices", null, {
|
||||
this.$footerBadgePublicRoomDevices.innerText = Localization.getTranslation("footer.public-room-devices", null, {
|
||||
roomId: this.roomId.toUpperCase()
|
||||
});
|
||||
this.$footerInstructionsPublicRoomDevices.removeAttribute('hidden');
|
||||
this.$footerBadgePublicRoomDevices.removeAttribute('hidden');
|
||||
|
||||
super.evaluateFooterBadges();
|
||||
Events.fire('evaluate-footer-badges');
|
||||
}
|
||||
|
||||
_getShareRoomURL() {
|
||||
|
@ -1717,8 +1730,8 @@ class PublicRoomDialog extends Dialog {
|
|||
this.roomId = null;
|
||||
this.inputKeyContainer._cleanUp();
|
||||
sessionStorage.removeItem('public_room_id');
|
||||
this.$footerInstructionsPublicRoomDevices.setAttribute('hidden', '');
|
||||
super.evaluateFooterBadges();
|
||||
this.$footerBadgePublicRoomDevices.setAttribute('hidden', '');
|
||||
Events.fire('evaluate-footer-badges');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1849,7 +1862,7 @@ class ReceiveTextDialog extends Dialog {
|
|||
|
||||
this._setDocumentTitleMessages();
|
||||
|
||||
document.changeFavicon("images/favicon-96x96-notification.png");
|
||||
changeFavicon("images/favicon-96x96-notification.png");
|
||||
this.show();
|
||||
}
|
||||
|
||||
|
@ -2059,15 +2072,20 @@ class Notifications {
|
|||
|
||||
constructor() {
|
||||
// Check if the browser supports notifications
|
||||
if (!('Notification' in window)) return;
|
||||
if (!('Notification' in window)) {
|
||||
Events.fire('header-evaluated');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether notification permissions have already been granted
|
||||
if (Notification.permission !== 'granted') {
|
||||
this.$button = $('notification');
|
||||
this.$button.removeAttribute('hidden');
|
||||
this.$button.addEventListener('click', _ => this._requestPermission());
|
||||
this.$headerNotificationButton = $('notification');
|
||||
this.$headerNotificationButton.removeAttribute('hidden');
|
||||
this.$headerNotificationButton.addEventListener('click', _ => this._requestPermission());
|
||||
}
|
||||
|
||||
Events.fire('header-evaluated');
|
||||
|
||||
Events.on('text-received', e => this._messageNotification(e.detail.text, e.detail.peerId));
|
||||
Events.on('files-received', e => this._downloadNotification(e.detail.files));
|
||||
Events.on('files-transfer-request', e => this._requestNotification(e.detail.request, e.detail.peerId));
|
||||
|
@ -2080,7 +2098,7 @@ class Notifications {
|
|||
return;
|
||||
}
|
||||
Events.fire('notify-user', Localization.getTranslation("notifications.notifications-enabled"));
|
||||
this.$button.setAttribute('hidden', "");
|
||||
this.$headerNotificationButton.setAttribute('hidden', "");
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -2462,7 +2480,7 @@ class PersistentStorage {
|
|||
return(secrets);
|
||||
} catch (e) {
|
||||
this.logBrowserNotCapable();
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2680,12 +2698,71 @@ class BrowserTabsConnector {
|
|||
}
|
||||
}
|
||||
|
||||
class BackgroundCanvas {
|
||||
constructor() {
|
||||
this.c = $$('canvas');
|
||||
this.cCtx = this.c.getContext('2d');
|
||||
this.$footer = $$('footer');
|
||||
|
||||
Events.on('bg-resize', _ => this.init());
|
||||
Events.on('redraw-canvas', _ => this.init());
|
||||
Events.on('translation-loaded', _ => this.init());
|
||||
|
||||
//fade-in on load
|
||||
Events.on('ui-faded-in', _ => this._fadeIn());
|
||||
|
||||
window.onresize = _ => Events.fire('bg-resize');
|
||||
}
|
||||
|
||||
_fadeIn() {
|
||||
this.c.classList.remove('opacity-0');
|
||||
}
|
||||
|
||||
init() {
|
||||
let oldW = this.w;
|
||||
let oldH = this.h;
|
||||
let oldOffset = this.offset
|
||||
this.w = document.documentElement.clientWidth;
|
||||
this.h = document.documentElement.clientHeight;
|
||||
this.offset = this.$footer.offsetHeight - 27;
|
||||
if (this.h >= 800) this.offset += 10;
|
||||
|
||||
if (oldW === this.w && oldH === this.h && oldOffset === this.offset) return; // nothing has changed
|
||||
|
||||
this.c.width = this.w;
|
||||
this.c.height = this.h;
|
||||
this.x0 = this.w / 2;
|
||||
this.y0 = this.h - this.offset;
|
||||
this.dw = Math.round(Math.max(this.w, this.h, 1000) / 13);
|
||||
|
||||
this.drawCircles(this.cCtx);
|
||||
}
|
||||
|
||||
|
||||
drawCircle(ctx, radius) {
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = 2;
|
||||
let opacity = Math.max(0, 0.3 * (1 - 1 * radius / Math.max(this.w, this.h)));
|
||||
ctx.strokeStyle = `rgba(128, 128, 128, ${opacity})`;
|
||||
ctx.arc(this.x0, this.y0, radius, 0, 2 * Math.PI);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
drawCircles(ctx) {
|
||||
ctx.clearRect(0, 0, this.w, this.h);
|
||||
for (let i = 0; i < 13; i++) {
|
||||
this.drawCircle(ctx, this.dw * i + 33 + 66);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PairDrop {
|
||||
constructor() {
|
||||
Events.on('initial-translation-loaded', _ => {
|
||||
const server = new ServerConnection();
|
||||
const peers = new PeersManager(server);
|
||||
const peersUI = new PeersUI();
|
||||
const backgroundCanvas = new BackgroundCanvas();
|
||||
const languageSelectDialog = new LanguageSelectDialog();
|
||||
const receiveFileDialog = new ReceiveFileDialog();
|
||||
const receiveRequestDialog = new ReceiveRequestDialog();
|
||||
|
@ -2710,7 +2787,6 @@ const persistentStorage = new PersistentStorage();
|
|||
const pairDrop = new PairDrop();
|
||||
const localization = new Localization();
|
||||
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('/service-worker.js')
|
||||
.then(serviceWorker => {
|
||||
|
@ -2728,62 +2804,3 @@ window.addEventListener('beforeinstallprompt', e => {
|
|||
}
|
||||
return e.preventDefault();
|
||||
});
|
||||
|
||||
// Background Circles
|
||||
Events.on('load', () => {
|
||||
let c = $$('canvas');
|
||||
let cCtx = c.getContext('2d');
|
||||
let x0, y0, w, h, dw, offset;
|
||||
|
||||
function init() {
|
||||
let oldW = w;
|
||||
let oldH = h;
|
||||
let oldOffset = offset
|
||||
w = document.documentElement.clientWidth;
|
||||
h = document.documentElement.clientHeight;
|
||||
offset = $$('footer').offsetHeight - 27;
|
||||
|
||||
if (oldW === w && oldH === h && oldOffset === offset) return; // nothing has changed
|
||||
|
||||
c.width = w;
|
||||
c.height = h;
|
||||
x0 = w / 2;
|
||||
y0 = h - offset;
|
||||
dw = Math.round(Math.max(w, h, 1000) / 13);
|
||||
|
||||
drawCircles(cCtx, dw);
|
||||
c.style.opacity = "1";
|
||||
}
|
||||
|
||||
Events.on('translation-loaded', _ => init());
|
||||
Events.on('bg-resize', _ => init());
|
||||
window.onresize = _ => Events.fire('bg-resize');
|
||||
|
||||
function drawCircle(ctx, radius) {
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = 2;
|
||||
let opacity = 0.3 * (1 - 1.2 * radius / Math.max(w, h));
|
||||
ctx.strokeStyle = `rgba(128, 128, 128, ${opacity})`;
|
||||
ctx.arc(x0, y0, radius, 0, 2 * Math.PI);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
function drawCircles(ctx, frame) {
|
||||
ctx.clearRect(0, 0, w, h);
|
||||
for (let i = 0; i < 13; i++) {
|
||||
drawCircle(ctx, dw * i + frame + 33);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.changeFavicon = function (src) {
|
||||
document.querySelector('[rel="icon"]').href = src;
|
||||
document.querySelector('[rel="shortcut icon"]').href = src;
|
||||
}
|
||||
|
||||
// close About PairDrop page on Escape
|
||||
window.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Escape") {
|
||||
window.location.hash = '#';
|
||||
}
|
||||
});
|
||||
|
|
|
@ -407,6 +407,11 @@ function getUrlWithoutArguments() {
|
|||
return `${window.location.protocol}//${window.location.host}${window.location.pathname}`;
|
||||
}
|
||||
|
||||
function changeFavicon(src) {
|
||||
document.querySelector('[rel="icon"]').href = src;
|
||||
document.querySelector('[rel="shortcut icon"]').href = src;
|
||||
}
|
||||
|
||||
function arrayBufferToBase64(buffer) {
|
||||
var binary = '';
|
||||
var bytes = new Uint8Array(buffer);
|
||||
|
@ -425,4 +430,4 @@ function base64ToArrayBuffer(base64) {
|
|||
bytes[i] = binary_string.charCodeAt(i);
|
||||
}
|
||||
return bytes.buffer;
|
||||
}
|
||||
}
|
|
@ -274,6 +274,9 @@ x-noscript {
|
|||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
#center {
|
||||
|
@ -422,10 +425,6 @@ x-no-peers {
|
|||
padding: 8px;
|
||||
height: 137px;
|
||||
text-align: center;
|
||||
animation: fade-in 600ms;
|
||||
animation-fill-mode: backwards;
|
||||
/* prevent flickering on load */
|
||||
animation-iteration-count: 0;
|
||||
}
|
||||
|
||||
x-no-peers h2,
|
||||
|
@ -643,7 +642,6 @@ footer .logo {
|
|||
margin-bottom: 8px;
|
||||
color: var(--primary-color);
|
||||
margin-top: -10px;
|
||||
animation: ease-in;
|
||||
}
|
||||
|
||||
.discovery-wrapper {
|
||||
|
@ -1258,22 +1256,23 @@ button::-moz-focus-inner {
|
|||
z-index: 1;
|
||||
}
|
||||
|
||||
#about:not(:target) header.fade-in {
|
||||
#about:not(:target) header {
|
||||
transition-delay: 400ms;
|
||||
}
|
||||
|
||||
#about:target header.fade-in {
|
||||
#about:target header {
|
||||
transition-delay: 100ms;
|
||||
}
|
||||
|
||||
#about .fade-in {
|
||||
#about > * {
|
||||
transition: opacity 300ms ease 300ms;
|
||||
will-change: opacity;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
#about:not(:target) .fade-in {
|
||||
opacity: 0 !important;
|
||||
#about:not(:target) > header,
|
||||
#about:not(:target) > section {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition-delay: 0s;
|
||||
}
|
||||
|
@ -1452,17 +1451,17 @@ x-peers:empty~x-instructions {
|
|||
|
||||
/* Prevent Cumulative Layout Shift */
|
||||
|
||||
body > header,
|
||||
canvas,
|
||||
#center,
|
||||
x-no-peers,
|
||||
x-peers,
|
||||
x-instructions,
|
||||
footer > .icon.logo,
|
||||
.discovery-wrapper,
|
||||
.known-as-wrapper {
|
||||
transition: opacity 0.5s ease 0.1s;
|
||||
opacity: 0; /* will be set to 1 after initial translation is loaded */
|
||||
.fade-in {
|
||||
animation: fade-in 600ms;
|
||||
animation-fill-mode: backwards;
|
||||
}
|
||||
|
||||
.no-animation-on-load {
|
||||
animation-iteration-count: 0;
|
||||
}
|
||||
|
||||
.opacity-0 {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* Responsive Styles */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue