diff --git a/public/js/components/Form/Upload/Dms.js b/public/js/components/Form/Upload/Dms.js index 82333dc7f..83b8d86bb 100644 --- a/public/js/components/Form/Upload/Dms.js +++ b/public/js/components/Form/Upload/Dms.js @@ -1,8 +1,10 @@ import DmsItem from './Dms/Item.js'; +import DmsPreview from './Dms/Preview.js'; export default { components: { - DmsItem + DmsItem, + DmsPreview }, emits: [ 'update:modelValue' @@ -24,6 +26,21 @@ export default { disabled: { type: Boolean, default: false + }, + // shows the chosen images and pdfs below the input before the upload + preview: Boolean, + // small, medium, large or a css length like '400px' + previewHeight: { + type: String, + default: 'medium' + } + }, + computed: { + previewFiles() { + if (!this.preview || !this.modelValue) + return []; + // stored dms files are json placeholders, they have no content to show + return Array.from(this.modelValue).filter(file => file instanceof File && file.type != 'application/x.fhc-dms+json'); } }, methods: { @@ -103,5 +120,6 @@ export default { > + ` } \ No newline at end of file diff --git a/public/js/components/Form/Upload/Dms/Preview.js b/public/js/components/Form/Upload/Dms/Preview.js new file mode 100644 index 000000000..e1b100929 --- /dev/null +++ b/public/js/components/Form/Upload/Dms/Preview.js @@ -0,0 +1,68 @@ +// only these types get a preview. html or svg in the iframe would run their scripts in the page origin +const IMAGE_TYPES = ['image/png', 'image/jpeg', 'image/gif', 'image/webp']; + +const HEIGHTS = { + small: '30vh', + medium: '50vh', + large: '80vh' +}; + +/** + * Preview of one chosen file before the upload: an image as img, a pdf in the pdf viewer of the browser. + * height: small, medium, large or a css length like '400px'. + */ +export default { + props: { + file: { + type: File, + required: true + }, + height: { + type: String, + default: 'medium' + } + }, + data() { + return { + url: '' + }; + }, + computed: { + isImage() { + return IMAGE_TYPES.includes(this.file.type); + }, + // android chrome has no inline pdf viewer, there a pdf gets no preview + isPdf() { + return this.file.type == 'application/pdf' && navigator.pdfViewerEnabled !== false; + }, + cssHeight() { + return HEIGHTS[this.height] || this.height; + } + }, + watch: { + file: { + handler() { + this.revokeUrl(); + // an object url only references the file, no base64 copy in memory + if (this.isImage || this.isPdf) + this.url = URL.createObjectURL(this.file); + }, + immediate: true + } + }, + unmounted() { + this.revokeUrl(); + }, + methods: { + revokeUrl() { + if (this.url) + URL.revokeObjectURL(this.url); + this.url = ''; + } + }, + template: ` +
+ + +
` +} diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 4f60f178c..e65c59b17 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -33136,6 +33136,26 @@ array( ) ) ), + array( + 'app' => 'anwesenheiten', + 'category' => 'global', + 'phrase' => 'errorValidateUhrzeit', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Die Endzeit muss nach der Startzeit liegen.', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'The end time must be after the start time.', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), array( 'app' => 'anwesenheiten', 'category' => 'global',