Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 31 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,36 +99,37 @@ Inline always open version
```
## Available props

| Prop | Type | Default | Description |
|-------------------------------|-----------------|-------------|------------------------------------------|
| value | Date\|String | | Date value of the datepicker |
| name | String | | Input name property |
| id | String | | Input id |
| format | String\|Function| dd MMM yyyy | Date formatting string or function |
| full-month-name | Boolean | false | To show the full month name |
| language | Object | en | Translation for days and months |
| disabled-dates | Object | | See below for configuration |
| placeholder | String | | Input placeholder text |
| inline | Boolean | | To show the datepicker always open |
| calendar-class | String\|Object | | CSS class applied to the calendar el |
| input-class | String\|Object | | CSS class applied to the input el |
| wrapper-class | String\|Object | | CSS class applied to the outer div |
| monday-first | Boolean | false | To start the week on Monday |
| clear-button | Boolean | false | Show an icon for clearing the date |
| clear-button-icon | String | | Use icon for button (ex: fa fa-times) |
| calendar-button | Boolean | false | Show an icon that that can be clicked |
| calendar-button-icon | String | | Use icon for button (ex: fa fa-calendar) |
| calendar-button-icon-content | String | | Use for material-icons (ex: event) |
| day-cell-content | Function | | Use to render custom content in day cell |
| bootstrap-styling | Boolean | false | Output bootstrap v4 styling classes. |
| initial-view | String | minimumView | If set, open on that view |
| disabled | Boolean | false | If true, disable Datepicker on screen |
| required | Boolean | false | Sets html required attribute on input |
| typeable | Boolean | false | If true, allow the user to type the date |
| use-utc | Boolean | false | use UTC for time calculations |
| open-date | Date\|String | | If set, open on that date |
| minimum-view | String | 'day' | If set, lower-level views won't show |
| maximum-view | String | 'year' | If set, higher-level views won't show |
| Prop | Type | Default | Description |
|------------------------------|------------------|-------------|------------------------------------------|
| value | Date\|String | | Date value of the datepicker |
| name | String | | Input name property |
| id | String | | Input id |
| format | String\|Function | dd MMM yyyy | Date formatting string or function |
| full-month-name | Boolean | false | To show the full month name |
| language | Object | en | Translation for days and months |
| disabled-dates | Object | | See below for configuration |
| placeholder | String | | Input placeholder text |
| inline | Boolean | | To show the datepicker always open |
| calendar-class | String\|Object | | CSS class applied to the calendar el |
| input-class | String\|Object | | CSS class applied to the input el |
| wrapper-class | String\|Object | | CSS class applied to the outer div |
| monday-first | Boolean | false | To start the week on Monday |
| calendarweek | Boolean | false | To display the calendar week |
| clear-button | Boolean | false | Show an icon for clearing the date |
| clear-button-icon | String | | Use icon for button (ex: fa fa-times) |
| calendar-button | Boolean | false | Show an icon that that can be clicked |
| calendar-button-icon | String | | Use icon for button (ex: fa fa-calendar) |
| calendar-button-icon-content | String | | Use for material-icons (ex: event) |
| day-cell-content | Function | | Use to render custom content in day cell |
| bootstrap-styling | Boolean | false | Output bootstrap v4 styling classes. |
| initial-view | String | minimumView | If set, open on that view |
| disabled | Boolean | false | If true, disable Datepicker on screen |
| required | Boolean | false | Sets html required attribute on input |
| typeable | Boolean | false | If true, allow the user to type the date |
| use-utc | Boolean | false | use UTC for time calculations |
| open-date | Date\|String | | If set, open on that date |
| minimum-view | String | 'day' | If set, lower-level views won't show |
| maximum-view | String | 'year' | If set, higher-level views won't show |


## Events
Expand Down
2 changes: 2 additions & 0 deletions src/components/Datepicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
:pageTimestamp="pageTimestamp"
:isRtl="isRtl"
:mondayFirst="mondayFirst"
:calendarWeek="calendarWeek"
:dayCellContent="dayCellContent"
:use-utc="useUtc"
@changedMonth="handleChangedMonthFromDayPicker"
Expand Down Expand Up @@ -135,6 +136,7 @@ export default {
inputClass: [String, Object, Array],
wrapperClass: [String, Object, Array],
mondayFirst: Boolean,
calendarWeek: Boolean,
clearButton: Boolean,
clearButtonIcon: String,
calendarButton: Boolean,
Expand Down
43 changes: 38 additions & 5 deletions src/components/PickerDay.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div :class="[calendarClass, 'vdp-datepicker__calendar']" v-show="showDayView" :style="calendarStyle" @mousedown.prevent>
<div :class="[calendarClass, 'vdp-datepicker__calendar', {'vdp-datepicker__calendar--week': calendarWeek}]" v-show="showDayView" :style="calendarStyle" @mousedown.prevent>
<slot name="beforeCalendarHeader"></slot>
<header>
<span
Expand All @@ -12,17 +12,22 @@
class="next"
:class="{'disabled': isRightNavDisabled}">&gt;</span>
</header>
<div :class="isRtl ? 'flex-rtl' : ''">
<div :class="{ 'flex-ltr': !isRtl, 'flex-rtl': isRtl }">
<span v-if="calendarWeek" class="cell day-header">{{ translation.calendarweek }}</span>
<span class="cell day-header" v-for="d in daysOfWeek" :key="d.timestamp">{{ d }}</span>
<span v-if="calendarWeek" class="cell weeknumber">{{ weeknumber(0) }}</span>
<template v-if="blankDays > 0">
<span class="cell day blank" v-for="d in blankDays" :key="d.timestamp"></span>
</template><!--
--><span class="cell day"
v-for="day in days"
</template>
<template v-for="(day, index) in days">
<span v-if="showCalendarWeek(day, index)" class="cell weeknumber">{{ weeknumber(index + 1) }}</span>
<span class="cell day"
:key="day.timestamp"
:class="dayClasses(day)"
v-html="dayCellContent(day)"
@click="selectDate(day)"></span>
<span v-if="showCalendarWeek(day, index, false)" class="cell weeknumber">{{ weeknumber(index + 1) }}</span>
</template>
</div>
</div>
</template>
Expand All @@ -47,6 +52,7 @@ export default {
translation: Object,
isRtl: Boolean,
mondayFirst: Boolean,
calendarWeek: Boolean,
useUtc: Boolean
},
data () {
Expand Down Expand Up @@ -367,6 +373,33 @@ export default {
*/
isDefined (prop) {
return typeof prop !== 'undefined' && prop
},
/**
* Whether the calender week shoud be displayed
* @param {Object} day
* @param {Number} index
* @param {Boolean} before
* @return {Boolean}
*/
showCalendarWeek (day, index, before = true) {
let show = false
if (this.calendarWeek && day.isSunday) {
if (before) {
show = !this.mondayFirst && index > 0
} else {
show = this.mondayFirst && index < this.days.length - 1
}
}

return show
},
/**
* Get calendar week for specific day
* @param {Number} index
* @return {Number}
*/
weeknumber (index) {
return this.utils.getWeekNumber(new Date(this.days[index].timestamp))
}
}
}
Expand Down
14 changes: 13 additions & 1 deletion src/locale/Language.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
export default class Language {
constructor (language, months, monthsAbbr, days) {
constructor (language, months, monthsAbbr, days, calendarweek) {
this.language = language
this.months = months
this.monthsAbbr = monthsAbbr
this.days = days
this.calendarweek = calendarweek
this.rtl = false
this.ymd = false
this.yearSuffix = ''
Expand Down Expand Up @@ -52,6 +53,17 @@ export default class Language {
}
this._days = days
}

get calendarweek () {
return this._calendarweek
}

set calendarweek (calendarweek = '') {
if (typeof calendarweek !== 'string') {
throw new TypeError('Calendar week must be a string')
}
this._calendarweek = calendarweek
}
}
// eslint-disable-next-line
;
3 changes: 2 additions & 1 deletion src/locale/translations/de.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ export default new Language(
'German',
['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'],
['So.', 'Mo.', 'Di.', 'Mi.', 'Do.', 'Fr.', 'Sa.']
['So.', 'Mo.', 'Di.', 'Mi.', 'Do.', 'Fr.', 'Sa.'],
'KW'
)
// eslint-disable-next-line
;
3 changes: 2 additions & 1 deletion src/locale/translations/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ export default new Language(
'English',
['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
'CW'
)
// eslint-disable-next-line
;
17 changes: 17 additions & 0 deletions src/styles/style.styl
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@
.disabled
color #ddd
cursor default
.flex-ltr
display flex
width 100%
flex-wrap wrap
.flex-rtl
display flex
width inherit
Expand Down Expand Up @@ -106,6 +110,19 @@
.year
width 33.333%

.vdp-datepicker__calendar--week
.weeknumber
color #999
.cell
width (100/8)%
header
span
width (100 - (100/8)*2)%

.prev
.next
width (100/8)%

.vdp-datepicker__clear-button
.vdp-datepicker__calendar-button
cursor pointer
Expand Down
15 changes: 15 additions & 0 deletions src/utils/DateUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,21 @@ const utils = {
return this.useUtc ? date.getUTCMinutes() : date.getMinutes()
},

/**
* Returns the weeknumber, using UTC or not
* - thursday in current week decides the year
* - january 4 is always in week 1
* - adjust to thursday in week 1 and count number of weeks from date to week1
* @param {Date} date
*/
getWeekNumber (date) {
this.useUtc ? date.setUTCHours(0, 0, 0, 0) : date.setHours(0, 0, 0, 0)
this.setDate(date, this.getDate(date) + 3 - (this.getDay(date) + 6) % 7)
const week1 = new Date(this.getFullYear(date), 0, 4)

return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 - 3 + (this.getDay(week1) + 6) % 7) / 7)
},

/**
* Sets the full year, using UTC or not
* @param {Date} date
Expand Down
17 changes: 17 additions & 0 deletions test/unit/specs/DateUtils.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,17 @@ describe('DateUtils', () => {
it('getMonthName accepts a number', () => {
expect(DateUtils.getMonthNameAbbr(3, en.monthsAbbr)).toEqual('Apr')
})

it('should give correct week number', () => {
expect(DateUtils.getWeekNumber(new Date(2018, 9, 31))).toEqual(44)
expect(DateUtils.getWeekNumber(new Date(2018, 9, 22))).toEqual(43)
expect(DateUtils.getWeekNumber(new Date(2018, 9, 20))).toEqual(42)
expect(DateUtils.getWeekNumber(new Date(2018, 9, 20), true)).toEqual(42)
})

it('calendarweek equals cw', () => {
expect(en.calendarweek).toEqual('CW')
})
})

describe('daysInMonth', () => {
Expand Down Expand Up @@ -163,6 +174,12 @@ describe('UTC functions', () => {
expect(utcUtils.getMinutes(date)).toEqual(date.getUTCMinutes())
})

it('getMinutes', () => {
const date = new Date(2018, 9, 31)
expect(DateUtils.getMinutes(date)).toEqual(date.getMinutes())
expect(utcUtils.getMinutes(date)).toEqual(date.getUTCMinutes())
})

it('setFullYear', () => {
const date = getAmbiguousDate()
expect(DateUtils.setFullYear(date, 2018)).toEqual(date.setFullYear(2018))
Expand Down
4 changes: 4 additions & 0 deletions test/unit/specs/Locale/Language.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@ describe('Language class', () => {
it('should throw when there are not exacty 7 days', () => {
expect(() => new Language('a', months, months, ['m', 't', 'w'])).toThrow(RangeError)
})

it('should throw when calendarweek is not a string', () => {
expect(() => new Language('a', months, months, days, 1)).toThrow(TypeError)
})
})
72 changes: 72 additions & 0 deletions test/unit/specs/PickerDay/calendarWeek.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import PickerDay from '@/components/PickerDay.vue'
import {shallow} from '@vue/test-utils'
import {en} from '@/locale'

describe('PickerDay: Datepicker with calendar week and sunday as first day of week', () => {
let wrapper
beforeEach(() => {
wrapper = shallow(PickerDay, {
propsData: {
calendarWeek: true,
translation: en,
allowedToShowView: () => true,
pageDate: new Date(2018, 9, 1)
}
})
})

it('should return false to show calendar week if day is sunday and index equals zero', () => {
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[0], 0)).toEqual(false)
})

it('should return false to show calendar week if day is not sunday', () => {
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[1], 1)).toEqual(false)
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[2], 2)).toEqual(false)
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[3], 3)).toEqual(false)
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[4], 4)).toEqual(false)
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[5], 5)).toEqual(false)
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[7], 7)).toEqual(false)
})

it('should return true to show calendar week if day is sunday', () => {
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[6], 6)).toEqual(true)
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[13], 13)).toEqual(true)
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[20], 20)).toEqual(true)
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[27], 27)).toEqual(true)
})
})

describe('PickerDay: Datepicker with calendar week and monday as first day of week', () => {
let wrapper
beforeEach(() => {
wrapper = shallow(PickerDay, {
propsData: {
calendarWeek: true,
mondayFirst: true,
translation: en,
allowedToShowView: () => true,
pageDate: new Date(2019, 2, 1)
}
})
})

it('should return false to show calendar week if day is sunday and index equals number of days', () => {
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[30], 30, false)).toEqual(false)
})

it('should return false to show calendar week if day is not sunday', () => {
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[1], 1, false)).toEqual(false)
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[3], 3, false)).toEqual(false)
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[4], 4, false)).toEqual(false)
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[5], 5, false)).toEqual(false)
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[6], 6, false)).toEqual(false)
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[7], 7, false)).toEqual(false)
})

it('should return true to show calendar week if day is sunday', () => {
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[2], 2, false)).toEqual(true)
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[9], 9, false)).toEqual(true)
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[16], 16, false)).toEqual(true)
expect(wrapper.vm.showCalendarWeek(wrapper.vm.days[23], 23, false)).toEqual(true)
})
})