Created
September 27, 2018 09:28
-
-
Save lucafaggianelli/634bd129d726f9d7410e2480897bb931 to your computer and use it in GitHub Desktop.
Calendar sample
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> | |
| <v-layout> | |
| <v-flex xs12> | |
| <v-card> | |
| <v-toolbar flat> | |
| <!-- Today Button --> | |
| <v-tooltip bottom> | |
| <v-btn slot="activator" | |
| flat | |
| color="primary" | |
| :icon="$vuetify.breakpoint.smAndDown" | |
| @click="setToday"> | |
| <span v-if="$vuetify.breakpoint.mdAndUp">{{ labels.today }}</span> | |
| <v-icon v-else>{{ labels.todayIcon }}</v-icon> | |
| </v-btn> | |
| <span>{{ todayDate }}</span> | |
| </v-tooltip> | |
| <!-- Prev and Next Buttons --> | |
| <v-tooltip bottom> | |
| <v-btn slot="activator" | |
| icon | |
| flat | |
| @click="prev"> | |
| <v-icon>keyboard_arrow_left</v-icon> | |
| </v-btn> | |
| <span>{{ prevLabel }}</span> | |
| </v-tooltip> | |
| <v-tooltip bottom> | |
| <v-btn slot="activator" | |
| icon | |
| flat | |
| @click="next"> | |
| <v-icon>keyboard_arrow_right</v-icon> | |
| </v-btn> | |
| <span>{{ nextLabel }}</span> | |
| </v-tooltip> | |
| <span class="title">{{ summary }}</span> | |
| <v-spacer></v-spacer> | |
| <v-menu> | |
| <v-btn flat slot="activator"> | |
| {{ currentType.label }} | |
| <v-icon>arrow_drop_down</v-icon> | |
| </v-btn> | |
| <v-list> | |
| <v-list-tile v-for="type in types" | |
| :key="type.id" | |
| @click="currentType = type"> | |
| <v-list-tile-content> | |
| <v-list-tile-title>{{ type.label }}</v-list-tile-title> | |
| </v-list-tile-content> | |
| <v-list-tile-action>{{ type.shortcut }}</v-list-tile-action> | |
| </v-list-tile> | |
| </v-list> | |
| </v-menu> | |
| </v-toolbar> | |
| <ds-gestures | |
| @swipeleft="next" | |
| @swiperight="prev"> | |
| <div v-if="currentType.schedule" class="ds-expand"> | |
| <ds-agenda | |
| :calendar="calendar" | |
| @add="add" | |
| @edit="edit" | |
| @view-day="viewDay"> | |
| </ds-agenda> | |
| </div> | |
| <div v-else class="ds-expand"> | |
| <ds-calendar ref="calendar" | |
| :calendar="calendar" | |
| @add="add" | |
| @add-at="addAt" | |
| @edit="edit" | |
| @view-day="viewDay" | |
| @added="handleAdd" | |
| @moved="handleMove"> | |
| </ds-calendar> | |
| </div> | |
| </ds-gestures> | |
| </v-card> | |
| <ds-event-dialog ref="eventDialog" | |
| v-bind="{$scopedSlots}" | |
| v-on="$listeners" | |
| :calendar="calendar" | |
| @saved="eventFinish" | |
| @actioned="eventFinish"> | |
| </ds-event-dialog> | |
| <v-dialog ref="optionsDialog" | |
| v-model="optionsVisible" | |
| v-bind="optionsDialog" | |
| :fullscreen="$dayspan.fullscreenDialogs"> | |
| <v-list> | |
| <template v-for="option in options"> | |
| <v-list-tile :key="option.text" @click="chooseOption( option )"> | |
| {{ option.text }} | |
| </v-list-tile> | |
| </template> | |
| </v-list> | |
| </v-dialog> | |
| <v-dialog ref="promptDialog" | |
| v-model="promptVisible" | |
| v-bind="promptDialog"> | |
| <v-card> | |
| <v-card-title>{{ promptQuestion }}</v-card-title> | |
| <v-card-actions> | |
| <v-btn color="primary" flat @click="choosePrompt( true )"> | |
| {{ labels.promptConfirm }} | |
| </v-btn> | |
| <v-spacer></v-spacer> | |
| <v-btn color="secondary" flat @click="choosePrompt( false )"> | |
| {{ labels.promptCancel }} | |
| </v-btn> | |
| </v-card-actions> | |
| </v-card> | |
| </v-dialog> | |
| <v-fab-transition> | |
| <v-btn | |
| class="ds-add-event-today" | |
| color="primary" | |
| fixed bottom right fab | |
| v-model="allowsAddToday" | |
| @click="addToday"> | |
| <v-icon>add</v-icon> | |
| </v-btn> | |
| </v-fab-transition> | |
| </v-flex> | |
| </v-layout> | |
| </template> | |
| <script> | |
| import { Sorts, Calendar, Op, Weekday } from 'dayspan' | |
| export default { | |
| name: 'app', | |
| data () { | |
| return { | |
| calendar: Calendar.months(), | |
| types: this.$dayspan.defaults.dsCalendarApp.types, | |
| optionsDialog: this.$dayspan.defaults.dsCalendarApp.optionsDialog, | |
| promptDialog: this.$dayspan.defaults.dsCalendarApp.promptDialog, | |
| labels: this.$dayspan.defaults.dsCalendarApp.labels, | |
| formats: this.$dayspan.defaults.dsCalendarApp.formats, | |
| allowsAddToday: true, | |
| drawer: null, | |
| optionsVisible: false, | |
| options: [], | |
| promptVisible: false, | |
| promptQuestion: '', | |
| promptCallback: null, | |
| events: [ | |
| { | |
| data: { | |
| title: 'PDC', | |
| color: '#3F51B5' | |
| }, | |
| schedule: { | |
| dayOfWeek: [Weekday.WEDNESDAY], | |
| times: [9], | |
| duration: 4, | |
| durationUnit: 'hours' | |
| } | |
| }, | |
| { | |
| data: { | |
| title: 'SB', | |
| color: '#4CAF50' | |
| }, | |
| schedule: { | |
| dayOfWeek: [Weekday.THURSDAY], | |
| duration: 3, | |
| durationUnit: 'hours' | |
| } | |
| } | |
| ] | |
| } | |
| }, | |
| computed: { | |
| currentType: { | |
| get () { | |
| return this.types.find((type) => | |
| type.type === this.calendar.type && | |
| type.size === this.calendar.size | |
| ) || this.types[0] | |
| }, | |
| set (type) { | |
| this.rebuild(undefined, true, type) | |
| } | |
| }, | |
| summary () { | |
| let small = this.$vuetify.breakpoint.xs | |
| if (small) { | |
| return this.calendar.start.format(this.formats.xs) | |
| } | |
| let large = this.$vuetify.breakpoint.mdAndUp | |
| return this.calendar.summary(false, !large, false, !large) | |
| }, | |
| todayDate () { | |
| return this.$dayspan.today.format(this.formats.today) | |
| }, | |
| nextLabel () { | |
| return this.labels.next(this.currentType) | |
| }, | |
| prevLabel () { | |
| return this.labels.prev(this.currentType) | |
| }, | |
| toolbarStyle () { | |
| let large = this.$vuetify.breakpoint.lgAndUp | |
| return large ? this.styles.toolbar.large : this.styles.toolbar.small | |
| }, | |
| hasCreatePopover () { | |
| return !!this.$scopedSlots.eventCreatePopover | |
| } | |
| }, | |
| methods: | |
| { | |
| setState (state) { | |
| state.eventSorter = state.listTimes | |
| ? Sorts.List([Sorts.FullDay, Sorts.Start]) | |
| : Sorts.Start | |
| this.calendar.set(state) | |
| this.triggerChange() | |
| }, | |
| applyEvents () { | |
| if (this.events) { | |
| this.calendar.removeEvents() | |
| this.calendar.addEvents(this.events) | |
| } | |
| }, | |
| isType (type, aroundDay) { | |
| let cal = this.calendar | |
| return (cal.type === type.type && cal.size === type.size && | |
| (!aroundDay || cal.span.matchesDay(aroundDay))) | |
| }, | |
| rebuild (aroundDay, force, forceType) { | |
| let type = forceType || this.currentType || this.types[ 2 ] | |
| if (this.isType(type, aroundDay) && !force) { | |
| return | |
| } | |
| let input = { | |
| type: type.type, | |
| size: type.size, | |
| around: aroundDay, | |
| eventsOutside: true, | |
| preferToday: false, | |
| listTimes: type.listTimes, | |
| updateRows: type.updateRows, | |
| updateColumns: type.listTimes, | |
| fill: !type.listTimes, | |
| otherwiseFocus: type.focus, | |
| repeatCovers: type.repeat | |
| } | |
| this.setState(input) | |
| }, | |
| next () { | |
| this.calendar.unselect().next() | |
| this.triggerChange() | |
| }, | |
| prev () { | |
| this.calendar.unselect().prev() | |
| this.triggerChange() | |
| }, | |
| setToday () { | |
| this.rebuild(this.$dayspan.today) | |
| }, | |
| viewDay (day) { | |
| this.rebuild(day, false, this.types[0]) | |
| }, | |
| edit (calendarEvent) { | |
| let eventDialog = this.$refs.eventDialog | |
| eventDialog.edit(calendarEvent) | |
| }, | |
| editPlaceholder (createEdit) { | |
| let placeholder = createEdit.calendarEvent | |
| let details = createEdit.details | |
| let eventDialog = this.$refs.eventDialog | |
| let calendar = this.$refs.calendar | |
| eventDialog.addPlaceholder(placeholder, details) | |
| eventDialog.$once('close', calendar.clearPlaceholder) | |
| }, | |
| add (day) { | |
| if (!this.$dayspan.features.addDay) { | |
| return | |
| } | |
| let eventDialog = this.$refs.eventDialog | |
| let calendar = this.$refs.calendar | |
| let useDialog = !this.hasCreatePopover | |
| calendar.addPlaceholder(day, true, useDialog) | |
| if (useDialog) { | |
| eventDialog.add(day) | |
| eventDialog.$once('close', calendar.clearPlaceholder) | |
| } | |
| }, | |
| addAt (dayHour) { | |
| if (!this.$dayspan.features.addTime) { | |
| return | |
| } | |
| let eventDialog = this.$refs.eventDialog | |
| let calendar = this.$refs.calendar | |
| let useDialog = !this.hasCreatePopover | |
| let at = dayHour.day.withHour(dayHour.hour) | |
| calendar.addPlaceholder(at, false, useDialog) | |
| if (useDialog) { | |
| eventDialog.addAt(dayHour.day, dayHour.hour) | |
| eventDialog.$once('close', calendar.clearPlaceholder) | |
| } | |
| }, | |
| addToday () { | |
| if (!this.$dayspan.features.addDay) { | |
| return | |
| } | |
| let eventDialog = this.$refs.eventDialog | |
| let calendar = this.$refs.calendar | |
| let useDialog = !this.hasCreatePopover || !calendar | |
| let day = this.$dayspan.today | |
| if (!this.calendar.filled.matchesDay(day)) { | |
| let first = this.calendar.days[ 0 ] | |
| let last = this.calendar.days[ this.calendar.days.length - 1 ] | |
| let firstDistance = Math.abs(first.currentOffset) | |
| let lastDistance = Math.abs(last.currentOffset) | |
| day = firstDistance < lastDistance ? first : last | |
| } | |
| calendar && calendar.addPlaceholder(day, true, useDialog) | |
| if (useDialog) { | |
| eventDialog.add(day) | |
| calendar && eventDialog.$once('close', calendar.clearPlaceholder) | |
| } | |
| }, | |
| handleAdd (addEvent) { | |
| let eventDialog = this.$refs.eventDialog | |
| let calendar = this.$refs.calendar | |
| addEvent.handled = true | |
| if (!this.hasCreatePopover) { | |
| if (addEvent.placeholder.fullDay) { | |
| eventDialog.add(addEvent.span.start, addEvent.span.days(Op.UP)) | |
| } else { | |
| eventDialog.addSpan(addEvent.span) | |
| } | |
| eventDialog.$once('close', addEvent.clearPlaceholder) | |
| } else { | |
| calendar.placeholderForCreate = true | |
| } | |
| }, | |
| handleMove (moveEvent) { | |
| let calendarEvent = moveEvent.calendarEvent | |
| let target = moveEvent.target | |
| let targetStart = target.start | |
| let sourceStart = calendarEvent.time.start | |
| let schedule = calendarEvent.schedule | |
| let options = [] | |
| moveEvent.handled = true | |
| let callbacks = { | |
| cancel: () => { | |
| moveEvent.clearPlaceholder() | |
| }, | |
| single: () => { | |
| calendarEvent.move(targetStart) | |
| this.eventsRefresh() | |
| moveEvent.clearPlaceholder() | |
| this.$emit('event-update', calendarEvent.event) | |
| }, | |
| instance: () => { | |
| calendarEvent.move(targetStart) | |
| this.eventsRefresh() | |
| moveEvent.clearPlaceholder() | |
| this.$emit('event-update', calendarEvent.event) | |
| }, | |
| duplicate: () => { | |
| schedule.setExcluded(targetStart, false) | |
| this.eventsRefresh() | |
| moveEvent.clearPlaceholder() | |
| this.$emit('event-update', calendarEvent.event) | |
| }, | |
| all: () => { | |
| schedule.moveTime(sourceStart.asTime(), targetStart.asTime()) | |
| this.eventsRefresh() | |
| moveEvent.clearPlaceholder() | |
| this.$emit('event-update', calendarEvent.event) | |
| } | |
| } | |
| options.push({ | |
| text: this.labels.moveCancel, | |
| callback: callbacks.cancel | |
| }) | |
| if (schedule.isSingleEvent()) { | |
| options.push({ | |
| text: this.labels.moveSingleEvent, | |
| callback: callbacks.single | |
| }) | |
| if (this.$dayspan.features.moveDuplicate) { | |
| options.push({ | |
| text: this.labels.moveDuplicate, | |
| callback: callbacks.duplicate | |
| }) | |
| } | |
| } else { | |
| if (this.$dayspan.features.moveInstance) { | |
| options.push({ | |
| text: this.labels.moveOccurrence, | |
| callback: callbacks.instance | |
| }) | |
| } | |
| if (this.$dayspan.features.moveDuplicate) { | |
| options.push({ | |
| text: this.labels.moveDuplicate, | |
| callback: callbacks.duplicate | |
| }) | |
| } | |
| if (this.$dayspan.features.moveAll && | |
| !schedule.isFullDay() && | |
| targetStart.sameDay(sourceStart)) { | |
| options.push({ | |
| text: this.labels.moveAll, | |
| callback: callbacks.all | |
| }) | |
| } | |
| } | |
| this.options = options | |
| this.optionsVisible = true | |
| }, | |
| chooseOption (option) { | |
| if (option) { | |
| option.callback() | |
| } | |
| this.optionsVisible = false | |
| }, | |
| choosePrompt (yes) { | |
| this.promptCallback(yes) | |
| this.promptVisible = false | |
| }, | |
| eventFinish (ev) { | |
| this.triggerChange() | |
| }, | |
| eventsRefresh () { | |
| this.calendar.refreshEvents() | |
| this.triggerChange() | |
| }, | |
| triggerChange () { | |
| this.$emit('change', { | |
| calendar: this.calendar | |
| }) | |
| }, | |
| loadState () { | |
| let state = {} | |
| state.events = this.events | |
| state.events.forEach(ev => { | |
| let defaults = this.$dayspan.getDefaultEventDetails() | |
| ev.data = Object.assign(defaults, ev.data) | |
| }) | |
| this.setState(state) | |
| } | |
| }, | |
| mounted () { | |
| if (!this.$dayspan.promptOpen) { | |
| this.$dayspan.promptOpen = (question, callback) => { | |
| this.promptVisible = false | |
| this.promptQuestion = question | |
| this.promptCallback = callback | |
| this.promptVisible = true | |
| } | |
| } | |
| this.loadState() | |
| }, | |
| watch: { | |
| 'events': () => this.applyEvents, | |
| 'calendar': () => this.applyEvents | |
| } | |
| } | |
| </script> | |
| <style> | |
| .ds-day .ds-out-calendar a.ds-dom { | |
| color: #757575; | |
| } | |
| </style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment