Compare commits

...

9 Commits

Author SHA1 Message Date
schlagmichdoch
d6287c4cf0 Increase version to v1.10.7
## Enhancements
- Implemented drag and drop into text fields
- Tidy up code
- Translations update from Hosted Weblate (Italian)

## Fixes
- Received URLs with single letter subdomains not hydrated into links #258
- Button does not change color on hover (#262 + #263)
- On Windows Edge, PeerUI shows „preparing“ when file selector is cancelled (#257)
2024-02-09 03:53:53 +01:00
schlagmichdoch
c83e55b448 Merge pull request #253 from weblate/weblate-pairdrop-pairdrop-spa
Translations update from Hosted Weblate
2024-02-09 03:46:54 +01:00
Hosted Weblate
49160f9b02 Translated using Weblate (Italian)
Currently translated at 100.0% (166 of 166 strings)

Translated using Weblate (Italian)

Currently translated at 87.9% (146 of 166 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Luca FiltroMan <FiltroMan@users.noreply.hosted.weblate.org>
Co-authored-by: Radosław Rudner <radek.rud112@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/pairdrop/pairdrop-spa/it/
Translation: PairDrop/pairdrop-spa
2024-02-09 03:46:01 +01:00
schlagmichdoch
7be2830a08 Merge pull request #259 from schlagmichdoch/fix_url_hydration
Prepare next patch version
2024-02-09 03:44:41 +01:00
schlagmichdoch
1f3dd080a0 Fix canceling file selector on Windows Edge sometimes blocks UI (#257) 2024-02-09 03:41:41 +01:00
schlagmichdoch
5d709966af Fix button color change on hover (fixes #262) 2024-02-09 03:40:21 +01:00
schlagmichdoch
99b0c6ff01 Fix URL not replaced with link node (fixes #258), beautify text via regex without rendering it, and fix execution order 2024-02-01 14:25:38 +01:00
schlagmichdoch
76e08927de Enable drag and drop and pasting in text fields; Tidy up existing drag and drop code. 2024-02-01 14:25:38 +01:00
schlagmichdoch
9118b0ae06 Use default line-height for textareas 2024-02-01 14:25:38 +01:00
10 changed files with 202 additions and 104 deletions

View File

@@ -36,7 +36,7 @@ If applicable, add screenshots to help explain your problem.
**Bug occurs on official PairDrop instance https://pairdrop.net/** **Bug occurs on official PairDrop instance https://pairdrop.net/**
No | Yes No | Yes
Version: v1.10.6 Version: v1.10.7
**Bug occurs on self-hosted PairDrop instance** **Bug occurs on self-hosted PairDrop instance**
No | Yes No | Yes
@@ -44,7 +44,7 @@ No | Yes
**Self-Hosted Setup** **Self-Hosted Setup**
Proxy: Nginx | Apache2 Proxy: Nginx | Apache2
Deployment: docker run | docker compose | npm run start:prod Deployment: docker run | docker compose | npm run start:prod
Version: v1.10.6 Version: v1.10.7
**Additional context** **Additional context**
Add any other context about the problem here. Add any other context about the problem here.

View File

@@ -45,11 +45,11 @@ This pairdrop-cli version was released alongside v1.10.4
#### Linux / Mac #### Linux / Mac
1. Download the latest _pairdrop-cli.zip_ from the [releases page](https://github.com/schlagmichdoch/PairDrop/releases) 1. Download the latest _pairdrop-cli.zip_ from the [releases page](https://github.com/schlagmichdoch/PairDrop/releases)
```shell ```shell
wget "https://github.com/schlagmichdoch/PairDrop/releases/download/v1.10.6/pairdrop-cli.zip" wget "https://github.com/schlagmichdoch/PairDrop/releases/download/v1.10.7/pairdrop-cli.zip"
``` ```
or or
```shell ```shell
curl -LO "https://github.com/schlagmichdoch/PairDrop/releases/download/v1.10.6/pairdrop-cli.zip" curl -LO "https://github.com/schlagmichdoch/PairDrop/releases/download/v1.10.7/pairdrop-cli.zip"
``` ```
2. Unzip the archive to a folder of your choice e.g. `/usr/share/pairdrop-cli/` 2. Unzip the archive to a folder of your choice e.g. `/usr/share/pairdrop-cli/`
```shell ```shell

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "pairdrop", "name": "pairdrop",
"version": "1.10.6", "version": "1.10.7",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "pairdrop", "name": "pairdrop",
"version": "1.10.6", "version": "1.10.7",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"express": "^4.18.2", "express": "^4.18.2",

View File

@@ -1,6 +1,6 @@
{ {
"name": "pairdrop", "name": "pairdrop",
"version": "1.10.6", "version": "1.10.7",
"type": "module", "type": "module",
"description": "", "description": "",
"main": "server/index.js", "main": "server/index.js",

View File

@@ -582,7 +582,7 @@
</svg> </svg>
<div class="title-wrapper" dir="ltr"> <div class="title-wrapper" dir="ltr">
<h1>PairDrop</h1> <h1>PairDrop</h1>
<div class="font-subheading">v1.10.6</div> <div class="font-subheading">v1.10.7</div>
</div> </div>
<div class="font-subheading" data-i18n-key="about.claim" data-i18n-attrs="text"></div> <div class="font-subheading" data-i18n-key="about.claim" data-i18n-attrs="text"></div>
<div class="row"> <div class="row">

View File

@@ -5,9 +5,9 @@
"display-name_data-placeholder": "Caricamento…", "display-name_data-placeholder": "Caricamento…",
"display-name_title": "Modifica il nome del tuo dispositivo permanentemente", "display-name_title": "Modifica il nome del tuo dispositivo permanentemente",
"traffic": "Il traffico è", "traffic": "Il traffico è",
"paired-devices_title": "Puoi essere rilevato dai dispositivi abbinati in ogni momento, indipendentemente dalla rete.", "paired-devices_title": "Puoi essere rilevato dai dispositivi associati in ogni momento, indipendentemente dalla rete.",
"public-room-devices": "nella stanza {{roomId}}", "public-room-devices": "nella stanza {{roomId}}",
"paired-devices": "da dispositivi abbinati", "paired-devices": "da dispositivi associati",
"on-this-network": "su questa rete", "on-this-network": "su questa rete",
"routed": "instradato attraverso il server", "routed": "instradato attraverso il server",
"discovery": "Puoi essere rilevato:", "discovery": "Puoi essere rilevato:",
@@ -15,7 +15,7 @@
"known-as": "Sei visibile come:" "known-as": "Sei visibile come:"
}, },
"header": { "header": {
"cancel-share-mode": "Fatto", "cancel-share-mode": "Annulla",
"theme-auto_title": "Adatta il tema al sistema automaticamente", "theme-auto_title": "Adatta il tema al sistema automaticamente",
"install_title": "Installa PairDrop", "install_title": "Installa PairDrop",
"theme-dark_title": "Usa sempre il tema scuro", "theme-dark_title": "Usa sempre il tema scuro",
@@ -26,13 +26,15 @@
"language-selector_title": "Imposta Lingua", "language-selector_title": "Imposta Lingua",
"about_title": "Informazioni su PairDrop", "about_title": "Informazioni su PairDrop",
"about_aria-label": "Apri Informazioni su PairDrop", "about_aria-label": "Apri Informazioni su PairDrop",
"theme-light_title": "Usa sempre il tema chiaro" "theme-light_title": "Usa sempre il tema chiaro",
"edit-share-mode": "Modifica",
"expand_title": "Espandi la riga dei pulsanti nell'intestazione"
}, },
"instructions": { "instructions": {
"x-instructions_mobile": "Tocca per inviare file o tocco prolungato per inviare un messaggio", "x-instructions_mobile": "Tocca per inviare file o tocco prolungato per inviare un messaggio",
"x-instructions-share-mode_desktop": "Clicca per inviare", "x-instructions-share-mode_desktop": "Clicca per inviare {{descriptor}}",
"activate-share-mode-and-other-files-plural": "e altri {{count}} files", "activate-share-mode-and-other-files-plural": "e altri {{count}} files",
"x-instructions-share-mode_mobile": "Tocca per inviare", "x-instructions-share-mode_mobile": "Tocca per inviare {{descriptor}}",
"activate-share-mode-base": "Apri PairDrop su altri dispositivi per inviare", "activate-share-mode-base": "Apri PairDrop su altri dispositivi per inviare",
"no-peers-subtitle": "Abbina dispositivi o entra in una stanza pubblica per essere rilevabile su altre reti", "no-peers-subtitle": "Abbina dispositivi o entra in una stanza pubblica per essere rilevabile su altre reti",
"activate-share-mode-shared-text": "testo condiviso", "activate-share-mode-shared-text": "testo condiviso",
@@ -41,23 +43,26 @@
"x-instructions_data-drop-peer": "Rilascia per inviare al peer", "x-instructions_data-drop-peer": "Rilascia per inviare al peer",
"x-instructions_data-drop-bg": "Rilascia per selezionare il destinatario", "x-instructions_data-drop-bg": "Rilascia per selezionare il destinatario",
"no-peers_data-drop-bg": "Rilascia per selezionare il destinatario", "no-peers_data-drop-bg": "Rilascia per selezionare il destinatario",
"webrtc-requirement": "Per usare questa istanza di PairDrop, devi attivare WebRTC!" "webrtc-requirement": "Per usare questa istanza di PairDrop, devi attivare WebRTC!",
"activate-share-mode-shared-file": "file condiviso",
"activate-share-mode-shared-files-plural": "{{count}} files condivisi",
"activate-share-mode-and-other-file": "ed 1 altro file"
}, },
"dialogs": { "dialogs": {
"auto-accept-instructions-2": "per accettare automaticamente tutti i files inviati da quel dispositivo.", "auto-accept-instructions-2": "per accettare automaticamente tutti i files inviati da quel dispositivo.",
"edit-paired-devices-title": "Modifica Dispositivi Abbinati", "edit-paired-devices-title": "Modifica Dispositivi Associati",
"cancel": "Annulla", "cancel": "Annulla",
"auto-accept-instructions-1": "Attiva", "auto-accept-instructions-1": "Attiva",
"pair-devices-title": "Abbina Dispositivi Permanentemente", "pair-devices-title": "Associa Dispositivi Permanentemente",
"temporary-public-room-title": "Stanza Pubblica Temporanea", "temporary-public-room-title": "Stanza Pubblica Temporanea",
"close": "Chiudi", "close": "Chiudi",
"unpair": "Dissocia", "unpair": "Dissocia",
"pair": "Abbina", "pair": "Associa",
"scan-qr-code": "o scannerizza il codice QR.", "scan-qr-code": "o scannerizza il codice QR.",
"input-key-on-this-device": "Inserisci questo codice su un altro dispositivo", "input-key-on-this-device": "Inserisci questo codice su un altro dispositivo",
"paired-devices-wrapper_data-empty": "Nessun dispositivo abbinato.", "paired-devices-wrapper_data-empty": "Nessun dispositivo associato.",
"enter-key-from-another-device": "Inserisci il codice dell'altro dispositivo qui.", "enter-key-from-another-device": "Inserisci il codice dell'altro dispositivo qui.",
"auto-accept": "accetta-automaticamente", "auto-accept": "accetta automaticamente",
"input-room-id-on-another-device": "Inserisci l'ID di questa stanza su un altro dispositivo", "input-room-id-on-another-device": "Inserisci l'ID di questa stanza su un altro dispositivo",
"enter-room-id-from-another-device": "Inserisci l'ID stanza da un altro dispositivo per accedere alla stanza.", "enter-room-id-from-another-device": "Inserisci l'ID stanza da un altro dispositivo per accedere alla stanza.",
"base64-paste-to-send": "Incolla qui per inviare {{type}}", "base64-paste-to-send": "Incolla qui per inviare {{type}}",
@@ -71,7 +76,7 @@
"join": "Unisciti", "join": "Unisciti",
"title-image-plural": "Immagini", "title-image-plural": "Immagini",
"send": "Invia", "send": "Invia",
"base64-tap-to-paste": "Tocca qui per incollare {{type}}", "base64-tap-to-paste": "Tocca qui per condividere {{type}}",
"base64-text": "testo", "base64-text": "testo",
"copy": "Copia", "copy": "Copia",
"file-other-description-image": "e 1 altra immagine", "file-other-description-image": "e 1 altra immagine",
@@ -82,7 +87,7 @@
"title-image": "Immagine", "title-image": "Immagine",
"file-other-description-file-plural": "e altri {{count}} files", "file-other-description-file-plural": "e altri {{count}} files",
"would-like-to-share": "vorrebbe condividere", "would-like-to-share": "vorrebbe condividere",
"send-message-to": "Invia un messaggio a", "send-message-to": "A:",
"language-selector-title": "Imposta Lingua", "language-selector-title": "Imposta Lingua",
"hr-or": "OPPURE", "hr-or": "OPPURE",
"download-again": "Scarica ancora", "download-again": "Scarica ancora",
@@ -92,11 +97,20 @@
"send-message-title": "Invia Messaggio", "send-message-title": "Invia Messaggio",
"file-other-description-image-plural": "e {{count}} altre immagini", "file-other-description-image-plural": "e {{count}} altre immagini",
"message_title": "Inserire messaggio da inviare", "message_title": "Inserire messaggio da inviare",
"pair-devices-qr-code_title": "Clicca per copiare il link di abbinamento di questo dispositivo", "pair-devices-qr-code_title": "Clicca per copiare il link di associazione a questo dispositivo",
"public-room-qr-code_title": "Clicca per copirare il link della stanza pubblica" "public-room-qr-code_title": "Clicca per copirare il link della stanza pubblica",
"message_placeholder": "Testo",
"paired-device-removed": "Il dispositivo associato è stato rimosso.",
"base64-title-files": "Condividi Files",
"base64-title-text": "Condividi Testo",
"share-text-subtitle": "Modifica messaggio prima dell'invio:",
"share-text-checkbox": "Mostra sempre questa casella di dialogo quando si condivide del testo",
"approve": "accetta",
"share-text-title": "Condividi Messaggio di Testo",
"close-toast_title": "Chiudi notifica"
}, },
"notifications": { "notifications": {
"request-title": "{{name}} vorrebbe trasferire {{count}} {{descriptor}}", "request-title": "{{name}} vorrebbe inviare {{count}} {{descriptor}}",
"unfinished-transfers-warning": "Ci sono dei trasferimenti in corso. Sei sicuro di voler chiudere PairDrop?", "unfinished-transfers-warning": "Ci sono dei trasferimenti in corso. Sei sicuro di voler chiudere PairDrop?",
"message-received": "Messaggio ricevuto da {{name}} - Clicca per copiare", "message-received": "Messaggio ricevuto da {{name}} - Clicca per copiare",
"rate-limit-join-key": "Limite raggiunto. Aspetta 10 secondi e riprova.", "rate-limit-join-key": "Limite raggiunto. Aspetta 10 secondi e riprova.",
@@ -104,22 +118,22 @@
"pairing-key-invalidated": "Il codice {{key}} è stato invalidato", "pairing-key-invalidated": "Il codice {{key}} è stato invalidato",
"pairing-key-invalid": "Codice non valido", "pairing-key-invalid": "Codice non valido",
"connected": "Connesso", "connected": "Connesso",
"pairing-not-persistent": "I dispositivi abbinati non sono persistenti", "pairing-not-persistent": "I dispositivi associati non sono permanenti",
"text-content-incorrect": "Il contenuto testuale non è corretto", "text-content-incorrect": "Il contenuto di testo è errato",
"message-transfer-completed": "Trasferimento del messaggio completato", "message-transfer-completed": "Trasferimento del messaggio completato",
"file-transfer-completed": "Trasferimento file completato", "file-transfer-completed": "Trasferimento file completato",
"file-content-incorrect": "Il contenuto del file non è corretto", "file-content-incorrect": "Il contenuto del file è errato",
"files-incorrect": "I file non sono corretti", "files-incorrect": "I file sono errati",
"selected-peer-left": "Peer selezionato ha abbandonato", "selected-peer-left": "Il peer selezionato ha abbandonato",
"link-received": "Link ricevuto da {{name}} - Clicca per aprire", "link-received": "Link ricevuto da {{name}} - Clicca per aprire",
"online": "Sei di nuovo online", "online": "Sei di nuovo online",
"public-room-left": "Ha lasciato la stanza pubblica {{publicRoomId}}", "public-room-left": "Hai abbandonato la stanza pubblica {{publicRoomId}}",
"copied-text": "Testo copiato negli appunti", "copied-text": "Testo copiato negli appunti",
"display-name-random-again": "Il nome visualizzato è generato casualmente un'altra volta", "display-name-random-again": "Il nome visualizzato viene di nuovo generato casualmente",
"display-name-changed-permanently": "Il nome visualizzato è cambiato permanentemente", "display-name-changed-permanently": "Il nome visualizzato è cambiato definitivamente",
"copied-to-clipboard-error": "La copia non è possibile. Copia manualmente.", "copied-to-clipboard-error": "La funzione di copia non è possibile. Copia manualmente.",
"pairing-success": "Dispositivi abbinati", "pairing-success": "Dispositivi associati",
"clipboard-content-incorrect": "Il contenuto copiato non è corretto", "clipboard-content-incorrect": "Il contenuto copiato è errato",
"display-name-changed-temporarily": "Il nome visualizzato è cambiato solo per questa sessione", "display-name-changed-temporarily": "Il nome visualizzato è cambiato solo per questa sessione",
"copied-to-clipboard": "Copiato negli appunti", "copied-to-clipboard": "Copiato negli appunti",
"offline": "Sei offline", "offline": "Sei offline",
@@ -128,14 +142,14 @@
"click-to-download": "Clicca per scaricare", "click-to-download": "Clicca per scaricare",
"pairing-cleared": "Tutti i dispositivi sono stati dissociati", "pairing-cleared": "Tutti i dispositivi sono stati dissociati",
"notifications-enabled": "Notifiche attivate", "notifications-enabled": "Notifiche attivate",
"online-requirement-pairing": "Devi essere online per abbinare dispositivi", "online-requirement-pairing": "Devi essere online per associare dispositivi",
"ios-memory-limit": "L'invio di file a dispositivi iOS è possibile solo 200 MB alla volta", "ios-memory-limit": "L'invio di file a dispositivi iOS è possibile solo 200 MB alla volta",
"online-requirement-public-room": "Devi essere online per creare una stanza pubblica", "online-requirement-public-room": "Devi essere online per creare una stanza pubblica",
"copied-text-error": "Scrittura negli appunti fallita. Copia manualmente!", "copied-text-error": "Scrittura negli appunti fallita. Copia manualmente!",
"download-successful": "{{descriptor}} scaricato", "download-successful": "{{descriptor}} scaricato",
"click-to-show": "Clicca per mostrare", "click-to-show": "Clicca per mostrare",
"notifications-permissions-error": "Il permesso all'invio delle notifiche è stato negato poiché l'utente ha ignorato varie volte le richieste di permesso. Ciò può essere ripristinato nelle \"informazioni sito\" cliccando sull'icona a forma di lucchetto vicino alla barra degli indirizzi.", "notifications-permissions-error": "Il permesso all'invio delle notifiche è stato negato poiché l'utente ha ignorato varie volte le richieste di permesso. Ciò può essere ripristinato nelle \"informazioni sito\" cliccando sull'icona a forma di lucchetto vicino alla barra degli indirizzi.",
"pair-url-copied-to-clipboard": "Link di abbinamento copiato negli appunti", "pair-url-copied-to-clipboard": "Link di associazione copiato negli appunti",
"room-url-copied-to-clipboard": "Link della stanza copiato negli appunti" "room-url-copied-to-clipboard": "Link della stanza copiato negli appunti"
}, },
"peer-ui": { "peer-ui": {
@@ -151,14 +165,18 @@
"claim": "Il modo più semplice per trasferire files tra dispositivi", "claim": "Il modo più semplice per trasferire files tra dispositivi",
"tweet_title": "Twitta riguardo PairDrop", "tweet_title": "Twitta riguardo PairDrop",
"close-about_aria-label": "Chiudi Informazioni su PairDrop", "close-about_aria-label": "Chiudi Informazioni su PairDrop",
"buy-me-a-coffee_title": "Comprami un caffè!", "buy-me-a-coffee_title": "Offrimi un caffè!",
"github_title": "PairDrop su GitHub", "github_title": "PairDrop su GitHub",
"faq_title": "Domande Frequenti" "faq_title": "Domande Frequenti",
"mastodon_title": "Scrivi su Mastodon di PairDrop",
"bluesky_title": "Seguici su BlueSky",
"custom_title": "Seguici",
"privacypolicy_title": "Apri la nostra policy sulla privacy"
}, },
"document-titles": { "document-titles": {
"file-transfer-requested": "Trasferimento File Richiesto", "file-transfer-requested": "Trasferimento File Richiesto",
"image-transfer-requested": "Trasferimento Immagine Richiesto", "image-transfer-requested": "Trasferimento Immagine Richiesto",
"message-received-plural": "{{count}} Messaggi ricevuti", "message-received-plural": "{{count}} Messaggi Ricevuti",
"message-received": "Messaggio ricevuto", "message-received": "Messaggio ricevuto",
"file-received": "File Ricevuto", "file-received": "File Ricevuto",
"file-received-plural": "{{count}} Files Ricevuti" "file-received-plural": "{{count}} Files Ricevuti"

View File

@@ -172,31 +172,34 @@ class PeersUI {
} }
_onDrop(e) { _onDrop(e) {
e.preventDefault();
if (this.shareMode.active || Dialog.anyDialogShown()) return; if (this.shareMode.active || Dialog.anyDialogShown()) return;
if (!$$('x-peer') || !$$('x-peer').contains(e.target)) { e.preventDefault();
if (e.dataTransfer.files.length > 0) {
Events.fire('activate-share-mode', {files: e.dataTransfer.files});
} else {
for (let i=0; i<e.dataTransfer.items.length; i++) {
if (e.dataTransfer.items[i].type === "text/plain") {
e.dataTransfer.items[i].getAsString(text => {
Events.fire('activate-share-mode', {text: text});
});
}
}
}
}
this._onDragEnd(); this._onDragEnd();
if ($$('x-peer') || !$$('x-peer').contains(e.target)) return; // dropped on peer
const files = e.dataTransfer.files;
const text = e.dataTransfer.getData("text");
if (files.length > 0) {
Events.fire('activate-share-mode', {
files: files
});
}
else if(text.length > 0) {
Events.fire('activate-share-mode', {
text: text
});
}
} }
_onDragOver(e) { _onDragOver(e) {
e.preventDefault();
if (this.shareMode.active || Dialog.anyDialogShown()) return; if (this.shareMode.active || Dialog.anyDialogShown()) return;
e.preventDefault();
this.$xInstructions.setAttribute('drop-bg', true); this.$xInstructions.setAttribute('drop-bg', true);
this.$xNoPeers.setAttribute('drop-bg', true); this.$xNoPeers.setAttribute('drop-bg', true);
} }
@@ -590,6 +593,9 @@ class PeerUI {
_onFilesSelected(e) { _onFilesSelected(e) {
const $input = e.target; const $input = e.target;
const files = $input.files; const files = $input.files;
if (files.length === 0) return;
Events.fire('files-selected', { Events.fire('files-selected', {
files: files, files: files,
to: this._peer.id to: this._peer.id
@@ -630,29 +636,28 @@ class PeerUI {
} }
_onDrop(e) { _onDrop(e) {
e.preventDefault();
if (PeerUI._shareMode.active || Dialog.anyDialogShown()) return; if (PeerUI._shareMode.active || Dialog.anyDialogShown()) return;
if (e.dataTransfer.files.length > 0) { e.preventDefault();
Events.fire('files-selected', {
files: e.dataTransfer.files,
to: this._peer.id
});
} else {
for (let i=0; i<e.dataTransfer.items.length; i++) {
if (e.dataTransfer.items[i].type === "text/plain") {
e.dataTransfer.items[i].getAsString(text => {
Events.fire('send-text', {
text: text,
to: this._peer.id
});
});
}
}
}
this._onDragEnd(); this._onDragEnd();
const peerId = this._peer.id;
const files = e.dataTransfer.files;
const text = e.dataTransfer.getData("text");
if (files.length > 0) {
Events.fire('files-selected', {
files: files,
to: peerId
});
}
else if (text.length > 0) {
Events.fire('send-text', {
text: text,
to: peerId
});
}
} }
_onDragOver() { _onDragOver() {
@@ -1896,6 +1901,8 @@ class SendTextDialog extends Dialog {
this.$submit = this.$el.querySelector('button[type="submit"]'); this.$submit = this.$el.querySelector('button[type="submit"]');
this.$form.addEventListener('submit', e => this._onSubmit(e)); this.$form.addEventListener('submit', e => this._onSubmit(e));
this.$text.addEventListener('input', _ => this._onInput()); this.$text.addEventListener('input', _ => this._onInput());
this.$text.addEventListener('paste', e => this._onPaste(e));
this.$text.addEventListener('drop', e => this._onDrop(e));
Events.on('text-recipient', e => this._onRecipient(e.detail.peerId, e.detail.deviceName)); Events.on('text-recipient', e => this._onRecipient(e.detail.peerId, e.detail.deviceName));
Events.on('keydown', e => this._onKeyDown(e)); Events.on('keydown', e => this._onKeyDown(e));
@@ -1914,6 +1921,40 @@ class SendTextDialog extends Dialog {
} }
} }
async _onDrop(e) {
e.preventDefault()
const text = e.dataTransfer.getData("text");
const selection = window.getSelection();
if (selection.rangeCount) {
selection.deleteFromDocument();
selection.getRangeAt(0).insertNode(document.createTextNode(text));
}
this._onInput();
}
async _onPaste(e) {
e.preventDefault()
const text = (e.clipboardData || window.clipboardData).getData('text');
const selection = window.getSelection();
if (selection.rangeCount) {
selection.deleteFromDocument();
const textNode = document.createTextNode(text);
const range = document.createRange();
range.setStart(textNode, textNode.length);
range.collapse(true);
selection.getRangeAt(0).insertNode(textNode);
selection.removeAllRanges();
selection.addRange(range);
}
this._onInput();
}
_textEmpty() { _textEmpty() {
return !this.$text.innerText || this.$text.innerText === "\n"; return !this.$text.innerText || this.$text.innerText === "\n";
} }
@@ -1997,12 +2038,22 @@ class ReceiveTextDialog extends Dialog {
window.blop.play(); window.blop.play();
this._receiveTextQueue.push({text: text, peerId: peerId}); this._receiveTextQueue.push({text: text, peerId: peerId});
this._setDocumentTitleMessages(); this._setDocumentTitleMessages();
changeFavicon("images/favicon-96x96-notification.png");
if (this.isShown()) return; if (this.isShown()) return;
this._dequeueRequests(); this._dequeueRequests();
} }
_dequeueRequests() { _dequeueRequests() {
if (!this._receiveTextQueue.length) return; if (!this._receiveTextQueue.length) {
this.$text.innerHTML = "";
return;
}
this._setDocumentTitleMessages();
changeFavicon("images/favicon-96x96-notification.png");
let {text, peerId} = this._receiveTextQueue.shift(); let {text, peerId} = this._receiveTextQueue.shift();
this._showReceiveTextDialog(text, peerId); this._showReceiveTextDialog(text, peerId);
} }
@@ -2013,41 +2064,68 @@ class ReceiveTextDialog extends Dialog {
this.$displayName.classList.add($(peerId).ui._badgeClassName()); this.$displayName.classList.add($(peerId).ui._badgeClassName());
this.$text.innerText = text; this.$text.innerText = text;
this.$text.classList.remove('text-center');
// Beautify text if text is short // Beautify text if text is not too long
if (text.length < 2000) { if (this.$text.innerText.length <= 300000) {
// replace URLs with actual links // Hacky workaround to replace URLs with link nodes in all cases
this.$text.innerHTML = this.$text.innerHTML // 1. Use text variable, find all valid URLs via regex and replace URLs with placeholder
.replace(/(^|<br>|\s|")((https?:\/\/|www.)(([a-z]|[A-Z]|[0-9]|[\-_~:\/?#\[\]@!$&'()*+,;=%]){2,}\.)(([a-z]|[A-Z]|[0-9]|[\-_~:\/?#\[\]@!$&'()*+,;=%.]){2,}))/g, // 2. Use html variable, find placeholders with regex and replace them with link nodes
(match, whitespace, url) => {
let link = url;
// prefix www.example.com with http protocol to prevent it from being a relative link let $textShadow = document.createElement('div');
if (link.startsWith('www')) { $textShadow.innerText = text;
link = "http://" + link
}
// Check if link is valid let linkNodes = {};
if (isUrlValid(link)) { let searchHTML = $textShadow.innerHTML;
return `${whitespace}<a href="${link}" target="_blank">${url}</a>`; const p = "@";
} const pRgx = new RegExp(`${p}\\d+`, 'g');
else { let occP = searchHTML.match(pRgx) || [];
return match;
let m = 0;
const allowedDomainChars = "a-zA-Z0-9áàäčçđéèêŋńñóòôöšŧüžæøåëìíîïðùúýþćěłřśţźǎǐǒǔǥǧǩǯəʒâûœÿãõāēīōūăąĉċďĕėęĝğġģĥħĩĭįıĵķĸĺļľņňŏőŕŗŝşťũŭůűųŵŷżאבגדהוזחטיךכלםמןנסעףפץצקרשתװױײ";
const urlRgx = new RegExp(`(^|\\n|\\s|["><\\-_~:\\/?#\\[\\]@!$&'()*+,;=%.])(((https?:\\/\\/)?(?:[${allowedDomainChars}](?:[${allowedDomainChars}-]{0,61}[${allowedDomainChars}])?\\.)+[${allowedDomainChars}][${allowedDomainChars}-]{0,61}[${allowedDomainChars}])(:?\\d*)\\/?([${allowedDomainChars}_\\/\\-#.]*)(\\?([${allowedDomainChars}\\-_~:\\/?#\\[\\]@!$&'()*+,;=%.]*))?)`, 'g');
$textShadow.innerText = text.replace(urlRgx,
(match, whitespaceOrSpecial, url, g3, scheme) => {
let link = url;
// prefix www.example.com with http protocol to prevent it from being a relative link
if (!scheme && link.startsWith('www')) {
link = "http://" + link
}
if (isUrlValid(link)) {
// link is valid -> replace with link node placeholder
// find linkNodePlaceholder that is not yet present in text node
m++;
while (occP.includes(`${p}${m}`)) {
m++;
} }
let linkNodePlaceholder = `${p}${m}`;
// add linkNodePlaceholder to text node and save a reference to linkNodes object
linkNodes[linkNodePlaceholder] = `<a href="${link}" target="_blank">${url}</a>`;
return `${whitespaceOrSpecial}${linkNodePlaceholder}`;
}
// link is not valid -> do not replace
return match;
});
this.$text.innerHTML = $textShadow.innerHTML.replace(pRgx,
(m) => {
let urlNode = linkNodes[m];
return urlNode ? urlNode : m;
}); });
} }
this._evaluateOverflowing(this.$text); this._evaluateOverflowing(this.$text);
this._setDocumentTitleMessages();
changeFavicon("images/favicon-96x96-notification.png");
this.show(); this.show();
} }
_setDocumentTitleMessages() { _setDocumentTitleMessages() {
document.title = !this._receiveTextQueue.length document.title = this._receiveTextQueue.length <= 1
? `${ Localization.getTranslation("document-titles.message-received") } - PairDrop` ? `${ Localization.getTranslation("document-titles.message-received") } - PairDrop`
: `${ Localization.getTranslation("document-titles.message-received-plural", null, {count: this._receiveTextQueue.length + 1}) } - PairDrop`; : `${ Localization.getTranslation("document-titles.message-received-plural", null, {count: this._receiveTextQueue.length + 1}) } - PairDrop`;
} }

View File

@@ -1,4 +1,4 @@
const cacheVersion = 'v1.10.6'; const cacheVersion = 'v1.10.7';
const cacheTitle = `pairdrop-cache-${cacheVersion}`; const cacheTitle = `pairdrop-cache-${cacheVersion}`;
const forceFetch = false; // FOR DEVELOPMENT: Set to true to always update assets instead of using cached versions const forceFetch = false; // FOR DEVELOPMENT: Set to true to always update assets instead of using cached versions
const relativePathsToCache = [ const relativePathsToCache = [

View File

@@ -12,7 +12,6 @@
display: block; display: block;
overflow: auto; overflow: auto;
resize: none; resize: none;
line-height: 16px;
max-height: 350px; max-height: 350px;
word-break: break-word; word-break: break-word;
word-wrap: anywhere; word-wrap: anywhere;

View File

@@ -626,12 +626,15 @@ x-dialog:not([show]) x-background {
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
z-index: -1;
opacity: 0; opacity: 0;
background-color: var(--accent-color); background-color: var(--accent-color);
transition: opacity 300ms; transition: opacity 300ms;
} }
.icon-button:before {
z-index: -1;
}
.btn:not([disabled]):hover:before, .btn:not([disabled]):hover:before,
.icon-button:hover:before { .icon-button:hover:before {
opacity: 0.3; opacity: 0.3;