update FileItem context strategy by reading File content on File change

This commit is contained in:
axolotle 2022-03-01 16:29:00 +01:00
parent 9b57063572
commit fd19dcebf6
3 changed files with 75 additions and 43 deletions

View file

@ -1,19 +1,24 @@
<template> <template>
<b-button-group class="w-100"> <b-button-group class="w-100">
<b-button @click="clearFiles" variant="danger" v-if="!this.required && this.value !== null && !this.value._removed"> <b-button
v-if="!this.required && this.value.file !== null"
@click="clearFiles" variant="danger"
>
<span class="sr-only">{{ $t('delete') }}</span>
<icon iname="trash" /> <icon iname="trash" />
</b-button> </b-button>
<b-form-file <b-form-file
v-model="file" v-model="file"
ref="input-file" ref="input-file"
:id="id" :id="id"
v-on="$listeners"
:required="required" :required="required"
:placeholder="_placeholder" :placeholder="_placeholder"
:accept="accept" :accept="accept"
:drop-placeholder="dropPlaceholder" :drop-placeholder="dropPlaceholder"
:state="state" :state="state"
:browse-text="$t('words.browse')" :browse-text="$t('words.browse')"
@input="onInput"
@blur="$parent.$emit('touch', name)" @blur="$parent.$emit('touch', name)"
@focusout.native="$parent.$emit('touch', name)" @focusout.native="$parent.$emit('touch', name)"
/> />
@ -21,18 +26,14 @@
</template> </template>
<script> <script>
import { getFileContent } from '@/helpers/commons'
export default { export default {
name: 'FileItem', name: 'FileItem',
data () {
return {
file: this.value
}
},
props: { props: {
id: { type: String, default: null }, id: { type: String, default: null },
value: { type: [File, null], default: null }, value: { type: Object, default: () => ({}) },
placeholder: { type: String, default: 'Choose a file or drop it here...' }, placeholder: { type: String, default: 'Choose a file or drop it here...' },
dropPlaceholder: { type: String, default: null }, dropPlaceholder: { type: String, default: null },
accept: { type: String, default: null }, accept: { type: String, default: null },
@ -41,24 +42,43 @@ export default {
name: { type: String, default: null } name: { type: String, default: null }
}, },
data () {
return {
file: this.value.file
}
},
computed: { computed: {
_placeholder: function () { _placeholder: function () {
return (this.value === null) ? this.placeholder : this.value.name return this.value.file === null ? this.placeholder : this.value.file.name
} }
}, },
methods: { methods: {
clearFiles () { onInput (file) {
const f = new File([''], this.placeholder) const value = {
f._removed = true file,
if (this.value && this.value.currentfile) { content: '',
this.$refs['input-file'].reset() currentfile: false,
this.$emit('input', f) removed: false
} else {
this.$refs['input-file'].setFiles([f])
this.file = f
this.$emit('input', f)
} }
// Update the value with the new File and an empty content for now
this.$emit('input', value)
// Asynchronously load the File content and update the value again
getFileContent(file).then(content => {
this.$emit('input', { ...value, content })
})
},
clearFiles () {
this.$refs['input-file'].reset()
this.$emit('input', {
file: null,
content: '',
current_file: false,
removed: true
})
} }
} }
} }

View file

@ -100,3 +100,26 @@ export function escapeHtml (unsafe) {
export function randint (min, max) { export function randint (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min return Math.floor(Math.random() * (max - min + 1)) + min
} }
/**
* Returns a File content.
*
* @param {File} file
* @param {Object} [extraParams] - Optionnal params
* @param {Boolean} [extraParams.base64] - returns a base64 representation of the file.
* @return {Promise<String>}
*/
export function getFileContent (file, { base64 = false } = {}) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onerror = reject
reader.onload = () => resolve(reader.result)
if (base64) {
reader.readAsDataURL(file)
} else {
reader.readAsText(file)
}
})
}

View file

@ -2,7 +2,12 @@ import i18n from '@/i18n'
import store from '@/store' import store from '@/store'
import evaluate from 'simple-evaluate' import evaluate from 'simple-evaluate'
import * as validators from '@/helpers/validators' import * as validators from '@/helpers/validators'
import { isObjectLiteral, isEmptyValue, flattenObjectLiteral } from '@/helpers/commons' import {
isObjectLiteral,
isEmptyValue,
flattenObjectLiteral,
getFileContent
} from '@/helpers/commons'
/** /**
@ -125,9 +130,12 @@ export function formatYunoHostArgument (arg) {
name: 'FileItem', name: 'FileItem',
props: defaultProps.concat(['accept']), props: defaultProps.concat(['accept']),
callback: function () { callback: function () {
if (value) { value = {
value = new File([''], value) // in case of already defined file, we receive only the file path (not the actual file)
value.currentfile = true file: value ? new File([''], value) : null,
content: '',
current_file: !!value,
removed: false
} }
} }
}, },
@ -353,25 +361,6 @@ export function configPanelsFieldIsVisible (expression, field, forms) {
} }
export function pFileReader (file, output, key, base64 = true) {
return new Promise((resolve, reject) => {
const fr = new FileReader()
fr.onerror = reject
fr.onload = () => {
output[key] = fr.result
if (base64) {
output[key] = fr.result.replace(/data:[^;]*;base64,/, '')
}
output[key + '[name]'] = file.name
resolve()
}
if (base64) {
fr.readAsDataURL(file)
} else {
fr.readAsText(file)
}
})
}
/** /**