MOBILE-1927 calendar: Allow creating events in offline
parent
5a9a7b1a11
commit
7ccfade21e
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { AddonCalendarProvider } from './providers/calendar';
|
import { AddonCalendarProvider } from './providers/calendar';
|
||||||
|
import { AddonCalendarOfflineProvider } from './providers/calendar-offline';
|
||||||
import { AddonCalendarHelperProvider } from './providers/helper';
|
import { AddonCalendarHelperProvider } from './providers/helper';
|
||||||
import { AddonCalendarMainMenuHandler } from './providers/mainmenu-handler';
|
import { AddonCalendarMainMenuHandler } from './providers/mainmenu-handler';
|
||||||
import { CoreMainMenuDelegate } from '@core/mainmenu/providers/delegate';
|
import { CoreMainMenuDelegate } from '@core/mainmenu/providers/delegate';
|
||||||
|
@ -25,6 +26,7 @@ import { CoreUpdateManagerProvider } from '@providers/update-manager';
|
||||||
// List of providers (without handlers).
|
// List of providers (without handlers).
|
||||||
export const ADDON_CALENDAR_PROVIDERS: any[] = [
|
export const ADDON_CALENDAR_PROVIDERS: any[] = [
|
||||||
AddonCalendarProvider,
|
AddonCalendarProvider,
|
||||||
|
AddonCalendarOfflineProvider,
|
||||||
AddonCalendarHelperProvider
|
AddonCalendarHelperProvider
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -35,6 +37,7 @@ export const ADDON_CALENDAR_PROVIDERS: any[] = [
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
AddonCalendarProvider,
|
AddonCalendarProvider,
|
||||||
|
AddonCalendarOfflineProvider,
|
||||||
AddonCalendarHelperProvider,
|
AddonCalendarHelperProvider,
|
||||||
AddonCalendarMainMenuHandler
|
AddonCalendarMainMenuHandler
|
||||||
]
|
]
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
<ion-item text-wrap *ngIf="eventTypeControl.value == 'course'">
|
<ion-item text-wrap *ngIf="eventTypeControl.value == 'course'">
|
||||||
<ion-label id="addon-calendar-course-label"><h2 [core-mark-required]="true">{{ 'core.course' | translate }}</h2></ion-label>
|
<ion-label id="addon-calendar-course-label"><h2 [core-mark-required]="true">{{ 'core.course' | translate }}</h2></ion-label>
|
||||||
<ion-select [formControlName]="'courseid'" aria-labelledby="addon-calendar-course-label" interface="action-sheet" [placeholder]="'core.noselection' | translate">
|
<ion-select [formControlName]="'courseid'" aria-labelledby="addon-calendar-course-label" interface="action-sheet" [placeholder]="'core.noselection' | translate">
|
||||||
<ion-option *ngFor="let course of courses" [value]="course.id">{{ course.fullname }}</ion-option>
|
<ion-option *ngFor="let course of courses" [value]="course.id"><core-format-text [text]="course.fullname"></core-format-text></ion-option>
|
||||||
</ion-select>
|
</ion-select>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
<ion-item text-wrap>
|
<ion-item text-wrap>
|
||||||
<ion-label id="addon-calendar-groupcourse-label"><h2 [core-mark-required]="true">{{ 'core.course' | translate }}</h2></ion-label>
|
<ion-label id="addon-calendar-groupcourse-label"><h2 [core-mark-required]="true">{{ 'core.course' | translate }}</h2></ion-label>
|
||||||
<ion-select [formControlName]="'groupcourseid'" aria-labelledby="addon-calendar-groupcourse-label" interface="action-sheet" [placeholder]="'core.noselection' | translate" (ionChange)="groupCourseSelected($event)">
|
<ion-select [formControlName]="'groupcourseid'" aria-labelledby="addon-calendar-groupcourse-label" interface="action-sheet" [placeholder]="'core.noselection' | translate" (ionChange)="groupCourseSelected($event)">
|
||||||
<ion-option *ngFor="let course of courses" [value]="course.id">{{ course.fullname }}</ion-option>
|
<ion-option *ngFor="let course of courses" [value]="course.id"><core-format-text [text]="course.fullname"></core-format-text></ion-option>
|
||||||
</ion-select>
|
</ion-select>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<!-- The course has no groups. -->
|
<!-- The course has no groups. -->
|
||||||
|
|
|
@ -26,6 +26,7 @@ import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
||||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||||
import { CoreRichTextEditorComponent } from '@components/rich-text-editor/rich-text-editor.ts';
|
import { CoreRichTextEditorComponent } from '@components/rich-text-editor/rich-text-editor.ts';
|
||||||
import { AddonCalendarProvider } from '../../providers/calendar';
|
import { AddonCalendarProvider } from '../../providers/calendar';
|
||||||
|
import { AddonCalendarOfflineProvider } from '../../providers/calendar-offline';
|
||||||
import { AddonCalendarHelperProvider } from '../../providers/helper';
|
import { AddonCalendarHelperProvider } from '../../providers/helper';
|
||||||
import { CoreSite } from '@classes/site';
|
import { CoreSite } from '@classes/site';
|
||||||
|
|
||||||
|
@ -79,6 +80,7 @@ export class AddonCalendarEditEventPage implements OnInit {
|
||||||
private coursesProvider: CoreCoursesProvider,
|
private coursesProvider: CoreCoursesProvider,
|
||||||
private utils: CoreUtilsProvider,
|
private utils: CoreUtilsProvider,
|
||||||
private calendarProvider: AddonCalendarProvider,
|
private calendarProvider: AddonCalendarProvider,
|
||||||
|
private calendarOffline: AddonCalendarOfflineProvider,
|
||||||
private calendarHelper: AddonCalendarHelperProvider,
|
private calendarHelper: AddonCalendarHelperProvider,
|
||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
@Optional() private svComponent: CoreSplitViewComponent) {
|
@Optional() private svComponent: CoreSplitViewComponent) {
|
||||||
|
@ -102,8 +104,10 @@ export class AddonCalendarEditEventPage implements OnInit {
|
||||||
this.groupControl = this.fb.control('');
|
this.groupControl = this.fb.control('');
|
||||||
this.descriptionControl = this.fb.control('');
|
this.descriptionControl = this.fb.control('');
|
||||||
|
|
||||||
|
const currentDate = this.timeUtils.toDatetimeFormat();
|
||||||
|
|
||||||
this.eventForm.addControl('name', this.fb.control('', Validators.required));
|
this.eventForm.addControl('name', this.fb.control('', Validators.required));
|
||||||
this.eventForm.addControl('timestart', this.fb.control(new Date().toISOString(), Validators.required));
|
this.eventForm.addControl('timestart', this.fb.control(currentDate, Validators.required));
|
||||||
this.eventForm.addControl('eventtype', this.eventTypeControl);
|
this.eventForm.addControl('eventtype', this.eventTypeControl);
|
||||||
this.eventForm.addControl('categoryid', this.fb.control(''));
|
this.eventForm.addControl('categoryid', this.fb.control(''));
|
||||||
this.eventForm.addControl('courseid', this.fb.control(this.courseId));
|
this.eventForm.addControl('courseid', this.fb.control(this.courseId));
|
||||||
|
@ -112,7 +116,7 @@ export class AddonCalendarEditEventPage implements OnInit {
|
||||||
this.eventForm.addControl('description', this.descriptionControl);
|
this.eventForm.addControl('description', this.descriptionControl);
|
||||||
this.eventForm.addControl('location', this.fb.control(''));
|
this.eventForm.addControl('location', this.fb.control(''));
|
||||||
this.eventForm.addControl('duration', this.fb.control(0));
|
this.eventForm.addControl('duration', this.fb.control(0));
|
||||||
this.eventForm.addControl('timedurationuntil', this.fb.control(new Date().toISOString()));
|
this.eventForm.addControl('timedurationuntil', this.fb.control(currentDate));
|
||||||
this.eventForm.addControl('timedurationminutes', this.fb.control(''));
|
this.eventForm.addControl('timedurationminutes', this.fb.control(''));
|
||||||
this.eventForm.addControl('repeat', this.fb.control(false));
|
this.eventForm.addControl('repeat', this.fb.control(false));
|
||||||
this.eventForm.addControl('repeats', this.fb.control('1'));
|
this.eventForm.addControl('repeats', this.fb.control('1'));
|
||||||
|
@ -131,9 +135,10 @@ export class AddonCalendarEditEventPage implements OnInit {
|
||||||
/**
|
/**
|
||||||
* Fetch the data needed to render the form.
|
* Fetch the data needed to render the form.
|
||||||
*
|
*
|
||||||
|
* @param {boolean} [refresh] Whether it's refreshing data.
|
||||||
* @return {Promise<any>} Promise resolved when done.
|
* @return {Promise<any>} Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected fetchData(): Promise<any> {
|
protected fetchData(refresh?: boolean): Promise<any> {
|
||||||
let accessInfo;
|
let accessInfo;
|
||||||
|
|
||||||
// Get access info.
|
// Get access info.
|
||||||
|
@ -151,6 +156,33 @@ export class AddonCalendarEditEventPage implements OnInit {
|
||||||
return Promise.reject(this.translate.instant('addon.calendar.nopermissiontoupdatecalendar'));
|
return Promise.reject(this.translate.instant('addon.calendar.nopermissiontoupdatecalendar'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.eventId && !refresh) {
|
||||||
|
// Get the event data if there's any.
|
||||||
|
promises.push(this.calendarOffline.getEvent(this.eventId).then((event) => {
|
||||||
|
this.hasOffline = true;
|
||||||
|
|
||||||
|
// Load the data in the form.
|
||||||
|
this.eventForm.controls.name.setValue(event.name);
|
||||||
|
this.eventForm.controls.timestart.setValue(this.timeUtils.toDatetimeFormat(event.timestart * 1000));
|
||||||
|
this.eventForm.controls.eventtype.setValue(event.eventtype);
|
||||||
|
this.eventForm.controls.categoryid.setValue(event.categoryid || '');
|
||||||
|
this.eventForm.controls.courseid.setValue(event.courseid || '');
|
||||||
|
this.eventForm.controls.groupcourseid.setValue(event.groupcourseid || '');
|
||||||
|
this.eventForm.controls.groupid.setValue(event.groupid || '');
|
||||||
|
this.eventForm.controls.description.setValue(event.description);
|
||||||
|
this.eventForm.controls.location.setValue(event.location);
|
||||||
|
this.eventForm.controls.duration.setValue(event.duration);
|
||||||
|
this.eventForm.controls.timedurationuntil.setValue(
|
||||||
|
this.timeUtils.toDatetimeFormat((event.timedurationuntil * 1000) || Date.now()));
|
||||||
|
this.eventForm.controls.timedurationminutes.setValue(event.timedurationminutes || '');
|
||||||
|
this.eventForm.controls.repeat.setValue(!!event.repeat);
|
||||||
|
this.eventForm.controls.repeats.setValue(event.repeats || '1');
|
||||||
|
}).catch(() => {
|
||||||
|
// No offline data.
|
||||||
|
this.hasOffline = false;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
if (types.category) {
|
if (types.category) {
|
||||||
// Get the categories.
|
// Get the categories.
|
||||||
promises.push(this.coursesProvider.getCategories(0, true).then((cats) => {
|
promises.push(this.coursesProvider.getCategories(0, true).then((cats) => {
|
||||||
|
@ -185,11 +217,13 @@ export class AddonCalendarEditEventPage implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(promises).then(() => {
|
return Promise.all(promises).then(() => {
|
||||||
// Set event types. If course is allowed, select it first.
|
if (!this.eventTypeControl.value) {
|
||||||
if (types.course) {
|
// Initialize event type value. If course is allowed, select it first.
|
||||||
this.eventTypeControl.setValue(AddonCalendarProvider.TYPE_COURSE);
|
if (types.course) {
|
||||||
} else {
|
this.eventTypeControl.setValue(AddonCalendarProvider.TYPE_COURSE);
|
||||||
this.eventTypeControl.setValue(eventTypes[0].value);
|
} else {
|
||||||
|
this.eventTypeControl.setValue(eventTypes[0].value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.eventTypes = eventTypes;
|
this.eventTypes = eventTypes;
|
||||||
|
@ -227,7 +261,7 @@ export class AddonCalendarEditEventPage implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise.all(promises).finally(() => {
|
Promise.all(promises).finally(() => {
|
||||||
this.fetchData().finally(() => {
|
this.fetchData(true).finally(() => {
|
||||||
refresher.complete();
|
refresher.complete();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -333,8 +367,8 @@ export class AddonCalendarEditEventPage implements OnInit {
|
||||||
// Send the data.
|
// Send the data.
|
||||||
const modal = this.domUtils.showModalLoading('core.sending');
|
const modal = this.domUtils.showModalLoading('core.sending');
|
||||||
|
|
||||||
this.calendarProvider.submitEvent(this.eventId, data).then((event) => {
|
this.calendarProvider.submitEvent(this.eventId, data).then((result) => {
|
||||||
this.returnToList(event);
|
this.returnToList(result.event);
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
this.domUtils.showErrorModalDefault(error, 'Error sending data.');
|
this.domUtils.showErrorModalDefault(error, 'Error sending data.');
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
|
@ -348,10 +382,14 @@ export class AddonCalendarEditEventPage implements OnInit {
|
||||||
* @param {number} [event] Event.
|
* @param {number} [event] Event.
|
||||||
*/
|
*/
|
||||||
protected returnToList(event?: any): void {
|
protected returnToList(event?: any): void {
|
||||||
const data: any = {
|
if (event) {
|
||||||
event: event
|
const data: any = {
|
||||||
};
|
event: event
|
||||||
this.eventsProvider.trigger(AddonCalendarProvider.NEW_EVENT_EVENT, data, this.currentSite.getId());
|
};
|
||||||
|
this.eventsProvider.trigger(AddonCalendarProvider.NEW_EVENT_EVENT, data, this.currentSite.getId());
|
||||||
|
} else {
|
||||||
|
this.eventsProvider.trigger(AddonCalendarProvider.NEW_EVENT_DISCARDED_EVENT, {}, this.currentSite.getId());
|
||||||
|
}
|
||||||
|
|
||||||
if (this.svComponent && this.svComponent.isOn()) {
|
if (this.svComponent && this.svComponent.isOn()) {
|
||||||
// Empty form.
|
// Empty form.
|
||||||
|
@ -369,7 +407,12 @@ export class AddonCalendarEditEventPage implements OnInit {
|
||||||
*/
|
*/
|
||||||
discard(): void {
|
discard(): void {
|
||||||
this.domUtils.showConfirm(this.translate.instant('core.areyousure')).then(() => {
|
this.domUtils.showConfirm(this.translate.instant('core.areyousure')).then(() => {
|
||||||
// @todo.
|
this.calendarOffline.deleteEvent(this.eventId).then(() => {
|
||||||
|
this.returnToList();
|
||||||
|
}).catch(() => {
|
||||||
|
// Shouldn't happen.
|
||||||
|
this.domUtils.showErrorModal('Error discarding event.');
|
||||||
|
});
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
// Cancelled.
|
// Cancelled.
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,9 +17,28 @@
|
||||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||||
</ion-refresher>
|
</ion-refresher>
|
||||||
<core-loading [hideUntil]="eventsLoaded">
|
<core-loading [hideUntil]="eventsLoaded">
|
||||||
|
<!-- There is data to be synchronized -->
|
||||||
|
<ion-card class="core-warning-card" icon-start *ngIf="hasOffline">
|
||||||
|
<ion-icon name="warning"></ion-icon> {{ 'core.hasdatatosync' | translate:{$a: 'addon.calendar.calendar' | translate} }}
|
||||||
|
</ion-card>
|
||||||
|
|
||||||
<core-empty-box *ngIf="!filteredEvents || !filteredEvents.length" icon="calendar" [message]="'addon.calendar.noevents' | translate">
|
<core-empty-box *ngIf="!filteredEvents || !filteredEvents.length" icon="calendar" [message]="'addon.calendar.noevents' | translate">
|
||||||
</core-empty-box>
|
</core-empty-box>
|
||||||
|
|
||||||
|
<ion-list *ngIf="offlineEvents && offlineEvents.length" no-margin>
|
||||||
|
<ng-container *ngFor="let event of offlineEvents">
|
||||||
|
<ion-item-divider> {{ 'core.notsent' | translate }}</ion-item-divider>
|
||||||
|
<a ion-item text-wrap [title]="event.name" (click)="gotoEvent(event.id)" [class.core-split-item-selected]="event.id == eventId">
|
||||||
|
<core-icon *ngIf="event.icon" [name]="event.icon" item-start></core-icon>
|
||||||
|
<h2><core-format-text [text]="event.name"></core-format-text></h2>
|
||||||
|
<p>
|
||||||
|
{{ event.timestart * 1000 | coreFormatDate: "strftimedatetimeshort" }}
|
||||||
|
<span *ngIf="event.timeduration"> - {{ (event.timestart + event.timeduration) * 1000 | coreFormatDate: "strftimedatetimeshort" }}</span>
|
||||||
|
</p>
|
||||||
|
</a>
|
||||||
|
</ng-container>
|
||||||
|
</ion-list>
|
||||||
|
|
||||||
<ion-list *ngIf="filteredEvents && filteredEvents.length" no-margin>
|
<ion-list *ngIf="filteredEvents && filteredEvents.length" no-margin>
|
||||||
<ng-container *ngFor="let event of filteredEvents">
|
<ng-container *ngFor="let event of filteredEvents">
|
||||||
<ion-item-divider *ngIf="event.showDate">
|
<ion-item-divider *ngIf="event.showDate">
|
||||||
|
@ -43,7 +62,7 @@
|
||||||
|
|
||||||
<!-- Create a calendar event. -->
|
<!-- Create a calendar event. -->
|
||||||
<ion-fab core-fab bottom end *ngIf="canCreate">
|
<ion-fab core-fab bottom end *ngIf="canCreate">
|
||||||
<button ion-fab (click)="openCreate()" [attr.aria-label]="'addon.calendar.newevent' | translate">
|
<button ion-fab (click)="openEdit()" [attr.aria-label]="'addon.calendar.newevent' | translate">
|
||||||
<ion-icon name="add"></ion-icon>
|
<ion-icon name="add"></ion-icon>
|
||||||
</button>
|
</button>
|
||||||
</ion-fab>
|
</ion-fab>
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { Component, ViewChild, OnDestroy } from '@angular/core';
|
||||||
import { IonicPage, Content, PopoverController, NavParams, NavController } from 'ionic-angular';
|
import { IonicPage, Content, PopoverController, NavParams, NavController } from 'ionic-angular';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { AddonCalendarProvider } from '../../providers/calendar';
|
import { AddonCalendarProvider } from '../../providers/calendar';
|
||||||
|
import { AddonCalendarOfflineProvider } from '../../providers/calendar-offline';
|
||||||
import { AddonCalendarHelperProvider } from '../../providers/helper';
|
import { AddonCalendarHelperProvider } from '../../providers/helper';
|
||||||
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
|
@ -55,10 +56,12 @@ export class AddonCalendarListPage implements OnDestroy {
|
||||||
protected eventId: number;
|
protected eventId: number;
|
||||||
protected preSelectedCourseId: number;
|
protected preSelectedCourseId: number;
|
||||||
protected newEventObserver: any;
|
protected newEventObserver: any;
|
||||||
|
protected discardedObserver: any;
|
||||||
|
|
||||||
courses: any[];
|
courses: any[];
|
||||||
eventsLoaded = false;
|
eventsLoaded = false;
|
||||||
events = [];
|
events = [];
|
||||||
|
offlineEvents = [];
|
||||||
notificationsEnabled = false;
|
notificationsEnabled = false;
|
||||||
filteredEvents = [];
|
filteredEvents = [];
|
||||||
canLoadMore = false;
|
canLoadMore = false;
|
||||||
|
@ -67,12 +70,14 @@ export class AddonCalendarListPage implements OnDestroy {
|
||||||
course: this.allCourses
|
course: this.allCourses
|
||||||
};
|
};
|
||||||
canCreate = false;
|
canCreate = false;
|
||||||
|
hasOffline = false;
|
||||||
|
|
||||||
constructor(private translate: TranslateService, private calendarProvider: AddonCalendarProvider, navParams: NavParams,
|
constructor(private translate: TranslateService, private calendarProvider: AddonCalendarProvider, navParams: NavParams,
|
||||||
private domUtils: CoreDomUtilsProvider, private coursesProvider: CoreCoursesProvider, private utils: CoreUtilsProvider,
|
private domUtils: CoreDomUtilsProvider, private coursesProvider: CoreCoursesProvider, private utils: CoreUtilsProvider,
|
||||||
private calendarHelper: AddonCalendarHelperProvider, sitesProvider: CoreSitesProvider,
|
private calendarHelper: AddonCalendarHelperProvider, sitesProvider: CoreSitesProvider,
|
||||||
localNotificationsProvider: CoreLocalNotificationsProvider, private popoverCtrl: PopoverController,
|
localNotificationsProvider: CoreLocalNotificationsProvider, private popoverCtrl: PopoverController,
|
||||||
eventsProvider: CoreEventsProvider, private navCtrl: NavController, appProvider: CoreAppProvider) {
|
eventsProvider: CoreEventsProvider, private navCtrl: NavController, appProvider: CoreAppProvider,
|
||||||
|
private calendarOffline: AddonCalendarOfflineProvider) {
|
||||||
|
|
||||||
this.siteHomeId = sitesProvider.getCurrentSite().getSiteHomeId();
|
this.siteHomeId = sitesProvider.getCurrentSite().getSiteHomeId();
|
||||||
this.notificationsEnabled = localNotificationsProvider.isAvailable();
|
this.notificationsEnabled = localNotificationsProvider.isAvailable();
|
||||||
|
@ -87,7 +92,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.preSelectedCourseId = navParams.get('courseId') || null;
|
||||||
|
|
||||||
// Listen for events added. When an event is added, we 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) => {
|
||||||
if (data && data.event) {
|
if (data && data.event) {
|
||||||
if (this.splitviewCtrl.isOn()) {
|
if (this.splitviewCtrl.isOn()) {
|
||||||
|
@ -97,19 +102,25 @@ export class AddonCalendarListPage implements OnDestroy {
|
||||||
|
|
||||||
this.eventsLoaded = false;
|
this.eventsLoaded = false;
|
||||||
this.refreshEvents(false).finally(() => {
|
this.refreshEvents(false).finally(() => {
|
||||||
this.eventsLoaded = true;
|
|
||||||
|
|
||||||
// In tablet mode try to open the event.
|
// In tablet mode try to open the event (only if it's an online event).
|
||||||
if (this.splitviewCtrl.isOn()) {
|
if (this.splitviewCtrl.isOn() && data.event.id > 0) {
|
||||||
if (data.event.id) {
|
this.gotoEvent(data.event.id);
|
||||||
this.gotoEvent(data.event.id);
|
|
||||||
} else {
|
|
||||||
// It's an offline event.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, sitesProvider.getCurrentSiteId());
|
}, sitesProvider.getCurrentSiteId());
|
||||||
|
|
||||||
|
// Listen for new event discarded event. When it does, reload the data.
|
||||||
|
this.discardedObserver = eventsProvider.on(AddonCalendarProvider.NEW_EVENT_DISCARDED_EVENT, () => {
|
||||||
|
if (this.splitviewCtrl.isOn()) {
|
||||||
|
// Discussion added, clear details page.
|
||||||
|
this.splitviewCtrl.emptyDetails();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.eventsLoaded = false;
|
||||||
|
this.refreshEvents(false);
|
||||||
|
}, sitesProvider.getCurrentSiteId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -126,8 +137,6 @@ export class AddonCalendarListPage implements OnDestroy {
|
||||||
// Take first and load it.
|
// Take first and load it.
|
||||||
this.gotoEvent(this.events[0].id);
|
this.gotoEvent(this.events[0].id);
|
||||||
}
|
}
|
||||||
}).finally(() => {
|
|
||||||
this.eventsLoaded = true;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +176,18 @@ export class AddonCalendarListPage implements OnDestroy {
|
||||||
return this.fetchEvents(refresh);
|
return this.fetchEvents(refresh);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return Promise.all(promises);
|
// Get offline events.
|
||||||
|
promises.push(this.calendarOffline.getAllEvents().then((events) => {
|
||||||
|
this.hasOffline = !!events.length;
|
||||||
|
|
||||||
|
// Format data and sort by timestart.
|
||||||
|
events.forEach(this.calendarHelper.formatEventData.bind(this.calendarHelper));
|
||||||
|
this.offlineEvents = events.sort((a, b) => a.timestart - b.timestart);
|
||||||
|
}));
|
||||||
|
|
||||||
|
return Promise.all(promises).finally(() => {
|
||||||
|
this.eventsLoaded = true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -194,6 +214,8 @@ export class AddonCalendarListPage implements OnDestroy {
|
||||||
return this.fetchEvents();
|
return this.fetchEvents();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
events.forEach(this.calendarHelper.formatEventData.bind(this.calendarHelper));
|
||||||
|
|
||||||
// Sort the events by timestart, they're ordered by id.
|
// Sort the events by timestart, they're ordered by id.
|
||||||
events.sort((a, b) => {
|
events.sort((a, b) => {
|
||||||
if (a.timestart == b.timestart) {
|
if (a.timestart == b.timestart) {
|
||||||
|
@ -203,7 +225,6 @@ export class AddonCalendarListPage implements OnDestroy {
|
||||||
return a.timestart - b.timestart;
|
return a.timestart - b.timestart;
|
||||||
});
|
});
|
||||||
|
|
||||||
events.forEach(this.calendarHelper.formatEventData.bind(this.calendarHelper));
|
|
||||||
this.getCategories = this.shouldLoadCategories(events);
|
this.getCategories = this.shouldLoadCategories(events);
|
||||||
|
|
||||||
if (refresh) {
|
if (refresh) {
|
||||||
|
@ -427,10 +448,16 @@ export class AddonCalendarListPage implements OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open page to create an event.
|
* Open page to create/edit an event.
|
||||||
|
*
|
||||||
|
* @param {number} [eventId] Event ID to edit.
|
||||||
*/
|
*/
|
||||||
openCreate(): void {
|
openEdit(eventId?: number): void {
|
||||||
const params: any = {};
|
const params: any = {};
|
||||||
|
|
||||||
|
if (eventId) {
|
||||||
|
params.eventId = eventId;
|
||||||
|
}
|
||||||
if (this.filter.course.id != this.allCourses.id) {
|
if (this.filter.course.id != this.allCourses.id) {
|
||||||
params.courseId = this.filter.course.id;
|
params.courseId = this.filter.course.id;
|
||||||
}
|
}
|
||||||
|
@ -452,7 +479,15 @@ export class AddonCalendarListPage implements OnDestroy {
|
||||||
*/
|
*/
|
||||||
gotoEvent(eventId: number): void {
|
gotoEvent(eventId: number): void {
|
||||||
this.eventId = eventId;
|
this.eventId = eventId;
|
||||||
this.splitviewCtrl.push('AddonCalendarEventPage', { id: eventId });
|
|
||||||
|
if (eventId < 0) {
|
||||||
|
// It's an offline event, go to the edit page.
|
||||||
|
this.openEdit(eventId);
|
||||||
|
} else {
|
||||||
|
this.splitviewCtrl.push('AddonCalendarEventPage', {
|
||||||
|
id: eventId
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,215 @@
|
||||||
|
// (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 { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
|
||||||
|
import { AddonCalendarProvider } from './calendar';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service to handle offline calendar events.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AddonCalendarOfflineProvider {
|
||||||
|
|
||||||
|
// Variables for database.
|
||||||
|
static EVENTS_TABLE = 'addon_calendar_offline_events';
|
||||||
|
|
||||||
|
protected siteSchema: CoreSiteSchema = {
|
||||||
|
name: 'AddonCalendarOfflineProvider',
|
||||||
|
version: 1,
|
||||||
|
tables: [
|
||||||
|
{
|
||||||
|
name: AddonCalendarOfflineProvider.EVENTS_TABLE,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'id', // Negative for offline entries.
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
type: 'TEXT',
|
||||||
|
notNull: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'timestart',
|
||||||
|
type: 'INTEGER',
|
||||||
|
notNull: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'eventtype',
|
||||||
|
type: 'TEXT',
|
||||||
|
notNull: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'categoryid',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'courseid',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'groupcourseid',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'groupid',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'description',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'location',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'duration',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'timedurationuntil',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'timedurationminutes',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'repeat',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'repeats',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'userid',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'timecreated',
|
||||||
|
type: 'INTEGER',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
primaryKeys: ['id']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(private sitesProvider: CoreSitesProvider) {
|
||||||
|
this.sitesProvider.registerSiteSchema(this.siteSchema);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete an offline event.
|
||||||
|
*
|
||||||
|
* @param {number} eventId Event ID.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {Promise<any>} Promise resolved if deleted, rejected if failure.
|
||||||
|
*/
|
||||||
|
deleteEvent(eventId: number, siteId?: string): Promise<any> {
|
||||||
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
const conditions: any = {
|
||||||
|
id: eventId
|
||||||
|
};
|
||||||
|
|
||||||
|
return site.getDb().deleteRecords(AddonCalendarOfflineProvider.EVENTS_TABLE, conditions);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all offline events.
|
||||||
|
*
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {Promise<any[]>} Promise resolved with events.
|
||||||
|
*/
|
||||||
|
getAllEvents(siteId?: string): Promise<any[]> {
|
||||||
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
return site.getDb().getRecords(AddonCalendarOfflineProvider.EVENTS_TABLE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an offline event.
|
||||||
|
*
|
||||||
|
* @param {number} eventId Event ID.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {Promise<any>} Promise resolved with the event.
|
||||||
|
*/
|
||||||
|
getEvent(eventId: number, siteId?: string): Promise<any> {
|
||||||
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
const conditions: any = {
|
||||||
|
id: eventId
|
||||||
|
};
|
||||||
|
|
||||||
|
return site.getDb().getRecord(AddonCalendarOfflineProvider.EVENTS_TABLE, conditions);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if there are offline events to send.
|
||||||
|
*
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {Promise<boolean>} Promise resolved with boolean: true if has offline events, false otherwise.
|
||||||
|
*/
|
||||||
|
hasEvents(siteId?: string): Promise<boolean> {
|
||||||
|
return this.getAllEvents(siteId).then((events) => {
|
||||||
|
return !!events.length;
|
||||||
|
}).catch(() => {
|
||||||
|
// No offline data found, return false.
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offline version for adding a new discussion to a forum.
|
||||||
|
*
|
||||||
|
* @param {number} eventId Event ID. If it's a new event, set it to undefined/null.
|
||||||
|
* @param {any} data Event data.
|
||||||
|
* @param {number} [timeCreated] The time the event was created. If not defined, current time.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {Promise<any>} Promise resolved with the stored event.
|
||||||
|
*/
|
||||||
|
saveEvent(eventId: number, data: any, timeCreated?: number, siteId?: string): Promise<any> {
|
||||||
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
timeCreated = timeCreated || Date.now();
|
||||||
|
|
||||||
|
const event = {
|
||||||
|
id: eventId || -timeCreated,
|
||||||
|
name: data.name,
|
||||||
|
timestart: data.timestart,
|
||||||
|
eventtype: data.eventtype,
|
||||||
|
categoryid: data.categoryid || null,
|
||||||
|
courseid: data.courseid || null,
|
||||||
|
groupcourseid: data.groupcourseid || null,
|
||||||
|
groupid: data.groupid || null,
|
||||||
|
description: data.description && data.description.text,
|
||||||
|
location: data.location,
|
||||||
|
duration: data.duration,
|
||||||
|
timedurationuntil: data.timedurationuntil,
|
||||||
|
timedurationminutes: data.timedurationminutes,
|
||||||
|
repeat: data.repeat ? 1 : 0,
|
||||||
|
repeats: data.repeats,
|
||||||
|
timecreated: timeCreated,
|
||||||
|
userid: site.getUserId()
|
||||||
|
};
|
||||||
|
|
||||||
|
return site.getDb().insertRecord(AddonCalendarOfflineProvider.EVENTS_TABLE, event).then(() => {
|
||||||
|
return event;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ import { CoreLoggerProvider } from '@providers/logger';
|
||||||
import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
|
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 { CoreTimeUtilsProvider } from '@providers/utils/time';
|
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
import { CoreGroupsProvider } from '@providers/groups';
|
import { CoreGroupsProvider } from '@providers/groups';
|
||||||
|
@ -25,6 +26,7 @@ import { CoreLocalNotificationsProvider } from '@providers/local-notifications';
|
||||||
import { CoreConfigProvider } from '@providers/config';
|
import { CoreConfigProvider } from '@providers/config';
|
||||||
import { ILocalNotification } from '@ionic-native/local-notifications';
|
import { ILocalNotification } from '@ionic-native/local-notifications';
|
||||||
import { SQLiteDB } from '@classes/sqlitedb';
|
import { SQLiteDB } from '@classes/sqlitedb';
|
||||||
|
import { AddonCalendarOfflineProvider } from './calendar-offline';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to handle calendar events.
|
* Service to handle calendar events.
|
||||||
|
@ -37,6 +39,7 @@ export class AddonCalendarProvider {
|
||||||
static DEFAULT_NOTIFICATION_TIME_SETTING = 'mmaCalendarDefaultNotifTime';
|
static DEFAULT_NOTIFICATION_TIME_SETTING = 'mmaCalendarDefaultNotifTime';
|
||||||
static DEFAULT_NOTIFICATION_TIME = 60;
|
static DEFAULT_NOTIFICATION_TIME = 60;
|
||||||
static NEW_EVENT_EVENT = 'addon_calendar_new_event';
|
static NEW_EVENT_EVENT = 'addon_calendar_new_event';
|
||||||
|
static NEW_EVENT_DISCARDED_EVENT = 'addon_calendar_new_event_discarded';
|
||||||
static TYPE_CATEGORY = 'category';
|
static TYPE_CATEGORY = 'category';
|
||||||
static TYPE_COURSE = 'course';
|
static TYPE_COURSE = 'course';
|
||||||
static TYPE_GROUP = 'group';
|
static TYPE_GROUP = 'group';
|
||||||
|
@ -214,7 +217,8 @@ export class AddonCalendarProvider {
|
||||||
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private groupsProvider: CoreGroupsProvider,
|
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private groupsProvider: CoreGroupsProvider,
|
||||||
private coursesProvider: CoreCoursesProvider, private timeUtils: CoreTimeUtilsProvider,
|
private coursesProvider: CoreCoursesProvider, private timeUtils: CoreTimeUtilsProvider,
|
||||||
private localNotificationsProvider: CoreLocalNotificationsProvider, private configProvider: CoreConfigProvider,
|
private localNotificationsProvider: CoreLocalNotificationsProvider, private configProvider: CoreConfigProvider,
|
||||||
private utils: CoreUtilsProvider) {
|
private utils: CoreUtilsProvider, private calendarOffline: AddonCalendarOfflineProvider,
|
||||||
|
private appProvider: CoreAppProvider) {
|
||||||
this.logger = logger.getInstance('AddonCalendarProvider');
|
this.logger = logger.getInstance('AddonCalendarProvider');
|
||||||
this.sitesProvider.registerSiteSchema(this.siteSchema);
|
this.sitesProvider.registerSiteSchema(this.siteSchema);
|
||||||
}
|
}
|
||||||
|
@ -918,14 +922,58 @@ export class AddonCalendarProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Submit an event, either to create it or to edit it.
|
* Submit a calendar event.
|
||||||
|
*
|
||||||
|
* @param {number} eventId ID of the event. If undefined/null, create a new event.
|
||||||
|
* @param {any} formData Form data.
|
||||||
|
* @param {number} [timeCreated] The time the event was created. Only if modifying a new offline event.
|
||||||
|
* @param {boolean} [forceOffline] True to always save it in offline.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {Promise<{sent: boolean, event: any}>} Promise resolved with the event and a boolean indicating if data was
|
||||||
|
* sent to server or stored in offline.
|
||||||
|
*/
|
||||||
|
submitEvent(eventId: number, formData: any, timeCreated?: number, forceOffline?: boolean, siteId?: string):
|
||||||
|
Promise<{sent: boolean, event: any}> {
|
||||||
|
|
||||||
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
|
// Function to store the event to be synchronized later.
|
||||||
|
const storeOffline = (): Promise<{sent: boolean, event: any}> => {
|
||||||
|
return this.calendarOffline.saveEvent(eventId, formData, timeCreated, siteId).then((event) => {
|
||||||
|
return {sent: false, event: event};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (forceOffline || !this.appProvider.isOnline()) {
|
||||||
|
// App is offline, store the event.
|
||||||
|
return storeOffline();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the event is already stored, discard it first.
|
||||||
|
return this.calendarOffline.deleteEvent(eventId, siteId).then(() => {
|
||||||
|
return this.submitEventOnline(eventId, formData, siteId).then((event) => {
|
||||||
|
return {sent: true, event: event};
|
||||||
|
}).catch((error) => {
|
||||||
|
if (error && !this.utils.isWebServiceError(error)) {
|
||||||
|
// Couldn't connect to server, store in offline.
|
||||||
|
return storeOffline();
|
||||||
|
} else {
|
||||||
|
// The WebService has thrown an error, reject.
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit an event, either to create it or to edit it. It will fail if offline or cannot connect.
|
||||||
*
|
*
|
||||||
* @param {number} eventId ID of the event. If undefined/null, create a new event.
|
* @param {number} eventId ID of the event. If undefined/null, create a new event.
|
||||||
* @param {any} formData Form data.
|
* @param {any} formData Form data.
|
||||||
* @param {string} [siteId] Site ID. If not provided, current site.
|
* @param {string} [siteId] Site ID. If not provided, current site.
|
||||||
* @return {Promise<any>} Promise resolved when done.
|
* @return {Promise<any>} Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
submitEvent(eventId: number, formData: any, siteId?: string): Promise<any> {
|
submitEventOnline(eventId: number, formData: any, siteId?: string): Promise<any> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
// Add data that is "hidden" in web.
|
// Add data that is "hidden" in web.
|
||||||
formData.id = eventId || 0;
|
formData.id = eventId || 0;
|
||||||
|
@ -940,7 +988,7 @@ export class AddonCalendarProvider {
|
||||||
|
|
||||||
return site.write('core_calendar_submit_create_update_form', params).then((result) => {
|
return site.write('core_calendar_submit_create_update_form', params).then((result) => {
|
||||||
if (result.validationerror) {
|
if (result.validationerror) {
|
||||||
return Promise.reject(null);
|
return Promise.reject(this.utils.createFakeWSError(''));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.event;
|
return result.event;
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { Injectable } from '@angular/core';
|
||||||
import { CoreLoggerProvider } from '@providers/logger';
|
import { CoreLoggerProvider } from '@providers/logger';
|
||||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||||
import { AddonCalendarProvider } from './calendar';
|
import { AddonCalendarProvider } from './calendar';
|
||||||
|
import { CoreConstants } from '@core/constants';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service that provides some features regarding lists of courses and categories.
|
* Service that provides some features regarding lists of courses and categories.
|
||||||
|
@ -47,6 +48,20 @@ export class AddonCalendarHelperProvider {
|
||||||
e.icon = this.courseProvider.getModuleIconSrc(e.modulename);
|
e.icon = this.courseProvider.getModuleIconSrc(e.modulename);
|
||||||
e.moduleIcon = e.icon;
|
e.moduleIcon = e.icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e.id < 0) {
|
||||||
|
// It's an offline event, add some calculated data.
|
||||||
|
e.format = 1;
|
||||||
|
e.visible = 1;
|
||||||
|
|
||||||
|
if (e.duration == 1) {
|
||||||
|
e.timeduration = e.timedurationuntil - e.timestart;
|
||||||
|
} else if (e.duration == 2) {
|
||||||
|
e.timeduration = e.timedurationminutes * CoreConstants.SECONDS_MINUTE;
|
||||||
|
} else {
|
||||||
|
e.timeduration = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -51,10 +51,10 @@ export class AddonModDataFieldDateComponent extends AddonModDataFieldPluginCompo
|
||||||
val = this.search['f_' + this.field.id + '_y'] ? new Date(this.search['f_' + this.field.id + '_y'] + '-' +
|
val = this.search['f_' + this.field.id + '_y'] ? new Date(this.search['f_' + this.field.id + '_y'] + '-' +
|
||||||
this.search['f_' + this.field.id + '_m'] + '-' + this.search['f_' + this.field.id + '_d']) : new Date();
|
this.search['f_' + this.field.id + '_m'] + '-' + this.search['f_' + this.field.id + '_d']) : new Date();
|
||||||
|
|
||||||
this.search['f_' + this.field.id] = val.toISOString();
|
this.search['f_' + this.field.id] = this.timeUtils.toDatetimeFormat(val.getTime());
|
||||||
} else {
|
} else {
|
||||||
val = this.value && this.value.content ? new Date(parseInt(this.value.content, 10) * 1000) : new Date();
|
val = this.value && this.value.content ? new Date(parseInt(this.value.content, 10) * 1000) : new Date();
|
||||||
val = val.toISOString();
|
val = this.timeUtils.toDatetimeFormat(val.getTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addControl('f_' + this.field.id, val);
|
this.addControl('f_' + this.field.id, val);
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { Injector, Injectable } from '@angular/core';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { AddonModDataFieldHandler } from '../../../providers/fields-delegate';
|
import { AddonModDataFieldHandler } from '../../../providers/fields-delegate';
|
||||||
import { AddonModDataFieldDateComponent } from '../component/date';
|
import { AddonModDataFieldDateComponent } from '../component/date';
|
||||||
|
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for date data field plugin.
|
* Handler for date data field plugin.
|
||||||
|
@ -24,7 +25,7 @@ export class AddonModDataFieldDateHandler implements AddonModDataFieldHandler {
|
||||||
name = 'AddonModDataFieldDateHandler';
|
name = 'AddonModDataFieldDateHandler';
|
||||||
type = 'date';
|
type = 'date';
|
||||||
|
|
||||||
constructor(private translate: TranslateService) { }
|
constructor(private translate: TranslateService, private timeUtils: CoreTimeUtilsProvider) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the Component to use to display the plugin data.
|
* Return the Component to use to display the plugin data.
|
||||||
|
@ -129,7 +130,7 @@ export class AddonModDataFieldDateHandler implements AddonModDataFieldHandler {
|
||||||
input = inputData[fieldName] && inputData[fieldName].substr(0, 10) || '';
|
input = inputData[fieldName] && inputData[fieldName].substr(0, 10) || '';
|
||||||
|
|
||||||
originalFieldData = (originalFieldData && originalFieldData.content &&
|
originalFieldData = (originalFieldData && originalFieldData.content &&
|
||||||
new Date(originalFieldData.content * 1000).toISOString().substr(0, 10)) || '';
|
this.timeUtils.toDatetimeFormat(originalFieldData.content * 1000).substr(0, 10)) || '';
|
||||||
|
|
||||||
return input != originalFieldData;
|
return input != originalFieldData;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1389,6 +1389,7 @@
|
||||||
"core.deleteduser": "Deleted user",
|
"core.deleteduser": "Deleted user",
|
||||||
"core.deleting": "Deleting",
|
"core.deleting": "Deleting",
|
||||||
"core.description": "Description",
|
"core.description": "Description",
|
||||||
|
"core.dfdatetimeinput": "YYYY-MM-DDThh:mm:ss.SSS",
|
||||||
"core.dfdaymonthyear": "MM-DD-YYYY",
|
"core.dfdaymonthyear": "MM-DD-YYYY",
|
||||||
"core.dfdayweekmonth": "ddd, D MMM",
|
"core.dfdayweekmonth": "ddd, D MMM",
|
||||||
"core.dffulldate": "dddd, D MMMM YYYY h[:]mm A",
|
"core.dffulldate": "dddd, D MMMM YYYY h[:]mm A",
|
||||||
|
|
|
@ -64,6 +64,7 @@
|
||||||
"deleteduser": "Deleted user",
|
"deleteduser": "Deleted user",
|
||||||
"deleting": "Deleting",
|
"deleting": "Deleting",
|
||||||
"description": "Description",
|
"description": "Description",
|
||||||
|
"dfdatetimeinput": "YYYY-MM-DDThh:mm:ss.SSS",
|
||||||
"dfdaymonthyear": "MM-DD-YYYY",
|
"dfdaymonthyear": "MM-DD-YYYY",
|
||||||
"dfdayweekmonth": "ddd, D MMM",
|
"dfdayweekmonth": "ddd, D MMM",
|
||||||
"dffulldate": "dddd, D MMMM YYYY h[:]mm A",
|
"dffulldate": "dddd, D MMMM YYYY h[:]mm A",
|
||||||
|
|
|
@ -299,6 +299,18 @@ export class CoreTimeUtilsProvider {
|
||||||
return moment(timestamp).format(format);
|
return moment(timestamp).format(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a timestamp to the format to set to a datetime input.
|
||||||
|
*
|
||||||
|
* @param {number} [timestamp] Timestamp to convert (in ms). If not provided, current time.
|
||||||
|
* @return {string} Formatted time.
|
||||||
|
*/
|
||||||
|
toDatetimeFormat(timestamp?: number): string {
|
||||||
|
timestamp = timestamp || Date.now();
|
||||||
|
|
||||||
|
return this.userDate(timestamp, 'core.dfdatetimeinput', false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a text into user timezone timestamp.
|
* Convert a text into user timezone timestamp.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue