date range picker
This commit is contained in:
@@ -1,471 +0,0 @@
|
||||
<template>
|
||||
<div class="ui-media" :class="'display-' + configuration.display">
|
||||
<div v-if="items.length > 0" class="ui-media-previews">
|
||||
<div v-for="item in items" class="ui-media-preview">
|
||||
<div class="ui-media-preview-image">
|
||||
<img v-if="item.source" :src="getPreview(item)" :alt="item.name" />
|
||||
<button v-if="!disabled" type="button" class="ui-media-preview-image-delete" @click="remove(item)" v-localize:title="'@ui.remove'"><i class="fth-x"></i></button>
|
||||
<button v-if="!disabled" type="button" class="ui-media-preview-image-edit" @click="edit(item)" v-localize:title="'@ui.edit'"><i class="fth-edit-2"></i></button>
|
||||
</div>
|
||||
<div class="ui-media-preview-text">
|
||||
<b :title="item.name">{{getFilename(item.name)}}</b>
|
||||
<span class="is-filesize">{{getFileinfo(item)}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-media-add" v-if="canAdd">
|
||||
<ui-select-button v-if="!configuration.disallowSelect" icon="fth-folder" label="@mediapicker.select_text" description="@mediapicker.select_description" :disabled="disabled" />
|
||||
<div v-if="!configuration.disallowUpload" class="ui-media-add-upload">
|
||||
<input type="file" :accept="acceptedFileExtensions" :multiple="multiple" @change="onUpload" />
|
||||
<ui-select-button icon="fth-upload" label="@mediapicker.upload_text" :description="uploadDescription" :disabled="true" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
import { each as _each, extend as _extend, debounce as _debounce, isArray as _isArray } from 'underscore';
|
||||
import Strings from 'zero/helpers/strings.js';
|
||||
import Overlay from 'zero/helpers/overlay.js';
|
||||
import MediaOverlay from 'zero/pages/media/media-item.vue';
|
||||
|
||||
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
|
||||
maxFileSize: 10
|
||||
};
|
||||
|
||||
export default {
|
||||
name: 'uiMediaOld',
|
||||
|
||||
props: {
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
config: {
|
||||
type: Object,
|
||||
default: () =>
|
||||
{
|
||||
return defaultConfig;
|
||||
}
|
||||
},
|
||||
value: {
|
||||
type: [Array, Object]
|
||||
}
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
configuration: {},
|
||||
items: []
|
||||
}),
|
||||
|
||||
watch: {
|
||||
config: {
|
||||
deep: true,
|
||||
handler: function ()
|
||||
{
|
||||
this.initialize();
|
||||
}
|
||||
},
|
||||
value: {
|
||||
deep: true,
|
||||
handler: function ()
|
||||
{
|
||||
this.initialize();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
multiple()
|
||||
{
|
||||
return this.configuration.limit > 1;
|
||||
},
|
||||
canAdd()
|
||||
{
|
||||
return !this.disabled && this.configuration.limit - this.items.length > 0;
|
||||
},
|
||||
uploadDescription()
|
||||
{
|
||||
return this.configuration.fileExtensions.length > 0 ? this.displayedFileExtensions : '@mediapicker.upload_description';
|
||||
},
|
||||
acceptedFileExtensions()
|
||||
{
|
||||
return this.configuration.fileExtensions.join(',');
|
||||
},
|
||||
displayedFileExtensions()
|
||||
{
|
||||
return this.configuration.fileExtensions.join(', ').replace(/\./g, '');
|
||||
}
|
||||
},
|
||||
|
||||
created()
|
||||
{
|
||||
this.initialize();
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
initialize()
|
||||
{
|
||||
this.configuration = _extend(defaultConfig, this.config);
|
||||
|
||||
if (_isArray(this.value))
|
||||
{
|
||||
this.items = this.value;
|
||||
}
|
||||
else if (!!this.value && typeof this.value === 'object' && this.value.source)
|
||||
{
|
||||
this.items = [this.value];
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
onUpload(event)
|
||||
{
|
||||
let remaining = this.configuration.limit - this.items.length;
|
||||
const files = event.target.files;
|
||||
|
||||
if (files && files.length > 0)
|
||||
{
|
||||
for (var i = 0; i < files.length; i++)
|
||||
{
|
||||
if (i >= remaining)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
this.addFile(files[i]);
|
||||
}
|
||||
}
|
||||
|
||||
this.update();
|
||||
},
|
||||
|
||||
|
||||
addFromLibrary(item)
|
||||
{
|
||||
this.items.push(item);
|
||||
this.update();
|
||||
},
|
||||
|
||||
|
||||
addFile(file)
|
||||
{
|
||||
var source = URL.createObjectURL(file);
|
||||
var media = {
|
||||
id: 'upload:' + Strings.guid(),
|
||||
name: file.name,
|
||||
source: source,
|
||||
size: file.size,
|
||||
mimeType: file.type
|
||||
};
|
||||
|
||||
this.items.push(media);
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e)
|
||||
{
|
||||
media.source = e.target.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
},
|
||||
|
||||
|
||||
remove(item)
|
||||
{
|
||||
const index = this.items.indexOf(item);
|
||||
this.items.splice(item, 1);
|
||||
this.update();
|
||||
},
|
||||
|
||||
|
||||
update()
|
||||
{
|
||||
this.$emit('input', this.multiple ? this.items : this.items[0]);
|
||||
},
|
||||
|
||||
|
||||
edit(item)
|
||||
{
|
||||
let model = JSON.parse(JSON.stringify(item));
|
||||
|
||||
let options = {
|
||||
title: '@iconpicker.title',
|
||||
closeLabel: '@ui.close',
|
||||
component: MediaOverlay,
|
||||
model: model,
|
||||
theme: 'dark',
|
||||
disabled: this.disabled
|
||||
};
|
||||
|
||||
return Overlay.open(options).then(value =>
|
||||
{
|
||||
if (value.deletionRequested)
|
||||
{
|
||||
this.remove(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.alternativeText = value.alternativeText;
|
||||
item.caption = value.caption;
|
||||
item.focalPoint = value.focalPoint;
|
||||
}
|
||||
}, () => { });
|
||||
},
|
||||
|
||||
|
||||
getPreview(item)
|
||||
{
|
||||
if (!item.id || item.id.indexOf('upload:') > -1 || item.source.indexOf("http") === 0)
|
||||
{
|
||||
return item.source;
|
||||
}
|
||||
|
||||
if (item.id.indexOf("native:") > -1)
|
||||
{
|
||||
return item.source + "?width=100&height=100";
|
||||
}
|
||||
|
||||
if (!item.hasThumbnail)
|
||||
{
|
||||
return item.source;
|
||||
}
|
||||
|
||||
var extension = '.' + item.source.split('.').pop();
|
||||
return item.source.replace(extension, ".thumb" + extension);
|
||||
},
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.ui-media
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
.ui-media-add
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
.ui-media-add-upload
|
||||
{
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
|
||||
.ui-select-button + &
|
||||
{
|
||||
margin-left: var(--padding);
|
||||
}
|
||||
|
||||
input[type="file"]
|
||||
{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-media-previews
|
||||
{
|
||||
.display-grid &
|
||||
{
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
|
||||
.ui-media-preview + .ui-media-preview
|
||||
{
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-media-previews + .ui-media-add,
|
||||
.ui-media-preview + .ui-media-preview
|
||||
{
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.ui-media:not(.display-grid) .ui-media-previews + .ui-media-add
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.ui-select-button + .ui-media-add-upload
|
||||
{
|
||||
margin-left: 0;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-media-preview
|
||||
{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ui-media-preview-image
|
||||
{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
/*background: var(--color-bg);*/
|
||||
border: 1px solid var(--color-line-light);
|
||||
padding: 3px;
|
||||
border-radius: var(--radius);
|
||||
color: var(--color-text);
|
||||
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;
|
||||
}
|
||||
|
||||
&:hover .ui-media-preview-image-delete,
|
||||
&:hover .ui-media-preview-image-edit
|
||||
{
|
||||
opacity: 1;
|
||||
transition-delay: 0.1s;
|
||||
}
|
||||
|
||||
.display-big &, .display-grid &
|
||||
{
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-media-preview-text
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-left: 16px;
|
||||
font-size: var(--font-size);
|
||||
|
||||
.is-filesize
|
||||
{
|
||||
color: var(--color-text-dim);
|
||||
margin-top: 3px;
|
||||
font-size: var(--font-size-xs);
|
||||
}
|
||||
|
||||
.display-grid &
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-media-preview-image-delete,
|
||||
.ui-media-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);
|
||||
z-index: 2;
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
|
||||
.ui-media.display-default &
|
||||
{
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-media-preview-image-edit
|
||||
{
|
||||
right: 30px;
|
||||
background: var(--color-bg);
|
||||
color: var(--color-text);
|
||||
|
||||
.ui-media.display-default &
|
||||
{
|
||||
right: 24px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,67 +0,0 @@
|
||||
<template>
|
||||
<div class="ui-tags" :class="{'is-disabled': disabled }">
|
||||
<ui-input-list :value="value" @input="$emit('input', $event)" :add-label="addLabel" :disabled="disabled" :max-items="maxItems" :max-length="maxLength" :plus-button="true" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'uiTags',
|
||||
|
||||
props: {
|
||||
addLabel: {
|
||||
type: String,
|
||||
default: '@ui.add'
|
||||
},
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
maxItems: {
|
||||
type: Number,
|
||||
default: 100
|
||||
},
|
||||
maxLength: {
|
||||
type: Number,
|
||||
default: 200
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.ui-tags
|
||||
{
|
||||
.ui-input-list
|
||||
{
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.ui-input-list-item
|
||||
{
|
||||
display: inline-grid;
|
||||
min-width: 0;
|
||||
|
||||
.ui-input
|
||||
{
|
||||
min-width: 120px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
& + .ui-input-list-item, & + .ui-button, & + .ui-select-button
|
||||
{
|
||||
margin-top: 0;
|
||||
margin-left: 6px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
@@ -1,118 +0,0 @@
|
||||
import Vue from 'vue';
|
||||
import Overlay from 'zero/helpers/overlay.js';
|
||||
import { find as _find, extend as _extend } from 'underscore';
|
||||
import Axios from 'axios';
|
||||
//import PasswordChangeOverlay from 'zero/pages/password-change.vue';
|
||||
|
||||
export default new Vue({
|
||||
|
||||
data: () => ({
|
||||
isAuthenticated: false,
|
||||
rejectReason: null,
|
||||
user: {
|
||||
name: null,
|
||||
email: null
|
||||
}
|
||||
}),
|
||||
|
||||
watch: {
|
||||
isAuthenticated(value)
|
||||
{
|
||||
this.$emit('authenticated', value);
|
||||
},
|
||||
user(value)
|
||||
{
|
||||
this.$emit('user', value);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
// loads the current user into the cache
|
||||
loadUser()
|
||||
{
|
||||
Axios.get('authentication/getUser').then(res =>
|
||||
{
|
||||
this.isAuthenticated = res.data.success && res.data.model;
|
||||
|
||||
if (res.data.success)
|
||||
{
|
||||
this.user = res.data.model;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// the cached user has been rejected by the server so we clear credentials here
|
||||
rejectUser(reason)
|
||||
{
|
||||
this.rejectReason = reason;
|
||||
this.isAuthenticated = false;
|
||||
this.user = null;
|
||||
},
|
||||
|
||||
// sets the current user and isAuthenticated to true
|
||||
setUser(user)
|
||||
{
|
||||
if (!user)
|
||||
{
|
||||
this.rejectUser();
|
||||
return;
|
||||
}
|
||||
this.isAuthenticated = true;
|
||||
this.user = user;
|
||||
},
|
||||
|
||||
// logs the user in with the passed credentials
|
||||
login(model)
|
||||
{
|
||||
return Axios.post('authentication/loginUser', model).then(res =>
|
||||
{
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
if (res.data.success)
|
||||
{
|
||||
this.setUser(res.data.model);
|
||||
resolve(res.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.rejectUser();
|
||||
reject(res.data.errors);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
// logs the current user out
|
||||
logout()
|
||||
{
|
||||
let promise = Axios.post('authentication/logoutUser');
|
||||
this.rejectUser("@login.rejectReasons.logout");
|
||||
return promise;
|
||||
},
|
||||
|
||||
// try to switch selected application for user
|
||||
switchApp(appId)
|
||||
{
|
||||
return Axios.post('authentication/switchApp', null, { params: { appId } }).then(res =>
|
||||
{
|
||||
//return this.zero.reloadConfig().then(() =>
|
||||
//{
|
||||
this.$emit('appswitch', res.data);
|
||||
return Promise.resolve(res.data.success);
|
||||
//});
|
||||
});
|
||||
},
|
||||
|
||||
// open overlay to update password
|
||||
openPasswordOverlay()
|
||||
{
|
||||
return Overlay.open({
|
||||
title: '@changepasswordoverlay.title',
|
||||
closeLabel: '@ui.close',
|
||||
confirmLabel: '@changepasswordoverlay.confirm',
|
||||
component: PasswordChangeOverlay
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -35,6 +35,7 @@ import uiToggle from './ui-toggle.vue';
|
||||
import uiProperty from './ui-property.vue';
|
||||
import uiColorpicker from './ui-colorpicker.vue';
|
||||
import uiDatepicker from './ui-datepicker.vue';
|
||||
import uiDaterangepicker from './ui-daterangepicker.vue';
|
||||
import uiSelect from './ui-select.vue';
|
||||
import uiForm from './ui-form.vue';
|
||||
import uiFormHeader from './ui-form-header.vue';
|
||||
@@ -81,6 +82,7 @@ export {
|
||||
uiProperty,
|
||||
uiColorpicker,
|
||||
uiDatepicker,
|
||||
uiDaterangepicker,
|
||||
uiSelect,
|
||||
uiForm,
|
||||
uiFormHeader,
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<ui-form ref="form" class="ui-daterangepicker" v-slot="form">
|
||||
<div class="ui-daterangepicker-items">
|
||||
<div :class="{ 'ui-split': options.rangeEnd }">
|
||||
<div class="ui-daterangepicker-group">
|
||||
<ui-property :label="options.fromText" :vertical="true">
|
||||
<ui-datepicker v-model="fromDate" v-bind="options" />
|
||||
</ui-property>
|
||||
</div>
|
||||
<div class="ui-daterangepicker-group" v-if="options.rangeEnd">
|
||||
<ui-property :label="options.toText" :vertical="true">
|
||||
<ui-datepicker v-model="toDate" v-bind="options" />
|
||||
</ui-property>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-confirm-buttons">
|
||||
<ui-button type="primary" label="@ui.confirm" @click="confirm"></ui-button>
|
||||
<ui-button type="light" label="@ui.close" @click="config.close"></ui-button>
|
||||
</div>
|
||||
</ui-form>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
model: Object,
|
||||
config: Object,
|
||||
},
|
||||
data: () => ({
|
||||
options: {},
|
||||
disabled: false,
|
||||
fromDate: null,
|
||||
toDate: null
|
||||
}),
|
||||
mounted()
|
||||
{
|
||||
this.options = this.model.options;
|
||||
this.fromDate = this.model.from;
|
||||
this.toDate = this.model.to;
|
||||
},
|
||||
methods: {
|
||||
confirm()
|
||||
{
|
||||
this.config.confirm({
|
||||
from: this.fromDate,
|
||||
to: this.toDate
|
||||
}, this.config);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.ui-daterangepicker
|
||||
{
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h3.ui-daterangepicker-group-header
|
||||
{
|
||||
font-weight: 400;
|
||||
font-size: var(--font-size);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,157 @@
|
||||
<template>
|
||||
<div class="ui-daterangepicker" :class="{'is-disabled': disabled }">
|
||||
<button v-if="!inline" type="button" class="ui-link" @click="schedule" v-localize="scheduleLocalize" :disabled="disabled"></button>
|
||||
<div v-if="inline && value" class="ui-daterangepicker-inline">
|
||||
<div class="ui-daterangepicker-group">
|
||||
<ui-property :vertical="true">
|
||||
<ui-datepicker v-model="value.from" :time="time" />
|
||||
</ui-property>
|
||||
</div>
|
||||
<div class="ui-daterangepicker-group" v-if="rangeEnd">
|
||||
<ui-property :vertical="true">
|
||||
<ui-datepicker v-model="value.to" :time="time" />
|
||||
</ui-property>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script lang="ts">
|
||||
import { generateId } from '../utils/numbers';
|
||||
import { formatDate, toIsoDate } from '../utils/dates';
|
||||
import * as overlays from '../services/overlay';
|
||||
|
||||
const DATETIME_FORMAT = 'DD.MM.YY HH:mm';
|
||||
const DATE_FORMAT = 'DD.MM.YY';
|
||||
|
||||
|
||||
export default {
|
||||
name: 'uiDaterangepicker',
|
||||
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
default: {
|
||||
from: null,
|
||||
to: null
|
||||
}
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
format: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
time: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
maxDate: {
|
||||
type: [String, Date],
|
||||
default: null
|
||||
},
|
||||
minDate: {
|
||||
type: [String, Date],
|
||||
default: null
|
||||
},
|
||||
fromLabel: {
|
||||
type: String,
|
||||
default: '@ui.date.range_from'
|
||||
},
|
||||
toLabel: {
|
||||
type: String,
|
||||
default: '@ui.date.range_to'
|
||||
},
|
||||
amPm: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
inline: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
rangeEnd: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
options: {
|
||||
type: Object,
|
||||
default: () => { }
|
||||
}
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
id: null,
|
||||
output: null,
|
||||
pickerOptions: {}
|
||||
}),
|
||||
|
||||
computed: {
|
||||
scheduleLocalize()
|
||||
{
|
||||
return {
|
||||
key: !this.value || (!this.value.from && !this.value.to) ? '@ui.date.set' :
|
||||
(this.value.from && !this.value.to ? '@ui.date.x' :
|
||||
(!this.value.from && this.value.to ? '@ui.date.y' : '@ui.date.xtoy')),
|
||||
tokens: {
|
||||
x: this.value ? formatDate(this.value.from, this.format || (this.time ? DATETIME_FORMAT : DATE_FORMAT)) : null,
|
||||
y: this.value ? formatDate(this.value.to, this.format || (this.time ? DATETIME_FORMAT : DATE_FORMAT)) : null
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
created()
|
||||
{
|
||||
this.id = 'daterangepicker-' + generateId();
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
async schedule()
|
||||
{
|
||||
const result = await overlays.open({
|
||||
component: DaterangepickerOverlay,
|
||||
model: {
|
||||
from: this.value.from,
|
||||
to: this.value.to,
|
||||
options: {
|
||||
format: this.format,
|
||||
time: this.time,
|
||||
max: this.maxDate,
|
||||
min: this.minDate,
|
||||
fromText: this.fromLabel,
|
||||
toText: this.toLabel,
|
||||
amPm: this.amPm,
|
||||
rangeEnd: this.rangeEnd
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (result.eventType == 'confirm')
|
||||
{
|
||||
this.$emit('change', result.value);
|
||||
this.$emit('input', result.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.ui-daterangepicker.is-primary .ui-link
|
||||
{
|
||||
color: var(--color-primary);
|
||||
font-weight: 700;
|
||||
text-decoration-color: var(--color-primary) !important;
|
||||
}
|
||||
|
||||
.ui-daterangepicker-inline
|
||||
{
|
||||
display: flex;
|
||||
gap: var(--padding-s);
|
||||
}
|
||||
</style>
|
||||
@@ -1,39 +0,0 @@
|
||||
<!--<template>
|
||||
<div v-if="!loading" class="ui-native-select" :disabled="disabled">
|
||||
<select :value="value" @input="$emit('input', $event.target.value)" :disabled="disabled">
|
||||
<option v-for="item in items" :value="item.code">{{item.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
import LanguagesApi from 'zero/api/languages.js';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: String
|
||||
},
|
||||
config: Object,
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
loading: true,
|
||||
items: []
|
||||
}),
|
||||
|
||||
mounted()
|
||||
{
|
||||
LanguagesApi.getSupportedCultures().then(res =>
|
||||
{
|
||||
this.items = res;
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>-->
|
||||
@@ -1,17 +0,0 @@
|
||||
<template>
|
||||
<ui-spacepicker :value="value" @input="$emit('input', $event)" :limit="limit" :disabled="disabled" />
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
value: [String, Array],
|
||||
disabled: Boolean,
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -18,6 +18,7 @@ export default function createFields(app: ZeroPluginOptions): void
|
||||
app.fieldType('inputlist', defineAsyncComponent(() => import('./inputlist.vue')));
|
||||
app.fieldType('nested', defineAsyncComponent(() => import('./nested.vue')));
|
||||
app.fieldType('datePicker', defineAsyncComponent(() => import('./datePicker.vue')));
|
||||
app.fieldType('dateRangePicker', defineAsyncComponent(() => import('./dateRangePicker.vue')));
|
||||
app.fieldType('iconPicker', defineAsyncComponent(() => import('./iconPicker.vue')));
|
||||
app.fieldType('colorPicker', defineAsyncComponent(() => import('./colorPicker.vue')));
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<div class="ui-box">
|
||||
<ui-daterangepicker :value="value" @input="$emit('input', $event)" :disabled="config.disabled"
|
||||
v-bind="{ format, time: pickTime, maxDate, minDate, fromLabel, toLabel, amPm, inline }" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
default: {
|
||||
from: null,
|
||||
to: null
|
||||
}
|
||||
},
|
||||
config: Object,
|
||||
format: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
pickTime: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
maxDate: {
|
||||
type: [String, Date],
|
||||
default: null
|
||||
},
|
||||
minDate: {
|
||||
type: [String, Date],
|
||||
default: null
|
||||
},
|
||||
fromLabel: {
|
||||
type: String,
|
||||
default: '@ui.date.range_from'
|
||||
},
|
||||
toLabel: {
|
||||
type: String,
|
||||
default: '@ui.date.range_to'
|
||||
},
|
||||
amPm: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
inline: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -88,6 +88,12 @@ declare module 'zero/schemas'
|
||||
*/
|
||||
datePicker(options?: DatePickerFieldOptions): ZeroEditorField;
|
||||
|
||||
/**
|
||||
* Create a date range picker
|
||||
* @param {DateRangePickerFieldOptions} options - Custom options
|
||||
*/
|
||||
dateRangePicker(options?: DateRangePickerFieldOptions): ZeroEditorField;
|
||||
|
||||
/**
|
||||
* Create an icon picker
|
||||
* @param {DatePickerFieldOptions} options - Custom options
|
||||
@@ -107,6 +113,13 @@ declare module 'zero/schemas'
|
||||
colors?: boolean;
|
||||
}
|
||||
|
||||
export interface DateRangePickerFieldOptions extends DatePickerFieldOptions
|
||||
{
|
||||
inline?: boolean;
|
||||
fromLabel?: string;
|
||||
toLabel?: string;
|
||||
}
|
||||
|
||||
export interface DatePickerFieldOptions
|
||||
{
|
||||
format?: string;
|
||||
|
||||
Reference in New Issue
Block a user