2016-07-27 06:15:02 +00:00
|
|
|
<template>
|
2016-12-08 16:06:34 +00:00
|
|
|
<el-input
|
2016-07-27 06:15:02 +00:00
|
|
|
class="el-date-editor"
|
2016-12-28 10:33:45 +00:00
|
|
|
:class="'el-date-editor--' + type"
|
2016-12-08 16:06:34 +00:00
|
|
|
:readonly="!editable || readonly"
|
|
|
|
:disabled="disabled"
|
|
|
|
:size="size"
|
2017-07-30 08:26:05 +00:00
|
|
|
:name="name"
|
2017-09-23 04:46:37 +00:00
|
|
|
v-if="!ranged"
|
2016-08-09 02:10:33 +00:00
|
|
|
v-clickoutside="handleClose"
|
2016-12-08 16:06:34 +00:00
|
|
|
:placeholder="placeholder"
|
|
|
|
@focus="handleFocus"
|
|
|
|
@blur="handleBlur"
|
|
|
|
@keydown.native="handleKeydown"
|
2017-01-03 09:38:44 +00:00
|
|
|
:value="displayValue"
|
2017-10-10 09:49:41 +00:00
|
|
|
@input="value => userInput = value"
|
2017-09-19 14:35:57 +00:00
|
|
|
@mouseenter.native="handleMouseEnter"
|
|
|
|
@mouseleave.native="showClose = false"
|
2017-10-10 09:49:41 +00:00
|
|
|
@change.native="handleChange"
|
2017-02-12 15:29:48 +00:00
|
|
|
:validateEvent="false"
|
2017-09-19 14:35:57 +00:00
|
|
|
:prefix-icon="triggerClass"
|
2016-12-08 16:06:34 +00:00
|
|
|
ref="reference">
|
2017-09-14 11:34:15 +00:00
|
|
|
<i slot="suffix"
|
2016-12-08 16:06:34 +00:00
|
|
|
class="el-input__icon"
|
|
|
|
@click="handleClickIcon"
|
2017-09-19 14:35:57 +00:00
|
|
|
:class="{ 'el-icon-circle-close': showClose }"
|
2016-07-27 06:15:02 +00:00
|
|
|
v-if="haveTrigger">
|
2016-12-08 16:06:34 +00:00
|
|
|
</i>
|
|
|
|
</el-input>
|
2017-09-23 04:46:37 +00:00
|
|
|
<div
|
|
|
|
class="el-date-editor el-range-editor el-input__inner"
|
|
|
|
:class="[
|
|
|
|
'el-date-editor--' + type,
|
|
|
|
'el-range-editor--' + size,
|
|
|
|
pickerVisible ? 'is-active' : ''
|
|
|
|
]"
|
|
|
|
@click="handleRangeClick"
|
|
|
|
@mouseenter="handleMouseEnter"
|
|
|
|
@mouseleave="showClose = false"
|
2017-10-10 09:49:41 +00:00
|
|
|
@keydown="handleKeydown"
|
2017-09-23 04:46:37 +00:00
|
|
|
ref="reference"
|
|
|
|
v-clickoutside="handleClose"
|
|
|
|
v-else>
|
|
|
|
<i :class="['el-input__icon', 'el-range__icon', triggerClass]"></i>
|
|
|
|
<input
|
|
|
|
:placeholder="startPlaceholder"
|
|
|
|
:value="displayValue && displayValue[0]"
|
2017-10-10 09:49:41 +00:00
|
|
|
@input="handleStartInput"
|
2017-09-23 04:46:37 +00:00
|
|
|
@change="handleStartChange"
|
2017-10-10 09:49:41 +00:00
|
|
|
@focus="handleFocus"
|
2017-09-23 04:46:37 +00:00
|
|
|
class="el-range-input">
|
|
|
|
<span class="el-range-separator">{{ rangeSeparator }}</span>
|
|
|
|
<input
|
|
|
|
:placeholder="endPlaceholder"
|
|
|
|
:value="displayValue && displayValue[1]"
|
2017-10-10 09:49:41 +00:00
|
|
|
@input="handleEndInput"
|
2017-09-23 04:46:37 +00:00
|
|
|
@change="handleEndChange"
|
2017-10-10 09:49:41 +00:00
|
|
|
@focus="handleFocus"
|
2017-09-23 04:46:37 +00:00
|
|
|
class="el-range-input">
|
|
|
|
<i
|
|
|
|
@click="handleClickIcon"
|
|
|
|
v-if="haveTrigger"
|
|
|
|
:class="{ 'el-icon-circle-close': showClose }"
|
|
|
|
class="el-input__icon el-range__close-icon">
|
|
|
|
</i>
|
|
|
|
</div>
|
2016-07-27 06:15:02 +00:00
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
import Vue from 'vue';
|
2016-10-13 03:12:24 +00:00
|
|
|
import Clickoutside from 'element-ui/src/utils/clickoutside';
|
2017-10-10 09:49:41 +00:00
|
|
|
import { formatDate, parseDate, isDate, getWeekNumber } from './util';
|
2016-10-13 03:12:24 +00:00
|
|
|
import Popper from 'element-ui/src/utils/vue-popper';
|
2016-10-27 09:31:22 +00:00
|
|
|
import Emitter from 'element-ui/src/mixins/emitter';
|
2017-07-18 05:47:35 +00:00
|
|
|
import Focus from 'element-ui/src/mixins/focus';
|
2016-12-08 16:06:34 +00:00
|
|
|
import ElInput from 'element-ui/packages/input';
|
2017-08-05 08:35:42 +00:00
|
|
|
import merge from 'element-ui/src/utils/merge';
|
2016-07-27 06:15:02 +00:00
|
|
|
|
2016-10-27 09:31:22 +00:00
|
|
|
const NewPopper = {
|
2016-10-12 09:41:49 +00:00
|
|
|
props: {
|
|
|
|
appendToBody: Popper.props.appendToBody,
|
|
|
|
offset: Popper.props.offset,
|
|
|
|
boundariesPadding: Popper.props.boundariesPadding
|
|
|
|
},
|
|
|
|
methods: Popper.methods,
|
2017-09-19 14:35:57 +00:00
|
|
|
data() {
|
|
|
|
return merge({ visibleArrow: true }, Popper.data);
|
|
|
|
},
|
2016-10-12 09:41:49 +00:00
|
|
|
beforeDestroy: Popper.beforeDestroy
|
|
|
|
};
|
|
|
|
|
2016-07-27 06:15:02 +00:00
|
|
|
const DEFAULT_FORMATS = {
|
|
|
|
date: 'yyyy-MM-dd',
|
|
|
|
month: 'yyyy-MM',
|
|
|
|
datetime: 'yyyy-MM-dd HH:mm:ss',
|
|
|
|
time: 'HH:mm:ss',
|
2017-03-24 07:44:23 +00:00
|
|
|
week: 'yyyywWW',
|
2016-07-27 06:15:02 +00:00
|
|
|
timerange: 'HH:mm:ss',
|
|
|
|
daterange: 'yyyy-MM-dd',
|
2016-11-26 15:19:08 +00:00
|
|
|
datetimerange: 'yyyy-MM-dd HH:mm:ss',
|
|
|
|
year: 'yyyy'
|
2016-07-27 06:15:02 +00:00
|
|
|
};
|
|
|
|
const HAVE_TRIGGER_TYPES = [
|
|
|
|
'date',
|
|
|
|
'datetime',
|
|
|
|
'time',
|
|
|
|
'time-select',
|
|
|
|
'week',
|
|
|
|
'month',
|
|
|
|
'year',
|
|
|
|
'daterange',
|
|
|
|
'timerange',
|
|
|
|
'datetimerange'
|
|
|
|
];
|
|
|
|
const DATE_FORMATTER = function(value, format) {
|
|
|
|
return formatDate(value, format);
|
|
|
|
};
|
|
|
|
const DATE_PARSER = function(text, format) {
|
|
|
|
return parseDate(text, format);
|
|
|
|
};
|
2017-09-23 04:46:37 +00:00
|
|
|
const RANGE_FORMATTER = function(value, format) {
|
2016-07-27 06:15:02 +00:00
|
|
|
if (Array.isArray(value) && value.length === 2) {
|
|
|
|
const start = value[0];
|
|
|
|
const end = value[1];
|
|
|
|
|
|
|
|
if (start && end) {
|
2017-09-23 04:46:37 +00:00
|
|
|
return [formatDate(start, format), formatDate(end, format)];
|
2016-07-27 06:15:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return '';
|
|
|
|
};
|
2017-09-23 04:46:37 +00:00
|
|
|
const RANGE_PARSER = function(array, format, separator) {
|
|
|
|
if (!Array.isArray(array)) {
|
|
|
|
array = array.split(separator);
|
|
|
|
}
|
2016-07-27 06:15:02 +00:00
|
|
|
if (array.length === 2) {
|
2016-12-13 14:51:43 +00:00
|
|
|
const range1 = array[0];
|
|
|
|
const range2 = array[1];
|
|
|
|
|
2016-07-27 06:15:02 +00:00
|
|
|
return [parseDate(range1, format), parseDate(range2, format)];
|
|
|
|
}
|
|
|
|
return [];
|
|
|
|
};
|
|
|
|
const TYPE_VALUE_RESOLVER_MAP = {
|
|
|
|
default: {
|
|
|
|
formatter(value) {
|
|
|
|
if (!value) return '';
|
|
|
|
return '' + value;
|
|
|
|
},
|
|
|
|
parser(text) {
|
|
|
|
if (text === undefined || text === '') return null;
|
|
|
|
return text;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
week: {
|
2017-03-24 07:44:23 +00:00
|
|
|
formatter(value, format) {
|
|
|
|
let date = formatDate(value, format);
|
|
|
|
const week = getWeekNumber(value);
|
|
|
|
|
|
|
|
date = /WW/.test(date)
|
|
|
|
? date.replace(/WW/, week < 10 ? '0' + week : week)
|
|
|
|
: date.replace(/W/, week);
|
|
|
|
return date;
|
2016-07-27 06:15:02 +00:00
|
|
|
},
|
|
|
|
parser(text) {
|
|
|
|
const array = (text || '').split('w');
|
|
|
|
if (array.length === 2) {
|
|
|
|
const year = Number(array[0]);
|
|
|
|
const month = Number(array[1]);
|
|
|
|
|
|
|
|
if (!isNaN(year) && !isNaN(month) && month < 54) {
|
|
|
|
return text;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
date: {
|
|
|
|
formatter: DATE_FORMATTER,
|
|
|
|
parser: DATE_PARSER
|
|
|
|
},
|
|
|
|
datetime: {
|
|
|
|
formatter: DATE_FORMATTER,
|
|
|
|
parser: DATE_PARSER
|
|
|
|
},
|
|
|
|
daterange: {
|
|
|
|
formatter: RANGE_FORMATTER,
|
|
|
|
parser: RANGE_PARSER
|
|
|
|
},
|
|
|
|
datetimerange: {
|
|
|
|
formatter: RANGE_FORMATTER,
|
|
|
|
parser: RANGE_PARSER
|
|
|
|
},
|
|
|
|
timerange: {
|
|
|
|
formatter: RANGE_FORMATTER,
|
|
|
|
parser: RANGE_PARSER
|
|
|
|
},
|
|
|
|
time: {
|
|
|
|
formatter: DATE_FORMATTER,
|
|
|
|
parser: DATE_PARSER
|
|
|
|
},
|
|
|
|
month: {
|
|
|
|
formatter: DATE_FORMATTER,
|
|
|
|
parser: DATE_PARSER
|
|
|
|
},
|
|
|
|
year: {
|
2016-11-26 15:19:08 +00:00
|
|
|
formatter: DATE_FORMATTER,
|
|
|
|
parser: DATE_PARSER
|
2016-07-27 06:15:02 +00:00
|
|
|
},
|
|
|
|
number: {
|
|
|
|
formatter(value) {
|
|
|
|
if (!value) return '';
|
|
|
|
return '' + value;
|
|
|
|
},
|
|
|
|
parser(text) {
|
|
|
|
let result = Number(text);
|
|
|
|
|
|
|
|
if (!isNaN(text)) {
|
|
|
|
return result;
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2016-09-21 04:46:53 +00:00
|
|
|
const PLACEMENT_MAP = {
|
|
|
|
left: 'bottom-start',
|
2017-07-20 03:27:01 +00:00
|
|
|
center: 'bottom',
|
2016-09-21 04:46:53 +00:00
|
|
|
right: 'bottom-end'
|
|
|
|
};
|
2016-07-27 06:15:02 +00:00
|
|
|
|
2017-10-10 09:49:41 +00:00
|
|
|
const parseAsFormatAndType = (value, cutsomFormat, type, rangeSeparator = '-') => {
|
|
|
|
if (!value) return null;
|
|
|
|
const parser = (
|
|
|
|
TYPE_VALUE_RESOLVER_MAP[type] ||
|
|
|
|
TYPE_VALUE_RESOLVER_MAP['default']
|
|
|
|
).parser;
|
|
|
|
const format = cutsomFormat || DEFAULT_FORMATS[type];
|
|
|
|
return parser(value, format, rangeSeparator);
|
|
|
|
};
|
|
|
|
|
|
|
|
const formatAsFormatAndType = (value, cutsomFormat, type) => {
|
|
|
|
if (!value) return null;
|
|
|
|
const formatter = (
|
|
|
|
TYPE_VALUE_RESOLVER_MAP[type] ||
|
|
|
|
TYPE_VALUE_RESOLVER_MAP['default']
|
|
|
|
).formatter;
|
|
|
|
const format = cutsomFormat || DEFAULT_FORMATS[type];
|
|
|
|
return formatter(value, format);
|
|
|
|
};
|
|
|
|
|
2017-05-04 10:11:47 +00:00
|
|
|
// only considers date-picker's value: Date or [Date, Date]
|
|
|
|
const valueEquals = function(a, b) {
|
|
|
|
const aIsArray = a instanceof Array;
|
|
|
|
const bIsArray = b instanceof Array;
|
|
|
|
if (aIsArray && bIsArray) {
|
|
|
|
return new Date(a[0]).getTime() === new Date(b[0]).getTime() &&
|
|
|
|
new Date(a[1]).getTime() === new Date(b[1]).getTime();
|
|
|
|
}
|
|
|
|
if (!aIsArray && !bIsArray) {
|
|
|
|
return new Date(a).getTime() === new Date(b).getTime();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2016-07-27 06:15:02 +00:00
|
|
|
export default {
|
2017-07-18 05:47:35 +00:00
|
|
|
mixins: [Emitter, NewPopper, Focus('reference')],
|
2016-08-29 11:19:14 +00:00
|
|
|
|
2016-07-27 06:15:02 +00:00
|
|
|
props: {
|
2016-12-08 16:06:34 +00:00
|
|
|
size: String,
|
2016-07-27 06:15:02 +00:00
|
|
|
format: String,
|
2017-10-10 09:49:41 +00:00
|
|
|
valueFormat: String,
|
2016-07-27 06:15:02 +00:00
|
|
|
readonly: Boolean,
|
|
|
|
placeholder: String,
|
2017-09-23 04:46:37 +00:00
|
|
|
startPlaceholder: String,
|
|
|
|
endPlaceholder: String,
|
2017-07-30 08:26:05 +00:00
|
|
|
name: String,
|
2016-11-13 03:45:38 +00:00
|
|
|
disabled: Boolean,
|
2016-12-26 15:02:40 +00:00
|
|
|
clearable: {
|
|
|
|
type: Boolean,
|
|
|
|
default: true
|
|
|
|
},
|
2016-12-20 08:38:47 +00:00
|
|
|
popperClass: String,
|
2016-11-13 03:45:38 +00:00
|
|
|
editable: {
|
|
|
|
type: Boolean,
|
|
|
|
default: true
|
|
|
|
},
|
2016-09-21 04:46:53 +00:00
|
|
|
align: {
|
|
|
|
type: String,
|
|
|
|
default: 'left'
|
|
|
|
},
|
2016-07-27 06:15:02 +00:00
|
|
|
value: {},
|
2017-04-14 15:33:20 +00:00
|
|
|
defaultValue: {},
|
2017-01-23 07:35:06 +00:00
|
|
|
rangeSeparator: {
|
2017-09-23 04:46:37 +00:00
|
|
|
default: '-'
|
2017-01-23 07:35:06 +00:00
|
|
|
},
|
2016-07-27 06:15:02 +00:00
|
|
|
pickerOptions: {}
|
|
|
|
},
|
|
|
|
|
2016-12-08 16:06:34 +00:00
|
|
|
components: { ElInput },
|
|
|
|
|
2016-10-20 12:12:21 +00:00
|
|
|
directives: { Clickoutside },
|
2016-07-27 06:15:02 +00:00
|
|
|
|
|
|
|
data() {
|
|
|
|
return {
|
2016-11-13 07:57:34 +00:00
|
|
|
pickerVisible: false,
|
|
|
|
showClose: false,
|
2017-10-10 09:49:41 +00:00
|
|
|
userInput: null,
|
|
|
|
valueOnOpen: null, // value when picker opens, used to determine whether to emit change
|
2017-04-28 04:28:09 +00:00
|
|
|
unwatchPickerOptions: null
|
2016-07-27 06:15:02 +00:00
|
|
|
};
|
|
|
|
},
|
|
|
|
|
|
|
|
watch: {
|
|
|
|
pickerVisible(val) {
|
2016-11-13 03:45:38 +00:00
|
|
|
if (this.readonly || this.disabled) return;
|
2017-10-10 09:49:41 +00:00
|
|
|
if (val) {
|
|
|
|
this.showPicker();
|
|
|
|
this.valueOnOpen = this.value;
|
2017-01-03 09:38:44 +00:00
|
|
|
} else {
|
2017-10-10 09:49:41 +00:00
|
|
|
this.hidePicker();
|
|
|
|
this.emitChange(this.value);
|
|
|
|
// flush user input if it is parsable
|
|
|
|
// this.displayValue here is not a typo, it merges text for both panels in range mode
|
|
|
|
const parsedValue = this.parseString(this.displayValue);
|
|
|
|
if (this.userInput && parsedValue && this.isValidValue(parsedValue)) {
|
|
|
|
this.userInput = null;
|
|
|
|
}
|
|
|
|
this.dispatch('ElFormItem', 'el.form.blur');
|
|
|
|
this.blur();
|
2016-11-07 08:26:03 +00:00
|
|
|
}
|
2016-11-13 07:57:34 +00:00
|
|
|
},
|
2017-10-10 09:49:41 +00:00
|
|
|
parsedValue: {
|
2016-11-13 07:57:34 +00:00
|
|
|
immediate: true,
|
|
|
|
handler(val) {
|
2017-10-10 09:49:41 +00:00
|
|
|
if (this.picker) {
|
|
|
|
this.picker.value = val;
|
|
|
|
}
|
2016-11-13 07:57:34 +00:00
|
|
|
}
|
2017-01-03 09:38:44 +00:00
|
|
|
},
|
2017-10-10 09:49:41 +00:00
|
|
|
defaultValue(val) {
|
|
|
|
// NOTE: should eventually move to jsx style picker + panel ?
|
|
|
|
if (this.picker) {
|
|
|
|
this.picker.defaultValue = val;
|
|
|
|
}
|
2016-07-27 06:15:02 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
computed: {
|
2017-09-23 04:46:37 +00:00
|
|
|
ranged() {
|
|
|
|
return this.type.indexOf('range') > -1;
|
|
|
|
},
|
|
|
|
|
2016-12-08 16:06:34 +00:00
|
|
|
reference() {
|
2017-09-23 04:46:37 +00:00
|
|
|
const reference = this.$refs.reference;
|
|
|
|
return reference.$el || reference;
|
2016-12-08 16:06:34 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
refInput() {
|
2017-09-23 04:46:37 +00:00
|
|
|
if (this.reference) {
|
|
|
|
return [].slice.call(this.reference.querySelectorAll('input'));
|
|
|
|
}
|
|
|
|
return [];
|
2016-12-08 16:06:34 +00:00
|
|
|
},
|
|
|
|
|
2016-11-13 07:57:34 +00:00
|
|
|
valueIsEmpty() {
|
2017-10-10 09:49:41 +00:00
|
|
|
const val = this.value;
|
2016-11-13 07:57:34 +00:00
|
|
|
if (Array.isArray(val)) {
|
2016-12-08 16:06:34 +00:00
|
|
|
for (let i = 0, len = val.length; i < len; i++) {
|
2016-11-13 07:57:34 +00:00
|
|
|
if (val[i]) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (val) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
|
2016-07-27 06:15:02 +00:00
|
|
|
triggerClass() {
|
|
|
|
return this.type.indexOf('time') !== -1 ? 'el-icon-time' : 'el-icon-date';
|
|
|
|
},
|
|
|
|
|
|
|
|
selectionMode() {
|
|
|
|
if (this.type === 'week') {
|
|
|
|
return 'week';
|
|
|
|
} else if (this.type === 'month') {
|
|
|
|
return 'month';
|
|
|
|
} else if (this.type === 'year') {
|
|
|
|
return 'year';
|
|
|
|
}
|
|
|
|
|
|
|
|
return 'day';
|
|
|
|
},
|
|
|
|
|
|
|
|
haveTrigger() {
|
|
|
|
if (typeof this.showTrigger !== 'undefined') {
|
|
|
|
return this.showTrigger;
|
|
|
|
}
|
|
|
|
return HAVE_TRIGGER_TYPES.indexOf(this.type) !== -1;
|
|
|
|
},
|
|
|
|
|
2017-10-10 09:49:41 +00:00
|
|
|
displayValue() {
|
|
|
|
const formattedValue = formatAsFormatAndType(this.parsedValue, this.format, this.type, this.rangeSeparator);
|
|
|
|
if (Array.isArray(this.userInput)) {
|
|
|
|
return [
|
|
|
|
this.userInput[0] || (formattedValue && formattedValue[0]) || '',
|
|
|
|
this.userInput[1] || (formattedValue && formattedValue[1]) || ''
|
|
|
|
];
|
|
|
|
} else {
|
|
|
|
return this.userInput !== null ? this.userInput : formattedValue || '';
|
|
|
|
}
|
|
|
|
},
|
2016-07-27 06:15:02 +00:00
|
|
|
|
2017-10-10 09:49:41 +00:00
|
|
|
parsedValue() {
|
|
|
|
const isParsed = isDate(this.value) || (Array.isArray(this.value) && this.value.every(isDate));
|
|
|
|
if (this.valueFormat && !isParsed) {
|
|
|
|
return parseAsFormatAndType(this.value, this.valueFormat, this.type, this.rangeSeparator) || this.value;
|
|
|
|
} else {
|
|
|
|
return this.value;
|
2016-07-27 06:15:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2016-10-12 09:41:49 +00:00
|
|
|
created() {
|
|
|
|
// vue-popper
|
2017-01-18 09:17:59 +00:00
|
|
|
this.popperOptions = {
|
2016-10-12 09:41:49 +00:00
|
|
|
boundariesPadding: 0,
|
|
|
|
gpuAcceleration: false
|
|
|
|
};
|
|
|
|
this.placement = PLACEMENT_MAP[this.align] || PLACEMENT_MAP.left;
|
|
|
|
},
|
|
|
|
|
2016-07-27 06:15:02 +00:00
|
|
|
methods: {
|
2017-10-10 09:49:41 +00:00
|
|
|
blur() {
|
|
|
|
this.refInput.forEach(input => input.blur());
|
|
|
|
},
|
|
|
|
|
|
|
|
// {parse, formatTo} Value deals maps component value with internal Date
|
|
|
|
// parseValue validates value according to panel, requires picker to be mounted
|
|
|
|
parseValue(value, customFormat) {
|
|
|
|
if (!value || (!Array.isArray(value) || !value.every(val => val))) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
const format = customFormat || this.valueFormat;
|
|
|
|
const parsedValue = parseAsFormatAndType(value, format, this.type, this.rangeSeparator);
|
|
|
|
return this.isValidValue(parsedValue) ? parsedValue : null;
|
|
|
|
},
|
|
|
|
|
|
|
|
formatToValue(date, customFormat) {
|
|
|
|
if (this.valueFormat && (isDate(date) || Array.isArray(date))) {
|
|
|
|
const format = customFormat || this.valueFormat;
|
|
|
|
return formatAsFormatAndType(date, format, this.type, this.rangeSeparator);
|
|
|
|
} else {
|
|
|
|
return date;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
// {parse, formatTo} String deals with user input
|
|
|
|
parseString(value) {
|
|
|
|
const type = Array.isArray(value) ? this.type : this.type.replace('range', '');
|
|
|
|
return parseAsFormatAndType(value, this.format, type);
|
|
|
|
},
|
|
|
|
|
|
|
|
formatToString(value) {
|
|
|
|
const type = Array.isArray(value) ? this.type : this.type.replace('range', '');
|
|
|
|
return formatAsFormatAndType(value, this.format, type);
|
|
|
|
},
|
|
|
|
|
2017-09-19 14:35:57 +00:00
|
|
|
handleMouseEnter() {
|
2016-11-24 06:14:02 +00:00
|
|
|
if (this.readonly || this.disabled) return;
|
2016-12-26 15:02:40 +00:00
|
|
|
if (!this.valueIsEmpty && this.clearable) {
|
2016-11-13 07:57:34 +00:00
|
|
|
this.showClose = true;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2017-10-10 09:49:41 +00:00
|
|
|
handleChange() {
|
|
|
|
if (this.userInput) {
|
|
|
|
const value = this.parseString(this.displayValue);
|
|
|
|
if (value) {
|
|
|
|
this.picker.value = value;
|
|
|
|
if (this.isValidValue(value)) {
|
|
|
|
this.emitInput(value);
|
|
|
|
this.userInput = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
handleStartInput(event) {
|
|
|
|
if (this.userInput) {
|
|
|
|
this.userInput = [event.target.value, this.userInput[1]];
|
2017-09-23 04:46:37 +00:00
|
|
|
} else {
|
2017-10-10 09:49:41 +00:00
|
|
|
this.userInput = [event.target.value, null];
|
2017-09-23 04:46:37 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2017-10-10 09:49:41 +00:00
|
|
|
handleEndInput(event) {
|
|
|
|
if (this.userInput) {
|
|
|
|
this.userInput = [this.userInput[0], event.target.value];
|
2017-09-23 04:46:37 +00:00
|
|
|
} else {
|
2017-10-10 09:49:41 +00:00
|
|
|
this.userInput = [null, event.target.value];
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
handleStartChange(event) {
|
|
|
|
const value = this.parseString(this.userInput && this.userInput[0]);
|
|
|
|
if (value) {
|
|
|
|
this.userInput = [this.formatToString(value), this.displayValue[1]];
|
|
|
|
const newValue = [value, this.picker.value && this.picker.value[1]];
|
|
|
|
this.picker.value = newValue;
|
|
|
|
if (this.isValidValue(newValue)) {
|
|
|
|
this.emitInput(newValue);
|
|
|
|
this.userInput = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
handleEndChange(event) {
|
|
|
|
const value = this.parseString(this.userInput && this.userInput[1]);
|
|
|
|
if (value) {
|
|
|
|
this.userInput = [this.displayValue[0], this.formatToString(value)];
|
|
|
|
const newValue = [this.picker.value && this.picker.value[0], value];
|
|
|
|
this.picker.value = newValue;
|
|
|
|
if (this.isValidValue(newValue)) {
|
|
|
|
this.emitInput(newValue);
|
|
|
|
this.userInput = null;
|
|
|
|
}
|
2017-09-23 04:46:37 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
handleClickIcon(event) {
|
2016-11-24 06:14:02 +00:00
|
|
|
if (this.readonly || this.disabled) return;
|
2016-12-26 15:02:40 +00:00
|
|
|
if (this.showClose) {
|
2017-09-23 04:46:37 +00:00
|
|
|
event.stopPropagation();
|
2017-10-10 09:49:41 +00:00
|
|
|
this.emitInput(null);
|
|
|
|
this.emitChange(null);
|
|
|
|
this.showClose = false;
|
|
|
|
if (this.picker && typeof this.picker.handleClear === 'function') {
|
|
|
|
this.picker.handleClear();
|
2017-01-03 09:38:44 +00:00
|
|
|
}
|
2016-11-13 07:57:34 +00:00
|
|
|
} else {
|
2017-10-10 09:49:41 +00:00
|
|
|
this.pickerVisible = !this.pickerVisible;
|
2016-11-13 07:57:34 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2016-08-09 02:10:33 +00:00
|
|
|
handleClose() {
|
|
|
|
this.pickerVisible = false;
|
2017-09-23 04:46:37 +00:00
|
|
|
if (this.ranged) {
|
|
|
|
this.$emit('blur', this);
|
|
|
|
}
|
2016-08-09 02:10:33 +00:00
|
|
|
},
|
|
|
|
|
2016-07-27 06:15:02 +00:00
|
|
|
handleFocus() {
|
|
|
|
const type = this.type;
|
|
|
|
|
2016-10-02 10:31:29 +00:00
|
|
|
if (HAVE_TRIGGER_TYPES.indexOf(type) !== -1 && !this.pickerVisible) {
|
|
|
|
this.pickerVisible = true;
|
2016-07-27 06:15:02 +00:00
|
|
|
}
|
|
|
|
this.$emit('focus', this);
|
|
|
|
},
|
|
|
|
|
|
|
|
handleBlur() {
|
|
|
|
this.$emit('blur', this);
|
|
|
|
},
|
|
|
|
|
|
|
|
handleKeydown(event) {
|
|
|
|
const keyCode = event.keyCode;
|
|
|
|
|
2017-10-10 09:49:41 +00:00
|
|
|
// ESC
|
|
|
|
if (keyCode === 27) {
|
2016-10-13 08:11:06 +00:00
|
|
|
this.pickerVisible = false;
|
2017-05-29 13:01:00 +00:00
|
|
|
event.stopPropagation();
|
2017-10-10 09:49:41 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tab
|
|
|
|
if (keyCode === 9) {
|
|
|
|
if (!this.ranged) {
|
|
|
|
this.handleChange();
|
|
|
|
this.pickerVisible = this.picker.visible = false;
|
|
|
|
this.blur();
|
|
|
|
event.stopPropagation();
|
|
|
|
} else {
|
|
|
|
// user may change focus between two input
|
|
|
|
setTimeout(() => {
|
|
|
|
if (this.refInput.indexOf(document.activeElement) === -1) {
|
|
|
|
this.pickerVisible = false;
|
|
|
|
this.blur();
|
|
|
|
event.stopPropagation();
|
|
|
|
}
|
|
|
|
}, 0);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Enter
|
|
|
|
if (keyCode === 13 && this.displayValue) {
|
|
|
|
const value = this.parseString(this.displayValue);
|
|
|
|
if (this.isValidValue(value)) {
|
|
|
|
this.handleChange();
|
|
|
|
this.pickerVisible = this.picker.visible = false;
|
|
|
|
this.blur();
|
|
|
|
}
|
|
|
|
event.stopPropagation();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if user is typing, do not let picker handle key input
|
|
|
|
if (this.userInput) {
|
|
|
|
event.stopPropagation();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// delegate other keys to panel
|
|
|
|
if (this.picker && this.picker.handleKeydown) {
|
|
|
|
this.picker.handleKeydown(event);
|
2016-07-27 06:15:02 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2017-09-23 04:46:37 +00:00
|
|
|
handleRangeClick() {
|
|
|
|
const type = this.type;
|
|
|
|
|
|
|
|
if (HAVE_TRIGGER_TYPES.indexOf(type) !== -1 && !this.pickerVisible) {
|
|
|
|
this.pickerVisible = true;
|
|
|
|
}
|
|
|
|
this.$emit('focus', this);
|
|
|
|
},
|
|
|
|
|
2016-07-27 06:15:02 +00:00
|
|
|
hidePicker() {
|
|
|
|
if (this.picker) {
|
|
|
|
this.picker.resetView && this.picker.resetView();
|
|
|
|
this.pickerVisible = this.picker.visible = false;
|
|
|
|
this.destroyPopper();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
showPicker() {
|
2016-12-26 02:45:20 +00:00
|
|
|
if (this.$isServer) return;
|
2016-07-27 06:15:02 +00:00
|
|
|
if (!this.picker) {
|
2017-04-28 04:28:09 +00:00
|
|
|
this.mountPicker();
|
2016-07-27 06:15:02 +00:00
|
|
|
}
|
2017-04-28 04:28:09 +00:00
|
|
|
this.pickerVisible = this.picker.visible = true;
|
2016-07-27 06:15:02 +00:00
|
|
|
|
2016-10-12 09:41:49 +00:00
|
|
|
this.updatePopper();
|
2016-07-27 06:15:02 +00:00
|
|
|
|
2017-10-10 09:49:41 +00:00
|
|
|
this.picker.value = this.parsedValue;
|
2016-12-08 16:06:34 +00:00
|
|
|
this.picker.resetView && this.picker.resetView();
|
2016-07-27 06:15:02 +00:00
|
|
|
|
|
|
|
this.$nextTick(() => {
|
2017-10-10 09:49:41 +00:00
|
|
|
this.picker.adjustSpinners && this.picker.adjustSpinners();
|
2016-07-27 06:15:02 +00:00
|
|
|
});
|
2017-04-28 04:28:09 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
mountPicker() {
|
2017-10-10 09:49:41 +00:00
|
|
|
this.picker = new Vue(this.panel).$mount();
|
|
|
|
this.picker.defaultValue = this.defaultValue;
|
2017-04-28 04:28:09 +00:00
|
|
|
this.picker.popperClass = this.popperClass;
|
|
|
|
this.popperElm = this.picker.$el;
|
|
|
|
this.picker.width = this.reference.getBoundingClientRect().width;
|
|
|
|
this.picker.showTime = this.type === 'datetime' || this.type === 'datetimerange';
|
|
|
|
this.picker.selectionMode = this.selectionMode;
|
2017-10-11 10:00:58 +00:00
|
|
|
this.picker.arrowControl = this.arrowControl || this.timeArrowControl || false;
|
2017-04-28 04:28:09 +00:00
|
|
|
if (this.format) {
|
|
|
|
this.picker.format = this.format;
|
|
|
|
}
|
|
|
|
|
|
|
|
const updateOptions = () => {
|
|
|
|
const options = this.pickerOptions;
|
|
|
|
|
|
|
|
if (options && options.selectableRange) {
|
|
|
|
let ranges = options.selectableRange;
|
|
|
|
const parser = TYPE_VALUE_RESOLVER_MAP.datetimerange.parser;
|
|
|
|
const format = DEFAULT_FORMATS.timerange;
|
|
|
|
|
|
|
|
ranges = Array.isArray(ranges) ? ranges : [ranges];
|
|
|
|
this.picker.selectableRange = ranges.map(range => parser(range, format, this.rangeSeparator));
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const option in options) {
|
|
|
|
if (options.hasOwnProperty(option) &&
|
|
|
|
// 忽略 time-picker 的该配置项
|
|
|
|
option !== 'selectableRange') {
|
|
|
|
this.picker[option] = options[option];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
updateOptions();
|
|
|
|
this.unwatchPickerOptions = this.$watch('pickerOptions', () => updateOptions(), { deep: true });
|
|
|
|
|
|
|
|
this.$el.appendChild(this.picker.$el);
|
|
|
|
this.picker.resetView && this.picker.resetView();
|
|
|
|
|
|
|
|
this.picker.$on('dodestroy', this.doDestroy);
|
2017-10-10 09:49:41 +00:00
|
|
|
this.picker.$on('pick', (date = '', visible = false) => {
|
|
|
|
this.userInput = null;
|
2017-04-28 04:28:09 +00:00
|
|
|
this.pickerVisible = this.picker.visible = visible;
|
2017-10-10 09:49:41 +00:00
|
|
|
this.emitInput(date);
|
2017-04-28 04:28:09 +00:00
|
|
|
this.picker.resetView && this.picker.resetView();
|
|
|
|
});
|
|
|
|
|
2017-09-23 04:46:37 +00:00
|
|
|
this.picker.$on('select-range', (start, end, pos) => {
|
|
|
|
if (this.refInput.length === 0) return;
|
|
|
|
if (!pos || pos === 'min') {
|
|
|
|
this.refInput[0].setSelectionRange(start, end);
|
|
|
|
this.refInput[0].focus();
|
|
|
|
} else if (pos === 'max') {
|
|
|
|
this.refInput[1].setSelectionRange(start, end);
|
|
|
|
this.refInput[1].focus();
|
|
|
|
}
|
2017-04-28 04:28:09 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
unmountPicker() {
|
|
|
|
if (this.picker) {
|
|
|
|
this.picker.$destroy();
|
|
|
|
this.picker.$off();
|
|
|
|
if (typeof this.unwatchPickerOptions === 'function') {
|
|
|
|
this.unwatchPickerOptions();
|
|
|
|
}
|
|
|
|
this.picker.$el.parentNode.removeChild(this.picker.$el);
|
|
|
|
}
|
2017-10-10 09:49:41 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
emitChange(val) {
|
|
|
|
const formatted = this.formatToValue(val);
|
|
|
|
if (!valueEquals(this.valueOnOpen, formatted)) {
|
|
|
|
this.$emit('change', formatted);
|
|
|
|
this.dispatch('ElFormItem', 'el.form.change', formatted);
|
|
|
|
this.valueOnOpen = formatted;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
emitInput(val) {
|
|
|
|
const formatted = this.formatToValue(val);
|
|
|
|
if (!valueEquals(this.value, formatted)) {
|
|
|
|
this.$emit('input', formatted);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
isValidValue(value) {
|
|
|
|
if (!this.picker) {
|
|
|
|
this.mountPicker();
|
|
|
|
}
|
|
|
|
if (this.picker.isValidValue) {
|
|
|
|
return value && this.picker.isValidValue(value);
|
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
2016-07-27 06:15:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
</script>
|