From fdf024f3787804a179af0fcf55dda3a62f939cfa Mon Sep 17 00:00:00 2001 From: schlagmichdoch Date: Mon, 6 Mar 2023 02:18:07 +0100 Subject: [PATCH] pairdrop-cli: add fallback if navigator.clipboard.readText() is not available --- public/index.html | 1 + public/scripts/ui.js | 85 +++++++++++++---------- public/styles.css | 21 +++++- public_included_ws_fallback/index.html | 1 + public_included_ws_fallback/scripts/ui.js | 85 +++++++++++++---------- public_included_ws_fallback/styles.css | 21 +++++- 6 files changed, 140 insertions(+), 74 deletions(-) diff --git a/public/index.html b/public/index.html index cbb0337..ad8658b 100644 --- a/public/index.html +++ b/public/index.html @@ -238,6 +238,7 @@ + diff --git a/public/scripts/ui.js b/public/scripts/ui.js index b7e75f3..62c1f83 100644 --- a/public/scripts/ui.js +++ b/public/scripts/ui.js @@ -1245,21 +1245,21 @@ class Base64ZipDialog extends Dialog { const base64Hash = window.location.hash.substring(1); this.$pasteBtn = this.$el.querySelector('#base64-paste-btn'); + this.$fallbackTextarea = this.$el.querySelector('.textarea'); if (base64Text) { this.show(); if (base64Text === "paste") { // ?base64text=paste // base64 encoded string is ready to be pasted from clipboard - this.$pasteBtn.innerText = 'Tap here to paste text'; - this.$pasteBtn.addEventListener('click', _ => this.processClipboard('text')); + this.preparePasting("text"); } else if (base64Text === "hash") { // ?base64text=hash#BASE64ENCODED // base64 encoded string is url hash which is never sent to server and faster (recommended) this.processBase64Text(base64Hash) .catch(_ => { Events.fire('notify-user', 'Text content is incorrect.'); - console.log("Text content incorrect.") + console.log("Text content incorrect."); }).finally(_ => { this.hide(); }); @@ -1269,7 +1269,7 @@ class Base64ZipDialog extends Dialog { this.processBase64Text(base64Text) .catch(_ => { Events.fire('notify-user', 'Text content is incorrect.'); - console.log("Text content incorrect.") + console.log("Text content incorrect."); }).finally(_ => { this.hide(); }); @@ -1282,14 +1282,13 @@ class Base64ZipDialog extends Dialog { this.processBase64Zip(base64Hash) .catch(_ => { Events.fire('notify-user', 'File content is incorrect.'); - console.log("File content incorrect.") + console.log("File content incorrect."); }).finally(_ => { this.hide(); }); } else { // ?base64zip=paste || ?base64zip=true - this.$pasteBtn.innerText = 'Tap here to paste files'; - this.$pasteBtn.addEventListener('click', _ => this.processClipboard('file')); + this.preparePasting('files'); } } } @@ -1299,39 +1298,53 @@ class Base64ZipDialog extends Dialog { this.$pasteBtn.innerText = "Processing..."; } - async processClipboard(type) { - if (!navigator.clipboard.readText) { - Events.fire('notify-user', 'This feature is not available on your browser.'); - console.log("navigator.clipboard.readText() is not available on your browser.") - this.hide(); - return; - } - - this._setPasteBtnToProcessing(); - - const base64 = await navigator.clipboard.readText(); - - if (!base64) return; - - if (type === "text") { - this.processBase64Text(base64) - .catch(_ => { - Events.fire('notify-user', 'Clipboard content is incorrect.'); - console.log("Clipboard content is incorrect.") - }).finally(_ => { - this.hide(); - }); + preparePasting(type) { + if (navigator.clipboard.readText) { + this.$pasteBtn.innerText = `Tap here to paste ${type}`; + this.$pasteBtn.addEventListener('click', _ => this.processClipboard(type), { once: true }); } else { - this.processBase64Zip(base64) - .catch(_ => { - Events.fire('notify-user', 'Clipboard content is incorrect.'); - console.log("Clipboard content is incorrect.") - }).finally(_ => { - this.hide(); - }); + console.log("`navigator.clipboard.readText()` is not available on your browser.\nOn Firefox you can set `dom.events.asyncClipboard.readText` to true under `about:config` for convenience.") + this.$pasteBtn.setAttribute('hidden', ''); + this.$fallbackTextarea.setAttribute('placeholder', `Paste here to send ${type}`); + this.$fallbackTextarea.removeAttribute('hidden'); + this.$fallbackTextarea.addEventListener('input', _ => this.processInput(type), { once: true }); + this.$fallbackTextarea.focus(); } } + async processInput(type) { + const base64 = this.$fallbackTextarea.textContent; + this.$fallbackTextarea.textContent = ''; + try { + // check if input is base64 encoded + window.atob(base64); + await this.processBase64(type, base64); + } catch (e) { + // input is not base64 string. Do nothing. + } + } + + async processClipboard(type) { + this._setPasteBtnToProcessing(); + const base64 = await navigator.clipboard.readText(); + await this.processBase64(type, base64); + } + + async processBase64(type, base64) { + if (!base64) return; + try { + if (type === "text") { + await this.processBase64Text(base64); + } else { + await this.processBase64Zip(base64); + } + } catch(_) { + Events.fire('notify-user', 'Clipboard content is incorrect.'); + console.log("Clipboard content is incorrect.") + } + this.hide(); + } + processBase64Text(base64Text){ return new Promise((resolve) => { this._setPasteBtnToProcessing(); diff --git a/public/styles.css b/public/styles.css index 237764e..db87050 100644 --- a/public/styles.css +++ b/public/styles.css @@ -791,10 +791,29 @@ x-dialog .dialog-subheader { margin: auto -24px; } -#base64-paste-btn { +#base64-paste-btn, +#base64-paste-dialog .textarea { width: 100%; height: 40vh; border: solid 12px #438cff; + text-align: center; +} + +#base64-paste-dialog .textarea { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; +} + +#base64-paste-dialog .textarea::before { + font-size: 15px; + letter-spacing: 0.12em; + color: var(--primary-color); + font-weight: 700; + text-transform: uppercase; + content: attr(placeholder); } #base64-paste-dialog button { diff --git a/public_included_ws_fallback/index.html b/public_included_ws_fallback/index.html index a2a4b4d..549e16e 100644 --- a/public_included_ws_fallback/index.html +++ b/public_included_ws_fallback/index.html @@ -241,6 +241,7 @@ + diff --git a/public_included_ws_fallback/scripts/ui.js b/public_included_ws_fallback/scripts/ui.js index 896608e..b1f666b 100644 --- a/public_included_ws_fallback/scripts/ui.js +++ b/public_included_ws_fallback/scripts/ui.js @@ -1246,21 +1246,21 @@ class Base64ZipDialog extends Dialog { const base64Hash = window.location.hash.substring(1); this.$pasteBtn = this.$el.querySelector('#base64-paste-btn'); + this.$fallbackTextarea = this.$el.querySelector('.textarea'); if (base64Text) { this.show(); if (base64Text === "paste") { // ?base64text=paste // base64 encoded string is ready to be pasted from clipboard - this.$pasteBtn.innerText = 'Tap here to paste text'; - this.$pasteBtn.addEventListener('click', _ => this.processClipboard('text')); + this.preparePasting("text"); } else if (base64Text === "hash") { // ?base64text=hash#BASE64ENCODED // base64 encoded string is url hash which is never sent to server and faster (recommended) this.processBase64Text(base64Hash) .catch(_ => { Events.fire('notify-user', 'Text content is incorrect.'); - console.log("Text content incorrect.") + console.log("Text content incorrect."); }).finally(_ => { this.hide(); }); @@ -1270,7 +1270,7 @@ class Base64ZipDialog extends Dialog { this.processBase64Text(base64Text) .catch(_ => { Events.fire('notify-user', 'Text content is incorrect.'); - console.log("Text content incorrect.") + console.log("Text content incorrect."); }).finally(_ => { this.hide(); }); @@ -1283,14 +1283,13 @@ class Base64ZipDialog extends Dialog { this.processBase64Zip(base64Hash) .catch(_ => { Events.fire('notify-user', 'File content is incorrect.'); - console.log("File content incorrect.") + console.log("File content incorrect."); }).finally(_ => { this.hide(); }); } else { // ?base64zip=paste || ?base64zip=true - this.$pasteBtn.innerText = 'Tap here to paste files'; - this.$pasteBtn.addEventListener('click', _ => this.processClipboard('file')); + this.preparePasting('files'); } } } @@ -1300,39 +1299,53 @@ class Base64ZipDialog extends Dialog { this.$pasteBtn.innerText = "Processing..."; } - async processClipboard(type) { - if (!navigator.clipboard.readText) { - Events.fire('notify-user', 'This feature is not available on your browser.'); - console.log("navigator.clipboard.readText() is not available on your browser.") - this.hide(); - return; - } - - this._setPasteBtnToProcessing(); - - const base64 = await navigator.clipboard.readText(); - - if (!base64) return; - - if (type === "text") { - this.processBase64Text(base64) - .catch(_ => { - Events.fire('notify-user', 'Clipboard content is incorrect.'); - console.log("Clipboard content is incorrect.") - }).finally(_ => { - this.hide(); - }); + preparePasting(type) { + if (navigator.clipboard.readText) { + this.$pasteBtn.innerText = `Tap here to paste ${type}`; + this.$pasteBtn.addEventListener('click', _ => this.processClipboard(type), { once: true }); } else { - this.processBase64Zip(base64) - .catch(_ => { - Events.fire('notify-user', 'Clipboard content is incorrect.'); - console.log("Clipboard content is incorrect.") - }).finally(_ => { - this.hide(); - }); + console.log("`navigator.clipboard.readText()` is not available on your browser.\nOn Firefox you can set `dom.events.asyncClipboard.readText` to true under `about:config` for convenience.") + this.$pasteBtn.setAttribute('hidden', ''); + this.$fallbackTextarea.setAttribute('placeholder', `Paste here to send ${type}`); + this.$fallbackTextarea.removeAttribute('hidden'); + this.$fallbackTextarea.addEventListener('input', _ => this.processInput(type), { once: true }); + this.$fallbackTextarea.focus(); } } + async processInput(type) { + const base64 = this.$fallbackTextarea.textContent; + this.$fallbackTextarea.textContent = ''; + try { + // check if input is base64 encoded + window.atob(base64); + await this.processBase64(type, base64); + } catch (e) { + // input is not base64 string. Do nothing. + } + } + + async processClipboard(type) { + this._setPasteBtnToProcessing(); + const base64 = await navigator.clipboard.readText(); + await this.processBase64(type, base64); + } + + async processBase64(type, base64) { + if (!base64) return; + try { + if (type === "text") { + await this.processBase64Text(base64); + } else { + await this.processBase64Zip(base64); + } + } catch(_) { + Events.fire('notify-user', 'Clipboard content is incorrect.'); + console.log("Clipboard content is incorrect.") + } + this.hide(); + } + processBase64Text(base64Text){ return new Promise((resolve) => { this._setPasteBtnToProcessing(); diff --git a/public_included_ws_fallback/styles.css b/public_included_ws_fallback/styles.css index 0f8742d..2d29898 100644 --- a/public_included_ws_fallback/styles.css +++ b/public_included_ws_fallback/styles.css @@ -817,10 +817,29 @@ x-dialog .dialog-subheader { margin: auto -24px; } -#base64-paste-btn { +#base64-paste-btn, +#base64-paste-dialog .textarea { width: 100%; height: 40vh; border: solid 12px #438cff; + text-align: center; +} + +#base64-paste-dialog .textarea { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; +} + +#base64-paste-dialog .textarea::before { + font-size: 15px; + letter-spacing: 0.12em; + color: var(--primary-color); + font-weight: 700; + text-transform: uppercase; + content: attr(placeholder); } #base64-paste-dialog button {