Centralize drag-and-drop upload code
This commit is contained in:
@@ -7,14 +7,14 @@ import Breadcrumbs from './Breadcrumbs.svelte';
|
|||||||
import DetailsWindow from './DetailsWindow.svelte';
|
import DetailsWindow from './DetailsWindow.svelte';
|
||||||
import FilePreview from './viewers/FilePreview.svelte';
|
import FilePreview from './viewers/FilePreview.svelte';
|
||||||
import SearchView from './SearchView.svelte';
|
import SearchView from './SearchView.svelte';
|
||||||
import UploadWidget from './upload_widget/UploadWidget.svelte';
|
import FSUploadWidget from './upload_widget/FSUploadWidget.svelte';
|
||||||
import { fs_path_url } from './FilesystemAPI';
|
import { fs_path_url } from './FilesystemAPI';
|
||||||
import { branding_from_path } from './edit_window/Branding.js'
|
|
||||||
import Menu from './Menu.svelte';
|
import Menu from './Menu.svelte';
|
||||||
import { FSNavigator } from "./FSNavigator"
|
import { FSNavigator } from "./FSNavigator"
|
||||||
import { writable } from 'svelte/store';
|
import { writable } from 'svelte/store';
|
||||||
import TransferLimit from '../file_viewer/TransferLimit.svelte';
|
import TransferLimit from '../file_viewer/TransferLimit.svelte';
|
||||||
import { stats } from "src/util/StatsSocket.js"
|
import { stats } from "src/util/StatsSocket.js"
|
||||||
|
import { css_from_path } from './edit_window/Branding';
|
||||||
|
|
||||||
let file_viewer
|
let file_viewer
|
||||||
let file_preview
|
let file_preview
|
||||||
@@ -41,7 +41,7 @@ onMount(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Custom CSS rules for the whole viewer
|
// Custom CSS rules for the whole viewer
|
||||||
document.documentElement.style = branding_from_path(nav.path)
|
document.documentElement.style = css_from_path(nav.path)
|
||||||
|
|
||||||
loading.set(false)
|
loading.set(false)
|
||||||
})
|
})
|
||||||
@@ -169,10 +169,10 @@ const search = async () => {
|
|||||||
<FilePreview
|
<FilePreview
|
||||||
bind:this={file_preview}
|
bind:this={file_preview}
|
||||||
nav={nav}
|
nav={nav}
|
||||||
|
upload_widget={upload_widget}
|
||||||
edit_window={edit_window}
|
edit_window={edit_window}
|
||||||
on:open_sibling={e => nav.open_sibling(e.detail)}
|
on:open_sibling={e => nav.open_sibling(e.detail)}
|
||||||
on:download={download}
|
on:download={download}
|
||||||
on:upload_picker={() => upload_widget.pick_files()}
|
|
||||||
/>
|
/>
|
||||||
{:else if view === "search"}
|
{:else if view === "search"}
|
||||||
<SearchView nav={nav} on:done={() => {view = "file"}} />
|
<SearchView nav={nav} on:done={() => {view = "file"}} />
|
||||||
@@ -206,7 +206,9 @@ const search = async () => {
|
|||||||
|
|
||||||
<EditWindow nav={nav} bind:this={edit_window} bind:visible={edit_visible} />
|
<EditWindow nav={nav} bind:this={edit_window} bind:visible={edit_visible} />
|
||||||
|
|
||||||
<UploadWidget nav={nav} bind:this={upload_widget} drop_upload />
|
<!-- This one is included at the highest level so uploads can keep running
|
||||||
|
even when the user navigates to a different directory -->
|
||||||
|
<FSUploadWidget nav={nav} bind:this={upload_widget} />
|
||||||
|
|
||||||
<LoadingIndicator loading={$loading}/>
|
<LoadingIndicator loading={$loading}/>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -10,7 +10,7 @@ export const branding_from_path = path => {
|
|||||||
add_styles(style, node.properties)
|
add_styles(style, node.properties)
|
||||||
}
|
}
|
||||||
last_generated_style = style
|
last_generated_style = style
|
||||||
return gen_css(style)
|
return style
|
||||||
}
|
}
|
||||||
|
|
||||||
// The last style which was generated is cached, when we don't have a complete
|
// The last style which was generated is cached, when we don't have a complete
|
||||||
@@ -21,6 +21,10 @@ export const branding_from_node = node => {
|
|||||||
return gen_css(last_generated_style)
|
return gen_css(last_generated_style)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const css_from_path = path => {
|
||||||
|
return gen_css(branding_from_path(path))
|
||||||
|
}
|
||||||
|
|
||||||
const gen_css = style => {
|
const gen_css = style => {
|
||||||
return Object.entries(style).map(([key, value]) => `--${key}:${value}`).join(';');
|
return Object.entries(style).map(([key, value]) => `--${key}:${value}`).join(';');
|
||||||
}
|
}
|
||||||
|
@@ -1,15 +1,16 @@
|
|||||||
<script>
|
<script>
|
||||||
import { fs_delete_all, fs_rename } from './../FilesystemAPI.ts'
|
import { fs_delete_all, fs_rename } from './../FilesystemAPI.ts'
|
||||||
import { createEventDispatcher, onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
import CreateDirectory from './CreateDirectory.svelte'
|
import CreateDirectory from './CreateDirectory.svelte'
|
||||||
import ListView from './ListView.svelte'
|
import ListView from './ListView.svelte'
|
||||||
import GalleryView from './GalleryView.svelte'
|
import GalleryView from './GalleryView.svelte'
|
||||||
import Button from '../../layout/Button.svelte';
|
import Button from '../../layout/Button.svelte';
|
||||||
import FileImporter from './FileImporter.svelte';
|
import FileImporter from './FileImporter.svelte';
|
||||||
import { formatDate } from '../../util/Formatting.svelte';
|
import { formatDate } from '../../util/Formatting.svelte';
|
||||||
let dispatch = createEventDispatcher()
|
import { drop_target } from "src/util/DropTarget.ts"
|
||||||
|
|
||||||
export let nav
|
export let nav
|
||||||
|
export let upload_widget
|
||||||
export let edit_window
|
export let edit_window
|
||||||
export let directory_view = ""
|
export let directory_view = ""
|
||||||
let large_icons = false
|
let large_icons = false
|
||||||
@@ -256,7 +257,13 @@ onMount(() => {
|
|||||||
|
|
||||||
<svelte:window on:keydown={detect_shift} on:keyup={detect_shift} />
|
<svelte:window on:keydown={detect_shift} on:keyup={detect_shift} />
|
||||||
|
|
||||||
<div class="container">
|
<div
|
||||||
|
class="container"
|
||||||
|
use:drop_target={{
|
||||||
|
upload: (files) => upload_widget.upload_files(files),
|
||||||
|
shadow: "var(--highlight_color) 0 0 10px 2px inset",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div class="width_container">
|
<div class="width_container">
|
||||||
{#if mode === "viewing"}
|
{#if mode === "viewing"}
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
@@ -296,7 +303,7 @@ onMount(() => {
|
|||||||
|
|
||||||
<div class="toolbar_spacer"></div>
|
<div class="toolbar_spacer"></div>
|
||||||
{#if $nav.permissions.update}
|
{#if $nav.permissions.update}
|
||||||
<button on:click={() => dispatch("upload_picker")} title="Upload files to this directory">
|
<button on:click={() => upload_widget.pick_files()} title="Upload files to this directory">
|
||||||
<i class="icon">cloud_upload</i>
|
<i class="icon">cloud_upload</i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
@@ -1,105 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { createEventDispatcher } from "svelte";
|
|
||||||
import { fade } from "svelte/transition";
|
|
||||||
|
|
||||||
let dispatch = createEventDispatcher()
|
|
||||||
let dragging = false
|
|
||||||
|
|
||||||
const paste = (e) => {
|
|
||||||
if (e.clipboardData.files.length !== 0) {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
dispatch("upload", e.clipboardData.files)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const can_upload = e => {
|
|
||||||
if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < e.dataTransfer.items.length; i++) {
|
|
||||||
if (e.dataTransfer.items[i].kind === "file") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const dragover = e => {
|
|
||||||
if (can_upload(e)) {
|
|
||||||
e.stopPropagation();
|
|
||||||
e.preventDefault();
|
|
||||||
dragging = true
|
|
||||||
console.log(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const dragleave = e => {
|
|
||||||
dragging = false
|
|
||||||
}
|
|
||||||
const drop = async e => {
|
|
||||||
dragging = false;
|
|
||||||
|
|
||||||
if (can_upload(e)) {
|
|
||||||
e.stopPropagation();
|
|
||||||
e.preventDefault();
|
|
||||||
} else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// if directory support is available
|
|
||||||
if(e.dataTransfer && e.dataTransfer.items && e.dataTransfer.items.length > 0) {
|
|
||||||
for (let i = 0; i < e.dataTransfer.items.length; i++) {
|
|
||||||
let entry = await e.dataTransfer.items[i].webkitGetAsEntry();
|
|
||||||
if (entry) {
|
|
||||||
read_dir_recursive(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files.length > 0) {
|
|
||||||
dispatch("upload_files", e.dataTransfer.files)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const read_dir_recursive = item => {
|
|
||||||
if (item.isDirectory) {
|
|
||||||
item.createReader().readEntries(entries => {
|
|
||||||
entries.forEach(entry => {
|
|
||||||
read_dir_recursive(entry);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
item.file(file => {
|
|
||||||
dispatch("upload_file", file)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<svelte:window
|
|
||||||
on:dragover={dragover}
|
|
||||||
on:dragenter={dragover}
|
|
||||||
on:dragleave={dragleave}
|
|
||||||
on:drop={drop}
|
|
||||||
on:paste={paste}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{#if dragging}
|
|
||||||
<div class="drag_target" transition:fade={{duration: 200}}>
|
|
||||||
Drop files here to upload them
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.drag_target {
|
|
||||||
position: fixed;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
padding: 50px;
|
|
||||||
font-size: 2em;
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
border-radius: 100px;
|
|
||||||
box-shadow: 0 0 10px 10px rgba(0, 0, 0, 0.5);
|
|
||||||
}
|
|
||||||
</style>
|
|
@@ -1,7 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { tick } from "svelte";
|
import { tick } from "svelte";
|
||||||
import { fade } from "svelte/transition";
|
import { fade } from "svelte/transition";
|
||||||
import DropUpload from "./DropUpload.svelte";
|
|
||||||
import UploadProgress from "./UploadProgress.svelte";
|
import UploadProgress from "./UploadProgress.svelte";
|
||||||
|
|
||||||
export let nav
|
export let nav
|
||||||
@@ -18,7 +17,6 @@ export const pick_files = () => {
|
|||||||
file_input_field.click()
|
file_input_field.click()
|
||||||
}
|
}
|
||||||
|
|
||||||
export let drop_upload = false
|
|
||||||
let visible = false
|
let visible = false
|
||||||
let upload_queue = [];
|
let upload_queue = [];
|
||||||
let task_id_counter = 0
|
let task_id_counter = 0
|
||||||
@@ -161,10 +159,6 @@ const leave_confirmation = (e) => {
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if drop_upload}
|
|
||||||
<DropUpload on:upload_files={e => upload_files(e.detail)} on:upload_file={e => upload_file(e.detail)}/>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.upload_input {
|
.upload_input {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
@@ -78,15 +78,19 @@ const cancel = () => {
|
|||||||
.prog {
|
.prog {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.bar {
|
.bar {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
padding: 2px 4px 1px 4px;
|
padding: 2px 4px 1px 4px;
|
||||||
margin: 4px;
|
margin: 4px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
line-break: anywhere;
|
||||||
}
|
}
|
||||||
.cancel {
|
.cancel {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 content;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center; /* Stop stretching the button */
|
align-items: center; /* Stop stretching the button */
|
||||||
|
@@ -16,6 +16,7 @@ import { stats } from "src/util/StatsSocket.js"
|
|||||||
import SlowDown from "src/layout/SlowDown.svelte";
|
import SlowDown from "src/layout/SlowDown.svelte";
|
||||||
|
|
||||||
export let nav
|
export let nav
|
||||||
|
export let upload_widget
|
||||||
export let edit_window
|
export let edit_window
|
||||||
|
|
||||||
let viewer
|
let viewer
|
||||||
@@ -59,7 +60,7 @@ export const seek = delta => {
|
|||||||
<Spinner></Spinner>
|
<Spinner></Spinner>
|
||||||
</div>
|
</div>
|
||||||
{:else if viewer_type === "dir"}
|
{:else if viewer_type === "dir"}
|
||||||
<FileManager nav={nav} edit_window={edit_window} on:upload_picker>
|
<FileManager nav={nav} upload_widget={upload_widget} edit_window={edit_window}>
|
||||||
<CustomBanner path={$nav.path}/>
|
<CustomBanner path={$nav.path}/>
|
||||||
</FileManager>
|
</FileManager>
|
||||||
{:else if $nav.context.premium_transfer === false && $stats.limits.transfer_limit_used > $stats.limits.transfer_limit}
|
{:else if $nav.context.premium_transfer === false && $stats.limits.transfer_limit_used > $stats.limits.transfer_limit}
|
||||||
|
@@ -2,16 +2,26 @@
|
|||||||
import Login from "../login/Login.svelte";
|
import Login from "../login/Login.svelte";
|
||||||
import Register from "../login/Register.svelte";
|
import Register from "../login/Register.svelte";
|
||||||
import UploadWidget from "./UploadWidget.svelte";
|
import UploadWidget from "./UploadWidget.svelte";
|
||||||
|
import { drop_target } from "src/util/DropTarget.ts"
|
||||||
|
|
||||||
const finish_login = async e => {
|
const finish_login = async e => {
|
||||||
location.reload()
|
location.reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let upload_widget
|
||||||
let page = "login"
|
let page = "login"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if window.user && window.user.username && window.user.username !== ""}
|
{#if window.user && window.user.username && window.user.username !== ""}
|
||||||
<UploadWidget/>
|
<div
|
||||||
|
class="drop_target"
|
||||||
|
use:drop_target={{
|
||||||
|
upload: (files) => upload_widget.upload_files(files),
|
||||||
|
shadow: "var(--highlight_color) 0 0 10px 2px inset",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<UploadWidget bind:this={upload_widget}/>
|
||||||
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<section>
|
<section>
|
||||||
<p>
|
<p>
|
||||||
@@ -51,6 +61,9 @@ let page = "login"
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.drop_target {
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
.tab_bar > button {
|
.tab_bar > button {
|
||||||
width: 40%;
|
width: 40%;
|
||||||
max-width: 10em;
|
max-width: 10em;
|
||||||
|
@@ -21,15 +21,6 @@ const file_input_change = (event) => {
|
|||||||
// This resets the file input field
|
// This resets the file input field
|
||||||
file_input_field.nodeValue = ""
|
file_input_field.nodeValue = ""
|
||||||
}
|
}
|
||||||
let dragging = false
|
|
||||||
const drop = (e) => {
|
|
||||||
dragging = false;
|
|
||||||
if (e.dataTransfer && e.dataTransfer.items.length > 0) {
|
|
||||||
e.preventDefault()
|
|
||||||
e.stopPropagation()
|
|
||||||
upload_files(e.dataTransfer.files)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const paste = (e) => {
|
const paste = (e) => {
|
||||||
if (e.clipboardData.files[0]) {
|
if (e.clipboardData.files[0]) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -43,7 +34,7 @@ let upload_queue = []
|
|||||||
let state = "idle" // idle, uploading, finished
|
let state = "idle" // idle, uploading, finished
|
||||||
let upload_stats
|
let upload_stats
|
||||||
|
|
||||||
const upload_files = async (files) => {
|
export const upload_files = async (files) => {
|
||||||
if (files.length === 0) {
|
if (files.length === 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -279,14 +270,7 @@ const keydown = (e) => {
|
|||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window
|
<svelte:window on:paste={paste} on:keydown={keydown} on:beforeunload={leave_confirmation} />
|
||||||
on:dragover|preventDefault|stopPropagation={() => { dragging = true }}
|
|
||||||
on:dragenter|preventDefault|stopPropagation={() => { dragging = true }}
|
|
||||||
on:dragleave|preventDefault|stopPropagation={() => { dragging = false }}
|
|
||||||
on:drop={drop}
|
|
||||||
on:paste={paste}
|
|
||||||
on:keydown={keydown}
|
|
||||||
on:beforeunload={leave_confirmation} />
|
|
||||||
|
|
||||||
<Konami/>
|
<Konami/>
|
||||||
|
|
||||||
@@ -327,11 +311,6 @@ const keydown = (e) => {
|
|||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<UploadStats bind:this={upload_stats} upload_queue={upload_queue}/>
|
<UploadStats bind:this={upload_stats} upload_queue={upload_queue}/>
|
||||||
|
|
||||||
<div id="file_drop_highlight" class="highlight_green" class:hide={!dragging}>
|
|
||||||
Gimme gimme gimme!<br/>
|
|
||||||
Drop your files to upload them
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{#each upload_queue as file}
|
{#each upload_queue as file}
|
||||||
|
@@ -4,7 +4,8 @@ import { FSNavigator } from "src/filesystem/FSNavigator.ts"
|
|||||||
import { fs_encode_path, fs_node_icon } from "src/filesystem/FilesystemAPI.ts";
|
import { fs_encode_path, fs_node_icon } from "src/filesystem/FilesystemAPI.ts";
|
||||||
import Button from "src/layout/Button.svelte";
|
import Button from "src/layout/Button.svelte";
|
||||||
import CreateDirectory from "src/filesystem/filemanager/CreateDirectory.svelte";
|
import CreateDirectory from "src/filesystem/filemanager/CreateDirectory.svelte";
|
||||||
import UploadWidget from "src/filesystem/upload_widget/UploadWidget.svelte";
|
import FSUploadWidget from "src/filesystem/upload_widget/FSUploadWidget.svelte";
|
||||||
|
import { drop_target } from "src/util/DropTarget.ts"
|
||||||
|
|
||||||
const nav = new FSNavigator(false)
|
const nav = new FSNavigator(false)
|
||||||
let upload_widget
|
let upload_widget
|
||||||
@@ -14,6 +15,7 @@ var creating_dir = false
|
|||||||
onMount(() => nav.navigate("/me", false))
|
onMount(() => nav.navigate("/me", false))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<div class="wrapper" use:drop_target={{upload: (files) => upload_widget.upload_files(files)}}>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
{#if $nav.permissions.update}
|
{#if $nav.permissions.update}
|
||||||
<Button
|
<Button
|
||||||
@@ -72,10 +74,14 @@ onMount(() => nav.navigate("/me", false))
|
|||||||
</a>
|
</a>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<UploadWidget nav={nav} bind:this={upload_widget} drop_upload />
|
<FSUploadWidget nav={nav} bind:this={upload_widget} />
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.wrapper {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
.toolbar {
|
.toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@@ -1,9 +1,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import UploadLib from "./UploadLib.svelte";
|
import UploadLib from "./UploadLib.svelte";
|
||||||
|
import { drop_target } from "src/util/DropTarget.ts"
|
||||||
|
|
||||||
let upload_widget
|
let upload_widget
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<div class="wrapper" use:drop_target={{upload: (files) => upload_widget.upload_files(files)}}>
|
||||||
<div class="upload_buttons">
|
<div class="upload_buttons">
|
||||||
<button on:click={() => upload_widget.pick_files() } class="big_button button_highlight">
|
<button on:click={() => upload_widget.pick_files() } class="big_button button_highlight">
|
||||||
<i class="icon small">cloud_upload</i>
|
<i class="icon small">cloud_upload</i>
|
||||||
@@ -18,8 +20,12 @@ let upload_widget
|
|||||||
<div class="center">
|
<div class="center">
|
||||||
<UploadLib bind:this={upload_widget}/>
|
<UploadLib bind:this={upload_widget}/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.wrapper {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
.center {
|
.center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
@@ -17,15 +17,6 @@ const file_input_change = (event) => {
|
|||||||
// This resets the file input field
|
// This resets the file input field
|
||||||
file_input_field.nodeValue = ""
|
file_input_field.nodeValue = ""
|
||||||
}
|
}
|
||||||
let dragging = false
|
|
||||||
const drop = (e) => {
|
|
||||||
dragging = false;
|
|
||||||
if (e.dataTransfer && e.dataTransfer.items.length > 0) {
|
|
||||||
e.preventDefault()
|
|
||||||
e.stopPropagation()
|
|
||||||
upload_files(e.dataTransfer.files)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const paste = (e) => {
|
const paste = (e) => {
|
||||||
if (e.clipboardData.files[0]) {
|
if (e.clipboardData.files[0]) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -39,7 +30,7 @@ let upload_queue = []
|
|||||||
let state = "idle" // idle, uploading, finished
|
let state = "idle" // idle, uploading, finished
|
||||||
let upload_stats
|
let upload_stats
|
||||||
|
|
||||||
const upload_files = async (files) => {
|
export const upload_files = async (files) => {
|
||||||
if (files.length === 0) {
|
if (files.length === 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -88,7 +79,6 @@ const start_upload = () => {
|
|||||||
if (active_uploads === 0 && finished_count != 0) {
|
if (active_uploads === 0 && finished_count != 0) {
|
||||||
state = "finished"
|
state = "finished"
|
||||||
upload_stats.finish()
|
upload_stats.finish()
|
||||||
// uploads_finished()
|
|
||||||
} else {
|
} else {
|
||||||
state = "uploading"
|
state = "uploading"
|
||||||
upload_stats.start()
|
upload_stats.start()
|
||||||
@@ -180,17 +170,9 @@ const keydown = (e) => {
|
|||||||
case "m": share_tumblr(); break
|
case "m": share_tumblr(); break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window
|
<svelte:window on:paste={paste} on:keydown={keydown} on:beforeunload={leave_confirmation} />
|
||||||
on:dragover|preventDefault|stopPropagation={() => { dragging = true }}
|
|
||||||
on:dragenter|preventDefault|stopPropagation={() => { dragging = true }}
|
|
||||||
on:dragleave|preventDefault|stopPropagation={() => { dragging = false }}
|
|
||||||
on:drop={drop}
|
|
||||||
on:paste={paste}
|
|
||||||
on:keydown={keydown}
|
|
||||||
on:beforeunload={leave_confirmation} />
|
|
||||||
|
|
||||||
<input bind:this={file_input_field} on:change={file_input_change} type="file" name="file" multiple="multiple" class="hide"/>
|
<input bind:this={file_input_field} on:change={file_input_change} type="file" name="file" multiple="multiple" class="hide"/>
|
||||||
|
|
||||||
@@ -209,10 +191,6 @@ const keydown = (e) => {
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div id="file_drop_highlight" class="highlight_green" class:hide={!dragging}>
|
|
||||||
Drop your files to upload them
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#each upload_queue as file}
|
{#each upload_queue as file}
|
||||||
<UploadProgressBar bind:this={file.component} job={file}></UploadProgressBar>
|
<UploadProgressBar bind:this={file.component} job={file}></UploadProgressBar>
|
||||||
{/each}
|
{/each}
|
||||||
|
95
svelte/src/util/DropTarget.ts
Normal file
95
svelte/src/util/DropTarget.ts
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
export const drop_target = (
|
||||||
|
node: HTMLElement,
|
||||||
|
args: {
|
||||||
|
upload: (files: File[]) => void,
|
||||||
|
shadow: string | undefined,
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
const can_upload = (e: DragEvent) => {
|
||||||
|
// Check for files
|
||||||
|
if (
|
||||||
|
e.dataTransfer &&
|
||||||
|
e.dataTransfer.files &&
|
||||||
|
e.dataTransfer.files.length > 0
|
||||||
|
) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.dataTransfer && e.dataTransfer.items) {
|
||||||
|
for (let i = 0; i < e.dataTransfer.items.length; i++) {
|
||||||
|
if (e.dataTransfer.items[i].kind === "file") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const dragover = (e: DragEvent) => {
|
||||||
|
if (can_upload(e)) {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
if (args.shadow === undefined) {
|
||||||
|
node.style.boxShadow = "var(--highlight_color) 0 0 2px 2px"
|
||||||
|
} else {
|
||||||
|
node.style.boxShadow = args.shadow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const dragleave = (e: DragEvent) => {
|
||||||
|
node.style.boxShadow = ""
|
||||||
|
}
|
||||||
|
const drop = async (e: DragEvent) => {
|
||||||
|
node.style.boxShadow = ""
|
||||||
|
|
||||||
|
if (can_upload(e)) {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// if directory support is available
|
||||||
|
if (e.dataTransfer && e.dataTransfer.items && e.dataTransfer.items.length > 0) {
|
||||||
|
for (let i = 0; i < e.dataTransfer.items.length; i++) {
|
||||||
|
const entry: FileSystemEntry | null = e.dataTransfer.items[i].webkitGetAsEntry();
|
||||||
|
if (entry !== null) {
|
||||||
|
read_dir_recursive(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files.length > 0) {
|
||||||
|
const files: File[] = []
|
||||||
|
for (let i = 0; i < e.dataTransfer.files.length; i++) {
|
||||||
|
files.push(e.dataTransfer.files[i])
|
||||||
|
}
|
||||||
|
args.upload(files)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const read_dir_recursive = (item: FileSystemEntry) => {
|
||||||
|
if (item.isDirectory) {
|
||||||
|
(item as FileSystemDirectoryEntry).createReader().readEntries(entries => {
|
||||||
|
entries.forEach(entry => {
|
||||||
|
read_dir_recursive(entry);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
(item as FileSystemFileEntry).file(file => {
|
||||||
|
args.upload([file])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node.addEventListener("dragover", dragover)
|
||||||
|
node.addEventListener("dragenter", dragover)
|
||||||
|
node.addEventListener("dragleave", dragleave)
|
||||||
|
node.addEventListener("drop", drop)
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy() {
|
||||||
|
node.removeEventListener("dragover", dragover)
|
||||||
|
node.removeEventListener("dragenter", dragover)
|
||||||
|
node.removeEventListener("dragleave", dragleave)
|
||||||
|
node.removeEventListener("drop", drop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user