MOBILE-2317 core: Fix tslint warnings

main
Dani Palou 2018-01-29 10:05:20 +01:00
parent 76eed98cb5
commit 01ddf7019c
204 changed files with 4243 additions and 3872 deletions

View File

@ -6,7 +6,21 @@ var gulp = require('gulp'),
slash = require('gulp-slash'),
clipEmptyFiles = require('gulp-clip-empty-files'),
gutil = require('gulp-util'),
File = gutil.File;
File = gutil.File,
license = '' +
'// (C) Copyright 2015 Martin Dougiamas\n' +
'//\n' +
'// Licensed under the Apache License, Version 2.0 (the "License");\n' +
'// you may not use this file except in compliance with the License.\n' +
'// You may obtain a copy of the License at\n' +
'//\n' +
'// http://www.apache.org/licenses/LICENSE-2.0\n' +
'//\n' +
'// Unless required by applicable law or agreed to in writing, software\n' +
'// distributed under the License is distributed on an "AS IS" BASIS,\n' +
'// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n' +
'// See the License for the specific language governing permissions and\n' +
'// limitations under the License.\n\n';
// Get the names of the JSON files inside a directory.
function getFilenames(dir) {
@ -211,15 +225,40 @@ gulp.task('config', function(done) {
gulp.src(paths.config)
.pipe(through(function(file) {
// Convert the contents of the file into a TypeScript class.
// Disable the rule variable-name in the file.
var config = JSON.parse(file.contents.toString()),
contents = 'export class CoreConfigConstants {\n';
contents = license + '// tslint:disable: variable-name\n' + 'export class CoreConfigConstants {\n';
for (var key in config) {
var value = config[key];
if (typeof value != 'number' && typeof value != 'boolean') {
value = JSON.stringify(value);
if (typeof value == 'string') {
// Wrap the string in ' .
value = "'" + value + "'";
} else if (typeof value != 'number' && typeof value != 'boolean') {
// Stringify with 4 spaces of indentation, and then add 4 more spaces in each line.
value = JSON.stringify(value, null, 4).replace(/^(?: )/gm, ' ').replace(/^(?:})/gm, ' }');
// Replace " by ' in values.
value = value.replace(/: "([^"]*)"/g, ": '$1'");
// Check if the keys have "-" in it.
var matches = value.match(/"([^"]*\-[^"]*)":/g);
if (matches) {
// Replace " by ' in keys. We cannot remove them because keys have chars like '-'.
value = value.replace(/"([^"]*)":/g, "'$1':");
} else {
// Remove ' in keys.
value = value.replace(/"([^"]*)":/g, "$1:");
}
contents += ' public static ' + key + ' = ' + value + ';\n';
// Add type any to the key.
key = key + ': any';
}
// If key has quotation marks, remove them.
if (key[0] == '"') {
key = key.substr(1, key.length - 2);
}
contents += ' static ' + key + ' = ' + value + ';\n';
}
contents += '}\n';

View File

@ -42,7 +42,6 @@ export class AddonCalendarModule {
calendarProvider.scheduleAllSitesEventsNotifications();
});
localNotificationsProvider.registerClick(AddonCalendarProvider.COMPONENT, (data) => {
if (data.eventid) {
initDelegate.ready().then(() => {

View File

@ -27,7 +27,7 @@ import * as moment from 'moment';
/**
* Page that displays a single calendar event.
*/
@IonicPage({segment: "addon-calendar-event"})
@IonicPage({ segment: 'addon-calendar-event' })
@Component({
selector: 'page-addon-calendar-event',
templateUrl: 'event.html',
@ -72,13 +72,13 @@ export class AddonCalendarEventPage {
/**
* View loaded.
*/
ionViewDidLoad() {
ionViewDidLoad(): void {
this.fetchEvent().finally(() => {
this.eventLoaded = true;
});
}
updateNotificationTime() {
updateNotificationTime(): void {
if (!isNaN(this.notificationTime) && this.event && this.event.id) {
this.calendarProvider.updateNotificationTime(this.event, this.notificationTime);
}
@ -86,8 +86,10 @@ export class AddonCalendarEventPage {
/**
* Fetches the event and updates the view.
*
* @return {Promise<any>} Promise resolved when done.
*/
fetchEvent() {
fetchEvent(): Promise<any> {
return this.calendarProvider.getEvent(this.eventId).then((event) => {
this.calendarHelper.formatEventData(event);
this.event = event;
@ -96,7 +98,7 @@ export class AddonCalendarEventPage {
let title = this.translate.instant('addon.calendar.type' + event.eventtype);
if (event.moduleIcon) {
// It's a module event, translate the module name to the current language.
let name = this.courseProvider.translateModuleName(event.modulename);
const name = this.courseProvider.translateModuleName(event.modulename);
if (name.indexOf('core.mod_') === -1) {
event.moduleName = name;
}
@ -130,7 +132,7 @@ export class AddonCalendarEventPage {
*
* @param {any} refresher Refresher.
*/
refreshEvent(refresher: any) {
refreshEvent(refresher: any): void {
this.calendarProvider.invalidateEvent(this.eventId).finally(() => {
this.fetchEvent().finally(() => {
refresher.complete();

View File

@ -30,7 +30,7 @@ import { CoreSplitViewComponent } from '../../../../components/split-view/split-
/**
* Page that displays the list of calendar events.
*/
@IonicPage({segment: "addon-calendar-list"})
@IonicPage({ segment: 'addon-calendar-list' })
@Component({
selector: 'page-addon-calendar-list',
templateUrl: 'list.html',
@ -84,7 +84,7 @@ export class AddonCalendarListPage implements OnDestroy {
/**
* View loaded.
*/
ionViewDidLoad() {
ionViewDidLoad(): void {
if (this.eventId) {
// There is an event to load, open the event in a new state.
this.gotoEvent(this.eventId);
@ -104,8 +104,9 @@ export class AddonCalendarListPage implements OnDestroy {
* Fetch all the data required for the view.
*
* @param {boolean} [refresh] Empty events array first.
* @return {Promise<any>} Promise resolved when done.
*/
fetchData(refresh = false) {
fetchData(refresh: boolean = false): Promise<any> {
this.daysLoaded = 0;
this.emptyEventsTimes = 0;
@ -114,6 +115,7 @@ export class AddonCalendarListPage implements OnDestroy {
// Add "All courses".
courses.unshift(this.allCourses);
this.courses = courses;
return this.fetchEvents(refresh);
});
}
@ -122,8 +124,9 @@ export class AddonCalendarListPage implements OnDestroy {
* Fetches the events and updates the view.
*
* @param {boolean} [refresh] Empty events array first.
* @return {Promise<any>} Promise resolved when done.
*/
fetchEvents(refresh = false) {
fetchEvents(refresh: boolean = false): Promise<any> {
return this.calendarProvider.getEventsList(this.daysLoaded, AddonCalendarProvider.DAYS_INTERVAL).then((events) => {
this.daysLoaded += AddonCalendarProvider.DAYS_INTERVAL;
if (events.length === 0) {
@ -170,6 +173,7 @@ export class AddonCalendarListPage implements OnDestroy {
// Success retrieving events. Get categories if needed.
if (this.getCategories) {
this.getCategories = false;
return this.loadCategories();
}
});
@ -177,8 +181,10 @@ export class AddonCalendarListPage implements OnDestroy {
/**
* Get filtered events.
*
* @return {any[]} Filtered events.
*/
protected getFilteredEvents() {
protected getFilteredEvents(): any[] {
if (this.filter.course.id == -1) {
// No filter, display everything.
return this.events;
@ -191,8 +197,9 @@ export class AddonCalendarListPage implements OnDestroy {
* 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) {
protected shouldDisplayEvent(event: any): boolean {
if (event.eventtype == 'user' || event.eventtype == 'site') {
// User or site event, display it.
return true;
@ -241,14 +248,17 @@ export class AddonCalendarListPage implements OnDestroy {
}
// Categories not loaded yet. We should get them if there's any category event.
let found = events.some(event => event.categoryid != 'undefined' && event.categoryid > 0);
const found = events.some((event) => event.categoryid != 'undefined' && event.categoryid > 0);
return found || this.getCategories;
}
/**
* Load categories to be able to filter events.
*
* @return {Promise<any>} Promise resolved when done.
*/
protected loadCategories() {
protected loadCategories(): Promise<any> {
return this.coursesProvider.getCategories(0, true).then((cats) => {
this.categoriesRetrieved = true;
this.categories = {};
@ -266,8 +276,8 @@ export class AddonCalendarListPage implements OnDestroy {
*
* @param {any} refresher Refresher.
*/
refreshEvents(refresher: any) {
let promises = [];
refreshEvents(refresher: any): void {
const promises = [];
promises.push(this.calendarProvider.invalidateEventsList(this.courses));
@ -289,8 +299,10 @@ export class AddonCalendarListPage implements OnDestroy {
* @param {MouseEvent} event Event.
*/
openCourseFilter(event: MouseEvent): void {
let popover = this.popoverCtrl.create(CoreCoursePickerMenuPopoverComponent, {courses: this.courses,
courseId: this.filter.course.id});
const popover = this.popoverCtrl.create(CoreCoursePickerMenuPopoverComponent, {
courses: this.courses,
courseId: this.filter.course.id
});
popover.onDidDismiss((course) => {
if (course) {
this.filter.course = course;
@ -306,14 +318,16 @@ export class AddonCalendarListPage implements OnDestroy {
/**
* Open calendar events settings.
*/
openSettings() {
openSettings(): void {
this.navCtrl.push('AddonCalendarSettingsPage');
}
/**
* Navigate to a particular event.
*
* @param {number} eventId Event to load.
*/
gotoEvent(eventId) {
gotoEvent(eventId: number): void {
this.eventId = eventId;
this.splitviewCtrl.push('AddonCalendarEventPage', { id: eventId });
}
@ -321,7 +335,7 @@ export class AddonCalendarListPage implements OnDestroy {
/**
* Page destroyed.
*/
ngOnDestroy() {
ngOnDestroy(): void {
this.obsDefaultTimeChange && this.obsDefaultTimeChange.off();
}
}

View File

@ -21,7 +21,7 @@ import { CoreSitesProvider } from '../../../../providers/sites';
/**
* Page that displays the calendar settings.
*/
@IonicPage({segment: "addon-calendar-settings"})
@IonicPage({ segment: 'addon-calendar-settings' })
@Component({
selector: 'page-addon-calendar-settings',
templateUrl: 'settings.html',
@ -36,15 +36,20 @@ export class AddonCalendarSettingsPage {
/**
* View loaded.
*/
ionViewDidLoad() {
ionViewDidLoad(): void {
this.calendarProvider.getDefaultNotificationTime().then((time) => {
this.defaultTime = time;
});
}
updateDefaultTime(newTime) {
/**
* Update default time.
*
* @param {number} newTime New time.
*/
updateDefaultTime(newTime: number): void {
this.calendarProvider.setDefaultNotificationTime(newTime);
this.eventsProvider.trigger(AddonCalendarProvider.DEFAULT_NOTIFICATION_TIME_CHANGED, { time: newTime },
this.sitesProvider.getCurrentSiteId());
};
}
}

View File

@ -28,9 +28,9 @@ import { CoreConfigProvider } from '../../../providers/config';
*/
@Injectable()
export class AddonCalendarProvider {
public static DAYS_INTERVAL = 30;
public static COMPONENT = 'AddonCalendarEvents';
public static DEFAULT_NOTIFICATION_TIME_CHANGED = 'AddonCalendarDefaultNotificationTimeChangedEvent';
static DAYS_INTERVAL = 30;
static COMPONENT = 'AddonCalendarEvents';
static DEFAULT_NOTIFICATION_TIME_CHANGED = 'AddonCalendarDefaultNotificationTimeChangedEvent';
protected DEFAULT_NOTIFICATION_TIME_SETTING = 'mmaCalendarDefaultNotifTime';
protected ROOT_CACHE_KEY = 'mmaCalendar:';
protected DEFAULT_NOTIFICATION_TIME = 60;
@ -121,7 +121,8 @@ export class AddonCalendarProvider {
getDefaultNotificationTime(siteId?: string): Promise<number> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
let key = this.DEFAULT_NOTIFICATION_TIME_SETTING + '#' + siteId;
const key = this.DEFAULT_NOTIFICATION_TIME_SETTING + '#' + siteId;
return this.configProvider.get(key, this.DEFAULT_NOTIFICATION_TIME);
}
@ -135,17 +136,25 @@ export class AddonCalendarProvider {
*/
getEvent(id: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
let presets = {
const preSets = {
cacheKey: this.getEventCacheKey(id)
},
data = {
"options[userevents]": 0,
"options[siteevents]": 0,
"events[eventids][0]": id
options: {
userevents: 0,
siteevents: 0,
},
events: {
eventids: [
id
]
}
};
return site.read('core_calendar_get_calendar_events', data, presets).then((response) => {
return site.read('core_calendar_get_calendar_events', data, preSets).then((response) => {
// The WebService returns all category events. Check the response to search for the event we want.
let event = response.events.find((e) => {return e.id == id});
const event = response.events.find((e) => { return e.id == id; });
return event || this.getEventFromLocalDb(id);
}).catch(() => {
return this.getEventFromLocalDb(id);
@ -190,6 +199,7 @@ export class AddonCalendarProvider {
if (time == -1) {
return this.getDefaultNotificationTime(siteId);
}
return time;
});
}
@ -221,7 +231,8 @@ export class AddonCalendarProvider {
* @param {string} [siteId] Site to get the events from. If not defined, use current site.
* @return {Promise<any[]>} Promise to be resolved when the participants are retrieved.
*/
getEventsList(daysToStart = 0, daysInterval = AddonCalendarProvider.DAYS_INTERVAL, siteId?: string) : Promise<any[]> {
getEventsList(daysToStart: number = 0, daysInterval: number = AddonCalendarProvider.DAYS_INTERVAL, siteId?: string)
: Promise<any[]> {
return this.sitesProvider.getSite(siteId).then((site) => {
siteId = site.getId();
@ -229,34 +240,39 @@ export class AddonCalendarProvider {
courses.push({ id: site.getSiteHomeId() }); // Add front page.
return this.groupsProvider.getUserGroups(courses, siteId).then((groups) => {
let now = this.timeUtils.timestamp(),
const now = this.timeUtils.timestamp(),
start = now + (CoreConstants.SECONDS_DAY * daysToStart),
end = start + (CoreConstants.SECONDS_DAY * daysInterval);
// The core_calendar_get_calendar_events needs all the current user courses and groups.
let data = {
"options[userevents]": 1,
"options[siteevents]": 1,
"options[timestart]": start,
"options[timeend]": end
end = start + (CoreConstants.SECONDS_DAY * daysInterval),
data = {
options: {
userevents: 1,
siteevents: 1,
timestart: start,
timeend: end
},
events: {
courseids: [],
groupids: []
}
};
courses.forEach((course, index) => {
data["events[courseids][" + index + "]"] = course.id;
data.events.courseids[index] = course.id;
});
groups.forEach((group, index) => {
data["events[groupids][" + index + "]"] = group.id;
data.events.groupids[index] = group.id;
});
// We need to retrieve cached data using cache key because we have timestamp in the params.
let preSets = {
const preSets = {
cacheKey: this.getEventsListCacheKey(daysToStart, daysInterval),
getCacheUsingCacheKey: true
};
return site.read('core_calendar_get_calendar_events', data, preSets).then((response) => {
this.storeEventsInLocalDB(response.events, siteId);
return response.events;
});
});
@ -295,11 +311,12 @@ export class AddonCalendarProvider {
return this.sitesProvider.getSite(siteId).then((site) => {
siteId = site.getId();
let promises = [];
const promises = [];
promises.push(this.coursesProvider.invalidateUserCourses(siteId));
promises.push(this.groupsProvider.invalidateUserGroups(courses, siteId));
promises.push(site.invalidateWsCacheForKeyStartingWith(this.getEventsListPrefixCacheKey()));
return Promise.all(promises);
});
}
@ -325,6 +342,7 @@ export class AddonCalendarProvider {
*/
isCalendarDisabledInSite(site?: CoreSite): boolean {
site = site || this.sitesProvider.getCurrentSite();
return site.isFeatureDisabled('$mmSideMenuDelegate_mmaCalendar');
}
@ -340,7 +358,6 @@ export class AddonCalendarProvider {
});
}
/**
* Get the next events for all the sites and schedules their notifications.
* If an event notification time is 0, cancel its scheduled notification (if any).
@ -351,7 +368,7 @@ export class AddonCalendarProvider {
scheduleAllSitesEventsNotifications(): Promise<any[]> {
if (this.localNotificationsProvider.isAvailable()) {
return this.sitesProvider.getSitesIds().then((siteIds) => {
let promises = [];
const promises = [];
siteIds.forEach((siteId) => {
// Check if calendar is disabled for the site.
@ -391,16 +408,16 @@ export class AddonCalendarProvider {
}
// If time is -1, get event default time.
let promise = time == -1 ? this.getDefaultNotificationTime(siteId) : Promise.resolve(time);
const promise = time == -1 ? this.getDefaultNotificationTime(siteId) : Promise.resolve(time);
return promise.then((time) => {
let timeEnd = (event.timestart + event.timeduration) * 1000;
const timeEnd = (event.timestart + event.timeduration) * 1000;
if (timeEnd <= new Date().getTime()) {
// The event has finished already, don't schedule it.
return Promise.resolve();
}
let dateTriggered = new Date((event.timestart - (time * 60)) * 1000),
const dateTriggered = new Date((event.timestart - (time * 60)) * 1000),
startDate = new Date(event.timestart * 1000),
notification = {
id: event.id,
@ -421,7 +438,6 @@ export class AddonCalendarProvider {
}
}
/**
* Schedules the notifications for a list of events.
* If an event notification time is 0, cancel its scheduled notification (if any).
@ -432,7 +448,7 @@ export class AddonCalendarProvider {
* @return {Promise<any[]>} Promise resolved when all the notifications have been scheduled.
*/
scheduleEventsNotifications(events: any[], siteId?: string): Promise<any[]> {
var promises = [];
const promises = [];
if (this.localNotificationsProvider.isAvailable()) {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
@ -456,7 +472,8 @@ export class AddonCalendarProvider {
setDefaultNotificationTime(time: number, siteId?: string): Promise<any[]> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
let key = this.DEFAULT_NOTIFICATION_TIME_SETTING + '#' + siteId;
const key = this.DEFAULT_NOTIFICATION_TIME_SETTING + '#' + siteId;
return this.configProvider.set(key, time);
}
@ -471,7 +488,7 @@ export class AddonCalendarProvider {
return this.sitesProvider.getSite(siteId).then((site) => {
siteId = site.getId();
let promises = [],
const promises = [],
db = site.getDb();
events.forEach((event) => {
@ -480,7 +497,7 @@ export class AddonCalendarProvider {
// Event not stored, return empty object.
return {};
}).then((e) => {
let eventRecord = {
const eventRecord = {
id: event.id,
name: event.name,
description: event.description,

View File

@ -23,12 +23,12 @@ import { CoreCourseProvider } from '../../../core/course/providers/course';
export class AddonCalendarHelperProvider {
protected logger;
private EVENTICONS = {
'course': 'ionic',
'group': 'people',
'site': 'globe',
'user': 'person',
'category': 'albums'
protected EVENTICONS = {
course: 'ionic',
group: 'people',
site: 'globe',
user: 'person',
category: 'albums'
};
constructor(logger: CoreLoggerProvider, private courseProvider: CoreCourseProvider) {
@ -40,11 +40,11 @@ export class AddonCalendarHelperProvider {
*
* @param {any} e Event to format.
*/
formatEventData(e: any) {
formatEventData(e: any): void {
e.icon = this.EVENTICONS[e.eventtype] || false;
if (!e.icon) {
e.icon = this.courseProvider.getModuleIconSrc(e.modulename);
e.moduleIcon = e.icon;
}
};
}
}

View File

@ -32,8 +32,7 @@ export class AddonCalendarMainMenuHandler implements CoreMainMenuHandler {
* @return {boolean} Whether or not the handler is enabled on a site level.
*/
isEnabled(): boolean | Promise<boolean> {
let isDisabled = this.calendarProvider.isCalendarDisabledInSite();
return !isDisabled;
return !this.calendarProvider.isCalendarDisabledInSite();
}
/**

View File

@ -25,8 +25,8 @@ import { CoreUtilsProvider } from '../../../../providers/utils/utils';
})
export class AddonUserProfileFieldCheckboxComponent implements OnInit {
@Input() field: any; // The profile field to be rendered.
@Input() edit?: boolean = false; // True if editing the field. Defaults to false.
@Input() disabled?: boolean = false; // True if disabled. Defaults to false.
@Input() edit?: false; // True if editing the field. Defaults to false.
@Input() disabled?: false; // True if disabled. Defaults to false.
@Input() form?: FormGroup; // Form where to add the form control.
constructor(private fb: FormBuilder, protected utils: CoreUtilsProvider) { }
@ -34,14 +34,14 @@ export class AddonUserProfileFieldCheckboxComponent implements OnInit {
/**
* Component being initialized.
*/
ngOnInit() {
let field = this.field;
ngOnInit(): void {
const field = this.field;
if (field && this.edit && this.form) {
field.modelName = 'profile_field_' + field.shortname;
// Initialize the value.
let formData = {
const formData = {
value: this.utils.isTrueOrOne(field.defaultdata),
disabled: this.disabled
};
@ -49,5 +49,4 @@ export class AddonUserProfileFieldCheckboxComponent implements OnInit {
field.required && !field.locked ? Validators.requiredTrue : null));
}
}
}

View File

@ -24,7 +24,9 @@ import { AddonUserProfileFieldCheckboxComponent } from '../component/checkbox';
export class AddonUserProfileFieldCheckboxHandler implements CoreUserProfileFieldHandler {
name = 'checkbox';
constructor() {}
constructor() {
// Nothing to do.
}
/**
* Whether or not the handler is enabled on a site level.
@ -45,7 +47,7 @@ export class AddonUserProfileFieldCheckboxHandler implements CoreUserProfileFiel
* @return {CoreUserProfileFieldHandlerData} Data to send for the field.
*/
getData(field: any, signup: boolean, registerAuth: string, formValues: any): CoreUserProfileFieldHandlerData {
let name = 'profile_field_' + field.shortname;
const name = 'profile_field_' + field.shortname;
if (typeof formValues[name] != 'undefined') {
return {
@ -61,8 +63,7 @@ export class AddonUserProfileFieldCheckboxHandler implements CoreUserProfileFiel
*
* @return {any} The component to use, undefined if not found.
*/
getComponent() {
getComponent(): any {
return AddonUserProfileFieldCheckboxComponent;
}
}

View File

@ -26,8 +26,8 @@ import { CoreUtilsProvider } from '../../../../providers/utils/utils';
})
export class AddonUserProfileFieldDatetimeComponent implements OnInit {
@Input() field: any; // The profile field to be rendered.
@Input() edit?: boolean = false; // True if editing the field. Defaults to false.
@Input() disabled?: boolean = false; // True if disabled. Defaults to false.
@Input() edit? = false; // True if editing the field. Defaults to false.
@Input() disabled? = false; // True if disabled. Defaults to false.
@Input() form?: FormGroup; // Form where to add the form control.
constructor(private fb: FormBuilder, private timeUtils: CoreTimeUtilsProvider, protected utils: CoreUtilsProvider) { }
@ -35,14 +35,15 @@ export class AddonUserProfileFieldDatetimeComponent implements OnInit {
/**
* Component being initialized.
*/
ngOnInit() {
let field = this.field,
year;
ngOnInit(): void {
const field = this.field;
let year;
if (field && this.edit && this.form) {
field.modelName = 'profile_field_' + field.shortname;
// Check if it's only date or it has time too.
let hasTime = this.utils.isTrueOrOne(field.param3);
const hasTime = this.utils.isTrueOrOne(field.param3);
field.format = hasTime ? this.timeUtils.getLocalizedDateFormat('LLL') : this.timeUtils.getLocalizedDateFormat('LL');
// Check min value.
@ -61,7 +62,7 @@ export class AddonUserProfileFieldDatetimeComponent implements OnInit {
}
}
let formData = {
const formData = {
value: field.defaultdata,
disabled: this.disabled
};
@ -69,5 +70,4 @@ export class AddonUserProfileFieldDatetimeComponent implements OnInit {
field.required && !field.locked ? Validators.required : null));
}
}
}

View File

@ -24,7 +24,9 @@ import { AddonUserProfileFieldDatetimeComponent } from '../component/datetime';
export class AddonUserProfileFieldDatetimeHandler implements CoreUserProfileFieldHandler {
name = 'datetime';
constructor() {}
constructor() {
// Nothing to do.
}
/**
* Whether or not the handler is enabled on a site level.
@ -45,10 +47,11 @@ export class AddonUserProfileFieldDatetimeHandler implements CoreUserProfileFiel
* @return {CoreUserProfileFieldHandlerData} Data to send for the field.
*/
getData(field: any, signup: boolean, registerAuth: string, formValues: any): CoreUserProfileFieldHandlerData {
let name = 'profile_field_' + field.shortname;
const name = 'profile_field_' + field.shortname;
if (formValues[name]) {
let milliseconds = new Date(formValues[name]).getTime();
const milliseconds = new Date(formValues[name]).getTime();
return {
type: 'datetime',
name: 'profile_field_' + field.shortname,
@ -62,8 +65,7 @@ export class AddonUserProfileFieldDatetimeHandler implements CoreUserProfileFiel
*
* @return {any} The component to use, undefined if not found.
*/
getComponent() {
getComponent(): any {
return AddonUserProfileFieldDatetimeComponent;
}
}

View File

@ -24,8 +24,8 @@ import { FormGroup, FormBuilder, Validators } from '@angular/forms';
})
export class AddonUserProfileFieldMenuComponent implements OnInit {
@Input() field: any; // The profile field to be rendered.
@Input() edit?: boolean = false; // True if editing the field. Defaults to false.
@Input() disabled?: boolean = false; // True if disabled. Defaults to false.
@Input() edit? = false; // True if editing the field. Defaults to false.
@Input() disabled? = false; // True if disabled. Defaults to false.
@Input() form?: FormGroup; // Form where to add the form control.
constructor(private fb: FormBuilder) { }
@ -33,8 +33,8 @@ export class AddonUserProfileFieldMenuComponent implements OnInit {
/**
* Component being initialized.
*/
ngOnInit() {
let field = this.field;
ngOnInit(): void {
const field = this.field;
if (field && this.edit && this.form) {
field.modelName = 'profile_field_' + field.shortname;
@ -46,7 +46,7 @@ export class AddonUserProfileFieldMenuComponent implements OnInit {
field.options = [];
}
let formData = {
const formData = {
value: field.defaultdata,
disabled: this.disabled
};
@ -56,5 +56,4 @@ export class AddonUserProfileFieldMenuComponent implements OnInit {
}
}
}

View File

@ -24,7 +24,9 @@ import { AddonUserProfileFieldMenuComponent } from '../component/menu';
export class AddonUserProfileFieldMenuHandler implements CoreUserProfileFieldHandler {
name = 'menu';
constructor() {}
constructor() {
// Nothing to do.
}
/**
* Whether or not the handler is enabled on a site level.
@ -45,7 +47,7 @@ export class AddonUserProfileFieldMenuHandler implements CoreUserProfileFieldHan
* @return {CoreUserProfileFieldHandlerData} Data to send for the field.
*/
getData(field: any, signup: boolean, registerAuth: string, formValues: any): CoreUserProfileFieldHandlerData {
let name = 'profile_field_' + field.shortname;
const name = 'profile_field_' + field.shortname;
if (formValues[name]) {
return {
@ -61,8 +63,7 @@ export class AddonUserProfileFieldMenuHandler implements CoreUserProfileFieldHan
*
* @return {any} The component to use, undefined if not found.
*/
getComponent() {
getComponent(): any {
return AddonUserProfileFieldMenuComponent;
}
}

View File

@ -25,8 +25,8 @@ import { CoreUtilsProvider } from '../../../../providers/utils/utils';
})
export class AddonUserProfileFieldTextComponent implements OnInit {
@Input() field: any; // The profile field to be rendered.
@Input() edit?: boolean = false; // True if editing the field. Defaults to false.
@Input() disabled?: boolean = false; // True if disabled. Defaults to false.
@Input() edit? = false; // True if editing the field. Defaults to false.
@Input() disabled? = false; // True if disabled. Defaults to false.
@Input() form?: FormGroup; // Form where to add the form control.
constructor(private fb: FormBuilder, protected utils: CoreUtilsProvider) { }
@ -34,8 +34,8 @@ export class AddonUserProfileFieldTextComponent implements OnInit {
/**
* Component being initialized.
*/
ngOnInit() {
let field = this.field;
ngOnInit(): void {
const field = this.field;
if (field && this.edit && this.form) {
field.modelName = 'profile_field_' + field.shortname;
@ -48,7 +48,7 @@ export class AddonUserProfileFieldTextComponent implements OnInit {
// Check if it's a password or text.
field.inputType = this.utils.isTrueOrOne(field.param3) ? 'password' : 'text';
let formData = {
const formData = {
value: field.defaultdata,
disabled: this.disabled
};
@ -57,5 +57,4 @@ export class AddonUserProfileFieldTextComponent implements OnInit {
field.required && !field.locked ? Validators.required : null));
}
}
}

View File

@ -46,7 +46,7 @@ export class AddonUserProfileFieldTextHandler implements CoreUserProfileFieldHan
* @return {CoreUserProfileFieldHandlerData} Data to send for the field.
*/
getData(field: any, signup: boolean, registerAuth: string, formValues: any): CoreUserProfileFieldHandlerData {
let name = 'profile_field_' + field.shortname;
const name = 'profile_field_' + field.shortname;
return {
type: 'text',
@ -60,8 +60,7 @@ export class AddonUserProfileFieldTextHandler implements CoreUserProfileFieldHan
*
* @return {any} The component to use, undefined if not found.
*/
getComponent() {
getComponent(): any {
return AddonUserProfileFieldTextComponent;
}
}

View File

@ -24,24 +24,26 @@ import { FormGroup, Validators, FormControl} from '@angular/forms';
})
export class AddonUserProfileFieldTextareaComponent implements OnInit {
@Input() field: any; // The profile field to be rendered.
@Input() edit?: boolean = false; // True if editing the field. Defaults to false.
@Input() disabled?: boolean = false; // True if disabled. Defaults to false.
@Input() edit? = false; // True if editing the field. Defaults to false.
@Input() disabled? = false; // True if disabled. Defaults to false.
@Input() form?: FormGroup; // Form where to add the form control.
control: FormControl
control: FormControl;
constructor() {}
constructor() {
// Nothing to do.
}
/**
* Component being initialized.
*/
ngOnInit() {
let field = this.field;
ngOnInit(): void {
const field = this.field;
if (field && this.edit && this.form) {
field.modelName = 'profile_field_' + field.shortname;
let formData = {
const formData = {
value: field.defaultdata,
disabled: this.disabled
};
@ -50,5 +52,4 @@ export class AddonUserProfileFieldTextareaComponent implements OnInit {
this.form.addControl(field.modelName, this.control);
}
}
}

View File

@ -46,10 +46,10 @@ export class AddonUserProfileFieldTextareaHandler implements CoreUserProfileFiel
* @return {CoreUserProfileFieldHandlerData} Data to send for the field.
*/
getData(field: any, signup: boolean, registerAuth: string, formValues: any): CoreUserProfileFieldHandlerData {
let name = 'profile_field_' + field.shortname;
const name = 'profile_field_' + field.shortname;
if (formValues[name]) {
let text = formValues[name] || '';
let text = formValues[name] || '';
// Add some HTML to the message in case the user edited with textarea.
text = this.textUtils.formatHtmlLines(text);
@ -69,8 +69,7 @@ export class AddonUserProfileFieldTextareaHandler implements CoreUserProfileFiel
*
* @return {any} The component to use, undefined if not found.
*/
getComponent() {
getComponent(): any {
return AddonUserProfileFieldTextareaComponent;
}
}

View File

@ -18,7 +18,6 @@ import { AddonUserProfileFieldMenuModule } from './menu/menu.module';
import { AddonUserProfileFieldTextModule } from './text/text.module';
import { AddonUserProfileFieldTextareaModule } from './textarea/textarea.module';
@NgModule({
declarations: [],
imports: [

View File

@ -25,8 +25,8 @@ import { CoreLoginHelperProvider } from '../core/login/providers/helper';
templateUrl: 'app.html'
})
export class MoodleMobileApp implements OnInit {
// Use the page name (string) because the page is lazy loaded (Ionic feature). That way we can load pages without
// having to import them. The downside is that each page needs to implement a ngModule.
// Use page name (string) because the page is lazy loaded (Ionic feature). That way we can load pages without importing them.
// The downside is that each page needs to implement a ngModule.
rootPage: any = 'CoreLoginInitPage';
protected logger;
protected lastUrls = {};
@ -48,7 +48,7 @@ export class MoodleMobileApp implements OnInit {
/**
* Component being initialized.
*/
ngOnInit() {
ngOnInit(): void {
// Go to sites page when user is logged out.
this.eventsProvider.on(CoreEventsProvider.LOGOUT, () => {
this.appProvider.getRootNavController().setRoot('CoreLoginSitesPage');
@ -93,7 +93,7 @@ export class MoodleMobileApp implements OnInit {
});
// Handle app launched with a certain URL (custom URL scheme).
(<any>window).handleOpenURL = (url: string) => {
(<any> window).handleOpenURL = (url: string): void => {
// First check that the URL hasn't been treated a few seconds ago. Sometimes this function is called more than once.
if (this.lastUrls[url] && Date.now() - this.lastUrls[url] < 3000) {
// Function called more than once, stop.
@ -113,4 +113,3 @@ export class MoodleMobileApp implements OnInit {
});
}
}

View File

@ -66,9 +66,8 @@ import { CoreUserModule } from '../core/user/user.module';
import { AddonCalendarModule } from '../addon/calendar/calendar.module';
import { AddonUserProfileFieldModule } from '../addon/userprofilefield/userprofilefield.module';
// For translate loader. AoT requires an exported function for factories.
export function createTranslateLoader(http: HttpClient) {
export function createTranslateLoader(http: HttpClient): TranslateHttpLoader {
return new TranslateHttpLoader(http, './assets/lang/', '.json');
}

View File

@ -1,3 +1,17 @@
// (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 { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

View File

@ -73,6 +73,7 @@ export class CoreSyncBaseProvider {
if (this.isSyncing(id, siteId)) {
// There's already a sync ongoing for this discussion, return the promise.
const uniqueId = this.getUniqueSyncId(id);
return this.syncPromises[siteId][uniqueId];
}
}
@ -136,6 +137,7 @@ export class CoreSyncBaseProvider {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
const uniqueId = this.getUniqueSyncId(id);
return !!(this.syncPromises[siteId] && this.syncPromises[siteId][uniqueId]);
}
@ -163,6 +165,7 @@ export class CoreSyncBaseProvider {
setSyncTime(id: number, siteId?: string, time?: number): Promise<any> {
return this.sitesProvider.getSiteDb(siteId).then((db) => {
time = typeof time != 'undefined' ? time : Date.now();
return db.insertOrUpdateRecord(CoreSyncProvider.SYNC_TABLE, { time: time }, { component: this.component, id: id });
});
}
@ -178,6 +181,7 @@ export class CoreSyncBaseProvider {
setSyncWarnings(id: number, warnings: string[], siteId?: string): Promise<any> {
return this.sitesProvider.getSiteDb(siteId).then((db) => {
warnings = warnings || [];
return db.insertOrUpdateRecord(CoreSyncProvider.SYNC_TABLE, { warnings: JSON.stringify(warnings) },
{ component: this.component, id: id });
});
@ -194,8 +198,11 @@ export class CoreSyncBaseProvider {
waitForSync(id: number, siteId?: string): Promise<any> {
const promise = this.getOngoingSync(id, siteId);
if (promise) {
return promise.catch(() => {});
return promise.catch(() => {
// Ignore errors.
});
}
return Promise.resolve();
}
}

View File

@ -23,12 +23,14 @@
export class CoreCache {
protected cacheStore = {};
constructor() {}
constructor() {
// Nothing to do.
}
/**
* Clear the cache.
*/
clear() {
clear(): void {
this.cacheStore = {};
}
@ -75,7 +77,7 @@ export class CoreCache {
*/
invalidate(id: any): void {
const entry = this.getEntry(id);
for (let name in entry) {
for (const name in entry) {
entry[name].timemodified = 0;
}
}
@ -94,6 +96,7 @@ export class CoreCache {
value: value,
timemodified: Date.now()
};
return value;
}
}

View File

@ -145,7 +145,7 @@ export class CoreDelegate {
* @param {boolean} [enabled] Only enabled, or any.
* @return {any} Handler.
*/
protected getHandler(handlerName: string, enabled = false): any {
protected getHandler(handlerName: string, enabled: boolean = false): any {
return enabled ? this.enabledHandlers[handlerName] : this.handlers[handlerName];
}
@ -156,7 +156,7 @@ export class CoreDelegate {
* @param {boolean} [enabled] Only enabled, or any.
* @return {boolean} If the handler is registered or not.
*/
hasHandler(name: string, enabled = false): boolean {
hasHandler(name: string, enabled: boolean = false): boolean {
return enabled ? typeof this.enabledHandlers[name] !== 'undefined' : typeof this.handlers[name] !== 'undefined';
}
@ -171,6 +171,7 @@ export class CoreDelegate {
if (!this.lastUpdateHandlersStart) {
return true;
}
return time == this.lastUpdateHandlersStart;
}
@ -183,11 +184,13 @@ export class CoreDelegate {
registerHandler(handler: CoreDelegateHandler): boolean {
if (typeof this.handlers[handler.name] !== 'undefined') {
this.logger.log(`Addon '${handler.name}' already registered`);
return false;
}
this.logger.log(`Registered addon '${handler.name}'`);
this.handlers[handler.name] = handler;
return true;
}
@ -199,9 +202,9 @@ export class CoreDelegate {
* @return {Promise<void>} Resolved when done.
*/
protected updateHandler(handler: CoreDelegateHandler, time: number): Promise<void> {
let promise,
siteId = this.sitesProvider.getCurrentSiteId(),
const siteId = this.sitesProvider.getCurrentSiteId(),
currentSite = this.sitesProvider.getCurrentSite();
let promise;
if (!this.sitesProvider.isLoggedIn()) {
promise = Promise.reject(null);
@ -235,7 +238,7 @@ export class CoreDelegate {
* @return {boolean} Whether is enabled or disabled in site.
*/
protected isFeatureDisabled(handler: CoreDelegateHandler, site: any): boolean {
return typeof this.featurePrefix != "undefined" && site.isFeatureDisabled(this.featurePrefix + handler.name);
return typeof this.featurePrefix != 'undefined' && site.isFeatureDisabled(this.featurePrefix + handler.name);
}
/**
@ -244,7 +247,7 @@ export class CoreDelegate {
* @return {Promise<void>} Resolved when done.
*/
protected updateHandlers(): Promise<void> {
let promises = [],
const promises = [],
now = Date.now();
this.logger.debug('Updating handlers for current site.');
@ -252,7 +255,7 @@ export class CoreDelegate {
this.lastUpdateHandlersStart = now;
// Loop over all the handlers.
for (let name in this.handlers) {
for (const name in this.handlers) {
promises.push(this.updateHandler(this.handlers[name], now));
}
@ -274,7 +277,7 @@ export class CoreDelegate {
* Update handlers Data.
* Override this function to update handlers data.
*/
updateData() {
updateData(): any {
// To be overridden.
}
}

View File

@ -23,7 +23,9 @@ import { Observable } from 'rxjs';
@Injectable()
export class CoreInterceptor implements HttpInterceptor {
constructor() {}
constructor() {
// Nothing to do.
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
// Add the header and serialize the body if needed.
@ -44,14 +46,14 @@ export class CoreInterceptor implements HttpInterceptor {
* @param {boolean} [addNull] Add null values to the serialized as empty parameters.
* @return {string} Serialization of the object.
*/
public static serialize(obj: any, addNull?: boolean) : string {
static serialize(obj: any, addNull?: boolean): string {
let query = '',
fullSubName,
subValue,
innerObj;
for (let name in obj) {
let value = obj[name];
for (const name in obj) {
const value = obj[name];
if (value instanceof Array) {
for (let i = 0; i < value.length; ++i) {
@ -62,7 +64,7 @@ export class CoreInterceptor implements HttpInterceptor {
query += this.serialize(innerObj) + '&';
}
} else if (value instanceof Object) {
for (let subName in value) {
for (const subName in value) {
subValue = value[subName];
fullSubName = name + '[' + subName + ']';
innerObj = {};

View File

@ -107,7 +107,7 @@ export interface CoreSiteWSPreSets {
* @type {string}
*/
typeExpected?: string;
};
}
/**
* Response of checking local_mobile status.
@ -190,10 +190,10 @@ export class CoreSite {
protected cleanUnicode = false;
protected lastAutoLogin = 0;
protected moodleReleases = {
'3.1': 2016052300,
'3.2': 2016120500,
'3.3': 2017051503,
'3.4': 2017111300
3.1: 2016052300,
3.2: 2016120500,
3.3: 2017051503,
3.4: 2017111300
};
/**
@ -211,7 +211,7 @@ export class CoreSite {
constructor(injector: Injector, public id: string, public siteUrl: string, public token?: string, public infos?: any,
public privateToken?: string, public config?: any, public loggedOut?: boolean) {
// Inject the required services.
let logger = injector.get(CoreLoggerProvider);
const logger = injector.get(CoreLoggerProvider);
this.appProvider = injector.get(CoreAppProvider);
this.dbProvider = injector.get(CoreDbProvider);
this.domUtils = injector.get(CoreDomUtilsProvider);
@ -385,6 +385,7 @@ export class CoreSite {
*/
canAccessMyFiles(): boolean {
const infos = this.getInfo();
return infos && (typeof infos.usercanmanageownfiles === 'undefined' || infos.usercanmanageownfiles);
}
@ -395,6 +396,7 @@ export class CoreSite {
*/
canDownloadFiles(): boolean {
const infos = this.getInfo();
return infos && infos.downloadfiles;
}
@ -405,15 +407,15 @@ export class CoreSite {
* @param {boolean} [whenUndefined=true] The value to return when the parameter is undefined.
* @return {boolean} Whether can use advanced feature.
*/
canUseAdvancedFeature(feature: string, whenUndefined = true) : boolean {
let infos = this.getInfo(),
canUse = true;
canUseAdvancedFeature(feature: string, whenUndefined: boolean = true): boolean {
const infos = this.getInfo();
let canUse = true;
if (typeof infos.advancedfeatures === 'undefined') {
canUse = whenUndefined;
} else {
for (let i in infos.advancedfeatures) {
let item = infos.advancedfeatures[i];
for (const i in infos.advancedfeatures) {
const item = infos.advancedfeatures[i];
if (item.name === feature && parseInt(item.value, 10) === 0) {
canUse = false;
}
@ -431,6 +433,7 @@ export class CoreSite {
*/
canUploadFiles(): boolean {
const infos = this.getInfo();
return infos && infos.uploadfiles;
}
@ -440,11 +443,11 @@ export class CoreSite {
* @return {Promise<any>} A promise to be resolved when the site info is retrieved.
*/
fetchSiteInfo(): Promise<any> {
// get_site_info won't be cached.
let preSets = {
// The get_site_info WS call won't be cached.
const preSets = {
getFromCache: false,
saveToCache: false
}
};
// Reset clean Unicode to check if it's supported again.
this.cleanUnicode = false;
@ -468,6 +471,7 @@ export class CoreSite {
if (typeof preSets.saveToCache == 'undefined') {
preSets.saveToCache = true;
}
return this.request(method, data, preSets);
}
@ -490,6 +494,7 @@ export class CoreSite {
if (typeof preSets.emergencyCache == 'undefined') {
preSets.emergencyCache = false;
}
return this.request(method, data, preSets);
}
@ -513,7 +518,7 @@ export class CoreSite {
* means that it will fallback on the 'local_mobile_' prefixed function if it is available and the non-prefixed is not.
*/
request(method: string, data: any, preSets: CoreSiteWSPreSets, retrying?: boolean): Promise<any> {
let initialToken = this.token;
const initialToken = this.token;
data = data || {};
// Check if the method is available, use a prefixed version if possible.
@ -525,11 +530,12 @@ export class CoreSite {
method = compatibilityMethod;
} else {
this.logger.error(`WS function '${method}' is not available, even in compatibility mode.`);
return Promise.reject(this.wsProvider.createFakeWSError('core.wsfunctionnotavailable', true));
}
}
let wsPreSets: CoreWSPreSets = {
const wsPreSets: CoreWSPreSets = {
wsToken: this.token,
siteUrl: this.siteUrl,
cleanUnicode: this.cleanUnicode,
@ -564,8 +570,7 @@ export class CoreSite {
this.saveToCache(method, data, response, preSets);
}
// We pass back a clone of the original object, this may
// prevent errors if in the callback the object is modified.
// We pass back a clone of the original object, this may prevent errors if in the callback the object is modified.
return this.utils.clone(response);
}).catch((error) => {
if (error.errorcode == 'invalidtoken' ||
@ -588,39 +593,47 @@ export class CoreSite {
// User deleted, trigger event.
this.eventsProvider.trigger(CoreEventsProvider.USER_DELETED, { params: data }, this.id);
error.message = this.translate.instant('core.userdeleted');
return Promise.reject(error);
} else if (error.errorcode === 'forcepasswordchangenotice') {
// Password Change Forced, trigger event.
this.eventsProvider.trigger(CoreEventsProvider.PASSWORD_CHANGE_FORCED, {}, this.id);
error.message = this.translate.instant('core.forcepasswordchangenotice');
return Promise.reject(error);
} else if (error.errorcode === 'usernotfullysetup') {
// User not fully setup, trigger event.
this.eventsProvider.trigger(CoreEventsProvider.USER_NOT_FULLY_SETUP, {}, this.id);
error.message = this.translate.instant('core.usernotfullysetup');
return Promise.reject(error);
} else if (error.errorcode === 'sitepolicynotagreed') {
// Site policy not agreed, trigger event.
this.eventsProvider.trigger(CoreEventsProvider.SITE_POLICY_NOT_AGREED, {}, this.id);
error.message = this.translate.instant('core.sitepolicynotagreederror');
return Promise.reject(error);
} else if (error.errorcode === 'dmlwriteexception' && this.textUtils.hasUnicodeData(data)) {
if (!this.cleanUnicode) {
// Try again cleaning unicode.
this.cleanUnicode = true;
return this.request(method, data, preSets);
}
// This should not happen.
error.message = this.translate.instant('core.unicodenotsupported');
return Promise.reject(error);
} else if (typeof preSets.emergencyCache !== 'undefined' && !preSets.emergencyCache) {
this.logger.debug(`WS call '${method}' failed. Emergency cache is forbidden, rejecting.`);
return Promise.reject(error);
}
this.logger.debug(`WS call '${method}' failed. Trying to use the emergency cache.`);
preSets.omitExpires = true;
preSets.getFromCache = true;
return this.getFromCache(method, data, preSets, true).catch(() => {
return Promise.reject(error);
});
@ -635,7 +648,7 @@ export class CoreSite {
* @param {boolean} [checkPrefix=true] When true also checks with the compatibility prefix.
* @return {boolean} Whether the WS is available.
*/
wsAvailable(method: string, checkPrefix = true) : boolean {
wsAvailable(method: string, checkPrefix: boolean = true): boolean {
if (typeof this.infos == 'undefined') {
return false;
}
@ -676,8 +689,8 @@ export class CoreSite {
* @return {Promise<any>} Promise resolved with the WS response.
*/
protected getFromCache(method: string, data: any, preSets: CoreSiteWSPreSets, emergency?: boolean): Promise<any> {
let id = this.getCacheId(method, data),
promise;
const id = this.getCacheId(method, data);
let promise;
if (!this.db || !preSets.getFromCache) {
return Promise.reject(null);
@ -691,12 +704,13 @@ export class CoreSite {
} else if (entries.length > 1) {
// More than one entry found. Search the one with same ID as this call.
for (let i = 0, len = entries.length; i < len; i++) {
let entry = entries[i];
const entry = entries[i];
if (entry.id == id) {
return entry;
}
}
}
return entries[0];
});
} else {
@ -711,6 +725,7 @@ export class CoreSite {
if (!preSets.omitExpires) {
if (now > entry.expirationTime) {
this.logger.debug('Cached element found, but it is expired');
return Promise.reject(null);
}
}
@ -718,6 +733,7 @@ export class CoreSite {
if (typeof entry != 'undefined' && typeof entry.data != 'undefined') {
const expires = (entry.expirationTime - now) / 1000;
this.logger.info(`Cached element found, id: ${id} expires in ${expires} seconds`);
return JSON.parse(entry.data);
}
@ -735,13 +751,13 @@ export class CoreSite {
* @return {Promise<any>} Promise resolved when the response is saved.
*/
protected saveToCache(method: string, data: any, response: any, preSets: CoreSiteWSPreSets): Promise<any> {
let id = this.getCacheId(method, data),
cacheExpirationTime = CoreConfigConstants.cache_expiration_time,
promise,
const id = this.getCacheId(method, data),
entry: any = {
id: id,
data: JSON.stringify(response)
}
};
let cacheExpirationTime = CoreConfigConstants.cache_expiration_time,
promise;
if (!this.db) {
return Promise.reject(null);
@ -761,6 +777,7 @@ export class CoreSite {
if (preSets.cacheKey) {
entry.key = preSets.cacheKey;
}
return this.db.insertOrUpdateRecord(this.WS_CACHE_TABLE, entry, { id: id });
});
}
@ -819,6 +836,7 @@ export class CoreSite {
}
this.logger.debug('Invalidate all the cache for site: ' + this.id);
return this.db.updateRecords(this.WS_CACHE_TABLE, { expirationTime: 0 });
}
@ -837,6 +855,7 @@ export class CoreSite {
}
this.logger.debug('Invalidate cache for key: ' + key);
return this.db.updateRecords(this.WS_CACHE_TABLE, { expirationTime: 0 }, { key: key });
}
@ -854,7 +873,7 @@ export class CoreSite {
return Promise.resolve();
}
let promises = [];
const promises = [];
this.logger.debug('Invalidating multiple cache keys');
keys.forEach((key) => {
@ -879,8 +898,10 @@ export class CoreSite {
}
this.logger.debug('Invalidate cache for key starting with: ' + key);
let sql = 'UPDATE ' + this.WS_CACHE_TABLE + ' SET expirationTime=0 WHERE key LIKE ?';
return this.db.execute(sql, [key + "%"]);
const sql = 'UPDATE ' + this.WS_CACHE_TABLE + ' SET expirationTime=0 WHERE key LIKE ?';
return this.db.execute(sql, [key + '%']);
}
/**
@ -911,6 +932,7 @@ export class CoreSite {
deleteFolder(): Promise<any> {
if (this.fileProvider.isAvailable()) {
const siteFolder = this.fileProvider.getSiteFolder(this.id);
return this.fileProvider.removeDir(siteFolder).catch(() => {
// Ignore any errors, $mmFS.removeDir fails if folder doesn't exists.
});
@ -927,6 +949,7 @@ export class CoreSite {
getSpaceUsage(): Promise<number> {
if (this.fileProvider.isAvailable()) {
const siteFolderPath = this.fileProvider.getSiteFolder(this.id);
return this.fileProvider.getDirectorySize(siteFolderPath).catch(() => {
return 0;
});
@ -943,6 +966,7 @@ export class CoreSite {
*/
getDocsUrl(page?: string): Promise<string> {
const release = this.infos.release ? this.infos.release : undefined;
return this.urlUtils.getDocsUrl(release, page);
}
@ -961,17 +985,19 @@ export class CoreSite {
return Promise.resolve({ code: 0 });
}
let observable = this.http.post(checkUrl, {service: service}).timeout(CoreConstants.WS_TIMEOUT);
const observable = this.http.post(checkUrl, { service: service }).timeout(CoreConstants.WS_TIMEOUT);
return this.utils.observableToPromise(observable).then((data: any) => {
if (typeof data != 'undefined' && data.errorcode === 'requirecorrectaccess') {
if (!retrying) {
this.siteUrl = this.urlUtils.addOrRemoveWWW(this.siteUrl);
return this.checkLocalMobilePlugin(true);
} else {
return Promise.reject(data.error);
}
} else if (typeof data == 'undefined' || typeof data.code == 'undefined') {
// local_mobile returned something we didn't expect. Let's assume it's not installed.
} else if (typeof data == 'undefined' || typeof data.code == 'undefined') {
// The local_mobile returned something we didn't expect. Let's assume it's not installed.
return { code: 0, warning: 'core.login.localmobileunexpectedresponse' };
}
@ -1037,9 +1063,10 @@ export class CoreSite {
return this.checkLocalMobilePlugin().then((data: LocalMobileResponse): any => {
if (typeof data.service == 'undefined') {
// local_mobile NOT installed. Reject.
// The local_mobile NOT installed. Reject.
return Promise.reject(null);
}
return data;
});
}
@ -1057,6 +1084,7 @@ export class CoreSite {
const siteUrl = this.urlUtils.removeProtocolAndWWW(this.siteUrl);
url = this.urlUtils.removeProtocolAndWWW(url);
return url.indexOf(siteUrl) == 0;
}
@ -1071,6 +1099,7 @@ export class CoreSite {
if (config.httpswwwroot) {
this.siteUrl = config.httpswwwroot;
}
return config;
});
}
@ -1132,14 +1161,14 @@ export class CoreSite {
*/
openWithAutoLogin(inApp: boolean, url: string, options?: any, alertMessage?: string): Promise<InAppBrowserObject> {
// Convenience function to open the URL.
let open = (url) => {
return new Promise<InAppBrowserObject>((resolve, reject) => {
const open = (url): Promise<any> => {
return new Promise<InAppBrowserObject>((resolve, reject): void => {
if (modal) {
modal.dismiss();
}
if (alertMessage) {
let alert = this.domUtils.showAlert(this.translate.instant('core.notice'), alertMessage, undefined, 3000);
const alert = this.domUtils.showAlert(this.translate.instant('core.notice'), alertMessage, undefined, 3000);
alert.onDidDismiss(() => {
if (inApp) {
resolve(this.utils.openInApp(url, options));
@ -1157,8 +1186,8 @@ export class CoreSite {
});
};
if (!this.privateToken || !this.wsAvailable('tool_mobile_get_autologin_key') ||
(this.lastAutoLogin && this.timeUtils.timestamp() - this.lastAutoLogin < 6 * CoreConstants.SECONDS_MINUTE)) {
if (!this.privateToken || !this.wsAvailable('tool_mobile_get_autologin_key') ||
(this.lastAutoLogin && this.timeUtils.timestamp() - this.lastAutoLogin < CoreConstants.SECONDS_MINUTE * 6)) {
// No private token, WS not available or last auto-login was less than 6 minutes ago.
// Open the final URL without auto-login.
return Promise.resolve(open(url));
@ -1172,7 +1201,7 @@ export class CoreSite {
// Use write to not use cache.
return this.write('tool_mobile_get_autologin_key', params).then((data) => {
if (!data.autologinurl || !data.key) {
if (!data.autologinurl || !data.key) {
// Not valid data, open the final URL without auto-login.
return open(url);
}
@ -1204,6 +1233,7 @@ export class CoreSite {
} else {
this.utils.openInBrowser(url);
}
return Promise.resolve(null);
}
}
@ -1216,10 +1246,10 @@ export class CoreSite {
* @param {boolean} [ignoreCache] True if it should ignore cached data.
* @return {Promise<any>} Promise resolved with site config.
*/
getConfig(name?: string, ignoreCache?: boolean) {
let preSets: CoreSiteWSPreSets = {
getConfig(name?: string, ignoreCache?: boolean): Promise<any> {
const preSets: CoreSiteWSPreSets = {
cacheKey: this.getConfigCacheKey()
}
};
if (ignoreCache) {
preSets.getFromCache = false;
@ -1229,18 +1259,20 @@ export class CoreSite {
return this.read('tool_mobile_get_config', {}, preSets).then((config) => {
if (name) {
// Return the requested setting.
for (let x in config.settings) {
for (const x in config.settings) {
if (config.settings[x].name == name) {
return config.settings[x].value;
}
}
return Promise.reject(null);
} else {
// Return all settings in the same array.
let settings = {};
const settings = {};
config.settings.forEach((setting) => {
settings[setting.name] = setting.value;
});
return settings;
}
});
@ -1295,6 +1327,7 @@ export class CoreSite {
}
const regEx = new RegExp('(,|^)' + this.textUtils.escapeForRegex(name) + '(,|$)', 'g');
return !!disabledFeatures.match(regEx);
}
@ -1328,7 +1361,7 @@ export class CoreSite {
}
for (let i = 0; i < versions.length; i++) {
let versionNumber = this.getVersionNumber(versions[i]);
const versionNumber = this.getVersionNumber(versions[i]);
if (i == versions.length - 1) {
// It's the last version, check only if site version is greater than this one.
return siteVersion >= versionNumber;
@ -1355,7 +1388,7 @@ export class CoreSite {
* @return {number} Version number, 0 if invalid.
*/
protected getVersionNumber(version: string): number {
let data = this.getMajorAndMinor(version);
const data = this.getMajorAndMinor(version);
if (!data) {
// Invalid version.
@ -1376,17 +1409,17 @@ export class CoreSite {
* @param {string} version Release version (e.g. '3.1.0').
* @return {object} Object with major and minor. Returns false if invalid version.
*/
protected getMajorAndMinor(version) : any {
protected getMajorAndMinor(version: string): any {
const match = version.match(/(\d)+(?:\.(\d)+)?(?:\.(\d)+)?/);
if (!match || !match[1]) {
if (!match || !match[1]) {
// Invalid version.
return false;
}
return {
major: match[1] + '.' + (match[2] || '0'),
minor: parseInt(match[3] || 0, 10)
}
major: match[1] + '.' + (match[2] || '0'),
minor: parseInt(match[3], 10) || 0
};
}
/**
@ -1396,9 +1429,9 @@ export class CoreSite {
* @return {number} Next major version number.
*/
protected getNextMajorVersionNumber(version: string): number {
let data = this.getMajorAndMinor(version),
position,
const data = this.getMajorAndMinor(version),
releases = Object.keys(this.moodleReleases);
let position;
if (!data) {
// Invalid version.
@ -1407,7 +1440,7 @@ export class CoreSite {
position = releases.indexOf(data.major);
if (position == -1 || position == releases.length -1) {
if (position == -1 || position == releases.length - 1) {
// Major version not found or it's the last one. Use the last one.
return this.moodleReleases[releases[position]];
}

View File

@ -64,13 +64,13 @@ export class SQLiteDB {
*/
buildCreateTableSql(name: string, columns: any[], primaryKeys?: string[], uniqueKeys?: string[][], foreignKeys?: any[],
tableCheck?: string): string {
let sql = `CREATE TABLE IF NOT EXISTS ${name} (`,
columnsSql = [];
const columnsSql = [];
let sql = `CREATE TABLE IF NOT EXISTS ${name} (`;
// First define all the columns.
for (let index in columns) {
let column = columns[index],
columnSql: string = column.name || '';
for (const index in columns) {
const column = columns[index];
let columnSql: string = column.name || '';
if (column.type) {
columnSql += ' ' + column.type;
@ -110,8 +110,8 @@ export class SQLiteDB {
}
if (uniqueKeys && uniqueKeys.length) {
for (let index in uniqueKeys) {
let setOfKeys = uniqueKeys[index];
for (const index in uniqueKeys) {
const setOfKeys = uniqueKeys[index];
if (setOfKeys && setOfKeys.length) {
sql += `, UNIQUE (${setOfKeys.join(', ')})`;
}
@ -122,9 +122,8 @@ export class SQLiteDB {
sql += `, CHECK (${tableCheck})`;
}
for (let index in foreignKeys) {
let foreignKey = foreignKeys[index];
for (const index in foreignKeys) {
const foreignKey = foreignKeys[index];
if (!foreignKey.columns || !!foreignKey.columns.length) {
return;
@ -146,8 +145,10 @@ export class SQLiteDB {
/**
* Close the database.
*
* @return {Promise<any>} Promise resolved when done.
*/
close() {
close(): Promise<any> {
return this.ready().then(() => {
return this.db.close();
});
@ -161,7 +162,8 @@ export class SQLiteDB {
* @return {Promise<number>} Promise resolved with the count of records returned from the specified criteria.
*/
countRecords(table: string, conditions?: object): Promise<number> {
let selectAndParams = this.whereClause(conditions);
const selectAndParams = this.whereClause(conditions);
return this.countRecordsSelect(table, selectAndParams[0], selectAndParams[1]);
}
@ -174,10 +176,11 @@ export class SQLiteDB {
* @param {string} [countItem] The count string to be used in the SQL call. Default is COUNT('x').
* @return {Promise<number>} Promise resolved with the count of records returned from the specified criteria.
*/
countRecordsSelect(table: string, select='', params?: any, countItem="COUNT('x')") : Promise<number> {
countRecordsSelect(table: string, select: string = '', params?: any, countItem: string = 'COUNT(\'x\')'): Promise<number> {
if (select) {
select = 'WHERE ' + select;
}
return this.countRecordsSql(`SELECT ${countItem} FROM ${table} ${select}`, params);
}
@ -192,9 +195,10 @@ export class SQLiteDB {
*/
countRecordsSql(sql: string, params?: any): Promise<number> {
return this.getFieldSql(sql, params).then((count) => {
if (typeof count != 'number' || count < 0) {
if (typeof count != 'number' || count < 0) {
return 0;
}
return count;
});
}
@ -224,7 +228,8 @@ export class SQLiteDB {
*/
createTable(name: string, columns: any[], primaryKeys?: string[], uniqueKeys?: string[][], foreignKeys?: any[],
tableCheck?: string): Promise<any> {
let sql = this.buildCreateTableSql(name, columns, primaryKeys, uniqueKeys, foreignKeys, tableCheck);
const sql = this.buildCreateTableSql(name, columns, primaryKeys, uniqueKeys, foreignKeys, tableCheck);
return this.execute(sql);
}
@ -246,10 +251,11 @@ export class SQLiteDB {
* @return {Promise<any>} Promise resolved when success.
*/
createTablesFromSchema(tables: any[]): Promise<any> {
let promises = [];
const promises = [];
tables.forEach((table) => {
promises.push(this.createTableFromSchema(table));
});
return Promise.all(promises);
}
@ -267,7 +273,8 @@ export class SQLiteDB {
return this.execute(`DELETE FROM TABLE ${table}`);
}
let selectAndParams = this.whereClause(conditions);
const selectAndParams = this.whereClause(conditions);
return this.deleteRecordsSelect(table, selectAndParams[0], selectAndParams[1]);
}
@ -280,7 +287,8 @@ export class SQLiteDB {
* @return {Promise<any>} Promise resolved when done.
*/
deleteRecordsList(table: string, field: string, values: any[]): Promise<any> {
let selectAndParams = this.whereClauseList(field, values);
const selectAndParams = this.whereClauseList(field, values);
return this.deleteRecordsSelect(table, selectAndParams[0], selectAndParams[1]);
}
@ -292,7 +300,7 @@ export class SQLiteDB {
* @param {any[]} [params] Array of sql parameters.
* @return {Promise<any>} Promise resolved when done.
*/
deleteRecordsSelect(table: string, select='', params?: any[]) : Promise<any> {
deleteRecordsSelect(table: string, select: string = '', params?: any[]): Promise<any> {
if (select) {
select = 'WHERE ' + select;
}
@ -336,8 +344,8 @@ export class SQLiteDB {
*/
protected formatDataToInsert(data: object): void {
// Remove undefined entries and convert null to "NULL".
for (let name in data) {
let value = data[name];
for (const name in data) {
const value = data[name];
if (typeof value == 'undefined') {
delete data[name];
}
@ -363,7 +371,8 @@ export class SQLiteDB {
* @return {Promise<any>} Promise resolved with the field's value.
*/
getField(table: string, field: string, conditions?: object): Promise<any> {
let selectAndParams = this.whereClause(conditions);
const selectAndParams = this.whereClause(conditions);
return this.getFieldSelect(table, field, selectAndParams[0], selectAndParams[1]);
}
@ -376,7 +385,7 @@ export class SQLiteDB {
* @param {any[]} [params] Array of sql parameters.
* @return {Promise<any>} Promise resolved with the field's value.
*/
getFieldSelect(table: string, field: string, select='', params?: any[]) : Promise<any> {
getFieldSelect(table: string, field: string, select: string = '', params?: any[]): Promise<any> {
if (select) {
select = 'WHERE ' + select;
}
@ -411,7 +420,7 @@ export class SQLiteDB {
* meaning return empty. Other values will become part of the returned SQL fragment.
* @return {any[]} A list containing the constructed sql fragment and an array of parameters.
*/
getInOrEqual(items: any, equal=true, onEmptyItems?: any) : any[] {
getInOrEqual(items: any, equal: boolean = true, onEmptyItems?: any): any[] {
let sql,
params;
@ -428,6 +437,7 @@ export class SQLiteDB {
if (Array.isArray(items) && !items.length) {
if (onEmptyItems === null) { // Special case, NULL value.
sql = equal ? ' IS NULL' : ' IS NOT NULL';
return [sql, []];
} else {
items = [onEmptyItems]; // Rest of cases, prepare items for processing.
@ -462,8 +472,9 @@ export class SQLiteDB {
* @param {string} [fields='*'] A comma separated list of fields to return.
* @return {Promise<any>} Promise resolved with the record, rejected if not found.
*/
getRecord(table: string, conditions?: object, fields='*') : Promise<any> {
let selectAndParams = this.whereClause(conditions);
getRecord(table: string, conditions?: object, fields: string = '*'): Promise<any> {
const selectAndParams = this.whereClause(conditions);
return this.getRecordSelect(table, selectAndParams[0], selectAndParams[1], fields);
}
@ -476,7 +487,7 @@ export class SQLiteDB {
* @param {string} [fields='*'] A comma separated list of fields to return.
* @return {Promise<any>} Promise resolved with the record, rejected if not found.
*/
getRecordSelect(table: string, select='', params=[], fields='*') : Promise<any> {
getRecordSelect(table: string, select: string = '', params: any[] = [], fields: string = '*'): Promise<any> {
if (select) {
select = ' WHERE ' + select;
}
@ -517,8 +528,10 @@ export class SQLiteDB {
* @param {number} [limitNum=0] Return a subset comprising this many records in total.
* @return {Promise<any>} Promise resolved with the records.
*/
getRecords(table: string, conditions?: object, sort='', fields='*', limitFrom=0, limitNum=0) : Promise<any> {
let selectAndParams = this.whereClause(conditions);
getRecords(table: string, conditions?: object, sort: string = '', fields: string = '*', limitFrom: number = 0,
limitNum: number = 0): Promise<any> {
const selectAndParams = this.whereClause(conditions);
return this.getRecordsSelect(table, selectAndParams[0], selectAndParams[1], sort, fields, limitFrom, limitNum);
}
@ -534,8 +547,10 @@ export class SQLiteDB {
* @param {number} [limitNum=0] Return a subset comprising this many records in total.
* @return {Promise<any>} Promise resolved with the records.
*/
getRecordsList(table: string, field: string, values: any[], sort='', fields='*', limitFrom=0, limitNum=0) : Promise<any> {
let selectAndParams = this.whereClauseList(field, values);
getRecordsList(table: string, field: string, values: any[], sort: string = '', fields: string = '*', limitFrom: number = 0,
limitNum: number = 0): Promise<any> {
const selectAndParams = this.whereClauseList(field, values);
return this.getRecordsSelect(table, selectAndParams[0], selectAndParams[1], sort, fields, limitFrom, limitNum);
}
@ -551,7 +566,8 @@ export class SQLiteDB {
* @param {number} [limitNum=0] Return a subset comprising this many records in total.
* @return {Promise<any>} Promise resolved with the records.
*/
getRecordsSelect(table: string, select='', params=[], sort='', fields='*', limitFrom=0, limitNum=0) : Promise<any> {
getRecordsSelect(table: string, select: string = '', params: any[] = [], sort: string = '', fields: string = '*',
limitFrom: number = 0, limitNum: number = 0): Promise<any> {
if (select) {
select = ' WHERE ' + select;
}
@ -559,7 +575,8 @@ export class SQLiteDB {
sort = ' ORDER BY ' + sort;
}
let sql = `SELECT ${fields} FROM ${table} ${select} ${sort}`;
const sql = `SELECT ${fields} FROM ${table} ${select} ${sort}`;
return this.getRecordsSql(sql, params, limitFrom, limitNum);
}
@ -573,7 +590,7 @@ export class SQLiteDB {
* @return {Promise<any>} Promise resolved with the records.
*/
getRecordsSql(sql: string, params?: any[], limitFrom?: number, limitNum?: number): Promise<any> {
let limits = this.normaliseLimitFromNum(limitFrom, limitNum);
const limits = this.normaliseLimitFromNum(limitFrom, limitNum);
if (limits[0] || limits[1]) {
if (limits[1] < 1) {
@ -584,10 +601,11 @@ export class SQLiteDB {
return this.execute(sql, params).then((result) => {
// Retrieve the records.
let records = [];
const records = [];
for (let i = 0; i < result.rows.length; i++) {
records.push(result.rows.item(i));
}
return records;
});
}
@ -602,13 +620,13 @@ export class SQLiteDB {
protected getSqlInsertQuery(table: string, data: object): any[] {
this.formatDataToInsert(data);
let keys = Object.keys(data),
const keys = Object.keys(data),
fields = keys.join(','),
questionMarks = ',?'.repeat(keys.length).substr(1);
return [
`INSERT INTO ${table} (${fields}) VALUES (${questionMarks})`,
keys.map(key => data[key])
keys.map((key) => data[key])
];
}
@ -635,7 +653,7 @@ export class SQLiteDB {
* @return {Promise<any>} Promise resolved with done.
*/
insertOrUpdateRecord(table: string, data: object, conditions: object): Promise<any> {
return this.getRecord(table, conditions || data).then(() => {
return this.getRecord(table, conditions || data).then(() => {
// It exists, update it.
return this.updateRecords(table, data, conditions);
}).catch(() => {
@ -652,7 +670,7 @@ export class SQLiteDB {
* @return {Promise<number>} Promise resolved with new rowId. Please notice this rowId is internal from SQLite.
*/
insertRecord(table: string, data: object): Promise<number> {
let sqlAndParams = this.getSqlInsertQuery(table, data);
const sqlAndParams = this.getSqlInsertQuery(table, data);
return this.execute(sqlAndParams[0], sqlAndParams[1]).then((result) => {
return result.insertId;
@ -671,7 +689,7 @@ export class SQLiteDB {
return Promise.reject(null);
}
let statements = [];
const statements = [];
dataObjects.forEach((dataObject) => {
statements.push(this.getSqlInsertQuery(table, dataObject));
@ -708,8 +726,10 @@ export class SQLiteDB {
/**
* Open the database. Only needed if it was closed before, a database is automatically opened when created.
*
* @return {Promise<void>} Promise resolved when open.
*/
open() {
open(): Promise<any> {
return this.ready().then(() => {
return this.db.open();
});
@ -747,7 +767,7 @@ export class SQLiteDB {
* @param {any[]} [params] An array of sql parameters.
* @return {Promise<any>} Promise resolved if exists, rejected otherwise.
*/
recordExistsSelect(table: string, select='', params=[]) : Promise<any> {
recordExistsSelect(table: string, select: string = '', params: any[] = []): Promise<any> {
return this.getRecordSelect(table, select, params).then((record) => {
if (!record) {
return Promise.reject(null);
@ -780,25 +800,25 @@ export class SQLiteDB {
*/
updateRecords(table: string, data: any, conditions?: any): Promise<any> {
if (!data || !Object.keys(data).length) {
if (!data || !Object.keys(data).length) {
// No fields to update, consider it's done.
return Promise.resolve();
}
let whereAndParams = this.whereClause(conditions),
sets = [],
sql,
const whereAndParams = this.whereClause(conditions),
sets = [];
let sql,
params;
this.formatDataToInsert(data);
for (let key in data) {
for (const key in data) {
sets.push(`${key} = ?`);
}
sql = `UPDATE ${table} SET ${sets.join(', ')} WHERE ${whereAndParams[0]}`;
// Create the list of params using the "data" object and the params for the where clause.
params = Object.keys(data).map(key => data[key]).concat(whereAndParams[1]);
params = Object.keys(data).map((key) => data[key]).concat(whereAndParams[1]);
return this.execute(sql, params);
}
@ -813,16 +833,16 @@ export class SQLiteDB {
* @return {Promise<any>} Promise resolved when updated.
*/
updateRecordsWhere(table: string, data: any, where?: string, whereParams?: any[]): Promise<any> {
if (!data || !Object.keys(data).length) {
if (!data || !Object.keys(data).length) {
// No fields to update, consider it's done.
return Promise.resolve();
}
let sets = [],
sql,
const sets = [];
let sql,
params;
for (let key in data) {
for (const key in data) {
sets.push(`${key} = ?`);
}
@ -832,7 +852,7 @@ export class SQLiteDB {
}
// Create the list of params using the "data" object and the params for the where clause.
params = Object.keys(data).map(key => data[key]);
params = Object.keys(data).map((key) => data[key]);
if (where && whereParams) {
params = params.concat(whereParams[1]);
}
@ -846,16 +866,16 @@ export class SQLiteDB {
* @param {object} [conditions] The conditions to build the where clause. Must not contain numeric indexes.
* @return {any[]} An array list containing sql 'where' part and 'params'.
*/
whereClause(conditions={}) : any[] {
whereClause(conditions: any = {}): any[] {
if (!conditions || !Object.keys(conditions).length) {
return ['', []];
}
let where = [],
const where = [],
params = [];
for (let key in conditions) {
let value = conditions[key];
for (const key in conditions) {
const value = conditions[key];
if (typeof value == 'undefined' || value === null) {
where.push(key + ' IS NULL');
@ -877,11 +897,11 @@ export class SQLiteDB {
*/
whereClauseList(field: string, values: any[]): any[] {
if (!values || !values.length) {
return ["1 = 2", []]; // Fake condition, won't return rows ever.
return ['1 = 2', []]; // Fake condition, won't return rows ever.
}
let params = [],
select = '';
const params = [];
let select = '';
values.forEach((value) => {
if (typeof value == 'boolean') {
@ -903,7 +923,7 @@ export class SQLiteDB {
if (params.length == 1) {
select = select + field + ' = ?';
} else {
let questionMarks = ',?'.repeat(params.length).substr(1);
const questionMarks = ',?'.repeat(params.length).substr(1);
select = select + field + ' IN (' + questionMarks + ')';
}
}

View File

@ -32,12 +32,12 @@ import { Component, Input, OnChanges, OnDestroy, Output, EventEmitter, SimpleCha
})
export class CoreChronoComponent implements OnChanges, OnDestroy {
@Input() running: boolean; // Set it to true to start the chrono. Set it to false to stop it.
@Input() startTime?: number = 0; // Number of milliseconds to put in the chrono before starting.
@Input() startTime? = 0; // Number of milliseconds to put in the chrono before starting.
@Input() endTime?: number; // Number of milliseconds to stop the chrono.
@Input() reset?: boolean; // Set it to true to reset the chrono.
@Output() onEnd?: EventEmitter<void>; // Will emit an event when the endTime is reached.
time: number = 0;
time = 0;
protected interval;
constructor(private cdr: ChangeDetectorRef) {
@ -47,14 +47,14 @@ export class CoreChronoComponent implements OnChanges, OnDestroy {
/**
* Component being initialized.
*/
ngOnInit() {
ngOnInit(): void {
this.time = this.startTime || 0;
}
/**
* Component being initialized.
*/
ngOnChanges(changes: {[name: string]: SimpleChange}) {
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
if (changes && changes.running) {
if (changes.running.currentValue) {
this.start();
@ -110,7 +110,7 @@ export class CoreChronoComponent implements OnChanges, OnDestroy {
delete this.interval;
}
ngOnDestroy() {
ngOnDestroy(): void {
this.stop();
}
}

View File

@ -15,7 +15,6 @@
import { Component, Input, Output, OnInit, OnDestroy, EventEmitter, OnChanges, SimpleChange } from '@angular/core';
import { CoreContextMenuComponent } from './context-menu';
/**
* This directive adds a item to the Context Menu popover.
*
@ -36,9 +35,10 @@ import { CoreContextMenuComponent } from './context-menu';
export class CoreContextMenuItemComponent implements OnInit, OnDestroy, OnChanges {
@Input() content: string; // Content of the item.
@Input() iconDescription?: string; // Name of the icon to be shown on the left side of the item.
@Input() iconAction?: string; // Name of the icon to be shown on the right side of the item. It represents the action to do on
// click. If is "spinner" an spinner will be shown. If no icon or spinner is selected, no action
// or link will work. If href but no iconAction is provided arrow-right will be used.
@Input() iconAction?: string; // Name of the icon to show on the right side of the item. Represents the action to do on click.
// If is "spinner" an spinner will be shown.
// If no icon or spinner is selected, no action or link will work.
// If href but no iconAction is provided arrow-right will be used.
@Input() ariaDescription?: string; // Aria label to add to iconDescription.
@Input() ariaAction?: string; // Aria label to add to iconAction. If not set, it will be equal to content.
@Input() href?: string; // Link to go if no action provided.
@ -61,7 +61,7 @@ export class CoreContextMenuItemComponent implements OnInit, OnDestroy, OnChange
/**
* Component being initialized.
*/
ngOnInit() {
ngOnInit(): void {
// Initialize values.
this.priority = this.priority || 1;
this.closeOnClick = this.getBooleanValue(this.closeOnClick, true);
@ -92,13 +92,14 @@ export class CoreContextMenuItemComponent implements OnInit, OnDestroy, OnChange
if (typeof value == 'undefined') {
return defaultValue;
}
return value && value !== 'false';
}
/**
* Component destroyed.
*/
ngOnDestroy() {
ngOnDestroy(): void {
this.destroyed = true;
this.ctxtMenu.removeItem(this);
}
@ -106,7 +107,7 @@ export class CoreContextMenuItemComponent implements OnInit, OnDestroy, OnChange
/**
* Detect changes on input properties.
*/
ngOnChanges(changes: {[name: string]: SimpleChange}) {
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
if (changes.hidden && !changes.hidden.firstChange) {
this.ctxtMenu.itemsChanged();
}

View File

@ -56,6 +56,7 @@ export class CoreContextMenuPopoverComponent {
if (!item.iconAction) {
this.logger.warn('Items with action must have an icon action to work', item);
return false;
} else if (item.iconAction == 'spinner') {
return false;

View File

@ -43,15 +43,15 @@ export class CoreContextMenuComponent implements OnInit {
this.hideMenu = !this.items.some((item) => {
return !item.hidden;
});
})
});
}
/**
* Component being initialized.
*/
ngOnInit() {
this.icon = this.icon || 'more';
this.ariaLabel = this.title || this.translate.instant('core.info');
ngOnInit(): void {
this.icon = this.icon || 'more';
this.ariaLabel = this.title || this.translate.instant('core.info');
}
/**
@ -67,7 +67,7 @@ export class CoreContextMenuComponent implements OnInit {
/**
* Function called when the items change.
*/
itemsChanged() {
itemsChanged(): void {
this.itemsChangedStream.next();
}
@ -77,7 +77,7 @@ export class CoreContextMenuComponent implements OnInit {
* @param {CoreContextMenuItemComponent} item The item to remove.
*/
removeItem(item: CoreContextMenuItemComponent): void {
let index = this.items.indexOf(item);
const index = this.items.indexOf(item);
if (index >= 0) {
this.items.splice(index, 1);
}
@ -90,7 +90,7 @@ export class CoreContextMenuComponent implements OnInit {
* @param {MouseEvent} event Event.
*/
showContextMenu(event: MouseEvent): void {
let popover = this.popoverCtrl.create(CoreContextMenuPopoverComponent, {title: this.title, items: this.items});
const popover = this.popoverCtrl.create(CoreContextMenuPopoverComponent, { title: this.title, items: this.items });
popover.present({
ev: event
});

View File

@ -40,6 +40,7 @@ export class CoreCoursePickerMenuPopoverComponent {
*/
coursePicked(event: Event, course: any): boolean {
this.viewCtrl.dismiss(course);
return true;
}
}

View File

@ -29,5 +29,7 @@ export class CoreEmptyBoxComponent {
@Input() icon?: string; // Name of the icon to use.
@Input() image?: string; // Image source. If an icon is provided, image won't be used.
constructor() {}
constructor() {
// Nothing to do.
}
}

View File

@ -64,7 +64,7 @@ export class CoreFileComponent implements OnInit, OnDestroy {
/**
* Component being initialized.
*/
ngOnInit() {
ngOnInit(): void {
this.canDelete = this.utils.isTrueOrOne(this.canDelete);
this.alwaysDownload = this.utils.isTrueOrOne(this.alwaysDownload);
this.canDownload = this.utils.isTrueOrOne(this.canDownload);
@ -100,11 +100,11 @@ export class CoreFileComponent implements OnInit, OnDestroy {
*/
protected calculateState(): Promise<void> {
return this.filepoolProvider.getFileStateByUrl(this.siteId, this.fileUrl, this.timemodified).then((state) => {
let canDownload = this.sitesProvider.getCurrentSite().canDownloadFiles();
const canDownload = this.sitesProvider.getCurrentSite().canDownloadFiles();
this.isDownloaded = state === CoreConstants.DOWNLOADED || state === CoreConstants.OUTDATED;
this.isDownloaded = state === CoreConstants.DOWNLOADED || state === CoreConstants.OUTDATED;
this.isDownloading = canDownload && state === CoreConstants.DOWNLOADING;
this.showDownload = canDownload && (state === CoreConstants.NOT_DOWNLOADED || state === CoreConstants.OUTDATED ||
this.showDownload = canDownload && (state === CoreConstants.NOT_DOWNLOADED || state === CoreConstants.OUTDATED ||
(this.alwaysDownload && state === CoreConstants.DOWNLOADED));
});
}
@ -117,10 +117,12 @@ export class CoreFileComponent implements OnInit, OnDestroy {
protected downloadFile(): Promise<string> {
if (!this.sitesProvider.getCurrentSite().canDownloadFiles()) {
this.domUtils.showErrorModal('core.cannotdownloadfiles', true);
return Promise.reject(null);
}
this.isDownloading = true;
return this.filepoolProvider.downloadUrl(this.siteId, this.fileUrl, false, this.component, this.componentId,
this.timemodified, undefined, undefined, this.file).catch(() => {
@ -141,13 +143,13 @@ export class CoreFileComponent implements OnInit, OnDestroy {
* @return {Promise<string>} Promise resolved when file is opened.
*/
protected openFile(): Promise<any> {
let fixedUrl = this.sitesProvider.getCurrentSite().fixPluginfileURL(this.fileUrl),
promise;
const fixedUrl = this.sitesProvider.getCurrentSite().fixPluginfileURL(this.fileUrl);
let promise;
if (this.fileProvider.isAvailable()) {
promise = Promise.resolve().then(() => {
// The file system is available.
let isWifi = !this.appProvider.isNetworkAccessLimited(),
const isWifi = !this.appProvider.isNetworkAccessLimited(),
isOnline = this.appProvider.isOnline();
if (this.isDownloaded && !this.showDownload) {
@ -160,13 +162,15 @@ export class CoreFileComponent implements OnInit, OnDestroy {
return Promise.reject(this.translate.instant('core.networkerrormsg'));
}
let isDownloading = this.isDownloading;
const isDownloading = this.isDownloading;
this.isDownloading = true; // This check could take a while, show spinner.
return this.filepoolProvider.shouldDownloadBeforeOpen(fixedUrl, this.fileSize).then(() => {
if (isDownloading) {
// It's already downloading, stop.
return;
}
// Download and then return the local URL.
return this.downloadFile();
}, () => {
@ -243,6 +247,7 @@ export class CoreFileComponent implements OnInit, OnDestroy {
if (!this.appProvider.isOnline() && (!openAfterDownload || (openAfterDownload && !this.isDownloaded))) {
this.domUtils.showErrorModal('core.networkerrormsg', true);
return;
}
@ -266,7 +271,7 @@ export class CoreFileComponent implements OnInit, OnDestroy {
});
});
}
};
}
/**
* Delete the file.
@ -285,7 +290,7 @@ export class CoreFileComponent implements OnInit, OnDestroy {
/**
* Component destroyed.
*/
ngOnDestroy() {
ngOnDestroy(): void {
this.observer && this.observer.off();
}
}

View File

@ -51,8 +51,8 @@ export class CoreIframeComponent implements OnInit {
/**
* Component being initialized.
*/
ngOnInit() {
let iframe: HTMLIFrameElement = this.iframe && this.iframe.nativeElement;
ngOnInit(): void {
const iframe: HTMLIFrameElement = this.iframe && this.iframe.nativeElement;
this.safeUrl = this.sanitizer.bypassSecurityTrustResourceUrl(this.src);
this.iframeWidth = this.domUtils.formatPixelsSize(this.iframeWidth) || '100%';
@ -153,10 +153,12 @@ export class CoreIframeComponent implements OnInit {
url = this.textUtils.concatenatePaths(dirAndFile.directory, url);
} else {
this.logger.warn('Cannot get iframe dir path to open relative url', url, element);
return new Window(); // Return new Window object.
}
} else {
this.logger.warn('Cannot get iframe src to open relative url', url, element);
return new Window(); // Return new Window object.
}
}

View File

@ -52,7 +52,7 @@ export class CoreInputErrorsComponent implements OnInit {
/**
* Component is being initialized.
*/
ngOnInit() {
ngOnInit(): void {
this.initErrorMessages();
this.errorKeys = Object.keys(this.errorMessages);
@ -61,11 +61,11 @@ export class CoreInputErrorsComponent implements OnInit {
/**
* Initialize some common errors if they aren't set.
*/
protected initErrorMessages() {
this.errorMessages = this.errorMessages || {};
protected initErrorMessages(): void {
this.errorMessages = this.errorMessages || {};
this.errorMessages.required = this.errorMessages.required || this.translate.instant('core.required');
this.errorMessages.email = this.errorMessages.email || this.translate.instant('core.login.invalidemail');
this.errorMessages.required = this.errorMessages.required || this.translate.instant('core.required');
this.errorMessages.email = this.errorMessages.email || this.translate.instant('core.login.invalidemail');
this.errorMessages.date = this.errorMessages.date || this.translate.instant('core.login.invaliddate');
this.errorMessages.datetime = this.errorMessages.datetime || this.translate.instant('core.login.invaliddate');
this.errorMessages.datetimelocal = this.errorMessages.datetimelocal || this.translate.instant('core.login.invaliddate');
@ -73,24 +73,6 @@ export class CoreInputErrorsComponent implements OnInit {
this.errorMessages.url = this.errorMessages.url || this.translate.instant('core.login.invalidurl');
// @todo: Check how to handle min/max errors once we have a test case to use. Also, review previous errors.
// ['min', 'max'].forEach((type) => {
// // Initialize min/max errors if needed.
// if (!this.errorMessages[type]) {
// if (input && typeof input[type] != 'undefined' && input[type] !== '') {
// var value = input[type];
// if (input.type == 'date' || input.type == 'datetime' || input.type == 'datetime-local') {
// var date = moment(value);
// if (date.isValid()) {
// value = moment(value).format($translate.instant('core.dfdaymonthyear'));
// }
// }
// scope.errorMessages[type] = $translate.instant('core.login.invalidvalue' + type, {$a: value});
// } else {
// scope.errorMessages[type] = $translate.instant('core.login.profileinvaliddata');
// }
// }
// });
}
}

View File

@ -48,7 +48,7 @@ export class CoreLoadingComponent implements OnInit {
/**
* Component being initialized.
*/
ngOnInit() {
ngOnInit(): void {
if (!this.message) {
// Default loading message.
this.message = this.translate.instant('core.loading');

View File

@ -44,7 +44,7 @@ export class CoreLocalFileComponent implements OnInit {
fileExtension: string;
size: string;
timemodified: string;
newFileName: string = '';
newFileName = '';
editMode: boolean;
relativePath: string;
@ -59,7 +59,7 @@ export class CoreLocalFileComponent implements OnInit {
/**
* Component being initialized.
*/
ngOnInit() {
ngOnInit(): void {
this.manage = this.utils.isTrueOrOne(this.manage);
// Let's calculate the relative path for the file.
@ -83,11 +83,8 @@ export class CoreLocalFileComponent implements OnInit {
/**
* Load the basic data for the file.
*
* @param {[type]} scope [description]
* @param {[type]} file [description]
*/
protected loadFileBasicData() {
protected loadFileBasicData(): void {
this.fileName = this.file.name;
this.fileIcon = this.mimeUtils.getFileIcon(this.file.name);
this.fileExtension = this.mimeUtils.getFileExtension(this.file.name);
@ -107,7 +104,7 @@ export class CoreLocalFileComponent implements OnInit {
} else {
this.utils.openFile(this.file.toURL());
}
};
}
/**
* Activate the edit mode.
@ -124,7 +121,7 @@ export class CoreLocalFileComponent implements OnInit {
// $timeout(function() {
// $mmUtil.focusElement(element[0].querySelector('input'));
// });
};
}
/**
* Rename the file.
@ -135,10 +132,11 @@ export class CoreLocalFileComponent implements OnInit {
if (newName == this.file.name) {
// Name hasn't changed, stop.
this.editMode = false;
return;
}
let modal = this.domUtils.showModalLoading(),
const modal = this.domUtils.showModalLoading(),
fileAndDir = this.fileProvider.getFileAndDirectoryFromPath(this.relativePath),
newPath = this.textUtils.concatenatePaths(fileAndDir.directory, newName);
@ -159,7 +157,7 @@ export class CoreLocalFileComponent implements OnInit {
}).finally(() => {
modal.dismiss();
});
};
}
/**
* Delete the file.
@ -172,7 +170,7 @@ export class CoreLocalFileComponent implements OnInit {
// Ask confirmation.
this.domUtils.showConfirm(this.translate.instant('core.confirmdeletefile')).then(() => {
let modal = this.domUtils.showModalLoading();
const modal = this.domUtils.showModalLoading();
this.fileProvider.removeFile(this.relativePath).then(() => {
this.onDelete.emit();
}).catch(() => {

View File

@ -45,7 +45,7 @@ export class CoreMarkRequiredComponent implements OnInit, AfterViewInit {
/**
* Component being initialized.
*/
ngOnInit() {
ngOnInit(): void {
this.coreMarkRequired = this.utils.isTrueOrOne(this.coreMarkRequired);
}

View File

@ -37,7 +37,7 @@ export class CoreProgressBarComponent implements OnChanges {
/**
* Detect changes on input properties.
*/
ngOnChanges(changes: {[name: string]: SimpleChange}) {
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
if (changes.text && typeof changes.text.currentValue != 'undefined') {
// User provided a custom text, don't use default.
this.textSupplied = true;

View File

@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, Output, EventEmitter, ViewChild, ElementRef } from '@angular/core';
import { TextInput } from 'ionic-angular';
import { CoreDomUtilsProvider } from '../../providers/utils/dom';
@ -41,15 +40,15 @@ export class CoreRichTextEditorComponent {
// Based on: https://github.com/judgewest2000/Ionic3RichText/
// @todo: Resize, images, anchor button, fullscreen...
@Input() placeholder?: string = ""; // Placeholder to set in textarea.
@Input() placeholder? = ''; // Placeholder to set in textarea.
@Input() control: FormControl; // Form control.
@Output() public contentChanged: EventEmitter<string>;
@Output() contentChanged: EventEmitter<string>;
@ViewChild('editor') editor: ElementRef; // WYSIWYG editor.
@ViewChild('textarea') textarea: TextInput; // Textarea editor.
@ViewChild('decorate') decorate: ElementRef; // Buttons.
rteEnabled: boolean = false;
rteEnabled = false;
uniqueId = `rte{Math.floor(Math.random() * 1000000)}`;
editorElement: HTMLDivElement;
@ -60,7 +59,7 @@ export class CoreRichTextEditorComponent {
/**
* Init editor
*/
ngAfterContentInit() {
ngAfterContentInit(): void {
this.domUtils.isRichTextEditorEnabled().then((enabled) => {
this.rteEnabled = !!enabled;
});
@ -77,14 +76,14 @@ export class CoreRichTextEditorComponent {
this.editorElement.oninput = this.onChange.bind(this);
// Setup button actions.
let buttons = (this.decorate.nativeElement as HTMLDivElement).getElementsByTagName('button');
const buttons = (this.decorate.nativeElement as HTMLDivElement).getElementsByTagName('button');
for (let i = 0; i < buttons.length; i++) {
let button = buttons[i],
command = button.getAttribute('data-command');
const button = buttons[i];
let command = button.getAttribute('data-command');
if (command) {
if (command.includes('|')) {
let parameter = command.split('|')[1];
const parameter = command.split('|')[1];
command = command.split('|')[0];
button.addEventListener('click', ($event) => {
@ -101,8 +100,10 @@ export class CoreRichTextEditorComponent {
/**
* On change function to sync with form data.
*
* @param {Event} $event The event.
*/
onChange($event) {
onChange($event: Event): void {
if (this.rteEnabled) {
if (this.isNullOrWhiteSpace(this.editorElement.innerText)) {
this.clearText();
@ -121,8 +122,10 @@ export class CoreRichTextEditorComponent {
/**
* Toggle from rte editor to textarea syncing values.
*
* @param {Event} $event The event.
*/
toggleEditor($event) {
toggleEditor($event: Event): void {
$event.preventDefault();
$event.stopPropagation();
@ -139,10 +142,12 @@ export class CoreRichTextEditorComponent {
setTimeout(() => {
if (this.rteEnabled) {
this.editorElement.focus();
let range = document.createRange();
const range = document.createRange();
range.selectNodeContents(this.editorElement);
range.collapse(false);
let sel = window.getSelection();
const sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} else {
@ -158,10 +163,11 @@ export class CoreRichTextEditorComponent {
* Check if text is empty.
* @param {string} value text
*/
private isNullOrWhiteSpace(value: string) {
if (value == null || typeof value == "undefined") {
protected isNullOrWhiteSpace(value: string): boolean {
if (value == null || typeof value == 'undefined') {
return true;
}
value = value.replace(/[\n\r]/g, '');
value = value.split(' ').join('');
@ -171,7 +177,7 @@ export class CoreRichTextEditorComponent {
/**
* Clear the text.
*/
clearText() {
clearText(): void {
this.editorElement.innerHTML = '<p></p>';
this.textarea.value = '';
this.control.setValue(null);
@ -185,7 +191,7 @@ export class CoreRichTextEditorComponent {
* @param {string} command Command to execute.
* @param {any} [parameters] Parameters of the command.
*/
private buttonAction($event: any, command: string, parameters: any = null) {
protected buttonAction($event: any, command: string, parameters: any = null): void {
$event.preventDefault();
$event.stopPropagation();
document.execCommand(command, false, parameters);

View File

@ -31,20 +31,20 @@ import { CoreUtilsProvider } from '../../providers/utils/utils';
templateUrl: 'search-box.html'
})
export class CoreSearchBoxComponent implements OnInit {
@Input() initialValue?: string = ''; // Initial value for search text.
@Input() initialValue? = ''; // Initial value for search text.
@Input() searchLabel?: string; // Label to be used on action button.
@Input() placeholder?: string; // Placeholder text for search text input.
@Input() autocorrect?: string = 'on'; // Enables/disable Autocorrection on search text input.
@Input() autocorrect? = 'on'; // Enables/disable Autocorrection on search text input.
@Input() spellcheck?: string | boolean = true; // Enables/disable Spellchecker on search text input.
@Input() autoFocus?: string | boolean; // Enables/disable Autofocus when entering view.
@Input() lengthCheck?: number = 3; // Check value length before submit. If 0, any string will be submitted.
@Input() lengthCheck? = 3; // Check value length before submit. If 0, any string will be submitted.
@Output() onSubmit: EventEmitter<string>; // Send data when submitting the search form.
constructor(private translate: TranslateService, private utils: CoreUtilsProvider) {
this.onSubmit = new EventEmitter();
}
ngOnInit() {
ngOnInit(): void {
this.searchLabel = this.searchLabel || this.translate.instant('core.search');
this.placeholder = this.placeholder || this.translate.instant('core.search');
this.spellcheck = this.utils.isTrueOrOne(this.spellcheck);
@ -55,7 +55,7 @@ export class CoreSearchBoxComponent implements OnInit {
*
* @param {string} value Entered value.
*/
submitForm(value: string) {
submitForm(value: string): void {
if (value.length < this.lengthCheck) {
// The view should handle this case, but we check it here too just in case.
return;
@ -63,5 +63,4 @@ export class CoreSearchBoxComponent implements OnInit {
this.onSubmit.emit(value);
}
}

View File

@ -40,7 +40,7 @@ export class CoreShowPasswordComponent implements OnInit, AfterViewInit {
shown: boolean; // Whether the password is shown.
label: string; // Label for the button to show/hide.
iconName: string; // Name of the icon of the button to show/hide.
selector: string = ''; // Selector to identify the input.
selector = ''; // Selector to identify the input.
protected input: HTMLInputElement; // Input affected.
protected element: HTMLElement; // Current element.
@ -52,7 +52,7 @@ export class CoreShowPasswordComponent implements OnInit, AfterViewInit {
/**
* Component being initialized.
*/
ngOnInit() {
ngOnInit(): void {
this.shown = this.utils.isTrueOrOne(this.initialShown);
this.selector = 'input[name="' + this.name + '"]';
this.setData();
@ -61,14 +61,14 @@ export class CoreShowPasswordComponent implements OnInit, AfterViewInit {
/**
* View has been initialized.
*/
ngAfterViewInit() {
ngAfterViewInit(): void {
this.searchInput();
}
/**
* Search the input to show/hide.
*/
protected searchInput() {
protected searchInput(): void {
// Search the input.
this.input = <HTMLInputElement> this.element.querySelector(this.selector);
@ -89,7 +89,7 @@ export class CoreShowPasswordComponent implements OnInit, AfterViewInit {
/**
* Set label, icon name and input type.
*/
protected setData() {
protected setData(): void {
this.label = this.shown ? 'core.hide' : 'core.show';
this.iconName = this.shown ? 'eye-off' : 'eye';
if (this.input) {

View File

@ -40,12 +40,12 @@ export class CoreSitePickerComponent implements OnInit {
this.siteSelected = new EventEmitter();
}
ngOnInit() {
ngOnInit(): void {
this.selectedSite = this.initialSite || this.sitesProvider.getCurrentSiteId();
// Load the sites.
this.sitesProvider.getSites().then((sites) => {
let promises = [];
const promises = [];
sites.forEach((site: any) => {
// Format the site name.

View File

@ -17,13 +17,15 @@
import { Component } from '@angular/core';
import { IonicPage } from 'ionic-angular';
@IonicPage({segment: "core-placeholder"})
@IonicPage({ segment: 'core-placeholder' })
@Component({
selector: 'core-placeholder',
templateUrl: 'placeholder.html',
})
export class CoreSplitViewPlaceholderPage {
constructor() { }
constructor() {
// Nothing to do.
}
}

View File

@ -44,9 +44,9 @@ export class CoreSplitViewComponent implements OnInit {
// @todo Mix both panels header buttons
@ViewChild('detailNav') detailNav: Nav;
@Input() when?: string | boolean = "md"; //
protected isEnabled: boolean = false;
protected masterPageName: string = "";
@Input() when?: string | boolean = 'md';
protected isEnabled = false;
protected masterPageName = '';
protected loadDetailPage: any = false;
protected element: HTMLElement; // Current element.
@ -60,7 +60,7 @@ export class CoreSplitViewComponent implements OnInit {
/**
* Component being initialized.
*/
ngOnInit() {
ngOnInit(): void {
// Get the master page name and set an empty page as a placeholder.
this.masterPageName = this.masterNav.getActive().component.name;
this.emptyDetails();
@ -81,7 +81,7 @@ export class CoreSplitViewComponent implements OnInit {
* @param {any} page The component class or deeplink name you want to push onto the navigation stack.
* @param {any} params Any NavParams you want to pass along to the next view.
*/
push(page: any, params?: any, element?: HTMLElement) {
push(page: any, params?: any, element?: HTMLElement): void {
if (this.isEnabled) {
this.detailNav.setRoot(page, params);
} else {
@ -96,7 +96,7 @@ export class CoreSplitViewComponent implements OnInit {
/**
* Set the details panel to default info.
*/
emptyDetails() {
emptyDetails(): void {
this.loadDetailPage = false;
this.detailNav.setRoot('CoreSplitViewPlaceholderPage');
}
@ -106,7 +106,7 @@ export class CoreSplitViewComponent implements OnInit {
*
* @param {Boolean} isOn If it fits both panels at the same time.
*/
onSplitPaneChanged(isOn) {
onSplitPaneChanged(isOn: boolean): void {
this.isEnabled = isOn;
if (this.masterNav && this.detailNav) {
(isOn) ? this.activateSplitView() : this.deactivateSplitView();
@ -116,14 +116,14 @@ export class CoreSplitViewComponent implements OnInit {
/**
* Enable the split view, show both panels and do some magical navigation.
*/
activateSplitView() {
let currentView = this.masterNav.getActive(),
activateSplitView(): void {
const currentView = this.masterNav.getActive(),
currentPageName = currentView.component.name;
if (currentPageName != this.masterPageName) {
// CurrentView is a 'Detail' page remove it from the 'master' nav stack.
this.masterNav.pop();
// and add it to the 'detail' nav stack.
// And add it to the 'detail' nav stack.
this.detailNav.setRoot(currentView.component, currentView.data);
} else if (this.loadDetailPage) {
// MasterPage is shown, load the last detail page if found.
@ -135,8 +135,8 @@ export class CoreSplitViewComponent implements OnInit {
/**
* Disabled the split view, show only one panel and do some magical navigation.
*/
deactivateSplitView() {
let detailView = this.detailNav.getActive(),
deactivateSplitView(): void {
const detailView = this.detailNav.getActive(),
currentPageName = detailView.component.name;
if (currentPageName != 'CoreSplitViewPlaceholderPage') {
// Current detail view is a 'Detail' page so, not the placeholder page, push it on 'master' nav stack.

View File

@ -44,12 +44,12 @@ export class CoreTabComponent implements OnInit, OnDestroy {
@Input() icon?: string; // The tab icon.
@Input() badge?: string; // A badge to add in the tab.
@Input() badgeStyle?: string; // The badge color.
@Input() enabled?: boolean = true; // Whether the tab is enabled.
@Input() show?: boolean = true; // Whether the tab should be shown.
@Input() enabled? = true; // Whether the tab is enabled.
@Input() show? = true; // Whether the tab should be shown.
@Input() id?: string; // An ID to identify the tab.
@Output() ionSelect: EventEmitter<CoreTabComponent> = new EventEmitter<CoreTabComponent>();
@ContentChild(TemplateRef) template: TemplateRef<any> // Template defined by the content.
@ContentChild(TemplateRef) template: TemplateRef<any>; // Template defined by the content.
@ContentChild(Content) scroll: Content;
element: HTMLElement; // The core-tab element.
@ -62,21 +62,21 @@ export class CoreTabComponent implements OnInit, OnDestroy {
/**
* Component being initialized.
*/
ngOnInit() {
ngOnInit(): void {
this.tabs.addTab(this);
}
/**
* Component destroyed.
*/
ngOnDestroy() {
ngOnDestroy(): void {
this.tabs.removeTab(this);
}
/**
* Select tab.
*/
selectTab() {
selectTab(): void {
this.element.classList.add('selected');
this.loaded = true;
@ -85,9 +85,9 @@ export class CoreTabComponent implements OnInit, OnDestroy {
// Setup tab scrolling.
setTimeout(() => {
if (this.scroll) {
this.scroll.getScrollElement().onscroll = (e) => {
this.scroll.getScrollElement().onscroll = (e): void => {
this.tabs.showHideTabs(e);
}
};
}
}, 1);
}
@ -95,7 +95,7 @@ export class CoreTabComponent implements OnInit, OnDestroy {
/**
* Unselect tab.
*/
unselectTab() {
unselectTab(): void {
this.element.classList.remove('selected');
}
}

View File

@ -12,8 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, Output, EventEmitter, OnInit, OnChanges, AfterViewInit, ViewChild, ElementRef,
SimpleChange } from '@angular/core';
import {
Component, Input, Output, EventEmitter, OnInit, OnChanges, AfterViewInit, ViewChild, ElementRef,
SimpleChange
} from '@angular/core';
import { CoreTabComponent } from './tab';
import { Content } from 'ionic-angular';
@ -40,7 +42,7 @@ import { Content } from 'ionic-angular';
templateUrl: 'tabs.html'
})
export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
@Input() selectedIndex?: number = 0; // Index of the tab to select.
@Input() selectedIndex = 0; // Index of the tab to select.
@Input() hideUntil: boolean; // Determine when should the contents be shown.
@Output() ionChange: EventEmitter<CoreTabComponent> = new EventEmitter<CoreTabComponent>(); // Emitted when the tab changes.
@ViewChild('originalTabs') originalTabsRef: ElementRef;
@ -70,7 +72,7 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
/**
* Component being initialized.
*/
ngOnInit() {
ngOnInit(): void {
this.originalTabsContainer = this.originalTabsRef.nativeElement;
this.topTabsElement = this.topTabs.nativeElement;
}
@ -78,7 +80,7 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
/**
* View has been initialized.
*/
ngAfterViewInit() {
ngAfterViewInit(): void {
this.afterViewInitTriggered = true;
if (!this.initialized && this.hideUntil) {
// Tabs should be shown, initialize them.
@ -89,7 +91,7 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
/**
* Detect changes on input properties.
*/
ngOnChanges(changes: {[name: string]: SimpleChange}) {
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
// We need to wait for ngAfterViewInit because we need core-tab components to be executed.
if (!this.initialized && this.hideUntil && this.afterViewInitTriggered) {
// Tabs should be shown, initialize them.
@ -121,11 +123,12 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
*/
getIndex(tab: any): number {
for (let i = 0; i < this.tabs.length; i++) {
let t = this.tabs[i];
const t = this.tabs[i];
if (t === tab || (typeof t.id != 'undefined' && t.id === tab.id)) {
return i;
}
}
return -1;
}
@ -150,8 +153,10 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
selectedTab = this.tabs.find((tab, index) => {
if (tab.enabled && tab.show) {
selectedIndex = index;
return true;
}
return false;
});
}
@ -236,13 +241,13 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
/**
* Sort the tabs, keeping the same order as in the original list.
*/
protected sortTabs() {
protected sortTabs(): void {
if (this.originalTabsContainer) {
let newTabs = [],
newSelected;
const newTabs = [];
let newSelected;
this.tabs.forEach((tab, index) => {
let originalIndex = Array.prototype.indexOf.call(this.originalTabsContainer.children, tab.element);
const originalIndex = Array.prototype.indexOf.call(this.originalTabsContainer.children, tab.element);
if (originalIndex != -1) {
newTabs[originalIndex] = tab;
if (this.selected == index) {

View File

@ -16,34 +16,34 @@
* Static class to contain all the core constants.
*/
export class CoreConstants {
public static SECONDS_YEAR = 31536000;
public static SECONDS_WEEK = 604800;
public static SECONDS_DAY = 86400;
public static SECONDS_HOUR = 3600;
public static SECONDS_MINUTE = 60;
public static WIFI_DOWNLOAD_THRESHOLD = 104857600; // 100MB.
public static DOWNLOAD_THRESHOLD = 10485760; // 10MB.
public static DONT_SHOW_ERROR = 'CoreDontShowError';
public static NO_SITE_ID = 'NoSite';
static SECONDS_YEAR = 31536000;
static SECONDS_WEEK = 604800;
static SECONDS_DAY = 86400;
static SECONDS_HOUR = 3600;
static SECONDS_MINUTE = 60;
static WIFI_DOWNLOAD_THRESHOLD = 104857600; // 100MB.
static DOWNLOAD_THRESHOLD = 10485760; // 10MB.
static DONT_SHOW_ERROR = 'CoreDontShowError';
static NO_SITE_ID = 'NoSite';
// Settings constants.
public static SETTINGS_RICH_TEXT_EDITOR = 'CoreSettingsRichTextEditor';
public static SETTINGS_NOTIFICATION_SOUND = 'CoreSettingsNotificationSound';
public static SETTINGS_SYNC_ONLY_ON_WIFI = 'CoreSettingsSyncOnlyOnWifi';
static SETTINGS_RICH_TEXT_EDITOR = 'CoreSettingsRichTextEditor';
static SETTINGS_NOTIFICATION_SOUND = 'CoreSettingsNotificationSound';
static SETTINGS_SYNC_ONLY_ON_WIFI = 'CoreSettingsSyncOnlyOnWifi';
// WS constants.
public static WS_TIMEOUT = 30000;
public static WS_PREFIX = 'local_mobile_';
static WS_TIMEOUT = 30000;
static WS_PREFIX = 'local_mobile_';
// Login constants.
public static LOGIN_SSO_CODE = 2; // SSO in browser window is required.
public static LOGIN_SSO_INAPP_CODE = 3; // SSO in embedded browser is required.
public static LOGIN_LAUNCH_DATA = 'CoreLoginLaunchData';
static LOGIN_SSO_CODE = 2; // SSO in browser window is required.
static LOGIN_SSO_INAPP_CODE = 3; // SSO in embedded browser is required.
static LOGIN_LAUNCH_DATA = 'CoreLoginLaunchData';
// Download status constants.
public static DOWNLOADED = 'downloaded';
public static DOWNLOADING = 'downloading';
public static NOT_DOWNLOADED = 'notdownloaded';
public static OUTDATED = 'outdated';
public static NOT_DOWNLOADABLE = 'notdownloadable';
static DOWNLOADED = 'downloaded';
static DOWNLOADING = 'downloading';
static NOT_DOWNLOADED = 'notdownloaded';
static OUTDATED = 'outdated';
static NOT_DOWNLOADABLE = 'notdownloadable';
}

View File

@ -54,7 +54,9 @@ export class CoreContentLinksHandlerBase implements CoreContentLinksHandler {
*/
pattern?: RegExp;
constructor() {}
constructor() {
// Nothing to do.
}
/**
* Get the list of actions for a link (url).
@ -88,7 +90,7 @@ export class CoreContentLinksHandlerBase implements CoreContentLinksHandler {
*/
getSiteUrl(url: string): string {
if (this.pattern) {
var position = url.search(this.pattern);
const position = url.search(this.pattern);
if (position > -1) {
return url.substr(0, position);
}

View File

@ -64,6 +64,7 @@ export class CoreContentLinksModuleGradeHandler extends CoreContentLinksHandlerB
CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
courseId = courseId || params.courseid || params.cid;
return [{
action: (siteId, navCtrl?): void => {
// Check if userid is the site's current user.

View File

@ -54,8 +54,9 @@ export class CoreContentLinksModuleIndexHandler extends CoreContentLinksHandlerB
CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
courseId = courseId || params.courseid || params.cid;
return [{
action: (siteId, navCtrl?) => {
action: (siteId, navCtrl?): void => {
this.courseHelper.navigateToModule(parseInt(params.id, 10), siteId, courseId);
}
}];

View File

@ -43,7 +43,7 @@ export class CoreContentLinksChooseSitePage implements OnInit {
/**
* Component being initialized.
*/
ngOnInit() {
ngOnInit(): void {
if (!this.url) {
return this.leaveView();
}
@ -86,10 +86,9 @@ export class CoreContentLinksChooseSitePage implements OnInit {
/**
* Cancel and leave the view.
*/
protected leaveView() {
protected leaveView(): void {
this.sitesProvider.logout().finally(() => {
this.navCtrl.setRoot('CoreLoginSitesPage');
});
}
}

View File

@ -88,7 +88,7 @@ export interface CoreContentLinksHandler {
* @return {boolean|Promise<boolean>} Whether the handler is enabled for the URL and site.
*/
isEnabled?(siteId: string, url: string, params: any, courseId?: number): boolean | Promise<boolean>;
};
}
/**
* Action to perform when a link is clicked.
@ -119,7 +119,7 @@ export interface CoreContentLinksAction {
* @param {NavController} [navCtrl] Nav Controller to use to navigate.
*/
action(siteId: string, navCtrl?: NavController): void;
};
}
/**
* Actions and priority for a handler and URL.
@ -136,7 +136,7 @@ export interface CoreContentLinksHandlerActions {
* @type {CoreContentLinksAction[]}
*/
actions: CoreContentLinksAction[];
};
}
/**
* Delegate to register handlers to handle links.
@ -170,7 +170,7 @@ export class CoreContentLinksDelegate {
promises = [],
params = this.urlUtils.extractUrlParams(url);
for (let name in this.handlers) {
for (const name in this.handlers) {
const handler = this.handlers[name],
checkAll = handler.checkAllUsers,
isEnabledFn = this.isHandlerEnabled.bind(this, handler, url, params, courseId);
@ -192,8 +192,8 @@ export class CoreContentLinksDelegate {
// Set default values if any value isn't supplied.
actions.forEach((action) => {
action.message = action.message || 'core.view';
action.icon = action.icon || 'eye';
action.sites = action.sites || siteIds;
action.icon = action.icon || 'eye';
action.sites = action.sites || siteIds;
});
// Add them to the list.
@ -227,7 +227,7 @@ export class CoreContentLinksDelegate {
}
// Check if any handler supports this URL.
for (let name in this.handlers) {
for (const name in this.handlers) {
const handler = this.handlers[name],
siteUrl = handler.getSiteUrl(url);
@ -264,7 +264,7 @@ export class CoreContentLinksDelegate {
}
if (!handler.isEnabled) {
// isEnabled function not provided, assume it's enabled.
// Handler doesn't implement isEnabled, assume it's enabled.
return true;
}
@ -281,10 +281,12 @@ export class CoreContentLinksDelegate {
registerHandler(handler: CoreContentLinksHandler): boolean {
if (typeof this.handlers[handler.name] !== 'undefined') {
this.logger.log(`Addon '${handler.name}' already registered`);
return false;
}
this.logger.log(`Registered addon '${handler.name}'`);
this.handlers[handler.name] = handler;
return true;
}
@ -306,6 +308,7 @@ export class CoreContentLinksDelegate {
actions.forEach((entry) => {
sorted = sorted.concat(entry.actions);
});
return sorted;
}
}

View File

@ -100,14 +100,14 @@ export class CoreContentLinksHelperProvider {
return false;
}
const modal = this.domUtils.showModalLoading();
let username;
url = decodeURIComponent(url);
// App opened using custom URL scheme.
this.logger.debug('Treating custom URL scheme: ' + url);
let modal = this.domUtils.showModalLoading(),
username;
// Delete the scheme from the URL.
url = url.replace(contentLinksScheme + '=', '');
@ -124,6 +124,7 @@ export class CoreContentLinksHelperProvider {
}).then((siteIds) => {
if (siteIds.length) {
modal.dismiss(); // Dismiss modal so it doesn't collide with confirms.
return this.handleLink(url, username).then((treated) => {
if (!treated) {
this.domUtils.showErrorModal('core.contentlinks.errornoactions', true);
@ -134,14 +135,14 @@ export class CoreContentLinksHelperProvider {
const siteUrl = this.contentLinksDelegate.getSiteUrl(url);
if (!siteUrl) {
this.domUtils.showErrorModal('core.login.invalidsite', true);
return;
}
// Check that site exists.
return this.sitesProvider.checkSite(siteUrl).then((result) => {
// Site exists. We'll allow to add it.
let promise,
ssoNeeded = this.loginHelper.isSSOLoginNeeded(result.code),
const ssoNeeded = this.loginHelper.isSSOLoginNeeded(result.code),
hasRemoteAddonsLoaded = false,
pageName = 'CoreLoginCredentialsPage',
pageParams = {
@ -150,6 +151,7 @@ export class CoreContentLinksHelperProvider {
urlToOpen: url,
siteConfig: result.config
};
let promise;
modal.dismiss(); // Dismiss modal so it doesn't collide with confirms.
@ -161,7 +163,7 @@ export class CoreContentLinksHelperProvider {
const confirmMsg = this.translate.instant('core.contentlinks.confirmurlothersite');
promise = this.domUtils.showConfirm(confirmMsg).then(() => {
if (!ssoNeeded) {
// hasRemoteAddonsLoaded = $mmAddonManager.hasRemoteAddonsLoaded(); @todo
// @todo hasRemoteAddonsLoaded = $mmAddonManager.hasRemoteAddonsLoaded(); @todo
if (hasRemoteAddonsLoaded) {
// Store the redirect since logout will restart the app.
this.appProvider.storeRedirect(CoreConstants.NO_SITE_ID, pageName, pageParams);
@ -230,8 +232,10 @@ export class CoreContentLinksHelperProvider {
}
});
}
return true;
}
return false;
}).catch(() => {
return false;

View File

@ -37,7 +37,7 @@ import { CoreConstants } from '../../constants';
* @return {Promise<string>} Promise resolved when the prefetch finishes. The string returned will be stored as "extra" data in the
* filepool package. If you don't need to store extra data, don't return anything.
*/
export type prefetchFunction = (module: any, courseId: number, single: boolean, siteId: string, ...args) => Promise<string>;
export type prefetchFunction = (module: any, courseId: number, single: boolean, siteId: string, ...args: any[]) => Promise<string>;
/**
* Base prefetch handler to be registered in CoreCourseModulePrefetchDelegate. It is useful to minimize the amount of
@ -90,8 +90,8 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
*/
protected downloadPromises: { [s: string]: { [s: string]: Promise<any> } } = {};
// List of services that will be injected using injector. It's done like this so subclasses don't have to send all the
// services to the parent in the constructor.
// List of services that will be injected using injector.
// It's done like this so subclasses don't have to send all the services to the parent in the constructor.
protected translate: TranslateService;
protected appProvider: CoreAppProvider;
protected courseProvider: CoreCourseProvider;
@ -169,7 +169,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
// Get the intro files.
return this.getIntroFiles(module, courseId);
}).then((introFiles) => {
let downloadFn = prefetch ? this.filepoolProvider.prefetchPackage.bind(this.filepoolProvider) :
const downloadFn = prefetch ? this.filepoolProvider.prefetchPackage.bind(this.filepoolProvider) :
this.filepoolProvider.downloadPackage.bind(this.filepoolProvider),
contentFiles = this.getContentDownloadableFiles(module),
promises = [];
@ -183,7 +183,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
promises.push(downloadFn(siteId, contentFiles, this.component, module.id, undefined, dirPath));
} else {
// No dirPath, download everything in filepool root folder.
let files = introFiles.concat(contentFiles);
const files = introFiles.concat(contentFiles);
promises.push(downloadFn(siteId, files, this.component, module.id));
}
@ -197,8 +197,8 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
* @param {any} module The module object returned by WS.
* @return {any[]} List of files.
*/
getContentDownloadableFiles(module: any) {
let files = [];
getContentDownloadableFiles(module: any): any[] {
const files = [];
if (module.contents && module.contents.length) {
module.contents.forEach((content) => {
@ -237,6 +237,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
*/
getDownloadedSize?(module: any, courseId: number): number | Promise<number> {
const siteId = this.sitesProvider.getCurrentSiteId();
return this.filepoolProvider.getFilesSizeByComponent(siteId, this.component, module.id);
}
@ -275,7 +276,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
* @param {any} [instance] The instance to get the intro files (book, assign, ...). If not defined, module will be used.
* @return {any[]} List of intro files.
*/
getIntroFilesFromInstance(module: any, instance?: any) {
getIntroFilesFromInstance(module: any, instance?: any): any[] {
if (instance) {
if (typeof instance.introfiles != 'undefined') {
return instance.introfiles;
@ -305,6 +306,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
// There's already a download ongoing, return the promise.
return this.downloadPromises[siteId][this.getUniqueId(id)];
}
return Promise.resolve();
}
@ -314,7 +316,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
* @param {number} id Unique ID inside component.
* @return {string} Unique ID.
*/
getUniqueId(id: number) {
getUniqueId(id: number): string {
return this.component + '#' + id;
}
@ -363,10 +365,11 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
*
* @param {number} id Unique identifier per component.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Boolean} True if downloading, false otherwise.
* @return {boolean} True if downloading, false otherwise.
*/
isDownloading(id: number, siteId?: string): boolean {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
return !!(this.downloadPromises[siteId] && this.downloadPromises[siteId][this.getUniqueId(id)]);
}
@ -401,6 +404,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
if (this.isResource) {
return this.courseProvider.loadModuleContents(module, courseId, undefined, false, ignoreCache);
}
return Promise.resolve();
}
@ -432,8 +436,8 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when the module has been downloaded. Data returned is not reliable.
*/
prefetchPackage(module: any, courseId: number, single: boolean, downloadFn: prefetchFunction, siteId?: string, ...args) :
Promise<any> {
prefetchPackage(module: any, courseId: number, single: boolean, downloadFn: prefetchFunction, siteId?: string, ...args: any[])
: Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
if (!this.appProvider.isOnline()) {
@ -471,6 +475,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
*/
setDownloaded(id: number, siteId?: string, extra?: string): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.filepoolProvider.storePackageStatus(siteId, CoreConstants.DOWNLOADED, this.component, id, extra);
}
@ -483,6 +488,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
*/
setDownloading(id: number, siteId?: string): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.filepoolProvider.storePackageStatus(siteId, CoreConstants.DOWNLOADING, this.component, id);
}
@ -496,6 +502,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
*/
setPreviousStatusAndReject(id: number, error?: any, siteId?: string): Promise<never> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.filepoolProvider.setPackagePreviousStatus(siteId, this.component, id).then(() => {
return Promise.reject(error);
});

View File

@ -12,8 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, OnInit, OnChanges, OnDestroy, ViewContainerRef, ComponentFactoryResolver, ViewChild, ChangeDetectorRef,
SimpleChange, Output, EventEmitter } from '@angular/core';
import {
Component, Input, OnInit, OnChanges, OnDestroy, ViewContainerRef, ComponentFactoryResolver, ViewChild, ChangeDetectorRef,
SimpleChange, Output, EventEmitter
} from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreEventsProvider } from '../../../../providers/events';
import { CoreLoggerProvider } from '../../../../providers/logger';
@ -54,19 +56,19 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
// The component hasn't been initialized yet. Store the container.
this.componentContainers['courseFormat'] = el;
}
};
}
@ViewChild('courseSummary', { read: ViewContainerRef }) set courseSummary(el: ViewContainerRef) {
this.createComponent('courseSummary', this.cfDelegate.getCourseSummaryComponent(this.course), el);
};
}
@ViewChild('sectionSelector', { read: ViewContainerRef }) set sectionSelector(el: ViewContainerRef) {
this.createComponent('sectionSelector', this.cfDelegate.getSectionSelectorComponent(this.course), el);
};
}
@ViewChild('singleSection', { read: ViewContainerRef }) set singleSection(el: ViewContainerRef) {
this.createComponent('singleSection', this.cfDelegate.getSingleSectionComponent(this.course), el);
};
}
@ViewChild('allSections', { read: ViewContainerRef }) set allSections(el: ViewContainerRef) {
this.createComponent('allSections', this.cfDelegate.getAllSectionsComponent(this.course), el);
};
}
// Instances and containers of all the components that the handler could define.
protected componentContainers: { [type: string]: ViewContainerRef } = {};
@ -95,9 +97,9 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
this.sectionStatusObserver = eventsProvider.on(CoreEventsProvider.SECTION_STATUS_CHANGED, (data) => {
if (this.downloadEnabled && this.sections && this.sections.length && this.course && data.sectionId &&
data.courseId == this.course.id) {
// Check if the affected section is being downloaded. If so, we don't update section status
// because it'll already be updated when the download finishes.
let downloadId = this.courseHelper.getSectionDownloadId({id: data.sectionId});
// Check if the affected section is being downloaded.
// If so, we don't update section status because it'll already be updated when the download finishes.
const downloadId = this.courseHelper.getSectionDownloadId({ id: data.sectionId });
if (prefetchDelegate.isBeingDownloaded(downloadId)) {
return;
}
@ -105,7 +107,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
// Get the affected section.
let section;
for (let i = 0; i < this.sections.length; i++) {
let s = this.sections[i];
const s = this.sections[i];
if (s.id === data.sectionId) {
section = s;
break;
@ -131,7 +133,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
/**
* Component being initialized.
*/
ngOnInit() {
ngOnInit(): void {
this.displaySectionSelector = this.cfDelegate.displaySectionSelector(this.course);
this.createComponent(
@ -141,14 +143,14 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
/**
* Detect changes on input properties.
*/
ngOnChanges(changes: {[name: string]: SimpleChange}) {
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
if (changes.sections && this.sections) {
if (!this.selectedSection) {
// There is no selected section yet, calculate which one to load.
if (this.initialSectionId || this.initialSectionNumber) {
// We have an input indicating the section ID to load. Search the section.
for (let i = 0; i < this.sections.length; i++) {
let section = this.sections[i];
const section = this.sections[i];
if (section.id == this.initialSectionId || section.section == this.initialSectionNumber) {
this.loaded = true;
this.sectionChanged(section);
@ -166,7 +168,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
// We have a selected section, but the list has changed. Search the section in the list.
let newSection;
for (let i = 0; i < this.sections.length; i++) {
let section = this.sections[i];
const section = this.sections[i];
if (this.compareSections(section, this.selectedSection)) {
newSection = section;
break;
@ -186,10 +188,10 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
}
// Apply the changes to the components and call ngOnChanges if it exists.
for (let type in this.componentInstances) {
let instance = this.componentInstances[type];
for (const type in this.componentInstances) {
const instance = this.componentInstances[type];
for (let name in changes) {
for (const name in changes) {
instance[name] = changes[name].currentValue;
}
@ -238,6 +240,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
return true;
} catch (ex) {
this.logger.error('Error creating component', type, ex);
return false;
}
}
@ -247,8 +250,8 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
*
* @param {any} newSection The new selected section.
*/
sectionChanged(newSection: any) {
let previousValue = this.selectedSection;
sectionChanged(newSection: any): void {
const previousValue = this.selectedSection;
this.selectedSection = newSection;
// If there is a component to render the current section, update its section.
@ -314,7 +317,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
* @param {boolean} [manual] Whether the prefetch was started manually or it was automatically started because all modules
* are being downloaded.
*/
protected prefetchSection(section: any, manual?: boolean) {
protected prefetchSection(section: any, manual?: boolean): void {
this.courseHelper.prefetchSection(section, this.course.id, this.sections).catch((error) => {
// Don't show error message if it's an automatic download.
if (!manual) {
@ -328,7 +331,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
/**
* Component destroyed.
*/
ngOnDestroy() {
ngOnDestroy(): void {
if (this.sectionStatusObserver) {
this.sectionStatusObserver.off();
}

View File

@ -48,7 +48,7 @@ export class CoreCourseModuleCompletionComponent implements OnChanges {
/**
* Detect changes on input properties.
*/
ngOnChanges(changes: {[name: string]: SimpleChange}) {
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
if (changes.completion && this.completion) {
this.showStatus();
}
@ -68,7 +68,7 @@ export class CoreCourseModuleCompletionComponent implements OnChanges {
e.preventDefault();
e.stopPropagation();
let modal = this.domUtils.showModalLoading(),
const modal = this.domUtils.showModalLoading(),
params = {
cmid: this.completion.cmid,
completed: this.completion.state === 1 ? 0 : 1
@ -93,8 +93,8 @@ export class CoreCourseModuleCompletionComponent implements OnChanges {
* Set image and description to show as completion icon.
*/
protected showStatus(): void {
const moduleName = this.moduleName || '';
let langKey,
moduleName = this.moduleName || '',
image;
if (this.completion.tracking === 1 && this.completion.state === 0) {

View File

@ -41,5 +41,7 @@ export class CoreCourseModuleDescriptionComponent {
@Input() componentId?: string | number; // Component ID to use in conjunction with the component.
@Input() showFull?: string | boolean; // Whether to always display the full description.
constructor() {}
constructor() {
// Nothing to do.
}
}

View File

@ -39,7 +39,7 @@ export class CoreCourseModuleComponent implements OnInit {
/**
* Component being initialized.
*/
ngOnInit() {
ngOnInit(): void {
// Handler data must be defined. If it isn't, set it to prevent errors.
if (this.module && !this.module.handlerData) {
this.module.handlerData = {};
@ -51,7 +51,7 @@ export class CoreCourseModuleComponent implements OnInit {
*
* @param {Event} event Click event.
*/
moduleClicked(event: Event) {
moduleClicked(event: Event): void {
if (this.module.uservisible !== false && this.module.handlerData.action) {
this.module.handlerData.action(event, this.navCtrl, this.module, this.courseId);
}
@ -63,7 +63,7 @@ export class CoreCourseModuleComponent implements OnInit {
* @param {Event} event Click event.
* @param {CoreCourseModuleHandlerButton} button The clicked button.
*/
buttonClicked(event: Event, button: CoreCourseModuleHandlerButton) {
buttonClicked(event: Event, button: CoreCourseModuleHandlerButton): void {
if (button && button.action) {
button.action(event, this.navCtrl, this.module, this.courseId);
}

View File

@ -36,7 +36,7 @@ export class CoreCourseUnsupportedModuleComponent implements OnInit {
/**
* Component being initialized.
*/
ngOnInit() {
ngOnInit(): void {
this.isDisabledInSite = this.moduleDelegate.isModuleDisabledInSite(this.module.modname);
this.isSupportedByTheApp = this.moduleDelegate.hasHandler(this.module.modname);
this.moduleName = this.courseProvider.translateModuleName(this.module.modname);

View File

@ -12,8 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, OnChanges, ViewContainerRef, ComponentFactoryResolver, ChangeDetectorRef,
SimpleChange } from '@angular/core';
import { Component, Input, OnChanges, ViewContainerRef, ComponentFactoryResolver, SimpleChange } from '@angular/core';
import { CoreLoggerProvider } from '../../../../../providers/logger';
import { CoreCourseModuleDelegate } from '../../../providers/module-delegate';
import { CoreCourseUnsupportedModuleComponent } from '../../../components/unsupported-module/unsupported-module';
@ -37,17 +36,17 @@ export class CoreCourseFormatSingleActivityComponent implements OnChanges {
protected componentInstance: any;
constructor(logger: CoreLoggerProvider, private viewRef: ViewContainerRef, private factoryResolver: ComponentFactoryResolver,
private cdr: ChangeDetectorRef, private moduleDelegate: CoreCourseModuleDelegate) {
private moduleDelegate: CoreCourseModuleDelegate) {
this.logger = logger.getInstance('CoreCourseFormatSingleActivityComponent');
}
/**
* Detect changes on input properties.
*/
ngOnChanges(changes: {[name: string]: SimpleChange}) {
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
if (this.course && this.sections && this.sections.length) {
// In single activity the module should only have 1 section and 1 module. Get the module.
let module = this.sections[0] && this.sections[0].modules && this.sections[0].modules[0];
const module = this.sections[0] && this.sections[0].modules && this.sections[0].modules[0];
if (module && !this.componentInstance) {
// We haven't created the component yet. Create it now.
this.createComponent(module);
@ -55,11 +54,11 @@ export class CoreCourseFormatSingleActivityComponent implements OnChanges {
if (this.componentInstance && this.componentInstance.ngOnChanges) {
// Call ngOnChanges of the component.
let newChanges: {[name: string]: SimpleChange} = {};
const newChanges: { [name: string]: SimpleChange } = {};
// Check if course has changed.
if (changes.course) {
newChanges.course = changes.course
newChanges.course = changes.course;
this.componentInstance.course = this.course;
}
@ -69,7 +68,7 @@ export class CoreCourseFormatSingleActivityComponent implements OnChanges {
currentValue: module,
firstChange: changes.sections.firstChange,
previousValue: this.module,
isFirstChange: () => {
isFirstChange: (): boolean => {
return newChanges.module.firstChange;
}
};
@ -91,7 +90,7 @@ export class CoreCourseFormatSingleActivityComponent implements OnChanges {
* @return {boolean} Whether the component was successfully created.
*/
protected createComponent(module: any): boolean {
let componentClass = this.moduleDelegate.getMainComponent(this.course, module) || CoreCourseUnsupportedModuleComponent;
const componentClass = this.moduleDelegate.getMainComponent(this.course, module) || CoreCourseUnsupportedModuleComponent;
if (!componentClass) {
// No component to instantiate.
return false;
@ -108,11 +107,10 @@ export class CoreCourseFormatSingleActivityComponent implements OnChanges {
this.componentInstance.courseId = this.course.id;
this.componentInstance.module = module;
// this.cdr.detectChanges(); // The instances are used in ngIf, tell Angular that something has changed.
return true;
} catch (ex) {
this.logger.error('Error creating component', ex);
return false;
}
}

View File

@ -23,7 +23,9 @@ import { CoreCourseFormatSingleActivityComponent } from '../components/format';
export class CoreCourseFormatSingleActivityHandler implements CoreCourseFormatHandler {
name = 'singleactivity';
constructor() {}
constructor() {
// Nothing to do.
}
/**
* Whether or not the handler is enabled on a site level.
@ -56,6 +58,7 @@ export class CoreCourseFormatSingleActivityHandler implements CoreCourseFormatHa
if (sections && sections[0] && sections[0].modules && sections[0].modules[0]) {
return sections[0].modules[0].name;
}
return course.fullname || '';
}

View File

@ -22,7 +22,9 @@ import { CoreCourseFormatHandler } from '../../../providers/format-delegate';
export class CoreCourseFormatTopicsHandler implements CoreCourseFormatHandler {
name = 'topics';
constructor() {}
constructor() {
// Nothing to do.
}
/**
* Whether or not the handler is enabled on a site level.

View File

@ -43,7 +43,7 @@ export class CoreCourseFormatWeeksHandler implements CoreCourseFormatHandler {
* @return {any|Promise<any>} Current section (or promise resolved with current section).
*/
getCurrentSection(course: any, sections: any[]): any | Promise<any> {
let now = this.timeUtils.timestamp();
const now = this.timeUtils.timestamp();
if (now < course.startdate || (course.enddate && now > course.enddate)) {
// Course hasn't started yet or it has ended already. Return the first section.
@ -51,12 +51,12 @@ export class CoreCourseFormatWeeksHandler implements CoreCourseFormatHandler {
}
for (let i = 0; i < sections.length; i++) {
let section = sections[i];
const section = sections[i];
if (typeof section.section == 'undefined' || section.section < 1) {
continue;
}
let dates = this.getSectionDates(section, course.startdate);
const dates = this.getSectionDates(section, course.startdate);
if ((now >= dates.start) && (now < dates.end)) {
return section;
}
@ -77,11 +77,12 @@ export class CoreCourseFormatWeeksHandler implements CoreCourseFormatHandler {
// Hack alert. We add 2 hours to avoid possible DST problems. (e.g. we go into daylight savings and the date changes).
startDate = startDate + 7200;
let dates = {
const dates = {
start: startDate + (CoreConstants.SECONDS_WEEK * (section.section - 1)),
end: 0
};
dates.end = dates.start + CoreConstants.SECONDS_WEEK;
return dates;
}
}

View File

@ -22,6 +22,7 @@ import { CoreTextUtilsProvider } from '../../../../providers/utils/text';
import { CoreCourseProvider } from '../../providers/course';
import { CoreCourseHelperProvider } from '../../providers/helper';
import { CoreCourseFormatDelegate } from '../../providers/format-delegate';
import { CoreCourseModulePrefetchDelegate } from '../../providers/module-prefetch-delegate';
import { CoreCourseOptionsDelegate, CoreCourseOptionsHandlerToDisplay } from '../../providers/options-delegate';
import { CoreCoursesProvider } from '../../../courses/providers/courses';
@ -44,7 +45,7 @@ export class CoreCourseSectionPage implements OnDestroy {
courseHandlers: CoreCourseOptionsHandlerToDisplay[];
dataLoaded: boolean;
downloadEnabled: boolean;
downloadEnabledIcon: string = 'square-outline'; // Disabled by default.
downloadEnabledIcon = 'square-outline'; // Disabled by default.
prefetchCourseData = {
prefetchCourseIcon: 'spinner'
};
@ -57,7 +58,8 @@ export class CoreCourseSectionPage implements OnDestroy {
private courseFormatDelegate: CoreCourseFormatDelegate, private courseOptionsDelegate: CoreCourseOptionsDelegate,
private translate: TranslateService, private courseHelper: CoreCourseHelperProvider, eventsProvider: CoreEventsProvider,
private textUtils: CoreTextUtilsProvider, private coursesProvider: CoreCoursesProvider,
sitesProvider: CoreSitesProvider, private navCtrl: NavController) {
sitesProvider: CoreSitesProvider, private navCtrl: NavController,
private prefetchDelegate: CoreCourseModulePrefetchDelegate) {
this.course = navParams.get('course');
this.sectionId = navParams.get('sectionId');
this.sectionNumber = navParams.get('sectionNumber');
@ -82,9 +84,9 @@ export class CoreCourseSectionPage implements OnDestroy {
/**
* View loaded.
*/
ionViewDidLoad() {
ionViewDidLoad(): void {
let module = this.navParams.get('module');
const module = this.navParams.get('module');
if (module) {
this.courseHelper.openModule(this.navCtrl, module, this.course.id, this.sectionId);
}
@ -118,11 +120,11 @@ export class CoreCourseSectionPage implements OnDestroy {
/**
* Fetch and load all the data required for the view.
*/
protected loadData(refresh?: boolean) {
protected loadData(refresh?: boolean): Promise<any> {
// First of all, get the course because the data might have changed.
return this.coursesProvider.getUserCourse(this.course.id).then((course) => {
let promises = [],
promise;
const promises = [];
let promise;
this.course = course;
@ -148,10 +150,10 @@ export class CoreCourseSectionPage implements OnDestroy {
section.formattedName = name;
});
section.hasContent = this.courseHelper.sectionHasContent(section);
return section;
});
if (this.courseFormatDelegate.canViewAllSections(this.course)) {
// Add a fake first section (all sections).
this.sections.unshift({
@ -181,7 +183,7 @@ export class CoreCourseSectionPage implements OnDestroy {
*
* @param {any} refresher Refresher.
*/
doRefresh(refresher: any) {
doRefresh(refresher: any): void {
this.invalidateData().finally(() => {
this.loadData(true).finally(() => {
refresher.complete();
@ -192,7 +194,7 @@ export class CoreCourseSectionPage implements OnDestroy {
/**
* The completion of any of the modules have changed.
*/
onCompletionChange() {
onCompletionChange(): void {
this.invalidateData().finally(() => {
this.refreshAfterCompletionChange();
});
@ -201,16 +203,16 @@ export class CoreCourseSectionPage implements OnDestroy {
/**
* Invalidate the data.
*/
protected invalidateData() {
let promises = [];
protected invalidateData(): Promise<any> {
const promises = [];
promises.push(this.courseProvider.invalidateSections(this.course.id));
promises.push(this.coursesProvider.invalidateUserCourses());
promises.push(this.courseFormatDelegate.invalidateData(this.course, this.sections));
// if ($scope.sections) {
// promises.push($mmCoursePrefetchDelegate.invalidateCourseUpdates(courseId));
// }
if (this.sections) {
promises.push(this.prefetchDelegate.invalidateCourseUpdates(this.course.id));
}
return Promise.all(promises);
}
@ -218,9 +220,9 @@ export class CoreCourseSectionPage implements OnDestroy {
/**
* Refresh list after a completion change since there could be new activities.
*/
protected refreshAfterCompletionChange() {
protected refreshAfterCompletionChange(): void {
// Save scroll position to restore it once done.
let scrollElement = this.content.getScrollElement(),
const scrollElement = this.content.getScrollElement(),
scrollTop = scrollElement.scrollTop || 0,
scrollLeft = scrollElement.scrollLeft || 0;
@ -235,8 +237,10 @@ export class CoreCourseSectionPage implements OnDestroy {
/**
* Determines the prefetch icon of the course.
*
* @return {Promise<void>} Promise resolved when done.
*/
protected determineCoursePrefetchIcon() {
protected determineCoursePrefetchIcon(): Promise<void> {
return this.courseHelper.getCourseStatusIcon(this.course.id).then((icon) => {
this.prefetchCourseData.prefetchCourseIcon = icon;
});
@ -245,7 +249,7 @@ export class CoreCourseSectionPage implements OnDestroy {
/**
* Prefetch the whole course.
*/
prefetchCourse() {
prefetchCourse(): void {
this.courseHelper.confirmAndPrefetchCourse(this.prefetchCourseData, this.course, this.sections, this.courseHandlers)
.then((downloaded) => {
if (downloaded && this.downloadEnabled) {
@ -264,7 +268,7 @@ export class CoreCourseSectionPage implements OnDestroy {
/**
* Toggle download enabled.
*/
toggleDownload() {
toggleDownload(): void {
this.downloadEnabled = !this.downloadEnabled;
this.downloadEnabledIcon = this.downloadEnabled ? 'checkbox-outline' : 'square-outline';
}
@ -272,7 +276,7 @@ export class CoreCourseSectionPage implements OnDestroy {
/**
* Page destroyed.
*/
ngOnDestroy() {
ngOnDestroy(): void {
this.isDestroyed = true;
if (this.completionObserver) {
this.completionObserver.off();

View File

@ -35,7 +35,7 @@ export class CoreCourseUnsupportedModulePage {
/**
* Expand the description.
*/
expandDescription() {
expandDescription(): void {
this.textUtils.expandText(this.translate.instant('core.description'), this.module.description);
}
}

View File

@ -27,9 +27,9 @@ import { CoreConstants } from '../../constants';
*/
@Injectable()
export class CoreCourseProvider {
public static ALL_SECTIONS_ID = -1;
public static ACCESS_GUEST = 'courses_access_guest';
public static ACCESS_DEFAULT = 'courses_access_default';
static ALL_SECTIONS_ID = -1;
static ACCESS_GUEST = 'courses_access_guest';
static ACCESS_DEFAULT = 'courses_access_default';
protected ROOT_CACHE_KEY = 'mmCourse:';
@ -126,7 +126,7 @@ export class CoreCourseProvider {
this.logger.debug(`Getting completion status for user ${userId} in course ${courseId}`);
let params = {
const params = {
courseid: courseId,
userid: userId
},
@ -138,6 +138,7 @@ export class CoreCourseProvider {
if (data && data.statuses) {
return this.utils.arrayToObject(data.statuses, 'cmid');
}
return Promise.reject(null);
});
});
@ -167,6 +168,7 @@ export class CoreCourseProvider {
if (!entry) {
return Promise.reject(null);
}
return entry;
});
});
@ -222,7 +224,7 @@ export class CoreCourseProvider {
// We have courseId, we can use core_course_get_contents for compatibility.
this.logger.debug(`Getting module ${moduleId} in course ${courseId}`);
let params = {
const params = {
courseid: courseId,
options: [
{
@ -253,15 +255,17 @@ export class CoreCourseProvider {
return this.getSections(courseId, false, false, preSets, siteId);
}).then((sections) => {
for (let i = 0; i < sections.length; i++) {
let section = sections[i];
const section = sections[i];
for (let j = 0; j < section.modules.length; j++) {
let module = section.modules[j];
const module = section.modules[j];
if (module.id == moduleId) {
module.course = courseId;
return module;
}
}
}
return Promise.reject(null);
});
});
@ -276,7 +280,7 @@ export class CoreCourseProvider {
*/
getModuleBasicInfo(moduleId: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
let params = {
const params = {
cmid: moduleId
},
preSets = {
@ -284,11 +288,12 @@ export class CoreCourseProvider {
};
return site.read('core_course_get_course_module', params, preSets).then((response) => {
if (response.warnings && response.warnings.length) {
if (response.warnings && response.warnings.length) {
return Promise.reject(response.warnings[0]);
} else if (response.cm) {
return response.cm;
}
return Promise.reject(null);
});
});
@ -303,7 +308,7 @@ export class CoreCourseProvider {
*/
getModuleBasicGradeInfo(moduleId: number, siteId?: string): Promise<any> {
return this.getModuleBasicInfo(moduleId, siteId).then((info) => {
let grade = {
const grade = {
advancedgrading: info.advancedgrading || false,
grade: info.grade || false,
gradecat: info.gradecat || false,
@ -315,6 +320,7 @@ export class CoreCourseProvider {
if (grade.grade !== false || grade.advancedgrading !== false || grade.outcomes !== false) {
return grade;
}
return false;
});
}
@ -329,7 +335,7 @@ export class CoreCourseProvider {
*/
getModuleBasicInfoByInstance(id: number, module: string, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
let params = {
const params = {
instance: id,
module: module
},
@ -338,11 +344,12 @@ export class CoreCourseProvider {
};
return site.read('core_course_get_course_module_by_instance', params, preSets).then((response) => {
if (response.warnings && response.warnings.length) {
if (response.warnings && response.warnings.length) {
return Promise.reject(response.warnings[0]);
} else if (response.cm) {
return response.cm;
}
return Promise.reject(null);
});
});
@ -443,7 +450,7 @@ export class CoreCourseProvider {
preSets.cacheKey = this.getSectionsCacheKey(courseId);
preSets.getCacheUsingCacheKey = true; // This is to make sure users don't lose offline access when updating.
let params = {
const params = {
courseid: courseId,
options: [
{
@ -458,8 +465,8 @@ export class CoreCourseProvider {
};
return site.read('core_course_get_contents', params, preSets).then((sections) => {
let siteHomeId = site.getSiteHomeId(),
showSections = true;
const siteHomeId = site.getSiteHomeId();
let showSections = true;
if (courseId == siteHomeId) {
showSections = site.getStoredConfig('numsections');
@ -481,7 +488,7 @@ export class CoreCourseProvider {
* @param {number} courseId Course ID.
* @return {string} Cache key.
*/
protected getSectionsCacheKey(courseId) : string {
protected getSectionsCacheKey(courseId: number): string {
return this.ROOT_CACHE_KEY + 'sections:' + courseId;
}
@ -492,7 +499,7 @@ export class CoreCourseProvider {
* @return {any[]} Modules.
*/
getSectionsModules(sections: any[]): any[] {
if (!sections || !sections.length) {
if (!sections || !sections.length) {
return [];
}
@ -502,6 +509,7 @@ export class CoreCourseProvider {
modules = modules.concat(section.modules);
}
});
return modules;
}
@ -542,7 +550,7 @@ export class CoreCourseProvider {
*/
invalidateSections(courseId: number, siteId?: string, userId?: number): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
let promises = [],
const promises = [],
siteHomeId = site.getSiteHomeId();
userId = userId || site.getUserId();
@ -552,6 +560,7 @@ export class CoreCourseProvider {
if (courseId == siteHomeId) {
promises.push(site.invalidateConfig());
}
return Promise.all(promises);
});
}
@ -588,9 +597,10 @@ export class CoreCourseProvider {
* @return {Promise<void>} Promise resolved when the WS call is successful.
*/
logView(courseId: number, sectionNumber?: number, siteId?: string): Promise<void> {
let params: any = {
const params: any = {
courseid: courseId
};
if (typeof sectionNumber != 'undefined') {
params.sectionnumber = sectionNumber;
}
@ -600,7 +610,7 @@ export class CoreCourseProvider {
if (!response.status) {
return Promise.reject(null);
}
})
});
});
}
@ -617,7 +627,7 @@ export class CoreCourseProvider {
this.logger.debug(`Set previous status for course ${courseId} in site ${siteId}`);
return this.sitesProvider.getSite(siteId).then((site) => {
let db = site.getDb(),
const db = site.getDb(),
newData: any = {};
// Get current stored data.
@ -634,6 +644,7 @@ export class CoreCourseProvider {
return db.updateRecords(this.COURSE_STATUS_TABLE, newData, { id: courseId }).then(() => {
// Success updating, trigger event.
this.triggerCourseStatusChanged(courseId, newData.status, siteId);
return newData.status;
});
});
@ -649,7 +660,7 @@ export class CoreCourseProvider {
* @return {Promise<void>} Promise resolved when the status is stored.
*/
setCourseStatus(courseId: number, status: string, siteId?: string): Promise<void> {
siteId = siteId || this.sitesProvider.getCurrentSiteId()
siteId = siteId || this.sitesProvider.getCurrentSiteId();
this.logger.debug(`Set status '${status}' for course ${courseId} in site ${siteId}`);
@ -669,7 +680,7 @@ export class CoreCourseProvider {
downloadTime = entry.downloadTime;
previousDownloadTime = entry.previousDownloadTime;
} else {
// downloadTime will be updated, store current time as previous.
// The downloadTime will be updated, store current time as previous.
previousDownloadTime = entry.downloadTime;
}
@ -679,7 +690,7 @@ export class CoreCourseProvider {
}).then((previousStatus) => {
if (previousStatus != status) {
// Status has changed, update it.
let data = {
const data = {
id: courseId,
status: status,
previous: previousStatus,

View File

@ -80,9 +80,9 @@ export class CoreCourseFormatDefaultHandler implements CoreCourseFormatHandler {
}).then((courses) => {
if (courses && courses[0]) {
// Find the marked section.
let course = courses[0];
const course = courses[0];
for (let i = 0; i < sections.length; i++) {
let section = sections[i];
const section = sections[i];
if (section.section == course.marker) {
return section;
}
@ -91,7 +91,7 @@ export class CoreCourseFormatDefaultHandler implements CoreCourseFormatHandler {
// Marked section not found or we couldn't retrieve the marker. Return the first section.
for (let i = 0; i < sections.length; i++) {
let section = sections[i];
const section = sections[i];
if (section.id != CoreCourseProvider.ALL_SECTIONS_ID) {
return section;
}

View File

@ -170,7 +170,7 @@ export class CoreCourseFormatDelegate extends CoreDelegate {
* @return {any} Function returned value or default value.
*/
protected executeFunction(format: string, fnName: string, params?: any[]): any {
let handler = this.enabledHandlers[format];
const handler = this.enabledHandlers[format];
if (handler && handler[fnName]) {
return handler[fnName].apply(handler, params);
} else if (this.defaultHandler[fnName]) {

View File

@ -125,7 +125,7 @@ export class CoreCourseHelperProvider {
* @param {any[]} [completionStatus] List of completion status.
* @return {boolean} Whether the sections have content.
*/
addHandlerDataForModules(sections: any[], courseId: number, completionStatus?: any) {
addHandlerDataForModules(sections: any[], courseId: number, completionStatus?: any): boolean {
let hasContent = false;
sections.forEach((section) => {
@ -200,9 +200,9 @@ export class CoreCourseHelperProvider {
* @return {Promise<void>} Promise resolved when the states are calculated.
*/
calculateSectionsStatus(sections: any[], courseId: number, refresh?: boolean): Promise<void> {
const promises = [];
let allSectionsSection,
allSectionsStatus,
promises = [];
allSectionsStatus;
sections.forEach((section) => {
if (section.id === CoreCourseProvider.ALL_SECTIONS_ID) {
@ -248,9 +248,10 @@ export class CoreCourseHelperProvider {
*/
confirmAndPrefetchCourse(iconData: any, course: any, sections?: any[], courseHandlers?: CoreCourseOptionsHandlerToDisplay[])
: Promise<boolean> {
let initialIcon = iconData.prefetchCourseIcon,
promise,
const initialIcon = iconData.prefetchCourseIcon,
siteId = this.sitesProvider.getCurrentSiteId();
let promise;
iconData.prefetchCourseIcon = 'spinner';
@ -284,10 +285,11 @@ export class CoreCourseHelperProvider {
if (error) {
return Promise.reject(error);
}
return false;
});
});
};
}
/**
* Confirm and prefetches a list of courses.
@ -301,13 +303,13 @@ export class CoreCourseHelperProvider {
// Confirm the download without checking size because it could take a while.
return this.domUtils.showConfirm(this.translate.instant('core.areyousure')).then(() => {
let promises = [],
total = courses.length,
count = 0;
const promises = [],
total = courses.length;
let count = 0;
courses.forEach((course) => {
let subPromises = [],
sections,
const subPromises = [];
let sections,
handlers,
success = true;
@ -323,6 +325,7 @@ export class CoreCourseHelperProvider {
return this.prefetchCourse(course, sections, handlers, siteId);
}).catch((error) => {
success = false;
return Promise.reject(error);
}).finally(() => {
// Course downloaded or failed, notify the progress.
@ -345,7 +348,7 @@ export class CoreCourseHelperProvider {
// User cancelled.
return false;
});
};
}
/**
* Show confirmation dialog and then remove a module files.
@ -376,7 +379,7 @@ export class CoreCourseHelperProvider {
if (section && section.id != CoreCourseProvider.ALL_SECTIONS_ID) {
sizePromise = this.prefetchDelegate.getDownloadSize(section.modules, courseId);
} else {
let promises = [],
const promises = [],
results = {
size: 0,
total: true
@ -423,6 +426,7 @@ export class CoreCourseHelperProvider {
for (let i = 1; i < statuses.length; i++) {
status = this.filepoolProvider.determinePackagesStatus(status, statuses[i]);
}
return status;
});
}
@ -436,6 +440,7 @@ export class CoreCourseHelperProvider {
*/
getCourseDownloadPromise(courseId: number, siteId?: string): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.courseDwnPromises[siteId] && this.courseDwnPromises[siteId][courseId];
}
@ -485,6 +490,7 @@ export class CoreCourseHelperProvider {
return cm.course;
}).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'core.course.errorgetmodule', true);
return Promise.reject(null);
});
}
@ -500,7 +506,7 @@ export class CoreCourseHelperProvider {
*/
getModulePrefetchInfo(module: any, courseId: number, invalidateCache?: boolean, component?: string)
: Promise<CoreCourseModulePrefetchInfo> {
let moduleInfo: CoreCourseModulePrefetchInfo = {},
const moduleInfo: CoreCourseModulePrefetchInfo = {},
siteId = this.sitesProvider.getCurrentSiteId(),
promises = [];
@ -514,19 +520,6 @@ export class CoreCourseHelperProvider {
}));
// @todo: Decide what to display instead of timemodified. Last check_updates?
// promises.push(this.prefetchDelegate.getModuleTimemodified(module, courseId).then(function(moduleModified) {
// moduleInfo.timemodified = moduleModified;
// if (moduleModified > 0) {
// var now = $mmUtil.timestamp();
// if (now - moduleModified < 7 * 86400) {
// moduleInfo.timemodifiedReadable = moment(moduleModified * 1000).fromNow();
// } else {
// moduleInfo.timemodifiedReadable = moment(moduleModified * 1000).calendar();
// }
// } else {
// moduleInfo.timemodifiedReadable = "";
// }
// }));
promises.push(this.prefetchDelegate.getModuleStatus(module, courseId).then((moduleStatus) => {
moduleInfo.status = moduleStatus;
@ -589,8 +582,8 @@ export class CoreCourseHelperProvider {
navigateToModule(moduleId: number, siteId?: string, courseId?: number, sectionId?: number): Promise<void> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
let modal = this.domUtils.showModalLoading(),
promise,
const modal = this.domUtils.showModalLoading();
let promise,
site: CoreSite;
if (courseId && sectionId) {
@ -680,8 +673,8 @@ export class CoreCourseHelperProvider {
// First of all, mark the course as being downloaded.
this.courseDwnPromises[siteId][course.id] = this.courseProvider.setCourseStatus(course.id, CoreConstants.DOWNLOADING,
siteId).then(() => {
let promises = [],
allSectionsSection = sections[0];
const promises = [];
let allSectionsSection = sections[0];
// Prefetch all the sections. If the first section is "All sections", use it. Otherwise, use a fake "All sections".
if (sections[0].id != CoreCourseProvider.ALL_SECTIONS_ID) {
@ -727,7 +720,8 @@ export class CoreCourseHelperProvider {
// Show confirmation if needed.
return this.domUtils.confirmDownloadSize(size).then(() => {
// Invalidate content if refreshing and download the data.
let promise = refresh ? handler.invalidateContent(module.id, courseId) : Promise.resolve();
const promise = refresh ? handler.invalidateContent(module.id, courseId) : Promise.resolve();
return promise.catch(() => {
// Ignore errors.
}).then(() => {
@ -754,8 +748,8 @@ export class CoreCourseHelperProvider {
});
} else {
// Download all the sections except "All sections".
let promises = [],
allSectionsStatus;
const promises = [];
let allSectionsStatus;
section.isDownloading = true;
sections.forEach((section) => {
@ -802,9 +796,11 @@ export class CoreCourseHelperProvider {
// Section is downloaded or not downloadable, nothing to do.
return;
}
return this.prefetchSingleSection(section, result, courseId);
}, (error) => {
section.isDownloading = false;
return Promise.reject(error);
});
}
@ -818,7 +814,7 @@ export class CoreCourseHelperProvider {
* @param {number} courseId Course ID the section belongs to.
* @return {Promise<any>} Promise resolved when the section has been prefetched.
*/
protected prefetchSingleSection(section: any, result: any, courseId: number) {
protected prefetchSingleSection(section: any, result: any, courseId: number): Promise<any> {
if (section.id == CoreCourseProvider.ALL_SECTIONS_ID) {
return Promise.resolve();
}
@ -829,14 +825,13 @@ export class CoreCourseHelperProvider {
}
// We only download modules with status notdownloaded, downloading or outdated.
let modules = result[CoreConstants.OUTDATED].concat(result[CoreConstants.NOT_DOWNLOADED])
const modules = result[CoreConstants.OUTDATED].concat(result[CoreConstants.NOT_DOWNLOADED])
.concat(result[CoreConstants.DOWNLOADING]),
downloadId = this.getSectionDownloadId(section);
section.isDownloading = true;
// We prefetch all the modules to prevent incoeherences in the download count
// and also to download stale data that might not be marked as outdated.
// Prefetch all modules to prevent incoeherences in download count and to download stale data not marked as outdated.
return this.prefetchDelegate.prefetchModules(downloadId, modules, courseId, (data) => {
section.count = data.count;
section.total = data.total;

View File

@ -43,7 +43,7 @@ export interface CoreCourseModuleHandler extends CoreDelegateHandler {
* @return {any} The component to use, undefined if not found.
*/
getMainComponent(course: any, module: any): any;
};
}
/**
* Data needed to render the module in course contents.
@ -134,7 +134,7 @@ export interface CoreCourseModuleHandlerButton {
* @param {number} courseId The course ID.
*/
action(event: Event, navCtrl: NavController, module: any, courseId: number): void;
};
}
/**
* Delegate to register module handlers.
@ -158,9 +158,9 @@ export class CoreCourseModuleDelegate extends CoreDelegate {
* @return {any} The component to use, undefined if not found.
*/
getMainComponent?(course: any, module: any): any {
let handler = this.enabledHandlers[module.modname];
const handler = this.enabledHandlers[module.modname];
if (handler && handler.getMainComponent) {
let component = handler.getMainComponent(course, module);
const component = handler.getMainComponent(course, module);
if (component) {
return component;
}
@ -182,11 +182,11 @@ export class CoreCourseModuleDelegate extends CoreDelegate {
}
// Return the default data.
let defaultData: CoreCourseModuleHandlerData = {
const defaultData: CoreCourseModuleHandlerData = {
icon: this.courseProvider.getModuleIconSrc(module.modname),
title: module.name,
class: 'core-course-default-handler core-course-module-' + module.modname + '-handler',
action: (event: Event, navCtrl: NavController, module: any, courseId: number, options?: NavOptions) => {
action: (event: Event, navCtrl: NavController, module: any, courseId: number, options?: NavOptions): void => {
event.preventDefault();
event.stopPropagation();
@ -198,7 +198,7 @@ export class CoreCourseModuleDelegate extends CoreDelegate {
defaultData.buttons = [{
icon: 'open',
label: 'core.openinbrowser',
action: (e: Event) => {
action: (e: Event): void => {
e.preventDefault();
e.stopPropagation();
this.sitesProvider.getCurrentSite().openInBrowserWithAutoLoginIfSameSite(module.url);

View File

@ -210,8 +210,7 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
// Promises for check updates, to prevent performing the same request twice at the same time.
protected courseUpdatesPromises: { [s: string]: { [s: string]: Promise<any> } } = {};
// Promises and observables for prefetching, to prevent downloading the same section twice at the same time
// and notify the progress of the download.
// Promises and observables for prefetching, to prevent downloading same section twice at the same time and notify progress.
protected prefetchData: {
[s: string]: {
[s: string]: {
@ -222,9 +221,10 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
}
} = {};
constructor(loggerProvider: CoreLoggerProvider, protected sitesProvider: CoreSitesProvider, protected eventsProvider: CoreEventsProvider,
constructor(loggerProvider: CoreLoggerProvider, protected sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider,
private courseProvider: CoreCourseProvider, private filepoolProvider: CoreFilepoolProvider,
private timeUtils: CoreTimeUtilsProvider, private utils: CoreUtilsProvider, private fileProvider: CoreFileProvider) {
private timeUtils: CoreTimeUtilsProvider, private fileProvider: CoreFileProvider,
protected eventsProvider: CoreEventsProvider) {
super('CoreCourseModulePrefetchDelegate', loggerProvider, sitesProvider);
this.sitesProvider.createTableFromSchema(this.checkUpdatesTableSchema);
@ -277,7 +277,7 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
* @return {Promise<{toCheck: any[], cannotUse: any[]}>} Promise resolved with the lists.
*/
protected createToCheckList(modules: any[], courseId: number): Promise<{ toCheck: any[], cannotUse: any[] }> {
let result = {
const result = {
toCheck: [],
cannotUse: []
},
@ -341,6 +341,7 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
return handler.determineStatus(module, status, canCheck);
}
}
return status;
}
@ -358,7 +359,7 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
}
// Check if there's already a getCourseUpdates in progress.
let id = <string>Md5.hashAsciiStr(courseId + '#' + JSON.stringify(modules)),
const id = <string> Md5.hashAsciiStr(courseId + '#' + JSON.stringify(modules)),
siteId = this.sitesProvider.getCurrentSiteId();
if (this.courseUpdatesPromises[siteId] && this.courseUpdatesPromises[siteId][id]) {
@ -369,7 +370,7 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
}
this.courseUpdatesPromises[siteId][id] = this.createToCheckList(modules, courseId).then((data) => {
let result = {};
const result = {};
// Mark as false the modules that cannot use check updates WS.
data.cannotUse.forEach((module) => {
@ -383,7 +384,7 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
// Get the site, maybe the user changed site.
return this.sitesProvider.getSite(siteId).then((site) => {
let params = {
const params = {
courseid: courseId,
tocheck: data.toCheck
},
@ -399,7 +400,7 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
}
// Store the last execution of the check updates call.
let entry = {
const entry = {
courseId: courseId,
time: this.timeUtils.timestamp()
};
@ -407,8 +408,8 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
return this.treatCheckUpdatesResult(data.toCheck, response, result);
}).catch((error) => {
// Cannot get updates. Get the cached entries but discard the modules with a download time higher
// than the last execution of check updates.
// Cannot get updates.
// Get cached entries but discard modules with a download time higher than the last execution of check updates.
return site.getDb().getRecord(this.CHECK_UPDATES_TIMES_TABLE, { courseId: courseId }).then((entry) => {
preSets.getCacheUsingCacheKey = true;
preSets.omitExpires = true;
@ -502,9 +503,9 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
* to calculate the total size.
*/
getModuleDownloadSize(module: any, courseId: number, single?: boolean): Promise<{ size: number, total: boolean }> {
const handler = this.getPrefetchHandlerFor(module);
let downloadSize,
packageId,
handler = this.getPrefetchHandlerFor(module);
packageId;
// Check if the module has a prefetch handler.
if (handler) {
@ -526,6 +527,7 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
if (cachedSize) {
return cachedSize;
}
return Promise.reject(error);
});
});
@ -542,10 +544,10 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
* @return {Promise<number>} Promise resolved with the size.
*/
getModuleDownloadedSize(module: any, courseId: number): Promise<number> {
const handler = this.getPrefetchHandlerFor(module);
let downloadedSize,
packageId,
promise,
handler = this.getPrefetchHandlerFor(module);
promise;
// Check if the module has a prefetch handler.
if (handler) {
@ -566,9 +568,9 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
} else {
// Handler doesn't implement it, get the module files and check if they're downloaded.
promise = this.getModuleFiles(module, courseId).then((files) => {
let siteId = this.sitesProvider.getCurrentSiteId(),
promises = [],
size = 0;
const siteId = this.sitesProvider.getCurrentSiteId(),
promises = [];
let size = 0;
// Retrieve file size if it's downloaded.
files.forEach((file) => {
@ -641,15 +643,15 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
* @return {Promise<string>} Promise resolved with the status.
*/
getModuleStatus(module: any, courseId: number, updates?: any, refresh?: boolean, sectionId?: number): Promise<string> {
let handler = this.getPrefetchHandlerFor(module),
const handler = this.getPrefetchHandlerFor(module),
siteId = this.sitesProvider.getCurrentSiteId(),
canCheck = this.canCheckUpdates();
if (handler) {
// Check if the status is cached.
let component = handler.component,
packageId = this.filepoolProvider.getPackageId(component, module.id),
status = this.statusCache.getValue(packageId, 'status'),
const component = handler.component,
packageId = this.filepoolProvider.getPackageId(component, module.id);
let status = this.statusCache.getValue(packageId, 'status'),
updateStatus = true,
promise;
@ -696,6 +698,7 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
// Has updates, mark the module as outdated.
status = CoreConstants.OUTDATED;
return this.filepoolProvider.storePackageStatus(siteId, component, module.id, status).catch(() => {
// Ignore errors.
}).then(() => {
@ -704,11 +707,13 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
}).catch(() => {
// Error checking if module has updates.
const status = this.statusCache.getValue(packageId, 'status', true);
return this.determineModuleStatus(module, status, canCheck);
});
}, () => {
// Error getting updates, show the stored status.
updateStatus = false;
return currentStatus;
});
});
@ -716,6 +721,7 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
if (updateStatus) {
this.updateStatusCache(status, courseId, component, module.id, sectionId);
}
return this.determineModuleStatus(module, status, canCheck);
});
}
@ -741,11 +747,11 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
* - CoreConstants.OUTDATED (any[]) Modules with state OUTDATED.
*/
getModulesStatus(modules: any[], courseId: number, sectionId?: number, refresh?: boolean): any {
let promises = [],
status = CoreConstants.NOT_DOWNLOADABLE,
const promises = [],
result: any = {
total: 0
};
let status = CoreConstants.NOT_DOWNLOADABLE;
// Init result.
result[CoreConstants.NOT_DOWNLOADED] = [];
@ -761,9 +767,9 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
modules.forEach((module) => {
// Check if the module has a prefetch handler.
let handler = this.getPrefetchHandlerFor(module);
const handler = this.getPrefetchHandlerFor(module);
if (handler) {
let packageId = this.filepoolProvider.getPackageId(handler.component, module.id);
const packageId = this.filepoolProvider.getPackageId(handler.component, module.id);
promises.push(this.getModuleStatus(module, courseId, updates, refresh).then((modStatus) => {
if (modStatus != CoreConstants.NOT_DOWNLOADABLE) {
@ -793,6 +799,7 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
return Promise.all(promises).then(() => {
result.status = status;
return result;
});
});
@ -806,12 +813,12 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
* @return {Promise<{status: string, downloadTime?: number}>} Promise resolved with the data.
*/
protected getModuleStatusAndDownloadTime(module: any, courseId: number): Promise<{ status: string, downloadTime?: number }> {
let handler = this.getPrefetchHandlerFor(module),
const handler = this.getPrefetchHandlerFor(module),
siteId = this.sitesProvider.getCurrentSiteId();
if (handler) {
// Get the status from the cache.
let packageId = this.filepoolProvider.getPackageId(handler.component, module.id),
const packageId = this.filepoolProvider.getPackageId(handler.component, module.id),
status = this.statusCache.getValue(packageId, 'status');
if (typeof status != 'undefined' && status != CoreConstants.DOWNLOADED) {
@ -873,7 +880,7 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
* @return {Promise<any>} Promise resolved when modules are invalidated.
*/
invalidateModules(modules: any[], courseId: number): Promise<any> {
let promises = [];
const promises = [];
modules.forEach((module) => {
const handler = this.getPrefetchHandlerFor(module);
@ -914,6 +921,7 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
*/
isBeingDownloaded(id: string): boolean {
const siteId = this.sitesProvider.getCurrentSiteId();
return !!(this.prefetchData[siteId] && this.prefetchData[siteId][id]);
}
@ -925,11 +933,11 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
* @return {Promise<boolean>} Promise resolved with true if downloadable, false otherwise.
*/
isModuleDownloadable(module: any, courseId: number): Promise<boolean> {
let handler = this.getPrefetchHandlerFor(module);
const handler = this.getPrefetchHandlerFor(module);
if (handler) {
if (typeof handler.isDownloadable == 'function') {
let packageId = this.filepoolProvider.getPackageId(handler.component, module.id),
const packageId = this.filepoolProvider.getPackageId(handler.component, module.id),
downloadable = this.statusCache.getValue(packageId, 'downloadable');
if (typeof downloadable != 'undefined') {
@ -961,7 +969,7 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
* @return {Promise<boolean>} Promise resolved with boolean: whether the module has updates.
*/
moduleHasUpdates(module: any, courseId: number, updates: any): Promise<boolean> {
let handler = this.getPrefetchHandlerFor(module),
const handler = this.getPrefetchHandlerFor(module),
moduleUpdates = updates[module.id];
if (handler && handler.hasUpdates) {
@ -1000,6 +1008,7 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
if (handler) {
return handler.prefetch(module, courseId, single);
}
return Promise.resolve();
}
@ -1023,18 +1032,17 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
if (onProgress) {
currentData.subscriptions.push(currentData.observable.subscribe(onProgress));
}
return currentData.promise;
}
let promises = [],
count = 0,
let count = 0;
const promises = [],
total = modules.length,
moduleIds = modules.map((module) => {
return module.id;
});
// Initialize the prefetch data.
const prefetchData = {
}),
prefetchData = {
observable: new BehaviorSubject<CoreCourseModulesProgress>({ count: count, total: total }),
promise: undefined,
subscriptions: []
@ -1054,7 +1062,7 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
}
return handler.prefetch(module, courseId).then(() => {
let index = moduleIds.indexOf(id);
const index = moduleIds.indexOf(id);
if (index > -1) {
// It's one of the modules we were expecting to download.
moduleIds.splice(index, 1);
@ -1092,9 +1100,9 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
* @return {Promise<void>} Promise resolved when done.
*/
removeModuleFiles(module: any, courseId: number): Promise<void> {
let handler = this.getPrefetchHandlerFor(module),
siteId = this.sitesProvider.getCurrentSiteId(),
promise;
const handler = this.getPrefetchHandlerFor(module),
siteId = this.sitesProvider.getCurrentSiteId();
let promise;
if (handler && handler.removeFiles) {
// Handler implements a method to remove the files, use it.
@ -1102,12 +1110,13 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
} else {
// No method to remove files, use get files to try to remove the files.
promise = this.getModuleFiles(module, courseId).then((files) => {
let promises = [];
const promises = [];
files.forEach((file) => {
promises.push(this.filepoolProvider.removeFileByUrl(siteId, file.url || file.fileurl).catch(() => {
// Ignore errors.
}));
});
return Promise.all(promises);
});
}
@ -1180,10 +1189,11 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
* @param {string|number} [componentId] An ID to use in conjunction with the component.
* @param {number} [sectionId] Section ID of the module.
*/
updateStatusCache(status: string, courseId: number, component: string, componentId?: string | number, sectionId?: number): void {
let notify,
packageId = this.filepoolProvider.getPackageId(component, componentId),
updateStatusCache(status: string, courseId: number, component: string, componentId?: string | number, sectionId?: number)
: void {
const packageId = this.filepoolProvider.getPackageId(component, componentId),
cachedStatus = this.statusCache.getValue(packageId, 'status', true);
let notify;
// If the status has changed, notify that the section has changed.
notify = typeof cachedStatus != 'undefined' && cachedStatus !== status;

View File

@ -194,7 +194,7 @@ export class CoreCourseOptionsDelegate extends CoreDelegate {
* @return {Promise<any>} Promise resolved when done.
*/
clearAndInvalidateCoursesOptions(courseId?: number): Promise<any> {
let promises = [];
const promises = [];
this.eventsProvider.trigger(CoreCoursesProvider.EVENT_MY_COURSES_REFRESHED);
@ -208,7 +208,7 @@ export class CoreCourseOptionsDelegate extends CoreDelegate {
promises.push(this.coursesProvider.invalidateUserNavigationOptions());
promises.push(this.coursesProvider.invalidateUserAdministrationOptions());
for (let cId in this.coursesHandlers) {
for (const cId in this.coursesHandlers) {
promises.push(this.invalidateCourseHandlers(parseInt(cId, 10)));
}
}
@ -267,7 +267,7 @@ export class CoreCourseOptionsDelegate extends CoreDelegate {
Promise<CoreCourseOptionsHandlerToDisplay[]> {
course.id = parseInt(course.id, 10);
let accessData = {
const accessData = {
type: isGuest ? CoreCourseProvider.ACCESS_GUEST : CoreCourseProvider.ACCESS_DEFAULT
};
@ -282,9 +282,9 @@ export class CoreCourseOptionsDelegate extends CoreDelegate {
// Call getHandlersForAccess to make sure the handlers have been loaded.
return this.getHandlersForAccess(course.id, refresh, accessData, course.navOptions, course.admOptions);
}).then(() => {
let handlersToDisplay: CoreCourseOptionsHandlerToDisplay[] = [],
promises = [],
promise;
const handlersToDisplay: CoreCourseOptionsHandlerToDisplay[] = [],
promises = [];
let promise;
this.coursesHandlers[course.id].enabledHandlers.forEach((handler) => {
if (handler.shouldDisplayForCourse) {
@ -342,9 +342,10 @@ export class CoreCourseOptionsDelegate extends CoreDelegate {
*/
hasHandlersForDefault(courseId: number, refresh?: boolean, navOptions?: any, admOptions?: any): Promise<boolean> {
// Default access.
let accessData = {
const accessData = {
type: CoreCourseProvider.ACCESS_DEFAULT
};
return this.getHandlersForAccess(courseId, refresh, accessData, navOptions, admOptions).then((handlers) => {
return !!(handlers && handlers.length);
});
@ -361,9 +362,10 @@ export class CoreCourseOptionsDelegate extends CoreDelegate {
*/
hasHandlersForGuest(courseId: number, refresh?: boolean, navOptions?: any, admOptions?: any): Promise<boolean> {
// Guest access.
var accessData = {
const accessData = {
type: CoreCourseProvider.ACCESS_GUEST
};
return this.getHandlersForAccess(courseId, refresh, accessData, navOptions, admOptions).then((handlers) => {
return !!(handlers && handlers.length);
});
@ -376,7 +378,7 @@ export class CoreCourseOptionsDelegate extends CoreDelegate {
* @return {Promise<any>} Promise resolved when done.
*/
invalidateCourseHandlers(courseId: number): Promise<any> {
let promises = [],
const promises = [],
courseData = this.coursesHandlers[courseId];
if (!courseData) {
@ -405,6 +407,7 @@ export class CoreCourseOptionsDelegate extends CoreDelegate {
if (!this.lastUpdateHandlersForCoursesStart[courseId]) {
return true;
}
return time == this.lastUpdateHandlersForCoursesStart[courseId];
}
@ -434,8 +437,8 @@ export class CoreCourseOptionsDelegate extends CoreDelegate {
updateData(siteId?: string): void {
if (this.sitesProvider.getCurrentSiteId() === siteId) {
// Update handlers for all courses.
for (let courseId in this.coursesHandlers) {
let handler = this.coursesHandlers[courseId];
for (const courseId in this.coursesHandlers) {
const handler = this.coursesHandlers[courseId];
this.updateHandlersForCourse(parseInt(courseId, 10), handler.access, handler.navOptions, handler.admOptions);
}
}
@ -452,15 +455,15 @@ export class CoreCourseOptionsDelegate extends CoreDelegate {
* @protected
*/
updateHandlersForCourse(courseId: number, accessData: any, navOptions?: any, admOptions?: any): Promise<any> {
let promises = [],
const promises = [],
enabledForCourse = [],
siteId = this.sitesProvider.getCurrentSiteId(),
now = Date.now();
this.lastUpdateHandlersForCoursesStart[courseId] = now;
for (let name in this.enabledHandlers) {
let handler = this.enabledHandlers[name];
for (const name in this.enabledHandlers) {
const handler = this.enabledHandlers[name];
// Checks if the handler is enabled for the user.
promises.push(Promise.resolve(handler.isEnabledForCourse(courseId, accessData, navOptions, admOptions))

View File

@ -37,9 +37,9 @@ export class CoreCoursesCourseListItemComponent implements OnInit {
/**
* Component being initialized.
*/
ngOnInit() {
ngOnInit(): void {
// Check if the user is enrolled in the course.
return this.coursesProvider.getUserCourse(this.course.id).then(() => {
this.coursesProvider.getUserCourse(this.course.id).then(() => {
this.course.isEnrolled = true;
}).catch(() => {
this.course.isEnrolled = false;
@ -75,9 +75,10 @@ export class CoreCoursesCourseListItemComponent implements OnInit {
/**
* Open a course.
*
* @param {any} course The course to open.
*/
openCourse(course) {
openCourse(course: any): void {
this.navCtrl.push('CoreCoursesCoursePreviewPage', {course: course});
}
}

View File

@ -58,7 +58,7 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy {
/**
* Component being initialized.
*/
ngOnInit() {
ngOnInit(): void {
// Determine course prefetch icon.
this.courseHelper.getCourseStatusIcon(this.course.id).then((icon) => {
this.prefetchCourseData.prefetchCourseIcon = icon;
@ -83,8 +83,10 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy {
/**
* Open a course.
*
* @param {any} course The course to open.
*/
openCourse(course) {
openCourse(course: any): void {
this.courseFormatDelegate.openCourse(this.navCtrl, course);
}
@ -93,7 +95,7 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy {
*
* @param {Event} e Click event.
*/
prefetchCourse(e: Event) {
prefetchCourse(e: Event): void {
e.preventDefault();
e.stopPropagation();
@ -101,13 +103,13 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy {
if (!this.isDestroyed) {
this.domUtils.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true);
}
})
});
}
/**
* Component destroyed.
*/
ngOnDestroy() {
ngOnDestroy(): void {
this.isDestroyed = true;
if (this.courseStatusObserver) {

View File

@ -52,7 +52,7 @@ export class CoreCoursesOverviewEventsComponent implements OnChanges {
/**
* Detect changes on input properties.
*/
ngOnChanges(changes: {[name: string]: SimpleChange}) {
ngOnChanges(changes: {[name: string]: SimpleChange}): void {
this.showCourse = this.utils.isTrueOrOne(this.showCourse);
if (changes.events) {
@ -65,8 +65,9 @@ export class CoreCoursesOverviewEventsComponent implements OnChanges {
*
* @param {number} start Number of days to start getting events from today. E.g. -1 will get events from yesterday.
* @param {number} [end] Number of days after the start.
* @return {any[]} Filtered events.
*/
protected filterEventsByTime(start: number, end?: number) {
protected filterEventsByTime(start: number, end?: number): any[] {
start = moment().add(start, 'days').unix();
end = typeof end != 'undefined' ? moment().add(end, 'days').unix() : end;
@ -78,6 +79,7 @@ export class CoreCoursesOverviewEventsComponent implements OnChanges {
return start <= event.timesort;
}).map((event) => {
event.iconUrl = this.courseProvider.getModuleIconSrc(event.icon.component);
return event;
});
}
@ -85,7 +87,7 @@ export class CoreCoursesOverviewEventsComponent implements OnChanges {
/**
* Update the events displayed.
*/
protected updateEvents() {
protected updateEvents(): void {
this.empty = !this.events || this.events.length <= 0;
if (!this.empty) {
this.recentlyOverdue = this.filterEventsByTime(-14, 0);
@ -99,7 +101,7 @@ export class CoreCoursesOverviewEventsComponent implements OnChanges {
/**
* Load more events clicked.
*/
loadMoreEvents() {
loadMoreEvents(): void {
this.loadingMore = true;
this.loadMore.emit();
}
@ -110,14 +112,14 @@ export class CoreCoursesOverviewEventsComponent implements OnChanges {
* @param {Event} e Click event.
* @param {string} url Url of the action.
*/
action(e: Event, url: string) {
action(e: Event, url: string): void {
e.preventDefault();
e.stopPropagation();
// Fix URL format.
url = this.textUtils.decodeHTMLEntities(url);
let modal = this.domUtils.showModalLoading();
const modal = this.domUtils.showModalLoading();
this.contentLinksHelper.handleLink(url, undefined, this.navCtrl).then((treated) => {
if (!treated) {
return this.sitesProvider.getCurrentSite().openInBrowserWithAutoLoginIfSameSite(url);
@ -125,7 +127,5 @@ export class CoreCoursesOverviewEventsComponent implements OnChanges {
}).finally(() => {
modal.dismiss();
});
return false;
}
}

View File

@ -21,7 +21,7 @@ import { CoreCoursesProvider } from '../../providers/courses';
/**
* Page that displays available courses in current site.
*/
@IonicPage({segment: "core-courses-available-courses"})
@IonicPage({ segment: 'core-courses-available-courses' })
@Component({
selector: 'page-core-courses-available-courses',
templateUrl: 'available-courses.html',
@ -36,7 +36,7 @@ export class CoreCoursesAvailableCoursesPage {
/**
* View loaded.
*/
ionViewDidLoad() {
ionViewDidLoad(): void {
this.loadCourses().finally(() => {
this.coursesLoaded = true;
});
@ -44,9 +44,12 @@ export class CoreCoursesAvailableCoursesPage {
/**
* Load the courses.
*
* @return {Promise<any>} Promise resolved when done.
*/
protected loadCourses() {
protected loadCourses(): Promise<any> {
const frontpageCourseId = this.sitesProvider.getCurrentSite().getSiteHomeId();
return this.coursesProvider.getCoursesByField().then((courses) => {
this.courses = courses.filter((course) => {
return course.id != frontpageCourseId;
@ -61,8 +64,8 @@ export class CoreCoursesAvailableCoursesPage {
*
* @param {any} refresher Refresher.
*/
refreshCourses(refresher: any) {
let promises = [];
refreshCourses(refresher: any): void {
const promises = [];
promises.push(this.coursesProvider.invalidateUserCourses());
promises.push(this.coursesProvider.invalidateCoursesByField());
@ -72,5 +75,5 @@ export class CoreCoursesAvailableCoursesPage {
refresher.complete();
});
});
};
}
}

View File

@ -23,7 +23,7 @@ import { CoreCoursesProvider } from '../../providers/courses';
/**
* Page that displays a list of categories and the courses in the current category if any.
*/
@IonicPage({segment: "core-courses-categories"})
@IonicPage({ segment: 'core-courses-categories' })
@Component({
selector: 'page-core-courses-categories',
templateUrl: 'categories.html',
@ -47,7 +47,7 @@ export class CoreCoursesCategoriesPage {
/**
* View loaded.
*/
ionViewDidLoad() {
ionViewDidLoad(): void {
this.fetchCategories().finally(() => {
this.categoriesLoaded = true;
});
@ -55,8 +55,10 @@ export class CoreCoursesCategoriesPage {
/**
* Fetch the categories.
*
* @return {Promise<any>} Promise resolved when done.
*/
protected fetchCategories() {
protected fetchCategories(): Promise<any> {
return this.coursesProvider.getCategories(this.categoryId, true).then((cats) => {
this.currentCategory = undefined;
@ -73,6 +75,7 @@ export class CoreCoursesCategoriesPage {
if (a.depth == b.depth) {
return (a.sortorder > b.sortorder) ? 1 : ((b.sortorder > a.sortorder) ? -1 : 0);
}
return a.depth > b.depth ? 1 : -1;
});
@ -97,8 +100,8 @@ export class CoreCoursesCategoriesPage {
*
* @param {any} refresher Refresher.
*/
refreshCategories(refresher: any) {
let promises = [];
refreshCategories(refresher: any): void {
const promises = [];
promises.push(this.coursesProvider.invalidateUserCourses());
promises.push(this.coursesProvider.invalidateCategories(this.categoryId, true));
@ -116,7 +119,7 @@ export class CoreCoursesCategoriesPage {
*
* @param {number} categoryId The category ID.
*/
openCategory(categoryId: number) {
openCategory(categoryId: number): void {
this.navCtrl.push('CoreCoursesCategoriesPage', { categoryId: categoryId });
}
}

View File

@ -28,7 +28,7 @@ import { CoreCourseHelperProvider } from '../../../course/providers/helper';
/**
* Page that allows "previewing" a course and enrolling in it if enabled and not enrolled.
*/
@IonicPage({segment: "core-courses-course-preview"})
@IonicPage({ segment: 'core-courses-course-preview' })
@Component({
selector: 'page-core-courses-course-preview',
templateUrl: 'course-preview.html',
@ -36,7 +36,7 @@ import { CoreCourseHelperProvider } from '../../../course/providers/helper';
export class CoreCoursesCoursePreviewPage implements OnDestroy {
course: any;
isEnrolled: boolean;
handlersShouldBeShown: boolean = true;
handlersShouldBeShown = true;
handlersLoaded: boolean;
component = 'CoreCoursesCoursePreview';
selfEnrolInstances: any[] = [];
@ -47,7 +47,7 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
};
protected guestWSAvailable: boolean;
protected isGuestEnabled: boolean = false;
protected isGuestEnabled = false;
protected guestInstanceId: number;
protected enrollmentMethods: any[];
protected waitStart = 0;
@ -82,7 +82,7 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
/**
* View loaded.
*/
ionViewDidLoad() {
ionViewDidLoad(): void {
const currentSite = this.sitesProvider.getCurrentSite(),
currentSiteUrl = currentSite && currentSite.getURL();
@ -107,7 +107,7 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
if (icon == 'spinner') {
// Course is being downloaded. Get the download promise.
let promise = this.courseHelper.getCourseDownloadPromise(this.course.id);
const promise = this.courseHelper.getCourseDownloadPromise(this.course.id);
if (promise) {
// There is a download promise. If it fails, show an error.
promise.catch((error) => {
@ -127,7 +127,7 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
/**
* Page destroyed.
*/
ngOnDestroy() {
ngOnDestroy(): void {
this.pageDestroyed = true;
if (this.courseStatusObserver) {
@ -149,7 +149,7 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
// Search instance ID of guest enrolment method.
this.guestInstanceId = undefined;
for (let i = 0; i < this.enrollmentMethods.length; i++) {
let method = this.enrollmentMethods[i];
const method = this.enrollmentMethods[i];
if (method.type == 'guest') {
this.guestInstanceId = method.id;
break;
@ -162,6 +162,7 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
// Not active, reject.
return Promise.reject(null);
}
return info.passwordrequired;
});
}
@ -177,6 +178,7 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
protected getCourse(refresh?: boolean): Promise<any> {
// Get course enrolment methods.
this.selfEnrolInstances = [];
return this.coursesProvider.getCourseEnrolmentMethods(this.course.id).then((methods) => {
this.enrollmentMethods = methods;
@ -193,15 +195,18 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
// Check if user is enrolled in the course.
return this.coursesProvider.getUserCourse(this.course.id).then((course) => {
this.isEnrolled = true;
return course;
}).catch(() => {
// The user is not enrolled in the course. Use getCourses to see if it's an admin/manager and can see the course.
this.isEnrolled = false;
return this.coursesProvider.getCourse(this.course.id);
}).then((course) => {
// Success retrieving the course, we can assume the user has permissions to view it.
this.course.fullname = course.fullname || this.course.fullname;
this.course.summary = course.summary || this.course.summary;
return this.loadCourseHandlers(refresh, false);
}).catch(() => {
// The user is not an admin/manager. Check if we can provide guest access to the course.
@ -238,7 +243,7 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
/**
* Open the course.
*/
openCourse() {
openCourse(): void {
if (!this.handlersShouldBeShown) {
// Course cannot be opened.
return;
@ -250,14 +255,15 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
/**
* Enrol using PayPal.
*/
paypalEnrol() {
paypalEnrol(): void {
let window,
hasReturnedFromPaypal = false,
inAppLoadSubscription,
inAppFinishSubscription,
inAppExitSubscription,
appResumeSubscription,
urlLoaded = (event) => {
appResumeSubscription;
const urlLoaded = (event): void => {
if (event.url.indexOf(this.paypalReturnUrl) != -1) {
hasReturnedFromPaypal = true;
} else if (event.url.indexOf(this.courseUrl) != -1 && hasReturnedFromPaypal) {
@ -266,7 +272,7 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
window.close();
}
},
inAppClosed = () => {
inAppClosed = (): void => {
// InAppBrowser closed, refresh data.
unsubscribeAll();
@ -276,7 +282,7 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
this.dataLoaded = false;
this.refreshData();
},
unsubscribeAll = () => {
unsubscribeAll = (): void => {
inAppLoadSubscription && inAppLoadSubscription.unsubscribe();
inAppFinishSubscription && inAppFinishSubscription.unsubscribe();
inAppExitSubscription && inAppExitSubscription.unsubscribe();
@ -315,7 +321,7 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
*
* @param {number} instanceId The instance ID of the enrolment method.
*/
selfEnrolClicked(instanceId: number) {
selfEnrolClicked(instanceId: number): void {
this.domUtils.showConfirm(this.translate.instant('core.courses.confirmselfenrol')).then(() => {
this.selfEnrolInCourse('', instanceId);
}).catch(() => {
@ -331,7 +337,7 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
* @return {Promise<any>} Promise resolved when self enrolled.
*/
selfEnrolInCourse(password: string, instanceId: number): Promise<any> {
let modal = this.domUtils.showModalLoading('core.loading', true);
const modal = this.domUtils.showModalLoading('core.loading', true);
return this.coursesProvider.selfEnrol(this.course.id, password, instanceId).then(() => {
// Close modal and refresh data.
@ -370,7 +376,7 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
* @param {any} [refresher] The refresher if this was triggered by a Pull To Refresh.
*/
refreshData(refresher?: any): Promise<any> {
let promises = [];
const promises = [];
promises.push(this.coursesProvider.invalidateUserCourses());
promises.push(this.coursesProvider.invalidateCourse(this.course.id));
@ -393,8 +399,9 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
* Wait for the user to be enrolled in the course.
*
* @param {boolean} first If it's the first call (true) or it's a recursive call (false).
* @return {Promise<any>} Promise resolved when enrolled or timeout.
*/
protected waitForEnrolled(first?: boolean) {
protected waitForEnrolled(first?: boolean): Promise<any> {
if (first) {
this.waitStart = Date.now();
}
@ -406,12 +413,12 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
return this.coursesProvider.getUserCourse(this.course.id);
}).catch(() => {
// Not enrolled, wait a bit and try again.
if (this.pageDestroyed || (Date.now() - this.waitStart > 60000)) {
if (this.pageDestroyed || (Date.now() - this.waitStart > 60000)) {
// Max time reached or the user left the view, stop.
return;
}
return new Promise((resolve, reject) => {
return new Promise((resolve, reject): void => {
setTimeout(() => {
if (!this.pageDestroyed) {
// Wait again.
@ -427,12 +434,12 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
/**
* Prefetch the course.
*/
prefetchCourse() {
prefetchCourse(): void {
this.courseHelper.confirmAndPrefetchCourse(this.prefetchCourseData, this.course, undefined, this.course._handlers)
.catch((error) => {
if (!this.pageDestroyed) {
this.domUtils.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true);
}
})
});
}
}

View File

@ -24,7 +24,7 @@ import { CoreCourseOptionsDelegate } from '../../../course/providers/options-del
/**
* Page that displays the list of courses the user is enrolled in.
*/
@IonicPage({segment: "core-courses-my-courses"})
@IonicPage({ segment: 'core-courses-my-courses' })
@Component({
selector: 'page-core-courses-my-courses',
templateUrl: 'my-courses.html',
@ -51,7 +51,7 @@ export class CoreCoursesMyCoursesPage implements OnDestroy {
/**
* View loaded.
*/
ionViewDidLoad() {
ionViewDidLoad(): void {
this.searchEnabled = !this.coursesProvider.isSearchCoursesDisabledInSite();
this.fetchCourses().finally(() => {
@ -69,8 +69,10 @@ export class CoreCoursesMyCoursesPage implements OnDestroy {
/**
* Fetch the user courses.
*
* @return {Promise<any>} Promise resolved when done.
*/
protected fetchCourses() {
protected fetchCourses(): Promise<any> {
return this.coursesProvider.getUserCourses().then((courses) => {
const courseIds = courses.map((course) => {
@ -98,8 +100,8 @@ export class CoreCoursesMyCoursesPage implements OnDestroy {
*
* @param {any} refresher Refresher.
*/
refreshCourses(refresher: any) {
let promises = [];
refreshCourses(refresher: any): void {
const promises = [];
promises.push(this.coursesProvider.invalidateUserCourses());
promises.push(this.courseOptionsDelegate.clearAndInvalidateCoursesOptions());
@ -116,7 +118,7 @@ export class CoreCoursesMyCoursesPage implements OnDestroy {
/**
* Show or hide the filter.
*/
switchFilter() {
switchFilter(): void {
this.filter = '';
this.showFilter = !this.showFilter;
this.filteredCourses = this.courses;
@ -125,7 +127,7 @@ export class CoreCoursesMyCoursesPage implements OnDestroy {
/**
* Go to search courses.
*/
openSearch() {
openSearch(): void {
this.navCtrl.push('CoreCoursesSearchPage');
}
@ -134,7 +136,7 @@ export class CoreCoursesMyCoursesPage implements OnDestroy {
*
* @param {string} newValue New filter value.
*/
filterChanged(newValue: string) {
filterChanged(newValue: string): void {
if (!newValue || !this.courses) {
this.filteredCourses = this.courses;
} else {
@ -146,12 +148,15 @@ export class CoreCoursesMyCoursesPage implements OnDestroy {
/**
* Prefetch all the courses.
*
* @return {Promise<any>} Promise resolved when done.
*/
prefetchCourses() {
let initialIcon = this.prefetchCoursesData.icon;
prefetchCourses(): Promise<any> {
const initialIcon = this.prefetchCoursesData.icon;
this.prefetchCoursesData.icon = 'spinner';
this.prefetchCoursesData.badge = '';
return this.courseHelper.confirmAndPrefetchCourses(this.courses, (progress) => {
this.prefetchCoursesData.badge = progress.count + ' / ' + progress.total;
}).then((downloaded) => {
@ -169,7 +174,7 @@ export class CoreCoursesMyCoursesPage implements OnDestroy {
/**
* Initialize the prefetch icon for the list of courses.
*/
protected initPrefetchCoursesIcon() {
protected initPrefetchCoursesIcon(): void {
if (this.prefetchIconInitialized) {
// Already initialized.
return;
@ -180,6 +185,7 @@ export class CoreCoursesMyCoursesPage implements OnDestroy {
if (!this.courses || this.courses.length < 2) {
// Not enough courses.
this.prefetchCoursesData.icon = '';
return;
}
@ -196,7 +202,7 @@ export class CoreCoursesMyCoursesPage implements OnDestroy {
/**
* Page destroyed.
*/
ngOnDestroy() {
ngOnDestroy(): void {
this.isDestroyed = true;
this.myCoursesObserver && this.myCoursesObserver.off();
this.siteUpdatedObserver && this.siteUpdatedObserver.off();

View File

@ -26,7 +26,7 @@ import * as moment from 'moment';
/**
* Page that displays My Overview.
*/
@IonicPage({segment: "core-courses-my-overview"})
@IonicPage({ segment: 'core-courses-my-overview' })
@Component({
selector: 'page-core-courses-my-overview',
templateUrl: 'my-overview.html',
@ -34,7 +34,7 @@ import * as moment from 'moment';
export class CoreCoursesMyOverviewPage implements OnDestroy {
firstSelectedTab: number;
siteHomeEnabled: boolean;
tabsReady: boolean = false;
tabsReady = false;
tabShown = 'courses';
timeline = {
sort: 'sortbydates',
@ -76,12 +76,12 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
/**
* View loaded.
*/
ionViewDidLoad() {
ionViewDidLoad(): void {
this.searchEnabled = !this.coursesProvider.isSearchCoursesDisabledInSite();
// Decide which tab to load first.
this.siteHomeProvider.isAvailable().then((enabled) => {
let site = this.sitesProvider.getCurrentSite(),
const site = this.sitesProvider.getCurrentSite(),
displaySiteHome = site.getInfo() && site.getInfo().userhomepage === 0;
this.siteHomeEnabled = enabled;
@ -112,8 +112,8 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
*/
protected fetchMyOverviewTimelineByCourses(): Promise<any> {
return this.fetchUserCourses().then((courses) => {
let today = moment().unix(),
courseIds;
const today = moment().unix();
let courseIds;
courses = courses.filter((course) => {
return course.startdate <= today && (!course.enddate || course.enddate >= today);
});
@ -178,9 +178,8 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
* @return {Promise<any>} Promise resolved when done.
*/
protected fetchUserCourses(): Promise<any> {
let courseIds;
return this.coursesProvider.getUserCourses().then((courses) => {
courseIds = courses.map((course) => {
const courseIds = courses.map((course) => {
return course.id;
});
@ -204,7 +203,7 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
/**
* Show or hide the filter.
*/
switchFilter() {
switchFilter(): void {
this.showFilter = !this.showFilter;
this.courses.filter = '';
this.filteredCourses = this.courses[this.courses.selected];
@ -215,7 +214,7 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
*
* @param {string} newValue New filter value.
*/
filterChanged(newValue: string) {
filterChanged(newValue: string): void {
if (!newValue || !this.courses[this.courses.selected]) {
this.filteredCourses = this.courses[this.courses.selected];
} else {
@ -229,9 +228,10 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
* Refresh the data.
*
* @param {any} refresher Refresher.
* @return {Promise<any>} Promise resolved when done.
*/
refreshMyOverview(refresher: any) {
let promises = [];
refreshMyOverview(refresher: any): Promise<any> {
const promises = [];
if (this.tabShown == 'timeline') {
promises.push(this.myOverviewProvider.invalidateActionEventsByTimesort());
@ -249,11 +249,14 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
return this.fetchMyOverviewTimeline();
case 'sortbycourses':
return this.fetchMyOverviewTimelineByCourses();
default:
}
break;
case 'courses':
this.prefetchIconsInitialized = false;
return this.fetchMyOverviewCourses();
default:
}
}).finally(() => {
refresher.complete();
@ -263,7 +266,7 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
/**
* Change timeline sort being viewed.
*/
switchSort() {
switchSort(): void {
switch (this.timeline.sort) {
case 'sortbydates':
if (!this.timeline.loaded) {
@ -279,6 +282,7 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
});
}
break;
default:
}
}
@ -287,7 +291,7 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
*
* @param {string} tab Name of the new tab.
*/
tabChanged(tab: string) {
tabChanged(tab: string): void {
this.tabShown = tab;
switch (this.tabShown) {
case 'timeline':
@ -304,6 +308,7 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
});
}
break;
default:
}
}
@ -318,8 +323,9 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
* Load more events.
*
* @param {any} course Course.
* @return {Promise<any>} Promise resolved when done.
*/
loadMoreCourse(course) {
loadMoreCourse(course: any): Promise<any> {
return this.myOverviewProvider.getActionEventsByCourse(course.id, course.canLoadMore).then((courseEvents) => {
course.events = course.events.concat(courseEvents.events);
course.canLoadMore = courseEvents.canLoadMore;
@ -329,27 +335,30 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
/**
* Go to search courses.
*/
openSearch() {
openSearch(): void {
this.navCtrl.push('CoreCoursesSearchPage');
}
/**
* The selected courses have changed.
*/
selectedChanged() {
selectedChanged(): void {
this.filteredCourses = this.courses[this.courses.selected];
}
/**
* Prefetch all the shown courses.
*
* @return {Promise<any>} Promise resolved when done.
*/
prefetchCourses() {
let selected = this.courses.selected,
prefetchCourses(): Promise<any> {
const selected = this.courses.selected,
selectedData = this.prefetchCoursesData[selected],
initialIcon = selectedData.icon;
selectedData.icon = 'spinner';
selectedData.badge = '';
return this.courseHelper.confirmAndPrefetchCourses(this.courses[selected], (progress) => {
selectedData.badge = progress.count + ' / ' + progress.total;
}).then((downloaded) => {
@ -367,7 +376,7 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
/**
* Initialize the prefetch icon for selected courses.
*/
protected initPrefetchCoursesIcons() {
protected initPrefetchCoursesIcons(): void {
if (this.prefetchIconsInitialized) {
// Already initialized.
return;
@ -379,6 +388,7 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
if (!this.courses[filter] || this.courses[filter].length < 2) {
// Not enough courses.
this.prefetchCoursesData[filter].icon = '';
return;
}
@ -397,7 +407,7 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
/**
* Component being destroyed.
*/
ngOnDestroy() {
ngOnDestroy(): void {
this.isDestroyed = true;
}
}

View File

@ -20,7 +20,7 @@ import { CoreCoursesProvider } from '../../providers/courses';
/**
* Page that allows searching for courses.
*/
@IonicPage({segment: "core-courses-search"})
@IonicPage({ segment: 'core-courses-search' })
@Component({
selector: 'page-core-courses-search',
templateUrl: 'search.html',
@ -40,12 +40,12 @@ export class CoreCoursesSearchPage {
*
* @param {string} text The text to search.
*/
search(text: string) {
search(text: string): void {
this.currentSearch = text;
this.courses = undefined;
this.page = 0;
let modal = this.domUtils.showModalLoading('core.searching', true);
const modal = this.domUtils.showModalLoading('core.searching', true);
this.searchCourses().finally(() => {
modal.dismiss();
});
@ -53,8 +53,10 @@ export class CoreCoursesSearchPage {
/**
* Load more results.
*
* @param {any} infiniteScroll The infinit scroll instance.
*/
loadMoreResults(infiniteScroll) {
loadMoreResults(infiniteScroll: any): void {
this.searchCourses().finally(() => {
infiniteScroll.complete();
});
@ -62,8 +64,10 @@ export class CoreCoursesSearchPage {
/**
* Search courses or load the next page of current search.
*
* @return {Promise<any>} Promise resolved when done.
*/
protected searchCourses() {
protected searchCourses(): Promise<any> {
return this.coursesProvider.search(this.currentSearch, this.page).then((response) => {
if (this.page === 0) {
this.courses = response.courses;

View File

@ -18,7 +18,7 @@ import { IonicPage, ViewController } from 'ionic-angular';
/**
* Page that displays a form to enter a password to self enrol in a course.
*/
@IonicPage({segment: "core-courses-self-enrol-password"})
@IonicPage({ segment: 'core-courses-self-enrol-password' })
@Component({
selector: 'page-core-courses-self-enrol-password',
templateUrl: 'self-enrol-password.html',
@ -38,7 +38,7 @@ export class CoreCoursesSelfEnrolPasswordPage {
*
* @param {string} password Password to submit.
*/
submitPassword(password: string) {
submitPassword(password: string): void {
this.viewCtrl.dismiss(password);
}
}

View File

@ -51,11 +51,11 @@ export class CoreCoursesCourseLinkHandler extends CoreContentLinksHandlerBase {
CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
courseId = parseInt(params.id, 10);
let sectionId = params.sectionid ? parseInt(params.sectionid, 10) : null,
const sectionId = params.sectionid ? parseInt(params.sectionid, 10) : null,
sectionNumber = typeof params.section != 'undefined' ? parseInt(params.section, 10) : NaN,
pageParams: any = {
course: { id: courseId },
sectionId: sectionId || null
sectionId: sectionId || null
};
if (!isNaN(sectionNumber)) {
@ -63,7 +63,7 @@ export class CoreCoursesCourseLinkHandler extends CoreContentLinksHandlerBase {
}
return [{
action: (siteId, navCtrl?) => {
action: (siteId, navCtrl?): void => {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
if (siteId == this.sitesProvider.getCurrentSiteId()) {
this.actionEnrol(courseId, url, pageParams).catch(() => {
@ -109,7 +109,7 @@ export class CoreCoursesCourseLinkHandler extends CoreContentLinksHandlerBase {
* @return {Promise<any>} Promise resolved when done.
*/
protected actionEnrol(courseId: number, url: string, pageParams: any): Promise<any> {
let modal = this.domUtils.showModalLoading(),
const modal = this.domUtils.showModalLoading(),
isEnrolUrl = !!url.match(/(\/enrol\/index\.php)|(\/course\/enrol\.php)/);
// Check if user is enrolled in the course.
@ -119,7 +119,7 @@ export class CoreCoursesCourseLinkHandler extends CoreContentLinksHandlerBase {
modal.dismiss();
// The user can self enrol. If it's not a enrolment URL we'll ask for confirmation.
let promise = isEnrolUrl ? Promise.resolve() :
const promise = isEnrolUrl ? Promise.resolve() :
this.domUtils.showConfirm(this.translate.instant('core.courses.confirmselfenrol'));
return promise.then(() => {
@ -128,6 +128,7 @@ export class CoreCoursesCourseLinkHandler extends CoreContentLinksHandlerBase {
if (error) {
this.domUtils.showErrorModal(error);
}
return Promise.reject(null);
});
}, () => {
@ -147,13 +148,14 @@ export class CoreCoursesCourseLinkHandler extends CoreContentLinksHandlerBase {
error = this.translate.instant('core.courses.notenroled');
}
let body = this.translate.instant('core.twoparagraphs',
const body = this.translate.instant('core.twoparagraphs',
{ p1: error, p2: this.translate.instant('core.confirmopeninbrowser') });
this.domUtils.showConfirm(body).then(() => {
this.sitesProvider.getCurrentSite().openInBrowserWithAutoLogin(url);
}).catch(() => {
// User cancelled.
});
return Promise.reject(null);
});
});
@ -200,6 +202,7 @@ export class CoreCoursesCourseLinkHandler extends CoreContentLinksHandlerBase {
*/
protected selfEnrol(courseId: number, password?: string): Promise<any> {
const modal = this.domUtils.showModalLoading();
return this.coursesProvider.selfEnrol(courseId, password).then(() => {
// Success self enrolling the user, invalidate the courses list.
return this.coursesProvider.invalidateUserCourses().catch(() => {
@ -215,7 +218,7 @@ export class CoreCoursesCourseLinkHandler extends CoreContentLinksHandlerBase {
modal.dismiss();
if (error && error.code === CoreCoursesProvider.ENROL_INVALID_KEY) {
// Invalid password. Allow the user to input password.
let title = this.translate.instant('core.courses.selfenrolment'),
const title = this.translate.instant('core.courses.selfenrolment'),
body = ' ', // Empty message.
placeholder = this.translate.instant('core.courses.password');
@ -257,7 +260,7 @@ export class CoreCoursesCourseLinkHandler extends CoreContentLinksHandlerBase {
return;
}
return new Promise((resolve, reject) => {
return new Promise((resolve, reject): void => {
setTimeout(() => {
this.waitForEnrolled(courseId).then(resolve);
}, 5000);

View File

@ -43,9 +43,9 @@ export class CoreCoursesIndexLinkHandler extends CoreContentLinksHandlerBase {
getActions(siteIds: string[], url: string, params: any, courseId?: number):
CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
return [{
action: (siteId, navCtrl?) => {
var page = 'CoreCoursesMyCoursesPage', // By default, go to My Courses.
pageParams: any = {};
action: (siteId, navCtrl?): void => {
let page = 'CoreCoursesMyCoursesPage'; // By default, go to My Courses.
const pageParams: any = {};
if (this.coursesProvider.isGetCoursesByFieldAvailable()) {
if (params.categoryid) {

View File

@ -22,10 +22,10 @@ import { CoreSite } from '../../../classes/site';
*/
@Injectable()
export class CoreCoursesProvider {
public static SEARCH_PER_PAGE = 20;
public static ENROL_INVALID_KEY = 'CoreCoursesEnrolInvalidKey';
public static EVENT_MY_COURSES_UPDATED = 'courses_my_courses_updated';
public static EVENT_MY_COURSES_REFRESHED = 'courses_my_courses_refreshed';
static SEARCH_PER_PAGE = 20;
static ENROL_INVALID_KEY = 'CoreCoursesEnrolInvalidKey';
static EVENT_MY_COURSES_UPDATED = 'courses_my_courses_updated';
static EVENT_MY_COURSES_REFRESHED = 'courses_my_courses_refreshed';
protected ROOT_CACHE_KEY = 'mmCourses:';
protected logger;
@ -44,7 +44,7 @@ export class CoreCoursesProvider {
getCategories(categoryId: number, addSubcategories?: boolean, siteId?: string): Promise<any[]> {
return this.sitesProvider.getSite(siteId).then((site) => {
// Get parent when id is the root category.
let criteriaKey = categoryId == 0 ? 'parent' : 'id',
const criteriaKey = categoryId == 0 ? 'parent' : 'id',
data = {
criteria: [
{ key: criteriaKey, value: categoryId }
@ -53,7 +53,7 @@ export class CoreCoursesProvider {
},
preSets = {
cacheKey: this.getCategoriesCacheKey(categoryId, addSubcategories)
}
};
return site.read('core_course_get_categories', data, preSets);
});
@ -84,8 +84,8 @@ export class CoreCoursesProvider {
if (courseIds.length == 1) {
// Only 1 course, check if it belongs to the user courses. If so, use all user courses.
return this.getUserCourses(true, siteId).then((courses) => {
let courseId = courseIds[0],
useAllCourses = false;
const courseId = courseIds[0];
let useAllCourses = false;
if (courseId == siteHomeId) {
// It's site home, use all courses.
@ -140,6 +140,7 @@ export class CoreCoursesProvider {
*/
isMyCoursesDisabledInSite(site?: CoreSite): boolean {
site = site || this.sitesProvider.getCurrentSite();
return site.isFeatureDisabled('$mmSideMenuDelegate_mmCourses');
}
@ -163,6 +164,7 @@ export class CoreCoursesProvider {
*/
isSearchCoursesDisabledInSite(site?: CoreSite): boolean {
site = site || this.sitesProvider.getCurrentSite();
return site.isFeatureDisabled('$mmCoursesDelegate_search');
}
@ -178,6 +180,7 @@ export class CoreCoursesProvider {
if (courses && courses.length > 0) {
return courses[0];
}
return Promise.reject(null);
});
}
@ -191,12 +194,12 @@ export class CoreCoursesProvider {
*/
getCourseEnrolmentMethods(id: number, siteId?: string): Promise<any[]> {
return this.sitesProvider.getSite(siteId).then((site) => {
let params = {
const params = {
courseid: id
},
preSets = {
cacheKey: this.getCourseEnrolmentMethodsCacheKey(id)
}
};
return site.read('core_enrol_get_course_enrolment_methods', params, preSets);
});
@ -221,12 +224,12 @@ export class CoreCoursesProvider {
*/
getCourseGuestEnrolmentInfo(instanceId: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
let params = {
const params = {
instanceid: instanceId
},
preSets = {
cacheKey: this.getCourseGuestEnrolmentInfoCacheKey(instanceId)
}
};
return site.read('enrol_guest_get_instance_info', params, preSets).then((response) => {
return response.instanceinfo;
@ -261,14 +264,14 @@ export class CoreCoursesProvider {
}
return this.sitesProvider.getSite(siteId).then((site) => {
let data = {
const data = {
options: {
ids: ids
}
},
preSets = {
cacheKey: this.getCoursesCacheKey(ids)
}
};
return site.read('core_course_get_courses', data, preSets);
});
@ -299,13 +302,13 @@ export class CoreCoursesProvider {
*/
getCoursesByField(field?: string, value?: any, siteId?: string): Promise<any[]> {
return this.sitesProvider.getSite(siteId).then((site) => {
let data = {
const data = {
field: field || '',
value: field ? value : ''
},
preSets = {
cacheKey: this.getCoursesByFieldCacheKey(field, value)
}
};
return site.read('core_course_get_courses_by_field', data, preSets).then((courses) => {
if (courses.courses) {
@ -342,6 +345,7 @@ export class CoreCoursesProvider {
protected getCoursesByFieldCacheKey(field?: string, value?: any): string {
field = field || '';
value = field ? value : '';
return this.ROOT_CACHE_KEY + 'coursesbyfield:' + field + ':' + value;
}
@ -351,8 +355,7 @@ export class CoreCoursesProvider {
* @return {boolean} Whether get courses by field is available.
*/
isGetCoursesByFieldAvailable(): boolean {
let currentSite = this.sitesProvider.getCurrentSite();
return currentSite.wsAvailable('core_course_get_courses_by_field');
return this.sitesProvider.getCurrentSite().wsAvailable('core_course_get_courses_by_field');
}
/**
@ -367,8 +370,8 @@ export class CoreCoursesProvider {
// Get the list of courseIds to use based on the param.
return this.getCourseIdsForAdminAndNavOptions(courseIds, siteId).then((courseIds) => {
let promises = [],
navOptions,
const promises = [];
let navOptions,
admOptions;
// Get user navigation and administration options.
@ -420,12 +423,12 @@ export class CoreCoursesProvider {
*/
getUserAdministrationOptions(courseIds: number[], siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
let params = {
const params = {
courseids: courseIds
},
preSets = {
cacheKey: this.getUserAdministrationOptionsCacheKey(courseIds)
}
};
return site.read('core_course_get_user_administration_options', params, preSets).then((response) => {
// Format returned data.
@ -462,12 +465,12 @@ export class CoreCoursesProvider {
*/
getUserNavigationOptions(courseIds: number[], siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
let params = {
const params = {
courseids: courseIds
},
preSets = {
cacheKey: this.getUserNavigationOptionsCacheKey(courseIds)
}
};
return site.read('core_course_get_user_navigation_options', params, preSets).then((response) => {
// Format returned data.
@ -483,10 +486,10 @@ export class CoreCoursesProvider {
* @return {any} Formatted options.
*/
protected formatUserAdminOrNavOptions(courses: any[]): any {
let result = {};
const result = {};
courses.forEach((course) => {
let options = {};
const options = {};
if (course.options) {
course.options.forEach((option) => {
@ -516,7 +519,7 @@ export class CoreCoursesProvider {
return this.getUserCourses(preferCache, siteId).then((courses) => {
let course;
for (let i in courses) {
for (const i in courses) {
if (courses[i].id == id) {
course = courses[i];
break;
@ -537,7 +540,7 @@ export class CoreCoursesProvider {
getUserCourses(preferCache?: boolean, siteId?: string): Promise<any[]> {
return this.sitesProvider.getSite(siteId).then((site) => {
let userId = site.getUserId(),
const userId = site.getUserId(),
data = {
userid: userId
},
@ -621,7 +624,7 @@ export class CoreCoursesProvider {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.getCourseIdsForAdminAndNavOptions(courseIds, siteId).then((ids) => {
let promises = [];
const promises = [];
promises.push(this.invalidateUserAdministrationOptionsForCourses(ids, siteId));
promises.push(this.invalidateUserNavigationOptionsForCourses(ids, siteId));
@ -725,7 +728,8 @@ export class CoreCoursesProvider {
* @return {boolean} Whether guest WS is available.
*/
isGuestWSAvailable(): boolean {
let currentSite = this.sitesProvider.getCurrentSite();
const currentSite = this.sitesProvider.getCurrentSite();
return currentSite && currentSite.wsAvailable('enrol_guest_get_instance_info');
}
@ -738,18 +742,19 @@ export class CoreCoursesProvider {
* @param {string} [siteId] Site ID. If not defined, use current site.
* @return {Promise<{total: number, courses: any[]}>} Promise resolved with the courses and the total of matches.
*/
search(text: string, page = 0, perPage?: number, siteId?: string) : Promise<{total: number, courses: any[]}> {
search(text: string, page: number = 0, perPage?: number, siteId?: string): Promise<{ total: number, courses: any[] }> {
perPage = perPage || CoreCoursesProvider.SEARCH_PER_PAGE;
return this.sitesProvider.getSite(siteId).then((site) => {
let params = {
const params = {
criterianame: 'search',
criteriavalue: text,
page: page,
perpage: perPage
}, preSets = {
},
preSets = {
getFromCache: false
}
};
return site.read('core_course_search_courses', params, preSets).then((response) => {
return { total: response.total, courses: response.courses };
@ -767,13 +772,14 @@ export class CoreCoursesProvider {
* @return {Promise<any>} Promise resolved if the user is enrolled. If the password is invalid, the promise is rejected
* with an object with code = CoreCoursesProvider.ENROL_INVALID_KEY.
*/
selfEnrol(courseId: number, password = '', instanceId?: number, siteId?: string) : Promise<any> {
selfEnrol(courseId: number, password: string = '', instanceId?: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
let params: any = {
const params: any = {
courseid: courseId,
password: password
}
};
if (instanceId) {
params.instanceid = instanceId;
}
@ -786,7 +792,7 @@ export class CoreCoursesProvider {
let message;
response.warnings.forEach((warning) => {
// Invalid password warnings.
if (warning.warningcode == '2' || warning.warningcode == '3' || warning.warningcode == '4') {
if (warning.warningcode == '2' || warning.warningcode == '3' || warning.warningcode == '4') {
message = warning.message;
}
});
@ -798,6 +804,7 @@ export class CoreCoursesProvider {
}
}
}
return Promise.reject(null);
});
});

View File

@ -31,7 +31,7 @@ export class CoreCoursesMainMenuHandler implements CoreMainMenuHandler {
/**
* Check if the handler is enabled on a site level.
*
* @return {boolean} Whether or not the handler is enabled on a site level.
* @return {boolean | Promise<boolean>} Whether or not the handler is enabled on a site level.
*/
isEnabled(): boolean | Promise<boolean> {
// Check if my overview is enabled.

View File

@ -42,7 +42,7 @@ export class CoreCoursesMyOverviewLinkHandler extends CoreContentLinksHandlerBas
getActions(siteIds: string[], url: string, params: any, courseId?: number):
CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
return [{
action: (siteId, navCtrl?) => {
action: (siteId, navCtrl?): void => {
// Always use redirect to make it the new history root (to avoid "loops" in history).
this.loginHelper.redirect('CoreCoursesMyOverviewPage', undefined, siteId);
}

View File

@ -22,8 +22,8 @@ import * as moment from 'moment';
*/
@Injectable()
export class CoreCoursesMyOverviewProvider {
public static EVENTS_LIMIT = 20;
public static EVENTS_LIMIT_PER_COURSE = 10;
static EVENTS_LIMIT = 20;
static EVENTS_LIMIT_PER_COURSE = 10;
protected ROOT_CACHE_KEY = 'myoverview:';
constructor(private sitesProvider: CoreSitesProvider) { }
@ -40,7 +40,7 @@ export class CoreCoursesMyOverviewProvider {
Promise<{ events: any[], canLoadMore: number }> {
return this.sitesProvider.getSite(siteId).then((site) => {
let time = moment().subtract(14, 'days').unix(), // Check two weeks ago.
const time = moment().subtract(14, 'days').unix(), // Check two weeks ago.
data: any = {
timesortfrom: time,
courseid: courseId,
@ -58,6 +58,7 @@ export class CoreCoursesMyOverviewProvider {
if (courseEvents && courseEvents.events) {
return this.treatCourseEvents(courseEvents, time);
}
return Promise.reject(null);
});
});
@ -80,9 +81,10 @@ export class CoreCoursesMyOverviewProvider {
* @param {string} [siteId] Site ID. If not defined, use current site.
* @return {Promise<{[s: string]: {events: any[], canLoadMore: number}}>} Promise resolved when the info is retrieved.
*/
getActionEventsByCourses(courseIds: number[], siteId?: string) : Promise<{[s: string]: {events: any[], canLoadMore: number}}> {
getActionEventsByCourses(courseIds: number[], siteId?: string): Promise<{ [s: string]:
{ events: any[], canLoadMore: number } }> {
return this.sitesProvider.getSite(siteId).then((site) => {
let time = moment().subtract(14, 'days').unix(), // Check two weeks ago.
const time = moment().subtract(14, 'days').unix(), // Check two weeks ago.
data = {
timesortfrom: time,
courseids: courseIds,
@ -94,7 +96,7 @@ export class CoreCoursesMyOverviewProvider {
return site.read('core_calendar_get_action_events_by_courses', data, preSets).then((events): any => {
if (events && events.groupedbycourse) {
let courseEvents = {};
const courseEvents = {};
events.groupedbycourse.forEach((course) => {
courseEvents[course.courseid] = this.treatCourseEvents(course, time);
@ -126,7 +128,7 @@ export class CoreCoursesMyOverviewProvider {
*/
getActionEventsByTimesort(afterEventId: number, siteId?: string): Promise<{ events: any[], canLoadMore: number }> {
return this.sitesProvider.getSite(siteId).then((site) => {
let time = moment().subtract(14, 'days').unix(), // Check two weeks ago.
const time = moment().subtract(14, 'days').unix(), // Check two weeks ago.
data: any = {
timesortfrom: time,
limitnum: CoreCoursesMyOverviewProvider.EVENTS_LIMIT
@ -143,7 +145,7 @@ export class CoreCoursesMyOverviewProvider {
return site.read('core_calendar_get_action_events_by_timesort', data, preSets).then((events): any => {
if (events && events.events) {
let canLoadMore = events.events.length >= data.limitnum ? events.lastid : undefined;
const canLoadMore = events.events.length >= data.limitnum ? events.lastid : undefined;
// Filter events by time in case it uses cache.
events = events.events.filter((element) => {
@ -155,6 +157,7 @@ export class CoreCoursesMyOverviewProvider {
canLoadMore: canLoadMore
};
}
return Promise.reject(null);
});
});
@ -179,6 +182,7 @@ export class CoreCoursesMyOverviewProvider {
protected getActionEventsByTimesortCacheKey(afterEventId?: number, limit?: number): string {
afterEventId = afterEventId || 0;
limit = limit || 0;
return this.getActionEventsByTimesortPrefixCacheKey() + afterEventId + ':' + limit;
}
@ -226,6 +230,7 @@ export class CoreCoursesMyOverviewProvider {
*/
isDisabledInSite(site?: CoreSite): boolean {
site = site || this.sitesProvider.getCurrentSite();
return site.isFeatureDisabled('$mmSideMenuDelegate_mmaMyOverview');
}
@ -240,6 +245,7 @@ export class CoreCoursesMyOverviewProvider {
return false;
});
}
return Promise.resolve(false);
}
@ -251,7 +257,7 @@ export class CoreCoursesMyOverviewProvider {
* @return {{events: any[], canLoadMore: number}} Object with course events and last loaded event id if more can be loaded.
*/
protected treatCourseEvents(course: any, timeFrom: number): { events: any[], canLoadMore: number } {
let canLoadMore : number =
const canLoadMore: number =
course.events.length >= CoreCoursesMyOverviewProvider.EVENTS_LIMIT_PER_COURSE ? course.lastid : undefined;
// Filter events by time in case it uses cache.

View File

@ -29,7 +29,7 @@ export class InAppBrowserObjectMock extends InAppBrowserObject {
protected isLinux: boolean;
constructor(appProvider: CoreAppProvider, private fileProvider: CoreFileProvider, private urlUtils: CoreUrlUtilsProvider,
private url: string, target?: string, options = '') {
private url: string, target?: string, options: string = '') {
super(url, target, options);
if (!appProvider.isDesktop()) {
@ -44,8 +44,8 @@ export class InAppBrowserObjectMock extends InAppBrowserObject {
let width = 800,
height = 600,
display,
bwOptions: any = {};
display;
const bwOptions: any = {};
if (screen) {
display = this.screen.getPrimaryDisplay();
@ -74,7 +74,7 @@ export class InAppBrowserObjectMock extends InAppBrowserObject {
if (this.isLinux && this.isSSO) {
// SSO in Linux. Simulate it's an iOS device so we can retrieve the launch URL.
// This is needed because custom URL scheme is not supported in Linux.
let userAgent = 'Mozilla/5.0 (iPad) AppleWebKit/603.3.8 (KHTML, like Gecko) Mobile/14G60';
const userAgent = 'Mozilla/5.0 (iPad) AppleWebKit/603.3.8 (KHTML, like Gecko) Mobile/14G60';
this.window.webContents.setUserAgent(userAgent);
}
}
@ -93,7 +93,7 @@ export class InAppBrowserObjectMock extends InAppBrowserObject {
* @return {Promise<any>} Promise resolved when done.
*/
executeScript(details: any): Promise<any> {
return new Promise((resolve, reject) => {
return new Promise((resolve, reject): void => {
if (details.code) {
this.window.webContents.executeJavaScript(details.code, false, resolve);
} else if (details.file) {
@ -112,11 +112,11 @@ export class InAppBrowserObjectMock extends InAppBrowserObject {
* @param {number} [retry=0] Retry number.
* @return {Promise<string>} Promise resolved with the launch URL.
*/
protected getLaunchUrl(retry = 0) : Promise<string> {
return new Promise((resolve, reject) => {
protected getLaunchUrl(retry: number = 0): Promise<string> {
return new Promise((resolve, reject): void => {
// Execute Javascript to retrieve the launch link.
let jsCode = 'var el = document.querySelector("#launchapp"); el && el.href;',
found = false;
const jsCode = 'var el = document.querySelector("#launchapp"); el && el.href;';
let found = false;
this.window.webContents.executeJavaScript(jsCode).then((launchUrl) => {
found = true;
@ -151,7 +151,7 @@ export class InAppBrowserObjectMock extends InAppBrowserObject {
* @return {Promise<any>} Promise resolved when done.
*/
insertCSS(details: any): Promise<any> {
return new Promise((resolve, reject) => {
return new Promise((resolve, reject): void => {
if (details.code) {
this.window.webContents.insertCSS(details.code);
resolve();
@ -175,16 +175,18 @@ export class InAppBrowserObjectMock extends InAppBrowserObject {
*/
on(name: string): Observable<InAppBrowserEvent> {
// Create the observable.
return new Observable<InAppBrowserEvent>((observer: Observer<InAppBrowserEvent>) => {
return new Observable<InAppBrowserEvent>((observer: Observer<InAppBrowserEvent>): any => {
// Helper functions to handle events.
let received = (event, url) => {
const received = (event, url): void => {
try {
event.url = url || this.window.getURL();
event.type = name;
observer.next(event);
} catch(ex) {}
} catch (ex) {
// Ignore errors.
}
},
finishLoad = (event) => {
finishLoad = (event): void => {
// Check if user is back to launch page.
if (this.urlUtils.removeUrlParams(this.url) == this.urlUtils.removeUrlParams(this.window.getURL())) {
// The launch page was loaded. Search for the launch link.
@ -203,7 +205,6 @@ export class InAppBrowserObjectMock extends InAppBrowserObject {
if (this.isLinux && this.isSSO) {
// Linux doesn't support custom URL Schemes. Check if launch page is loaded.
// listeners[callback].push(finishLoad);
this.window.webContents.on('did-finish-load', finishLoad);
}
break;
@ -218,9 +219,10 @@ export class InAppBrowserObjectMock extends InAppBrowserObject {
case 'exit':
this.window.on('close', received);
break;
default:
}
return () => {
return (): void => {
// Unsubscribing. We need to remove the listeners.
switch (name) {
case 'loadstart':
@ -239,6 +241,7 @@ export class InAppBrowserObjectMock extends InAppBrowserObject {
case 'exit':
this.window.removeListener('close', received);
break;
default:
}
};
});

View File

@ -45,10 +45,10 @@ export class SQLiteDBMock extends SQLiteDB {
* @return {Promise<any>} Promise resolved when done.
*/
emptyDatabase(): Promise<any> {
return new Promise((resolve, reject) => {
return new Promise((resolve, reject): void => {
this.db.transaction((tx) => {
// Query all tables from sqlite_master that we have created and can modify.
let args = [],
const args = [],
query = `SELECT * FROM sqlite_master
WHERE name NOT LIKE 'sqlite\\_%' escape '\\' AND name NOT LIKE '\\_%' escape '\\'`;
@ -56,16 +56,17 @@ export class SQLiteDBMock extends SQLiteDB {
if (result.rows.length <= 0) {
// No tables to delete, stop.
resolve();
return;
}
// Drop all the tables.
let promises = [];
const promises = [];
for (let i = 0; i < result.rows.length; i++) {
promises.push(new Promise((resolve, reject) => {
promises.push(new Promise((resolve, reject): void => {
// Drop the table.
let name = JSON.stringify(result.rows.item(i).name);
const name = JSON.stringify(result.rows.item(i).name);
tx.executeSql('DROP TABLE ' + name, [], resolve, reject);
}));
}
@ -86,7 +87,7 @@ export class SQLiteDBMock extends SQLiteDB {
* @return {Promise<any>} Promise resolved with the result.
*/
execute(sql: string, params?: any[]): Promise<any> {
return new Promise((resolve, reject) => {
return new Promise((resolve, reject): void => {
// With WebSQL, all queries must be run in a transaction.
this.db.transaction((tx) => {
tx.executeSql(sql, params, (tx, results) => {
@ -107,14 +108,14 @@ export class SQLiteDBMock extends SQLiteDB {
* @return {Promise<any>} Promise resolved with the result.
*/
executeBatch(sqlStatements: any[]): Promise<any> {
return new Promise((resolve, reject) => {
return new Promise((resolve, reject): void => {
// Create a transaction to execute the queries.
this.db.transaction((tx) => {
let promises = [];
const promises = [];
// Execute all the queries. Each statement can be a string or an array.
sqlStatements.forEach((statement) => {
promises.push(new Promise((resolve, reject) => {
promises.push(new Promise((resolve, reject): void => {
let query,
params;

View File

@ -73,21 +73,21 @@ import { CoreInitDelegate } from '../../providers/init';
{
provide: Camera,
deps: [CoreAppProvider, CoreEmulatorCaptureHelperProvider],
useFactory: (appProvider: CoreAppProvider, captureHelper: CoreEmulatorCaptureHelperProvider) => {
useFactory: (appProvider: CoreAppProvider, captureHelper: CoreEmulatorCaptureHelperProvider): Camera => {
return appProvider.isMobile() ? new Camera() : new CameraMock(captureHelper);
}
},
{
provide: Clipboard,
deps: [CoreAppProvider],
useFactory: (appProvider: CoreAppProvider) => {
useFactory: (appProvider: CoreAppProvider): Clipboard => {
return appProvider.isMobile() ? new Clipboard() : new ClipboardMock(appProvider);
}
},
{
provide: File,
deps: [CoreAppProvider, CoreTextUtilsProvider],
useFactory: (appProvider: CoreAppProvider, textUtils: CoreTextUtilsProvider) => {
useFactory: (appProvider: CoreAppProvider, textUtils: CoreTextUtilsProvider): File => {
// Use platform instead of CoreAppProvider to prevent circular dependencies.
return appProvider.isMobile() ? new File() : new FileMock(appProvider, textUtils);
}
@ -95,7 +95,7 @@ import { CoreInitDelegate } from '../../providers/init';
{
provide: FileTransfer,
deps: [CoreAppProvider, CoreFileProvider],
useFactory: (appProvider: CoreAppProvider, fileProvider: CoreFileProvider) => {
useFactory: (appProvider: CoreAppProvider, fileProvider: CoreFileProvider): FileTransfer => {
// Use platform instead of CoreAppProvider to prevent circular dependencies.
return appProvider.isMobile() ? new FileTransfer() : new FileTransferMock(appProvider, fileProvider);
}
@ -103,14 +103,15 @@ import { CoreInitDelegate } from '../../providers/init';
{
provide: Globalization,
deps: [CoreAppProvider],
useFactory: (appProvider: CoreAppProvider) => {
useFactory: (appProvider: CoreAppProvider): Globalization => {
return appProvider.isMobile() ? new Globalization() : new GlobalizationMock(appProvider);
}
},
{
provide: InAppBrowser,
deps: [CoreAppProvider, CoreFileProvider, CoreUrlUtilsProvider],
useFactory: (appProvider: CoreAppProvider, fileProvider: CoreFileProvider, urlUtils: CoreUrlUtilsProvider) => {
useFactory: (appProvider: CoreAppProvider, fileProvider: CoreFileProvider, urlUtils: CoreUrlUtilsProvider)
: InAppBrowser => {
return !appProvider.isDesktop() ? new InAppBrowser() : new InAppBrowserMock(appProvider, fileProvider, urlUtils);
}
},
@ -118,7 +119,7 @@ import { CoreInitDelegate } from '../../providers/init';
{
provide: LocalNotifications,
deps: [CoreAppProvider, CoreUtilsProvider],
useFactory: (appProvider: CoreAppProvider, utils: CoreUtilsProvider) => {
useFactory: (appProvider: CoreAppProvider, utils: CoreUtilsProvider): LocalNotifications => {
// Use platform instead of CoreAppProvider to prevent circular dependencies.
return appProvider.isMobile() ? new LocalNotifications() : new LocalNotificationsMock(appProvider, utils);
}
@ -126,14 +127,14 @@ import { CoreInitDelegate } from '../../providers/init';
{
provide: MediaCapture,
deps: [CoreAppProvider, CoreEmulatorCaptureHelperProvider],
useFactory: (appProvider: CoreAppProvider, captureHelper: CoreEmulatorCaptureHelperProvider) => {
useFactory: (appProvider: CoreAppProvider, captureHelper: CoreEmulatorCaptureHelperProvider): MediaCapture => {
return appProvider.isMobile() ? new MediaCapture() : new MediaCaptureMock(captureHelper);
}
},
{
provide: Network,
deps: [Platform],
useFactory: (platform: Platform) => {
useFactory: (platform: Platform): Network => {
// Use platform instead of CoreAppProvider to prevent circular dependencies.
return platform.is('cordova') ? new Network() : new NetworkMock();
}
@ -144,7 +145,7 @@ import { CoreInitDelegate } from '../../providers/init';
{
provide: Zip,
deps: [CoreAppProvider, File, CoreMimetypeUtilsProvider, CoreTextUtilsProvider],
useFactory: (appProvider: CoreAppProvider, file: File, mimeUtils: CoreMimetypeUtilsProvider) => {
useFactory: (appProvider: CoreAppProvider, file: File, mimeUtils: CoreMimetypeUtilsProvider): Zip => {
// Use platform instead of CoreAppProvider to prevent circular dependencies.
return appProvider.isMobile() ? new Zip() : new ZipMock(file, mimeUtils);
}
@ -153,7 +154,7 @@ import { CoreInitDelegate } from '../../providers/init';
})
export class CoreEmulatorModule {
constructor(appProvider: CoreAppProvider, initDelegate: CoreInitDelegate, helper: CoreEmulatorHelperProvider) {
let win = <any>window; // Convert the "window" to "any" type to be able to use non-standard properties.
const win = <any> window; // Convert the "window" to "any" type to be able to use non-standard properties.
// Emulate Custom URL Scheme plugin in desktop apps.
if (appProvider.isDesktop()) {

View File

@ -22,7 +22,7 @@ import { CoreTimeUtilsProvider } from '../../../../providers/utils/time';
/**
* Page to capture media in browser or desktop.
*/
@IonicPage({segment: "core-emulator-capture-media"})
@IonicPage({ segment: 'core-emulator-capture-media' })
@Component({
selector: 'page-core-emulator-capture-media',
templateUrl: 'capture-media.html',
@ -75,10 +75,10 @@ export class CoreEmulatorCaptureMediaPage implements OnInit, OnDestroy {
/**
* Component being initialized.
*/
ngOnInit() {
ngOnInit(): void {
this.initVariables();
let constraints = {
const constraints = {
video: this.isAudio ? false : { facingMode: this.facingMode },
audio: !this.isImage
};
@ -99,14 +99,14 @@ export class CoreEmulatorCaptureMediaPage implements OnInit, OnDestroy {
this.mediaRecorder = new this.window.MediaRecorder(this.localMediaStream, { mimeType: this.mimetype });
// When video or audio is recorded, add it to the list of chunks.
this.mediaRecorder.ondataavailable = (e) => {
this.mediaRecorder.ondataavailable = (e): void => {
if (e.data.size > 0) {
chunks.push(e.data);
}
};
// When recording stops, create a Blob element with the recording and set it to the video or audio.
this.mediaRecorder.onstop = () => {
this.mediaRecorder.onstop = (): void => {
this.mediaBlob = new Blob(chunks);
chunks = [];
@ -119,7 +119,7 @@ export class CoreEmulatorCaptureMediaPage implements OnInit, OnDestroy {
waitTimeout;
// Listen for stream ready to display the stream.
this.streamVideo.nativeElement.onloadedmetadata = () => {
this.streamVideo.nativeElement.onloadedmetadata = (): void => {
if (hasLoaded) {
// Already loaded or timeout triggered, stop.
return;
@ -149,7 +149,7 @@ export class CoreEmulatorCaptureMediaPage implements OnInit, OnDestroy {
this.readyToCapture = true;
}
}).catch((error) => {
this.dismissWithError(-1, error.message || error);
this.dismissWithError(-1, error.message || error);
});
}
@ -160,7 +160,10 @@ export class CoreEmulatorCaptureMediaPage implements OnInit, OnDestroy {
* @param {MediaStream} stream Stream returned by getUserMedia.
*/
protected initAudioDrawer(stream: MediaStream): void {
let audioCtx = new (this.window.AudioContext || this.window.webkitAudioContext)(),
let skip = true,
running = false;
const audioCtx = new (this.window.AudioContext || this.window.webkitAudioContext)(),
canvasCtx = this.streamAudio.nativeElement.getContext('2d'),
source = audioCtx.createMediaStreamSource(stream),
analyser = audioCtx.createAnalyser(),
@ -168,9 +171,7 @@ export class CoreEmulatorCaptureMediaPage implements OnInit, OnDestroy {
dataArray = new Uint8Array(bufferLength),
width = this.streamAudio.nativeElement.width,
height = this.streamAudio.nativeElement.height,
running = false,
skip = true,
drawAudio = () => {
drawAudio = (): void => {
if (!running) {
return;
}
@ -184,8 +185,8 @@ export class CoreEmulatorCaptureMediaPage implements OnInit, OnDestroy {
return;
}
let sliceWidth = width / bufferLength,
x = 0;
const sliceWidth = width / bufferLength;
let x = 0;
analyser.getByteTimeDomainData(dataArray);
@ -198,7 +199,7 @@ export class CoreEmulatorCaptureMediaPage implements OnInit, OnDestroy {
canvasCtx.beginPath();
for (let i = 0; i < bufferLength; i++) {
let v = dataArray[i] / 128.0,
const v = dataArray[i] / 128.0,
y = v * height / 2;
if (i === 0) {
@ -218,7 +219,7 @@ export class CoreEmulatorCaptureMediaPage implements OnInit, OnDestroy {
source.connect(analyser);
this.audioDrawer = {
start: () => {
start: (): void => {
if (running) {
return;
}
@ -226,7 +227,7 @@ export class CoreEmulatorCaptureMediaPage implements OnInit, OnDestroy {
running = true;
drawAudio();
},
stop: () => {
stop: (): void => {
running = false;
}
};
@ -235,7 +236,7 @@ export class CoreEmulatorCaptureMediaPage implements OnInit, OnDestroy {
/**
* Initialize some variables based on the params.
*/
protected initVariables() {
protected initVariables(): void {
if (this.type == 'captureimage') {
this.isCaptureImage = true;
this.type = 'image';
@ -271,15 +272,15 @@ export class CoreEmulatorCaptureMediaPage implements OnInit, OnDestroy {
this.cdr.detectChanges();
} else {
// Get the image from the video and set it to the canvas, using video width/height.
let width = this.streamVideo.nativeElement.videoWidth,
height = this.streamVideo.nativeElement.videoHeight;
const width = this.streamVideo.nativeElement.videoWidth,
height = this.streamVideo.nativeElement.videoHeight,
loadingModal = this.domUtils.showModalLoading();
this.imgCanvas.nativeElement.width = width;
this.imgCanvas.nativeElement.height = height;
this.imgCanvas.nativeElement.getContext('2d').drawImage(this.streamVideo.nativeElement, 0, 0, width, height);
// Convert the image to blob and show it in an image element.
let loadingModal = this.domUtils.showModalLoading();
this.imgCanvas.nativeElement.toBlob((blob) => {
loadingModal.dismiss();
@ -312,7 +313,7 @@ export class CoreEmulatorCaptureMediaPage implements OnInit, OnDestroy {
this.resetChrono = true;
delete this.mediaBlob;
this.cdr.detectChanges();
};
}
/**
* Close the modal, returning some data (success).
@ -331,7 +332,7 @@ export class CoreEmulatorCaptureMediaPage implements OnInit, OnDestroy {
* @param {string} [cameraMessage] A specific message to use if it's a Camera capture. If not set, message will be used.
*/
dismissWithError(code: number, message: string, cameraMessage?: string): void {
let isCamera = this.isImage && !this.isCaptureImage,
const isCamera = this.isImage && !this.isCaptureImage,
error = isCamera ? (cameraMessage || message) : { code: code, message: message };
this.viewCtrl.dismiss(error, 'error');
}
@ -343,28 +344,31 @@ export class CoreEmulatorCaptureMediaPage implements OnInit, OnDestroy {
if (this.returnDataUrl) {
// Return the image as a base64 string.
this.dismissWithData(this.imgCanvas.nativeElement.toDataURL(this.mimetype, this.quality));
return;
}
if (!this.mediaBlob) {
// Shouldn't happen.
this.domUtils.showErrorModal('Please capture the media first.');
return;
}
// Create the file and return it.
let fileName = this.type + '_' + this.timeUtils.readableTimestamp() + '.' + this.extension,
path = this.textUtils.concatenatePaths(CoreFileProvider.TMPFOLDER, 'media/' + fileName);
let loadingModal = this.domUtils.showModalLoading();
const fileName = this.type + '_' + this.timeUtils.readableTimestamp() + '.' + this.extension,
path = this.textUtils.concatenatePaths(CoreFileProvider.TMPFOLDER, 'media/' + fileName),
loadingModal = this.domUtils.showModalLoading();
this.fileProvider.writeFile(path, this.mediaBlob).then((fileEntry) => {
if (this.isImage && !this.isCaptureImage) {
this.dismissWithData(fileEntry.toURL());
} else {
// The capture plugin returns a MediaFile, not a FileEntry. The only difference is that
// it supports a new function that won't be supported in desktop.
fileEntry.getFormatData = (successFn, errorFn) => {};
// The capture plugin returns a MediaFile, not a FileEntry.
// The only difference is that it supports a new function that won't be supported in desktop.
fileEntry.getFormatData = (successFn, errorFn): any => {
// Nothing to do.
};
this.dismissWithData([fileEntry]);
}
@ -373,7 +377,7 @@ export class CoreEmulatorCaptureMediaPage implements OnInit, OnDestroy {
}).finally(() => {
loadingModal.dismiss();
});
};
}
/**
* Stop capturing. Only for video and audio.
@ -384,7 +388,7 @@ export class CoreEmulatorCaptureMediaPage implements OnInit, OnDestroy {
this.mediaRecorder && this.mediaRecorder.stop();
this.isCapturing = false;
this.hasCaptured = true;
};
}
/**
* Page destroyed.

View File

@ -32,7 +32,7 @@ export class CameraMock extends Camera {
* @return {Promise<any>} Promise resolved when done.
*/
cleanup(): Promise<any> {
// iOS only, nothing to do.
// This function is iOS only, nothing to do.
return Promise.resolve();
}

View File

@ -49,15 +49,15 @@ export class CoreEmulatorCaptureHelperProvider {
* @return {Promise<any>} Promise resolved when captured, rejected if error.
*/
captureMedia(type: string, options: any): Promise<any> {
options = options || {};
options = options || {};
try {
// Build the params to send to the modal.
let deferred = this.utils.promiseDefer(),
const deferred = this.utils.promiseDefer(),
params: any = {
type: type
},
mimeAndExt,
};
let mimeAndExt,
modal: Modal;
// Initialize some data based on the type of media to capture.
@ -86,7 +86,7 @@ export class CoreEmulatorCaptureHelperProvider {
params.extension = 'jpeg';
}
if (options.quality >= 0 && options.quality <= 100) {
if (options.quality >= 0 && options.quality <= 100) {
params.quality = options.quality / 100;
}
@ -122,13 +122,13 @@ export class CoreEmulatorCaptureHelperProvider {
* @param {string[]} [mimetypes] List of supported mimetypes. If undefined, all mimetypes supported.
* @return {{extension: string, mimetype: string}} An object with mimetype and extension to use.
*/
protected getMimeTypeAndExtension(type: string, mimetypes) : {extension: string, mimetype: string} {
var result: any = {};
protected getMimeTypeAndExtension(type: string, mimetypes: string[]): { extension: string, mimetype: string } {
const result: any = {};
if (mimetypes && mimetypes.length) {
// Search for a supported mimetype.
for (let i = 0; i < mimetypes.length; i++) {
let mimetype = mimetypes[i],
const mimetype = mimetypes[i],
matches = mimetype.match(new RegExp('^' + type + '/'));
if (matches && matches.length && this.win.MediaRecorder.isTypeSupported(mimetype)) {
@ -160,7 +160,7 @@ export class CoreEmulatorCaptureHelperProvider {
* @return {boolean} Whether the function is supported.
*/
protected initGetUserMedia(): boolean {
let nav = <any>navigator;
const nav = <any> navigator;
// Check if there is a function to get user media.
if (typeof nav.mediaDevices == 'undefined') {
nav.mediaDevices = {};
@ -172,9 +172,10 @@ export class CoreEmulatorCaptureHelperProvider {
if (nav.getUserMedia) {
// Deprecated function exists, support the new function using the deprecated one.
navigator.mediaDevices.getUserMedia = (constraints) => {
let deferred = this.utils.promiseDefer();
navigator.mediaDevices.getUserMedia = (constraints): Promise<any> => {
const deferred = this.utils.promiseDefer();
nav.getUserMedia(constraints, deferred.resolve, deferred.reject);
return deferred.promise;
};
} else {
@ -190,14 +191,14 @@ export class CoreEmulatorCaptureHelperProvider {
*/
protected initMimeTypes(): void {
// Determine video and audio mimetype to use.
for (let mimeType in this.possibleVideoMimeTypes) {
for (const mimeType in this.possibleVideoMimeTypes) {
if (this.win.MediaRecorder.isTypeSupported(mimeType)) {
this.videoMimeType = mimeType;
break;
}
}
for (let mimeType in this.possibleAudioMimeTypes) {
for (const mimeType in this.possibleAudioMimeTypes) {
if (this.win.MediaRecorder.isTypeSupported(mimeType)) {
this.audioMimeType = mimeType;
break;

View File

@ -47,7 +47,7 @@ export class ClipboardMock extends Clipboard {
* @return {Promise<any>} Promise resolved when copied.
*/
copy(text: string): Promise<any> {
return new Promise((resolve, reject) => {
return new Promise((resolve, reject): void => {
if (this.isDesktop) {
this.clipboard.writeText(text);
resolve();
@ -77,7 +77,7 @@ export class ClipboardMock extends Clipboard {
* @return {Promise<any>} Promise resolved with the text.
*/
paste(): Promise<any> {
return new Promise((resolve, reject) => {
return new Promise((resolve, reject): void => {
if (this.isDesktop) {
resolve(this.clipboard.readText());
} else {

View File

@ -21,16 +21,16 @@ import { CoreFileProvider } from '../../../providers/file';
* Mock the File Transfer Error.
*/
export class FileTransferErrorMock implements FileTransferError {
public static FILE_NOT_FOUND_ERR = 1;
public static INVALID_URL_ERR = 2;
public static CONNECTION_ERR = 3;
public static ABORT_ERR = 4;
public static NOT_MODIFIED_ERR = 5;
static FILE_NOT_FOUND_ERR = 1;
static INVALID_URL_ERR = 2;
static CONNECTION_ERR = 3;
static ABORT_ERR = 4;
static NOT_MODIFIED_ERR = 5;
// tslint:disable-next-line: variable-name
constructor(public code: number, public source: string, public target: string, public http_status: number,
public body: string, public exception: string) {
public body: string, public exception: string) { }
}
};
/**
* Emulates the Cordova FileTransfer plugin in desktop apps and in browser.
@ -60,7 +60,7 @@ export class FileTransferObjectMock extends FileTransferObject {
source: string;
target: string;
xhr: XMLHttpRequest;
private reject: Function;
protected reject: Function;
constructor(private appProvider: CoreAppProvider, private fileProvider: CoreFileProvider) {
super();
@ -87,12 +87,12 @@ export class FileTransferObjectMock extends FileTransferObject {
* @returns {Promise<any>} Returns a Promise that resolves to a FileEntry object.
*/
download(source: string, target: string, trustAllHosts?: boolean, options?: { [s: string]: any; }): Promise<any> {
return new Promise((resolve, reject) => {
return new Promise((resolve, reject): void => {
// Use XMLHttpRequest instead of HttpClient to support onprogress and abort.
let basicAuthHeader = this.getBasicAuthHeader(source),
const basicAuthHeader = this.getBasicAuthHeader(source),
xhr = new XMLHttpRequest(),
isDesktop = this.appProvider.isDesktop(),
headers = null;
isDesktop = this.appProvider.isDesktop();
let headers = null;
this.xhr = xhr;
this.source = source;
@ -114,21 +114,21 @@ export class FileTransferObjectMock extends FileTransferObject {
// Prepare the request.
xhr.open('GET', source, true);
xhr.responseType = isDesktop ? 'arraybuffer' : 'blob';
for (let name in headers) {
for (const name in headers) {
xhr.setRequestHeader(name, headers[name]);
}
(<any>xhr).onprogress = (xhr, ev) => {
(<any> xhr).onprogress = (xhr, ev): void => {
if (this.progressListener) {
this.progressListener(ev);
}
};
xhr.onerror = (err) => {
xhr.onerror = (err): void => {
reject(new FileTransferError(-1, source, target, xhr.status, xhr.statusText));
};
xhr.onload = () => {
xhr.onload = (): void => {
// Finished dowloading the file.
let response = xhr.response;
if (!response) {
@ -160,8 +160,7 @@ export class FileTransferObjectMock extends FileTransferObject {
protected getBasicAuthHeader(urlString: string): any {
let header = null;
// This is changed due to MS Windows doesn't support credentials in http uris
// so we detect them by regexp and strip off from result url.
// MS Windows doesn't support credentials in http uris so we detect them by regexp and strip off from result url.
if (window.btoa) {
const credentials = this.getUrlCredentials(urlString);
if (credentials) {
@ -185,12 +184,12 @@ export class FileTransferObjectMock extends FileTransferObject {
* @return {{[s: string]: any}} Object with the headers.
*/
protected getHeadersAsObject(xhr: XMLHttpRequest): { [s: string]: any } {
const headersString = xhr.getAllResponseHeaders();
let result = {};
const headersString = xhr.getAllResponseHeaders(),
result = {};
if (headersString) {
const headers = headersString.split('\n');
for (let i in headers) {
for (const i in headers) {
const headerString = headers[i],
separatorPos = headerString.indexOf(':');
if (separatorPos != -1) {
@ -198,6 +197,7 @@ export class FileTransferObjectMock extends FileTransferObject {
}
}
}
return result;
}
@ -234,14 +234,14 @@ export class FileTransferObjectMock extends FileTransferObject {
* @returns {Promise<FileUploadResult>} Promise that resolves to a FileUploadResult and rejects with FileTransferError.
*/
upload(fileUrl: string, url: string, options?: FileUploadOptions, trustAllHosts?: boolean): Promise<FileUploadResult> {
return new Promise((resolve, reject) => {
return new Promise((resolve, reject): void => {
const basicAuthHeader = this.getBasicAuthHeader(url);
let fileKey = null,
fileName = null,
mimeType = null,
params = null,
headers = null,
httpMethod = null,
basicAuthHeader = this.getBasicAuthHeader(url);
httpMethod = null;
if (basicAuthHeader) {
url = url.replace(this.getUrlCredentials(url) + '@', '');
@ -258,7 +258,7 @@ export class FileTransferObjectMock extends FileTransferObject {
headers = options.headers;
httpMethod = options.httpMethod || 'POST';
if (httpMethod.toUpperCase() == "PUT"){
if (httpMethod.toUpperCase() == 'PUT') {
httpMethod = 'PUT';
} else {
httpMethod = 'POST';
@ -275,11 +275,11 @@ export class FileTransferObjectMock extends FileTransferObject {
headers = headers || {};
if (!headers['Content-Disposition']) {
headers['Content-Disposition'] = 'form-data;' + (fileKey ? ' name="' + fileKey + '";' : '') +
(fileName ? ' filename="' + fileName + '"' : '')
(fileName ? ' filename="' + fileName + '"' : '');
}
// For some reason, adding a Content-Type header with the mimeType makes the request fail (it doesn't detect
// the token in the params). Don't include this header, and delete it if it's supplied.
// Adding a Content-Type header with the mimeType makes the request fail (it doesn't detect the token in the params).
// Don't include this header, and delete it if it's supplied.
delete headers['Content-Type'];
// Get the file to upload.
@ -287,9 +287,9 @@ export class FileTransferObjectMock extends FileTransferObject {
return this.fileProvider.getFileObjectFromFileEntry(fileEntry);
}).then((file) => {
// Use XMLHttpRequest instead of HttpClient to support onprogress and abort.
let xhr = new XMLHttpRequest();
xhr.open(httpMethod || 'POST', url);
for (let name in headers) {
const xhr = new XMLHttpRequest();
xhr.open(httpMethod || 'POST', url);
for (const name in headers) {
// Filter "unsafe" headers.
if (name != 'Connection') {
xhr.setRequestHeader(name, headers[name]);
@ -307,24 +307,23 @@ export class FileTransferObjectMock extends FileTransferObject {
this.target = url;
this.reject = reject;
xhr.onerror = () => {
xhr.onerror = (): void => {
reject(new FileTransferError(-1, fileUrl, url, xhr.status, xhr.statusText));
};
xhr.onload = () => {
xhr.onload = (): void => {
// Finished uploading the file.
let result: FileUploadResult = {
resolve({
bytesSent: file.size,
responseCode: xhr.status,
response: xhr.response,
headers: this.getHeadersAsObject(xhr)
};
resolve(result);
});
};
// Create a form data to send params and the file.
let fd = new FormData();
for (var name in params) {
const fd = new FormData();
for (const name in params) {
fd.append(name, params[name]);
}
fd.append('file', file);

View File

@ -37,7 +37,8 @@ export class FileMock extends File {
* @returns {Promise<boolean>} Returns a Promise that resolves to true if the directory exists or rejects with an error.
*/
checkDir(path: string, dir: string): Promise<boolean> {
let fullPath = this.textUtils.concatenatePaths(path, dir);
const fullPath = this.textUtils.concatenatePaths(path, dir);
return this.resolveDirectoryUrl(fullPath).then(() => {
return true;
});
@ -55,8 +56,9 @@ export class FileMock extends File {
if (fse.isFile) {
return true;
} else {
let err = new FileError(13);
const err = new FileError(13);
err.message = 'input is not a file';
return Promise.reject<boolean>(err);
}
});
@ -71,7 +73,7 @@ export class FileMock extends File {
* @returns {Promise<Entry>} Returns a Promise that resolves to the new Entry object or rejects with an error.
*/
private copyMock(srce: Entry, destDir: DirectoryEntry, newName: string): Promise<Entry> {
return new Promise<Entry>((resolve, reject) => {
return new Promise<Entry>((resolve, reject): void => {
srce.copyTo(destDir, newName, (deste) => {
resolve(deste);
}, (err) => {
@ -132,7 +134,7 @@ export class FileMock extends File {
* @returns {Promise<DirectoryEntry>} Returns a Promise that resolves with a DirectoryEntry or rejects with an error.
*/
createDir(path: string, dirName: string, replace: boolean): Promise<DirectoryEntry> {
let options: any = {
const options: any = {
create: true
};
@ -156,7 +158,7 @@ export class FileMock extends File {
* @returns {Promise<FileEntry>} Returns a Promise that resolves to a FileEntry or rejects with an error.
*/
createFile(path: string, fileName: string, replace: boolean): Promise<FileEntry> {
let options: any = {
const options: any = {
create: true
};
@ -176,7 +178,7 @@ export class FileMock extends File {
* @returns {Promise<FileWriter>} Promise resolved with the FileWriter.
*/
private createWriterMock(fe: FileEntry): Promise<FileWriter> {
return new Promise<FileWriter>((resolve, reject) => {
return new Promise<FileWriter>((resolve, reject): void => {
fe.createWriter((writer) => {
resolve(writer);
}, (err) => {
@ -194,7 +196,9 @@ export class FileMock extends File {
private fillErrorMessageMock(err: any): void {
try {
err.message = this.cordovaFileError[err.code];
} catch (e) { }
} catch (e) {
// Ignore errors.
}
}
/**
@ -206,7 +210,7 @@ export class FileMock extends File {
* @returns {Promise<DirectoryEntry>}
*/
getDirectory(directoryEntry: DirectoryEntry, directoryName: string, flags: Flags): Promise<DirectoryEntry> {
return new Promise<DirectoryEntry>((resolve, reject) => {
return new Promise<DirectoryEntry>((resolve, reject): void => {
try {
directoryEntry.getDirectory(directoryName, flags, (de) => {
resolve(de);
@ -229,7 +233,7 @@ export class FileMock extends File {
* @returns {Promise<FileEntry>}
*/
getFile(directoryEntry: DirectoryEntry, fileName: string, flags: Flags): Promise<FileEntry> {
return new Promise<FileEntry>((resolve, reject) => {
return new Promise<FileEntry>((resolve, reject): void => {
try {
directoryEntry.getFile(fileName, flags, resolve, (err) => {
this.fillErrorMessageMock(err);
@ -250,15 +254,16 @@ export class FileMock extends File {
getFreeDiskSpace(): Promise<number> {
// FRequest a file system instance with a minimum size until we get an error.
if (window.requestFileSystem) {
return new Promise((resolve, reject) => {
return new Promise((resolve, reject): void => {
let iterations = 0,
maxIterations = 50,
calculateByRequest = (size: number, ratio: number) => {
return new Promise((resolve, reject) => {
maxIterations = 50;
const calculateByRequest = (size: number, ratio: number): Promise<any> => {
return new Promise((resolve, reject): void => {
window.requestFileSystem(LocalFileSystem.PERSISTENT, size, () => {
iterations++;
if (iterations > maxIterations) {
resolve(size);
return;
}
calculateByRequest(size * ratio, ratio).then(resolve);
@ -295,7 +300,8 @@ export class FileMock extends File {
return this.resolveDirectoryUrl(path).then((fse) => {
return this.getDirectory(fse, dirName, { create: false, exclusive: false });
}).then((de) => {
let reader: any = de.createReader();
const reader: any = de.createReader();
return this.readEntriesMock(reader);
});
}
@ -306,9 +312,9 @@ export class FileMock extends File {
* @return {Promise<any>} Promise resolved when loaded.
*/
load(): Promise<any> {
return new Promise((resolve, reject) => {
let basePath,
win = <any> window; // Convert to <any> to be able to use non-standard properties.
return new Promise((resolve, reject): void => {
const win = <any> window; // Convert to <any> to be able to use non-standard properties.
let basePath;
if (typeof win.requestFileSystem == 'undefined') {
win.requestFileSystem = win.webkitRequestFileSystem;
@ -321,15 +327,16 @@ export class FileMock extends File {
};
if (this.appProvider.isDesktop()) {
let fs = require('fs'),
const fs = require('fs'),
app = require('electron').remote.app;
// emulateCordovaFileForDesktop(fs);
// @todo emulateCordovaFileForDesktop(fs);
// Initialize File System. Get the path to use.
basePath = app.getPath('documents') || app.getPath('home');
if (!basePath) {
reject('Cannot calculate base path for file system.');
return;
}
@ -339,7 +346,7 @@ export class FileMock extends File {
fs.mkdir(basePath, (e) => {
if (!e || (e && e.code === 'EEXIST')) {
// Create successful or it already exists. Resolve.
// this.fileProvider.setHTMLBasePath(basePath);
// @todo this.fileProvider.setHTMLBasePath(basePath);
resolve(basePath);
} else {
reject('Error creating base path.');
@ -367,7 +374,7 @@ export class FileMock extends File {
* @returns {Promise<Entry>} Returns a Promise that resolves to the new Entry object or rejects with an error.
*/
private moveMock(srce: Entry, destDir: DirectoryEntry, newName: string): Promise<Entry> {
return new Promise<Entry>((resolve, reject) => {
return new Promise<Entry>((resolve, reject): void => {
srce.moveTo(destDir, newName, (deste) => {
resolve(deste);
}, (err) => {
@ -443,7 +450,6 @@ export class FileMock extends File {
* Read file and return data as a base64 encoded data url.
* A data url is of the form:
* data: [<mediatype>][;base64],<data>
* @param {string} path Base FileSystem.
* @param {string} file Name of file, relative to path.
* @returns {Promise<string>} Returns a Promise that resolves with the contents of the file as data URL or rejects
@ -471,7 +477,7 @@ export class FileMock extends File {
* @return {Promise<Entry[]>} Promise resolved with the list of files/dirs.
*/
private readEntriesMock(dr: DirectoryReader): Promise<Entry[]> {
return new Promise<Entry[]>((resolve, reject) => {
return new Promise<Entry[]>((resolve, reject): void => {
dr.readEntries((entries: any) => {
resolve(entries);
}, (err) => {
@ -494,8 +500,9 @@ export class FileMock extends File {
return this.getFile(directoryEntry, file, { create: false });
}).then((fileEntry: FileEntry) => {
const reader = new FileReader();
return new Promise<T>((resolve, reject) => {
reader.onloadend = () => {
return new Promise<T>((resolve, reject): void => {
reader.onloadend = (): void => {
if (reader.result !== undefined || reader.result !== null) {
resolve(<T> <any> reader.result);
} else if (reader.error !== undefined || reader.error !== null) {
@ -507,7 +514,7 @@ export class FileMock extends File {
fileEntry.file((file) => {
reader[`readAs${readAs}`].call(reader, file);
}, error => {
}, (error) => {
reject(error);
});
});
@ -521,7 +528,7 @@ export class FileMock extends File {
* @return {Promise<any>} Promise resolved when done.
*/
private removeMock(fe: Entry): Promise<any> {
return new Promise<any>((resolve, reject) => {
return new Promise<any>((resolve, reject): void => {
fe.remove(() => {
resolve({ success: true, fileRemoved: fe });
}, (err) => {
@ -588,6 +595,7 @@ export class FileMock extends File {
} else {
const err = new FileError(13);
err.message = 'input is not a directory';
return Promise.reject<DirectoryEntry>(err);
}
});
@ -599,7 +607,7 @@ export class FileMock extends File {
* @returns {Promise<Entry>}
*/
resolveLocalFilesystemUrl(fileUrl: string): Promise<Entry> {
return new Promise<Entry>((resolve, reject) => {
return new Promise<Entry>((resolve, reject): void => {
try {
window.resolveLocalFileSystemURL(fileUrl, (entry: any) => {
resolve(entry);
@ -621,7 +629,7 @@ export class FileMock extends File {
* @return {Promise<any>} Promise resolved when done.
*/
private rimrafMock(de: DirectoryEntry): Promise<any> {
return new Promise<any>((resolve, reject) => {
return new Promise<any>((resolve, reject): void => {
de.removeRecursively(() => {
resolve({ success: true, fileRemoved: de });
}, (err) => {
@ -643,8 +651,8 @@ export class FileMock extends File {
return this.writeFileInChunksMock(writer, data);
}
return new Promise<any>((resolve, reject) => {
writer.onwriteend = (evt) => {
return new Promise<any>((resolve, reject): void => {
writer.onwriteend = (evt): void => {
if (writer.error) {
reject(writer.error);
} else {
@ -667,7 +675,8 @@ export class FileMock extends File {
return this.writeFile(path, fileName, text, { replace: true });
}
/** Write a new file to the desired location.
/**
* Write a new file to the desired location.
*
* @param {string} path Base FileSystem. Please refer to the iOS and Android filesystems above
* @param {string} fileName path relative to base path
@ -696,7 +705,7 @@ export class FileMock extends File {
* @param {IWriteOptions} options replace file if set to true. See WriteOptions for more information.
* @returns {Promise<FileEntry>} Returns a Promise that resolves to updated file entry or rejects with an error.
*/
private writeFileEntryMock(fe: FileEntry, text: string | Blob | ArrayBuffer, options: IWriteOptions) {
private writeFileEntryMock(fe: FileEntry, text: string | Blob | ArrayBuffer, options: IWriteOptions): Promise<FileEntry> {
return this.createWriterMock(fe).then((writer) => {
if (options.append) {
writer.seek(writer.length);
@ -718,20 +727,19 @@ export class FileMock extends File {
* @return {Promise<any>} Promise resolved when done.
*/
private writeFileInChunksMock(writer: FileWriter, data: Blob): Promise<any> {
const BLOCK_SIZE = 1024 * 1024;
let writtenSize = 0;
function writeNextChunk() {
const BLOCK_SIZE = 1024 * 1024,
writeNextChunk = (): void => {
const size = Math.min(BLOCK_SIZE, data.size - writtenSize);
const chunk = data.slice(writtenSize, writtenSize + size);
writtenSize += size;
writer.write(chunk);
}
};
return new Promise<any>((resolve, reject) => {
return new Promise<any>((resolve, reject): void => {
writer.onerror = reject;
writer.onwrite = () => {
writer.onwrite = (): void => {
if (writtenSize < data.size) {
writeNextChunk();
} else {

Some files were not shown because too many files have changed in this diff Show More