forked from EVOgeek/Vmeda.Online
MOBILE-3021 calendar: Support links to calendar
parent
083ca7cd7e
commit
f07d6e1df7
|
@ -19,12 +19,14 @@ import { AddonCalendarHelperProvider } from './providers/helper';
|
||||||
import { AddonCalendarSyncProvider } from './providers/calendar-sync';
|
import { AddonCalendarSyncProvider } from './providers/calendar-sync';
|
||||||
import { AddonCalendarMainMenuHandler } from './providers/mainmenu-handler';
|
import { AddonCalendarMainMenuHandler } from './providers/mainmenu-handler';
|
||||||
import { AddonCalendarSyncCronHandler } from './providers/sync-cron-handler';
|
import { AddonCalendarSyncCronHandler } from './providers/sync-cron-handler';
|
||||||
|
import { AddonCalendarViewLinkHandler } from './providers/view-link-handler';
|
||||||
import { CoreMainMenuDelegate } from '@core/mainmenu/providers/delegate';
|
import { CoreMainMenuDelegate } from '@core/mainmenu/providers/delegate';
|
||||||
import { CoreCronDelegate } from '@providers/cron';
|
import { CoreCronDelegate } from '@providers/cron';
|
||||||
import { CoreInitDelegate } from '@providers/init';
|
import { CoreInitDelegate } from '@providers/init';
|
||||||
import { CoreLocalNotificationsProvider } from '@providers/local-notifications';
|
import { CoreLocalNotificationsProvider } from '@providers/local-notifications';
|
||||||
import { CoreLoginHelperProvider } from '@core/login/providers/helper';
|
import { CoreLoginHelperProvider } from '@core/login/providers/helper';
|
||||||
import { CoreUpdateManagerProvider } from '@providers/update-manager';
|
import { CoreUpdateManagerProvider } from '@providers/update-manager';
|
||||||
|
import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate';
|
||||||
|
|
||||||
// List of providers (without handlers).
|
// List of providers (without handlers).
|
||||||
export const ADDON_CALENDAR_PROVIDERS: any[] = [
|
export const ADDON_CALENDAR_PROVIDERS: any[] = [
|
||||||
|
@ -45,17 +47,20 @@ export const ADDON_CALENDAR_PROVIDERS: any[] = [
|
||||||
AddonCalendarHelperProvider,
|
AddonCalendarHelperProvider,
|
||||||
AddonCalendarSyncProvider,
|
AddonCalendarSyncProvider,
|
||||||
AddonCalendarMainMenuHandler,
|
AddonCalendarMainMenuHandler,
|
||||||
AddonCalendarSyncCronHandler
|
AddonCalendarSyncCronHandler,
|
||||||
|
AddonCalendarViewLinkHandler
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AddonCalendarModule {
|
export class AddonCalendarModule {
|
||||||
constructor(mainMenuDelegate: CoreMainMenuDelegate, calendarHandler: AddonCalendarMainMenuHandler,
|
constructor(mainMenuDelegate: CoreMainMenuDelegate, calendarHandler: AddonCalendarMainMenuHandler,
|
||||||
initDelegate: CoreInitDelegate, calendarProvider: AddonCalendarProvider, loginHelper: CoreLoginHelperProvider,
|
initDelegate: CoreInitDelegate, calendarProvider: AddonCalendarProvider, loginHelper: CoreLoginHelperProvider,
|
||||||
localNotificationsProvider: CoreLocalNotificationsProvider, updateManager: CoreUpdateManagerProvider,
|
localNotificationsProvider: CoreLocalNotificationsProvider, updateManager: CoreUpdateManagerProvider,
|
||||||
cronDelegate: CoreCronDelegate, syncHandler: AddonCalendarSyncCronHandler) {
|
cronDelegate: CoreCronDelegate, syncHandler: AddonCalendarSyncCronHandler,
|
||||||
|
contentLinksDelegate: CoreContentLinksDelegate, viewLinkHandler: AddonCalendarViewLinkHandler) {
|
||||||
|
|
||||||
mainMenuDelegate.registerHandler(calendarHandler);
|
mainMenuDelegate.registerHandler(calendarHandler);
|
||||||
cronDelegate.register(syncHandler);
|
cronDelegate.register(syncHandler);
|
||||||
|
contentLinksDelegate.registerHandler(viewLinkHandler);
|
||||||
|
|
||||||
initDelegate.ready().then(() => {
|
initDelegate.ready().then(() => {
|
||||||
calendarProvider.scheduleAllSitesEventsNotifications();
|
calendarProvider.scheduleAllSitesEventsNotifications();
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
<div class="hidden-phone addon-calendar-day-events">
|
<div class="hidden-phone addon-calendar-day-events">
|
||||||
<ng-container *ngFor="let event of day.filteredEvents | slice:0:4; let index = index">
|
<ng-container *ngFor="let event of day.filteredEvents | slice:0:4; let index = index">
|
||||||
<p *ngIf="index < 3 || day.filteredEvents.length == 4" class="addon-calendar-event" (click)="eventClicked(event)">
|
<p *ngIf="index < 3 || day.filteredEvents.length == 4" class="addon-calendar-event" (click)="eventClicked(event)">
|
||||||
<span class="calendar_event_type calendar_event_{{event.eventtype}}"></span>
|
<span class="calendar_event_type calendar_event_{{event.formattedType}}"></span>
|
||||||
<ion-icon *ngIf="event.offline && !event.deleted" name="time"></ion-icon>
|
<ion-icon *ngIf="event.offline && !event.deleted" name="time"></ion-icon>
|
||||||
<ion-icon *ngIf="event.deleted" name="trash"></ion-icon>
|
<ion-icon *ngIf="event.deleted" name="trash"></ion-icon>
|
||||||
{{ event.timestart * 1000 | coreFormatDate: timeFormat }}
|
{{ event.timestart * 1000 | coreFormatDate: timeFormat }}
|
||||||
|
|
|
@ -91,7 +91,7 @@ export class AddonCalendarCalendarComponent implements OnInit, OnChanges, OnDest
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
|
|
||||||
this.year = this.initialYear ? Number(this.initialYear) : now.getFullYear();
|
this.year = this.initialYear ? Number(this.initialYear) : now.getFullYear();
|
||||||
this.month = this.initialYear ? Number(this.initialYear) : now.getMonth() + 1;
|
this.month = this.initialMonth ? Number(this.initialMonth) : now.getMonth() + 1;
|
||||||
this.canNavigate = typeof this.canNavigate == 'undefined' ? true : this.utils.isTrueOrOne(this.canNavigate);
|
this.canNavigate = typeof this.canNavigate == 'undefined' ? true : this.utils.isTrueOrOne(this.canNavigate);
|
||||||
|
|
||||||
this.fetchData();
|
this.fetchData();
|
||||||
|
@ -328,31 +328,33 @@ export class AddonCalendarCalendarComponent implements OnInit, OnChanges, OnDest
|
||||||
protected mergeEvents(): void {
|
protected mergeEvents(): void {
|
||||||
const monthOfflineEvents = this.offlineEvents[this.calendarHelper.getMonthId(this.year, this.month)];
|
const monthOfflineEvents = this.offlineEvents[this.calendarHelper.getMonthId(this.year, this.month)];
|
||||||
|
|
||||||
if (!monthOfflineEvents && !this.deletedEvents.length) {
|
|
||||||
// No offline events, nothing to merge.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.weeks.forEach((week) => {
|
this.weeks.forEach((week) => {
|
||||||
week.days.forEach((day) => {
|
week.days.forEach((day) => {
|
||||||
|
|
||||||
if (this.deletedEvents.length) {
|
// Format online events.
|
||||||
// Mark as deleted the events that were deleted in offline.
|
day.events.forEach(this.calendarHelper.formatEventData.bind(this.calendarHelper));
|
||||||
day.events.forEach((event) => {
|
|
||||||
event.deleted = this.deletedEvents.indexOf(event.id) != -1;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.offlineEditedEventsIds.length) {
|
if (monthOfflineEvents || this.deletedEvents.length) {
|
||||||
// Remove the online events that were modified in offline.
|
// There is offline data, merge it.
|
||||||
day.events = day.events.filter((event) => {
|
|
||||||
return this.offlineEditedEventsIds.indexOf(event.id) == -1;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (monthOfflineEvents && monthOfflineEvents[day.mday]) {
|
if (this.deletedEvents.length) {
|
||||||
// Add the offline events (either new or edited).
|
// Mark as deleted the events that were deleted in offline.
|
||||||
day.events = this.sortEvents(day.events.concat(monthOfflineEvents[day.mday]));
|
day.events.forEach((event) => {
|
||||||
|
event.deleted = this.deletedEvents.indexOf(event.id) != -1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.offlineEditedEventsIds.length) {
|
||||||
|
// Remove the online events that were modified in offline.
|
||||||
|
day.events = day.events.filter((event) => {
|
||||||
|
return this.offlineEditedEventsIds.indexOf(event.id) == -1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (monthOfflineEvents && monthOfflineEvents[day.mday]) {
|
||||||
|
// Add the offline events (either new or edited).
|
||||||
|
day.events = this.sortEvents(day.events.concat(monthOfflineEvents[day.mday]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start class="core-module-icon">
|
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start class="core-module-icon">
|
||||||
<core-icon *ngIf="event.icon && !event.moduleIcon" [name]="event.icon" item-start></core-icon>
|
<core-icon *ngIf="event.icon && !event.moduleIcon" [name]="event.icon" item-start></core-icon>
|
||||||
<h2><core-format-text [text]="event.name"></core-format-text></h2>
|
<h2><core-format-text [text]="event.name"></core-format-text></h2>
|
||||||
<p [innerHTML]="event.formattedtime"></p>
|
<p><core-format-text [text]="event.formattedtime"></core-format-text></p>
|
||||||
<ion-note *ngIf="event.offline && !event.deleted" item-end>
|
<ion-note *ngIf="event.offline && !event.deleted" item-end>
|
||||||
<ion-icon name="time"></ion-icon>
|
<ion-icon name="time"></ion-icon>
|
||||||
<span text-wrap>{{ 'core.notsent' | translate }}</span>
|
<span text-wrap>{{ 'core.notsent' | translate }}</span>
|
||||||
|
|
|
@ -146,6 +146,8 @@ export class AddonCalendarUpcomingEventsComponent implements OnInit, OnChanges,
|
||||||
fetchEvents(): Promise<any> {
|
fetchEvents(): Promise<any> {
|
||||||
// Don't pass courseId and categoryId, we'll filter them locally.
|
// Don't pass courseId and categoryId, we'll filter them locally.
|
||||||
return this.calendarProvider.getUpcomingEvents().then((result) => {
|
return this.calendarProvider.getUpcomingEvents().then((result) => {
|
||||||
|
const promises = [];
|
||||||
|
|
||||||
this.onlineEvents = result.events;
|
this.onlineEvents = result.events;
|
||||||
|
|
||||||
this.onlineEvents.forEach(this.calendarHelper.formatEventData.bind(this.calendarHelper));
|
this.onlineEvents.forEach(this.calendarHelper.formatEventData.bind(this.calendarHelper));
|
||||||
|
@ -158,8 +160,12 @@ export class AddonCalendarUpcomingEventsComponent implements OnInit, OnChanges,
|
||||||
|
|
||||||
// Re-calculate the formatted time so it uses the device date.
|
// Re-calculate the formatted time so it uses the device date.
|
||||||
this.events.forEach((event) => {
|
this.events.forEach((event) => {
|
||||||
event.formattedtime = this.calendarProvider.formatEventTime(event, this.timeFormat);
|
promises.push(this.calendarProvider.formatEventTime(event, this.timeFormat).then((time) => {
|
||||||
|
event.formattedtime = time;
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start class="core-module-icon">
|
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start class="core-module-icon">
|
||||||
<core-icon *ngIf="event.icon && !event.moduleIcon" [name]="event.icon" item-start></core-icon>
|
<core-icon *ngIf="event.icon && !event.moduleIcon" [name]="event.icon" item-start></core-icon>
|
||||||
<h2><core-format-text [text]="event.name"></core-format-text></h2>
|
<h2><core-format-text [text]="event.name"></core-format-text></h2>
|
||||||
<p [innerHTML]="event.formattedtime"></p>
|
<p><core-format-text [text]="event.formattedtime"></core-format-text></p>
|
||||||
<ion-note *ngIf="event.offline && !event.deleted" item-end>
|
<ion-note *ngIf="event.offline && !event.deleted" item-end>
|
||||||
<ion-icon name="time"></ion-icon>
|
<ion-icon name="time"></ion-icon>
|
||||||
<span text-wrap>{{ 'core.notsent' | translate }}</span>
|
<span text-wrap>{{ 'core.notsent' | translate }}</span>
|
||||||
|
|
|
@ -188,7 +188,7 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
|
||||||
* View loaded.
|
* View loaded.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.currentMoment = moment().year(this.year).month(this.month - 1).day(this.day);
|
this.currentMoment = moment().year(this.year).month(this.month - 1).date(this.day);
|
||||||
|
|
||||||
this.fetchData(true, false);
|
this.fetchData(true, false);
|
||||||
}
|
}
|
||||||
|
@ -273,6 +273,7 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
|
||||||
fetchEvents(): Promise<any> {
|
fetchEvents(): Promise<any> {
|
||||||
// Don't pass courseId and categoryId, we'll filter them locally.
|
// Don't pass courseId and categoryId, we'll filter them locally.
|
||||||
return this.calendarProvider.getDayEvents(this.year, this.month, this.day).then((result) => {
|
return this.calendarProvider.getDayEvents(this.year, this.month, this.day).then((result) => {
|
||||||
|
const promises = [];
|
||||||
|
|
||||||
// Calculate the period name. We don't use the one in result because it's in server's language.
|
// Calculate the period name. We don't use the one in result because it's in server's language.
|
||||||
this.periodName = this.timeUtils.userDate(new Date(this.year, this.month - 1, this.day).getTime(),
|
this.periodName = this.timeUtils.userDate(new Date(this.year, this.month - 1, this.day).getTime(),
|
||||||
|
@ -288,9 +289,14 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
|
||||||
this.filterEvents();
|
this.filterEvents();
|
||||||
|
|
||||||
// Re-calculate the formatted time so it uses the device date.
|
// Re-calculate the formatted time so it uses the device date.
|
||||||
|
const dayTime = this.currentMoment.unix() * 1000;
|
||||||
this.events.forEach((event) => {
|
this.events.forEach((event) => {
|
||||||
event.formattedtime = this.calendarProvider.formatEventTime(event, this.timeFormat);
|
promises.push(this.calendarProvider.formatEventTime(event, this.timeFormat, true, dayTime).then((time) => {
|
||||||
|
event.formattedtime = time;
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,18 +29,11 @@
|
||||||
<ion-item text-wrap>
|
<ion-item text-wrap>
|
||||||
<core-icon *ngIf="event.icon && !event.moduleIcon" [name]="event.icon" item-start></core-icon>
|
<core-icon *ngIf="event.icon && !event.moduleIcon" [name]="event.icon" item-start></core-icon>
|
||||||
<h2><core-format-text [text]="event.name"></core-format-text></h2>
|
<h2><core-format-text [text]="event.name"></core-format-text></h2>
|
||||||
|
<p><core-format-text [text]="event.formattedtime"></core-format-text></p>
|
||||||
<ion-note item-end *ngIf="event.deleted">
|
<ion-note item-end *ngIf="event.deleted">
|
||||||
<ion-icon name="trash"></ion-icon> {{ 'core.deletedoffline' | translate }}
|
<ion-icon name="trash"></ion-icon> {{ 'core.deletedoffline' | translate }}
|
||||||
</ion-note>
|
</ion-note>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item text-wrap>
|
|
||||||
<h2>{{ 'addon.calendar.eventstarttime' | translate}}</h2>
|
|
||||||
<p>{{ event.timestart * 1000 | coreFormatDate }}</p>
|
|
||||||
</ion-item>
|
|
||||||
<ion-item text-wrap *ngIf="event.timeduration > 0">
|
|
||||||
<h2>{{ 'addon.calendar.eventendtime' | translate}}</h2>
|
|
||||||
<p>{{ (event.timestart + event.timeduration) * 1000 | coreFormatDate }}</p>
|
|
||||||
</ion-item>
|
|
||||||
<a ion-item text-wrap *ngIf="courseName" [href]="courseUrl" core-link capture="true">
|
<a ion-item text-wrap *ngIf="courseName" [href]="courseUrl" core-link capture="true">
|
||||||
<h2>{{ 'core.course' | translate}}</h2>
|
<h2>{{ 'core.course' | translate}}</h2>
|
||||||
<p><core-format-text [text]="courseName"></core-format-text></p>
|
<p><core-format-text [text]="courseName"></core-format-text></p>
|
||||||
|
|
|
@ -311,6 +311,13 @@ export class AddonCalendarEventPage implements OnDestroy {
|
||||||
event.deleted = deleted;
|
event.deleted = deleted;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Re-calculate the formatted time so it uses the device date.
|
||||||
|
promises.push(this.calendarProvider.getCalendarTimeFormat().then((timeFormat) => {
|
||||||
|
this.calendarProvider.formatEventTime(event, timeFormat).then((time) => {
|
||||||
|
event.formattedtime = time;
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
this.domUtils.showErrorModalDefault(error, 'addon.calendar.errorloadevent', true);
|
this.domUtils.showErrorModalDefault(error, 'addon.calendar.errorloadevent', true);
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
<ion-icon name="warning"></ion-icon> {{ 'core.hasdatatosync' | translate:{$a: 'addon.calendar.calendar' | translate} }}
|
<ion-icon name="warning"></ion-icon> {{ 'core.hasdatatosync' | translate:{$a: 'addon.calendar.calendar' | translate} }}
|
||||||
</ion-card>
|
</ion-card>
|
||||||
|
|
||||||
<addon-calendar-calendar [hidden]="!showCalendar" [courseId]="courseId" [categoryId]="categoryId" (onEventClicked)="gotoEvent($event)" (onDayClicked)="gotoDay($event)"></addon-calendar-calendar>
|
<addon-calendar-calendar [hidden]="!showCalendar" [initialYear]="year" [initialMonth]="month" [courseId]="courseId" [categoryId]="categoryId" (onEventClicked)="gotoEvent($event)" (onDayClicked)="gotoDay($event)"></addon-calendar-calendar>
|
||||||
|
|
||||||
<addon-calendar-upcoming-events *ngIf="loadUpcoming" [hidden]="showCalendar" [courseId]="courseId" [categoryId]="categoryId" (onEventClicked)="gotoEvent($event)"></addon-calendar-upcoming-events>
|
<addon-calendar-upcoming-events *ngIf="loadUpcoming" [hidden]="showCalendar" [courseId]="courseId" [categoryId]="categoryId" (onEventClicked)="gotoEvent($event)"></addon-calendar-upcoming-events>
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,8 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
|
||||||
protected manualSyncObserver: any;
|
protected manualSyncObserver: any;
|
||||||
protected onlineObserver: any;
|
protected onlineObserver: any;
|
||||||
|
|
||||||
|
year: number;
|
||||||
|
month: number;
|
||||||
courseId: number;
|
courseId: number;
|
||||||
categoryId: number;
|
categoryId: number;
|
||||||
canCreate = false;
|
canCreate = false;
|
||||||
|
@ -82,8 +84,12 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
|
||||||
|
|
||||||
this.courseId = navParams.get('courseId');
|
this.courseId = navParams.get('courseId');
|
||||||
this.eventId = navParams.get('eventId') || false;
|
this.eventId = navParams.get('eventId') || false;
|
||||||
|
this.year = navParams.get('year');
|
||||||
|
this.month = navParams.get('month');
|
||||||
this.notificationsEnabled = localNotificationsProvider.isAvailable();
|
this.notificationsEnabled = localNotificationsProvider.isAvailable();
|
||||||
this.currentSiteId = sitesProvider.getCurrentSiteId();
|
this.currentSiteId = sitesProvider.getCurrentSiteId();
|
||||||
|
this.loadUpcoming = !!navParams.get('upcoming');
|
||||||
|
this.showCalendar = !this.loadUpcoming;
|
||||||
|
|
||||||
// Listen for events added. When an event is added, reload the data.
|
// Listen for events added. When an event is added, reload the data.
|
||||||
this.newEventObserver = eventsProvider.on(AddonCalendarProvider.NEW_EVENT_EVENT, (data) => {
|
this.newEventObserver = eventsProvider.on(AddonCalendarProvider.NEW_EVENT_EVENT, (data) => {
|
||||||
|
|
|
@ -53,7 +53,6 @@ export class AddonCalendarListPage implements OnDestroy {
|
||||||
protected siteHomeId: number;
|
protected siteHomeId: number;
|
||||||
protected obsDefaultTimeChange: any;
|
protected obsDefaultTimeChange: any;
|
||||||
protected eventId: number;
|
protected eventId: number;
|
||||||
protected preSelectedCourseId: number;
|
|
||||||
protected newEventObserver: any;
|
protected newEventObserver: any;
|
||||||
protected discardedObserver: any;
|
protected discardedObserver: any;
|
||||||
protected editEventObserver: any;
|
protected editEventObserver: any;
|
||||||
|
@ -101,7 +100,7 @@ export class AddonCalendarListPage implements OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.eventId = navParams.get('eventId') || false;
|
this.eventId = navParams.get('eventId') || false;
|
||||||
this.preSelectedCourseId = navParams.get('courseId') || null;
|
this.courseId = navParams.get('courseId');
|
||||||
|
|
||||||
// Listen for events added. When an event is added, reload the data.
|
// Listen for events added. When an event is added, reload the data.
|
||||||
this.newEventObserver = eventsProvider.on(AddonCalendarProvider.NEW_EVENT_EVENT, (data) => {
|
this.newEventObserver = eventsProvider.on(AddonCalendarProvider.NEW_EVENT_EVENT, (data) => {
|
||||||
|
@ -284,12 +283,6 @@ export class AddonCalendarListPage implements OnDestroy {
|
||||||
this.courses = result.courses;
|
this.courses = result.courses;
|
||||||
this.categoryId = result.categoryId;
|
this.categoryId = result.categoryId;
|
||||||
|
|
||||||
if (this.preSelectedCourseId) {
|
|
||||||
this.filter.course = courses.find((course) => {
|
|
||||||
return course.id == this.preSelectedCourseId;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.fetchEvents(refresh);
|
return this.fetchEvents(refresh);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,9 @@ import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
|
||||||
import { CoreSite } from '@classes/site';
|
import { CoreSite } from '@classes/site';
|
||||||
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
||||||
import { CoreAppProvider } from '@providers/app';
|
import { CoreAppProvider } from '@providers/app';
|
||||||
|
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||||
|
import { CoreUrlUtilsProvider } from '@providers/utils/url';
|
||||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
import { CoreGroupsProvider } from '@providers/groups';
|
import { CoreGroupsProvider } from '@providers/groups';
|
||||||
import { CoreConstants } from '@core/constants';
|
import { CoreConstants } from '@core/constants';
|
||||||
|
@ -259,7 +261,9 @@ export class AddonCalendarProvider {
|
||||||
private sitesProvider: CoreSitesProvider,
|
private sitesProvider: CoreSitesProvider,
|
||||||
private groupsProvider: CoreGroupsProvider,
|
private groupsProvider: CoreGroupsProvider,
|
||||||
private coursesProvider: CoreCoursesProvider,
|
private coursesProvider: CoreCoursesProvider,
|
||||||
|
private textUtils: CoreTextUtilsProvider,
|
||||||
private timeUtils: CoreTimeUtilsProvider,
|
private timeUtils: CoreTimeUtilsProvider,
|
||||||
|
private urlUtils: CoreUrlUtilsProvider,
|
||||||
private localNotificationsProvider: CoreLocalNotificationsProvider,
|
private localNotificationsProvider: CoreLocalNotificationsProvider,
|
||||||
private configProvider: CoreConfigProvider,
|
private configProvider: CoreConfigProvider,
|
||||||
private utils: CoreUtilsProvider,
|
private utils: CoreUtilsProvider,
|
||||||
|
@ -487,15 +491,19 @@ export class AddonCalendarProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format event time. Equivalent to calendar_format_event_time.
|
* Format event time. Similar to calendar_format_event_time.
|
||||||
*
|
*
|
||||||
* @param {any} event Event to format.
|
* @param {any} event Event to format.
|
||||||
* @param {string} format Calendar time format (from getCalendarTimeFormat).
|
* @param {string} format Calendar time format (from getCalendarTimeFormat).
|
||||||
* @param {boolean} [useCommonWords=true] Whether to use common words like "Today", "Yesterday", etc.
|
* @param {boolean} [useCommonWords=true] Whether to use common words like "Today", "Yesterday", etc.
|
||||||
|
* @param {number} [seenDay] Timestamp of day currently seen. If set, the function will not add links to this day.
|
||||||
* @param {number} [showTime=0] Determine the show time GMT timestamp.
|
* @param {number} [showTime=0] Determine the show time GMT timestamp.
|
||||||
* @return {string} Formatted event time.
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {Promise<string>} Promise resolved with the formatted event time.
|
||||||
*/
|
*/
|
||||||
formatEventTime(event: any, format: string, useCommonWords: boolean = true, showTime: number = 0): string {
|
formatEventTime(event: any, format: string, useCommonWords: boolean = true, seenDay?: number, showTime: number = 0,
|
||||||
|
siteId?: string): Promise<string> {
|
||||||
|
|
||||||
const start = event.timestart * 1000,
|
const start = event.timestart * 1000,
|
||||||
end = (event.timestart + event.timeduration) * 1000;
|
end = (event.timestart + event.timeduration) * 1000;
|
||||||
let time;
|
let time;
|
||||||
|
@ -511,46 +519,50 @@ export class AddonCalendarProvider {
|
||||||
this.timeUtils.userDate(end, format);
|
this.timeUtils.userDate(end, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!showTime) {
|
|
||||||
return this.getDayRepresentation(start, useCommonWords) + ', ' + time;
|
|
||||||
} else {
|
|
||||||
return time;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Event lasts more than one day.
|
// Event lasts more than one day.
|
||||||
const midnightStart = moment(start).startOf('day').unix() * 1000,
|
const timeStart = this.timeUtils.userDate(start, format),
|
||||||
midnightEnd = moment(end).startOf('day').unix() * 1000,
|
timeEnd = this.timeUtils.userDate(end, format),
|
||||||
timeStart = this.timeUtils.userDate(start, format),
|
promises = [];
|
||||||
timeEnd = this.timeUtils.userDate(end, format);
|
|
||||||
let dayStart = this.getDayRepresentation(start, useCommonWords) + ', ',
|
|
||||||
dayEnd = this.getDayRepresentation(end, useCommonWords) + ', ';
|
|
||||||
|
|
||||||
if (showTime == midnightStart) {
|
// Don't use common words when the event lasts more than one day.
|
||||||
dayStart = '';
|
let dayStart = this.getDayRepresentation(start, false) + ', ',
|
||||||
|
dayEnd = this.getDayRepresentation(end, false) + ', ';
|
||||||
|
|
||||||
|
// Add links to the days if needed.
|
||||||
|
if (dayStart && (!seenDay || !moment(seenDay).isSame(start, 'day'))) {
|
||||||
|
promises.push(this.getViewUrl('day', event.timestart, undefined, siteId).then((url) => {
|
||||||
|
dayStart = this.urlUtils.buildLink(url, dayStart);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
if (dayEnd && (!seenDay || !moment(seenDay).isSame(end, 'day'))) {
|
||||||
|
promises.push(this.getViewUrl('day', end / 1000, undefined, siteId).then((url) => {
|
||||||
|
dayEnd = this.urlUtils.buildLink(url, dayEnd);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showTime == midnightEnd) {
|
return Promise.all(promises).then(() => {
|
||||||
dayEnd = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set printable representation.
|
|
||||||
if (moment().isSame(start, 'day')) {
|
|
||||||
// Event starts today, don't display the day.
|
|
||||||
return timeStart + ' <strong>»</strong> ' + dayEnd + timeEnd;
|
|
||||||
} else {
|
|
||||||
// The event starts in the future, print both days.
|
|
||||||
return dayStart + timeStart + ' <strong>»</strong> ' + dayEnd + timeEnd;
|
return dayStart + timeStart + ' <strong>»</strong> ' + dayEnd + timeEnd;
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
} else { // There is no time duration.
|
} else {
|
||||||
const time = this.timeUtils.userDate(start, format);
|
// There is no time duration.
|
||||||
|
time = this.timeUtils.userDate(start, format);
|
||||||
|
}
|
||||||
|
|
||||||
if (!showTime) {
|
if (!showTime) {
|
||||||
return this.getDayRepresentation(start, useCommonWords) + ', ' + time.trim();
|
// Display day + time.
|
||||||
|
if (seenDay && moment(seenDay).isSame(start, 'day')) {
|
||||||
|
// This day is currently being displayed, don't add an link.
|
||||||
|
return Promise.resolve(this.getDayRepresentation(start, useCommonWords) + ', ' + time);
|
||||||
} else {
|
} else {
|
||||||
return time;
|
// Add link to view the day.
|
||||||
|
return this.getViewUrl('day', event.timestart, undefined, siteId).then((url) => {
|
||||||
|
return this.urlUtils.buildLink(url, this.getDayRepresentation(start, useCommonWords)) + ', ' + time;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return Promise.resolve(time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -841,6 +853,21 @@ export class AddonCalendarProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the normalised event type.
|
||||||
|
* Activity events are normalised to be course events.
|
||||||
|
*
|
||||||
|
* @param {any} event The event to get its type.
|
||||||
|
* @return {string} Event type.
|
||||||
|
*/
|
||||||
|
getEventType(event: any): string {
|
||||||
|
if (event.modulename) {
|
||||||
|
return 'course';
|
||||||
|
}
|
||||||
|
|
||||||
|
return event.eventtype;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove an event reminder and cancel the notification.
|
* Remove an event reminder and cancel the notification.
|
||||||
*
|
*
|
||||||
|
@ -1155,6 +1182,31 @@ export class AddonCalendarProvider {
|
||||||
return this.getUpcomingEventsPrefixCacheKey() + (courseId ? courseId : '') + ':' + (categoryId ? categoryId : '');
|
return this.getUpcomingEventsPrefixCacheKey() + (courseId ? courseId : '') + ':' + (categoryId ? categoryId : '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get URL to view a calendar.
|
||||||
|
*
|
||||||
|
* @param {string} view The view to load: 'month', 'day', 'upcoming', etc.
|
||||||
|
* @param {number} [time] Time to load. If not defined, current time.
|
||||||
|
* @param {string} [courseId] Course to load. If not defined, all courses.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {Promise<string>} Promise resolved with the URL.x
|
||||||
|
*/
|
||||||
|
getViewUrl(view: string, time?: number, courseId?: string, siteId?: string): Promise<string> {
|
||||||
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
let url = this.textUtils.concatenatePaths(site.getURL(), 'calendar/view.php?view=' + view);
|
||||||
|
|
||||||
|
if (time) {
|
||||||
|
url += '&time=' + time;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (courseId) {
|
||||||
|
url += '&course=' + courseId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the week days, already ordered according to a specified starting day.
|
* Get the week days, already ordered according to a specified starting day.
|
||||||
*
|
*
|
||||||
|
|
|
@ -54,7 +54,7 @@ export class AddonCalendarHelperProvider {
|
||||||
|
|
||||||
const types = {};
|
const types = {};
|
||||||
events.forEach((event) => {
|
events.forEach((event) => {
|
||||||
types[event.eventtype] = true;
|
types[event.formattedType || event.eventtype] = true;
|
||||||
|
|
||||||
if (event.islastday) {
|
if (event.islastday) {
|
||||||
day.haslastdayofevent = true;
|
day.haslastdayofevent = true;
|
||||||
|
@ -133,6 +133,8 @@ export class AddonCalendarHelperProvider {
|
||||||
e.moduleIcon = e.icon;
|
e.moduleIcon = e.icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e.formattedType = this.calendarProvider.getEventType(e);
|
||||||
|
|
||||||
if (typeof e.duration != 'undefined') {
|
if (typeof e.duration != 'undefined') {
|
||||||
// It's an offline event, add some calculated data.
|
// It's an offline event, add some calculated data.
|
||||||
e.format = 1;
|
e.format = 1;
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
// (C) Copyright 2015 Martin Dougiamas
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { CoreContentLinksHandlerBase } from '@core/contentlinks/classes/base-handler';
|
||||||
|
import { CoreContentLinksAction } from '@core/contentlinks/providers/delegate';
|
||||||
|
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
|
||||||
|
import { AddonCalendarProvider } from './calendar';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content links handler for calendar view page.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AddonCalendarViewLinkHandler extends CoreContentLinksHandlerBase {
|
||||||
|
name = 'AddonCalendarViewLinkHandler';
|
||||||
|
pattern = /\/calendar\/view\.php/;
|
||||||
|
|
||||||
|
protected SUPPORTED_VIEWS = ['month', 'mini', 'minithree', 'day', 'upcoming', 'upcoming_mini'];
|
||||||
|
|
||||||
|
constructor(private linkHelper: CoreContentLinksHelperProvider, private calendarProvider: AddonCalendarProvider) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of actions for a link (url).
|
||||||
|
*
|
||||||
|
* @param {string[]} siteIds List of sites the URL belongs to.
|
||||||
|
* @param {string} url The URL to treat.
|
||||||
|
* @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
|
||||||
|
* @param {number} [courseId] Course ID related to the URL. Optional but recommended.
|
||||||
|
* @return {CoreContentLinksAction[]|Promise<CoreContentLinksAction[]>} List of (or promise resolved with list of) actions.
|
||||||
|
*/
|
||||||
|
getActions(siteIds: string[], url: string, params: any, courseId?: number):
|
||||||
|
CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
|
||||||
|
return [{
|
||||||
|
action: (siteId, navCtrl?): void => {
|
||||||
|
if (!params.view || params.view == 'month' || params.view == 'mini' || params.view == 'minithree') {
|
||||||
|
// Monthly view, open the calendar tab.
|
||||||
|
const stateParams: any = {
|
||||||
|
courseId: params.course
|
||||||
|
},
|
||||||
|
timestamp = params.time ? params.time * 1000 : Date.now();
|
||||||
|
|
||||||
|
const date = new Date(timestamp);
|
||||||
|
stateParams.year = date.getFullYear();
|
||||||
|
stateParams.month = date.getMonth() + 1;
|
||||||
|
|
||||||
|
this.linkHelper.goInSite(navCtrl, 'AddonCalendarIndexPage', stateParams, siteId); // @todo: Add checkMenu param.
|
||||||
|
|
||||||
|
} else if (params.view == 'day') {
|
||||||
|
// Daily view, open the page.
|
||||||
|
const stateParams: any = {
|
||||||
|
courseId: params.course
|
||||||
|
},
|
||||||
|
timestamp = params.time ? params.time * 1000 : Date.now();
|
||||||
|
|
||||||
|
const date = new Date(timestamp);
|
||||||
|
stateParams.year = date.getFullYear();
|
||||||
|
stateParams.month = date.getMonth() + 1;
|
||||||
|
stateParams.day = date.getDate();
|
||||||
|
|
||||||
|
this.linkHelper.goInSite(navCtrl, 'AddonCalendarDayPage', stateParams, siteId);
|
||||||
|
|
||||||
|
} else if (params.view == 'upcoming' || params.view == 'upcoming_mini') {
|
||||||
|
// Upcoming view, open the calendar tab.
|
||||||
|
const stateParams: any = {
|
||||||
|
courseId: params.course,
|
||||||
|
upcoming: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.linkHelper.goInSite(navCtrl, 'AddonCalendarIndexPage', stateParams, siteId); // @todo: Add checkMenu param.
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the handler is enabled for a certain site (site + user) and a URL.
|
||||||
|
* If not defined, defaults to true.
|
||||||
|
*
|
||||||
|
* @param {string} siteId The site ID.
|
||||||
|
* @param {string} url The URL to treat.
|
||||||
|
* @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
|
||||||
|
* @param {number} [courseId] Course ID related to the URL. Optional but recommended.
|
||||||
|
* @return {boolean|Promise<boolean>} Whether the handler is enabled for the URL and site.
|
||||||
|
*/
|
||||||
|
isEnabled(siteId: string, url: string, params: any, courseId?: number): boolean | Promise<boolean> {
|
||||||
|
if (params.view && this.SUPPORTED_VIEWS.indexOf(params.view) == -1) {
|
||||||
|
// This type of view isn't supported in the app.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.calendarProvider.isDisabled(siteId).then((disabled) => {
|
||||||
|
if (disabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.calendarProvider.canViewMonth(siteId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,6 +44,17 @@ export class CoreUrlUtilsProvider {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a URL and a text, return an HTML link.
|
||||||
|
*
|
||||||
|
* @param {string} url URL.
|
||||||
|
* @param {string} text Text of the link.
|
||||||
|
* @return {string} Link.
|
||||||
|
*/
|
||||||
|
buildLink(url: string, text: string): string {
|
||||||
|
return '<a href="' + url + '">' + text + '</a>';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the parameters from a URL and stores them in an object.
|
* Extracts the parameters from a URL and stores them in an object.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue