Files
mixtape/zero.Backoffice.UI/old_app/components/pickers/mediaPicker/mediapicker.vue
T

428 lines
9.3 KiB
Vue
Raw Normal View History

2020-05-14 16:05:33 +02:00
<template>
2020-06-02 12:08:38 +02:00
<div class="ui-mediapicker">
<div v-if="previews.length > 0" class="ui-mediapicker-previews">
<div v-for="item in previews" class="ui-mediapicker-preview">
2021-01-09 19:09:31 +01:00
<div v-if="!item.error" class="ui-mediapicker-preview-image" :class="{'media-pattern': item.thumbnailSource }">
2020-06-02 12:08:38 +02:00
<img v-if="item.thumbnailSource" :src="item.thumbnailSource" :alt="item.name" />
2021-01-20 15:54:12 +01:00
<button v-if="!disabled" type="button" class="ui-mediapicker-preview-image-delete" @click="remove(item)" v-localize:title="'@ui.remove'"><ui-icon symbol="fth-x" :size="12" /></button>
<button v-if="!disabled" type="button" class="ui-mediapicker-preview-image-edit" @click="edit(item)" v-localize:title="'@ui.edit'"><ui-icon symbol="fth-edit-2" :size="12" /></button>
2020-06-02 12:08:38 +02:00
</div>
2020-08-31 10:49:35 +02:00
<div v-if="!item.error" class="ui-mediapicker-preview-text">
2020-06-02 12:08:38 +02:00
<b :title="item.name">{{getFilename(item.name)}}</b>
<span class="is-filesize">{{getFileinfo(item)}}</span>
</div>
2020-08-31 10:49:35 +02:00
<div v-if="item.error">
2020-09-06 13:30:39 +02:00
<ui-select-button icon="fth-alert-circle color-red" label="@errors.preview.notfound" description="@errors.preview.notfound_text" @click="remove({ id: item.id })" :tokens="{ id: item.id }" />
2020-08-31 10:49:35 +02:00
</div>
2020-06-02 12:08:38 +02:00
</div>
</div>
<div v-if="canAdd" class="ui-mediapicker-select" :class="{'is-disabled': disabled }">
<input ref="input" type="hidden" :value="value" />
<ui-select-button icon="fth-plus" label="@mediapicker.select_text" description="@mediapicker.select_description" @click="pick" :disabled="disabled" />
</div>
2020-05-14 16:05:33 +02:00
</div>
</template>
<script>
2020-11-20 15:17:41 +01:00
import MediaApi from 'zero/api/media.js'
2020-11-01 22:20:29 +01:00
import PickMediaOverlay from './overlay.vue';
import Overlay from 'zero/helpers/overlay.js';
2020-05-14 16:05:33 +02:00
import { each as _each, extend as _extend, debounce as _debounce, isArray as _isArray } from 'underscore';
import Strings from 'zero/helpers/strings.js';
2020-05-14 16:05:33 +02:00
const TYPES = {
ALL: 'all',
IMAGE: 'image',
VIDEO: 'video',
DOCUMENT: 'document',
OTHER: 'other'
};
const DISPLAY = {
DEFAULT: 'default',
BIG: 'big',
GRID: 'grid'
};
const MAX_FILENAME_LENGTH = 32;
const defaultConfig = {
// maximum media items
limit: 1,
// media type
type: TYPES.ALL,
// how the previews are displayed
display: DISPLAY.DEFAULT,
// whether the select button is disallowed
disallowSelect: false,
// whether file upload is disallowed
disallowUpload: false,
// allowed file extensions
fileExtensions: [],
// maximum file size in MiB
2021-09-23 11:29:10 +02:00
maxFileSize: 10,
// whether to operate on the core database
shared: false
2020-05-14 16:05:33 +02:00
};
export default {
name: 'uiMediapicker',
props: {
value: {
2020-11-24 12:02:03 +01:00
type: [Array, String],
2020-05-14 16:05:33 +02:00
default: null
},
disabled: {
type: Boolean,
default: false
},
config: {
type: Object,
default: () =>
{
return defaultConfig;
}
},
},
2020-06-02 12:08:38 +02:00
data: () => ({
configuration: null,
2020-06-02 12:08:38 +02:00
previews: []
}),
watch: {
value()
{
this.updatePreviews();
}
2020-05-14 16:05:33 +02:00
},
2020-06-02 12:08:38 +02:00
2020-05-15 14:23:47 +02:00
created()
{
this.configuration = JSON.parse(JSON.stringify(_extend(defaultConfig, this.config)));
2020-05-15 14:23:47 +02:00
},
2020-06-02 12:08:38 +02:00
mounted()
{
this.updatePreviews();
},
computed: {
2020-06-02 13:36:33 +02:00
multiple()
{
return this.configuration.limit > 1;
},
2020-06-02 12:08:38 +02:00
canAdd()
{
return !this.disabled && this.configuration.limit - this.previews.length > 0;
},
},
2020-05-14 16:05:33 +02:00
methods: {
2020-06-02 12:08:38 +02:00
updatePreviews()
2020-05-14 16:05:33 +02:00
{
2020-06-02 12:08:38 +02:00
//console.info('preview', JSON.parse(JSON.stringify(this.value)));
let ids = [];
if (typeof this.value === 'string')
{
ids = [this.value];
}
else if (_isArray(this.value))
{
ids = this.value;
}
this.previews = [];
if (!ids || ids.length < 1)
{
this.$emit('previews', this.multiple ? [] : null);
2020-06-02 12:08:38 +02:00
return;
}
MediaApi.getByIds(ids).then(res =>
{
2020-08-31 10:49:35 +02:00
_each(ids, id =>
2020-06-02 12:08:38 +02:00
{
2020-08-31 10:49:35 +02:00
let value = res[id];
2020-06-02 12:08:38 +02:00
if (!value)
{
this.previews.push({
2020-09-06 13:30:39 +02:00
id: id,
error: true
2020-06-02 12:08:38 +02:00
});
}
else
{
this.previews.push(value);
}
});
this.$emit('previews', this.multiple ? this.previews : this.previews[0]);
2020-06-02 12:08:38 +02:00
});
},
remove(item)
{
let newValue = this.value;
if (typeof this.value === 'string')
{
newValue = null;
}
else if (_isArray(this.value))
{
const index = this.value.indexOf(item.id);
newValue.splice(index, 1);
}
this.onChange(newValue);
},
getFilename(name)
{
if (name.length < MAX_FILENAME_LENGTH)
{
return name;
}
const parts = name.split('.');
const extension = parts.pop();
return parts.join('.').substring(0, MAX_FILENAME_LENGTH - 6) + '...' + extension;
},
getFileinfo(item)
{
if (item.dimension)
{
return `${Strings.filesize(item.size)} ${item.dimension.width} × ${item.dimension.height}`;
}
return Strings.filesize(item.size);
},
onChange(value)
{
2020-05-14 16:05:33 +02:00
this.$emit('change', value);
this.$emit('input', value);
2020-06-02 12:08:38 +02:00
//this.updatePreviews();
2020-05-14 16:05:33 +02:00
// TODO this does not trigger the forms dirty flag
},
2020-06-02 12:08:38 +02:00
2020-05-14 16:05:33 +02:00
pick()
{
if (this.disabled)
{
return;
}
let options = _extend({
title: '@iconpicker.title',
closeLabel: '@ui.close',
component: PickMediaOverlay,
2020-06-22 15:42:50 +02:00
model: this.configuration.limit > 1 ? this.value[0] : this.value,
2020-06-03 15:16:43 +02:00
folderId: null, //'mediaFolders.97-A',
2020-05-15 14:23:47 +02:00
width: 520
2020-05-14 16:05:33 +02:00
}, typeof this.config === 'object' ? this.config : {});
options.display = 'dialog';
2020-05-14 16:05:33 +02:00
return Overlay.open(options).then(value =>
{
2020-06-02 13:36:33 +02:00
let newValue = this.value;
if (this.multiple)
{
if (!newValue)
{
newValue = [];
}
newValue.push(value.id);
}
else
{
newValue = value.id;
}
this.onChange(newValue);
2021-02-04 14:00:09 +01:00
return new Promise(resolve => resolve(newValue));
2020-05-14 16:05:33 +02:00
});
}
}
}
2020-06-02 12:08:38 +02:00
</script>
<style lang="scss">
.ui-mediapicker-previews
{
.display-grid &
{
display: flex;
gap: 10px;
2020-06-02 12:08:38 +02:00
.ui-mediapicker-preview + .ui-mediapicker-preview
{
margin-top: 0;
}
}
}
.ui-mediapicker-previews + .ui-mediapicker-select,
.ui-mediapicker-preview + .ui-mediapicker-preview
{
margin-top: 10px;
}
.ui-mediapicker:not(.display-grid) .ui-mediapicker-previews + .ui-mediapicker-add
{
display: flex;
flex-direction: column;
.ui-select-button + .ui-mediapicker-add-upload
{
margin-left: 0;
margin-top: 10px;
}
}
.ui-mediapicker-preview
{
display: flex;
align-items: center;
}
.ui-mediapicker-preview-image
{
display: flex;
justify-content: center;
align-items: center;
2021-01-09 19:09:31 +01:00
width: 80px;
height: 80px;
2020-06-02 12:08:38 +02:00
/*background: var(--color-bg);*/
border: 1px solid var(--color-line);
2021-01-20 15:54:12 +01:00
padding: 0;
2020-06-02 12:08:38 +02:00
border-radius: var(--radius);
color: var(--color-text);
2020-06-02 12:08:38 +02:00
position: relative;
overflow: hidden;
img
{
border-radius: 3px;
max-width: 100%;
max-height: 100%;
margin: auto;
display: block;
color: transprent;
overflow: hidden;
font-size: 0;
position: relative;
z-index: 2;
}
2020-09-06 13:30:39 +02:00
&.is-icon
{
2021-01-06 12:03:21 +01:00
width: 48px;
height: 48px;
2020-09-06 13:30:39 +02:00
display: inline-flex;
justify-content: center;
align-items: center;
border-radius: var(--radius);
background: var(--color-box);
color: var(--color-text);
2020-09-06 13:30:39 +02:00
text-align: center;
font-size: 16px;
}
2020-06-02 12:08:38 +02:00
&:hover .ui-mediapicker-preview-image-delete,
&:hover .ui-mediapicker-preview-image-edit
{
opacity: 1;
transition-delay: 0.1s;
}
.display-big &, .display-grid &
{
width: 100px;
height: 100px;
}
}
.ui-mediapicker-preview-text
{
display: flex;
flex-direction: column;
margin-left: 16px;
font-size: var(--font-size);
.is-filesize
{
color: var(--color-text-dim);
2020-06-02 12:08:38 +02:00
margin-top: 3px;
font-size: var(--font-size-xs);
}
.display-grid &
{
display: none;
}
}
.ui-mediapicker-preview-image-delete,
.ui-mediapicker-preview-image-edit
{
opacity: 0;
transition: opacity 0.15s ease;
position: absolute;
display: inline-block;
right: 3px;
bottom: 3px;
width: 24px;
height: 24px;
line-height: 26px;
border-radius: 20px;
background: var(--color-negative);
color: var(--color-primary-text);
2020-06-02 12:08:38 +02:00
z-index: 2;
text-align: center;
font-size: 13px;
.ui-media.display-default &
{
width: 20px;
height: 20px;
line-height: 22px;
}
}
.ui-mediapicker-preview-image-edit
{
right: 30px;
background: var(--color-box);
color: var(--color-text);
2020-06-02 12:08:38 +02:00
.ui-media.display-default &
{
right: 24px;
}
}
</style>