MOBILE-3021 calendar: Support monthly view
parent
fa837532d4
commit
661709acb4
|
@ -106,9 +106,13 @@
|
|||
"addon.calendar.eventname": "calendar",
|
||||
"addon.calendar.eventstarttime": "calendar",
|
||||
"addon.calendar.eventtype": "calendar",
|
||||
"addon.calendar.fri": "calendar",
|
||||
"addon.calendar.friday": "calendar",
|
||||
"addon.calendar.gotoactivity": "calendar",
|
||||
"addon.calendar.invalidtimedurationminutes": "calendar",
|
||||
"addon.calendar.invalidtimedurationuntil": "calendar",
|
||||
"addon.calendar.mon": "calendar",
|
||||
"addon.calendar.monday": "calendar",
|
||||
"addon.calendar.newevent": "calendar",
|
||||
"addon.calendar.noevents": "local_moodlemobileapp",
|
||||
"addon.calendar.nopermissiontoupdatecalendar": "error",
|
||||
|
@ -118,7 +122,15 @@
|
|||
"addon.calendar.repeateditthis": "calendar",
|
||||
"addon.calendar.repeatevent": "calendar",
|
||||
"addon.calendar.repeatweeksl": "calendar",
|
||||
"addon.calendar.sat": "calendar",
|
||||
"addon.calendar.saturday": "calendar",
|
||||
"addon.calendar.setnewreminder": "local_moodlemobileapp",
|
||||
"addon.calendar.sun": "calendar",
|
||||
"addon.calendar.sunday": "calendar",
|
||||
"addon.calendar.thu": "calendar",
|
||||
"addon.calendar.thursday": "calendar",
|
||||
"addon.calendar.tue": "calendar",
|
||||
"addon.calendar.tuesday": "calendar",
|
||||
"addon.calendar.typecategory": "calendar",
|
||||
"addon.calendar.typeclose": "calendar",
|
||||
"addon.calendar.typecourse": "calendar",
|
||||
|
@ -128,6 +140,8 @@
|
|||
"addon.calendar.typeopen": "calendar",
|
||||
"addon.calendar.typesite": "calendar",
|
||||
"addon.calendar.typeuser": "calendar",
|
||||
"addon.calendar.wed": "calendar",
|
||||
"addon.calendar.wednesday": "calendar",
|
||||
"addon.competency.activities": "tool_lp",
|
||||
"addon.competency.competencies": "competency",
|
||||
"addon.competency.competenciesmostoftennotproficientincourse": "tool_lp",
|
||||
|
@ -1657,6 +1671,7 @@
|
|||
"core.notingroup": "moodle",
|
||||
"core.notsent": "local_moodlemobileapp",
|
||||
"core.now": "moodle",
|
||||
"core.nummore": "local_moodlemobileapp",
|
||||
"core.numwords": "moodle",
|
||||
"core.offline": "message",
|
||||
"core.ok": "moodle",
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||
<!-- Period name and arrows to navigate. -->
|
||||
<ion-grid padding-top>
|
||||
<ion-row>
|
||||
<ion-col text-start *ngIf="canNavigate">
|
||||
<a ion-button icon-only clear (click)="loadPrevious()" [title]="'core.previous' | translate">
|
||||
<ion-icon name="arrow-back" md="ios-arrow-back"></ion-icon>
|
||||
</a>
|
||||
</ion-col>
|
||||
<ion-col text-center>
|
||||
<p>{{ periodName }}</p>
|
||||
</ion-col>
|
||||
<ion-col text-end *ngIf="canNavigate">
|
||||
<a ion-button icon-only clear (click)="loadNext()" [title]="'core.next' | translate">
|
||||
<ion-icon name="arrow-forward" md="ios-arrow-forward"></ion-icon>
|
||||
</a>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
|
||||
<!-- Calendar view. -->
|
||||
<ion-grid no-padding>
|
||||
<!-- List of days. -->
|
||||
<ion-row>
|
||||
<ion-col text-center *ngFor="let day of weekDays" class="addon-calendar-weekdays">
|
||||
<p>{{ day.shortname | translate }}</p>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
||||
<!-- Weeks. -->
|
||||
<ion-row *ngFor="let week of weeks">
|
||||
<ion-col *ngFor="let value of week.prepadding" class="dayblank"></ion-col> <!-- Empty slots (first week). -->
|
||||
<ion-col text-center *ngFor="let day of week.days" [ngClass]='{"hasevents": day.hasevents, "today": day.istoday, "weekend": day.isweekend, "duration_finish": day.haslastdayofevent}' >
|
||||
<p>{{ day.mday }}</p>
|
||||
|
||||
<!-- In phone, display some dots to indicate the type of events. -->
|
||||
<p class="hidden-tablet"><span *ngFor="let type of day.calendareventtypes" class="calendar_event_type calendar_event_{{type}}"></span></p>
|
||||
|
||||
<!-- In tablet, display list of events. -->
|
||||
<div class="hidden-phone" class="addon-calendar-day-events">
|
||||
<p *ngFor="let event of day.filteredEvents | slice:0:3">
|
||||
<span class="calendar_event_type calendar_event_{{event.eventtype}}"></span>
|
||||
{{event.name}}
|
||||
</p>
|
||||
<p *ngIf="day.filteredEvents.length > 3">{{ 'core.nummore' | translate:{$a: day.filteredEvents.length - 3} }}</p>
|
||||
</div>
|
||||
</ion-col>
|
||||
<ion-col *ngFor="let value of week.postpadding" class="dayblank"></ion-col> <!-- Empty slots (last week). -->
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
|
||||
</core-loading>
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
$calendar-event-category-color: $purple !default; // Purple.
|
||||
$calendar-event-course-color: $red !default; // Red.
|
||||
$calendar-event-group-color: $yellow !default; // Yellow.
|
||||
$calendar-event-user-color: $blue !default; // Blue.
|
||||
$calendar-event-site-color: $green !default; // Green.
|
||||
|
||||
ion-app.app-root addon-calendar-calendar {
|
||||
|
||||
.addon-calendar-weekdays {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.addon-calendar-day-events {
|
||||
@include text-align('start');
|
||||
}
|
||||
|
||||
.calendar_event_type {
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid white;
|
||||
@include margin-horizontal(1px, 1px);
|
||||
|
||||
&.calendar_event_category {
|
||||
background-color: $calendar-event-category-color;
|
||||
}
|
||||
&.calendar_event_course {
|
||||
background-color: $calendar-event-course-color;
|
||||
}
|
||||
&.calendar_event_group {
|
||||
background-color: $calendar-event-group-color;
|
||||
}
|
||||
&.calendar_event_user {
|
||||
background-color: $calendar-event-user-color;
|
||||
}
|
||||
&.calendar_event_site {
|
||||
background-color: $calendar-event-site-color;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
// (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 { Component, OnDestroy, OnInit, Input, OnChanges, SimpleChange } from '@angular/core';
|
||||
import { CoreEventsProvider } from '@providers/events';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { AddonCalendarProvider } from '../../providers/calendar';
|
||||
import { AddonCalendarHelperProvider } from '../../providers/helper';
|
||||
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
||||
|
||||
/**
|
||||
* Component that displays a calendar.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-calendar-calendar',
|
||||
templateUrl: 'addon-calendar-calendar.html',
|
||||
})
|
||||
export class AddonCalendarCalendarComponent implements OnInit, OnChanges, OnDestroy {
|
||||
@Input() initialYear: number | string; // Initial year to load.
|
||||
@Input() initialMonth: number | string; // Initial month to load.
|
||||
@Input() courseId: number | string;
|
||||
@Input() categoryId: number | string; // Category ID the course belongs to.
|
||||
@Input() canNavigate?: string | boolean; // Whether to include arrows to change the month. Defaults to true.
|
||||
|
||||
periodName: string;
|
||||
weekDays: any[];
|
||||
weeks: any[];
|
||||
loaded = false;
|
||||
|
||||
protected year: number;
|
||||
protected month: number;
|
||||
protected categoriesRetrieved = false;
|
||||
protected categories = {};
|
||||
|
||||
constructor(eventsProvider: CoreEventsProvider,
|
||||
sitesProvider: CoreSitesProvider,
|
||||
private calendarProvider: AddonCalendarProvider,
|
||||
private calendarHelper: AddonCalendarHelperProvider,
|
||||
private domUtils: CoreDomUtilsProvider,
|
||||
private timeUtils: CoreTimeUtilsProvider,
|
||||
private utils: CoreUtilsProvider,
|
||||
private coursesProvider: CoreCoursesProvider) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Component loaded.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
const now = new Date();
|
||||
|
||||
this.year = this.initialYear ? Number(this.initialYear) : now.getFullYear();
|
||||
this.month = this.initialYear ? Number(this.initialYear) : now.getMonth() + 1;
|
||||
this.canNavigate = typeof this.canNavigate == 'undefined' ? true : this.utils.isTrueOrOne(this.canNavigate);
|
||||
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect changes on input properties.
|
||||
*/
|
||||
ngOnChanges(changes: {[name: string]: SimpleChange}): void {
|
||||
|
||||
if ((changes.courseId || changes.categoryId) && this.weeks) {
|
||||
const courseId = this.courseId ? Number(this.courseId) : undefined,
|
||||
categoryId = this.categoryId ? Number(this.categoryId) : undefined;
|
||||
|
||||
this.filterEvents(courseId, categoryId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch contacts.
|
||||
*
|
||||
* @param {boolean} [refresh=false] True if we are refreshing contacts, false if we are loading more.
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
fetchData(refresh: boolean = false): Promise<any> {
|
||||
const courseId = this.courseId ? Number(this.courseId) : undefined,
|
||||
categoryId = this.categoryId ? Number(this.categoryId) : undefined,
|
||||
promises = [];
|
||||
|
||||
promises.push(this.loadCategories());
|
||||
|
||||
promises.push(this.calendarProvider.getMonthlyEvents(this.year, this.month, courseId, categoryId).then((result) => {
|
||||
|
||||
// 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).getTime(), 'core.strftimemonthyear');
|
||||
|
||||
this.weekDays = this.calendarProvider.getWeekDays(result.daynames[0].dayno);
|
||||
this.weeks = result.weeks;
|
||||
|
||||
this.filterEvents(courseId, categoryId);
|
||||
}));
|
||||
|
||||
return Promise.all(promises).catch((error) => {
|
||||
this.domUtils.showErrorModalDefault(error, 'addon.calendar.errorloadevents', true);
|
||||
}).finally(() => {
|
||||
this.loaded = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load categories to be able to filter events.
|
||||
*
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
protected loadCategories(): Promise<any> {
|
||||
if (this.categoriesRetrieved) {
|
||||
// Already retrieved, stop.
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return this.coursesProvider.getCategories(0, true).then((cats) => {
|
||||
this.categoriesRetrieved = true;
|
||||
this.categories = {};
|
||||
|
||||
// Index categories by ID.
|
||||
cats.forEach((category) => {
|
||||
this.categories[category.id] = category;
|
||||
});
|
||||
}).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter events to only display events belonging to a certain course.
|
||||
*
|
||||
* @param {number} courseId Course ID.
|
||||
* @param {number} categoryId Category the course belongs to.
|
||||
*/
|
||||
filterEvents(courseId: number, categoryId: number): void {
|
||||
|
||||
this.weeks.forEach((week) => {
|
||||
week.days.forEach((day) => {
|
||||
if (!courseId || courseId < 0) {
|
||||
day.filteredEvents = day.events;
|
||||
} else {
|
||||
day.filteredEvents = day.events.filter((event) => {
|
||||
return this.calendarHelper.shouldDisplayEvent(event, courseId, categoryId, this.categories);
|
||||
});
|
||||
}
|
||||
|
||||
// Re-calculate some properties.
|
||||
this.calendarHelper.calculateDayData(day, day.filteredEvents);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh events.
|
||||
*
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
refreshData(): Promise<any> {
|
||||
const promises = [];
|
||||
|
||||
promises.push(this.calendarProvider.invalidateMonthlyEvents(this.year, this.month));
|
||||
promises.push(this.coursesProvider.invalidateCategories(0, true));
|
||||
|
||||
this.categoriesRetrieved = false; // Get categories again.
|
||||
|
||||
return Promise.all(promises).then(() => {
|
||||
return this.fetchData(true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load next month.
|
||||
*/
|
||||
loadNext(): void {
|
||||
if (this.month === 12) {
|
||||
this.month = 1;
|
||||
this.year++;
|
||||
} else {
|
||||
this.month++;
|
||||
}
|
||||
|
||||
this.loaded = false;
|
||||
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load previous month.
|
||||
*/
|
||||
loadPrevious(): void {
|
||||
if (this.month === 1) {
|
||||
this.month = 12;
|
||||
this.year--;
|
||||
} else {
|
||||
this.month--;
|
||||
}
|
||||
|
||||
this.loaded = false;
|
||||
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Component destroyed.
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
// @todo
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// (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 { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { IonicModule } from 'ionic-angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreComponentsModule } from '@components/components.module';
|
||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||
import { AddonCalendarCalendarComponent } from '../components/calendar/calendar';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonCalendarCalendarComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
IonicModule,
|
||||
TranslateModule.forChild(),
|
||||
CoreComponentsModule,
|
||||
CoreDirectivesModule
|
||||
],
|
||||
providers: [
|
||||
],
|
||||
exports: [
|
||||
AddonCalendarCalendarComponent
|
||||
]
|
||||
})
|
||||
export class AddonCalendarComponentsModule {}
|
|
@ -22,9 +22,13 @@
|
|||
"eventname": "Event title",
|
||||
"eventstarttime": "Start time",
|
||||
"eventtype": "Event type",
|
||||
"fri": "Fri",
|
||||
"friday": "Friday",
|
||||
"gotoactivity": "Go to activity",
|
||||
"invalidtimedurationminutes": "The duration in minutes you have entered is invalid. Please enter the duration in minutes greater than 0 or select no duration.",
|
||||
"invalidtimedurationuntil": "The date and time you selected for duration until is before the start time of the event. Please correct this before proceeding.",
|
||||
"mon": "Mon",
|
||||
"monday": "Monday",
|
||||
"newevent": "New event",
|
||||
"noevents": "There are no events",
|
||||
"nopermissiontoupdatecalendar": "Sorry, but you do not have permission to update the calendar event",
|
||||
|
@ -34,7 +38,15 @@
|
|||
"repeateditthis": "Apply changes to this event only",
|
||||
"repeatevent": "Repeat this event",
|
||||
"repeatweeksl": "Repeat weekly, creating altogether",
|
||||
"sat": "Sat",
|
||||
"saturday": "Saturday",
|
||||
"setnewreminder": "Set a new reminder",
|
||||
"sun": "Sun",
|
||||
"sunday": "Sunday",
|
||||
"thu": "Thu",
|
||||
"thursday": "Thursday",
|
||||
"tue": "Tue",
|
||||
"tuesday": "Tuesday",
|
||||
"typeclose": "Close event",
|
||||
"typecourse": "Course event",
|
||||
"typecategory": "Category event",
|
||||
|
@ -43,5 +55,7 @@
|
|||
"typegroup": "Group event",
|
||||
"typeopen": "Open event",
|
||||
"typesite": "Site event",
|
||||
"typeuser": "User event"
|
||||
"typeuser": "User event",
|
||||
"wed": "Wed",
|
||||
"wednesday": "Wednesday"
|
||||
}
|
|
@ -15,9 +15,8 @@
|
|||
<ion-refresher [enabled]="loaded" (ionRefresh)="doRefresh($event)">
|
||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||
</ion-refresher>
|
||||
<core-loading [hideUntil]="loaded">
|
||||
|
||||
</core-loading>
|
||||
<addon-calendar-calendar [courseId]="courseId" [categoryId]="categoryId"></addon-calendar-calendar>
|
||||
|
||||
<!-- Create a calendar event. -->
|
||||
<ion-fab core-fab bottom end *ngIf="canCreate">
|
||||
|
|
|
@ -18,6 +18,7 @@ import { TranslateModule } from '@ngx-translate/core';
|
|||
import { CoreComponentsModule } from '@components/components.module';
|
||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||
import { CorePipesModule } from '@pipes/pipes.module';
|
||||
import { AddonCalendarComponentsModule } from '../../components/components.module';
|
||||
import { AddonCalendarIndexPage } from './index';
|
||||
|
||||
@NgModule({
|
||||
|
@ -28,6 +29,7 @@ import { AddonCalendarIndexPage } from './index';
|
|||
CoreComponentsModule,
|
||||
CoreDirectivesModule,
|
||||
CorePipesModule,
|
||||
AddonCalendarComponentsModule,
|
||||
IonicPageModule.forChild(AddonCalendarIndexPage),
|
||||
TranslateModule.forChild()
|
||||
],
|
||||
|
|
|
@ -8,12 +8,20 @@
|
|||
//
|
||||
// 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.
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OFx ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { IonicPage } from 'ionic-angular';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { IonicPage, NavParams, NavController, PopoverController } from 'ionic-angular';
|
||||
import { CoreLocalNotificationsProvider } from '@providers/local-notifications';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { AddonCalendarProvider } from '../../providers/calendar';
|
||||
import { AddonCalendarHelperProvider } from '../../providers/helper';
|
||||
import { AddonCalendarCalendarComponent } from '../../components/calendar/calendar';
|
||||
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
||||
import { CoreCoursePickerMenuPopoverComponent } from '@components/course-picker-menu/course-picker-menu-popover';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
/**
|
||||
* Page that displays the calendar events.
|
||||
|
@ -24,15 +32,154 @@ import { IonicPage } from 'ionic-angular';
|
|||
templateUrl: 'index.html',
|
||||
})
|
||||
export class AddonCalendarIndexPage implements OnInit {
|
||||
@ViewChild(AddonCalendarCalendarComponent) calendarComponent: AddonCalendarCalendarComponent;
|
||||
|
||||
constructor() {
|
||||
// @todo
|
||||
protected allCourses = {
|
||||
id: -1,
|
||||
fullname: this.translate.instant('core.fulllistofcourses'),
|
||||
category: -1
|
||||
};
|
||||
|
||||
courseId: number;
|
||||
categoryId: number;
|
||||
canCreate = false;
|
||||
courses: any[];
|
||||
notificationsEnabled = false;
|
||||
loaded = false;
|
||||
|
||||
constructor(localNotificationsProvider: CoreLocalNotificationsProvider,
|
||||
navParams: NavParams,
|
||||
private navCtrl: NavController,
|
||||
private domUtils: CoreDomUtilsProvider,
|
||||
private calendarProvider: AddonCalendarProvider,
|
||||
private calendarHelper: AddonCalendarHelperProvider,
|
||||
private translate: TranslateService,
|
||||
private coursesProvider: CoreCoursesProvider,
|
||||
private popoverCtrl: PopoverController) {
|
||||
|
||||
this.courseId = navParams.get('courseId');
|
||||
this.notificationsEnabled = localNotificationsProvider.isAvailable();
|
||||
}
|
||||
|
||||
/**
|
||||
* View loaded.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
// @todo
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all the data required for the view.
|
||||
*
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
fetchData(): Promise<any> {
|
||||
const promises = [];
|
||||
|
||||
// Load courses for the popover.
|
||||
promises.push(this.coursesProvider.getUserCourses(false).then((courses) => {
|
||||
// Add "All courses".
|
||||
courses.unshift(this.allCourses);
|
||||
this.courses = courses;
|
||||
|
||||
if (this.courseId) {
|
||||
// Search the course to get the category.
|
||||
const course = this.courses.find((course) => {
|
||||
return course.id == this.courseId;
|
||||
});
|
||||
|
||||
if (course) {
|
||||
this.categoryId = course.category;
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
// Check if user can create events.
|
||||
promises.push(this.calendarHelper.canEditEvents(this.courseId).then((canEdit) => {
|
||||
this.canCreate = canEdit;
|
||||
}));
|
||||
|
||||
return Promise.all(promises).catch((error) => {
|
||||
this.domUtils.showErrorModalDefault(error, 'addon.calendar.errorloadevents', true);
|
||||
}).finally(() => {
|
||||
this.loaded = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the data.
|
||||
*
|
||||
* @param {any} [refresher] Refresher.
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
doRefresh(refresher?: any): void {
|
||||
if (!this.loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
const promises = [];
|
||||
|
||||
promises.push(this.calendarProvider.invalidateAllowedEventTypes().then(() => {
|
||||
return this.fetchData();
|
||||
}));
|
||||
|
||||
// Refresh the sub-component.
|
||||
promises.push(this.calendarComponent.refreshData());
|
||||
|
||||
Promise.all(promises).finally(() => {
|
||||
refresher && refresher.complete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the context menu.
|
||||
*
|
||||
* @param {MouseEvent} event Event.
|
||||
*/
|
||||
openCourseFilter(event: MouseEvent): void {
|
||||
const popover = this.popoverCtrl.create(CoreCoursePickerMenuPopoverComponent, {
|
||||
courses: this.courses,
|
||||
courseId: this.courseId
|
||||
});
|
||||
|
||||
popover.onDidDismiss((course) => {
|
||||
if (course) {
|
||||
this.courseId = course.id > 0 ? course.id : undefined;
|
||||
this.categoryId = course.id > 0 ? course.category : undefined;
|
||||
|
||||
// Course viewed has changed, check if the user can create events for this course calendar.
|
||||
this.calendarHelper.canEditEvents(this.courseId).then((canEdit) => {
|
||||
this.canCreate = canEdit;
|
||||
});
|
||||
}
|
||||
});
|
||||
popover.present({
|
||||
ev: event
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Open page to create/edit an event.
|
||||
*
|
||||
* @param {number} [eventId] Event ID to edit.
|
||||
*/
|
||||
openEdit(eventId?: number): void {
|
||||
const params: any = {};
|
||||
|
||||
if (eventId) {
|
||||
params.eventId = eventId;
|
||||
}
|
||||
if (this.courseId) {
|
||||
params.courseId = this.courseId;
|
||||
}
|
||||
|
||||
this.navCtrl.push('AddonCalendarEditEventPage', params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open calendar events settings.
|
||||
*/
|
||||
openSettings(): void {
|
||||
this.navCtrl.push('AddonCalendarSettingsPage');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -423,50 +423,10 @@ export class AddonCalendarListPage implements OnDestroy {
|
|||
return this.events;
|
||||
}
|
||||
|
||||
return this.events.filter(this.shouldDisplayEvent.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an event should be displayed based on the filter.
|
||||
*
|
||||
* @param {any} event Event object.
|
||||
* @return {boolean} Whether it should be displayed.
|
||||
*/
|
||||
protected shouldDisplayEvent(event: any): boolean {
|
||||
if (event.eventtype == 'user' || event.eventtype == 'site') {
|
||||
// User or site event, display it.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.eventtype == 'category') {
|
||||
if (!event.categoryid || !Object.keys(this.categories).length) {
|
||||
// We can't tell if the course belongs to the category, display them all.
|
||||
return true;
|
||||
}
|
||||
if (event.categoryid == this.filter.course.category) {
|
||||
// The event is in the same category as the course, display it.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check parent categories.
|
||||
let category = this.categories[this.filter.course.category];
|
||||
while (category) {
|
||||
if (!category.parent) {
|
||||
// Category doesn't have parent, stop.
|
||||
break;
|
||||
}
|
||||
|
||||
if (event.categoryid == category.parent) {
|
||||
return true;
|
||||
}
|
||||
category = this.categories[category.parent];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Show the event if it is from site home or if it matches the selected course.
|
||||
return event.courseid === this.siteHomeId || event.courseid == this.filter.course.id;
|
||||
return this.events.filter((event) => {
|
||||
return this.calendarHelper.shouldDisplayEvent(event, this.filter.course.id, this.filter.course.category,
|
||||
this.categories);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -51,6 +51,37 @@ export class AddonCalendarProvider {
|
|||
static TYPE_USER = 'user';
|
||||
protected ROOT_CACHE_KEY = 'mmaCalendar:';
|
||||
|
||||
protected weekDays = [
|
||||
{
|
||||
shortname: 'addon.calendar.sun',
|
||||
fullname: 'addon.calendar.sunday'
|
||||
},
|
||||
{
|
||||
shortname: 'addon.calendar.mon',
|
||||
fullname: 'addon.calendar.monday'
|
||||
},
|
||||
{
|
||||
shortname: 'addon.calendar.tue',
|
||||
fullname: 'addon.calendar.tuesday'
|
||||
},
|
||||
{
|
||||
shortname: 'addon.calendar.wed',
|
||||
fullname: 'addon.calendar.wednesday'
|
||||
},
|
||||
{
|
||||
shortname: 'addon.calendar.thu',
|
||||
fullname: 'addon.calendar.thursday'
|
||||
},
|
||||
{
|
||||
shortname: 'addon.calendar.fri',
|
||||
fullname: 'addon.calendar.friday'
|
||||
},
|
||||
{
|
||||
shortname: 'addon.calendar.sat',
|
||||
fullname: 'addon.calendar.saturday'
|
||||
}
|
||||
];
|
||||
|
||||
// Variables for database.
|
||||
static EVENTS_TABLE = 'addon_calendar_events_2';
|
||||
static REMINDERS_TABLE = 'addon_calendar_reminders';
|
||||
|
@ -875,6 +906,18 @@ export class AddonCalendarProvider {
|
|||
return this.getUpcomingEventsPrefixCacheKey() + (courseId ? courseId : '') + ':' + (categoryId ? categoryId : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the week days, already ordered according to a specified starting day.
|
||||
*
|
||||
* @param {number} [startingDay=0] Starting day. 0=Sunday, 1=Monday, ...
|
||||
* @return {any[]} Week days.
|
||||
*/
|
||||
getWeekDays(startingDay?: number): any[] {
|
||||
startingDay = startingDay || 0;
|
||||
|
||||
return this.weekDays.slice(startingDay).concat(this.weekDays.slice(0, startingDay));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates access information.
|
||||
*
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
import { AddonCalendarProvider } from './calendar';
|
||||
import { CoreConstants } from '@core/constants';
|
||||
|
@ -33,11 +34,35 @@ export class AddonCalendarHelperProvider {
|
|||
category: 'fa-cubes'
|
||||
};
|
||||
|
||||
constructor(logger: CoreLoggerProvider, private courseProvider: CoreCourseProvider,
|
||||
constructor(logger: CoreLoggerProvider,
|
||||
private courseProvider: CoreCourseProvider,
|
||||
private sitesProvider: CoreSitesProvider,
|
||||
private calendarProvider: AddonCalendarProvider) {
|
||||
this.logger = logger.getInstance('AddonCalendarHelperProvider');
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate some day data based on a list of events for that day.
|
||||
*
|
||||
* @param {any} day Day.
|
||||
* @param {any[]} events Events.
|
||||
*/
|
||||
calculateDayData(day: any, events: any[]): void {
|
||||
day.hasevents = events.length > 0;
|
||||
day.haslastdayofevent = false;
|
||||
|
||||
const types = {};
|
||||
events.forEach((event) => {
|
||||
types[event.eventtype] = true;
|
||||
|
||||
if (event.islastday) {
|
||||
day.haslastdayofevent = true;
|
||||
}
|
||||
});
|
||||
|
||||
day.calendareventtypes = Object.keys(types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current user can create/edit events.
|
||||
*
|
||||
|
@ -155,4 +180,51 @@ export class AddonCalendarHelperProvider {
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an event should be displayed based on the filter.
|
||||
*
|
||||
* @param {any} event Event object.
|
||||
* @param {number} courseId Course ID to filter.
|
||||
* @param {number} categoryId Category ID the course belongs to.
|
||||
* @param {any} categories Categories indexed by ID.
|
||||
* @return {boolean} Whether it should be displayed.
|
||||
*/
|
||||
shouldDisplayEvent(event: any, courseId: number, categoryId: number, categories: any): boolean {
|
||||
if (event.eventtype == 'user' || event.eventtype == 'site') {
|
||||
// User or site event, display it.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.eventtype == 'category') {
|
||||
if (!event.categoryid || !Object.keys(categories).length) {
|
||||
// We can't tell if the course belongs to the category, display them all.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.categoryid == categoryId) {
|
||||
// The event is in the same category as the course, display it.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check parent categories.
|
||||
let category = categories[categoryId];
|
||||
while (category) {
|
||||
if (!category.parent) {
|
||||
// Category doesn't have parent, stop.
|
||||
break;
|
||||
}
|
||||
|
||||
if (event.categoryid == category.parent) {
|
||||
return true;
|
||||
}
|
||||
category = categories[category.parent];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Show the event if it is from site home or if it matches the selected course.
|
||||
return event.courseid === this.sitesProvider.getSiteHomeId() || event.courseid == courseId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,9 +106,13 @@
|
|||
"addon.calendar.eventname": "Event title",
|
||||
"addon.calendar.eventstarttime": "Start time",
|
||||
"addon.calendar.eventtype": "Event type",
|
||||
"addon.calendar.fri": "Fri",
|
||||
"addon.calendar.friday": "Friday",
|
||||
"addon.calendar.gotoactivity": "Go to activity",
|
||||
"addon.calendar.invalidtimedurationminutes": "The duration in minutes you have entered is invalid. Please enter the duration in minutes greater than 0 or select no duration.",
|
||||
"addon.calendar.invalidtimedurationuntil": "The date and time you selected for duration until is before the start time of the event. Please correct this before proceeding.",
|
||||
"addon.calendar.mon": "Mon",
|
||||
"addon.calendar.monday": "Monday",
|
||||
"addon.calendar.newevent": "New event",
|
||||
"addon.calendar.noevents": "There are no events",
|
||||
"addon.calendar.nopermissiontoupdatecalendar": "Sorry, but you do not have permission to update the calendar event",
|
||||
|
@ -118,7 +122,15 @@
|
|||
"addon.calendar.repeateditthis": "Apply changes to this event only",
|
||||
"addon.calendar.repeatevent": "Repeat this event",
|
||||
"addon.calendar.repeatweeksl": "Repeat weekly, creating altogether",
|
||||
"addon.calendar.sat": "Sat",
|
||||
"addon.calendar.saturday": "Saturday",
|
||||
"addon.calendar.setnewreminder": "Set a new reminder",
|
||||
"addon.calendar.sun": "Sun",
|
||||
"addon.calendar.sunday": "Sunday",
|
||||
"addon.calendar.thu": "Thu",
|
||||
"addon.calendar.thursday": "Thursday",
|
||||
"addon.calendar.tue": "Tue",
|
||||
"addon.calendar.tuesday": "Tuesday",
|
||||
"addon.calendar.typecategory": "Category event",
|
||||
"addon.calendar.typeclose": "Close event",
|
||||
"addon.calendar.typecourse": "Course event",
|
||||
|
@ -128,6 +140,8 @@
|
|||
"addon.calendar.typeopen": "Open event",
|
||||
"addon.calendar.typesite": "Site event",
|
||||
"addon.calendar.typeuser": "User event",
|
||||
"addon.calendar.wed": "Wed",
|
||||
"addon.calendar.wednesday": "Wednesday",
|
||||
"addon.competency.activities": "Activities",
|
||||
"addon.competency.competencies": "Competencies",
|
||||
"addon.competency.competenciesmostoftennotproficientincourse": "Competencies most often not proficient in this course",
|
||||
|
@ -1658,6 +1672,7 @@
|
|||
"core.notingroup": "Sorry, but you need to be part of a group to see this page.",
|
||||
"core.notsent": "Not sent",
|
||||
"core.now": "now",
|
||||
"core.nummore": "{{$a}} more",
|
||||
"core.numwords": "{{$a}} words",
|
||||
"core.offline": "Offline",
|
||||
"core.ok": "OK",
|
||||
|
|
|
@ -184,6 +184,7 @@
|
|||
"notingroup": "Sorry, but you need to be part of a group to see this page.",
|
||||
"notsent": "Not sent",
|
||||
"now": "now",
|
||||
"nummore": "{{$a}} more",
|
||||
"numwords": "{{$a}} words",
|
||||
"offline": "Offline",
|
||||
"ok": "OK",
|
||||
|
|
|
@ -28,6 +28,7 @@ $green: #5e8100; // Accent.
|
|||
$red: #cb3d4d;
|
||||
$orange: #f98012; // Accent (never text).
|
||||
$yellow: #fbad1a; // Accent (never text).
|
||||
$purple: #8e24aa; // Accent (never text).
|
||||
$core-color: $orange;
|
||||
|
||||
// Branded apps customization
|
||||
|
|
Loading…
Reference in New Issue