Created
September 27, 2018 09:28
-
-
Save lucafaggianelli/634bd129d726f9d7410e2480897bb931 to your computer and use it in GitHub Desktop.
Calendar sample
This file contains 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