Skip to content

Commit

Permalink
Merge pull request #515 from intuitem/improve/add_ctrl_v_file_paste_f…
Browse files Browse the repository at this point in the history
…or_evidences

Add Ctrl+V paste for evidence attachment FileInput
  • Loading branch information
ab-smith authored Jun 4, 2024
2 parents 48dffdd + ed35965 commit 5d59978
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 0 deletions.
57 changes: 57 additions & 0 deletions frontend/src/lib/components/Forms/FileInput.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,69 @@
export let field: string;
export let helpText: string | undefined = undefined;
export let form;
export let allowPaste: boolean = false;
// allowPaste should be set to false when we have multiple FileField at the same time (the ideal implementation would be to deduce to which FileInput the paste operation must be forwarded depending on the targetElement of the "paste" event)
const { errors, constraints } = formFieldProxy(form, field);
let value = fileProxy(form, field);
let fileInput: null | HTMLInputElement = null;
$: classesTextField = (errors: string[] | undefined) => (errors ? 'input-error' : '');
const allowedExtensions = new Set(['jpg', 'jpeg', 'png', 'svg', 'webp', 'gif', 'bmp', 'tiff']);
function getShortenPreciseType(preciseType: string): string {
const shortPreciseTypeResult = /^[a-z0-9]+/.exec(preciseType);
if (shortPreciseTypeResult === null) return '';
return shortPreciseTypeResult[0];
}
function getAppropriateExtension(mimeType: string): string | null {
const [mainType, preciseType] = mimeType.toLocaleLowerCase().split('/');
const shortPreciseType = getShortenPreciseType(preciseType);
if (mainType === 'image' && allowedExtensions.has(shortPreciseType)) return shortPreciseType;
return null;
}
function generateFilename(mimeType: string): string | null {
const extension = getAppropriateExtension(mimeType);
if (extension === null) return null;
// We could implement some contextual data in the filename (for example the evidence name or the name of an object this evidence is related to etc...)
const date = new Date();
return `${date.getDay()}-${date.getMonth()}-${date.getFullYear()}_${date.getHours()}-${date.getMinutes()}-${date.getSeconds()}_${date.getMilliseconds()}.${extension}`;
}
function onPaste(event: ClipboardEvent) {
if (!allowPaste || fileInput === null) return;
const items = event.clipboardData?.items;
if (!items) return;
for (const item of items) {
if (item.kind === 'file') {
const blob = item.getAsFile();
if (blob === null) continue;
const filename = generateFilename(blob.type);
if (filename === null) continue;
const file = new File([blob], filename, { type: blob.type });
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
fileInput.files = dataTransfer.files; // It seems to work fine even with the superforms fileProxy.
const event = new Event('change', { bubbles: true }); // Do we really need bubbles: true ?
fileInput.dispatchEvent(event);
// A toast should appear to tell the user the Paste operation was successfull.
event.preventDefault();
break;
}
}
}
</script>

<svelte:document on:paste={onPaste} />

<div>
{#if label !== undefined}
{#if $constraints?.required}
Expand All @@ -41,6 +97,7 @@
aria-invalid={$errors ? 'true' : undefined}
placeholder=""
bind:files={$value}
bind:this={fileInput}
{...$constraints}
{...$$restProps}
/>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/components/Forms/ModelForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@
<HiddenInput {form} field="requirement_assessments" />
<FileInput
{form}
allowPaste={true}
helpText={object.attachment
? `${m.attachmentWarningText()}: ${object.attachment}`
: m.attachmentHelpText()}
Expand Down

0 comments on commit 5d59978

Please sign in to comment.