mirror of
				https://github.com/crater-invoice/crater.git
				synced 2025-10-31 13:41:09 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			650 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Vue
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			650 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Vue
		
	
	
		
			Executable File
		
	
	
	
	
| <template>
 | |
|   <div :class="[wrapperClass, isRtl ? 'rtl' : '']" class="base-date-input">
 | |
|     <date-input
 | |
|       :selected-date="selectedDate"
 | |
|       :reset-typed-date="resetTypedDate"
 | |
|       :format="customFormatter"
 | |
|       :translation="translation"
 | |
|       :inline="inline"
 | |
|       :id="id"
 | |
|       :name="name"
 | |
|       :ref-name="refName"
 | |
|       :open-date="openDate"
 | |
|       :placeholder="placeholder"
 | |
|       :input-class="inputClass"
 | |
|       :typeable="typeable"
 | |
|       :clear-button="clearButton"
 | |
|       :clear-button-icon="clearButtonIcon"
 | |
|       :calendar-button="calendarButton"
 | |
|       :calendar-button-icon="calendarButtonIcon"
 | |
|       :calendar-button-icon-content="calendarButtonIconContent"
 | |
|       :disabled="disabled"
 | |
|       :required="required"
 | |
|       :class="{'required-date': invalid}"
 | |
|       :bootstrap-styling="bootstrapStyling"
 | |
|       :use-utc="useUtc"
 | |
|       @showCalendar="showCalendar"
 | |
|       @closeCalendar="close"
 | |
|       @typedDate="setTypedDate"
 | |
|       @clearDate="clearDate">
 | |
|       <slot slot="afterDateInput" name="afterDateInput"/>
 | |
|     </date-input>
 | |
| 
 | |
|     <!-- Day View -->
 | |
|     <picker-day
 | |
|       v-if="allowedToShowView('day')"
 | |
|       :page-date="pageDate"
 | |
|       :selected-date="selectedDate"
 | |
|       :show-day-view="showDayView"
 | |
|       :full-month-name="fullMonthName"
 | |
|       :allowed-to-show-view="allowedToShowView"
 | |
|       :disabled-dates="disabledDates"
 | |
|       :highlighted="highlighted"
 | |
|       :calendar-class="calendarClass"
 | |
|       :calendar-style="calendarStyle"
 | |
|       :translation="translation"
 | |
|       :page-timestamp="pageTimestamp"
 | |
|       :is-rtl="isRtl"
 | |
|       :monday-first="mondayFirst"
 | |
|       :day-cell-content="dayCellContent"
 | |
|       :use-utc="useUtc"
 | |
|       @changedMonth="handleChangedMonthFromDayPicker"
 | |
|       @selectDate="selectDate"
 | |
|       @showMonthCalendar="showMonthCalendar"
 | |
|       @selectedDisabled="selectDisabledDate">
 | |
|       <slot slot="beforeCalendarHeader" name="beforeCalendarHeader"/>
 | |
|     </picker-day>
 | |
| 
 | |
|     <!-- Month View -->
 | |
|     <picker-month
 | |
|       v-if="allowedToShowView('month')"
 | |
|       :page-date="pageDate"
 | |
|       :selected-date="selectedDate"
 | |
|       :show-month-view="showMonthView"
 | |
|       :allowed-to-show-view="allowedToShowView"
 | |
|       :disabled-dates="disabledDates"
 | |
|       :calendar-class="calendarClass"
 | |
|       :calendar-style="calendarStyle"
 | |
|       :translation="translation"
 | |
|       :is-rtl="isRtl"
 | |
|       :use-utc="useUtc"
 | |
|       @selectMonth="selectMonth"
 | |
|       @showYearCalendar="showYearCalendar"
 | |
|       @changedYear="setPageDate">
 | |
|       <slot slot="beforeCalendarHeader" name="beforeCalendarHeader"/>
 | |
|     </picker-month>
 | |
| 
 | |
|     <!-- Year View -->
 | |
|     <picker-year
 | |
|       v-if="allowedToShowView('year')"
 | |
|       :page-date="pageDate"
 | |
|       :selected-date="selectedDate"
 | |
|       :show-year-view="showYearView"
 | |
|       :allowed-to-show-view="allowedToShowView"
 | |
|       :disabled-dates="disabledDates"
 | |
|       :calendar-class="calendarClass"
 | |
|       :calendar-style="calendarStyle"
 | |
|       :translation="translation"
 | |
|       :is-rtl="isRtl"
 | |
|       :use-utc="useUtc"
 | |
|       @selectYear="selectYear"
 | |
|       @changedDecade="setPageDate">
 | |
|       <slot slot="beforeCalendarHeader" name="beforeCalendarHeader"/>
 | |
|     </picker-year>
 | |
|   </div>
 | |
| </template>
 | |
| <script>
 | |
| import en from './src/locale/translations/en'
 | |
| import DateInput from './DateInput'
 | |
| import PickerDay from './PickerDay.vue'
 | |
| import PickerMonth from './PickerMonth.vue'
 | |
| import PickerYear from './PickerYear.vue'
 | |
| import utils, { makeDateUtils } from './src/DateUtils'
 | |
| import { mapGetters } from 'vuex'
 | |
| import moment from 'moment'
 | |
| 
 | |
| export default {
 | |
|   components: {
 | |
|     DateInput,
 | |
|     PickerDay,
 | |
|     PickerMonth,
 | |
|     PickerYear
 | |
|   },
 | |
|   props: {
 | |
|     value: {
 | |
|       validator: val => utils.validateDateInput(val)
 | |
|     },
 | |
|     name: String,
 | |
|     refName: String,
 | |
|     id: String,
 | |
|     // format: {
 | |
|     //   type: [String, Function],
 | |
|     //   default: 'dd MMM yyyy'
 | |
|     // },
 | |
|     language: {
 | |
|       type: Object,
 | |
|       default: () => en
 | |
|     },
 | |
|     openDate: {
 | |
|       validator: val => utils.validateDateInput(val)
 | |
|     },
 | |
|     dayCellContent: Function,
 | |
|     fullMonthName: Boolean,
 | |
|     disabledDates: Object,
 | |
|     highlighted: Object,
 | |
|     placeholder: String,
 | |
|     inline: Boolean,
 | |
|     calendarClass: [String, Object, Array],
 | |
|     inputClass: [String, Object, Array],
 | |
|     wrapperClass: [String, Object, Array],
 | |
|     mondayFirst: Boolean,
 | |
|     clearButton: Boolean,
 | |
|     clearButtonIcon: String,
 | |
|     calendarButton: Boolean,
 | |
|     calendarButtonIcon: String,
 | |
|     calendarButtonIconContent: String,
 | |
|     bootstrapStyling: Boolean,
 | |
|     initialView: String,
 | |
|     disabled: Boolean,
 | |
|     required: Boolean,
 | |
|     invalid: Boolean,
 | |
|     typeable: Boolean,
 | |
|     useUtc: Boolean,
 | |
|     minimumView: {
 | |
|       type: String,
 | |
|       default: 'day'
 | |
|     },
 | |
|     maximumView: {
 | |
|       type: String,
 | |
|       default: 'year'
 | |
|     }
 | |
|   },
 | |
|   data () {
 | |
|     const startDate = this.openDate ? new Date(this.openDate) : new Date()
 | |
|     const constructedDateUtils = makeDateUtils(this.useUtc)
 | |
|     const pageTimestamp = constructedDateUtils.setDate(startDate, 1)
 | |
|     return {
 | |
|       /*
 | |
|        * Vue cannot observe changes to a Date Object so date must be stored as a timestamp
 | |
|        * This represents the first day of the current viewing month
 | |
|        * {Number}
 | |
|        */
 | |
|       pageTimestamp,
 | |
|       /*
 | |
|        * Selected Date
 | |
|        * {Date}
 | |
|        */
 | |
|       selectedDate: null,
 | |
|       /*
 | |
|        * Flags to show calendar views
 | |
|        * {Boolean}
 | |
|        */
 | |
|       showDayView: false,
 | |
|       showMonthView: false,
 | |
|       showYearView: false,
 | |
|       /*
 | |
|        * Positioning
 | |
|        */
 | |
|       calendarHeight: 0,
 | |
|       resetTypedDate: new Date(),
 | |
|       utils: constructedDateUtils
 | |
|     }
 | |
|   },
 | |
|   watch: {
 | |
|     value (value) {
 | |
|       this.setValue(value)
 | |
|     },
 | |
|     openDate () {
 | |
|       this.setPageDate()
 | |
|     },
 | |
|     initialView () {
 | |
|       this.setInitialView()
 | |
|     }
 | |
|   },
 | |
|   computed: {
 | |
|     ...mapGetters('preferences', {
 | |
|       'format': 'getMomentDateFormat'
 | |
|     }),
 | |
|     customFormatter () {
 | |
|       let newDate = new Date(this.value)
 | |
|       return moment(newDate).format(this.format)
 | |
|     },
 | |
|     computedInitialView () {
 | |
|       if (!this.initialView) {
 | |
|         return this.minimumView
 | |
|       }
 | |
| 
 | |
|       return this.initialView
 | |
|     },
 | |
|     pageDate () {
 | |
|       return new Date(this.pageTimestamp)
 | |
|     },
 | |
| 
 | |
|     translation () {
 | |
|       return this.language
 | |
|     },
 | |
| 
 | |
|     calendarStyle () {
 | |
|       return {
 | |
|         position: this.isInline ? 'static' : undefined
 | |
|       }
 | |
|     },
 | |
|     isOpen () {
 | |
|       return this.showDayView || this.showMonthView || this.showYearView
 | |
|     },
 | |
|     isInline () {
 | |
|       return !!this.inline
 | |
|     },
 | |
|     isRtl () {
 | |
|       return this.translation.rtl === true
 | |
|     }
 | |
|   },
 | |
|   mounted () {
 | |
|     this.init()
 | |
|   },
 | |
|   methods: {
 | |
|     /**
 | |
|      * Called in the event that the user navigates to date pages and
 | |
|      * closes the picker without selecting a date.
 | |
|      */
 | |
|     resetDefaultPageDate () {
 | |
|       if (this.selectedDate === null) {
 | |
|         this.setPageDate()
 | |
|         return
 | |
|       }
 | |
|       this.setPageDate(this.selectedDate)
 | |
|     },
 | |
|     /**
 | |
|      * Effectively a toggle to show/hide the calendar
 | |
|      * @return {mixed}
 | |
|      */
 | |
|     showCalendar () {
 | |
|       if (this.disabled || this.isInline) {
 | |
|         return false
 | |
|       }
 | |
|       if (this.isOpen) {
 | |
|         return this.close(true)
 | |
|       }
 | |
|       this.setInitialView()
 | |
|     },
 | |
|     /**
 | |
|      * Sets the initial picker page view: day, month or year
 | |
|      */
 | |
|     setInitialView () {
 | |
|       const initialView = this.computedInitialView
 | |
|       if (!this.allowedToShowView(initialView)) {
 | |
|         throw new Error(`initialView '${this.initialView}' cannot be rendered based on minimum '${this.minimumView}' and maximum '${this.maximumView}'`)
 | |
|       }
 | |
|       switch (initialView) {
 | |
|         case 'year':
 | |
|           this.showYearCalendar()
 | |
|           break
 | |
|         case 'month':
 | |
|           this.showMonthCalendar()
 | |
|           break
 | |
|         default:
 | |
|           this.showDayCalendar()
 | |
|           break
 | |
|       }
 | |
|     },
 | |
|     /**
 | |
|      * Are we allowed to show a specific picker view?
 | |
|      * @param {String} view
 | |
|      * @return {Boolean}
 | |
|      */
 | |
|     allowedToShowView (view) {
 | |
|       const views = ['day', 'month', 'year']
 | |
|       const minimumViewIndex = views.indexOf(this.minimumView)
 | |
|       const maximumViewIndex = views.indexOf(this.maximumView)
 | |
|       const viewIndex = views.indexOf(view)
 | |
| 
 | |
|       return viewIndex >= minimumViewIndex && viewIndex <= maximumViewIndex
 | |
|     },
 | |
|     /**
 | |
|      * Show the day picker
 | |
|      * @return {Boolean}
 | |
|      */
 | |
|     showDayCalendar () {
 | |
|       if (!this.allowedToShowView('day')) {
 | |
|         return false
 | |
|       }
 | |
|       this.close()
 | |
|       this.showDayView = true
 | |
|       return true
 | |
|     },
 | |
|     /**
 | |
|      * Show the month picker
 | |
|      * @return {Boolean}
 | |
|      */
 | |
|     showMonthCalendar () {
 | |
|       if (!this.allowedToShowView('month')) {
 | |
|         return false
 | |
|       }
 | |
|       this.close()
 | |
|       this.showMonthView = true
 | |
|       return true
 | |
|     },
 | |
|     /**
 | |
|      * Show the year picker
 | |
|      * @return {Boolean}
 | |
|      */
 | |
|     showYearCalendar () {
 | |
|       if (!this.allowedToShowView('year')) {
 | |
|         return false
 | |
|       }
 | |
|       this.close()
 | |
|       this.showYearView = true
 | |
|       return true
 | |
|     },
 | |
|     /**
 | |
|      * Set the selected date
 | |
|      * @param {Number} timestamp
 | |
|      */
 | |
|     setDate (timestamp) {
 | |
|       const date = new Date(timestamp)
 | |
|       this.selectedDate = date
 | |
|       this.setPageDate(date)
 | |
|       this.$emit('selected', date)
 | |
|       this.$emit('input', date)
 | |
|     },
 | |
|     /**
 | |
|      * Clear the selected date
 | |
|      */
 | |
|     clearDate () {
 | |
|       this.selectedDate = null
 | |
|       this.setPageDate()
 | |
|       this.$emit('selected', null)
 | |
|       this.$emit('input', null)
 | |
|       this.$emit('cleared')
 | |
|     },
 | |
|     /**
 | |
|      * @param {Object} date
 | |
|      */
 | |
|     selectDate (date) {
 | |
|       this.setDate(date.timestamp)
 | |
|       if (!this.isInline) {
 | |
|         this.close(true)
 | |
|       }
 | |
|       this.resetTypedDate = new Date()
 | |
|     },
 | |
|     /**
 | |
|      * @param {Object} date
 | |
|      */
 | |
|     selectDisabledDate (date) {
 | |
|       this.$emit('selectedDisabled', date)
 | |
|     },
 | |
|     /**
 | |
|      * @param {Object} month
 | |
|      */
 | |
|     selectMonth (month) {
 | |
|       const date = new Date(month.timestamp)
 | |
|       if (this.allowedToShowView('day')) {
 | |
|         this.setPageDate(date)
 | |
|         this.$emit('changedMonth', month)
 | |
|         this.showDayCalendar()
 | |
|       } else {
 | |
|         this.selectDate(month)
 | |
|       }
 | |
|     },
 | |
|     /**
 | |
|      * @param {Object} year
 | |
|      */
 | |
|     selectYear (year) {
 | |
|       const date = new Date(year.timestamp)
 | |
|       if (this.allowedToShowView('month')) {
 | |
|         this.setPageDate(date)
 | |
|         this.$emit('changedYear', year)
 | |
|         this.showMonthCalendar()
 | |
|       } else {
 | |
|         this.selectDate(year)
 | |
|       }
 | |
|     },
 | |
|     /**
 | |
|      * Set the datepicker value
 | |
|      * @param {Date|String|Number|null} date
 | |
|      */
 | |
|     setValue (date) {
 | |
|       if (typeof date === 'string' || typeof date === 'number') {
 | |
|         let parsed = new Date(date)
 | |
|         date = isNaN(parsed.valueOf()) ? null : parsed
 | |
|       }
 | |
|       if (!date) {
 | |
|         this.setPageDate()
 | |
|         this.selectedDate = null
 | |
|         return
 | |
|       }
 | |
|       this.selectedDate = date
 | |
|       this.setPageDate(date)
 | |
|     },
 | |
|     /**
 | |
|      * Sets the date that the calendar should open on
 | |
|      */
 | |
|     setPageDate (date) {
 | |
|       if (!date) {
 | |
|         if (this.openDate) {
 | |
|           date = new Date(this.openDate)
 | |
|         } else {
 | |
|           date = new Date()
 | |
|         }
 | |
|       }
 | |
|       this.pageTimestamp = this.utils.setDate(new Date(date), 1)
 | |
|     },
 | |
|     /**
 | |
|      * Handles a month change from the day picker
 | |
|      */
 | |
|     handleChangedMonthFromDayPicker (date) {
 | |
|       this.setPageDate(date)
 | |
|       this.$emit('changedMonth', date)
 | |
|     },
 | |
|     /**
 | |
|      * Set the date from a typedDate event
 | |
|      */
 | |
|     setTypedDate (date) {
 | |
|       this.setDate(date.getTime())
 | |
|     },
 | |
|     /**
 | |
|      * Close all calendar layers
 | |
|      * @param {Boolean} emitEvent - emit close event
 | |
|      */
 | |
|     close (emitEvent) {
 | |
|       this.showDayView = this.showMonthView = this.showYearView = false
 | |
|       if (!this.isInline) {
 | |
|         if (emitEvent) {
 | |
|           this.$emit('closed')
 | |
|         }
 | |
|         document.removeEventListener('click', this.clickOutside, false)
 | |
|       }
 | |
|     },
 | |
|     /**
 | |
|      * Initiate the component
 | |
|      */
 | |
|     init () {
 | |
|       if (this.value) {
 | |
|         this.setValue(this.value)
 | |
|       }
 | |
|       if (this.isInline) {
 | |
|         this.setInitialView()
 | |
|       }
 | |
|     }
 | |
|   },
 | |
| }
 | |
| // eslint-disable-next-line
 | |
| ;
 | |
| </script>
 | |
| <style lang="css">
 | |
| .rtl {
 | |
| 	direction: rtl;
 | |
| }
 | |
| 
 | |
| .required-date {
 | |
|   border: 1px solid #FB7178;
 | |
|   border-radius: 5px;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker {
 | |
| 	position: relative;
 | |
| 	text-align: left;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker * {
 | |
| 	box-sizing: border-box;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar {
 | |
| 	position: absolute;
 | |
| 	z-index: 100;
 | |
| 	background: #fff;
 | |
| 	width: 300px;
 | |
| 	border: 1px solid #ccc;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar header {
 | |
| 	display: block;
 | |
| 	line-height: 40px;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar header span {
 | |
| 	display: inline-block;
 | |
| 	text-align: center;
 | |
| 	width: 71.42857142857143%;
 | |
| 	float: left;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar header .prev,
 | |
| .vdp-datepicker__calendar header .next {
 | |
| 	width: 14.285714285714286%;
 | |
| 	float: left;
 | |
| 	text-indent: -10000px;
 | |
| 	position: relative;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar header .prev:after,
 | |
| .vdp-datepicker__calendar header .next:after {
 | |
| 	content: '';
 | |
| 	position: absolute;
 | |
| 	left: 50%;
 | |
| 	top: 50%;
 | |
| 	transform: translateX(-50%) translateY(-50%);
 | |
| 	border: 6px solid transparent;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar header .prev:after {
 | |
| 	border-right: 10px solid #000;
 | |
| 	margin-left: -5px;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar header .prev.disabled:after {
 | |
| 	border-right: 10px solid #ddd;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar header .next:after {
 | |
| 	border-left: 10px solid #000;
 | |
| 	margin-left: 5px;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar header .next.disabled:after {
 | |
| 	border-left: 10px solid #ddd;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar header .prev:not(.disabled),
 | |
| .vdp-datepicker__calendar header .next:not(.disabled),
 | |
| .vdp-datepicker__calendar header .up:not(.disabled) {
 | |
| 	cursor: pointer;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar header .prev:not(.disabled):hover,
 | |
| .vdp-datepicker__calendar header .next:not(.disabled):hover,
 | |
| .vdp-datepicker__calendar header .up:not(.disabled):hover {
 | |
| 	background: #eee;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar .disabled {
 | |
| 	color: #ddd;
 | |
| 	cursor: default;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar .flex-rtl {
 | |
| 	display: flex;
 | |
| 	width: inherit;
 | |
| 	flex-wrap: wrap;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar .cell {
 | |
| 	display: inline-block;
 | |
| 	padding: 0 5px;
 | |
| 	width: 14.285714285714286%;
 | |
| 	height: 40px;
 | |
| 	line-height: 40px;
 | |
| 	text-align: center;
 | |
| 	vertical-align: middle;
 | |
| 	border: 1px solid transparent;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar .cell:not(.blank):not(.disabled).day,
 | |
| .vdp-datepicker__calendar .cell:not(.blank):not(.disabled).month,
 | |
| .vdp-datepicker__calendar .cell:not(.blank):not(.disabled).year {
 | |
| 	cursor: pointer;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar .cell:not(.blank):not(.disabled).day:hover,
 | |
| .vdp-datepicker__calendar .cell:not(.blank):not(.disabled).month:hover,
 | |
| .vdp-datepicker__calendar .cell:not(.blank):not(.disabled).year:hover {
 | |
| 	border: 1px solid #4bd;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar .cell.selected {
 | |
| 	background: #4bd;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar .cell.selected:hover {
 | |
| 	background: #4bd;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar .cell.selected.highlighted {
 | |
| 	background: #4bd;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar .cell.highlighted {
 | |
| 	background: #cae5ed;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar .cell.highlighted.disabled {
 | |
| 	color: #a3a3a3;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar .cell.grey {
 | |
| 	color: #888;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar .cell.grey:hover {
 | |
| 	background: inherit;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar .cell.day-header {
 | |
| 	font-size: 75%;
 | |
| 	white-space: nowrap;
 | |
| 	cursor: inherit;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar .cell.day-header:hover {
 | |
| 	background: inherit;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__calendar .month,
 | |
| .vdp-datepicker__calendar .year {
 | |
| 	width: 33.333%;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__clear-button,
 | |
| .vdp-datepicker__calendar-button {
 | |
| 	cursor: pointer;
 | |
| 	font-style: normal;
 | |
| }
 | |
| 
 | |
| .vdp-datepicker__clear-button.disabled,
 | |
| .vdp-datepicker__calendar-button.disabled {
 | |
| 	color: #999;
 | |
| 	cursor: default;
 | |
| }
 | |
| </style>
 |