mirror of https://github.com/nextcloud/calendar
Merge pull request #5891 from nextcloud/feat/calendar-widget-private-calendar
Feat: calendar widget for private calendars
This commit is contained in:
commit
97fce2ac52
|
@ -73,24 +73,55 @@ class ReferenceProvider extends ADiscoverableReferenceProvider {
|
|||
public function matchReference(string $referenceText): bool {
|
||||
$start = $this->urlGenerator->getAbsoluteURL('/apps/' . Application::APP_ID);
|
||||
$startIndex = $this->urlGenerator->getAbsoluteURL('/index.php/apps/' . Application::APP_ID);
|
||||
if (preg_match('/^' . preg_quote($start, '/') . '\/p\/[a-zA-Z0-9]+$/i', $referenceText) === 1 || preg_match('/^' . preg_quote($startIndex, '/') . '\/p\/[a-zA-Z0-9]+$/i', $referenceText) === 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$start = $this->urlGenerator->getAbsoluteURL('/remote.php/dav/calendars');
|
||||
if (preg_match('/^' . preg_quote($start, '/') . '\/[a-zA-Z0-9-]+\/[a-zA-Z0-9-]+\/$/i', $referenceText) === 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return preg_match('/^' . preg_quote($start, '/') . '\/p\/[a-zA-Z0-9]+$/i', $referenceText) === 1 || preg_match('/^' . preg_quote($startIndex, '/') . '\/p\/[a-zA-Z0-9]+$/i', $referenceText) === 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
public function resolveReference(string $referenceText): ?IReference {
|
||||
if ($this->matchReference($referenceText)) {
|
||||
$token = $this->getCalendarTokenFromLink($referenceText);
|
||||
|
||||
$type = $this->getType($referenceText);
|
||||
$reference = new Reference($referenceText);
|
||||
$reference->setTitle('calendar');
|
||||
$reference->setDescription($token);
|
||||
$reference->setRichObject(
|
||||
'calendar_widget',
|
||||
[
|
||||
'title' => 'calendar',
|
||||
'token' => $token,
|
||||
'url' => $referenceText,]
|
||||
);
|
||||
$reference->setDescription('calendar widget');
|
||||
|
||||
switch ($type) {
|
||||
case 'public':
|
||||
$token = $this->getCalendarTokenFromLink($referenceText);
|
||||
$url = $this->getUrlFromLink($token, 'public');
|
||||
$reference->setRichObject(
|
||||
'calendar_widget',
|
||||
[
|
||||
'title' => 'calendar',
|
||||
'token' => $token,
|
||||
'isPublic' => true,
|
||||
'url' => $url,
|
||||
]
|
||||
);
|
||||
break;
|
||||
case 'private':
|
||||
$url = $this->getUrlFromLink($referenceText, 'private');
|
||||
$reference->setRichObject(
|
||||
'calendar_widget',
|
||||
[
|
||||
'title' => 'calendar',
|
||||
'isPublic' => false,
|
||||
'url' => $url,
|
||||
]
|
||||
);
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return $reference;
|
||||
}
|
||||
|
@ -99,14 +130,31 @@ class ReferenceProvider extends ADiscoverableReferenceProvider {
|
|||
}
|
||||
|
||||
private function getCalendarTokenFromLink(string $url): ?string {
|
||||
|
||||
|
||||
if (preg_match('/\/p\/([a-zA-Z0-9]+)/', $url, $output_array)) {
|
||||
return $output_array[1];
|
||||
}
|
||||
return $url;
|
||||
return null;
|
||||
|
||||
}
|
||||
private function getUrlFromLink(string $data, string $type): ?string {
|
||||
if ($type === 'public') {
|
||||
return "{$this->urlGenerator->getWebroot()}/remote.php/dav/public-calendars/{$data}/";
|
||||
} elseif ($type === 'private' && preg_match('/\/remote.php\/dav\/calendars\/([a-zA-Z0-9-]+)\/([a-zA-Z0-9-]+)\//', $data, $output_array)) {
|
||||
return $this->urlGenerator->getWebroot().$output_array[0];
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
private function getType(string $url): string {
|
||||
if (preg_match('/\/p\/([a-zA-Z0-9]+)/', $url) === 1) {
|
||||
return 'public';
|
||||
}
|
||||
if (preg_match('/\/dav\/calendars\/([^\/]+)\/([^\/]+)/', $url) === 1) {
|
||||
return 'private';
|
||||
}
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
public function getCachePrefix(string $referenceId): string {
|
||||
return '';
|
||||
|
|
|
@ -22,9 +22,10 @@
|
|||
-->
|
||||
|
||||
<template>
|
||||
<FullCalendar ref="fullCalendar"
|
||||
<FullCalendar v-if="calendarOptions"
|
||||
ref="fullCalendar"
|
||||
:class="isWidget? 'fullcalendar-widget': ''"
|
||||
:options="options" />
|
||||
:options="calendarOptions" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -77,6 +78,10 @@ export default {
|
|||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
/**
|
||||
* Whether or not the user is authenticated
|
||||
*/
|
||||
|
@ -89,6 +94,7 @@ export default {
|
|||
return {
|
||||
updateTodayJob: null,
|
||||
updateTodayJobPreviousDate: null,
|
||||
calendarOptions: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -154,6 +160,13 @@ export default {
|
|||
}
|
||||
},
|
||||
eventSources() {
|
||||
if (this.isWidget) {
|
||||
const calendar = this.$store.getters.getCalendarByUrl(this.url)
|
||||
if (!calendar) {
|
||||
return []
|
||||
}
|
||||
return [calendar].map(eventSource(this.$store))
|
||||
}
|
||||
return this.$store.getters.enabledCalendars.map(eventSource(this.$store))
|
||||
},
|
||||
widgetView() {
|
||||
|
@ -194,6 +207,22 @@ export default {
|
|||
const calendarApi = this.$refs.fullCalendar.getApi()
|
||||
calendarApi.gotoDate(getYYYYMMDDFromFirstdayParam(newDate))
|
||||
},
|
||||
eventSources(sources, oldSources) {
|
||||
const newSources = sources.filter(source => !oldSources.map(oldSource => oldSource.id).includes(source.id))
|
||||
const removedSources = oldSources.filter(oldSource => !sources.map(source => source.id).includes(oldSource.id))
|
||||
|
||||
// Hackity hack! Unfortunately, calendarOptions.eventSources is not reactive ...
|
||||
// Ref https://fullcalendar.io/docs/Calendar-addEventSource
|
||||
// TODO: Find a better/safer way to prevent duplicated event sources
|
||||
const calendarApi = this.$refs.fullCalendar.getApi()
|
||||
for (const source of newSources) {
|
||||
calendarApi.addEventSource(source)
|
||||
}
|
||||
const eventSources = calendarApi.getEventSources()
|
||||
for (const source of removedSources) {
|
||||
eventSources.find(x => x.id === source.id)?.remove()
|
||||
}
|
||||
},
|
||||
modificationCount: debounce(function() {
|
||||
const calendarApi = this.$refs.fullCalendar.getApi()
|
||||
calendarApi.refetchEvents()
|
||||
|
@ -213,7 +242,7 @@ export default {
|
|||
* we have to register a resize-observer here, that will automatically
|
||||
* update the fullCalendar size, when the available space changes.
|
||||
*/
|
||||
mounted() {
|
||||
mounted() {
|
||||
if (window.ResizeObserver) {
|
||||
const resizeObserver = new ResizeObserver(debounce(() => {
|
||||
this.$refs.fullCalendar
|
||||
|
@ -225,6 +254,8 @@ export default {
|
|||
}
|
||||
},
|
||||
async created() {
|
||||
this.calendarOptions = await this.options
|
||||
|
||||
this.updateTodayJob = setInterval(() => {
|
||||
const newDate = getYYYYMMDDFromFirstdayParam('now')
|
||||
|
||||
|
|
|
@ -20,7 +20,9 @@ registerWidget('calendar_widget', async (el, { richObjectType, richObject, acces
|
|||
store,
|
||||
propsData: {
|
||||
isWidget: true,
|
||||
referenceToken: richObject.token,
|
||||
isPublic: richObject.isPublic,
|
||||
referenceToken: richObject?.token,
|
||||
url: richObject.url,
|
||||
},
|
||||
}).$mount(el)
|
||||
return new NcCustomPickerRenderResult(vueElement.$el, vueElement)
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
<CalendarGrid v-if="!showEmptyCalendarScreen"
|
||||
ref="calendarGridWidget"
|
||||
:is-widget="isWidget"
|
||||
:url="url"
|
||||
:is-authenticated-user="isAuthenticatedUser" />
|
||||
<EmptyCalendar v-else />
|
||||
|
||||
|
@ -139,14 +140,26 @@ export default {
|
|||
EditSimple,
|
||||
},
|
||||
props: {
|
||||
// Is the calendar in a widget ?
|
||||
isWidget: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// The reference token for the widget for public share calendars
|
||||
referenceToken: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
// Is public share ?
|
||||
isPublic: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
},
|
||||
// Url of private calendar
|
||||
url: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -263,7 +276,7 @@ export default {
|
|||
})
|
||||
this.$store.dispatch('initializeCalendarJsConfig')
|
||||
|
||||
if (this.$route?.name.startsWith('Public') || this.$route?.name.startsWith('Embed') || this.isWidget) {
|
||||
if (this.$route?.name.startsWith('Public') || this.$route?.name.startsWith('Embed') || this.isPublic) {
|
||||
await initializeClientForPublicView()
|
||||
const tokens = this.isWidget ? [this.referenceToken] : this.$route.params.tokens.split('-')
|
||||
const calendars = await this.$store.dispatch('getPublicCalendars', { tokens })
|
||||
|
|
Loading…
Reference in New Issue