refactor(date-picker): using time-picker

This commit is contained in:
07akioni 2019-07-24 16:30:14 +08:00
parent 65aa95b606
commit 656d8c0dd4
10 changed files with 515 additions and 370 deletions

View File

@ -9,13 +9,13 @@
>
<!--EXAMPLE_START-->
<n-date-picker
v-model="dateTimeTimestamp"
v-model="ts1"
type="datetime"
style="margin-right: 12px;"
@change="onDateTimeChange"
/>
<n-date-picker
v-model="dateTimestamp"
v-model="ts2"
type="date"
@change="onDateChange"
/>
@ -26,18 +26,20 @@
style="flex-wrap: nowrap;"
>
<n-input
v-model="dateTimeTimestamp"
placeholder="dateTimeTimestamp"
:value="ts1"
placeholder="ts1"
type="text"
style="margin-right: 12px;"
@input="handleInputTs1"
/>
<n-input
v-model="dateTimestamp"
placeholder="dateTimestamp"
:value="ts2"
placeholder="ts2"
type="text"
@input="handleInputTs2"
/>
</div>
<pre class="n-doc-section__inspect">datetime v-model: {{ dateTimeTimestamp }}, date v-model: {{ dateTimestamp }}</pre>
<pre class="n-doc-section__inspect">datetime v-model: {{ JSON.stringify(ts1) }}, date v-model: {{ JSON.stringify(ts2) }}</pre>
<n-doc-source-block>
<!--SOURCE-->
</n-doc-source-block>
@ -48,8 +50,8 @@
export default {
data () {
return {
dateTimeTimestamp: 891360258000,
dateTimestamp: 891360258000
ts1: null,
ts2: 0
}
},
methods: {
@ -58,6 +60,13 @@ export default {
},
onDateChange (timestamp, dateString) {
this.$NMessage.success(`${timestamp}, ${dateString}`)
},
handleInputTs1 (v) {
v = Number(v)
this.ts1 = Number.isNaN(v) ? null : v
},
handleInputTs2 (v) {
this.ts2 = Number.isNaN(v) ? null : v
}
}
}

View File

@ -12,9 +12,9 @@
class="n-date-picker__input"
:placeholder="placeholder"
:readonly="disabled ? 'disabled' : false"
@focus="openCalendar"
@click="handleActivatorClick"
@blur="handleDateTimeInputBlur"
@keyup.enter="handleDateTimeInputEnter"
@input="handleDateTimeInputInput"
>
<div class="n-date-picker__icon">
<n-icon
@ -28,9 +28,17 @@
>
<div ref="content">
<datetime-panel
v-model="panelValue"
v-if="type === 'datetime'"
:value="value"
:active="active"
@change="handlePanelValueChange"
@input="handlePanelInput"
@close="closeCalendar"
/>
<date-panel
v-if="type === 'date'"
:value="value"
:active="active"
@input="handlePanelInput"
@close="closeCalendar"
/>
</div>
@ -44,6 +52,7 @@ import NIcon from '../../Icon'
import detachable from '../../../mixins/detachable'
import placeable from '../../../mixins/placeable'
import DatetimePanel from './panel/datetime'
import DatePanel from './panel/date'
import clickoutside from '../../../directives/clickoutside'
const DATE_FORMAT = {
@ -68,16 +77,13 @@ export default {
},
components: {
NIcon,
DatetimePanel
DatetimePanel,
DatePanel
},
mixins: [
detachable,
placeable
],
model: {
prop: 'value',
event: 'change'
},
props: {
disabled: {
type: Boolean,
@ -88,7 +94,7 @@ export default {
default: 'bottom-start'
},
value: {
type: [Number, String],
type: Number,
required: false,
default: null
},
@ -111,21 +117,14 @@ export default {
data () {
return {
displayDateTimeString: '',
displayDateString: '',
displayTimeString: '',
rightDisplayDateTimeString: '',
rightDisplayDateString: '',
rightDisplayTimeString: '',
calendarDateTime: moment(),
rightCalendarDateTime: moment(),
currentDateTime: moment(),
active: false,
showTimeSelector: false,
showRightTimeSelector: false,
calendar: [],
rightCalendar: [],
...TIME_CONST,
panelValue: this.value
...TIME_CONST
}
},
computed: {
@ -181,75 +180,10 @@ export default {
}
},
methods: {
handlePanelValueChange (value, valueString) {
this.$emit('change', value, valueString)
handlePanelInput (value, valueString) {
this.$emit('input', value, 'unavailable for now')
this.refreshSelectedDateTimeString()
},
/**
* If new datetime is null or undefined, emit null to value.
* Else adjust new datetime by props.type and emit it to value.
*/
setValue (newSelectedDateTime) {
if (newSelectedDateTime === null || newSelectedDateTime === undefined) {
this.$emit('change', null)
return
}
if (newSelectedDateTime.isValid()) {
const adjustedDateTime = this.adjustDateTimeAccrodingToType(newSelectedDateTime)
if (this.computedSelectedDateTime === null || adjustedDateTime.valueOf() !== this.computedSelectedDateTime.valueOf()) {
this.$emit('change', adjustedDateTime.valueOf(), adjustedDateTime.format(this.format))
}
}
},
adjustDateTimeAccrodingToType (datetime) {
if (this.type === 'datetime') {
return moment(datetime).startOf('second')
} else {
return moment(datetime).startOf('date').hour(0)
}
},
justifySelectedDateTimeAfterChangeTimeString () {
if (this.computedSelectedDateTime === null) {
// case here is impossible for now, because you can't clear time for now
} else {
const newDisplayDateTimeString = this.displayDateString + ' ' + this.displayTimeString
const newSelectedDateTime = moment(newDisplayDateTimeString, this.format, true)
this.setValue(newSelectedDateTime)
}
},
handleTimeInput (e) {
const newDisplayDateTimeString = this.displayDateString + ' ' + e.target.value
const newSelectedDateTime = moment(newDisplayDateTimeString, this.format, true)
this.setValue(newSelectedDateTime)
},
handleDateInput (e) {
const newDisplayDateTimeString = e.target.value + ' ' + this.displayTimeString
const newSelectedDateTime = moment(newDisplayDateTimeString, this.format, true)
this.setValue(newSelectedDateTime)
},
handleTimeInputBlur () {
this.refreshSelectedDateTimeString()
},
handleDateInputBlur () {
this.refreshSelectedDateTimeString()
},
handleTimeConfirmClick () {
this.justifySelectedDateTimeAfterChangeTimeString()
this.refreshSelectedDateTimeString()
this.closeTimeSelector()
},
handleTimeCancelClick () {
this.closeTimeSelector()
},
openTimeSelector () {
if (this.computedSelectedDateTime === null) {
this.setValue(moment())
}
this.showTimeSelector = true
},
closeTimeSelector () {
this.showTimeSelector = false
},
/**
* If not selected, display nothing,
* else update datetime related string
@ -260,16 +194,6 @@ export default {
return
}
this.displayDateTimeString = this.computedSelectedDateTime.format(this.format)
this.displayDateString = this.computedSelectedDateTime.format('YYYY-MM-DD')
this.displayTimeString = this.computedSelectedDateTime.format('HH:mm:ss')
},
/**
* If new time is invalid, do nothing.
* If valid, update.
*/
handleDateTimeInputEnter () {
const newSelectedDateTime = moment(this.displayDateTimeString, this.format, true)
this.setValue(newSelectedDateTime)
},
/**
* If new SelectedDateTime is valid, update `selectedDateTime` and `calendarTime`
@ -277,12 +201,18 @@ export default {
*/
handleDateTimeInputBlur () {
const newSelectedDateTime = moment(this.displayDateTimeString, this.format, true)
this.setValue(newSelectedDateTime)
/**
* If newSelectedDateTime is invalid, display string need to be restored
*/
this.refreshSelectedDateTimeString()
this.closeCalendar()
if (newSelectedDateTime.isValid()) {
this.$emit('input', newSelectedDateTime.valueOf())
} else {
this.refreshSelectedDateTimeString()
}
},
handleActivatorClick (e) {
if (this.active) {
e.stopPropagation()
} else {
this.openCalendar()
}
},
/**
* Calendar view related methods
@ -301,6 +231,12 @@ export default {
},
toggleCalendar () {
},
handleDateTimeInputInput (v) {
const newSelectedDateTime = moment(this.displayDateTimeString, this.format, true)
if (newSelectedDateTime.isValid()) {
this.$emit('input', newSelectedDateTime.valueOf())
}
}
}
}

View File

@ -0,0 +1,328 @@
<template>
<transition name="n-date-picker-calendar--transition">
<div
v-if="active"
v-clickoutside.lazy="handleClickOutside"
class="n-date-picker-calendar"
>
<div style="width: 100%; height: 12px" />
<div class="n-date-picker-calendar__month-modifier">
<div
class="n-date-picker-calendar__fast-prev"
@click="prevYear"
>
<n-icon
type="ios-arrow-back"
size="14"
/>
<n-icon
type="ios-arrow-back"
size="14"
/>
</div>
<div
class="n-date-picker-calendar__prev"
@click="prevMonth"
>
<n-icon
type="ios-arrow-back"
size="14"
/>
</div>
<div class="n-date-picker-calendar__month-year">
{{ calendarDateTime.format('MMMM') }} {{ calendarDateTime.year() }}
</div>
<div
class="n-date-picker-calendar__next"
@click="nextMonth"
>
<n-icon
type="ios-arrow-forward"
size="14"
/>
</div>
<div
class="n-date-picker-calendar__fast-next"
@click="nextYear"
>
<n-icon
type="ios-arrow-forward"
size="14"
/>
<n-icon
type="ios-arrow-forward"
size="14"
/>
</div>
</div>
<div class="n-date-picker-calendar__weekdays">
<div
v-for="weekday in weekdays"
:key="weekday"
class="n-date-picker-calendar__weekday"
>
{{ weekday }}
</div>
</div>
<div class="n-date-picker-calendar__divider" />
<div class="n-date-picker-calendar__dates">
<div
v-for="dateItem in dateArray(calendarDateTime, valueAsMoment, currentDateTime)"
:key="dateItem.timestamp"
class="n-date-picker-calendar__date"
:class="{
'n-date-picker-calendar__date--current': dateItem.isCurrentDate,
'n-date-picker-calendar__date--selected': dateItem.isSelectedDate,
'n-date-picker-calendar__date--in-display-month': dateItem.isDateOfDisplayMonth
}"
@click="handleDateClick(dateItem)"
>
{{ dateItem.date }}
</div>
</div>
<div class="n-date-picker-calendar__actions">
<n-button
size="tiny"
round
@click="setSelectedDateTimeToNow"
>
Now
</n-button>
<n-button
size="tiny"
round
auto-text-color
type="primary"
@click="handleConfirmClick"
>
Confirm
</n-button>
</div>
</div>
</transition>
</template>
<script>
import moment from 'moment'
import { dateArray, setDate } from '../utils'
import NIcon from '../../../Icon'
import clickoutside from '../../../../directives/clickoutside'
import NButton from '../../../Button'
import NInput from '../../../Input'
const DATETIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'
const DATE_FORMAT = 'YYYY-MM-DD'
const DATE_VALIDATE_FORMAT = ['YYYY-MM-DD', 'YYYY-MM-D', 'YYYY-M-D', 'YYYY-M-DD']
const PLACEHOLDER = 'Select date and time'
const TIME_CONST = {
weekdays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
hours: ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23'],
minutes: ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59'],
seconds: ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59']
}
export default {
components: {
NButton,
NIcon
},
directives: {
clickoutside
},
props: {
active: {
type: Boolean,
default: true
},
value: {
type: Number,
required: false,
default: null
},
debug: {
type: Boolean,
default: false
},
placeholder: {
type: String,
default: PLACEHOLDER
},
format: {
type: String,
default: DATETIME_FORMAT
}
},
data () {
return {
displayDateString: '',
calendarDateTime: moment(),
currentDateTime: moment(),
calendar: [],
...TIME_CONST
}
},
computed: {
computedHour () {
if (this.valueAsMoment) return this.valueAsMoment.format('HH')
else return null
},
computedMinute () {
if (this.valueAsMoment) return this.valueAsMoment.format('mm')
else return null
},
computedSecond () {
if (this.valueAsMoment) return this.valueAsMoment.format('ss')
else return null
},
/**
* If value is valid return null.
* If value is not valid, return moment(value)
*/
valueAsMoment () {
if (this.value === null || this.value === undefined) return null
const newSelectedDateTime = moment(this.value)
if (newSelectedDateTime.isValid()) {
return newSelectedDateTime
} else {
return null
}
}
},
watch: {
valueAsMoment (newValue) {
if (newValue !== null) {
this.displayDateString = newValue.format(DATE_FORMAT)
} else {
this.displayDateString = ''
}
}
},
created () {
if (this.valueAsMoment !== null) {
this.displayDateString = this.valueAsMoment.format(DATE_FORMAT)
} else {
this.displayDateString = ''
}
},
methods: {
dateArray,
handleClickOutside () {
this.closeCalendar()
},
setValue (newSelectedDateTime) {
if (newSelectedDateTime === null || newSelectedDateTime === undefined) {
this.$emit('input', null)
} else if (newSelectedDateTime.isValid()) {
const adjustedDateTime = this.adjustValue(newSelectedDateTime)
if (this.valueAsMoment === null || adjustedDateTime.valueOf() !== this.valueAsMoment.valueOf()) {
this.refreshDisplayDateString(adjustedDateTime)
this.$emit('input', adjustedDateTime.valueOf())
}
}
},
adjustValue (value) {
return moment(value).startOf('day')
},
handleDateInput (value) {
const date = moment(value, DATE_FORMAT, true)
if (date.isValid()) {
if (!this.valueAsMoment) {
const newValue = moment()
newValue.year(date.year())
newValue.month(date.month())
newValue.date(date.date())
this.$emit('input', this.adjustValue(newValue).valueOf())
} else {
const newValue = this.valueAsMoment
newValue.year(date.year())
newValue.month(date.month())
newValue.date(date.date())
this.$emit('input', this.adjustValue(newValue).valueOf())
}
} else {
// do nothing
}
},
handleDateInputBlur () {
const date = moment(this.displayDateString, DATE_VALIDATE_FORMAT, true)
if (date.isValid()) {
if (!this.valueAsMoment) {
const newValue = moment()
newValue.year(date.year())
newValue.month(date.month())
newValue.date(date.date())
this.$emit('input', this.adjustValue(newValue).valueOf())
} else {
const newValue = this.valueAsMoment
newValue.year(date.year())
newValue.month(date.month())
newValue.date(date.date())
this.$emit('input', this.adjustValue(newValue).valueOf())
}
} else {
this.refreshDisplayDateString()
}
},
clearSelectedDateTime () {
this.$emit('input', null)
this.displayDateString = ''
},
setSelectedDateTimeToNow () {
this.$emit('input', this.adjustValue(moment()).valueOf())
this.calendarDateTime = moment()
},
handleDateClick (dateItem) {
let newSelectedDateTime = moment()
if (this.valueAsMoment !== null) {
newSelectedDateTime = moment(this.valueAsMoment)
}
newSelectedDateTime = setDate(newSelectedDateTime, dateItem)
this.$emit('input', this.adjustValue(newSelectedDateTime).valueOf())
},
/**
* If not selected, display nothing,
* else update datetime related string
*/
refreshDisplayDateString (time) {
if (this.valueAsMoment === null) {
this.displayDateString = ''
return
}
if (time === undefined) {
time = this.valueAsMoment
}
this.displayDateString = time.format(DATE_FORMAT)
},
handleConfirmClick () {
this.$emit('confirm')
this.closeCalendar()
},
closeCalendar () {
if (this.active) {
this.$emit('close')
}
},
nextYear () {
this.calendarDateTime.add(1, 'year')
this.$forceUpdate()
},
prevYear () {
this.calendarDateTime.subtract(1, 'year')
this.$forceUpdate()
},
nextMonth () {
this.calendarDateTime.add(1, 'month')
this.$forceUpdate()
},
prevMonth () {
this.calendarDateTime.subtract(1, 'month')
this.$forceUpdate()
},
handleTimePickerInput (value) {
this.$emit('input', value)
}
}
}
</script>

View File

@ -8,100 +8,20 @@
<div
class="n-date-picker-calendar__date-time-input-wrapper"
>
<input
<n-input
v-model="displayDateString"
class="n-date-picker-calendar__date-input"
placeholder="Select date"
@blur="handleDateInputBlur"
@input="handleDateInput"
>
<div
ref="timeSelector"
class="n-date-picker-calendar__time-input-wrapper"
>
<input
v-model="displayTimeString"
class="n-date-picker-calendar__time-input"
placeholder="Select time"
@click="openTimeSelector"
@input="handleTimeInput"
@blur="handleTimeInputBlur"
>
<transition name="n-date-picker-time-selector--transition">
<div
v-if="showTimeSelector"
class="n-date-picker-time-selector"
>
<div class="n-date-picker-time-selector__selection-wrapper">
<div class="n-date-picker-time-selector__hour">
<div
v-for="hour in hours"
:key="hour"
class="n-date-picker-time-selector__item"
:class="{
'n-date-picker-time-selector__item--active':
hour === computedHour
}"
@click="setHour(hour)"
>
{{ hour }}
</div>
</div>
<div class="n-date-picker-time-selector__minute">
<div
v-for="minute in minutes"
:key="minute"
class="n-date-picker-time-selector__item"
:class="{
'n-date-picker-time-selector__item--active':
minute === computedMinute
}"
@click="setMinute(minute)"
>
{{ minute }}
</div>
</div>
<div class="n-date-picker-time-selector__hour">
<div
v-for="second in seconds"
:key="second"
class="n-date-picker-time-selector__item"
:class="{
'n-date-picker-time-selector__item--active':
second === computedSecond
}"
@click="setSecond(second)"
>
{{ second }}
</div>
</div>
</div>
<div class="n-date-picker-time-selector__actions">
<n-button
size="tiny"
round
@click="handleTimeCancelClick"
>
Cancel
</n-button>
<n-button
size="tiny"
round
auto-text-color
type="primary"
@click="handleTimeConfirmClick"
>
Confirm
</n-button>
</div>
</div>
</transition>
</div>
/>
<n-time-picker
class="n-date-picker-calendar__time-input"
:value="value"
stop-selector-bubble
@input="handleTimePickerInput"
/>
</div>
<!-- <div
v-else
style="width: 100%; height: 12px;"
/>-->
<div class="n-date-picker-calendar__month-modifier">
<div
class="n-date-picker-calendar__fast-prev"
@ -163,7 +83,7 @@
<div class="n-date-picker-calendar__divider" />
<div class="n-date-picker-calendar__dates">
<div
v-for="dateItem in dateArray(calendarDateTime, computedSelectedDateTime, currentDateTime)"
v-for="dateItem in dateArray(calendarDateTime, valueAsMoment, currentDateTime)"
:key="dateItem.timestamp"
class="n-date-picker-calendar__date"
:class="{
@ -189,7 +109,7 @@
round
auto-text-color
type="primary"
@click="handleDateInputAndTimeInputConfirmClick"
@click="handleConfirmClick"
>
Confirm
</n-button>
@ -205,15 +125,15 @@ import NIcon from '../../../Icon'
import clickoutside from '../../../../directives/clickoutside'
import NButton from '../../../Button'
import NTimePicker from '../../../TimePicker'
import NInput from '../../../Input'
const DATETIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'
const DATE_FORMAT = 'YYYY-MM-DD'
const DATE_VALIDATE_FORMAT = ['YYYY-MM-DD', 'YYYY-MM-D', 'YYYY-M-D', 'YYYY-M-DD']
const PLACEHOLDER = 'Select date and time'
const DATE_FORMAT = {
date: 'YYYY-MM-DD',
datetime: 'YYYY-MM-DD HH:mm:ss'
}
const PLACEHOLDER = {
date: 'Select date',
datetime: 'Select date and time'
}
const TIME_CONST = {
weekdays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
hours: ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23'],
@ -224,74 +144,65 @@ const TIME_CONST = {
export default {
components: {
NButton,
NIcon
NIcon,
NTimePicker,
NInput
},
directives: {
clickoutside
},
model: {
prop: 'value',
event: 'change'
},
props: {
active: {
type: Boolean,
default: true
},
value: {
type: [Number, String],
type: Number,
required: false,
default: null
},
debug: {
type: Boolean,
default: false
},
placeholder: {
type: String,
default: PLACEHOLDER
},
format: {
type: String,
default: DATETIME_FORMAT
}
},
data () {
return {
displayDateTimeString: '',
displayDateString: '',
displayTimeString: '',
rightDisplayDateTimeString: '',
rightDisplayDateString: '',
rightDisplayTimeString: '',
calendarDateTime: moment(),
rightCalendarDateTime: moment(),
currentDateTime: moment(),
showTimeSelector: false,
showRightTimeSelector: false,
calendar: [],
rightCalendar: [],
...TIME_CONST
}
},
computed: {
placeholder () {
return PLACEHOLDER[this.type]
},
format () {
return DATE_FORMAT[this.type]
},
computedHour () {
if (this.computedSelectedDateTime) return this.computedSelectedDateTime.format('HH')
if (this.valueAsMoment) return this.valueAsMoment.format('HH')
else return null
},
computedMinute () {
if (this.computedSelectedDateTime) return this.computedSelectedDateTime.format('mm')
if (this.valueAsMoment) return this.valueAsMoment.format('mm')
else return null
},
computedSecond () {
if (this.computedSelectedDateTime) return this.computedSelectedDateTime.format('ss')
if (this.valueAsMoment) return this.valueAsMoment.format('ss')
else return null
},
/**
* If value is valid return null.
* If value is not valid, return moment(value)
*/
computedSelectedDateTime () {
valueAsMoment () {
if (this.value === null || this.value === undefined) return null
const newSelectedDateTime = moment(Number(this.value))
const newSelectedDateTime = moment(this.value)
if (newSelectedDateTime.isValid()) {
return newSelectedDateTime
} else {
@ -299,170 +210,113 @@ export default {
}
}
},
watch: {
valueAsMoment (newValue) {
if (newValue !== null) {
this.displayDateString = newValue.format(DATE_FORMAT)
} else {
this.displayDateString = ''
}
}
},
created () {
if (this.valueAsMoment !== null) {
this.displayDateString = this.valueAsMoment.format(DATE_FORMAT)
} else {
this.displayDateString = ''
}
},
methods: {
dateArray,
handleClickOutside () {
this.closeCalendar()
console.log('clickoutside')
},
dateArray,
/**
* If new datetime is null or undefined, emit null to value.
* Else adjust new datetime by props.type and emit it to value.
*/
setValue (newSelectedDateTime) {
if (newSelectedDateTime === null || newSelectedDateTime === undefined) {
this.$emit('change', null)
return
}
if (newSelectedDateTime.isValid()) {
const adjustedDateTime = this.adjustDateTime(newSelectedDateTime)
if (this.computedSelectedDateTime === null || adjustedDateTime.valueOf() !== this.computedSelectedDateTime.valueOf()) {
this.refreshSelectedDateTimeString(adjustedDateTime)
this.$emit('change', adjustedDateTime.valueOf(), adjustedDateTime.format(this.format))
this.$emit('input', null)
} else if (newSelectedDateTime.isValid()) {
const adjustedDateTime = this.adjustValue(newSelectedDateTime)
if (this.valueAsMoment === null || adjustedDateTime.valueOf() !== this.valueAsMoment.valueOf()) {
this.refreshDisplayDateString(adjustedDateTime)
this.$emit('input', adjustedDateTime.valueOf())
}
}
// this.$nextTick(this.refreshSelectedDateTimeString)
},
adjustDateTime (datetime) {
adjustValue (datetime) {
return moment(datetime).startOf('second')
},
justifySelectedDateTimeAfterChangeTimeString () {
if (this.computedSelectedDateTime === null) {
// case here is impossible for now, because you can't clear time for now
handleDateInput (value) {
const date = moment(value, DATE_FORMAT, true)
if (date.isValid()) {
if (!this.valueAsMoment) {
const newValue = moment()
newValue.year(date.year())
newValue.month(date.month())
newValue.date(date.date())
this.$emit('input', this.adjustValue(newValue).valueOf())
} else {
const newValue = this.valueAsMoment
newValue.year(date.year())
newValue.month(date.month())
newValue.date(date.date())
this.$emit('input', this.adjustValue(newValue).valueOf())
}
} else {
const newDisplayDateTimeString = this.displayDateString + ' ' + this.displayTimeString
const newSelectedDateTime = moment(newDisplayDateTimeString, this.format, true)
this.setValue(newSelectedDateTime)
// do nothing
}
},
handleTimeInput (e) {
const newDisplayDateTimeString = this.displayDateString + ' ' + e.target.value
const newSelectedDateTime = moment(newDisplayDateTimeString, this.format, true)
this.setValue(newSelectedDateTime)
},
handleDateInput (e) {
const newDisplayDateTimeString = e.target.value + ' ' + this.displayTimeString
const newSelectedDateTime = moment(newDisplayDateTimeString, this.format, true)
this.setValue(newSelectedDateTime)
},
handleTimeInputBlur () {
this.refreshSelectedDateTimeString()
},
handleDateInputBlur () {
this.refreshSelectedDateTimeString()
},
handleTimeConfirmClick () {
this.justifySelectedDateTimeAfterChangeTimeString()
this.refreshSelectedDateTimeString()
this.closeTimeSelector()
},
handleTimeCancelClick () {
this.closeTimeSelector()
},
setHour (hour) {
try {
const timeArray = this.displayTimeString.split(':')
timeArray[0] = hour
this.displayTimeString = timeArray.join(':')
} catch (err) {
} finally {
this.justifySelectedDateTimeAfterChangeTimeString()
const date = moment(this.displayDateString, DATE_VALIDATE_FORMAT, true)
if (date.isValid()) {
if (!this.valueAsMoment) {
const newValue = moment()
newValue.year(date.year())
newValue.month(date.month())
newValue.date(date.date())
this.$emit('input', this.adjustValue(newValue).valueOf())
} else {
const newValue = this.valueAsMoment
newValue.year(date.year())
newValue.month(date.month())
newValue.date(date.date())
this.$emit('input', this.adjustValue(newValue).valueOf())
}
} else {
this.refreshDisplayDateString()
}
},
setMinute (minute) {
try {
const timeArray = this.displayTimeString.split(':')
timeArray[1] = minute
this.displayTimeString = timeArray.join(':')
} catch (err) {
} finally {
this.justifySelectedDateTimeAfterChangeTimeString()
}
},
setSecond (second) {
try {
const timeArray = this.displayTimeString.split(':')
timeArray[2] = second
this.displayTimeString = timeArray.join(':')
} catch (err) {
} finally {
this.justifySelectedDateTimeAfterChangeTimeString()
}
},
openTimeSelector () {
if (this.computedSelectedDateTime === null) {
this.setValue(moment())
}
this.showTimeSelector = true
},
closeTimeSelector () {
this.showTimeSelector = false
},
clearSelectedDateTime () {
this.setValue(null)
this.displayDateTimeString = ''
this.$emit('input', null)
this.displayDateString = ''
this.displayTimeString = ''
},
setSelectedDateTimeToNow () {
this.setValue(moment())
this.$emit('input', this.adjustValue(moment()).valueOf())
this.calendarDateTime = moment()
},
handleDateClick (dateItem) {
let newSelectedDateTime = moment()
if (this.computedSelectedDateTime !== null) {
newSelectedDateTime = moment(this.computedSelectedDateTime)
if (this.valueAsMoment !== null) {
newSelectedDateTime = moment(this.valueAsMoment)
}
newSelectedDateTime = setDate(newSelectedDateTime, dateItem)
this.setValue(newSelectedDateTime)
this.$emit('input', this.adjustValue(newSelectedDateTime).valueOf())
},
/**
* If not selected, display nothing,
* else update datetime related string
*/
refreshSelectedDateTimeString (time) {
if (this.computedSelectedDateTime === null) {
this.displayDateTimeString = ''
refreshDisplayDateString (time) {
if (this.valueAsMoment === null) {
this.displayDateString = ''
return
}
if (time === undefined) {
time = this.computedSelectedDateTime
time = this.valueAsMoment
}
this.displayDateTimeString = time.format(this.format)
this.displayDateString = time.format('YYYY-MM-DD')
this.displayTimeString = time.format('HH:mm:ss')
this.displayDateString = time.format(DATE_FORMAT)
},
/**
* If new time is invalid, do nothing.
* If valid, update.
*/
handleDateTimeInputEnter () {
const newSelectedDateTime = moment(this.displayDateTimeString, this.format, true)
this.setValue(newSelectedDateTime)
},
/**
* If new SelectedDateTime is valid, update `selectedDateTime` and `calendarTime`
* Whatever happened, refresh selectedDateTime
*/
handleDateTimeInputBlur () {
const newSelectedDateTime = moment(this.displayDateTimeString, this.format, true)
this.setValue(newSelectedDateTime)
/**
* If newSelectedDateTime is invalid, display string need to be restored
*/
this.refreshSelectedDateTimeString()
},
handleDateInputAndTimeInputConfirmClick () {
const newDisplayDateTimeString = `${this.displayDateString.trim()} ${this.displayTimeString.trim()}`
const newSelectedDateTime = moment(newDisplayDateTimeString, this.format, true)
if (this.computedSelectedDateTime === null) {
this.setValue(moment())
} else {
this.setValue(newSelectedDateTime)
}
handleConfirmClick () {
this.$emit('confirm')
this.closeCalendar()
},
closeCalendar () {
@ -485,6 +339,9 @@ export default {
prevMonth () {
this.calendarDateTime.subtract(1, 'month')
this.$forceUpdate()
},
handleTimePickerInput (value) {
this.$emit('input', value)
}
}
}

View File

@ -23,6 +23,11 @@ export default {
</script>
<style lang="scss">
.n-modal-content {
&::-webkit-scrollbar {
width: 0px;
}
}
.n-modal-content--transition-enter-active {
opacity: 1;

View File

@ -13,6 +13,7 @@
<div
ref="contentWrapper"
class="n-content-wrapper"
@click="handleContentClick"
>
<div
ref="content"
@ -21,7 +22,7 @@
<div
v-if="active"
v-clickoutside.lazy="closeTimeSelector"
class="n-time-picker"
class="n-time-picker-selector"
>
<div class="n-time-picker__selection-wrapper">
<div
@ -92,7 +93,7 @@
round
auto-text-color
type="primary"
@click="handleComfirmClick"
@click="handleConfirmClick"
>
Confirm
</n-button>
@ -153,14 +154,16 @@ export default {
},
mixins: [detachable, placeable],
props: {
stopSelectorBubble: {
type: Boolean,
default: false
},
placement: {
type: String,
default: 'bottom-start'
},
value: {
validator (value) {
return moment(value).isValid()
},
type: Number,
default: null
},
format: {
@ -290,9 +293,14 @@ export default {
this.$emit('input', this.memorizedValue)
this.active = false
},
handleComfirmClick () {
handleConfirmClick () {
this.refreshTimeString()
this.active = false
},
handleContentClick (e) {
if (this.stopSelectorBubble) {
e.stopPropagation()
}
}
}
}

View File

@ -52,6 +52,7 @@ export default {
}
},
mounted () {
this.$refs.content.style = 'position: absolute;'
this.$nextTick().then(() => {
this.registerScrollListeners()
this.registerResizeListener()

View File

@ -38,7 +38,7 @@
color: rgba(221, 238, 247, 0.3);
height: 20px;
}
.n-date-picker__input, .n-date-picker-calendar__date-input, .n-date-picker-calendar__time-input {
.n-date-picker__input, .n-date-picker-calendar__date-input {
-webkit-appearance: none;
box-sizing: border-box;
border: none;

View File

@ -1,4 +1,4 @@
@include b(time-picker) {
@include b(time-picker-selector) {
background-color: rgba(97, 104, 132, 1);
box-shadow:0px 2px 20px 0px rgba(0,0,0,0.16);
font-size: 12px;
@ -6,7 +6,7 @@
margin-top: 4px;
width: 180px;
overflow: hidden;
@include fade-in-transition(time-picker, center top);
@include fade-in-transition(time-picker, top left);
.n-time-picker__selection-wrapper {
position: relative;
height: 244px;

View File

@ -7,4 +7,5 @@
@include b(tooltip__content) {
padding: 8px 14px;
white-space: nowrap;
}