Last active
March 5, 2018 00:26
-
-
Save isuke/2ceb61d0babefa0324151892ad97aa71 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| export default | |
| props: | |
| $_calendarable_defaultYear: | |
| type: Number | |
| require: false | |
| default: -> moment().year() | |
| note: "current display year. default today's year." | |
| $_calendarable_defaultMonth: | |
| type: Number | |
| require: false | |
| default: -> moment().month() + 1 | |
| note: "current display month. default today's month." | |
| $_calendarable_defaultSelectedDates: | |
| type: Array | |
| require: false | |
| default: -> [moment().format('YYYY-MM-DD')] | |
| note: "default initial selected date. ex) ['2018-01-15']. default today." | |
| $_calendarable_startDayOfWeek: | |
| type: Number | |
| require: false | |
| default: 1 | |
| note: "start day of week. 0: Sun, 1: Mon, .., 6: sat" | |
| $_calendarable_selectMode: | |
| type: String | |
| require: false | |
| default: 'single' | |
| validator: (val) -> ['single', 'multiple', 'range'].includes(val) | |
| node: "select mode. 'single', 'multiple' or 'range'." | |
| $_calendarable_disableDates: | |
| type: Array | |
| require: false | |
| default: -> [] | |
| # default: -> # DEBUG | |
| # [ | |
| # (momentValue) -> (momentValue.day() == 3 || momentValue.day() == 4) | |
| # ] | |
| note: """ | |
| disable any date. | |
| ex) | |
| [ | |
| function(momentValue) { | |
| return (momentValue.day() === 0 || momentValue.day() === 6); | |
| }, | |
| function(date) { | |
| return momentValue.isBefore('2018-03-15'); | |
| }, | |
| ] | |
| """ | |
| $_calendarable_classes: | |
| type: Object | |
| require: false | |
| dafault: -> [] | |
| # default: -> # DEBUG | |
| # { | |
| # '-special': (momentValue) -> | |
| # range = moment.range(moment('2018-3-5'), moment('2018-3-13')) | |
| # momentValue.within(range) | |
| # } | |
| note: """ | |
| Attach any (HTML) classes by date. | |
| ex) | |
| { | |
| 'special-date': function(momentValue) { | |
| const range = moment.range(moment('2018-3-5'), moment('2018-3-13')) | |
| return momentValue.within(range) | |
| } | |
| }); | |
| """ | |
| $_calendarable_weekNames: | |
| type: Array | |
| require: true | |
| default: -> ['日', '月', '火', '水', '木', '金', '土'] | |
| validator: (val) -> val.length == 7 | |
| note: "day of week names. must start from Sunday. ex) ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']" | |
| computed: | |
| $_calendarable_isSingleMode: -> @$_calendarable_selectMode == 'single' | |
| $_calendarable_isMultipleMode: -> @$_calendarable_selectMode == 'multiple' | |
| $_calendarable_isRangeMode: -> @$_calendarable_selectMode == 'range' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <template lang="pug"> | |
| .smart-calendar | |
| .buttons | |
| button.prev(@click="subtractMonth") ◀ | |
| button.next(@click="addMonth") ▶ | |
| p.title {{currentYear}}年 {{currentMonth}}月 | |
| table.table | |
| thead.head | |
| tr.row | |
| td.col(v-for="dayOfWeek in weekIndexes", :class="headClass(dayOfWeek)") {{$_calendarable_weekNames[dayOfWeek]}} | |
| tbody.body | |
| tr.row(v-for="week in calendar") | |
| td.col( | |
| v-for="date in week", | |
| :class="dateClass(date)", | |
| @click="selecteDate(date)" | |
| @mouseover="hoverDate(date)") {{date.day}} | |
| </template> | |
| <script lang="coffee"> | |
| import calendarable from '@scripts/mixins/calendarable.coffee' | |
| export default | |
| name: 'SmartCalendar' | |
| introduction: "TODO" | |
| token: """ | |
| <smart-calendar> | |
| </smart-calendar> | |
| """ | |
| description: """ | |
| <p>TODO</p> | |
| """ | |
| mixins: [calendarable] | |
| data: -> | |
| weekForClassName: ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'] | |
| currentYear: undefined | |
| currentMonth: undefined | |
| selectedDates: [] | |
| isSelectingRange: false | |
| hoverStartDate: | |
| year: undefined | |
| month: undefined | |
| date: undefined | |
| dayOfWeek: undefined | |
| hoverdDate: | |
| year: undefined | |
| month: undefined | |
| date: undefined | |
| dayOfWeek: undefined | |
| computed: | |
| calendar: -> | |
| currentMonthMoment = @createMoment() | |
| prevMonthMoment = currentMonthMoment.clone().subtract(1, 'month') | |
| nextMonthMoment = currentMonthMoment.clone().add(1, 'month') | |
| prevMonthLastDay = prevMonthMoment.daysInMonth() | |
| currentMonthLastDay = currentMonthMoment.daysInMonth() | |
| currentMonthFirstDayOfWeek = @weekIndexes.indexOf(currentMonthMoment.day()) | |
| nextMonthFirstDayOfWeek = @weekIndexes.indexOf(nextMonthMoment.day()) | |
| prevMonthYear = prevMonthMoment.year() | |
| currentMonthYear = currentMonthMoment.year() | |
| nextMonthYear = nextMonthMoment.year() | |
| prevMonth = prevMonthMoment.month() + 1 | |
| currentMonth = currentMonthMoment.month() + 1 | |
| nextMonth = nextMonthMoment.month() + 1 | |
| calendar = [] | |
| dayIdx = 1 | |
| for w in [0..5] | |
| week = [] | |
| break if currentMonthLastDay < dayIdx | |
| for d in [0..6] | |
| if w == 0 and d < currentMonthFirstDayOfWeek | |
| week[d] = | |
| year: prevMonthYear | |
| month: prevMonth | |
| day: prevMonthLastDay - (currentMonthFirstDayOfWeek - d) + 1 | |
| dayOfWeek: @weekIndexes[d] | |
| else if currentMonthLastDay < dayIdx | |
| week[d] = | |
| year: nextMonthYear | |
| month: nextMonth | |
| day: d - nextMonthFirstDayOfWeek + 1 | |
| dayOfWeek: @weekIndexes[d] | |
| dayIdx++ | |
| else | |
| week[d] = | |
| year: currentMonthYear | |
| month: currentMonth | |
| day: dayIdx | |
| dayOfWeek: @weekIndexes[d] | |
| dayIdx++ | |
| calendar.push(week) | |
| calendar | |
| weekIndexes: -> | |
| w = [0..6] | |
| _.times @$_calendarable_startDayOfWeek, (_n) => | |
| tail = _.tail(w) | |
| tail.push(_.head(w)) | |
| w = tail | |
| w | |
| methods: | |
| createMoment: (year = @currentYear, month = @currentMonth, day = 1) -> moment({ year: year, month: month - 1, day: day}) | |
| createMomentByDate: (date) -> @createMoment(date.year, date.month, date.day) | |
| createMomentRangeByDates: (date1, date2) -> | |
| moment1 = @createMomentByDate(date1) | |
| moment2 = @createMomentByDate(date2) | |
| if moment1.isBefore(moment2) | |
| moment.range(moment1, moment2) | |
| else | |
| moment.range(moment2, moment1) | |
| toDateFromMoment: (moment) -> | |
| { | |
| year: moment.year() | |
| month: moment.month() + 1 | |
| day: moment.date() | |
| dayOfWeek: moment.day() | |
| } | |
| toDatesFromMomentRaange: (momentRange, ignoreDisable = true) -> | |
| _(Array.from(momentRange.by('days'))) | |
| .map (moment) => | |
| @toDateFromMoment(moment) if ignoreDisable && ! @isDisable(moment) | |
| .compact() | |
| .value() | |
| addMonth: -> | |
| nextMonthMoment = @createMoment().add(1, 'month') | |
| @currentYear = nextMonthMoment.year() | |
| @currentMonth = nextMonthMoment.month() + 1 | |
| @$emit('update:month', @currentYear, @currentMonth) | |
| subtractMonth: -> | |
| prevMonthMoment = @createMoment().subtract(1, 'month') | |
| @currentYear = prevMonthMoment.year() | |
| @currentMonth = prevMonthMoment.month() + 1 | |
| @$emit('update:month', @currentYear, @currentMonth) | |
| selecteDate: (date) -> | |
| moment = @createMomentByDate(date) | |
| unless @isDisable(moment) | |
| switch @$_calendarable_selectMode | |
| when 'single' | |
| @selectedDates = [date] | |
| when 'multiple' | |
| if @includesDate(@selectedDates, date) | |
| @selectedDates = _.filter @selectedDates, (selectedDate) => ! @isEqDate(selectedDate, date) | |
| else | |
| @selectedDates.push(date) | |
| when 'range' | |
| if @isSelectingRange | |
| @isSelectingRange = false | |
| hoverEndDate = @hoverdDate || @hoverStartDate | |
| rangeMoment = @createMomentRangeByDates(@hoverStartDate, hoverEndDate) | |
| @selectedDates = @toDatesFromMomentRaange(rangeMoment) | |
| @hoverStartDate = undefined | |
| @hoverdDate = undefined | |
| else | |
| @selectedDates = [] | |
| @hoverStartDate = date | |
| @isSelectingRange = true | |
| else | |
| throw "error" | |
| @$emit('update:date', @selectedDates) | |
| hoverDate: (date) -> | |
| if @$_calendarable_isRangeMode && @isSelectingRange | |
| @hoverdDate = date | |
| headClass: (dayOfWeek) -> | |
| { | |
| "-#{@weekForClassName[dayOfWeek]}": true | |
| } | |
| dateClass: (date) -> | |
| moment = @createMomentByDate(date) | |
| if @$_calendarable_isRangeMode && @isSelectingRange && @hoverStartDate && @hoverdDate | |
| momentRange = @createMomentRangeByDates(@hoverStartDate, @hoverdDate) | |
| result = { | |
| '-selected': @includesDate(@selectedDates, date) | |
| "-#{@weekForClassName[date.dayOfWeek]}": true | |
| "-disable": @isDisable(moment) | |
| "-inhover": momentRange && moment.within(momentRange) | |
| "-hoverstart": momentRange && momentRange.start.isSame(moment) | |
| "-hoverend": momentRange && momentRange.end.isSame(moment) | |
| } | |
| _.forEach @$_calendarable_classes, (func, className) => result[className] = true if func(moment) | |
| result | |
| isEqDate: (date1, date2) -> | |
| date1.year == date2.year && | |
| date1.month == date2.month && | |
| date1.day == date2.day | |
| includesDate: (dates, date) -> | |
| _.reduce dates, (result, d) => | |
| result || @isEqDate(d, date) | |
| , false | |
| isDisable: (moment) -> | |
| _.reduce @$_calendarable_disableDates, (result, func) => | |
| result || func(moment) | |
| , false | |
| created: -> | |
| @currentYear = @$_calendarable_defaultYear | |
| @currentMonth = @$_calendarable_defaultMonth | |
| _.forEach @$_calendarable_defaultSelectedDates, (defaultSelectedDate) => | |
| m = moment(defaultSelectedDate, 'YYYY-MM-DD') | |
| d = @toDateFromMoment(m) | |
| @selectedDates.push(d) | |
| mounted: -> null | |
| </script> | |
| <style lang="stylus" scoped> | |
| .smart-calendar { | |
| background-color: white; /* DEBUG */ | |
| color: black; /* DEBUG */ | |
| > .table { | |
| > .head, > .body { | |
| .row { | |
| .col { | |
| border: 1px solid black; /* DEBUG */ | |
| &.-sun { | |
| background-color: #FF6666; /* DEBUG */ | |
| } | |
| &.-sat { | |
| background-color: #6666FF; /* DEBUG */ | |
| } | |
| } | |
| } | |
| } | |
| > .head { | |
| .row { | |
| .col { | |
| } | |
| } | |
| } | |
| > .body { | |
| .row { | |
| .col { | |
| cursor: pointer; | |
| &.-special { /* DEBUG */ | |
| &:before { content: "★" } | |
| } | |
| &.-inhover { | |
| text-decoration: underline; | |
| } | |
| &.-hoverstart { | |
| &:before { content: "【" } /* DEBUG */ | |
| } | |
| &.-hoverend { | |
| &:after { content: "】" } /* DEBUG */ | |
| } | |
| &.-selected { | |
| color: red; /* DEBUG */ | |
| } | |
| &.-disable { | |
| cursor: default; | |
| background-color: gray; /* DEBUG */ | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| </style> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <template lang="pug"> | |
| .smart-datepicker | |
| smart-calendar( | |
| :$_calendarable_default-year="$_calendarable_defaultYear", | |
| :$_calendarable_default-month="$_calendarable_defaultMonth", | |
| :$_calendarable_default-selected-dates="$_calendarable_defaultSelectedDates", | |
| :$_calendarable_start-day-of-week="$_calendarable_startDayOfWeek", | |
| :$_calendarable_select-mode="$_calendarable_selectMode", | |
| :$_calendarable_disable-dates="$_calendarable_disableDates", | |
| :$_calendarable_classes="$_calendarable_classes", | |
| :$_calendarable_week-names="$_calendarable_weekNames", | |
| @update:date="selectDate") | |
| input.input(type="text", :value="dateStr") | |
| </template> | |
| <script lang="coffee"> | |
| import SmartCalendar from '@components/SmartCalendar.vue' | |
| import calendarable from '@scripts/mixins/calendarable.coffee' | |
| export default | |
| name: 'SmartDatepicker' | |
| introduction: "TODO" | |
| token: """ | |
| <smart-datepicker> | |
| </smart-datepicker> | |
| """ | |
| description: """ | |
| <p>TODO</p> | |
| """ | |
| mixins: [calendarable] | |
| data: -> | |
| dates: [] | |
| computed: | |
| dateStr: -> | |
| _(@dates) | |
| .map (date) => | |
| "#{date.year}/#{date.month}/#{date.day}" | |
| .join(', ') | |
| methods: | |
| selectDate: (value) -> | |
| @dates = value | |
| components: | |
| 'smart-calendar': SmartCalendar | |
| </script> | |
| <style lang="stylus" scoped> | |
| .smart-datepicker {} | |
| </style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment