feat: Enhance dataset management and improve frontend components
Some checks failed
CI Pipeline / japa-tests (push) Failing after 1m0s
Some checks failed
CI Pipeline / japa-tests (push) Failing after 1m0s
- Added preloads 'allowed_extensions_mimetypes' and 'dependent_array_min_length' in adonisrc.ts - Updated @symfony/webpack-encore from ^4.6.1 to ^5.0.1 - AdminuserController: Implemented pagination for 10 records in index method - Enabled reviewers to reject datasets to editors with email notifications (DatasetController.ts) - Submitter DatasetController: Files now loaded in ascending order (sort_order) in edit mode - file.ts: Removed serialization of fileData due to browser issues - Modified FileUpload.vue to mark already uploaded files as deleted - Improved keyword search in SearchCategoryAutocomplete.vue - Started development on Category.vue for submitters to categorize DDC - Added new route /dataset/categorize in routes.ts - Introduced 2 new rules in start/rules: allowed_extensions_mimetypes.ts and dependent_array_min_length.ts - Performed npm updates
This commit is contained in:
parent
49bd96ee77
commit
f67b736a88
23 changed files with 2392 additions and 2759 deletions
|
@ -3,10 +3,6 @@
|
|||
class="relative h-full flex flex-col bg-white dark:bg-slate-900/70 shadow-xl rounded-md"
|
||||
v-on:dragenter="dragEnterHandler" v-on:dragleave="dragLeaveHandler" v-on:dragover="dragOverHandler"
|
||||
v-on:drop="dropHandler">
|
||||
<!-- ondrop="dropHandler(event);"
|
||||
ondragover="dragOverHandler(event);"
|
||||
ondragleave="dragLeaveHandler(event);"
|
||||
ondragenter="dragEnterHandler(event);" -->
|
||||
|
||||
<!-- overlay -->
|
||||
<div id="overlay" ref="overlay"
|
||||
|
@ -23,15 +19,6 @@
|
|||
|
||||
<!-- scroll area -->
|
||||
<div class="h-full p-8 w-full h-full flex flex-col">
|
||||
<!-- <header id="dropzone" class="border-dashed border-2 border-gray-400 py-12 flex flex-col justify-center items-center">
|
||||
<p class="mb-3 font-semibold text-gray-900 flex flex-wrap justify-center">
|
||||
<span>Drag and drop your</span> <span>files anywhere or</span>
|
||||
</p>
|
||||
<input id="hidden-input" type="file" multiple class="hidden" />
|
||||
<button id="button" class="mt-2 rounded-sm px-3 py-1 bg-gray-200 hover:bg-gray-300 focus:shadow-outline focus:outline-none">
|
||||
Upload a file
|
||||
</button>
|
||||
</header> -->
|
||||
<header class="flex items-center justify-center w-full">
|
||||
<label for="dropzone-file"
|
||||
class="flex flex-col items-center justify-center w-full h-64 border-2 border-gray-300 border-dashed rounded-lg cursor-pointer bg-gray-50 dark:bg-gray-700 hover:bg-gray-100 dark:border-gray-600 dark:hover:border-gray-500 dark:hover:bg-gray-600">
|
||||
|
@ -47,14 +34,12 @@
|
|||
</p>
|
||||
<!-- <p class="text-xs text-gray-500 dark:text-gray-400">SVG, PNG, JPG or GIF (MAX. 800x400px)</p> -->
|
||||
</div>
|
||||
<input id="dropzone-file" type="file" class="hidden" @change="onChangeFile" multiple="true"/>
|
||||
<input id="dropzone-file" type="file" class="hidden" @change="onChangeFile" multiple="true" />
|
||||
</label>
|
||||
</header>
|
||||
|
||||
<h1 class="pt-8 pb-3 font-semibold sm:text-lg text-gray-900">To Upload</h1>
|
||||
|
||||
<!-- <ul id="gallery" class="flex flex-1 flex-wrap -m-1"> -->
|
||||
|
||||
<draggable id="galleryxy" tag="ul" class="flex flex-1 flex-wrap -m-1" v-model="items" item-key="sort_order">
|
||||
<!-- <li
|
||||
v-if="files.length == 0"
|
||||
|
@ -86,52 +71,44 @@
|
|||
</li> -->
|
||||
<template #item="{ index, element }">
|
||||
<li class="block p-1 w-1/2 sm:w-1/3 md:w-1/4 lg:w-1/6 xl:w-1/8 h-24" :key="index">
|
||||
<article v-if="element.type.match('image.*')" tabindex="0"
|
||||
class="bg-gray-50 group hasImage w-full h-full rounded-md cursor-pointer relative text-transparent hover:text-white shadow-sm">
|
||||
<!-- :src="element.fileSrc" :src="generateURL(element)" -->
|
||||
<img :alt="element.name" :src="element.fileSrc"
|
||||
class="img-preview w-full h-full sticky object-cover rounded-md bg-fixed opacity-75" />
|
||||
<!-- <section
|
||||
class="hasError text-red-500 shadow-sm font-semibold flex flex-row rounded-md text-xs break-words w-full h-full z-21 absolute top-0 py-2 px-3"
|
||||
>
|
||||
<p class="p-1 text-xs" v-if="errors[`files.${index}`]">
|
||||
{{ errors[`files.${index}`].join(', ') }}
|
||||
</p>
|
||||
<button
|
||||
class="delete ml-auto focus:outline-none hover:bg-gray-300 p-1 rounded-md"
|
||||
@click="removeFile(index)"
|
||||
>
|
||||
<DeleteIcon></DeleteIcon>
|
||||
</button>
|
||||
</section> -->
|
||||
<section
|
||||
class="flex flex-col rounded-md text-xs break-words w-full h-full z-20 absolute top-0 py-2 px-3">
|
||||
<!-- :src="element.fileSrc" :src="generateURL(element)" -->
|
||||
<!-- <article
|
||||
v-if="element.type.match('image.*')"
|
||||
tabindex="0"
|
||||
class="bg-gray-50 group hasImage w-full h-full rounded-md cursor-pointer relative text-transparent hover:text-white shadow-sm"
|
||||
>
|
||||
|
||||
<img
|
||||
:alt="element.name"
|
||||
:src="element.fileSrc"
|
||||
class="img-preview w-full h-full sticky object-cover rounded-md bg-fixed opacity-75"
|
||||
/>
|
||||
<section class="flex flex-col rounded-md text-xs break-words w-full h-full z-20 absolute top-0 py-2 px-3">
|
||||
<h1 class="flex-1">{{ element.name }}</h1>
|
||||
<div class="flex">
|
||||
<p class="p-1 size text-xs">{{ getFileSize(element) }}</p>
|
||||
<p class="p-1 size text-xs text-gray-700">{{ element.sort_order }}</p>
|
||||
<button class="delete ml-auto focus:outline-none hover:bg-gray-300 p-1 rounded-md"
|
||||
@click="removeFile(index)">
|
||||
<button
|
||||
class="delete ml-auto focus:outline-none hover:bg-gray-300 p-1 rounded-md"
|
||||
@click.prevent="removeFile(index)"
|
||||
>
|
||||
<DeleteIcon></DeleteIcon>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
<!-- <div class="text-red-400 text-sm w-full h-full rounded-md cursor-pointer relative shadow-sm" v-if="errors[`files.${index}`]">
|
||||
{{ errors[`files.${index}`].join(', ') }}
|
||||
</div> -->
|
||||
</article>
|
||||
</section>
|
||||
</article> -->
|
||||
<!-- :class="errors && errors[`files.${index}`] ? 'bg-red-400' : 'bg-gray-100'" -->
|
||||
<article v-else tabindex="0"
|
||||
<article tabindex="0"
|
||||
class="bg-gray-100 group w-full h-full rounded-md cursor-pointer relative shadow-sm">
|
||||
<section
|
||||
class="flex flex-col rounded-md text-xs break-words w-full h-full z-20 absolute top-0 py-2 px-3">
|
||||
<h1 class="flex-1 text-gray-700 group-hover:text-blue-800">{{ element.name }}</h1>
|
||||
<div class="flex">
|
||||
<p class="p-1 size text-xs text-gray-700">{{ getFileSize(element) }}</p>
|
||||
<p class="p-1 size text-xs text-gray-700">{{ element.sort_order }}</p>
|
||||
<p class="p-1 size text-xs text-gray-700">sort: {{ element.sort_order }}</p>
|
||||
<button
|
||||
class="delete ml-auto focus:outline-none hover:bg-gray-300 p-1 rounded-md text-gray-800"
|
||||
@click="removeFile(index)">
|
||||
@click.prevent="removeFile(index)">
|
||||
<DeleteIcon></DeleteIcon>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -142,6 +119,58 @@
|
|||
</draggable>
|
||||
<!-- </ul> -->
|
||||
|
||||
<!--<ul id="deletetFiles"></ul> -->
|
||||
|
||||
<div>
|
||||
<h1 v-if="deletetFiles.length > 0" class="pt-8 pb-3 font-semibold sm:text-lg text-gray-900">Files To
|
||||
Delete</h1>
|
||||
<ul id="deletetFiles" tag="ul" class="flex flex-1 flex-wrap -m-1">
|
||||
<li v-for="(element, index) in deletetFiles" :key="index"
|
||||
class="block p-1 w-1/2 sm:w-1/3 md:w-1/4 lg:w-1/6 xl:w-1/8 h-24">
|
||||
<!-- <article
|
||||
v-if="element.type.match('image.*')"
|
||||
tabindex="0"
|
||||
class="bg-red-50 group hasImage w-full h-full rounded-md cursor-pointer relative text-transparent hover:text-white shadow-sm"
|
||||
>
|
||||
<img
|
||||
:alt="element.name"
|
||||
:src="element.fileSrc"
|
||||
class="img-preview w-full h-full sticky object-cover rounded-md bg-fixed opacity-75"
|
||||
/>
|
||||
<section class="flex flex-col rounded-md text-xs break-words w-full h-full z-20 absolute top-0 py-2 px-3">
|
||||
<h1 class="flex-1">{{ element.name }}</h1>
|
||||
<div class="flex">
|
||||
<p class="p-1 size text-xs">{{ getFileSize(element) }}</p>
|
||||
<p class="p-1 size text-xs text-gray-700">{{ element.sort_order }}</p>
|
||||
<button
|
||||
class="delete ml-auto focus:outline-none hover:bg-gray-300 p-1 rounded-md"
|
||||
@click.prevent="reactivateFile(index)"
|
||||
>
|
||||
<RefreshIcon></RefreshIcon>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</article> -->
|
||||
<article tabindex="0"
|
||||
class="bg-red-100 group w-full h-full rounded-md cursor-pointer relative shadow-sm">
|
||||
<section
|
||||
class="flex flex-col rounded-md text-xs break-words w-full h-full z-20 absolute top-0 py-2 px-3">
|
||||
<h1 class="flex-1 text-gray-700 group-hover:text-blue-800">{{ element.name }}</h1>
|
||||
<div class="flex">
|
||||
<!-- <p class="p-1 size text-xs text-gray-700">{{ getFileSize(element) }}</p> -->
|
||||
<p class="p-1 size text-xs text-gray-700">{{ element.sort_order }}</p>
|
||||
<button
|
||||
class="delete ml-auto focus:outline-none hover:bg-gray-300 p-1 rounded-md text-gray-800"
|
||||
@click.prevent="reactivateFile(index)">
|
||||
<RefreshIcon></RefreshIcon>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div v-if="fileErrors" class="flex flex-col mt-6 animate-fade-in" v-for="fileError in fileErrors">
|
||||
<div class="bg-yellow-500 border-l-4 border-orange-400 text-white p-4" role="alert">
|
||||
<p class="font-bold">Be Warned</p>
|
||||
|
@ -149,21 +178,12 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="text-red-400 text-sm" v-if="errors && Array.isArray(errors['files.0'])">
|
||||
{{ errors['files.0'].join(', ') }}
|
||||
</div> -->
|
||||
<!-- <div v-if="hasErrors">
|
||||
<div class="font-medium text-red-600">Whoops! Something went wrong.</div>
|
||||
|
||||
<ul class="mt-3 list-disc list-inside text-sm text-red-600">
|
||||
<li v-for="(error, key) in errors" :key="key">{{ error }}</li>
|
||||
</ul>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<!-- sticky footer -->
|
||||
<footer class="flex justify-end px-8 pb-8 pt-4">
|
||||
<button id="cancel" class="ml-3 rounded-sm px-3 py-1 hover:bg-gray-300 focus:shadow-outline focus:outline-none"
|
||||
<button id="cancel"
|
||||
class="ml-3 rounded-sm px-3 py-1 hover:bg-gray-300 focus:shadow-outline focus:outline-none"
|
||||
@click="clearAllFiles">
|
||||
Clear
|
||||
</button>
|
||||
|
@ -175,6 +195,7 @@
|
|||
import { Component, Vue, Prop, Ref, Watch } from 'vue-facing-decorator';
|
||||
import { usePage } from '@inertiajs/vue3';
|
||||
import DeleteIcon from '@/Components/Icons/Delete.vue';
|
||||
import RefreshIcon from '@/Components/Icons/Refresh.vue';
|
||||
// import { Page, PageProps, Errors, ErrorBag } from '@inertiajs/inertia';
|
||||
import Draggable from 'vuedraggable';
|
||||
import { Buffer } from 'buffer';
|
||||
|
@ -212,18 +233,11 @@ interface InteriaPage {
|
|||
name: 'file-upload',
|
||||
components: {
|
||||
DeleteIcon,
|
||||
RefreshIcon,
|
||||
Draggable,
|
||||
},
|
||||
})
|
||||
class FileUploadComponent extends Vue {
|
||||
/**
|
||||
* Connect map id.
|
||||
*/
|
||||
// @Prop({
|
||||
// type: Object,
|
||||
// default: () => ({}),
|
||||
// })
|
||||
// errors: IErrorMessage;
|
||||
|
||||
@Ref('overlay') overlay: HTMLDivElement;
|
||||
|
||||
|
@ -236,6 +250,23 @@ class FileUploadComponent extends Vue {
|
|||
})
|
||||
files: Array<TethysFile | File>;
|
||||
|
||||
|
||||
@Prop({
|
||||
type: Array<File>,
|
||||
default: [],
|
||||
})
|
||||
filesToDelete: Array<TethysFile>;
|
||||
|
||||
// // deletetFiles: Array<TethysFile> = [];
|
||||
get deletetFiles(): Array<TethysFile> {
|
||||
return this.filesToDelete;
|
||||
}
|
||||
set deletetFiles(values: Array<TethysFile>) {
|
||||
// this.modelValue = value;
|
||||
this.filesToDelete.length = 0;
|
||||
this.filesToDelete.push(...values);
|
||||
}
|
||||
|
||||
get items(): Array<TethysFile | File> {
|
||||
return this.files;
|
||||
}
|
||||
|
@ -249,10 +280,20 @@ class FileUploadComponent extends Vue {
|
|||
// });
|
||||
}
|
||||
|
||||
@Watch("files", {
|
||||
deep: true //also in case of pushing
|
||||
@Watch('files', {
|
||||
deep: true, //also in case of pushing
|
||||
})
|
||||
public propertyWatcher(newItems: Array<TethysFile>) {
|
||||
public propertyWatcherFiles(newItems: Array<TethysFile>) {
|
||||
// Update sort_order based on the new index when the list is changed
|
||||
newItems.forEach((item, index) => {
|
||||
item.sort_order = index + 1; // Assuming sort_order starts from 1
|
||||
});
|
||||
}
|
||||
|
||||
@Watch('filesToDelete', {
|
||||
deep: true, //also in case of pushing
|
||||
})
|
||||
public propertyWatcherDeletedFiles(newItems: Array<TethysFile>) {
|
||||
// Update sort_order based on the new index when the list is changed
|
||||
newItems.forEach((item, index) => {
|
||||
item.sort_order = index + 1; // Assuming sort_order starts from 1
|
||||
|
@ -262,7 +303,7 @@ class FileUploadComponent extends Vue {
|
|||
public created() {
|
||||
for (const file of this.files) {
|
||||
if (!(file instanceof File)) {
|
||||
// console.log(`${file.name} path is ${file.filePath} here.`);
|
||||
// console.log(`${file.name} path is ${file.filePath} here.`);
|
||||
this.generateURL(file);
|
||||
// console.log(`${file.fileSrc} path.`);
|
||||
}
|
||||
|
@ -281,35 +322,45 @@ class FileUploadComponent extends Vue {
|
|||
1 > --this.counter && this.overlay.classList.remove('draggedover');
|
||||
}
|
||||
|
||||
public dragOverHandler(e) {
|
||||
if (this._hasFiles(e.dataTransfer)) {
|
||||
e.preventDefault();
|
||||
public dragOverHandler(event: DragEvent): void {
|
||||
if (this._hasFiles(event.dataTransfer)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
public startDrag(evt, item) {
|
||||
evt.dataTransfer.dropEffect = 'move';
|
||||
evt.dataTransfer.effectAllowed = 'move';
|
||||
evt.dataTransfer.setData('itemID', item.id);
|
||||
public startDrag(event: DragEvent, item: { id: string }) {
|
||||
const dataTransfer = event.dataTransfer;
|
||||
|
||||
// Check if dataTransfer is not null
|
||||
if (dataTransfer) {
|
||||
dataTransfer.dropEffect = 'move';
|
||||
dataTransfer.effectAllowed = 'move';
|
||||
dataTransfer.setData('itemID', item.id);
|
||||
} else {
|
||||
console.warn('dataTransfer is null, drag event may not be supported.');
|
||||
}
|
||||
}
|
||||
|
||||
// reset counter and append file to gallery when file is dropped
|
||||
|
||||
public dropHandler(event) {
|
||||
public dropHandler(event: DragEvent): void {
|
||||
event.preventDefault();
|
||||
for (const file of event.dataTransfer.files) {
|
||||
// let fileName = String(file.name.replace(/\.[^/.]+$/, ''));
|
||||
// file.label = fileName;
|
||||
// if (file.type.match('image.*')) {
|
||||
// this.generateURL(file);
|
||||
// }
|
||||
this._addFile(file);
|
||||
const dataTransfer = event.dataTransfer;
|
||||
if (dataTransfer) {
|
||||
for (const file of event.dataTransfer?.files) {
|
||||
// let fileName = String(file.name.replace(/\.[^/.]+$/, ''));
|
||||
// file.label = fileName;
|
||||
// if (file.type.match('image.*')) {
|
||||
// this.generateURL(file);
|
||||
// }
|
||||
this._addFile(file);
|
||||
}
|
||||
this.overlay.classList.remove('draggedover');
|
||||
this.counter = 0;
|
||||
}
|
||||
this.overlay.classList.remove('draggedover');
|
||||
this.counter = 0;
|
||||
}
|
||||
|
||||
public onChangeFile(event) {
|
||||
public onChangeFile(event: Event) {
|
||||
event.preventDefault();
|
||||
// let uploadedFile = event.target.files[0];
|
||||
// let fileName = String(event.target.files[0].name.replace(/\.[^/.]+$/, ''));
|
||||
|
@ -343,13 +394,46 @@ class FileUploadComponent extends Vue {
|
|||
return Object.fromEntries(Object.entries(this.errors).filter(([key]) => key.startsWith('file')));
|
||||
}
|
||||
|
||||
public clearAllFiles(event) {
|
||||
public clearAllFiles(event: Event) {
|
||||
event.preventDefault();
|
||||
this.items.splice(0);
|
||||
}
|
||||
|
||||
public removeFile(key) {
|
||||
public removeFile(key: number) {
|
||||
// Check if the key is within the bounds of the items array
|
||||
if (key < 0 || key >= this.items.length) {
|
||||
console.error('Invalid key provided for removal.');
|
||||
return;
|
||||
}
|
||||
let fileToDelete = this.items[key];
|
||||
// Remove the file from items
|
||||
this.items.splice(key, 1);
|
||||
|
||||
// Check if the file is of type TethysFile based on its properties
|
||||
if (this.isTethysFile(fileToDelete)) {
|
||||
this.deletetFiles.push(fileToDelete);
|
||||
}
|
||||
}
|
||||
// Helper method to check if a file is of type TethysFile
|
||||
private isTethysFile(file: any): file is TethysFile {
|
||||
// Replace the following conditions with the actual properties of TethysFile
|
||||
return file && typeof file.id === 'number'; // Example property check
|
||||
}
|
||||
|
||||
public reactivateFile(key: number) {
|
||||
// Check if the key is within the bounds of the items array
|
||||
if (key < 0 || key >= this.deletetFiles.length) {
|
||||
console.error('Invalid key provided for reactivate.');
|
||||
return;
|
||||
}
|
||||
let fileToReactivate = this.deletetFiles[key];
|
||||
// Remove the file from items
|
||||
this.deletetFiles.splice(key, 1);
|
||||
|
||||
// Check if the file is of type TethysFile based on its properties
|
||||
if (this.isTethysFile(fileToReactivate)) {
|
||||
this.items.push(fileToReactivate);
|
||||
}
|
||||
}
|
||||
|
||||
public generateURL(file: TethysFile | File): string {
|
||||
|
@ -358,21 +442,21 @@ class FileUploadComponent extends Vue {
|
|||
// const blob = new Blob([file.fileData], { type: 'image/png'});
|
||||
// let fileSrc = file.fileData;
|
||||
|
||||
let localUrl: string = "";
|
||||
let localUrl: string = '';
|
||||
if (file instanceof File) {
|
||||
localUrl = URL.createObjectURL(file as Blob);
|
||||
} else if (file.fileData) {
|
||||
// const blob = new Blob([file.fileData]);
|
||||
// const blob = new Blob([file.fileData]);
|
||||
// localUrl = URL.createObjectURL(blob);
|
||||
const parsed = JSON.parse(file.fileData);
|
||||
file.fileData = "";
|
||||
file.fileData = '';
|
||||
// retrieve the original buffer of data
|
||||
const buff = Buffer.from(parsed.blob, "base64");
|
||||
const buff = Buffer.from(parsed.blob, 'base64');
|
||||
const blob = new Blob([buff], { type: 'application/octet-stream' });
|
||||
// file.blob = blob;
|
||||
localUrl = URL.createObjectURL(blob);
|
||||
file.fileSrc = localUrl;
|
||||
}
|
||||
file.fileSrc = localUrl;
|
||||
}
|
||||
|
||||
// setTimeout(() => {
|
||||
// URL.revokeObjectURL(localUrl);
|
||||
|
@ -380,8 +464,6 @@ class FileUploadComponent extends Vue {
|
|||
return localUrl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// private async downloadFile(id: number): Promise<string> {
|
||||
// const response = await axios.get<Blob>(`/api/download/${id}`, {
|
||||
// responseType: 'blob',
|
||||
|
@ -393,9 +475,7 @@ class FileUploadComponent extends Vue {
|
|||
// return url;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
public getFileSize(file) {
|
||||
public getFileSize(file: File) {
|
||||
if (file.size > 1024) {
|
||||
if (file.size > 1048576) {
|
||||
return Math.round(file.size / 1048576) + 'mb';
|
||||
|
@ -421,7 +501,7 @@ class FileUploadComponent extends Vue {
|
|||
private _addFile(file: File) {
|
||||
// const reader = new FileReader();
|
||||
// reader.onload = (event) => {
|
||||
// const base64Data = (event.target as FileReader).result as string;
|
||||
// const base64Data = (event.target as FileReader).result as string;
|
||||
// this.items.push(test);
|
||||
|
||||
// };
|
||||
|
@ -442,30 +522,23 @@ class FileUploadComponent extends Vue {
|
|||
mime_type: file.type,
|
||||
visible_in_frontdoor: false,
|
||||
visible_in_oai: false,
|
||||
fileSrc: file.type.match('image.*')? this.generateURL(file) : "",
|
||||
fileSrc: file.type.match('image.*') ? this.generateURL(file) : '',
|
||||
blob: file as Blob,
|
||||
sort_order: (this.items.length + 1),
|
||||
sort_order: this.items.length + 1,
|
||||
};
|
||||
// this.items.push(test);
|
||||
this.items[this.items.length] = test;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.items.push(file);
|
||||
}
|
||||
}
|
||||
|
||||
// private async readBase64(blob: Blob): Promise<string> {
|
||||
// return new Promise<string>((resolve, reject) => {
|
||||
// const reader = new FileReader();
|
||||
// reader.onload = (event) => resolve((event.target as FileReader).result as string);
|
||||
// reader.onerror = reject;
|
||||
// reader.readAsDataURL(blob);
|
||||
// });
|
||||
// }
|
||||
|
||||
// use to check if a file is being dragged
|
||||
private _hasFiles({ types = [] as Array<string> }) {
|
||||
return types.indexOf('Files') > -1;
|
||||
// private _hasFiles({ types = [] as Array<string> }) {
|
||||
// return types.indexOf('Files') > -1;
|
||||
// }
|
||||
private _hasFiles(dataTransfer: DataTransfer | null): boolean {
|
||||
return dataTransfer ? dataTransfer.items.length > 0 : false;
|
||||
}
|
||||
}
|
||||
export default FileUploadComponent;
|
||||
|
|
Loading…
Add table
editor.link_modal.header
Reference in a new issue