Duplicate calendar event

Signed-off-by: rogelio-o <yo@rogelioorts.com>
Signed-off-by: szaimen <szaimen@e.mail.de>
Signed-off-by: Richard Steinmetz <richard@steinmetz.cloud>
This commit is contained in:
rogelio-o 2020-10-02 18:33:38 +02:00 committed by Richard Steinmetz
parent cb9590cb5f
commit 04c0f9e7eb
No known key found for this signature in database
GPG Key ID: 27137D9E7D273FB2
6 changed files with 117 additions and 2 deletions

View File

@ -116,6 +116,9 @@ export default {
}, {
keys: [['Ctrl+Delete']],
label: t('calendar', 'Delete edited event'),
}, {
keys: [['Ctrl+d']],
label: t('calendar', 'Duplicate event'),
}],
}]
},

View File

@ -444,6 +444,14 @@ export default {
this.deleteAndLeave(false)
}
},
keyboardDuplicateEvent(event) {
if (event.key === 'd' && event.ctrlKey === true) {
event.preventDefault()
if (!this.isNew && !this.isReadOnly && !this.canCreateRecurrenceException) {
this.duplicateEvent()
}
}
},
/**
* Saves a calendar-object
*
@ -480,6 +488,16 @@ export default {
this.requiresActionOnRouteLeave = false
this.closeEditor()
},
/**
* Duplicates a calendar-object and saves it
*
* @return {Promise<void>}
*/
async duplicateEvent() {
await this.$store.dispatch('duplicateCalendarObjectInstance')
},
/**
* Deletes a calendar-object
*

View File

@ -21,8 +21,8 @@
*/
import { getDateFromDateTimeValue } from '../utils/date.js'
import { DurationValue } from '@nextcloud/calendar-js'
import { getHexForColorName } from '../utils/color.js'
import { DurationValue, DateTimeValue } from '@nextcloud/calendar-js'
import { getHexForColorName, getClosestCSS3ColorNameForHex } from '../utils/color.js'
import { mapAlarmComponentToAlarmObject } from './alarm.js'
import { mapAttendeePropertyToAttendeeObject } from './attendee.js'
import {
@ -179,7 +179,53 @@ const mapEventComponentToEventObject = (eventComponent) => {
return eventObject
}
/**
* Copy data from a calendar-object-instance into a calendar-js event-component
*
* @param {object} eventObject The calendar-object-instance object
* @param {EventComponent} eventComponent The calendar-js EventComponent object
*/
const copyCalendarObjectInstanceIntoEventComponent = (eventObject, eventComponent) => {
eventComponent.title = eventObject.title
eventComponent.location = eventObject.location
eventComponent.description = eventObject.description
eventComponent.accessClass = eventObject.accessClass
eventComponent.status = eventObject.status
eventComponent.timeTransparency = eventObject.timeTransparency
for (const category of eventObject.categories) {
eventComponent.addCategory(category)
}
if (eventObject.organizer) {
eventComponent.setOrganizerFromNameAndEMail(eventObject.organizer.commonName, eventObject.organizer.uri)
}
for (const alarm of eventObject.alarms) {
if (alarm.isRelative) {
const duration = DurationValue.fromSeconds(alarm.relativeTrigger)
eventComponent.addRelativeAlarm(alarm.type, duration, alarm.relativeIsRelatedToStart)
} else {
const date = DateTimeValue.fromJSDate(alarm.absoluteDate)
eventComponent.addAbsoluteAlarm(alarm.type, date)
}
}
for (const attendee of eventObject.attendees) {
eventComponent.addProperty(attendee.attendeeProperty)
}
for (const rule of eventObject.eventComponent.getPropertyIterator('RRULE')) {
eventComponent.addProperty(rule)
}
if (eventObject.customColor) {
eventComponent.color = getClosestCSS3ColorNameForHex(eventObject.customColor)
}
}
export {
getDefaultEventObject,
mapEventComponentToEventObject,
copyCalendarObjectInstanceIntoEventComponent,
}

View File

@ -27,6 +27,7 @@ import {
import { AttendeeProperty, Property, DateTimeValue, DurationValue, RecurValue } from '@nextcloud/calendar-js'
import { getBySetPositionAndBySetFromDate, getWeekDayFromDate } from '../utils/recurrence.js'
import {
copyCalendarObjectInstanceIntoEventComponent,
getDefaultEventObject,
mapEventComponentToEventObject,
} from '../models/event.js'
@ -1567,6 +1568,33 @@ const actions = {
}
},
/**
* Duplicate calendar-object-instance
*
* @param {object} vuex The vuex destructuring object
* @param {object} vuex.state The Vuex state
* @param {Function} vuex.dispatch The Vuex dispatch function
* @param {Function} vuex.commit The Vuex commit function
* @return {Promise<void>}
*/
async duplicateCalendarObjectInstance({ state, dispatch, commit }) {
const oldCalendarObjectInstance = state.calendarObjectInstance
const oldEventComponent = oldCalendarObjectInstance.eventComponent
const startDate = oldEventComponent.startDate.getInUTC()
const endDate = oldEventComponent.endDate.getInUTC()
const calendarObject = await dispatch('createNewEvent', {
start: startDate.unixTime,
end: endDate.unixTime,
timezoneId: oldEventComponent.startDate.timezoneId,
isAllDay: oldEventComponent.isAllDay(),
})
const eventComponent = getObjectAtRecurrenceId(calendarObject, startDate.jsDate)
copyCalendarObjectInstanceIntoEventComponent(oldCalendarObjectInstance, eventComponent)
const calendarObjectInstance = mapEventComponentToEventObject(eventComponent)
await commit('setCalendarObjectInstanceForNewEvent', { calendarObject, calendarObjectInstance })
},
/**
* Deletes a calendar-object-instance
*

View File

@ -63,6 +63,12 @@
</template>
{{ $t('calendar', 'Export') }}
</ActionLink>
<ActionButton v-if="!canCreateRecurrenceException && !isReadOnly" @click="duplicateEvent()">
<template #icon>
<ContentDuplicate :size="20" decorative />
</template>
{{ $t('calendar', 'Duplicate') }}
</ActionButton>
<ActionButton v-if="canDelete && !canCreateRecurrenceException" @click="deleteAndLeave(false)">
<template #icon>
<Delete :size="20" decorative />
@ -252,6 +258,7 @@ import AccountMultiple from 'vue-material-design-icons/AccountMultiple.vue'
import CalendarBlank from 'vue-material-design-icons/CalendarBlank.vue'
import Delete from 'vue-material-design-icons/Delete.vue'
import Download from 'vue-material-design-icons/Download.vue'
import ContentDuplicate from 'vue-material-design-icons/ContentDuplicate.vue'
import InformationOutline from 'vue-material-design-icons/InformationOutline.vue'
import MapMarker from 'vue-material-design-icons/MapMarker.vue'
@ -279,6 +286,7 @@ export default {
CalendarBlank,
Delete,
Download,
ContentDuplicate,
InformationOutline,
MapMarker,
InvitationResponseButtons,
@ -326,11 +334,13 @@ export default {
window.addEventListener('keydown', this.keyboardCloseEditor)
window.addEventListener('keydown', this.keyboardSaveEvent)
window.addEventListener('keydown', this.keyboardDeleteEvent)
window.addEventListener('keydown', this.keyboardDuplicateEvent)
},
beforeDestroy() {
window.removeEventListener('keydown', this.keyboardCloseEditor)
window.removeEventListener('keydown', this.keyboardSaveEvent)
window.removeEventListener('keydown', this.keyboardDeleteEvent)
window.removeEventListener('keydown', this.keyboardDuplicateEvent)
},
methods: {
/**

View File

@ -73,6 +73,12 @@
</template>
{{ $t('calendar', 'Export') }}
</ActionLink>
<ActionButton v-if="!canCreateRecurrenceException && !isReadOnly" @click="duplicateEvent()">
<template #icon>
<ContentDuplicate :size="20" decorative />
</template>
{{ $t('calendar', 'Duplicate') }}
</ActionButton>
<ActionButton v-if="canDelete && !canCreateRecurrenceException" @click="deleteAndLeave(false)">
<template #icon>
<Delete :size="20" decorative />
@ -177,6 +183,7 @@ import CalendarBlank from 'vue-material-design-icons/CalendarBlank.vue'
import Close from 'vue-material-design-icons/Close.vue'
import Delete from 'vue-material-design-icons/Delete.vue'
import Download from 'vue-material-design-icons/Download.vue'
import ContentDuplicate from 'vue-material-design-icons/ContentDuplicate.vue'
import { mapState } from 'vuex'
export default {
@ -198,6 +205,7 @@ export default {
CalendarBlank,
Close,
Download,
ContentDuplicate,
Delete,
InvitationResponseButtons,
},
@ -246,6 +254,7 @@ export default {
window.addEventListener('keydown', this.keyboardCloseEditor)
window.addEventListener('keydown', this.keyboardSaveEvent)
window.addEventListener('keydown', this.keyboardDeleteEvent)
window.addEventListener('keydown', this.keyboardDuplicateEvent)
this.$nextTick(() => {
const isNew = this.$route.name === 'NewPopoverView'
@ -261,6 +270,7 @@ export default {
window.removeEventListener('keydown', this.keyboardCloseEditor)
window.removeEventListener('keydown', this.keyboardSaveEvent)
window.removeEventListener('keydown', this.keyboardDeleteEvent)
window.removeEventListener('keydown', this.keyboardDuplicateEvent)
},
methods: {
showMore() {