mirror of
https://github.com/schlagmichdoch/PairDrop.git
synced 2025-04-22 15:56:17 -04:00
Merge branch 'implement_paste_base64_zip'
This commit is contained in:
commit
000cdb2f70
7 changed files with 178 additions and 57 deletions
|
@ -18,6 +18,9 @@ server {
|
||||||
location /ca.crt {
|
location /ca.crt {
|
||||||
alias /etc/ssl/certs/snapdropCA.crt;
|
alias /etc/ssl/certs/snapdropCA.crt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# To allow POST on static pages
|
||||||
|
error_page 405 =200 $uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
|
@ -42,5 +45,7 @@ server {
|
||||||
location /ca.crt {
|
location /ca.crt {
|
||||||
alias /etc/ssl/certs/snapdropCA.crt;
|
alias /etc/ssl/certs/snapdropCA.crt;
|
||||||
}
|
}
|
||||||
|
# To allow POST on static pages
|
||||||
|
error_page 405 =200 $uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ server {
|
||||||
location /ca.crt {
|
location /ca.crt {
|
||||||
alias /etc/ssl/certs/snapdropCA.crt;
|
alias /etc/ssl/certs/snapdropCA.crt;
|
||||||
}
|
}
|
||||||
|
# To allow POST on static pages
|
||||||
|
error_page 405 =200 $uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
|
@ -34,5 +36,7 @@ server {
|
||||||
location /ca.crt {
|
location /ca.crt {
|
||||||
alias /etc/ssl/certs/snapdropCA.crt;
|
alias /etc/ssl/certs/snapdropCA.crt;
|
||||||
}
|
}
|
||||||
|
# To allow POST on static pages
|
||||||
|
error_page 405 =200 $uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,7 @@
|
||||||
<div id="displayName" placeholder=" "></div>
|
<div id="displayName" placeholder=" "></div>
|
||||||
<div class="font-body2">You can be discovered by everyone on this network</div>
|
<div class="font-body2">You can be discovered by everyone on this network</div>
|
||||||
</footer>
|
</footer>
|
||||||
<!-- JoinRoom Dialog -->
|
<!-- Pair Device Dialog -->
|
||||||
<x-dialog id="pairDeviceDialog">
|
<x-dialog id="pairDeviceDialog">
|
||||||
<form action="#">
|
<form action="#">
|
||||||
<x-background class="full center text-center">
|
<x-background class="full center text-center">
|
||||||
|
@ -116,6 +116,7 @@
|
||||||
</x-background>
|
</x-background>
|
||||||
</form>
|
</form>
|
||||||
</x-dialog>
|
</x-dialog>
|
||||||
|
<!-- Clear Devices Dialog -->
|
||||||
<x-dialog id="clearDevicesDialog">
|
<x-dialog id="clearDevicesDialog">
|
||||||
<form action="#">
|
<form action="#">
|
||||||
<x-background class="full center text-center">
|
<x-background class="full center text-center">
|
||||||
|
@ -192,6 +193,15 @@
|
||||||
</x-paper>
|
</x-paper>
|
||||||
</x-background>
|
</x-background>
|
||||||
</x-dialog>
|
</x-dialog>
|
||||||
|
<!-- Receive Dialog -->
|
||||||
|
<x-dialog id="base64ZipDialog">
|
||||||
|
<x-background class="full center">
|
||||||
|
<x-paper shadow="2">
|
||||||
|
<button class="button center" id="base64ZipPasteBtn" title="Paste">Tap here to paste files</button>
|
||||||
|
<button class="button center" close>Close</button>
|
||||||
|
</x-paper>
|
||||||
|
</x-background>
|
||||||
|
</x-dialog>
|
||||||
<!-- Toast -->
|
<!-- Toast -->
|
||||||
<div class="toast-container full center">
|
<div class="toast-container full center">
|
||||||
<x-toast class="row" shadow="1" id="toast">File Transfer Completed</x-toast>
|
<x-toast class="row" shadow="1" id="toast">File Transfer Completed</x-toast>
|
||||||
|
|
|
@ -30,12 +30,17 @@
|
||||||
"display": "minimal-ui",
|
"display": "minimal-ui",
|
||||||
"theme_color": "#3367d6",
|
"theme_color": "#3367d6",
|
||||||
"share_target": {
|
"share_target": {
|
||||||
"method":"GET",
|
"action": "/",
|
||||||
"action": "/?share_target",
|
"method":"POST",
|
||||||
|
"enctype": "multipart/form-data",
|
||||||
"params": {
|
"params": {
|
||||||
"title": "title",
|
"title": "title",
|
||||||
"text": "text",
|
"text": "text",
|
||||||
"url": "url"
|
"url": "url",
|
||||||
|
"files": [{
|
||||||
|
"name": "allfiles",
|
||||||
|
"accept": ["*/*"]
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"file_handlers": [
|
"file_handlers": [
|
||||||
|
|
|
@ -931,7 +931,6 @@ class SendTextDialog extends Dialog {
|
||||||
|
|
||||||
_onRecipient(recipient) {
|
_onRecipient(recipient) {
|
||||||
this._recipient = recipient;
|
this._recipient = recipient;
|
||||||
this._handleShareTargetText();
|
|
||||||
this.show();
|
this.show();
|
||||||
|
|
||||||
const range = document.createRange();
|
const range = document.createRange();
|
||||||
|
@ -943,12 +942,6 @@ class SendTextDialog extends Dialog {
|
||||||
sel.addRange(range);
|
sel.addRange(range);
|
||||||
}
|
}
|
||||||
|
|
||||||
_handleShareTargetText() {
|
|
||||||
if (!window.shareTargetText) return;
|
|
||||||
this.$text.textContent = window.shareTargetText;
|
|
||||||
window.shareTargetText = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
_send() {
|
_send() {
|
||||||
Events.fire('send-text', {
|
Events.fire('send-text', {
|
||||||
to: this._recipient,
|
to: this._recipient,
|
||||||
|
@ -997,6 +990,45 @@ class ReceiveTextDialog extends Dialog {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Base64ZipDialog extends Dialog {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super('base64ZipDialog');
|
||||||
|
const urlParams = new URL(window.location).searchParams;
|
||||||
|
const base64zip = urlParams.get('base64zip');
|
||||||
|
this.$pasteBtn = this.$el.querySelector('#base64ZipPasteBtn')
|
||||||
|
this.$pasteBtn.addEventListener('click', _ => this.processClipboard())
|
||||||
|
if (base64zip) this.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
async processClipboard() {
|
||||||
|
this.$pasteBtn.pointerEvents = "none";
|
||||||
|
this.$pasteBtn.innerText = "Processing...";
|
||||||
|
try {
|
||||||
|
const base64zip = await navigator.clipboard.readText();
|
||||||
|
let bstr = atob(base64zip), n = bstr.length, u8arr = new Uint8Array(n);
|
||||||
|
while (n--) {
|
||||||
|
u8arr[n] = bstr.charCodeAt(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
const zipBlob = new File([u8arr], 'archive.zip');
|
||||||
|
|
||||||
|
let files = [];
|
||||||
|
const zipEntries = await zipper.getEntries(zipBlob);
|
||||||
|
for (let i = 0; i < zipEntries.length; i++) {
|
||||||
|
let fileBlob = await zipper.getData(zipEntries[i]);
|
||||||
|
files.push(new File([fileBlob], zipEntries[i].filename));
|
||||||
|
}
|
||||||
|
Events.fire('activate-paste-mode', {files: files, text: ""})
|
||||||
|
} catch (e) {
|
||||||
|
Events.fire('notify-user', 'Clipboard content is malformed.')
|
||||||
|
} finally {
|
||||||
|
window.history.replaceState({}, "Rewrite URL", '/');
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Toast extends Dialog {
|
class Toast extends Dialog {
|
||||||
constructor() {
|
constructor() {
|
||||||
super('toast');
|
super('toast');
|
||||||
|
@ -1135,20 +1167,35 @@ class NetworkStatusUI {
|
||||||
|
|
||||||
class WebShareTargetUI {
|
class WebShareTargetUI {
|
||||||
constructor() {
|
constructor() {
|
||||||
const parsedUrl = new URL(window.location);
|
const urlParams = new URL(window.location).searchParams;
|
||||||
const title = parsedUrl.searchParams.get('title');
|
const share_target_type = urlParams.get("share-target")
|
||||||
const text = parsedUrl.searchParams.get('text');
|
if (share_target_type) {
|
||||||
const url = parsedUrl.searchParams.get('url');
|
if (share_target_type === "text") {
|
||||||
|
const title = urlParams.get('title') || '';
|
||||||
|
const text = urlParams.get('text') || '';
|
||||||
|
const url = urlParams.get('url') || '';
|
||||||
|
let shareTargetText;
|
||||||
|
|
||||||
let shareTargetText = title ? title : '';
|
if (url) {
|
||||||
shareTargetText += text ? shareTargetText ? ' ' + text : text : '';
|
shareTargetText = url; // We share only the Link - no text. Because link-only text becomes clickable.
|
||||||
|
} else if (title && text) {
|
||||||
|
shareTargetText = title + '\r\n' + text;
|
||||||
|
} else {
|
||||||
|
shareTargetText = title + text;
|
||||||
|
}
|
||||||
|
|
||||||
if(url) shareTargetText = url; // We share only the Link - no text. Because link-only text becomes clickable.
|
|
||||||
|
|
||||||
if (!shareTargetText) return;
|
|
||||||
window.shareTargetText = shareTargetText;
|
|
||||||
history.pushState({}, 'URL Rewrite', '/');
|
|
||||||
console.log('Shared Target Text:', '"' + shareTargetText + '"');
|
console.log('Shared Target Text:', '"' + shareTargetText + '"');
|
||||||
|
Events.fire('activate-paste-mode', {files: [], text: shareTargetText})
|
||||||
|
} else if (share_target_type === "files") {
|
||||||
|
caches.match("share_target_files")
|
||||||
|
.then(files => {
|
||||||
|
console.debug(files)
|
||||||
|
Events.fire('activate-paste-mode', {files: files, text: ""})
|
||||||
|
})
|
||||||
|
caches.delete("share_target_files").then( _ => console.log("shared files deleted from cache"));
|
||||||
|
}
|
||||||
|
window.history.replaceState({}, "Rewrite URL", '/');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1219,7 +1266,7 @@ class PersistentStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
logBrowserNotCapable() {
|
logBrowserNotCapable() {
|
||||||
console.log("This browser does not support IndexedDB. Paired devices will be gone after closing the browser.");
|
console.log("This browser does not support IndexedDB. Paired devices will be gone after the browser is closed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
static set(key, value) {
|
static set(key, value) {
|
||||||
|
@ -1382,6 +1429,7 @@ class PairDrop {
|
||||||
const receiveTextDialog = new ReceiveTextDialog();
|
const receiveTextDialog = new ReceiveTextDialog();
|
||||||
const pairDeviceDialog = new PairDeviceDialog();
|
const pairDeviceDialog = new PairDeviceDialog();
|
||||||
const clearDevicesDialog = new ClearDevicesDialog();
|
const clearDevicesDialog = new ClearDevicesDialog();
|
||||||
|
const base64ZipDialog = new Base64ZipDialog();
|
||||||
const toast = new Toast();
|
const toast = new Toast();
|
||||||
const notifications = new Notifications();
|
const notifications = new Notifications();
|
||||||
const networkStatusUI = new NetworkStatusUI();
|
const networkStatusUI = new NetworkStatusUI();
|
||||||
|
|
|
@ -27,6 +27,36 @@ self.addEventListener('install', function(event) {
|
||||||
|
|
||||||
|
|
||||||
self.addEventListener('fetch', function(event) {
|
self.addEventListener('fetch', function(event) {
|
||||||
|
if (event.request.method === "POST") {
|
||||||
|
// Requests related to Web Share Target.
|
||||||
|
event.respondWith(
|
||||||
|
(async () => {
|
||||||
|
const formData = await event.request.formData();
|
||||||
|
const title = formData.get("title");
|
||||||
|
const text = formData.get("text");
|
||||||
|
const url = formData.get("url");
|
||||||
|
const files = formData.get("files");
|
||||||
|
console.debug(title)
|
||||||
|
console.debug(text)
|
||||||
|
console.debug(url)
|
||||||
|
console.debug(files)
|
||||||
|
let share_url = "/";
|
||||||
|
if (files.length > 0) {
|
||||||
|
// Save to Cache?
|
||||||
|
caches.open("share_target_files")
|
||||||
|
.then(cache => {
|
||||||
|
cache.addAll(files)
|
||||||
|
console.debug("files added to cache")
|
||||||
|
});
|
||||||
|
share_url = "/?share-target=files";
|
||||||
|
} else if (title.length > 0 || text.length > 0 || url.length) {
|
||||||
|
share_url = `/?share-target=text&title=${title}&text=${text}&url=${url}`;
|
||||||
|
}
|
||||||
|
return Response.redirect(encodeURI(share_url), 303);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Regular requests not related to Web Share Target.
|
||||||
event.respondWith(
|
event.respondWith(
|
||||||
caches.match(event.request)
|
caches.match(event.request)
|
||||||
.then(function (response) {
|
.then(function (response) {
|
||||||
|
@ -38,6 +68,7 @@ self.addEventListener('fetch', function(event) {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -532,10 +532,28 @@ x-dialog .row-reverse {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#base64ZipPasteBtn {
|
||||||
|
width: 100%;
|
||||||
|
height: 40vh;
|
||||||
|
border: solid 12px #438cff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#base64ZipDialog button {
|
||||||
|
margin: auto;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#base64ZipDialog button[close] {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
#base64ZipDialog button[close]:before {
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Button */
|
/* Button */
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
padding: 0 16px;
|
padding: 2px 16px 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
min-height: 36px;
|
min-height: 36px;
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue