forked from EVOgeek/Vmeda.Online
MOBILE-3021 calendar: Support monthly view
parent
fa837532d4
commit
661709acb4
|
@ -106,9 +106,13 @@
|
||||||
"addon.calendar.eventname": "calendar",
|
"addon.calendar.eventname": "calendar",
|
||||||
"addon.calendar.eventstarttime": "calendar",
|
"addon.calendar.eventstarttime": "calendar",
|
||||||
"addon.calendar.eventtype": "calendar",
|
"addon.calendar.eventtype": "calendar",
|
||||||
|
"addon.calendar.fri": "calendar",
|
||||||
|
"addon.calendar.friday": "calendar",
|
||||||
"addon.calendar.gotoactivity": "calendar",
|
"addon.calendar.gotoactivity": "calendar",
|
||||||
"addon.calendar.invalidtimedurationminutes": "calendar",
|
"addon.calendar.invalidtimedurationminutes": "calendar",
|
||||||
"addon.calendar.invalidtimedurationuntil": "calendar",
|
"addon.calendar.invalidtimedurationuntil": "calendar",
|
||||||
|
"addon.calendar.mon": "calendar",
|
||||||
|
"addon.calendar.monday": "calendar",
|
||||||
"addon.calendar.newevent": "calendar",
|
"addon.calendar.newevent": "calendar",
|
||||||
"addon.calendar.noevents": "local_moodlemobileapp",
|
"addon.calendar.noevents": "local_moodlemobileapp",
|
||||||
"addon.calendar.nopermissiontoupdatecalendar": "error",
|
"addon.calendar.nopermissiontoupdatecalendar": "error",
|
||||||
|
@ -118,7 +122,15 @@
|
||||||
"addon.calendar.repeateditthis": "calendar",
|
"addon.calendar.repeateditthis": "calendar",
|
||||||
"addon.calendar.repeatevent": "calendar",
|
"addon.calendar.repeatevent": "calendar",
|
||||||
"addon.calendar.repeatweeksl": "calendar",
|
"addon.calendar.repeatweeksl": "calendar",
|
||||||
|
"addon.calendar.sat": "calendar",
|
||||||
|
"addon.calendar.saturday": "calendar",
|
||||||
"addon.calendar.setnewreminder": "local_moodlemobileapp",
|
"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.typecategory": "calendar",
|
||||||
"addon.calendar.typeclose": "calendar",
|
"addon.calendar.typeclose": "calendar",
|
||||||
"addon.calendar.typecourse": "calendar",
|
"addon.calendar.typecourse": "calendar",
|
||||||
|
@ -128,6 +140,8 @@
|
||||||
"addon.calendar.typeopen": "calendar",
|
"addon.calendar.typeopen": "calendar",
|
||||||
"addon.calendar.typesite": "calendar",
|
"addon.calendar.typesite": "calendar",
|
||||||
"addon.calendar.typeuser": "calendar",
|
"addon.calendar.typeuser": "calendar",
|
||||||
|
"addon.calendar.wed": "calendar",
|
||||||
|
"addon.calendar.wednesday": "calendar",
|
||||||
"addon.competency.activities": "tool_lp",
|
"addon.competency.activities": "tool_lp",
|
||||||
"addon.competency.competencies": "competency",
|
"addon.competency.competencies": "competency",
|
||||||
"addon.competency.competenciesmostoftennotproficientincourse": "tool_lp",
|
"addon.competency.competenciesmostoftennotproficientincourse": "tool_lp",
|
||||||
|
@ -1657,6 +1671,7 @@
|
||||||
"core.notingroup": "moodle",
|
"core.notingroup": "moodle",
|
||||||
"core.notsent": "local_moodlemobileapp",
|
"core.notsent": "local_moodlemobileapp",
|
||||||
"core.now": "moodle",
|
"core.now": "moodle",
|
||||||
|
"core.nummore": "local_moodlemobileapp",
|
||||||
"core.numwords": "moodle",
|
"core.numwords": "moodle",
|
||||||
"core.offline": "message",
|
"core.offline": "message",
|
||||||
"core.ok": "moodle",
|
"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",
|
"eventname": "Event title",
|
||||||
"eventstarttime": "Start time",
|
"eventstarttime": "Start time",
|
||||||
"eventtype": "Event type",
|
"eventtype": "Event type",
|
||||||
|
"fri": "Fri",
|
||||||
|
"friday": "Friday",
|
||||||
"gotoactivity": "Go to activity",
|
"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.",
|
"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.",
|
"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",
|
"newevent": "New event",
|
||||||
"noevents": "There are no events",
|
"noevents": "There are no events",
|
||||||
"nopermissiontoupdatecalendar": "Sorry, but you do not have permission to update the calendar event",
|
"nopermissiontoupdatecalendar": "Sorry, but you do not have permission to update the calendar event",
|
||||||
|
@ -34,7 +38,15 @@
|
||||||
"repeateditthis": "Apply changes to this event only",
|
"repeateditthis": "Apply changes to this event only",
|
||||||
"repeatevent": "Repeat this event",
|
"repeatevent": "Repeat this event",
|
||||||
"repeatweeksl": "Repeat weekly, creating altogether",
|
"repeatweeksl": "Repeat weekly, creating altogether",
|
||||||
|
"sat": "Sat",
|
||||||
|
"saturday": "Saturday",
|
||||||
"setnewreminder": "Set a new reminder",
|
"setnewreminder": "Set a new reminder",
|
||||||
|
"sun": "Sun",
|
||||||
|
"sunday": "Sunday",
|
||||||
|
"thu": "Thu",
|
||||||
|
"thursday": "Thursday",
|
||||||
|
"tue": "Tue",
|
||||||
|
"tuesday": "Tuesday",
|
||||||
"typeclose": "Close event",
|
"typeclose": "Close event",
|
||||||
"typecourse": "Course event",
|
"typecourse": "Course event",
|
||||||
"typecategory": "Category event",
|
"typecategory": "Category event",
|
||||||
|
@ -43,5 +55,7 @@
|
||||||
"typegroup": "Group event",
|
"typegroup": "Group event",
|
||||||
"typeopen": "Open event",
|
"typeopen": "Open event",
|
||||||
"typesite": "Site 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 [enabled]="loaded" (ionRefresh)="doRefresh($event)">
|
||||||
<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]="loaded">
|
|
||||||
|
|
||||||
</core-loading>
|
<addon-calendar-calendar [courseId]="courseId" [categoryId]="categoryId"></addon-calendar-calendar>
|
||||||
|
|
||||||
<!-- Create a calendar event. -->
|
<!-- Create a calendar event. -->
|
||||||
<ion-fab core-fab bottom end *ngIf="canCreate">
|
<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 { CoreComponentsModule } from '@components/components.module';
|
||||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||||
import { CorePipesModule } from '@pipes/pipes.module';
|
import { CorePipesModule } from '@pipes/pipes.module';
|
||||||
|
import { AddonCalendarComponentsModule } from '../../components/components.module';
|
||||||
import { AddonCalendarIndexPage } from './index';
|
import { AddonCalendarIndexPage } from './index';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -28,6 +29,7 @@ import { AddonCalendarIndexPage } from './index';
|
||||||
CoreComponentsModule,
|
CoreComponentsModule,
|
||||||
CoreDirectivesModule,
|
CoreDirectivesModule,
|
||||||
CorePipesModule,
|
CorePipesModule,
|
||||||
|
AddonCalendarComponentsModule,
|
||||||
IonicPageModule.forChild(AddonCalendarIndexPage),
|
IonicPageModule.forChild(AddonCalendarIndexPage),
|
||||||
TranslateModule.forChild()
|
TranslateModule.forChild()
|
||||||
],
|
],
|
||||||
|
|
|
@ -8,12 +8,20 @@
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
// 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
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
import { IonicPage } from 'ionic-angular';
|
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.
|
* Page that displays the calendar events.
|
||||||
|
@ -24,15 +32,154 @@ import { IonicPage } from 'ionic-angular';
|
||||||
templateUrl: 'index.html',
|
templateUrl: 'index.html',
|
||||||
})
|
})
|
||||||
export class AddonCalendarIndexPage implements OnInit {
|
export class AddonCalendarIndexPage implements OnInit {
|
||||||
|
@ViewChild(AddonCalendarCalendarComponent) calendarComponent: AddonCalendarCalendarComponent;
|
||||||
|
|
||||||
constructor() {
|
protected allCourses = {
|
||||||
// @todo
|
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.
|
* View loaded.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.events.filter(this.shouldDisplayEvent.bind(this));
|
return this.events.filter((event) => {
|
||||||
}
|
return this.calendarHelper.shouldDisplayEvent(event, this.filter.course.id, this.filter.course.category,
|
||||||
|
this.categories);
|
||||||
/**
|
});
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -51,6 +51,37 @@ export class AddonCalendarProvider {
|
||||||
static TYPE_USER = 'user';
|
static TYPE_USER = 'user';
|
||||||
protected ROOT_CACHE_KEY = 'mmaCalendar:';
|
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.
|
// Variables for database.
|
||||||
static EVENTS_TABLE = 'addon_calendar_events_2';
|
static EVENTS_TABLE = 'addon_calendar_events_2';
|
||||||
static REMINDERS_TABLE = 'addon_calendar_reminders';
|
static REMINDERS_TABLE = 'addon_calendar_reminders';
|
||||||
|
@ -875,6 +906,18 @@ export class AddonCalendarProvider {
|
||||||
return this.getUpcomingEventsPrefixCacheKey() + (courseId ? courseId : '') + ':' + (categoryId ? categoryId : '');
|
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.
|
* Invalidates access information.
|
||||||
*
|
*
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { CoreLoggerProvider } from '@providers/logger';
|
import { CoreLoggerProvider } from '@providers/logger';
|
||||||
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
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';
|
import { CoreConstants } from '@core/constants';
|
||||||
|
@ -33,11 +34,35 @@ export class AddonCalendarHelperProvider {
|
||||||
category: 'fa-cubes'
|
category: 'fa-cubes'
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(logger: CoreLoggerProvider, private courseProvider: CoreCourseProvider,
|
constructor(logger: CoreLoggerProvider,
|
||||||
|
private courseProvider: CoreCourseProvider,
|
||||||
|
private sitesProvider: CoreSitesProvider,
|
||||||
private calendarProvider: AddonCalendarProvider) {
|
private calendarProvider: AddonCalendarProvider) {
|
||||||
this.logger = logger.getInstance('AddonCalendarHelperProvider');
|
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.
|
* Check if current user can create/edit events.
|
||||||
*
|
*
|
||||||
|
@ -155,4 +180,51 @@ export class AddonCalendarHelperProvider {
|
||||||
|
|
||||||
return false;
|
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.eventname": "Event title",
|
||||||
"addon.calendar.eventstarttime": "Start time",
|
"addon.calendar.eventstarttime": "Start time",
|
||||||
"addon.calendar.eventtype": "Event type",
|
"addon.calendar.eventtype": "Event type",
|
||||||
|
"addon.calendar.fri": "Fri",
|
||||||
|
"addon.calendar.friday": "Friday",
|
||||||
"addon.calendar.gotoactivity": "Go to activity",
|
"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.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.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.newevent": "New event",
|
||||||
"addon.calendar.noevents": "There are no events",
|
"addon.calendar.noevents": "There are no events",
|
||||||
"addon.calendar.nopermissiontoupdatecalendar": "Sorry, but you do not have permission to update the calendar event",
|
"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.repeateditthis": "Apply changes to this event only",
|
||||||
"addon.calendar.repeatevent": "Repeat this event",
|
"addon.calendar.repeatevent": "Repeat this event",
|
||||||
"addon.calendar.repeatweeksl": "Repeat weekly, creating altogether",
|
"addon.calendar.repeatweeksl": "Repeat weekly, creating altogether",
|
||||||
|
"addon.calendar.sat": "Sat",
|
||||||
|
"addon.calendar.saturday": "Saturday",
|
||||||
"addon.calendar.setnewreminder": "Set a new reminder",
|
"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.typecategory": "Category event",
|
||||||
"addon.calendar.typeclose": "Close event",
|
"addon.calendar.typeclose": "Close event",
|
||||||
"addon.calendar.typecourse": "Course event",
|
"addon.calendar.typecourse": "Course event",
|
||||||
|
@ -128,6 +140,8 @@
|
||||||
"addon.calendar.typeopen": "Open event",
|
"addon.calendar.typeopen": "Open event",
|
||||||
"addon.calendar.typesite": "Site event",
|
"addon.calendar.typesite": "Site event",
|
||||||
"addon.calendar.typeuser": "User event",
|
"addon.calendar.typeuser": "User event",
|
||||||
|
"addon.calendar.wed": "Wed",
|
||||||
|
"addon.calendar.wednesday": "Wednesday",
|
||||||
"addon.competency.activities": "Activities",
|
"addon.competency.activities": "Activities",
|
||||||
"addon.competency.competencies": "Competencies",
|
"addon.competency.competencies": "Competencies",
|
||||||
"addon.competency.competenciesmostoftennotproficientincourse": "Competencies most often not proficient in this course",
|
"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.notingroup": "Sorry, but you need to be part of a group to see this page.",
|
||||||
"core.notsent": "Not sent",
|
"core.notsent": "Not sent",
|
||||||
"core.now": "now",
|
"core.now": "now",
|
||||||
|
"core.nummore": "{{$a}} more",
|
||||||
"core.numwords": "{{$a}} words",
|
"core.numwords": "{{$a}} words",
|
||||||
"core.offline": "Offline",
|
"core.offline": "Offline",
|
||||||
"core.ok": "OK",
|
"core.ok": "OK",
|
||||||
|
|
|
@ -184,6 +184,7 @@
|
||||||
"notingroup": "Sorry, but you need to be part of a group to see this page.",
|
"notingroup": "Sorry, but you need to be part of a group to see this page.",
|
||||||
"notsent": "Not sent",
|
"notsent": "Not sent",
|
||||||
"now": "now",
|
"now": "now",
|
||||||
|
"nummore": "{{$a}} more",
|
||||||
"numwords": "{{$a}} words",
|
"numwords": "{{$a}} words",
|
||||||
"offline": "Offline",
|
"offline": "Offline",
|
||||||
"ok": "OK",
|
"ok": "OK",
|
||||||
|
|
|
@ -28,6 +28,7 @@ $green: #5e8100; // Accent.
|
||||||
$red: #cb3d4d;
|
$red: #cb3d4d;
|
||||||
$orange: #f98012; // Accent (never text).
|
$orange: #f98012; // Accent (never text).
|
||||||
$yellow: #fbad1a; // Accent (never text).
|
$yellow: #fbad1a; // Accent (never text).
|
||||||
|
$purple: #8e24aa; // Accent (never text).
|
||||||
$core-color: $orange;
|
$core-color: $orange;
|
||||||
|
|
||||||
// Branded apps customization
|
// Branded apps customization
|
||||||
|
|
Loading…
Reference in New Issue