Skip to content

Instantly share code, notes, and snippets.

@lucafaggianelli
Created September 27, 2018 09:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lucafaggianelli/634bd129d726f9d7410e2480897bb931 to your computer and use it in GitHub Desktop.
Save lucafaggianelli/634bd129d726f9d7410e2480897bb931 to your computer and use it in GitHub Desktop.
Calendar sample
<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