|
@@ -0,0 +1,666 @@
|
|
|
|
+<template>
|
|
|
|
+ <div class="datepicker">
|
|
|
|
+ <template v-if="hasInput">
|
|
|
|
+ <input class="form-control datepicker-input" :class="{'with-reset-button': clearButton}" type="text" :placeholder="placeholder"
|
|
|
|
+ :style="{width:width}"
|
|
|
|
+ @click="inputClick"
|
|
|
|
+ v-model="inputValue"/>
|
|
|
|
+ <button v-if="clearButton && value" type="button" class="close" @click="inputValue = ''">
|
|
|
|
+ <span>×</span>
|
|
|
|
+ </button>
|
|
|
|
+ </template>
|
|
|
|
+ <div class="datepicker-popup" :style="paneStyle" @mouseover="handleMouseOver" @mouseout="handleMouseOver" v-show="displayDayView">
|
|
|
|
+ <div class="datepicker-ctrl" v-if="false">
|
|
|
|
+ <span class="datepicker-preBtn glyphicon glyphicon-chevron-left" aria-hidden="true" @click="preNextMonthClick(0)"></span>
|
|
|
|
+ <span class="datepicker-nextBtn glyphicon glyphicon-chevron-right" aria-hidden="true" @click="preNextMonthClick(1)"></span>
|
|
|
|
+ </div>
|
|
|
|
+ <template v-for="(p, pan) in pane" >
|
|
|
|
+ <div class="datepicker-inner">
|
|
|
|
+ <div class="datepicker-body">
|
|
|
|
+ <!--<p @click="switchMonthView">{{stringifyDayHeader(currDate, pan)}}</p>-->
|
|
|
|
+ <div class="datepicker-weekRange">
|
|
|
|
+ <span v-for="w in text.daysOfWeek">{{w}}</span>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="datepicker-dateRange">
|
|
|
|
+ <span v-for="d in dateRange[pan]" class="day-cell" :class="getItemClasses(d)" :data-date="stringify(d.date)" @click="daySelect(d.date, $event)"><div>
|
|
|
|
+ <template v-if="d.sclass !== 'datepicker-item-gray'">
|
|
|
|
+ {{getSpecailDay(d.date) || d.text}}
|
|
|
|
+ </template>
|
|
|
|
+ <template v-else>
|
|
|
|
+ {{d.text}}
|
|
|
|
+ </template>
|
|
|
|
+ <div v-if="d.sclass !== 'datepicker-item-gray'"><slot :name="stringify(d.date)"></slot></div></div>
|
|
|
|
+ </span>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </template>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="datepicker-popup" :style="paneStyle" v-show="displayMonthView">
|
|
|
|
+ <div class="datepicker-ctrl">
|
|
|
|
+ <span class="datepicker-preBtn glyphicon glyphicon-chevron-left" aria-hidden="true" @click="preNextYearClick(0)"></span>
|
|
|
|
+ <span class="datepicker-nextBtn glyphicon glyphicon-chevron-right" aria-hidden="true" @click="preNextYearClick(1)"></span>
|
|
|
|
+ </div>
|
|
|
|
+ <template v-for="(p, pan) in pane" >
|
|
|
|
+ <div class="datepicker-inner">
|
|
|
|
+ <div class="datepicker-body">
|
|
|
|
+ <p @click="switchDecadeView">{{stringifyYearHeader(currDate, pan)}}</p>
|
|
|
|
+ <div class="datepicker-monthRange">
|
|
|
|
+ <template v-for="(m, $index) in text.months">
|
|
|
|
+ <span :class="{'datepicker-dateRange-item-active':
|
|
|
|
+ (text.months[parse(value).getMonth()] === m) &&
|
|
|
|
+ currDate.getFullYear() + pan === parse(value).getFullYear()}"
|
|
|
|
+ @click="monthSelect(stringifyYearHeader(currDate, pan), $index)"
|
|
|
|
+ >{{m.substr(0,3)}}</span>
|
|
|
|
+ </template>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </template>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="datepicker-popup" :style="paneStyle" v-show="displayYearView">
|
|
|
|
+ <div class="datepicker-ctrl">
|
|
|
|
+ <span class="datepicker-preBtn glyphicon glyphicon-chevron-left" aria-hidden="true" @click="preNextDecadeClick(0)"></span>
|
|
|
|
+ <span class="datepicker-nextBtn glyphicon glyphicon-chevron-right" aria-hidden="true" @click="preNextDecadeClick(1)"></span>
|
|
|
|
+ </div>
|
|
|
|
+ <template v-for="(p, pan) in pane" >
|
|
|
|
+ <div class="datepicker-inner">
|
|
|
|
+ <div class="datepicker-body">
|
|
|
|
+ <p>{{stringifyDecadeHeader(currDate, pan)}}</p>
|
|
|
|
+ <div class="datepicker-monthRange decadeRange">
|
|
|
|
+ <template v-for="decade in decadeRange[pan]">
|
|
|
|
+ <span :class="{'datepicker-dateRange-item-active':
|
|
|
|
+ parse(inputValue).getFullYear() === decade.text}"
|
|
|
|
+ @click.stop="yearSelect(decade.text)"
|
|
|
|
+ >{{decade.text}}</span>
|
|
|
|
+ </template>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </template>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script>
|
|
|
|
+ export default {
|
|
|
|
+ name: 'calendar',
|
|
|
|
+ props: {
|
|
|
|
+ value: {
|
|
|
|
+ type: String
|
|
|
|
+ },
|
|
|
|
+ format: {
|
|
|
|
+ default: 'MM/dd/yyyy'
|
|
|
|
+ },
|
|
|
|
+ disabledDaysOfWeek: {
|
|
|
|
+ type: Array,
|
|
|
|
+ default () {
|
|
|
|
+ return []
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ width: {
|
|
|
|
+ type: String,
|
|
|
|
+ default: '200px'
|
|
|
|
+ },
|
|
|
|
+ clearButton: {
|
|
|
|
+ type: Boolean,
|
|
|
|
+ default: false
|
|
|
|
+ },
|
|
|
|
+ lang: {
|
|
|
|
+ type: String,
|
|
|
|
+ default: navigator.language
|
|
|
|
+ },
|
|
|
|
+ placeholder: {
|
|
|
|
+ type: String
|
|
|
|
+ },
|
|
|
|
+ hasInput: {
|
|
|
|
+ type: Boolean,
|
|
|
|
+ default: true
|
|
|
|
+ },
|
|
|
|
+ pane: {
|
|
|
|
+ type: Number,
|
|
|
|
+ default: 1
|
|
|
|
+ },
|
|
|
|
+ borderWidth: {
|
|
|
|
+ type: Number,
|
|
|
|
+ default: 2
|
|
|
|
+ },
|
|
|
|
+ onDayClick: {
|
|
|
|
+ type: Function,
|
|
|
|
+ default () {}
|
|
|
|
+ },
|
|
|
|
+ changePane: {
|
|
|
|
+ type: Function,
|
|
|
|
+ default () {}
|
|
|
|
+ },
|
|
|
|
+ specialDays: {
|
|
|
|
+ type: Object,
|
|
|
|
+ default () {
|
|
|
|
+ return {}
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ rangeBus: {
|
|
|
|
+ type: Function,
|
|
|
|
+ default () {
|
|
|
|
+ // return new Vue()
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ rangeStatus: {
|
|
|
|
+ type: Number,
|
|
|
|
+ default: 0
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ mounted () {
|
|
|
|
+ this._blur = (e) => {
|
|
|
|
+ if (!this.$el.contains(e.target) && this.hasInput) this.close()
|
|
|
|
+ }
|
|
|
|
+ this.$emit('child-created', this)
|
|
|
|
+ // this.inputValue = this.value
|
|
|
|
+ // this.dateFormat = this.format
|
|
|
|
+ this.currDate = this.parse(this.inputValue) || this.parse(new Date())
|
|
|
|
+ const year = this.currDate.getFullYear()
|
|
|
|
+ const month = this.currDate.getMonth()
|
|
|
|
+ this.changePane(year, month, this.pane)
|
|
|
|
+ if (!this.hasInput) {
|
|
|
|
+ this.displayDayView = true
|
|
|
|
+ this.updatePaneStyle()
|
|
|
|
+ }
|
|
|
|
+ if (this.rangeStatus) {
|
|
|
|
+ this.eventbus = this.rangeBus()
|
|
|
|
+ if (typeof this.eventbus === 'object' && !this.eventbus.$on) {
|
|
|
|
+ console.warn('Calendar rangeBus doesn\'t exist')
|
|
|
|
+ this.rangeStatus = 0
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (this.rangeStatus === 2) {
|
|
|
|
+ this._updateRangeStart = (date) => {
|
|
|
|
+ this.rangeStart = date
|
|
|
|
+ this.currDate = date
|
|
|
|
+ this.inputValue = this.stringify(this.currDate)
|
|
|
|
+ }
|
|
|
|
+ this.eventbus.$on('calendar-rangestart', this._updateRangeStart)
|
|
|
|
+ }
|
|
|
|
+ document.addEventListener('click', this._blur)
|
|
|
|
+ },
|
|
|
|
+ beforeDestroy () {
|
|
|
|
+ document.removeEventListener('click', this._blur)
|
|
|
|
+ if (this.rangeStatus === 2) {
|
|
|
|
+ this.eventbus.$off('calendar-rangestart', this._updateRangeStart)
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ data () {
|
|
|
|
+ return {
|
|
|
|
+ inputValue: this.value,
|
|
|
|
+ dateFormat: this.format,
|
|
|
|
+ currDate: new Date(),
|
|
|
|
+ dateRange: [],
|
|
|
|
+ decadeRange: [],
|
|
|
|
+ paneStyle: {
|
|
|
|
+ width: ''
|
|
|
|
+ },
|
|
|
|
+ displayDayView: false,
|
|
|
|
+ displayMonthView: false,
|
|
|
|
+ displayYearView: false,
|
|
|
|
+ rangeStart: false,
|
|
|
|
+ rangeEnd: false
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ watch: {
|
|
|
|
+ currDate () {
|
|
|
|
+ this.getDateRange()
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ computed: {
|
|
|
|
+ text () {
|
|
|
|
+ return this.translations(this.lang)
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ methods: {
|
|
|
|
+ handleMouseOver (event) {
|
|
|
|
+ let target = event.target
|
|
|
|
+ // this.rangeEnd = false
|
|
|
|
+ if (!this.rangeStart) {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ if (event.type === 'mouseout') {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ while (this.$el.contains(target) && !~target.className.indexOf('day-cell')) {
|
|
|
|
+ target = target.parentNode
|
|
|
|
+ }
|
|
|
|
+ if (~target.className.indexOf('day-cell') && !~target.className.indexOf('datepicker-item-gray')) {
|
|
|
|
+ const rangeEnd = target.getAttribute('data-date')
|
|
|
|
+ if (this.rangeStart < this.parse(rangeEnd)) {
|
|
|
|
+ this.rangeEnd = this.parse(rangeEnd)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ getItemClasses (d) {
|
|
|
|
+ const clazz = []
|
|
|
|
+ clazz.push(d.sclass)
|
|
|
|
+ if (this.rangeStart && this.rangeEnd && d.sclass !== 'datepicker-item-gray') {
|
|
|
|
+ if (d.date > this.rangeStart && d.date < this.rangeEnd) {
|
|
|
|
+ clazz.push('daytoday-range')
|
|
|
|
+ }
|
|
|
|
+ /* eslint-disable eqeqeq */
|
|
|
|
+ if (this.stringify(d.date) == this.stringify(this.rangeStart)) {
|
|
|
|
+ clazz.push('daytoday-start')
|
|
|
|
+ }
|
|
|
|
+ /* eslint-disable eqeqeq */
|
|
|
|
+ if (this.stringify(d.date) == this.stringify(this.rangeEnd)) {
|
|
|
|
+ clazz.push('daytoday-end')
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return clazz.join(' ')
|
|
|
|
+ },
|
|
|
|
+ translations (lang) {
|
|
|
|
+ lang = lang || 'en'
|
|
|
|
+ let text = {
|
|
|
|
+ daysOfWeek: ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'],
|
|
|
|
+ limit: 'Limit reached ({{limit}} items max).',
|
|
|
|
+ loading: 'Loading...',
|
|
|
|
+ minLength: 'Min. Length',
|
|
|
|
+ months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
|
|
|
|
+ notSelected: 'Nothing Selected',
|
|
|
|
+ required: 'Required',
|
|
|
|
+ search: 'Search'
|
|
|
|
+ }
|
|
|
|
+ return window.VueCalendarLang ? window.VueCalendarLang(lang) : text
|
|
|
|
+ },
|
|
|
|
+ close () {
|
|
|
|
+ this.displayDayView = this.displayMonthView = this.displayYearView = false
|
|
|
|
+ },
|
|
|
|
+ inputClick () {
|
|
|
|
+ this.currDate = this.parse(this.inputValue) || this.parse(new Date())
|
|
|
|
+ if (this.displayMonthView || this.displayYearView) {
|
|
|
|
+ this.displayDayView = false
|
|
|
|
+ } else {
|
|
|
|
+ this.displayDayView = !this.displayDayView
|
|
|
|
+ }
|
|
|
|
+ this.updatePaneStyle()
|
|
|
|
+ },
|
|
|
|
+ updatePaneStyle () {
|
|
|
|
+ if (!(this.displayMonthView || this.displayYearView)) {
|
|
|
|
+ this.$nextTick(function () {
|
|
|
|
+ let offsetLeft = this.$el.offsetLeft
|
|
|
|
+ let offsetWidth = this.$el.querySelector('.datepicker-inner').offsetWidth
|
|
|
|
+ let popWidth = this.pane * offsetWidth + this.borderWidth // add border
|
|
|
|
+ this.paneStyle.width = popWidth + 'px'
|
|
|
|
+ if (this.hasInput) {
|
|
|
|
+ if (popWidth + offsetLeft > document.documentElement.clientWidth) {
|
|
|
|
+ this.paneStyle.right = '0px'
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ this.paneStyle.position = 'initial'
|
|
|
|
+ }
|
|
|
|
+ this.$forceUpdate()
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ preNextDecadeClick (flag) {
|
|
|
|
+ const year = this.currDate.getFullYear()
|
|
|
|
+ const months = this.currDate.getMonth()
|
|
|
|
+ const date = this.currDate.getDate()
|
|
|
|
+ if (flag === 0) {
|
|
|
|
+ this.currDate = new Date(year - 10, months, date)
|
|
|
|
+ } else {
|
|
|
|
+ this.currDate = new Date(year + 10, months, date)
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ preNextMonthClick (flag) {
|
|
|
|
+ const year = this.currDate.getFullYear()
|
|
|
|
+ const month = this.currDate.getMonth()
|
|
|
|
+ const date = this.currDate.getDate()
|
|
|
|
+ if (flag === 0) {
|
|
|
|
+ const preMonth = this.getYearMonth(year, month - 1)
|
|
|
|
+ this.currDate = new Date(preMonth.year, preMonth.month, date)
|
|
|
|
+ this.changePane(preMonth.year, preMonth.month, this.pane)
|
|
|
|
+ } else {
|
|
|
|
+ const nextMonth = this.getYearMonth(year, month + 1)
|
|
|
|
+ this.currDate = new Date(nextMonth.year, nextMonth.month, date)
|
|
|
|
+ this.changePane(nextMonth.year, nextMonth.month, this.pane)
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ preNextYearClick (flag) {
|
|
|
|
+ const year = this.currDate.getFullYear()
|
|
|
|
+ const months = this.currDate.getMonth()
|
|
|
|
+ const date = this.currDate.getDate()
|
|
|
|
+ if (flag === 0) {
|
|
|
|
+ this.currDate = new Date(year - 1, months, date)
|
|
|
|
+ } else {
|
|
|
|
+ this.currDate = new Date(year + 1, months, date)
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ yearSelect (year) {
|
|
|
|
+ this.displayYearView = false
|
|
|
|
+ this.displayMonthView = true
|
|
|
|
+ this.currDate = new Date(year, this.currDate.getMonth(), this.currDate.getDate())
|
|
|
|
+ },
|
|
|
|
+ daySelect (date, event) {
|
|
|
|
+ let el = event.target
|
|
|
|
+ if (el.classList[0] === 'datepicker-item-disable') {
|
|
|
|
+ return false
|
|
|
|
+ } else {
|
|
|
|
+ if (this.hasInput) {
|
|
|
|
+ this.currDate = date
|
|
|
|
+ this.inputValue = this.stringify(this.currDate)
|
|
|
|
+ this.displayDayView = false
|
|
|
|
+ if (this.rangeStatus === 1) {
|
|
|
|
+ this.eventbus.$emit('calendar-rangestart', this.currDate)
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ this.onDayClick(date, this.stringify(date))
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ switchMonthView () {
|
|
|
|
+ this.displayDayView = false
|
|
|
|
+ this.displayMonthView = true
|
|
|
|
+ },
|
|
|
|
+ switchDecadeView () {
|
|
|
|
+ this.displayMonthView = false
|
|
|
|
+ this.displayYearView = true
|
|
|
|
+ },
|
|
|
|
+ monthSelect (year, index) {
|
|
|
|
+ this.displayMonthView = false
|
|
|
|
+ this.displayDayView = true
|
|
|
|
+ this.currDate = new Date(year, index, this.currDate.getDate())
|
|
|
|
+ this.changePane(year, index, this.pane)
|
|
|
|
+ },
|
|
|
|
+ getYearMonth (year, month) {
|
|
|
|
+ if (month > 11) {
|
|
|
|
+ year++
|
|
|
|
+ month = 0
|
|
|
|
+ } else if (month < 0) {
|
|
|
|
+ year--
|
|
|
|
+ month = 11
|
|
|
|
+ }
|
|
|
|
+ return {year: year, month: month}
|
|
|
|
+ },
|
|
|
|
+ getSpecailDay (v) {
|
|
|
|
+ return this.specialDays[this.stringify(v)]
|
|
|
|
+ },
|
|
|
|
+ stringifyDecadeHeader (date, pan) {
|
|
|
|
+ const yearStr = date.getFullYear().toString()
|
|
|
|
+ const firstYearOfDecade = parseInt(yearStr.substring(0, yearStr.length - 1) + 0, 10) + (pan * 10)
|
|
|
|
+ const lastYearOfDecade = parseInt(firstYearOfDecade, 10) + 10
|
|
|
|
+ return firstYearOfDecade + '-' + lastYearOfDecade
|
|
|
|
+ },
|
|
|
|
+ siblingsMonth (v, n) {
|
|
|
|
+ return new Date(v.getFullYear(), v.getMonth() * 1 + n)
|
|
|
|
+ },
|
|
|
|
+ stringifyDayHeader (date, month = 0) {
|
|
|
|
+ const d = this.siblingsMonth(date, month)
|
|
|
|
+ return this.text.months[d.getMonth()] + ' ' + d.getFullYear()
|
|
|
|
+ },
|
|
|
|
+ parseMonth (date) {
|
|
|
|
+ return this.text.months[date.getMonth()]
|
|
|
|
+ },
|
|
|
|
+ stringifyYearHeader (date, year = 0) {
|
|
|
|
+ return date.getFullYear() + year
|
|
|
|
+ },
|
|
|
|
+ stringify (date, format = this.dateFormat) {
|
|
|
|
+ if (!date) date = this.parse()
|
|
|
|
+ if (!date) return ''
|
|
|
|
+ const year = date.getFullYear()
|
|
|
|
+ const month = date.getMonth() + 1
|
|
|
|
+ const day = date.getDate()
|
|
|
|
+ const monthName = this.parseMonth(date)
|
|
|
|
+ return format
|
|
|
|
+ .replace(/yyyy/g, year)
|
|
|
|
+ .replace(/MMMM/g, monthName)
|
|
|
|
+ .replace(/MMM/g, monthName.substring(0, 3))
|
|
|
|
+ .replace(/MM/g, ('0' + month).slice(-2))
|
|
|
|
+ .replace(/dd/g, ('0' + day).slice(-2))
|
|
|
|
+ .replace(/yy/g, year)
|
|
|
|
+ .replace(/M(?!a)/g, month)
|
|
|
|
+ .replace(/d/g, day)
|
|
|
|
+ },
|
|
|
|
+ parse (str = this.inputValue) {
|
|
|
|
+ let date
|
|
|
|
+ if (str.length === 10 && (this.dateFormat === 'dd-MM-yyyy' || this.dateFormat === 'dd/MM/yyyy')) {
|
|
|
|
+ date = new Date(str.substring(6, 10), str.substring(3, 5) - 1, str.substring(0, 2))
|
|
|
|
+ } else {
|
|
|
|
+ date = new Date(str)
|
|
|
|
+ date.setHours(0, 0, 0)
|
|
|
|
+ }
|
|
|
|
+ return isNaN(date.getFullYear()) ? new Date() : date
|
|
|
|
+ },
|
|
|
|
+ getDayCount (year, month) {
|
|
|
|
+ const dict = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
|
|
|
+ if (month === 1) {
|
|
|
|
+ if ((year % 400 === 0) || (year % 4 === 0 && year % 100 !== 0)) {
|
|
|
|
+ return 29
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return dict[month]
|
|
|
|
+ },
|
|
|
|
+ getDateRange () {
|
|
|
|
+ this.dateRange = []
|
|
|
|
+ this.decadeRange = []
|
|
|
|
+ for (let p = 0; p < this.pane; p++) {
|
|
|
|
+ let currMonth = this.siblingsMonth(this.currDate, p)
|
|
|
|
+ let time = {
|
|
|
|
+ year: currMonth.getFullYear(),
|
|
|
|
+ month: currMonth.getMonth()
|
|
|
|
+ }
|
|
|
|
+ let yearStr = time.year.toString()
|
|
|
|
+ this.decadeRange[p] = []
|
|
|
|
+ let firstYearOfDecade = (yearStr.substring(0, yearStr.length - 1) + 0) - 1
|
|
|
|
+ for (let i = 0; i < 12; i++) {
|
|
|
|
+ this.decadeRange[p].push({
|
|
|
|
+ text: firstYearOfDecade + i + p * 10
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ this.dateRange[p] = []
|
|
|
|
+ const currMonthFirstDay = new Date(time.year, time.month, 1)
|
|
|
|
+ let firstDayWeek = currMonthFirstDay.getDay() + 1
|
|
|
|
+ if (firstDayWeek === 0) {
|
|
|
|
+ firstDayWeek = 7
|
|
|
|
+ }
|
|
|
|
+ const dayCount = this.getDayCount(time.year, time.month)
|
|
|
|
+ if (firstDayWeek > 1) {
|
|
|
|
+ const preMonth = this.getYearMonth(time.year, time.month - 1)
|
|
|
|
+ const prevMonthDayCount = this.getDayCount(preMonth.year, preMonth.month)
|
|
|
|
+ for (let i = 1; i < firstDayWeek; i++) {
|
|
|
|
+ const dayText = prevMonthDayCount - firstDayWeek + i + 1
|
|
|
|
+ this.dateRange[p].push({
|
|
|
|
+ text: dayText,
|
|
|
|
+ date: new Date(preMonth.year, preMonth.month, dayText),
|
|
|
|
+ sclass: 'datepicker-item-gray'
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ for (let i = 1; i <= dayCount; i++) {
|
|
|
|
+ const date = new Date(time.year, time.month, i)
|
|
|
|
+ const week = date.getDay()
|
|
|
|
+ let sclass = ''
|
|
|
|
+ this.disabledDaysOfWeek.forEach((el) => {
|
|
|
|
+ if (week === parseInt(el, 10)) sclass = 'datepicker-item-disable'
|
|
|
|
+ })
|
|
|
|
+ if (i === this.currDate.getDate()) {
|
|
|
|
+ if (this.inputValue) {
|
|
|
|
+ const valueDate = this.parse(this.inputValue)
|
|
|
|
+ if (valueDate) {
|
|
|
|
+ if (valueDate.getFullYear() === time.year && valueDate.getMonth() === time.month) {
|
|
|
|
+ sclass = 'datepicker-dateRange-item-active'
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ this.dateRange[p].push({
|
|
|
|
+ text: i,
|
|
|
|
+ date: date,
|
|
|
|
+ sclass: sclass
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ if (this.dateRange[p].length < 42) {
|
|
|
|
+ const nextMonthNeed = 42 - this.dateRange[p].length
|
|
|
|
+ const nextMonth = this.getYearMonth(time.year, time.month + 1)
|
|
|
|
+ for (let i = 1; i <= nextMonthNeed; i++) {
|
|
|
|
+ this.dateRange[p].push({
|
|
|
|
+ text: i,
|
|
|
|
+ date: new Date(nextMonth.year, nextMonth.month, i),
|
|
|
|
+ sclass: 'datepicker-item-gray'
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<style lang="scss">
|
|
|
|
+ @mixin clearfix() {
|
|
|
|
+ &:before,
|
|
|
|
+ &:after {
|
|
|
|
+ content: " "; // 1
|
|
|
|
+ display: table; // 2
|
|
|
|
+ }
|
|
|
|
+ &:after {
|
|
|
|
+ clear: both;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ .datepicker{
|
|
|
|
+ position: relative;
|
|
|
|
+ display: block;
|
|
|
|
+ }
|
|
|
|
+ input.datepicker-input.with-reset-button {
|
|
|
|
+ padding-right: 25px;
|
|
|
|
+ }
|
|
|
|
+ .datepicker > button.close {
|
|
|
|
+ position: absolute;
|
|
|
|
+ top: 0;
|
|
|
|
+ right: 0;
|
|
|
|
+ outline: none;
|
|
|
|
+ z-index: 2;
|
|
|
|
+ display: block;
|
|
|
|
+ width: 34px;
|
|
|
|
+ height: 34px;
|
|
|
|
+ line-height: 34px;
|
|
|
|
+ text-align: center;
|
|
|
|
+ }
|
|
|
|
+ .datepicker > button.close:focus {
|
|
|
|
+ opacity: .2;
|
|
|
|
+ }
|
|
|
|
+ .datepicker-popup{
|
|
|
|
+ position: absolute;
|
|
|
|
+ border: 1px solid #ccc;
|
|
|
|
+ /*border-radius: 5px;*/
|
|
|
|
+ background: #e4e4e4;
|
|
|
|
+ /*margin-top: 2px;*/
|
|
|
|
+ z-index: 1000;
|
|
|
|
+ /*box-shadow: 0 6px 12px rgba(0,0,0,0.175);*/
|
|
|
|
+ @include clearfix;
|
|
|
|
+ }
|
|
|
|
+ .datepicker-inner{
|
|
|
|
+ width: 100%;
|
|
|
|
+ /*float: left;*/
|
|
|
|
+ }
|
|
|
|
+ .datepicker-body{
|
|
|
|
+ padding: 5px;
|
|
|
|
+ text-align: center;
|
|
|
|
+ }
|
|
|
|
+ .datepicker-ctrl p,
|
|
|
|
+ .datepicker-ctrl span,
|
|
|
|
+ .datepicker-body span{
|
|
|
|
+ display: inline-block;
|
|
|
|
+ width: 14.2857%;
|
|
|
|
+ line-height: 24px;
|
|
|
|
+ height: 28px;
|
|
|
|
+ // border-radius: 4px;
|
|
|
|
+ padding:2px;
|
|
|
|
+
|
|
|
|
+ div{
|
|
|
|
+ background-color:#fff;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ .datepicker-ctrl p {
|
|
|
|
+ width: 65%;
|
|
|
|
+ }
|
|
|
|
+ .datepicker-ctrl span {
|
|
|
|
+ position: absolute;
|
|
|
|
+ }
|
|
|
|
+ .datepicker-body span {
|
|
|
|
+ text-align: center;
|
|
|
|
+ }
|
|
|
|
+ .datepicker-monthRange span{
|
|
|
|
+ width: 48px;
|
|
|
|
+ height: 50px;
|
|
|
|
+ line-height: 45px;
|
|
|
|
+ }
|
|
|
|
+ .datepicker-item-disable {
|
|
|
|
+ background-color: white!important;
|
|
|
|
+ cursor: not-allowed!important;
|
|
|
|
+ }
|
|
|
|
+ .decadeRange span:first-child,
|
|
|
|
+ .decadeRange span:last-child,
|
|
|
|
+ .datepicker-item-disable,
|
|
|
|
+ .datepicker-item-gray{
|
|
|
|
+ color: #999;
|
|
|
|
+ }
|
|
|
|
+ .datepicker-dateRange-item-active:hover,
|
|
|
|
+ .datepicker-dateRange-item-active {
|
|
|
|
+ background: rgb(50, 118, 177)!important;
|
|
|
|
+ color: white!important;
|
|
|
|
+ }
|
|
|
|
+ .datepicker-monthRange {
|
|
|
|
+ margin-top: 10px
|
|
|
|
+ }
|
|
|
|
+ .datepicker-monthRange span,
|
|
|
|
+ .datepicker-ctrl span,
|
|
|
|
+ .datepicker-ctrl p,
|
|
|
|
+ .datepicker-dateRange span {
|
|
|
|
+ cursor: pointer;
|
|
|
|
+ }
|
|
|
|
+ .datepicker-monthRange span:hover,
|
|
|
|
+ .datepicker-ctrl p:hover,
|
|
|
|
+ .datepicker-ctrl i:hover,
|
|
|
|
+ .datepicker-dateRange span:hover,
|
|
|
|
+ .datepicker-dateRange-item-hover {
|
|
|
|
+ background-color : #eeeeee;
|
|
|
|
+ }
|
|
|
|
+ .datepicker-dateRange {
|
|
|
|
+ .daytoday-start,
|
|
|
|
+ .daytoday-start:hover,
|
|
|
|
+ .daytoday-end,
|
|
|
|
+ .daytoday-end:hover{
|
|
|
|
+ background: rgb(50, 118, 177)!important;
|
|
|
|
+ color: white!important;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ .datepicker-dateRange .daytoday-range,
|
|
|
|
+ .datepicker-dateRange .daytoday-range:hover{
|
|
|
|
+ background-color: #ddd;
|
|
|
|
+ }
|
|
|
|
+ .datepicker-weekRange span{
|
|
|
|
+ font-weight: bold;
|
|
|
|
+ }
|
|
|
|
+ .datepicker-label{
|
|
|
|
+ background-color: #f8f8f8;
|
|
|
|
+ font-weight: 700;
|
|
|
|
+ padding: 7px 0;
|
|
|
|
+ text-align: center;
|
|
|
|
+ }
|
|
|
|
+ .datepicker-ctrl{
|
|
|
|
+ position: relative;
|
|
|
|
+ /*height: 30px;*/
|
|
|
|
+ line-height: 30px;
|
|
|
|
+ font-weight: bold;
|
|
|
|
+ text-align: center;
|
|
|
|
+ }
|
|
|
|
+ .month-btn{
|
|
|
|
+ font-weight: bold;
|
|
|
|
+ -webkit-user-select:none;
|
|
|
|
+ -moz-user-select:none;
|
|
|
|
+ -ms-user-select:none;
|
|
|
|
+ user-select:none;
|
|
|
|
+ }
|
|
|
|
+ .datepicker-preBtn{
|
|
|
|
+ left: 2px;
|
|
|
|
+ }
|
|
|
|
+ .datepicker-nextBtn{
|
|
|
|
+ right: 2px;
|
|
|
|
+ }
|
|
|
|
+</style>
|