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:
parent
cb9590cb5f
commit
04c0f9e7eb
|
@ -116,6 +116,9 @@ export default {
|
|||
}, {
|
||||
keys: [['Ctrl+Delete']],
|
||||
label: t('calendar', 'Delete edited event'),
|
||||
}, {
|
||||
keys: [['Ctrl+d']],
|
||||
label: t('calendar', 'Duplicate event'),
|
||||
}],
|
||||
}]
|
||||
},
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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: {
|
||||
/**
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue