[#2246] added drop files support for the file field
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
|
||||
let fileInput;
|
||||
let filesListElem;
|
||||
let isDragOver = false;
|
||||
|
||||
// normalize uploadedFiles type
|
||||
$: if (!Array.isArray(uploadedFiles)) {
|
||||
@@ -68,104 +69,143 @@
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function dropHandler(e) {
|
||||
e.preventDefault();
|
||||
|
||||
isDragOver = false;
|
||||
|
||||
const files = e.dataTransfer?.files || [];
|
||||
|
||||
if (maxReached || !files.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const file of files) {
|
||||
const currentTotal = valueAsArray.length + uploadedFiles.length - deletedFileIndexes.length;
|
||||
|
||||
if (field.options?.maxSelect <= currentTotal) {
|
||||
break;
|
||||
}
|
||||
|
||||
uploadedFiles.push(file);
|
||||
}
|
||||
|
||||
uploadedFiles = uploadedFiles;
|
||||
}
|
||||
</script>
|
||||
|
||||
<Field
|
||||
class="form-field form-field-list form-field-file {field.required ? 'required' : ''}"
|
||||
name={field.name}
|
||||
let:uniqueId
|
||||
<div
|
||||
class="block"
|
||||
on:dragover|preventDefault={() => {
|
||||
isDragOver = true;
|
||||
}}
|
||||
on:dragleave={() => {
|
||||
isDragOver = false;
|
||||
}}
|
||||
on:drop={dropHandler}
|
||||
>
|
||||
<label for={uniqueId}>
|
||||
<i class={CommonHelper.getFieldTypeIcon(field.type)} />
|
||||
<span class="txt">{field.name}</span>
|
||||
</label>
|
||||
<Field
|
||||
class="
|
||||
form-field form-field-list form-field-file
|
||||
{field.required ? 'required' : ''}
|
||||
{isDragOver ? 'dragover' : ''}
|
||||
"
|
||||
name={field.name}
|
||||
let:uniqueId
|
||||
>
|
||||
<label for={uniqueId}>
|
||||
<i class={CommonHelper.getFieldTypeIcon(field.type)} />
|
||||
<span class="txt">{field.name}</span>
|
||||
</label>
|
||||
|
||||
<div bind:this={filesListElem} class="list">
|
||||
{#each valueAsArray as filename, i (filename + record.id)}
|
||||
{@const isDeleted = deletedFileIndexes.includes(i)}
|
||||
<div class="list-item">
|
||||
<div class:fade={deletedFileIndexes.includes(i)}>
|
||||
<RecordFileThumb {record} {filename} />
|
||||
<div bind:this={filesListElem} class="list">
|
||||
{#each valueAsArray as filename, i (filename + record.id)}
|
||||
{@const isDeleted = deletedFileIndexes.includes(i)}
|
||||
<div class="list-item">
|
||||
<div class:fade={deletedFileIndexes.includes(i)}>
|
||||
<RecordFileThumb {record} {filename} />
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<a
|
||||
href={ApiClient.files.getUrl(record, filename)}
|
||||
class="txt-ellipsis {isDeleted ? 'txt-strikethrough txt-hint' : 'link-primary'}"
|
||||
title="Download"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{filename}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
{#if deletedFileIndexes.includes(i)}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-danger btn-transparent"
|
||||
on:click={() => restoreExistingFile(i)}
|
||||
>
|
||||
<span class="txt">Restore</span>
|
||||
</button>
|
||||
{:else}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-transparent btn-hint btn-sm btn-circle btn-remove"
|
||||
use:tooltip={"Remove file"}
|
||||
on:click={() => removeExistingFile(i)}
|
||||
>
|
||||
<i class="ri-close-line" />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<div class="content">
|
||||
<a
|
||||
href={ApiClient.files.getUrl(record, filename)}
|
||||
class="txt-ellipsis {isDeleted ? 'txt-strikethrough txt-hint' : 'link-primary'}"
|
||||
title="Download"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
{#each uploadedFiles as file, i}
|
||||
<div class="list-item">
|
||||
<figure class="thumb">
|
||||
<UploadedFilePreview {file} />
|
||||
</figure>
|
||||
<div class="filename m-r-auto" title={file.name}>
|
||||
<small class="label label-success m-r-5">New</small>
|
||||
<span class="txt">{file.name}</span>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-transparent btn-hint btn-sm btn-circle btn-remove"
|
||||
use:tooltip={"Remove file"}
|
||||
on:click={() => removeNewFile(i)}
|
||||
>
|
||||
{filename}
|
||||
</a>
|
||||
<i class="ri-close-line" />
|
||||
</button>
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<div class="actions">
|
||||
{#if deletedFileIndexes.includes(i)}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-danger btn-transparent"
|
||||
on:click={() => restoreExistingFile(i)}
|
||||
>
|
||||
<span class="txt">Restore</span>
|
||||
</button>
|
||||
{:else}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-transparent btn-hint btn-sm btn-circle btn-remove"
|
||||
use:tooltip={"Remove file"}
|
||||
on:click={() => removeExistingFile(i)}
|
||||
>
|
||||
<i class="ri-close-line" />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
{#each uploadedFiles as file, i}
|
||||
<div class="list-item">
|
||||
<figure class="thumb">
|
||||
<UploadedFilePreview {file} />
|
||||
</figure>
|
||||
<div class="filename m-r-auto" title={file.name}>
|
||||
<small class="label label-success m-r-5">New</small>
|
||||
<span class="txt">{file.name}</span>
|
||||
</div>
|
||||
<div class="list-item list-item-btn">
|
||||
<input
|
||||
bind:this={fileInput}
|
||||
type="file"
|
||||
class="hidden"
|
||||
multiple={isMultiple}
|
||||
on:change={() => {
|
||||
for (let file of fileInput.files) {
|
||||
uploadedFiles.push(file);
|
||||
}
|
||||
uploadedFiles = uploadedFiles;
|
||||
fileInput.value = null; // reset
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-transparent btn-sm btn-circle btn-remove"
|
||||
use:tooltip={"Remove file"}
|
||||
on:click={() => removeNewFile(i)}
|
||||
class="btn btn-transparent btn-sm btn-block"
|
||||
disabled={maxReached}
|
||||
on:click={() => fileInput?.click()}
|
||||
>
|
||||
<i class="ri-close-line" />
|
||||
<i class="ri-upload-cloud-line" />
|
||||
<span class="txt">Upload new file</span>
|
||||
</button>
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<div class="list-item list-item-btn">
|
||||
<input
|
||||
bind:this={fileInput}
|
||||
type="file"
|
||||
class="hidden"
|
||||
multiple={isMultiple}
|
||||
on:change={() => {
|
||||
for (let file of fileInput.files) {
|
||||
uploadedFiles.push(file);
|
||||
}
|
||||
uploadedFiles = uploadedFiles;
|
||||
fileInput.value = null; // reset
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-transparent btn-sm btn-block"
|
||||
disabled={maxReached}
|
||||
on:click={() => fileInput?.click()}
|
||||
>
|
||||
<i class="ri-upload-cloud-line" />
|
||||
<span class="txt">Upload new file</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Field>
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user