Compare commits

..

24 Commits

Author SHA1 Message Date
schlagmichdoch
3e502a76d0 Increase version to v1.10.10
## Enhancements
- Make displayName field more intuitive by hiding the placeholder when it is focussed (#319)

## Fixes
- Fixes substring error on server (#308)

## Languages
- New Language Czech
- New Language Ukrainian
- Translations update from Hosted Weblate (Indonesian)
2024-08-17 16:04:08 +02:00
schlagmichdoch
08af4670ee Enable Czech and Ukrainian translations 2024-08-17 15:58:46 +02:00
schlagmichdoch
a458c00213 Merge pull request #309 from weblate/weblate-pairdrop-pairdrop-spa
Translations update from Hosted Weblate
2024-08-16 16:06:46 +02:00
Hosted Weblate
2e088b8434 Translated using Weblate (Indonesian)
Currently translated at 100.0% (166 of 166 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Ian Perdiansah <ianperdiansah05@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/pairdrop/pairdrop-spa/id/
Translation: PairDrop/pairdrop-spa
2024-08-16 14:06:28 +00:00
Hosted Weblate
31e3b4304c Translated using Weblate (Czech)
Currently translated at 100.0% (166 of 166 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Ladislav Vlach <vlach.ladislav@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/pairdrop/pairdrop-spa/cs/
Translation: PairDrop/pairdrop-spa
2024-08-16 14:06:28 +00:00
Hosted Weblate
d73e5666b9 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (166 of 166 strings)

Added translation using Weblate (Ukrainian)

Co-authored-by: Bezruchenko Simon <worcposj44@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/pairdrop/pairdrop-spa/uk/
Translation: PairDrop/pairdrop-spa
2024-08-16 14:06:27 +00:00
schlagmichdoch
96a055b7d0 Merge branch 'fix-displayname-firefox' 2024-08-16 16:03:35 +02:00
schlagmichdoch
703894e309 update dev nginx conf parameter http2 to new syntax 2024-08-16 16:03:25 +02:00
schlagmichdoch
13f7d36da0 Increase contrast between default badge and text 2024-08-07 20:52:10 +02:00
schlagmichdoch
1549ff48c9 Remove selection from text if displayname is blurred 2024-08-07 20:15:38 +02:00
schlagmichdoch
9f4d99c8db Prevent edited displayname from flickering on page load by changing loading order 2024-08-07 15:27:40 +02:00
schlagmichdoch
563c8dd8a8 Remove redundant placeholder which is added back when page is localized. 2024-08-07 15:27:40 +02:00
schlagmichdoch
43c346894d Make displayName field more intuitive by collapsing it when focussed and empty. (fixes #319) 2024-08-07 15:27:39 +02:00
schlagmichdoch
a68cd75b71 Merge pull request #316 from avadhesh18/patch-1 2024-07-28 16:17:19 +02:00
Avadhesh
e85a2e6293 Update README.md
Improved the summary because "List view" was confusing.
2024-07-28 11:55:47 +05:30
schlagmichdoch
794e6304fe Merge pull request #314 from schlagmichdoch/reduce-docker-size
Switch Docker base image to reduce size
2024-07-17 15:41:25 +02:00
schlagmichdoch
f9b8b0fadf Fix dev environment variable FQDN missing and update docs 2024-07-17 15:37:39 +02:00
schlagmichdoch
10f648b7cd Reduce image size by switching to alpine and excluding folders from being copied into the image 2024-07-17 14:44:08 +02:00
schlagmichdoch
331c61fec8 Change docs to reflect that dev files are now included in master branch 2024-07-14 13:10:16 +02:00
schlagmichdoch
fa24e77d3b rename directory docker to dev 2024-07-14 13:10:09 +02:00
schlagmichdoch
6ca039910a fix dev docker and docs 2024-07-13 21:50:45 +02:00
schlagmichdoch
9f02f7b3ca add docker-compose-dev.yml and needed conf files 2024-07-13 21:50:45 +02:00
schlagmichdoch
04d65da779 Fix substring error if remoteAddress is undefined and replace deprecated request.connection with request.socket (fixes #308) 2024-07-13 21:50:44 +02:00
schlagmichdoch
e6f2c776dc Remove duplicate Firewall section 2024-07-13 16:49:06 +02:00
24 changed files with 634 additions and 72 deletions

View File

@@ -1,5 +1,13 @@
node_modules
.github .github
.git* .git*
.idea
*.md dev
docs
licenses
node_modules
pairdrop-cli
*.md
*.yml
Dockerfile
rtc_config_example.json
turnserver_example.conf

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.9 Version: v1.10.10
**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.9 Version: v1.10.10
**Additional context** **Additional context**
Add any other context about the problem here. Add any other context about the problem here.

3
.gitignore vendored
View File

@@ -1,7 +1,6 @@
node_modules node_modules
.DS_Store .DS_Store
fqdn.env /dev/certs
/docker/certs
qrcode-svg/ qrcode-svg/
turnserver.conf turnserver.conf
rtc_config.json rtc_config.json

View File

@@ -1,11 +1,13 @@
FROM node:lts-alpine FROM alpine:latest
WORKDIR /home/node/app WORKDIR /home/node/app
COPY package*.json ./ COPY package*.json ./
RUN npm ci RUN apk add --no-cache nodejs npm
RUN NODE_ENV="production" npm ci --omit=dev
# Directories and files excluded via .dockerignore
COPY . . COPY . .
# environment settings # environment settings

View File

@@ -32,7 +32,7 @@ Send a file from your phone to your laptop?
<img src="docs/pairdrop_screenshot_mobile.gif" alt="Screenshot GIF showing PairDrop in use" style="width: 300px"> <img src="docs/pairdrop_screenshot_mobile.gif" alt="Screenshot GIF showing PairDrop in use" style="width: 300px">
## Differences to the [Snapdrop](https://github.com/RobinLinus/snapdrop) it is based on ## Differences to the [Snapdrop](https://github.com/RobinLinus/snapdrop) it is based on
<details><summary>List view</summary> <details><summary>View all differences</summary>
### Paired Devices and Public Rooms — Internet Transfer ### Paired Devices and Public Rooms — Internet Transfer
* Transfer files over the Internet between paired devices or by entering temporary public rooms. * Transfer files over the Internet between paired devices or by entering temporary public rooms.

View File

@@ -0,0 +1,3 @@
FROM nginx:alpine
RUN apk add --no-cache openssl

42
dev/nginx/default.conf Normal file
View File

@@ -0,0 +1,42 @@
server {
listen 80;
expires epoch;
location / {
proxy_connect_timeout 300;
proxy_pass http://pairdrop:3000;
proxy_set_header Connection "upgrade";
proxy_set_header Upgrade $http_upgrade;
}
location /ca.crt {
alias /etc/ssl/certs/pairdropCA.crt;
}
# To allow POST on static pages
error_page 405 =200 $uri;
}
server {
listen 443 ssl;
http2 on;
ssl_certificate /etc/ssl/certs/pairdrop-dev.crt;
ssl_certificate_key /etc/ssl/certs/pairdrop-dev.key;
expires epoch;
location / {
proxy_connect_timeout 300;
proxy_pass http://pairdrop:3000;
proxy_set_header Connection "upgrade";
proxy_set_header Upgrade $http_upgrade;
}
location /ca.crt {
alias /etc/ssl/certs/pairdropCA.crt;
}
# To allow POST on static pages
error_page 405 =200 $uri;
}

9
dev/openssl/create.sh Normal file
View File

@@ -0,0 +1,9 @@
#!/bin/sh
cnf_dir='/mnt/openssl/'
certs_dir='/etc/ssl/certs/'
openssl req -config ${cnf_dir}pairdropCA.cnf -new -x509 -days 1 -keyout ${certs_dir}pairdropCA.key -out ${certs_dir}pairdropCA.crt
openssl req -config ${cnf_dir}pairdropCert.cnf -new -out /tmp/pairdrop-dev.csr -keyout ${certs_dir}pairdrop-dev.key
openssl x509 -req -in /tmp/pairdrop-dev.csr -CA ${certs_dir}pairdropCA.crt -CAkey ${certs_dir}pairdropCA.key -CAcreateserial -extensions req_ext -extfile ${cnf_dir}pairdropCert.cnf -sha512 -days 1 -out ${certs_dir}pairdrop-dev.crt
exec "$@"

View File

@@ -0,0 +1,26 @@
[ req ]
default_bits = 2048
default_md = sha256
default_days = 1
encrypt_key = no
distinguished_name = subject
x509_extensions = x509_ext
string_mask = utf8only
prompt = no
[ subject ]
organizationName = PairDrop
OU = CA
commonName = pairdrop-CA
[ x509_ext ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
# You only need digitalSignature below. *If* you don't allow
# RSA Key transport (i.e., you use ephemeral cipher suites), then
# omit keyEncipherment because that's key transport.
basicConstraints = critical, CA:TRUE, pathlen:0
keyUsage = critical, digitalSignature, keyEncipherment, cRLSign, keyCertSign

View File

@@ -0,0 +1,29 @@
[ req ]
default_bits = 2048
default_md = sha256
default_days = 1
encrypt_key = no
distinguished_name = subject
req_extensions = req_ext
string_mask = utf8only
prompt = no
[ subject ]
organizationName = PairDrop
OU = Development
# Use a friendly name here because it's presented to the user. The server's DNS
# names are placed in Subject Alternate Names. Plus, DNS names here is deprecated
# by both IETF and CA/Browser Forums. If you place a DNS name here, then you
# must include the DNS name in the SAN too (otherwise, Chrome and others that
# strictly follow the CA/Browser Baseline Requirements will fail).
commonName = ${ENV::FQDN}
[ req_ext ]
subjectKeyIdentifier = hash
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = DNS:${ENV::FQDN}
nsComment = "OpenSSL Generated Certificate"
extendedKeyUsage = serverAuth

34
docker-compose-dev.yml Normal file
View File

@@ -0,0 +1,34 @@
version: "3"
services:
pairdrop:
build: .
container_name: pairdrop
restart: unless-stopped
environment:
- PUID=1000 # UID to run the application as
- PGID=1000 # GID to run the application as
- WS_FALLBACK=false # Set to true to enable websocket fallback if the peer to peer WebRTC connection is not available to the client.
- RATE_LIMIT=false # Set to true to limit clients to 1000 requests per 5 min.
- RTC_CONFIG=false # Set to the path of a file that specifies the STUN/TURN servers.
- DEBUG_MODE=false # Set to true to debug container and peer connections.
- TZ=Etc/UTC # Time Zone
ports:
- "127.0.0.1:3000:3000" # Web UI. Change the port number before the last colon e.g. `127.0.0.1:9000:3000`
nginx:
build:
context: dev/
dockerfile: nginx-with-openssl.Dockerfile
image: "nginx-with-openssl"
volumes:
- ./public:/usr/share/nginx/html
- ./dev/certs:/etc/ssl/certs
- ./dev/openssl:/mnt/openssl
- ./dev/nginx/default.conf:/etc/nginx/conf.d/default.conf
ports:
- "8080:80"
- "8443:443"
environment:
- FQDN=localhost
entrypoint: /mnt/openssl/create.sh
command: ["nginx", "-g", "daemon off;"]
restart: unless-stopped

View File

@@ -652,68 +652,74 @@ To run PairDrop including its own coturn-server you need to punch holes in the f
<br> <br>
### Firewall
To run PairDrop including its own coturn-server you need to punch holes in the firewall. These ports must be opened additionally:
- 3478 tcp/udp
- 5349 tcp/udp
- 10000:20000 tcp/udp
<br>
## Local Development ## Local Development
### Install ### Install
All files needed for developing are available on the branch `dev`. All files needed for developing are available in the folder `./dev`.
First, [Install docker with docker-compose.](https://docs.docker.com/compose/install/) For convenience, there is also a docker compose file for developing:
Then, clone the repository and run docker-compose: #### Developing with docker compose
First, [Install docker with docker compose.](https://docs.docker.com/compose/install/)
Then, clone the repository and run docker compose:
```bash ```bash
git clone https://github.com/schlagmichdoch/PairDrop.git && cd PairDrop git clone https://github.com/schlagmichdoch/PairDrop.git && cd PairDrop
``` ```
```bash ```bash
git checkout dev docker compose -f docker-compose-dev.yml up --no-deps --build
```
```bash
docker compose -f docker-compose-dev.yml up -d
``` ```
Now point your web browser to `http://localhost:8080`. Now point your web browser to `http://localhost:8080`.
- To restart the containers, run `docker compose restart`.
- To stop the containers, run `docker compose stop`.
- To debug the Node.js server, run `docker logs pairdrop`. - To debug the Node.js server, run `docker logs pairdrop`.
- After changes to the code you have to rerun the `docker compose` command
<br> <br>
### Testing PWA related features #### Testing PWA related features
PWAs requires the app to be served under a correctly set up and trusted TLS endpoint. PWAs requires the app to be served under a correctly set up and trusted TLS endpoint.
The NGINX container creates a CA certificate and a website certificate for you. The NGINX container creates a CA certificate and a website certificate for you.
To correctly set the common name of the certificate, To correctly set the common name of the certificate,
you need to change the FQDN environment variable in `docker/fqdn.env` you need to change the FQDN environment variable in `docker-compose-dev.yml`
to the fully qualified domain name of your workstation. to the fully qualified domain name of your workstation. (Default: localhost)
If you want to test PWA features, you need to trust the CA of the certificate for your local deployment. \ If you want to test PWA features, you need to trust the CA of the certificate for your local deployment. \
For your convenience, you can download the crt file from `http://<Your FQDN>:8080/ca.crt`. \ For your convenience, you can download the crt file from `http://<Your FQDN>:8080/ca.crt`. \
Install that certificate to the trust store of your operating system. \ Install that certificate to the trust store of your operating system. \
- On Windows, make sure to install it to the `Trusted Root Certification Authorities` store. ##### Windows
- On macOS, double-click the installed CA certificate in `Keychain Access`, - Make sure to install it to the `Trusted Root Certification Authorities` store.
##### macOS
- Double-click the installed CA certificate in `Keychain Access`,
- expand `Trust`, and select `Always Trust` for SSL. - expand `Trust`, and select `Always Trust` for SSL.
- Firefox uses its own trust store. To install the CA,
- point Firefox at `http://<Your FQDN>:8080/ca.crt`. ##### Firefox
Firefox uses its own trust store. To install the CA:
- point Firefox at `http://<Your FQDN>:8080/ca.crt` (Default: `http://localhost:8080/ca.crt`)
- When prompted, select `Trust this CA to identify websites` and click _OK_. - When prompted, select `Trust this CA to identify websites` and click _OK_.
Alternatively:
1. Download `ca.crt` from `http://<Your FQDN>:8080/ca.crt` (Default: `http://localhost:8080/ca.crt`)
2. Go to `about:preferences#privacy` scroll down to `Security` and `Certificates` and click `View Certificates`
3. Import the downloaded certificate file (step 1)
##### Chrome
- When using Chrome, you need to restart Chrome so it reloads the trust store (`chrome://restart`). - When using Chrome, you need to restart Chrome so it reloads the trust store (`chrome://restart`).
- Additionally, after installing a new cert, you need to clear the Storage (DevTools → Application → Clear storage → Clear site data). - Additionally, after installing a new cert, you need to clear the Storage (DevTools → Application → Clear storage → Clear site data).
##### Google Chrome
- To skip the installation of the certificate, you can also open `chrome://flags/#unsafely-treat-insecure-origin-as-secure`
- The feature `Insecure origins treated as secure` must be enabled and the list must include your PairDrop test instance. E.g.: `http://127.0.0.1:3000,https://127.0.0.1:8443`
Please note that the certificates (CA and webserver cert) expire after a day. Please note that the certificates (CA and webserver cert) expire after a day.
Also, whenever you restart the NGINX Docker container new certificates are created. Also, whenever you restart the NGINX Docker container new certificates are created.
The site is served on `https://<Your FQDN>:8443`. The site is served on `https://<Your FQDN>:8443` (Default: `https://localhost:8443`).
[< Back](/README.md) [< Back](/README.md)

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.9/pairdrop-cli.zip" wget "https://github.com/schlagmichdoch/PairDrop/releases/download/v1.10.10/pairdrop-cli.zip"
``` ```
or or
```shell ```shell
curl -LO "https://github.com/schlagmichdoch/PairDrop/releases/download/v1.10.9/pairdrop-cli.zip" curl -LO "https://github.com/schlagmichdoch/PairDrop/releases/download/v1.10.10/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.9", "version": "1.10.10",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "pairdrop", "name": "pairdrop",
"version": "1.10.9", "version": "1.10.10",
"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.9", "version": "1.10.10",
"type": "module", "type": "module",
"description": "", "description": "",
"main": "server/index.js", "main": "server/index.js",

View File

@@ -159,7 +159,7 @@
<div class="column"> <div class="column">
<div class="known-as-wrapper"> <div class="known-as-wrapper">
<span data-i18n-key="footer.known-as" data-i18n-attrs="text"></span> <span data-i18n-key="footer.known-as" data-i18n-attrs="text"></span>
<div id="display-name" class="badge" data-i18n-key="footer.display-name" data-i18n-attrs="data-placeholder title" placeholder="Loading..." autocorrect="off" autocomplete="off" autocapitalize="none" spellcheck="false" contenteditable></div> <div id="display-name" class="badge" data-i18n-key="footer.display-name" data-i18n-attrs="data-placeholder title" autocorrect="off" autocomplete="off" autocapitalize="none" spellcheck="false" contenteditable></div>
<svg class="icon edit-pen"> <svg class="icon edit-pen">
<use xlink:href="#edit-pen-icon"></use> <use xlink:href="#edit-pen-icon"></use>
</svg> </svg>
@@ -202,6 +202,11 @@
<span>&nbsp;&nbsp;-&nbsp;&nbsp;</span> <span>&nbsp;&nbsp;-&nbsp;&nbsp;</span>
<span>(Catalan)</span> <span>(Catalan)</span>
</button> </button>
<button class="btn fw wrap" value="cs">
<span>Čeština</span>
<span>&nbsp;&nbsp;-&nbsp;&nbsp;</span>
<span>(Czech)</span>
</button>
<button class="btn fw wrap" value="da"> <button class="btn fw wrap" value="da">
<span>Dansk</span> <span>Dansk</span>
<span>&nbsp;&nbsp;-&nbsp;&nbsp;</span> <span>&nbsp;&nbsp;-&nbsp;&nbsp;</span>
@@ -285,6 +290,11 @@
<span>&nbsp;&nbsp;-&nbsp;&nbsp;</span> <span>&nbsp;&nbsp;-&nbsp;&nbsp;</span>
<span>(Turkish)</span> <span>(Turkish)</span>
</button> </button>
<button class="btn fw wrap" value="uk">
<span>Українська</span>
<span>&nbsp;&nbsp;-&nbsp;&nbsp;</span>
<span>(Ukrainian)</span>
</button>
<button class="btn fw wrap" value="zh-CN"> <button class="btn fw wrap" value="zh-CN">
<span>中文</span> <span>中文</span>
<span>&nbsp;&nbsp;-&nbsp;&nbsp;</span> <span>&nbsp;&nbsp;-&nbsp;&nbsp;</span>
@@ -612,7 +622,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.9</div> <div class="font-subheading">v1.10.10</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

@@ -4,6 +4,181 @@
"about_title": "O službě PairDrop", "about_title": "O službě PairDrop",
"language-selector_title": "Nastavit jazyk", "language-selector_title": "Nastavit jazyk",
"theme-auto_title": "Automatické přizpůsobení tématu systému", "theme-auto_title": "Automatické přizpůsobení tématu systému",
"pair-device_title": "Spárovat zařízení permanentně" "pair-device_title": "Spárovat zařízení permanentně",
"theme-light_title": "Vždy používat světlé téma",
"theme-dark_title": "Vždy používat tmavé téma",
"notification_title": "Povolit upozornění",
"install_title": "Nainstalovat PairDrop",
"edit-paired-devices_title": "Upravit spárovaná zařízení",
"join-public-room_title": "Připojte se dočasně k veřejné místnosti",
"cancel-share-mode": "Zrušit",
"edit-share-mode": "Upravit",
"expand_title": "Rozbalit řádek tlačítka záhlaví"
},
"about": {
"buy-me-a-coffee_title": "Kupte mi kávu!",
"close-about_aria-label": "Zavřít O PairDrop",
"claim": "Nejjednodušší způsob přenosu souborů mezi zařízeními",
"github_title": "PairDrop na GitHubu",
"tweet_title": "Tweet o PairDrop",
"mastodon_title": "Napište o PairDrop na Mastodon",
"custom_title": "Sledujte nás",
"privacypolicy_title": "Otevřete naše zásady ochrany osobních údajů",
"bluesky_title": "Sledujte nás na BlueSky",
"faq_title": "Často kladené otázky"
},
"footer": {
"webrtc": "pokud WebRTC není k dispozici.",
"known-as": "Jste známí jako:",
"display-name_data-placeholder": "Načítání…",
"display-name_title": "Trvale upravit název zařízení",
"discovery": "Můžete být objeveni:",
"on-this-network": "na této síti",
"on-this-network_title": "V této síti vás může objevit každý.",
"paired-devices": "pomocí spárovaných zařízení",
"paired-devices_title": "Spárovaná zařízení vás mohou kdykoli objevit nezávisle na síti.",
"public-room-devices": "v místnosti {{roomId}}",
"public-room-devices_title": "Zařízení v této veřejné místnosti vás mohou objevit nezávisle na síti.",
"traffic": "Provoz je",
"routed": "směrovány přes server"
},
"dialogs": {
"auto-accept": "auto-accept",
"pair-devices-title": "Spárujte zařízení trvale",
"input-key-on-this-device": "Zadejte tento klíč na jiném zařízení",
"scan-qr-code": "nebo naskenujte QR kód.",
"enter-key-from-another-device": "Zde zadejte klíč z jiného zařízení.",
"temporary-public-room-title": "Dočasná veřejná místnost",
"input-room-id-on-another-device": "Zadejte toto ID místnosti na jiném zařízení",
"enter-room-id-from-another-device": "Chcete-li se připojit k místnosti, zadejte ID místnosti z jiného zařízení.",
"hr-or": "NEBO",
"pair": "Párovat",
"cancel": "Zrušit",
"edit-paired-devices-title": "Upravit spárovaná zařízení",
"unpair": "Zrušit spárování",
"paired-device-removed": "Spárované zařízení bylo odstraněno.",
"paired-devices-wrapper_data-empty": "Žádná spárovaná zařízení.",
"auto-accept-instructions-1": "Aktivovat",
"auto-accept-instructions-2": "automaticky přijímat všechny soubory odeslané z tohoto zařízení.",
"close": "Zavřít",
"join": "Připojit",
"leave": "Odejít",
"accept": "Přijmout",
"decline": "Odmítnout",
"would-like-to-share": "by se rád podělil",
"has-sent": "odeslal:",
"share": "Sdílet",
"download": "Stáhnout",
"send-message-title": "Poslat zprávu",
"send-message-to": "Komu:",
"message_title": "Vložte zprávu k odeslání",
"message_placeholder": "Text",
"send": "Odeslat",
"receive-text-title": "Zpráva přijata",
"copy": "Kopírovat",
"base64-title-files": "Sdílet soubory",
"base64-title-text": "Sdílet text",
"base64-processing": "Zpracovává se…",
"base64-tap-to-paste": "Klepnutím sem sdílejte {{type}}",
"base64-files": "soubory",
"file-other-description-image": "a 1 další obrázek",
"base64-paste-to-send": "Sem vložte schránku pro sdílení {{type}}",
"base64-text": "text",
"file-other-description-file": "a 1 další soubor",
"file-other-description-image-plural": "a další obrázky ({{count}})",
"file-other-description-file-plural": "a {{count}} dalších souborů",
"title-image": "Obrázek",
"title-file": "Soubor",
"title-image-plural": "Obrázky",
"title-file-plural": "Soubory",
"receive-title": "{{descriptor}} Přijato",
"download-again": "Stáhnout znovu",
"language-selector-title": "Nastavit jazyk",
"system-language": "Jazyk systému",
"public-room-qr-code_title": "Kliknutím zkopírujete odkaz do veřejné místnosti",
"pair-devices-qr-code_title": "Kliknutím zkopírujete odkaz pro spárování tohoto zařízení",
"approve": "schválit",
"share-text-title": "Sdílet textovou zprávu",
"share-text-subtitle": "Upravit zprávu před odesláním:",
"share-text-checkbox": "Při sdílení textu vždy zobrazit tento dialog",
"close-toast_title": "Zavřít oznámení"
},
"instructions": {
"no-peers_data-drop-bg": "Uvolněním vyberte příjemce",
"no-peers-title": "Otevřete PairDrop na jiných zařízeních a posílejte soubory",
"no-peers-subtitle": "Spárujte zařízení nebo vstupte do veřejné místnosti, abyste byli zjistitelní v jiných sítích",
"x-instructions_desktop": "Kliknutím odešlete soubory nebo kliknutím pravým tlačítkem odešlete zprávu",
"x-instructions_mobile": "Klepnutím odešlete soubory nebo dlouhým klepnutím odešlete zprávu",
"x-instructions_data-drop-peer": "Uvolněním odešlete",
"x-instructions_data-drop-bg": "Uvolněním vyberte příjemce",
"x-instructions-share-mode_desktop": "Kliknutím odešlete {{descriptor}}",
"x-instructions-share-mode_mobile": "Klepnutím odešlete {{descriptor}}",
"activate-share-mode-base": "Pro odeslání otevřete PairDrop na jiných zařízeních",
"activate-share-mode-and-other-file": "a 1 další soubor",
"activate-share-mode-and-other-files-plural": "a {{count}} dalších souborů",
"activate-share-mode-shared-text": "sdílený text",
"activate-share-mode-shared-file": "sdílený soubor",
"activate-share-mode-shared-files-plural": "{{count}} sdílených souborů",
"webrtc-requirement": "Chcete-li použít PairDrop, musí být povoleno WebRTC!"
},
"notifications": {
"display-name-changed-permanently": "Zobrazované jméno je trvale změněno",
"display-name-changed-temporarily": "Zobrazované jméno je změněno pouze pro tuto relaci",
"display-name-random-again": "Zobrazované jméno je opět náhodně generováno",
"download-successful": "{{descriptor}} staženo",
"pairing-tabs-error": "Spárování dvou záložek webového prohlížeče není možné",
"pairing-success": "Zařízení spárována",
"pairing-not-persistent": "Spárovaná zařízení nejsou trvalá",
"pairing-key-invalid": "Neplatný klíč",
"pairing-key-invalidated": "Klíč {{key}} byl neplatný",
"public-room-id-invalid": "Neplatné ID místnosti",
"public-room-left": "Opustit veřejnou místnost {{publicRoomId}}",
"copied-to-clipboard": "Zkopírováno do schránky",
"pair-url-copied-to-clipboard": "Odkaz pro spárování tohoto zařízení byl zkopírován do schránky",
"room-url-copied-to-clipboard": "Odkaz do veřejné místnosti zkopírován do schránky",
"pairing-cleared": "Všechna nespárovaná zařízení",
"copied-to-clipboard-error": "Kopírování není možné. Kopírovat ručně.",
"text-content-incorrect": "Textový obsah je nesprávný",
"file-content-incorrect": "Obsah souboru je nesprávný",
"clipboard-content-incorrect": "Obsah schránky je nesprávný",
"notifications-enabled": "Oznámení povolena",
"notifications-permissions-error": "Oprávnění k oznámení bylo zablokováno, protože uživatel několikrát odmítl výzvu k povolení. Toto lze resetovat v části Informace o stránce, ke které se dostanete kliknutím na ikonu zámku vedle řádku adresy URL.",
"link-received": "Odkaz obdržel {{name}} kliknutím otevřete",
"message-received": "Zpráva přijatá uživatelem {{name}} kliknutím zkopírujte",
"click-to-download": "Kliknutím stáhnete",
"request-title": "{{name}} chce přenést {{count}} {{descriptor}}",
"copied-text": "Text byl zkopírován do schránky",
"click-to-show": "Kliknutím zobrazíte",
"copied-text-error": "Zápis do schránky se nezdařil. Zkopírujte ručně!",
"offline": "Jste offline",
"online": "Jste zpět online",
"connected": "Připojeno",
"online-requirement-public-room": "Chcete-li vytvořit veřejnou místnost, musíte být online",
"online-requirement-pairing": "Chcete-li spárovat zařízení, musíte být online",
"connecting": "Připojování…",
"files-incorrect": "Soubory jsou nesprávné",
"file-transfer-completed": "Přenos souborů byl dokončen",
"message-transfer-completed": "Přenos zprávy byl dokončen",
"ios-memory-limit": "Odesílání souborů do iOS je možné pouze do velikosti 200 MB najednou",
"unfinished-transfers-warning": "Existují nedokončené přenosy Opravdu chcete zavřít PairDrop?",
"rate-limit-join-key": "Bylo dosaženo limitu. Počkejte 10 sekund a zkuste to znovu.",
"selected-peer-left": "Vybraný partner odešel"
},
"document-titles": {
"file-received": "Soubor byl přijat",
"file-received-plural": "Počet přijatých souborů: {{count}}",
"file-transfer-requested": "Požadován přenos souboru",
"message-received": "Zpráva přijata",
"image-transfer-requested": "Požadován přenos obrázku",
"message-received-plural": "Počet přijatých zpráv: {{count}}"
},
"peer-ui": {
"click-to-send-share-mode": "Kliknutím odešlete {{descriptor}}",
"click-to-send": "Kliknutím odešlete soubory nebo kliknutím pravým tlačítkem odešlete zprávu",
"transferring": "Přenáší se…",
"connection-hash": "Chcete-li ověřit bezpečnost šifrování typu end-to-end, porovnejte toto číslo zabezpečení na obou zařízeních",
"preparing": "Připravuje se…",
"waiting": "Čekání…",
"processing": "Zpracovává se…"
} }
} }

View File

@@ -101,7 +101,7 @@
"transferring": "Mentransfer…" "transferring": "Mentransfer…"
}, },
"dialogs": { "dialogs": {
"base64-paste-to-send": "Tempel di sini untuk mengirim {{type}}", "base64-paste-to-send": "Tempel salinan di sini untuk mengirim {{type}}",
"auto-accept-instructions-2": "untuk secara otomatis menerima semua file yang dikirim dari perangkat tersebut.", "auto-accept-instructions-2": "untuk secara otomatis menerima semua file yang dikirim dari perangkat tersebut.",
"receive-text-title": "Pesan Diterima", "receive-text-title": "Pesan Diterima",
"edit-paired-devices-title": "Edit Perangkat yg. Dipasangkan", "edit-paired-devices-title": "Edit Perangkat yg. Dipasangkan",
@@ -154,7 +154,12 @@
"base64-title-files": "Bagikan File", "base64-title-files": "Bagikan File",
"base64-title-text": "Bagikan Teks", "base64-title-text": "Bagikan Teks",
"message_placeholder": "Teks", "message_placeholder": "Teks",
"paired-device-removed": "Perangkat yang dipasangkan telah dihapus." "paired-device-removed": "Perangkat yang dipasangkan telah dihapus.",
"approve": "menyetujui",
"share-text-title": "Kirim Pesan Teks",
"share-text-subtitle": "Edit pesan sebelum mengirim:",
"share-text-checkbox": "Selalu tampilkan dialog ini ketika mengirimkan teks",
"close-toast_title": "Tutup notifikasi"
}, },
"about": { "about": {
"claim": "Cara termudah untuk mentransfer file lintas perangkat", "claim": "Cara termudah untuk mentransfer file lintas perangkat",
@@ -162,7 +167,11 @@
"close-about_aria-label": "Tutup Tentang PairDrop", "close-about_aria-label": "Tutup Tentang PairDrop",
"buy-me-a-coffee_title": "Traktir aku kopi!", "buy-me-a-coffee_title": "Traktir aku kopi!",
"github_title": "PairDrop di GitHub", "github_title": "PairDrop di GitHub",
"faq_title": "Pertanyaan yang sering diajukan" "faq_title": "Pertanyaan yang sering diajukan",
"mastodon_title": "Tulis tentang PairDrop di Mastodon",
"bluesky_title": "Ikuti kami di BlueSky",
"custom_title": "Ikuti kami",
"privacypolicy_title": "Buka kebijakan privasi kami"
}, },
"document-titles": { "document-titles": {
"file-transfer-requested": "Permintaan Transfer File", "file-transfer-requested": "Permintaan Transfer File",

184
public/lang/uk.json Normal file
View File

@@ -0,0 +1,184 @@
{
"header": {
"about_aria-label": "Відкрити \"Про PairDrop\"",
"theme-auto_title": "Автоматично адаптувати тему до системної",
"theme-light_title": "Завжди використовувати світлу тему",
"install_title": "Встановити PairDrop",
"join-public-room_title": "Приєднатися до публічної кімнати тимчасово",
"cancel-share-mode": "Скасувати",
"edit-share-mode": "Редагувати",
"about_title": "Про PairDrop",
"language-selector_title": "Встановити мову",
"theme-dark_title": "Завжди використовувати темну тему",
"pair-device_title": "Зв'язати ваші пристрої назавжди",
"notification_title": "Увімкнути сповіщення",
"edit-paired-devices_title": "Редагувати зв'язані пристрої",
"expand_title": "Розгорнути рядок кнопок заголовка"
},
"instructions": {
"no-peers_data-drop-bg": "Відпустіть, щоб вибрати одержувача",
"x-instructions_desktop": "Натисніть, щоб надіслати файли, або клацніть правою кнопкою миші, щоб надіслати повідомлення",
"x-instructions_data-drop-peer": "Відпустіть, щоб надіслати партнеру",
"x-instructions-share-mode_desktop": "Натисніть, щоб надіслати {{descriptor}}",
"x-instructions-share-mode_mobile": "Торкніться, щоб надіслати {{descriptor}}",
"activate-share-mode-and-other-file": "та 1 інший файл",
"activate-share-mode-shared-file": "спільний файл",
"webrtc-requirement": "Щоб використовувати цей екземпляр PairDrop, WebRTC має бути увімкнено!",
"no-peers-title": "Відкрийте PairDrop на інших пристроях, щоб надіслати файли",
"no-peers-subtitle": "Зв’яжіть пристрої або введіть публічну кімнату, щоб бути помітним в інших мережах",
"x-instructions_mobile": "Торкніться, щоб надіслати файли, або довго натисніть, щоб надіслати повідомлення",
"x-instructions_data-drop-bg": "Відпустіть, щоб вибрати одержувача",
"activate-share-mode-base": "Відкрийте PairDrop на інших пристроях, щоб надіслати",
"activate-share-mode-and-other-files-plural": "та {{count}} інших файлів",
"activate-share-mode-shared-text": "спільний текст",
"activate-share-mode-shared-files-plural": "{{count}} спільних файлів"
},
"footer": {
"known-as": "Вам відомо як:",
"discovery": "Вас можна знайти:",
"public-room-devices": "у кімнаті {{roomId}}",
"public-room-devices_title": "Вас можуть знайти пристрої в цій публічній кімнаті, незалежно від мережі.",
"traffic": "Трафік",
"webrtc": "якщо WebRTC недоступний.",
"display-name_data-placeholder": "Завантаження…",
"display-name_title": "Редагувати назву вашого пристрою назавжди",
"on-this-network_title": "Вас можуть знайти всі на цій мережі.",
"routed": "маршрутизований через сервер",
"on-this-network": "в цій мережі",
"paired-devices": "через зв'язані пристрої",
"paired-devices_title": "Вас можуть знайти зв'язані пристрої в будь-який час, незалежно від мережі."
},
"dialogs": {
"input-key-on-this-device": "Введіть цей ключ на іншому пристрої",
"scan-qr-code": "або відскануйте QR-код.",
"enter-key-from-another-device": "Введіть ключ з іншого пристрою тут.",
"temporary-public-room-title": "Тимчасова публічна кімната",
"input-room-id-on-another-device": "Введіть цей ID кімнати на іншому пристрої",
"enter-room-id-from-another-device": "Введіть ID кімнати з іншого пристрою, щоб приєднатися до кімнати.",
"hr-or": "АБО",
"cancel": "Скасувати",
"edit-paired-devices-title": "Редагувати Зв'язані пристрої",
"unpair": "Від'єднати",
"paired-device-removed": "Зв'язаний пристрій був видалений.",
"paired-devices-wrapper_data-empty": "Немає зв'язаних пристроїв.",
"auto-accept-instructions-1": "Активувати",
"auto-accept": "автоматичне прийняття",
"auto-accept-instructions-2": "щоб автоматично приймати всі файли, надіслані з цього пристрою.",
"join": "Приєднатися",
"leave": "Покинути",
"accept": "Прийняти",
"decline": "Відхилити",
"has-sent": "відправив:",
"share": "Поділитися",
"download": "Завантажити",
"send-message-title": "Надіслати повідомлення",
"send-message-to": "Кому:",
"message_title": "Введіть повідомлення для надсилання",
"base64-title-text": "Поділитися текстом",
"base64-processing": "Обробка…",
"base64-text": "текст",
"file-other-description-image": "та ще 1 зображення",
"file-other-description-file": "та ще 1 файл",
"file-other-description-image-plural": "та ще {{count}} зображень",
"title-file": "Файл",
"title-image-plural": "Зображення",
"title-file-plural": "Файли",
"receive-title": "{{descriptor}} отримано",
"system-language": "Системна мова",
"public-room-qr-code_title": "Натисніть, щоб скопіювати посилання на публічну кімнату",
"share-text-title": "Поділитися текстовим повідомленням",
"share-text-subtitle": "Редагувати повідомлення перед відправкою:",
"share-text-checkbox": "Завжди показувати цей діалог при поділі тексту",
"close-toast_title": "Закрити сповіщення",
"pair-devices-title": "Зв’язати пристрої назавжди",
"pair": "Приєднати",
"close": "Закрити",
"would-like-to-share": "хоче поділитися",
"copy": "Копіювати",
"message_placeholder": "Текст",
"send": "Надіслати",
"base64-title-files": "Поділитися файлами",
"receive-text-title": "Повідомлення отримано",
"base64-tap-to-paste": "Натисніть тут, щоб поділитися {{type}}",
"base64-paste-to-send": "Вставте буфер обміну тут, щоб поділитися {{type}}",
"file-other-description-file-plural": "та ще {{count}} файлів",
"base64-files": "файли",
"title-image": "Зображення",
"language-selector-title": "Встановити мову",
"approve": "схвалити",
"download-again": "Завантажити знову",
"pair-devices-qr-code_title": "Натисніть, щоб скопіювати посилання для зв'язування цього пристрою"
},
"about": {
"close-about_aria-label": "Закрити \"Про PairDrop\"",
"github_title": "PairDrop на GitHub",
"buy-me-a-coffee_title": "Купи мені каву!",
"tweet_title": "Твіт про PairDrop",
"bluesky_title": "Підписуйтесь на нас у BlueSky",
"privacypolicy_title": "Відкрити нашу політику конфіденційності",
"faq_title": "Часто задавані питання",
"mastodon_title": "Напишіть про PairDrop на Mastodon",
"custom_title": "Підписуйтесь на нас",
"claim": "Найпростіший спосіб передачі файлів між пристроями"
},
"notifications": {
"display-name-changed-temporarily": "Відображуване ім'я було змінено тільки для цієї сесії",
"display-name-random-again": "Відображуване ім'я згенерувалося випадковим чином знову",
"download-successful": "{{descriptor}} завантажено",
"pairing-tabs-error": "Зв'язування двох вкладок браузера неможливе",
"pairing-success": "Пристрої зв'язані",
"pairing-not-persistent": "Зв'язані пристрої не є постійними",
"pairing-key-invalid": "Недійсний ключ",
"pairing-key-invalidated": "Ключ {{key}} недійсний",
"pairing-cleared": "Всі пристрої роз'єднані",
"public-room-id-invalid": "Недійсний ID кімнати",
"public-room-left": "Покинув публічну кімнату {{publicRoomId}}",
"copied-to-clipboard-error": "Копіювання неможливе. Скопіюйте вручну.",
"clipboard-content-incorrect": "Вміст буфера обміну неправильний",
"link-received": "Посилання отримано від {{name}} - Натисніть, щоб відкрити",
"message-received": "Повідомлення отримано від {{name}} - Натисніть, щоб скопіювати",
"click-to-download": "Натисніть, щоб завантажити",
"request-title": "{{name}} хоче передати {{count}} {{descriptor}}",
"click-to-show": "Натисніть, щоб показати",
"copied-text": "Текст скопійовано в буфер обміну",
"copied-text-error": "Запис у буфер обміну не вдався. Скопіюйте вручну!",
"offline": "Ви офлайн",
"online-requirement-pairing": "Вам потрібно бути онлайн, щоб зв'язати пристрої",
"online-requirement-public-room": "Вам потрібно бути онлайн, щоб створити публічну кімнату",
"connecting": "Підключення…",
"ios-memory-limit": "Відправка файлів на iOS можлива лише до 200 МБ за один раз",
"message-transfer-completed": "Передача повідомлення завершена",
"rate-limit-join-key": "Досягнуто ліміт швидкості. Зачекайте 10 секунд і спробуйте знову.",
"selected-peer-left": "Обраний пір залишив",
"files-incorrect": "Файли неправильні",
"display-name-changed-permanently": "Відображуване ім'я було змінено назавжди",
"notifications-permissions-error": "Дозвіл на сповіщення було заблоковано, оскільки користувач кілька разів відхилив запит на дозвіл. Це можна скинути в інформації про сторінку, до якої можна отримати доступ, натиснувши значок замка поруч з рядком URL.",
"copied-to-clipboard": "Скопійовано в буфер обміну",
"pair-url-copied-to-clipboard": "Посилання для зв'язування цього пристрою скопійовано в буфер обміну",
"room-url-copied-to-clipboard": "Посилання на публічну кімнату скопійовано в буфер обміну",
"text-content-incorrect": "Текстовий вміст неправильний",
"file-content-incorrect": "Вміст файлу неправильний",
"notifications-enabled": "Сповіщення увімкнені",
"connected": "Підключено",
"online": "Ви знову онлайн",
"file-transfer-completed": "Передача файлу завершена",
"unfinished-transfers-warning": "Є незавершені передачі. Ви впевнені, що хочете закрити PairDrop?"
},
"document-titles": {
"file-received": "Файл отримано",
"file-received-plural": "Отримано {{count}} файлів",
"image-transfer-requested": "Запит на передачу зображення",
"message-received": "Повідомлення отримано",
"message-received-plural": "Отримано {{count}} повідомлень",
"file-transfer-requested": "Запит на передачу файлу"
},
"peer-ui": {
"click-to-send-share-mode": "Натисніть, щоб відправити {{descriptor}}",
"connection-hash": "Щоб перевірити безпеку кінцевого шифрування, порівняйте цей номер безпеки на обох пристроях",
"processing": "Обробка…",
"click-to-send": "Натисніть, щоб відправити файли, або клацніть правою кнопкою миші, щоб відправити повідомлення",
"preparing": "Підготовка…",
"waiting": "Чекаю…",
"transferring": "Переводимо…"
}
}

View File

@@ -3,7 +3,7 @@ class Localization {
Localization.$htmlRoot = document.querySelector('html'); Localization.$htmlRoot = document.querySelector('html');
Localization.defaultLocale = "en"; Localization.defaultLocale = "en";
Localization.supportedLocales = ["ar", "be", "ca", "da", "de", "en", "es", "fr", "he", "hu", "id", "it", "ja", "kn", "nb", "nl", "pl", "pt-BR", "ro", "ru", "tr", "zh-CN", "zh-TW"]; Localization.supportedLocales = ["ar", "be", "ca", "cs", "da", "de", "en", "es", "fr", "he", "hu", "id", "it", "ja", "kn", "nb", "nl", "pl", "pt-BR", "ro", "ru", "tr", "uk", "zh-CN", "zh-TW"];
Localization.supportedLocalesRtl = ["ar", "he"]; Localization.supportedLocalesRtl = ["ar", "he"];
Localization.translations = {}; Localization.translations = {};

View File

@@ -201,15 +201,11 @@ class FooterUI {
this.$discoveryWrapper = $$('footer .discovery-wrapper'); this.$discoveryWrapper = $$('footer .discovery-wrapper');
this.$displayName.addEventListener('keydown', e => this._onKeyDownDisplayName(e)); this.$displayName.addEventListener('keydown', e => this._onKeyDownDisplayName(e));
this.$displayName.addEventListener('keyup', e => this._onKeyUpDisplayName(e)); this.$displayName.addEventListener('focus', e => this._onFocusDisplayName(e));
this.$displayName.addEventListener('blur', e => this._saveDisplayName(e.target.innerText)); this.$displayName.addEventListener('blur', e => this._onBlurDisplayName(e));
Events.on('display-name', e => this._onDisplayName(e.detail.displayName)); Events.on('display-name', e => this._onDisplayName(e.detail.displayName));
Events.on('self-display-name-changed', e => this._insertDisplayName(e.detail)); Events.on('self-display-name-changed', e => this._insertDisplayName(e.detail));
// Load saved display name on page load
Events.on('ws-connected', _ => this._loadSavedDisplayName());
Events.on('evaluate-footer-badges', _ => this._evaluateFooterBadges()); Events.on('evaluate-footer-badges', _ => this._evaluateFooterBadges());
} }
@@ -234,17 +230,20 @@ class FooterUI {
} }
async _loadSavedDisplayName() { async _loadSavedDisplayName() {
const displayName = await this._getSavedDisplayName() const displayNameSaved = await this._getSavedDisplayName()
if (!displayName) return; if (!displayNameSaved) return;
console.log("Retrieved edited display name:", displayName) console.log("Retrieved edited display name:", displayNameSaved)
Events.fire('self-display-name-changed', displayName); Events.fire('self-display-name-changed', displayNameSaved);
} }
_onDisplayName(displayName){ async _onDisplayName(displayNameServer){
// set display name // load saved displayname first to prevent flickering
this.$displayName.setAttribute('placeholder', displayName); await this._loadSavedDisplayName();
// set original display name as placeholder
this.$displayName.setAttribute('placeholder', displayNameServer);
} }
@@ -259,9 +258,27 @@ class FooterUI {
} }
} }
_onKeyUpDisplayName(e) { _onFocusDisplayName(e) {
if (!e.target.innerText) {
// Fix z-position of cursor when div is completely empty (Firefox only)
e.target.innerText = "\n";
// On Chromium based browsers the cursor position is lost when adding sth. to the focused node. This adds it back.
let sel = window.getSelection();
sel.collapse(e.target.lastChild);
}
}
async _onBlurDisplayName(e) {
// fix for Firefox inserting a linebreak into div on edit which prevents the placeholder from showing automatically when it is empty // fix for Firefox inserting a linebreak into div on edit which prevents the placeholder from showing automatically when it is empty
if (/^(\n|\r|\r\n)$/.test(e.target.innerText)) e.target.innerText = ''; if (/^(\n|\r|\r\n)$/.test(e.target.innerText)) {
e.target.innerText = '';
}
// Remove selection from text
window.getSelection().removeAllRanges();
await this._saveDisplayName(e.target.innerText)
} }
async _saveDisplayName(newDisplayName) { async _saveDisplayName(newDisplayName) {

View File

@@ -1,4 +1,4 @@
const cacheVersion = 'v1.10.9'; const cacheVersion = 'v1.10.10';
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 = [
@@ -29,6 +29,7 @@ const relativePathsToCache = [
'lang/ar.json', 'lang/ar.json',
'lang/be.json', 'lang/be.json',
'lang/ca.json', 'lang/ca.json',
'lang/cs.json',
'lang/da.json', 'lang/da.json',
'lang/de.json', 'lang/de.json',
'lang/en.json', 'lang/en.json',
@@ -47,6 +48,7 @@ const relativePathsToCache = [
'lang/ro.json', 'lang/ro.json',
'lang/ru.json', 'lang/ru.json',
'lang/tr.json', 'lang/tr.json',
'lang/uk.json',
'lang/zh-CN.json', 'lang/zh-CN.json',
'lang/zh-TW.json' 'lang/zh-TW.json'
]; ];

View File

@@ -557,6 +557,10 @@ footer .logo {
position: relative; position: relative;
} }
#display-name:focus::before {
display: none;
}
html:not([dir="rtl"]) #display-name, html:not([dir="rtl"]) #display-name,
html:not([dir="rtl"]) .edit-pen { html:not([dir="rtl"]) .edit-pen {
margin-left: -1rem; margin-left: -1rem;
@@ -939,8 +943,8 @@ body {
--lt-dialog-bg-color: #fff; --lt-dialog-bg-color: #fff;
--lt-bg-color: 255,255,255; --lt-bg-color: 255,255,255;
--lt-bg-color-secondary: #f2f2f2; --lt-bg-color-secondary: #f2f2f2;
--lt-border-color: #a9a9a9; --lt-border-color: #757575;
--lt-badge-color: #a5a5a5; --lt-badge-color: #757575;
--lt-lang-hr-color: #DDD; --lt-lang-hr-color: #DDD;
--lt-shadow-color-secondary-rgb: 0,0,0; --lt-shadow-color-secondary-rgb: 0,0,0;
@@ -953,8 +957,8 @@ body {
--dt-dialog-bg-color: #141414; --dt-dialog-bg-color: #141414;
--dt-bg-color: 0,0,0; --dt-bg-color: 0,0,0;
--dt-bg-color-secondary: #262628; --dt-bg-color-secondary: #262628;
--dt-border-color: #919191; --dt-border-color: #757575;
--dt-badge-color: #717171; --dt-badge-color: #757575;
--dt-lang-hr-color: #404040; --dt-lang-hr-color: #404040;
--dt-shadow-color-secondary-rgb: 255,255,255; --dt-shadow-color-secondary-rgb: 255,255,255;

View File

@@ -44,15 +44,18 @@ export default class Peer {
_setIP(request) { _setIP(request) {
if (request.headers['cf-connecting-ip']) { if (request.headers['cf-connecting-ip']) {
this.ip = request.headers['cf-connecting-ip'].split(/\s*,\s*/)[0]; this.ip = request.headers['cf-connecting-ip'].split(/\s*,\s*/)[0];
} else if (request.headers['x-forwarded-for']) { }
else if (request.headers['x-forwarded-for']) {
this.ip = request.headers['x-forwarded-for'].split(/\s*,\s*/)[0]; this.ip = request.headers['x-forwarded-for'].split(/\s*,\s*/)[0];
} else { }
this.ip = request.connection.remoteAddress; else {
this.ip = request.socket.remoteAddress ?? '';
} }
// remove the prefix used for IPv4-translated addresses // remove the prefix used for IPv4-translated addresses
if (this.ip.substring(0,7) === "::ffff:") if (this.ip.substring(0,7) === "::ffff:") {
this.ip = this.ip.substring(7); this.ip = this.ip.substring(7);
}
let ipv6_was_localized = false; let ipv6_was_localized = false;
if (this.conf.ipv6Localize && this.ip.includes(':')) { if (this.conf.ipv6Localize && this.ip.includes(':')) {