Compare commits

...

23 Commits

Author SHA1 Message Date
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
schlagmichdoch
b36105b1cf Remove trailing back quote` from command in how-to.md
Fixes #256
2024-01-30 19:09:09 +01:00
schlagmichdoch
ad4f727d19 Merge pull request #212 from comradekingu/patch-2
README reworked
2024-01-30 19:05:00 +01:00
schlagmichdoch
3fa0873bc4 Increase version to v1.10.6
## Changes
- Fix loading error on older iOS and Mac versions
- Fix websocket-fallback info text position
- Translations update from Hosted Weblate (Turkish, Japanese, Indonesian)
2024-01-21 20:09:11 +01:00
schlagmichdoch
a03482bc7f Merge branch 'master' into translate 2024-01-21 20:01:09 +01:00
schlagmichdoch
40aa46fdd9 Merge pull request #245 from weblate/weblate-pairdrop-pairdrop-spa
Translations update from Hosted Weblate
2024-01-21 19:56:08 +01:00
Hosted Weblate
9003094e49 Translated using Weblate (Indonesian)
Currently translated at 93.9% (156 of 166 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Reza Almanda <rezaalmanda27@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/pairdrop/pairdrop-spa/id/
Translation: PairDrop/pairdrop-spa
2024-01-21 19:55:10 +01:00
Hosted Weblate
0459a361c3 Translated using Weblate (Japanese)
Currently translated at 98.1% (163 of 166 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: RintanBroadleaf <rintanbroadleaf@outlook.jp>
Translate-URL: https://hosted.weblate.org/projects/pairdrop/pairdrop-spa/ja/
Translation: PairDrop/pairdrop-spa
2024-01-21 19:55:10 +01:00
Hosted Weblate
10a669d7c6 Translated using Weblate (Turkish)
Currently translated at 100.0% (166 of 166 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/pairdrop/pairdrop-spa/tr/
Translation: PairDrop/pairdrop-spa
2024-01-21 19:55:10 +01:00
schlagmichdoch
3fbca72d74 Merge pull request #243 from schlagmichdoch/fix-regex-error
Fix Error Invalid Group Specifier Name on MacOS Safari and iOS Firefox on older MacOS/iOS
2024-01-21 19:53:57 +01:00
Allan Nordhøy
f048c4f1bd GIF 2024-01-13 13:46:19 +00:00
Allan Nordhøy
6c1672ba25 Fixing conflicts, better 2024-01-13 13:44:44 +00:00
Allan Nordhøy
caf19bdb45 Merge branch 'master' into patch-2 2024-01-13 13:25:31 +00:00
Allan Nordhøy
5dcda58ce5 Structure and requested fixes 2024-01-13 13:18:06 +00:00
schlagmichdoch
59360fb047 Fix websocket-fallback info text not centered when line is broken 2024-01-12 01:43:08 +01:00
schlagmichdoch
2e15a018da Fix Error Invalid Group Specifier Name on Safari by removing REGEX lookbehind group construct (fixes #239) 2024-01-12 01:23:14 +01:00
schlagmichdoch
041261be2a Fix url argument case ?share_target 2024-01-06 16:15:30 +01:00
schlagmichdoch
f152645452 Increase version to v1.10.5
## Changes
- Fix Zip Release workflow
2024-01-06 15:41:39 +01:00
schlagmichdoch
a7f5d336c3 Fix Zip Release workflow: wrong upload path 2024-01-06 15:37:05 +01:00
schlagmichdoch
4a5a2ceb67 Merge branch 'master' into patch-2 2023-12-04 21:16:41 +01:00
Allan Nordhøy
214d557feb README reworked 2023-11-30 01:20:28 +00:00
14 changed files with 290 additions and 172 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/**
No | Yes
Version: v1.10.4
Version: v1.10.6
**Bug occurs on self-hosted PairDrop instance**
No | Yes
@@ -44,7 +44,7 @@ No | Yes
**Self-Hosted Setup**
Proxy: Nginx | Apache2
Deployment: docker run | docker compose | npm run start:prod
Version: v1.10.4
Version: v1.10.6
**Additional context**
Add any other context about the problem here.

View File

@@ -32,5 +32,5 @@ jobs:
- name: Upload Release
uses: ncipollo/release-action@6c75be85e571768fa31b40abf38de58ba0397db5 # v1.13.0
with:
artifacts: "pairdrop-cli.zip"
artifacts: "pairdrop-cli/pairdrop-cli.zip"
token: ${{ secrets.GITHUB_TOKEN }}

178
README.md
View File

@@ -3,133 +3,127 @@
<img src="public/images/android-chrome-512x512.png" alt="Logo" width="150" height="150">
</a>
<h1>PairDrop</h1>
# _Send it_, with [PairDrop](https://pairdrop.net)
<p>
Local file sharing in your browser. Inspired by Apple's AirDrop.
<br />
<a href="https://pairdrop.net"><strong>Explore »</strong></a>
Local file sharing <a href="https://pairdrop.net"><strong>in your web browser</strong></a>.
<br />
<br />
<a href="https://github.com/schlagmichdoch/PairDrop/issues">Report Bug</a>
·
<a href="https://github.com/schlagmichdoch/PairDrop/issues">Request Feature</a>
<a href="https://github.com/schlagmichdoch/PairDrop/issues">Report a bug</a>
<br />
<a href="https://github.com/schlagmichdoch/PairDrop/issues">Request feature</a>
</p>
</div>
## Features
[PairDrop](https://pairdrop.net) is a sublime alternative to AirDrop that works on all platforms.
File sharing on your local network that works on all platforms.
- File Sharing on your local network
- Send images, documents or text via peer to peer connection to devices on the same local network.
- Internet Transfers
- Join temporary public rooms to transfer files easily over the internet!
- Web-Application
- As it is web based, it runs on all devices.
- A multi-platform AirDrop-like solution that works.
- Send images, documents or text via peer-to-peer connection to devices on the same local network.
- Internet transfers
- Join temporary public rooms to transfer files easily over the Internet.
- Web-app
- Works on all devices with a modern web-browser.
Send a file from your phone to your laptop?
<br>Share photos in original quality with friends using Android and iOS?
<br>Share private files peer-to-peer between Linux systems?
You want to quickly send a file from your phone to your laptop?
<br>You want to share photos in original quality with friends that use a mixture of Android and iOS?
<br>You want to share private files peer to peer between Linux systems?
<br>AirDrop is unreliable again?
<br>_Send it with PairDrop!_
<img src="docs/pairdrop_screenshot_mobile.gif" alt="Screenshot GIF showing PairDrop in use" style="width: 300px">
Developed based on [Snapdrop](https://github.com/RobinLinus/snapdrop)
## Differences to the [Snapdrop](https://github.com/RobinLinus/snapdrop) it is based on
<details><summary>List view</summary>
## Differences to Snapdrop
<details><summary>Click to expand</summary>
### Paired Devices and Public Rooms - Internet Transfer
* Transfer files over the internet between paired devices or by entering temporary public rooms.
* Connect to devices in complex network environments (public Wi-Fi, company network, Apple Private Relay, VPN etc.).
### Paired Devices and Public Rooms — Internet Transfer
* Transfer files over the Internet between paired devices or by entering temporary public rooms.
* Connect to devices in complex network environments (public Wi-Fi, company network, iCloud Private Relay, VPN, etc.).
* Connect to devices on your mobile hotspot.
* Devices outside your local network that are behind a NAT are connected automatically via the PairDrop TURN server.
* Devices outside of your local network that are behind a NAT are auto-connected via the PairDrop TURN server.
* Connect to devices on your mobile hotspot.
* You will always discover devices on your local network. Paired devices and devices in the same public room are shown additionally.
* Devices from the local network, in the same public room, or previously paired are shown.
#### Persistent Device Pairing
* Pair your devices via a 6-digit code or a QR-Code.
* Paired devices will always find each other via shared secrets independently of their local network.
* Paired devices are persistent. You find your devices even after reopening PairDrop.
* You can edit and unpair devices easily
* Ideal to always connect easily to your own devices
Always connect to known devices
* Pair devices via a 6-digit code or a QR-Code.
* Paired devices always find each other via shared secrets independently of their local network.
* Pairing is persistent. You find your devices even after reopening PairDrop.
* You can edit and unpair devices easily.
#### Temporary Public Rooms
* Enter a public room via a 5-letter code or a QR-Code.
* Enter a public room to temporarily connect to devices outside your local network.
* All devices in the same public room see each other mutually.
* Public rooms are temporary. Public rooms are left as soon as PairDrop is closed.
* Ideal to connect easily to others in complex network situations or over the internet.
### [Improved UI for sending/receiving files](https://github.com/RobinLinus/snapdrop/issues/560)
* Files are transferred only after a request is accepted first. On transfer completion files are downloaded automatically if possible.
Connect to others in complex network situations, or over the Internet.
* Enter a public room via a 5-letter code or a QR-code.
* Enter a public room to temporarily connect to devices outside your local network.
* All devices in the same public room see each other.
* Public rooms are temporary. Closing PairDrop leaves all rooms.
### [Improved UI for Sending/Receiving Files](https://github.com/RobinLinus/snapdrop/issues/560)
* Files are transferred after a request is accepted. Files are auto-downloaded upon completing a transfer, if possible.
* Multiple files are downloaded as a ZIP file
* On iOS and Android, in addition to downloading, files can be shared or saved to the gallery via the Share menu.
* Multiple files are transferred at once with an overall progress indicator
* Download, share or save to gallery via the "Share" menu on Android and iOS.
* Multiple files are transferred at once with an overall progress indicator.
### Send Files or Text Directly From Share Menu, Context Menu or CLI
* [Send files directly from context menu on Windows](docs/how-to.md#send-multiple-files-and-directories-directly-from-context-menu-on-windows)
* [Send files directly from context menu on Ubuntu (using Nautilus)](/docs/how-to.md#send-multiple-files-and-directories-directly-from-context-menu-on-ubuntu-using-nautilus)
* [Send files directly from share menu on iOS](docs/how-to.md#send-directly-from-share-menu-on-ios)
* [Send files directly from share menu on Android](docs/how-to.md#send-directly-from-share-menu-on-android)
* [Send files directly via command-line interface](docs/how-to.md#send-directly-via-command-line-interface)
* [Send files directly from context menu on Ubuntu (using Nautilus)](docs/how-to.md#send-multiple-files-and-directories-directly-from-context-menu-on-ubuntu-using-nautilus)
* [Send files directly from the context menu on Windows](docs/how-to.md#send-files-directly-from-context-menu-on-windows)
* [Send directly from the "Share" menu on iOS](docs/how-to.md#send-directly-from-share-menu-on-ios)
* [Send directly from the "Share" menu on Android](docs/how-to.md#send-directly-from-share-menu-on-android)
* [Send directly via the command-line interface](docs/how-to.md#send-directly-via-command-line-interface)
### Other changes
* Change your display name permanently to easily differentiate your devices
* [Paste files/text and choose the recipient afterwords ](https://github.com/RobinLinus/snapdrop/pull/534)
### Other Changes
* Change your display name to easily differentiate your devices.
* [Paste files/text and choose the recipient afterwards ](https://github.com/RobinLinus/snapdrop/pull/534)
* [Prevent devices from sleeping on file transfer](https://github.com/RobinLinus/snapdrop/pull/413)
* Warn user before PairDrop is closed on file transfer
* Open PairDrop on multiple tabs simultaneously (Thanks [@willstott101](https://github.com/willstott101))
* [Video and Audio preview](https://github.com/RobinLinus/snapdrop/pull/455) (Thanks [@victorwads](https://github.com/victorwads))
* Switch theme back to auto/system after darkmode or lightmode is enabled
* [Video and audio preview](https://github.com/RobinLinus/snapdrop/pull/455) (Thanks [@victorwads](https://github.com/victorwads))
* Switch theme back to auto/system after dark or light mode is on
* Node-only implementation (Thanks [@Bellisario](https://github.com/Bellisario))
* Automatic restart on error (Thanks [@KaKi87](https://github.com/KaKi87))
* Auto-restart on error (Thanks [@KaKi87](https://github.com/KaKi87))
* Lots of stability fixes (Thanks [@MWY001](https://github.com/MWY001) [@skiby7](https://github.com/skiby7) and [@willstott101](https://github.com/willstott101))
* To host PairDrop on your local network (e.g. on Raspberry Pi): [All peers connected with private IPs are discoverable by each other](https://github.com/RobinLinus/snapdrop/pull/558)
* When hosting PairDrop yourself you can [set your own STUN/TURN servers](docs/host-your-own.md#specify-stunturn-servers)
* Built-in translations via [Weblate](https://hosted.weblate.org/engage/pairdrop/)
* Airy design (Thanks [@Avieshek](https://linktr.ee/avieshek/))
* When hosting PairDrop yourself, you can [set your own STUN/TURN servers](docs/host-your-own.md#specify-stunturn-servers)
* Translations.
</details>
## Screenshots
<img src="docs/pairdrop_screenshot_mobile.gif" alt="Gif of Screenshots that show PairDrop in use" style="width: 300px">
## PairDrop is built with the following awesome technologies:
* Vanilla HTML5 / ES6 / CSS3 frontend
* [WebRTC](http://webrtc.org/) / [WebSockets](http://www.websocket.org/)
* [NodeJS](https://nodejs.org/en/) backend
* [Progressive Web App](https://wikipedia.org/wiki/Progressive_Web_App)
* [IndexedDB API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API)
* [Weblate](https://weblate.org/) Web based localization tool
* [zip.js](https://github.com/gildas-lormeau/zip.js) JavaScript library to zip and unzip files ([BSD 3-Clause License](licenses/BSD_3-Clause-zip-js))
* [NoSleep](https://github.com/richtr/NoSleep.js) JavaScript library to prevent display sleep and enable wake lock in any Android or iOS web browser ([MIT License](licenses/MIT-NoSleep))
* [heic2any](https://github.com/alexcorvi/heic2any) JavaScript library to convert HEIC/HEIF images to PNG/GIF/JPEG ([MIT License](licenses/MIT-heic2any))
* [cyrb53](https://github.com/bryc) Super fast hash function
Have any questions? Read our [FAQ](docs/faq.md).
You can [host your own instance with Docker](docs/host-your-own.md).
## Support PairDrop
<a href="https://www.buymeacoffee.com/pairdrop" target="_blank">
<img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" >
</a>
PairDrop is free and always will be.
Still, we have to pay for the domain and the server.
To contribute and support, please use BuyMeACoffee via the button above.
Thanks a lot for supporting free and open software!
## Translate PairDrop
## Translate PairDrop on [Hosted Weblate](https://hosted.weblate.org/engage/pairdrop/)
<a href="https://hosted.weblate.org/engage/pairdrop/">
<img src="https://hosted.weblate.org/widget/pairdrop/pairdrop-spa/open-graph.png" alt="Translation status" style="width: 300px" />
<img src="https://hosted.weblate.org/widget/pairdrop/horizontal-blue.svg" alt="Translation status" style="width: 300px" />
</a>
## How to contribute
## Built with the following awesome technologies:
* Vanilla HTML5 / JS ES6 / CSS 3 frontend
* [WebRTC](http://webrtc.org/) / WebSockets
* [Node.js](https://nodejs.org/en/) backend
* [Progressive web app (PWA)](https://en.wikipedia.org/wiki/Progressive_web_app) unified functionality
* [IndexedDB API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) storage handling
* [zip.js](https://gildas-lormeau.github.io/zip.js/) library
* [cyrb53](https://github.com/bryc/code/blob/master/jshash/experimental/cyrb53.js) super-fast hash function
* [NoSleep](https://github.com/richtr/NoSleep.js) display sleep, add wake lock ([MIT](licenses/MIT-NoSleep))
* [heic2any](https://github.com/alexcorvi/heic2any) HEIC/HEIF to PNG/GIF/JPEG ([MIT](licenses/MIT-heic2any))
* [Weblate](https://weblate.org/) web-based localization tool
[FAQ](docs/faq.md)
[Host your own instance with Docker or Node.js](docs/host-your-own.md).
## Support
<a href="https://www.buymeacoffee.com/pairdrop" target="_blank">
<img src="https://cdn.buymeacoffee.com/buttons/v2/default-blue.png" alt="Buy me a coffee" style="height: 60px !important;width: 217px !important;" >
</a>
<br />
<br />
PairDrop is libre, and always will be. \
I footed the bill for the domain and the server, and you can help create great softeare by supporting me. \
Please use BuyMeACoffee via the button above. \
Thanks a lot for supporting copylefted libre software!
## Contributing
Feel free to [open an issue](https://github.com/schlagmichdoch/pairdrop/issues/new/choose) or a
[pull request](https://github.com/schlagmichdoch/pairdrop/pulls) but follow
[pull request](https://github.com/schlagmichdoch/pairdrop/pulls), following the
[Contributing Guidelines](CONTRIBUTING.md).

View File

@@ -45,11 +45,11 @@ This pairdrop-cli version was released alongside v1.10.4
#### Linux / Mac
1. Download the latest _pairdrop-cli.zip_ from the [releases page](https://github.com/schlagmichdoch/PairDrop/releases)
```shell
wget "https://github.com/schlagmichdoch/PairDrop/releases/download/v1.10.4/pairdrop-cli.zip"
wget "https://github.com/schlagmichdoch/PairDrop/releases/download/v1.10.6/pairdrop-cli.zip"
```
or
```shell
curl -LO "https://github.com/schlagmichdoch/PairDrop/releases/download/v1.10.4/pairdrop-cli.zip"
curl -LO "https://github.com/schlagmichdoch/PairDrop/releases/download/v1.10.6/pairdrop-cli.zip"
```
2. Unzip the archive to a folder of your choice e.g. `/usr/share/pairdrop-cli/`
```shell
@@ -125,7 +125,7 @@ It is possible to send multiple files with PairDrop via the context menu by addi
```
3. Make the shell file _send-with-pairdrop_ executable
```shell
chmod +x ~/.local/share/nautilus/scripts/send-with-pairdrop`
chmod +x ~/.local/share/nautilus/scripts/send-with-pairdrop
```
4. You are done! You can now send multiple files and directories directly via PairDrop:

4
package-lock.json generated
View File

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

View File

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

View File

@@ -139,7 +139,7 @@
<div class="edit-btn btn btn-small btn-rounded btn-dark text-white" data-i18n-key="header.edit-share-mode" data-i18n-attrs="text" hidden></div>
</div>
</div>
<div id="websocket-fallback" hidden>
<div id="websocket-fallback" class="text-center" hidden>
<span data-i18n-key="footer.traffic" data-i18n-attrs="text"></span>
<span data-i18n-key="footer.routed" data-i18n-attrs="text"></span>
<span data-i18n-key="footer.webrtc" data-i18n-attrs="text"></span>
@@ -582,7 +582,7 @@
</svg>
<div class="title-wrapper" dir="ltr">
<h1>PairDrop</h1>
<div class="font-subheading">v1.10.4</div>
<div class="font-subheading">v1.10.6</div>
</div>
<div class="font-subheading" data-i18n-key="about.claim" data-i18n-attrs="text"></div>
<div class="row">

View File

@@ -69,7 +69,9 @@
"language-selector_title": "Atur Bahasa",
"about_title": "Tentang PairDrop",
"about_aria-label": "Buka Tentang PairDrop",
"theme-light_title": "Selalu gunakan tema terang"
"theme-light_title": "Selalu gunakan tema terang",
"edit-share-mode": "Sunting",
"expand_title": "Perluas baris tombol header"
},
"instructions": {
"x-instructions_mobile": "Ketuk untuk mengirim file atau ketuk lama untuk mengirim pesan",
@@ -83,7 +85,11 @@
"no-peers-title": "Buka PairDrop di perangkat lain untuk berkirim file",
"x-instructions_data-drop-peer": "Lepaskan untuk mengirim ke rekan",
"x-instructions_data-drop-bg": "Lepaskan untuk memilih penerima",
"no-peers_data-drop-bg": "Lepaskan untuk memilih penerima"
"no-peers_data-drop-bg": "Lepaskan untuk memilih penerima",
"activate-share-mode-and-other-file": "dan 1 file lainnya",
"activate-share-mode-shared-file": "file yang dibagikan",
"activate-share-mode-shared-files-plural": "{{count}} file yang dibagikan",
"webrtc-requirement": "Untuk menggunakan instance PairDrop ini, WebRTC harus diaktifkan!"
},
"peer-ui": {
"processing": "Memproses…",
@@ -111,7 +117,7 @@
"join": "Gabung",
"title-image-plural": "Gambar",
"send": "Kirim",
"base64-tap-to-paste": "Ketuk di sini untuk menempelkan {{type}}",
"base64-tap-to-paste": "Ketuk di sini untuk membagikan{{type}}",
"base64-text": "teks",
"copy": "Salin",
"file-other-description-image": "dan 1 gambar lainnya",
@@ -125,7 +131,7 @@
"title-image": "Gambar",
"file-other-description-file-plural": "dan {{count}} file lainnya",
"would-like-to-share": "ingin berbagi",
"send-message-to": "Kirim pesan ke",
"send-message-to": "Ke:",
"language-selector-title": "Pilih Bahasa",
"pair": "Pasangkan",
"hr-or": "ATAU",
@@ -144,7 +150,11 @@
"enter-room-id-from-another-device": "Masukkan room ID dari perangkat lain untuk bergabung dengan room.",
"message_title": "Masukkan pesan untuk dikirim",
"pair-devices-qr-code_title": "Klik untuk menyalin tautan untuk memasangkan perangkat ini",
"public-room-qr-code_title": "Klik untuk menyalin tautan ke ruang publik"
"public-room-qr-code_title": "Klik untuk menyalin tautan ke ruang publik",
"base64-title-files": "Bagikan File",
"base64-title-text": "Bagikan Teks",
"message_placeholder": "Teks",
"paired-device-removed": "Perangkat yang dipasangkan telah dihapus."
},
"about": {
"claim": "Cara termudah untuk mentransfer file lintas perangkat",

View File

@@ -69,7 +69,9 @@
"language-selector_title": "言語を設定",
"about_title": "PairDropについて",
"about_aria-label": "PairDropについてを開く",
"theme-light_title": "常にライトテーマを使用する"
"theme-light_title": "常にライトテーマを使用する",
"edit-share-mode": "編集",
"expand_title": "ヘッダーボタン列を拡大する"
},
"instructions": {
"x-instructions_mobile": "タップしてファイルを送信または長押ししてメッセージを送信します",
@@ -83,7 +85,11 @@
"no-peers-title": "他のデバイスでPairDropを開いてファイルを送信します",
"x-instructions_data-drop-peer": "離すとこの相手に送信します",
"x-instructions_data-drop-bg": "送信したい相手の上で離してください",
"no-peers_data-drop-bg": "送信したい相手の上で離してください"
"no-peers_data-drop-bg": "送信したい相手の上で離してください",
"activate-share-mode-and-other-file": "もう1つの別のファイル",
"activate-share-mode-shared-file": "共有されたファイル",
"activate-share-mode-shared-files-plural": "{{count}}個の共有されたファイル",
"webrtc-requirement": "このPairDropインスタンスを使用するには、WebRTCを有効にする必要があります"
},
"peer-ui": {
"processing": "処理中…",
@@ -144,7 +150,16 @@
"enter-room-id-from-another-device": "他のデバイスに表示された参加したいルームのIDを入力します。",
"message_title": "送信するメッセージを挿入",
"pair-devices-qr-code_title": "クリックしてこのデバイスをペア設定するリンクをコピー",
"public-room-qr-code_title": "クリックしてパブリックルームへのリンクをコピー"
"public-room-qr-code_title": "クリックしてパブリックルームへのリンクをコピー",
"paired-device-removed": "ペア設定されたデバイスが削除されました。",
"message_placeholder": "テキスト",
"base64-title-files": "共有されたファイル",
"base64-title-text": "テキストを共有",
"approve": "承諾",
"share-text-subtitle": "送信する前にメッセージを編集する:",
"share-text-checkbox": "テキストを共有するときに常にこのダイアログを表示する",
"close-toast_title": "通知を閉じる",
"share-text-title": "テキストメッセージを共有します"
},
"about": {
"claim": "デバイス間でファイルを転送する最も簡単な方法",
@@ -152,7 +167,11 @@
"close-about_aria-label": "PairDropについてを閉じる",
"buy-me-a-coffee_title": "コーヒーをおごってください!",
"github_title": "GitHubでPairDropを見る",
"faq_title": "FAQ"
"faq_title": "FAQ",
"mastodon_title": "MastodonにPairDropについて書く",
"bluesky_title": "BlueSkyでフォロー",
"custom_title": "フォロー",
"privacypolicy_title": "プライバシーポリシーを開く"
},
"document-titles": {
"file-transfer-requested": "ファイルの転送がリクエストされました",

View File

@@ -12,7 +12,8 @@
"cancel-share-mode": "Bitti",
"join-public-room_title": "Geçici olarak genel odaya katılın",
"language-selector_title": "Dili Seç",
"edit-share-mode": "Düzenle"
"edit-share-mode": "Düzenle",
"expand_title": "Başlık düğmesi satırını genişlet"
},
"instructions": {
"no-peers_data-drop-bg": "Alıcıyı seçmek için bırakın",
@@ -166,7 +167,11 @@
"close-about_aria-label": "PairDrop Hakkında'yı Kapat",
"buy-me-a-coffee_title": "Bana bir kahve al!",
"github_title": "GitHub'da PairDrop",
"faq_title": "Sıkça sorulan sorular"
"faq_title": "Sıkça sorulan sorular",
"custom_title": "Bizi takip edin",
"privacypolicy_title": "Gizlilik politikamızıın",
"mastodon_title": "Mastodon'da PairDrop hakkında yazın",
"bluesky_title": "Bizi BlueSky'da takip edin"
},
"document-titles": {
"file-transfer-requested": "Dosya Transferi Talep Edildi",

View File

@@ -172,31 +172,34 @@ class PeersUI {
}
_onDrop(e) {
e.preventDefault();
if (this.shareMode.active || Dialog.anyDialogShown()) return;
if (!$$('x-peer') || !$$('x-peer').contains(e.target)) {
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});
});
}
}
}
}
e.preventDefault();
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) {
e.preventDefault();
if (this.shareMode.active || Dialog.anyDialogShown()) return;
e.preventDefault();
this.$xInstructions.setAttribute('drop-bg', true);
this.$xNoPeers.setAttribute('drop-bg', true);
}
@@ -630,29 +633,28 @@ class PeerUI {
}
_onDrop(e) {
e.preventDefault();
if (PeerUI._shareMode.active || Dialog.anyDialogShown()) return;
if (e.dataTransfer.files.length > 0) {
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
});
});
}
}
}
e.preventDefault();
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() {
@@ -1896,6 +1898,8 @@ class SendTextDialog extends Dialog {
this.$submit = this.$el.querySelector('button[type="submit"]');
this.$form.addEventListener('submit', e => this._onSubmit(e));
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('keydown', e => this._onKeyDown(e));
@@ -1914,6 +1918,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() {
return !this.$text.innerText || this.$text.innerText === "\n";
}
@@ -1997,12 +2035,22 @@ class ReceiveTextDialog extends Dialog {
window.blop.play();
this._receiveTextQueue.push({text: text, peerId: peerId});
this._setDocumentTitleMessages();
changeFavicon("images/favicon-96x96-notification.png");
if (this.isShown()) return;
this._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();
this._showReceiveTextDialog(text, peerId);
}
@@ -2013,35 +2061,68 @@ class ReceiveTextDialog extends Dialog {
this.$displayName.classList.add($(peerId).ui._badgeClassName());
this.$text.innerText = text;
this.$text.classList.remove('text-center');
// Beautify text if text is short
if (text.length < 2000) {
// replace URLs with actual links
this.$text.innerHTML = this.$text.innerHTML
.replace(/(^|(?<=(<br>|\s)))(https?:\/\/|www.)(([a-z]|[A-Z]|[0-9]|[\-_~:\/?#\[\]@!$&'()*+,;=%]){2,}\.)(([a-z]|[A-Z]|[0-9]|[\-_~:\/?#\[\]@!$&'()*+,;=%.]){2,})/g,
(url) => {
let link = url;
// Beautify text if text is not too long
if (this.$text.innerText.length <= 300000) {
// Hacky workaround to replace URLs with link nodes in all cases
// 1. Use text variable, find all valid URLs via regex and replace URLs with placeholder
// 2. Use html variable, find placeholders with regex and replace them with link nodes
// prefix www.example.com with http protocol to prevent it from being a relative link
if (link.startsWith('www')) {
link = "http://" + link
let $textShadow = document.createElement('div');
$textShadow.innerText = text;
let linkNodes = {};
let searchHTML = $textShadow.innerHTML;
const p = "@";
const pRgx = new RegExp(`${p}\\d+`, 'g');
let occP = searchHTML.match(pRgx) || [];
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}`;
return `<a href="${link}" target="_blank">${url}</a>`;
// 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._setDocumentTitleMessages();
changeFavicon("images/favicon-96x96-notification.png");
this.show();
}
_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-plural", null, {count: this._receiveTextQueue.length + 1}) } - PairDrop`;
}

View File

@@ -583,4 +583,14 @@ async function decodeBase64Text(base64) {
if (!base64) throw new Error('Base64 is empty');
return decodeURIComponent(escape(window.atob(base64)))
}
function isUrlValid(url) {
try {
let urlObj = new URL(url);
return true;
}
catch (e) {
return false;
}
}

View File

@@ -1,4 +1,4 @@
const cacheVersion = 'v1.10.4';
const cacheVersion = 'v1.10.6';
const cacheTitle = `pairdrop-cache-${cacheVersion}`;
const forceFetch = false; // FOR DEVELOPMENT: Set to true to always update assets instead of using cached versions
const relativePathsToCache = [
@@ -193,7 +193,7 @@ const evaluateRequestData = function (request) {
const objectStoreRequest = objectStore.add(fileObjects[i]);
objectStoreRequest.onsuccess = _ => {
if (i === fileObjects.length - 1) resolve(pairDropUrl + '?share-target=files');
if (i === fileObjects.length - 1) resolve(pairDropUrl + '?share_target=files');
}
}
}
@@ -202,7 +202,7 @@ const evaluateRequestData = function (request) {
}
}
else {
let urlArgument = '?share-target=text';
let urlArgument = '?share_target=text';
if (title) urlArgument += `&title=${title}`;
if (text) urlArgument += `&text=${text}`;

View File

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