2
0
Fork 0

MOBILE-2748 icon: Make getModuleIconSrc async

main
Pau Ferrer Ocaña 2021-09-27 16:46:43 +02:00
parent 74891f4e2f
commit 1c0a86d045
22 changed files with 123 additions and 117 deletions

View File

@ -99,9 +99,9 @@ export class AddonBlockActivityModulesComponent extends CoreBlockBaseComponent i
let icon: string; let icon: string;
if (modName === 'resources') { if (modName === 'resources') {
icon = CoreCourse.getModuleIconSrc('page', modIcons['page']); icon = await CoreCourse.getModuleIconSrc('page', modIcons['page']);
} else { } else {
icon = CoreCourseModuleDelegate.getModuleIconSrc(modName, modIcons[modName]) || ''; icon = await CoreCourseModuleDelegate.getModuleIconSrc(modName, modIcons[modName]);
} }
this.entries.push({ this.entries.push({

View File

@ -52,14 +52,14 @@ export class AddonBlockRecentlyAccessedItemsProvider {
const items: AddonBlockRecentlyAccessedItemsItem[] = const items: AddonBlockRecentlyAccessedItemsItem[] =
await site.read('block_recentlyaccesseditems_get_recent_items', undefined, preSets); await site.read('block_recentlyaccesseditems_get_recent_items', undefined, preSets);
return items.map((item) => { return await Promise.all(items.map(async (item) => {
const modicon = item.icon && CoreDomUtils.getHTMLElementAttribute(item.icon, 'src'); const modicon = item.icon && CoreDomUtils.getHTMLElementAttribute(item.icon, 'src');
item.iconUrl = CoreCourse.getModuleIconSrc(item.modname, modicon || undefined); item.iconUrl = await CoreCourse.getModuleIconSrc(item.modname, modicon || undefined);
item.iconTitle = item.icon && CoreDomUtils.getHTMLElementAttribute(item.icon, 'title'); item.iconTitle = item.icon && CoreDomUtils.getHTMLElementAttribute(item.icon, 'title');
return item; return item;
}); }));
} }
/** /**

View File

@ -51,12 +51,12 @@ export class AddonBlockTimelineEventsComponent implements OnChanges {
/** /**
* Detect changes on input properties. * Detect changes on input properties.
*/ */
ngOnChanges(changes: {[name: string]: SimpleChange}): void { async ngOnChanges(changes: {[name: string]: SimpleChange}): Promise<void> {
this.showCourse = CoreUtils.isTrueOrOne(this.showCourse); this.showCourse = CoreUtils.isTrueOrOne(this.showCourse);
if (changes.events || changes.from || changes.to) { if (changes.events || changes.from || changes.to) {
if (this.events && this.events.length > 0) { if (this.events && this.events.length > 0) {
const filteredEvents = this.filterEventsByTime(this.from, this.to); const filteredEvents = await this.filterEventsByTime(this.from, this.to);
this.empty = !filteredEvents || filteredEvents.length <= 0; this.empty = !filteredEvents || filteredEvents.length <= 0;
const eventsByDay: Record<number, AddonCalendarEvent[]> = {}; const eventsByDay: Record<number, AddonCalendarEvent[]> = {};
@ -92,22 +92,22 @@ export class AddonBlockTimelineEventsComponent implements OnChanges {
* @param end Number of days after the start. * @param end Number of days after the start.
* @return Filtered events. * @return Filtered events.
*/ */
protected filterEventsByTime(start: number, end?: number): AddonBlockTimelineEvent[] { protected async filterEventsByTime(start: number, end?: number): Promise<AddonBlockTimelineEvent[]> {
start = moment().add(start, 'days').startOf('day').unix(); start = moment().add(start, 'days').startOf('day').unix();
end = typeof end != 'undefined' ? moment().add(end, 'days').startOf('day').unix() : end; end = typeof end != 'undefined' ? moment().add(end, 'days').startOf('day').unix() : end;
return this.events.filter((event) => { return await Promise.all(this.events.filter((event) => {
if (end) { if (end) {
return start <= event.timesort && event.timesort < end; return start <= event.timesort && event.timesort < end;
} }
return start <= event.timesort; return start <= event.timesort;
}).map((event) => { }).map(async (event) => {
event.iconUrl = CoreCourse.getModuleIconSrc(event.icon.component); event.iconUrl = await CoreCourse.getModuleIconSrc(event.icon.component);
event.iconTitle = event.modulename && CoreCourse.translateModuleName(event.modulename); event.iconTitle = event.modulename && CoreCourse.translateModuleName(event.modulename);
return event; return event;
}); }));
} }
/** /**

View File

@ -68,8 +68,8 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro
isCurrentMonth = false; isCurrentMonth = false;
isPastMonth = false; isPastMonth = false;
protected year?: number; protected year: number;
protected month?: number; protected month: number;
protected categoriesRetrieved = false; protected categoriesRetrieved = false;
protected categories: { [id: number]: CoreCategoryData } = {}; protected categories: { [id: number]: CoreCategoryData } = {};
protected currentSiteId: string; protected currentSiteId: string;
@ -121,16 +121,19 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro
); );
this.differ = differs.find([]).create(); this.differ = differs.find([]).create();
const now = new Date();
this.year = now.getFullYear();
this.month = now.getMonth() + 1;
} }
/** /**
* Component loaded. * Component loaded.
*/ */
ngOnInit(): void { ngOnInit(): void {
const now = new Date(); this.year = this.initialYear ? this.initialYear : this.year;
this.month = this.initialMonth ? this.initialMonth : this.month;
this.year = this.initialYear ? this.initialYear : now.getFullYear();
this.month = this.initialMonth ? this.initialMonth : now.getMonth() + 1;
this.calculateIsCurrentMonth(); this.calculateIsCurrentMonth();
@ -211,11 +214,11 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro
// Don't pass courseId and categoryId, we'll filter them locally. // Don't pass courseId and categoryId, we'll filter them locally.
let result: { daynames: Partial<AddonCalendarDayName>[]; weeks: Partial<AddonCalendarWeek>[] }; let result: { daynames: Partial<AddonCalendarDayName>[]; weeks: Partial<AddonCalendarWeek>[] };
try { try {
result = await AddonCalendar.getMonthlyEvents(this.year!, this.month!); result = await AddonCalendar.getMonthlyEvents(this.year, this.month);
} catch (error) { } catch (error) {
if (!CoreApp.isOnline()) { if (!CoreApp.isOnline()) {
// Allow navigating to non-cached months in offline (behave as if using emergency cache). // Allow navigating to non-cached months in offline (behave as if using emergency cache).
result = await AddonCalendarHelper.getOfflineMonthWeeks(this.year!, this.month!); result = await AddonCalendarHelper.getOfflineMonthWeeks(this.year, this.month);
} else { } else {
throw error; throw error;
} }
@ -223,27 +226,29 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro
// Calculate the period name. We don't use the one in result because it's in server's language. // Calculate the period name. We don't use the one in result because it's in server's language.
this.periodName = CoreTimeUtils.userDate( this.periodName = CoreTimeUtils.userDate(
new Date(this.year!, this.month! - 1).getTime(), new Date(this.year, this.month - 1).getTime(),
'core.strftimemonthyear', 'core.strftimemonthyear',
); );
this.weekDays = AddonCalendar.getWeekDays(result.daynames[0].dayno); this.weekDays = AddonCalendar.getWeekDays(result.daynames[0].dayno);
this.weeks = result.weeks as AddonCalendarWeek[]; this.weeks = result.weeks as AddonCalendarWeek[];
this.calculateIsCurrentMonth(); this.calculateIsCurrentMonth();
this.weeks.forEach((week) => { await Promise.all(this.weeks.map(async (week) => {
week.days.forEach((day) => { await Promise.all(week.days.map(async (day) => {
day.periodName = CoreTimeUtils.userDate( day.periodName = CoreTimeUtils.userDate(
new Date(this.year!, this.month! - 1, day.mday).getTime(), new Date(this.year, this.month - 1, day.mday).getTime(),
'core.strftimedaydate', 'core.strftimedaydate',
); );
day.eventsFormated = day.eventsFormated || []; day.eventsFormated = day.eventsFormated || [];
day.filteredEvents = day.filteredEvents || []; day.filteredEvents = day.filteredEvents || [];
day.events.forEach((event) => { // Format online events.
/// Format online events. const onlineEventsFormatted = await Promise.all(
day.eventsFormated!.push(AddonCalendarHelper.formatEventData(event)); day.events.map(async (event) => AddonCalendarHelper.formatEventData(event)),
}); );
});
}); day.eventsFormated = day.eventsFormated.concat(onlineEventsFormatted);
}));
}));
if (this.isCurrentMonth) { if (this.isCurrentMonth) {
const currentDay = new Date().getDate(); const currentDay = new Date().getDate();
@ -323,7 +328,7 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro
// Don't invalidate monthly events after a change, it has already been handled. // Don't invalidate monthly events after a change, it has already been handled.
if (!afterChange) { if (!afterChange) {
promises.push(AddonCalendar.invalidateMonthlyEvents(this.year!, this.month!)); promises.push(AddonCalendar.invalidateMonthlyEvents(this.year, this.month));
} }
promises.push(CoreCourses.invalidateCategories(0, true)); promises.push(CoreCourses.invalidateCategories(0, true));
promises.push(AddonCalendar.invalidateTimeFormat()); promises.push(AddonCalendar.invalidateTimeFormat());
@ -386,7 +391,7 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro
* @param day Day. * @param day Day.
*/ */
dayClicked(day: number): void { dayClicked(day: number): void {
this.onDayClicked.emit({ day: day, month: this.month!, year: this.year! }); this.onDayClicked.emit({ day: day, month: this.month, year: this.year });
} }
/** /**
@ -398,7 +403,7 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro
this.currentTime = CoreTimeUtils.timestamp(); this.currentTime = CoreTimeUtils.timestamp();
this.isCurrentMonth = this.year == now.getFullYear() && this.month == now.getMonth() + 1; this.isCurrentMonth = this.year == now.getFullYear() && this.month == now.getMonth() + 1;
this.isPastMonth = this.year! < now.getFullYear() || (this.year == now.getFullYear() && this.month! < now.getMonth() + 1); this.isPastMonth = this.year < now.getFullYear() || (this.year == now.getFullYear() && this.month < now.getMonth() + 1);
} }
/** /**
@ -432,9 +437,9 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro
protected decreaseMonth(): void { protected decreaseMonth(): void {
if (this.month === 1) { if (this.month === 1) {
this.month = 12; this.month = 12;
this.year!--; this.year--;
} else { } else {
this.month!--; this.month--;
} }
} }
@ -444,9 +449,9 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro
protected increaseMonth(): void { protected increaseMonth(): void {
if (this.month === 12) { if (this.month === 12) {
this.month = 1; this.month = 1;
this.year!++; this.year++;
} else { } else {
this.month!++; this.month++;
} }
} }
@ -455,7 +460,7 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro
*/ */
protected mergeEvents(): void { protected mergeEvents(): void {
const monthOfflineEvents: { [day: number]: AddonCalendarEventToDisplay[] } = const monthOfflineEvents: { [day: number]: AddonCalendarEventToDisplay[] } =
this.offlineEvents[AddonCalendarHelper.getMonthId(this.year!, this.month!)]; this.offlineEvents[AddonCalendarHelper.getMonthId(this.year, this.month)];
this.weeks.forEach((week) => { this.weeks.forEach((week) => {
week.days.forEach((day) => { week.days.forEach((day) => {

View File

@ -173,7 +173,7 @@ export class AddonCalendarUpcomingEventsComponent implements OnInit, DoCheck, On
async fetchEvents(): Promise<void> { async fetchEvents(): Promise<void> {
// Don't pass courseId and categoryId, we'll filter them locally. // Don't pass courseId and categoryId, we'll filter them locally.
const result = await AddonCalendar.getUpcomingEvents(); const result = await AddonCalendar.getUpcomingEvents();
this.onlineEvents = result.events.map((event) => AddonCalendarHelper.formatEventData(event)); this.onlineEvents = await Promise.all(result.events.map((event) => AddonCalendarHelper.formatEventData(event)));
// Schedule notifications for the events retrieved. // Schedule notifications for the events retrieved.
AddonCalendar.scheduleEventsNotifications(this.onlineEvents); AddonCalendar.scheduleEventsNotifications(this.onlineEvents);
// Merge the online events with offline data. // Merge the online events with offline data.

View File

@ -333,7 +333,7 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
try { try {
// Don't pass courseId and categoryId, we'll filter them locally. // Don't pass courseId and categoryId, we'll filter them locally.
result = await AddonCalendar.getDayEvents(this.year, this.month, this.day); result = await AddonCalendar.getDayEvents(this.year, this.month, this.day);
this.onlineEvents = result.events.map((event) => AddonCalendarHelper.formatEventData(event)); this.onlineEvents = await Promise.all(result.events.map((event) => AddonCalendarHelper.formatEventData(event)));
} catch (error) { } catch (error) {
if (CoreApp.isOnline()) { if (CoreApp.isOnline()) {
throw error; throw error;

View File

@ -207,7 +207,7 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
try { try {
// Get the event data. // Get the event data.
const event = await AddonCalendar.getEventById(this.eventId); const event = await AddonCalendar.getEventById(this.eventId);
this.event = AddonCalendarHelper.formatEventData(event); this.event = await AddonCalendarHelper.formatEventData(event);
try { try {
const offlineEvent = AddonCalendarHelper.formatOfflineEventData( const offlineEvent = AddonCalendarHelper.formatOfflineEventData(

View File

@ -161,7 +161,9 @@ export class AddonCalendarHelperProvider {
* *
* @param event Event to format. * @param event Event to format.
*/ */
formatEventData(event: AddonCalendarEvent | AddonCalendarEventBase | AddonCalendarGetEventsEvent): AddonCalendarEventToDisplay { async formatEventData(
event: AddonCalendarEvent | AddonCalendarEventBase | AddonCalendarGetEventsEvent,
): Promise<AddonCalendarEventToDisplay> {
const eventFormatted: AddonCalendarEventToDisplay = { const eventFormatted: AddonCalendarEventToDisplay = {
...event, ...event,
@ -176,7 +178,7 @@ export class AddonCalendarHelperProvider {
}; };
if (event.modulename) { if (event.modulename) {
eventFormatted.eventIcon = CoreCourse.getModuleIconSrc(event.modulename); eventFormatted.eventIcon = await CoreCourse.getModuleIconSrc(event.modulename);
eventFormatted.moduleIcon = eventFormatted.eventIcon; eventFormatted.moduleIcon = eventFormatted.eventIcon;
eventFormatted.iconTitle = CoreCourse.translateModuleName(event.modulename); eventFormatted.iconTitle = CoreCourse.translateModuleName(event.modulename);
} }

View File

@ -53,8 +53,8 @@ export class AddonModForumModuleHandlerService extends CoreModuleHandlerBase imp
/** /**
* @inheritdoc * @inheritdoc
*/ */
getData(module: CoreCourseAnyModuleData, courseId: number): CoreCourseModuleHandlerData { async getData(module: CoreCourseAnyModuleData, courseId: number): Promise<CoreCourseModuleHandlerData> {
const data = super.getData(module, courseId); const data = await super.getData(module, courseId);
if ('afterlink' in module && !!module.afterlink) { if ('afterlink' in module && !!module.afterlink) {
data.extraBadgeColor = ''; data.extraBadgeColor = '';

View File

@ -44,7 +44,7 @@ export class AddonModLabelModuleHandlerService extends CoreModuleHandlerBase imp
/** /**
* @inheritdoc * @inheritdoc
*/ */
getData(module: CoreCourseWSModule): CoreCourseModuleHandlerData { async getData(module: CoreCourseWSModule): Promise<CoreCourseModuleHandlerData> {
// Remove the description from the module so it isn't rendered twice. // Remove the description from the module so it isn't rendered twice.
const title = module.description || ''; const title = module.description || '';
module.description = ''; module.description = '';

View File

@ -54,13 +54,13 @@ export class AddonModLtiModuleHandlerService extends CoreModuleHandlerBase imple
/** /**
* @inheritdoc * @inheritdoc
*/ */
getData( async getData(
module: CoreCourseAnyModuleData, module: CoreCourseAnyModuleData,
courseId: number, courseId: number,
sectionId?: number, sectionId?: number,
forCoursePage?: boolean, forCoursePage?: boolean,
): CoreCourseModuleHandlerData { ): Promise<CoreCourseModuleHandlerData> {
const data = super.getData(module, courseId, sectionId, forCoursePage); const data = await super.getData(module, courseId, sectionId, forCoursePage);
data.showDownloadButton = false; data.showDownloadButton = false;
data.buttons = [{ data.buttons = [{

View File

@ -63,12 +63,12 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase
/** /**
* @inheritdoc * @inheritdoc
*/ */
getData( async getData(
module: CoreCourseAnyModuleData, module: CoreCourseAnyModuleData,
courseId: number, courseId: number,
sectionId?: number, sectionId?: number,
forCoursePage?: boolean, forCoursePage?: boolean,
): CoreCourseModuleHandlerData { ): Promise<CoreCourseModuleHandlerData> {
const updateStatus = (status: string): void => { const updateStatus = (status: string): void => {
if (!handlerData.buttons) { if (!handlerData.buttons) {
return; return;
@ -79,7 +79,7 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase
}; };
const openWithPicker = CoreFileHelper.defaultIsOpenWithPicker(); const openWithPicker = CoreFileHelper.defaultIsOpenWithPicker();
const handlerData = super.getData(module, courseId, sectionId, forCoursePage); const handlerData = await super.getData(module, courseId, sectionId, forCoursePage);
handlerData.updateStatus = updateStatus.bind(this); handlerData.updateStatus = updateStatus.bind(this);
handlerData.buttons = [{ handlerData.buttons = [{
hidden: true, hidden: true,
@ -233,7 +233,7 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase
// No previously set, just set the icon. // No previously set, just set the icon.
if (resourceData.icon == '') { if (resourceData.icon == '') {
resourceData.icon = CoreCourse.getModuleIconSrc(module.modname, 'modicon' in module ? module.modicon : undefined); resourceData.icon = await CoreCourse.getModuleIconSrc(module.modname, 'modicon' in module ? module.modicon : undefined);
} }
return resourceData; return resourceData;

View File

@ -54,7 +54,7 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple
/** /**
* @inheritdoc * @inheritdoc
*/ */
getData(module: CoreCourseAnyModuleData, courseId: number): CoreCourseModuleHandlerData { async getData(module: CoreCourseAnyModuleData, courseId: number): Promise<CoreCourseModuleHandlerData> {
/** /**
* Open the URL. * Open the URL.
@ -77,7 +77,7 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple
}; };
const handlerData: CoreCourseModuleHandlerData = { const handlerData: CoreCourseModuleHandlerData = {
icon: CoreCourse.getModuleIconSrc(module.modname, 'modicon' in module ? module.modicon : undefined), icon: await CoreCourse.getModuleIconSrc(module.modname, 'modicon' in module ? module.modicon : undefined),
title: module.name, title: module.name,
class: 'addon-mod_url-handler', class: 'addon-mod_url-handler',
showDownloadButton: false, showDownloadButton: false,
@ -111,7 +111,7 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple
}], }],
}; };
this.hideLinkButton(module, courseId).then((hideButton) => { this.hideLinkButton(module, courseId).then(async (hideButton) => {
if (!handlerData.buttons) { if (!handlerData.buttons) {
return; return;
} }
@ -121,7 +121,7 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple
if (module.contents && module.contents[0]) { if (module.contents && module.contents[0]) {
// Calculate the icon to use. // Calculate the icon to use.
handlerData.icon = AddonModUrl.guessIcon(module.contents[0].fileurl) || handlerData.icon = AddonModUrl.guessIcon(module.contents[0].fileurl) ||
CoreCourse.getModuleIconSrc(module.modname, 'modicon' in module ? module.modicon : undefined); await CoreCourse.getModuleIconSrc(module.modname, 'modicon' in module ? module.modicon : undefined);
} }
return; return;

View File

@ -34,14 +34,14 @@ export class CoreModuleHandlerBase implements Partial<CoreCourseModuleHandler> {
/** /**
* @inheritdoc * @inheritdoc
*/ */
getData( async getData(
module: CoreCourseAnyModuleData, module: CoreCourseAnyModuleData,
courseId: number, // eslint-disable-line @typescript-eslint/no-unused-vars courseId: number, // eslint-disable-line @typescript-eslint/no-unused-vars
sectionId?: number, // eslint-disable-line @typescript-eslint/no-unused-vars sectionId?: number, // eslint-disable-line @typescript-eslint/no-unused-vars
forCoursePage?: boolean, // eslint-disable-line @typescript-eslint/no-unused-vars forCoursePage?: boolean, // eslint-disable-line @typescript-eslint/no-unused-vars
): CoreCourseModuleHandlerData { ): Promise<CoreCourseModuleHandlerData> {
return { return {
icon: CoreCourse.getModuleIconSrc(module.modname, 'modicon' in module ? module.modicon : undefined), icon: await CoreCourse.getModuleIconSrc(module.modname, 'modicon' in module ? module.modicon : undefined),
title: module.name, title: module.name,
class: 'addon-mod_' + module.modname + '-handler', class: 'addon-mod_' + module.modname + '-handler',
showDownloadButton: true, showDownloadButton: true,

View File

@ -89,16 +89,16 @@ export class CoreCourseContentsPage implements OnInit, OnDestroy {
* Component being initialized. * Component being initialized.
*/ */
async ngOnInit(): Promise<void> { async ngOnInit(): Promise<void> {
const course = CoreNavigator.getRouteParam<CoreCourseAnyCourseData>('course');
if (!course) { try {
CoreDomUtils.showErrorModal('Missing required course parameter.'); this.course = CoreNavigator.getRequiredRouteParam<CoreCourseAnyCourseData>('course');
} catch (error) {
CoreDomUtils.showErrorModal(error);
CoreNavigator.back(); CoreNavigator.back();
return; return;
} }
this.course = course;
this.sectionId = CoreNavigator.getRouteNumberParam('sectionId'); this.sectionId = CoreNavigator.getRouteNumberParam('sectionId');
this.sectionNumber = CoreNavigator.getRouteNumberParam('sectionNumber'); this.sectionNumber = CoreNavigator.getRouteNumberParam('sectionNumber');
this.moduleId = CoreNavigator.getRouteNumberParam('moduleId'); this.moduleId = CoreNavigator.getRouteNumberParam('moduleId');

View File

@ -190,8 +190,8 @@ export class CoreCourseHelperProvider {
hasContent = true; hasContent = true;
section.modules.forEach((module) => { section.modules.forEach(async (module) => {
module.handlerData = CoreCourseModuleDelegate.getModuleDataFor( module.handlerData = await CoreCourseModuleDelegate.getModuleDataFor(
module.modname, module.modname,
module, module,
courseId, courseId,
@ -1610,7 +1610,7 @@ export class CoreCourseHelperProvider {
if (CoreSites.getCurrentSiteId() == site.getId()) { if (CoreSites.getCurrentSiteId() == site.getId()) {
// Try to use the module's handler to navigate cleanly. // Try to use the module's handler to navigate cleanly.
module.handlerData = CoreCourseModuleDelegate.getModuleDataFor( module.handlerData = await CoreCourseModuleDelegate.getModuleDataFor(
module.modname, module.modname,
module, module,
courseId, courseId,
@ -1664,9 +1664,9 @@ export class CoreCourseHelperProvider {
* @param modParams Params to pass to the module * @param modParams Params to pass to the module
* @param True if module can be opened, false otherwise. * @param True if module can be opened, false otherwise.
*/ */
openModule(module: CoreCourseModule, courseId: number, sectionId?: number, modParams?: Params): boolean { async openModule(module: CoreCourseModule, courseId: number, sectionId?: number, modParams?: Params): Promise<boolean> {
if (!module.handlerData) { if (!module.handlerData) {
module.handlerData = CoreCourseModuleDelegate.getModuleDataFor( module.handlerData = await CoreCourseModuleDelegate.getModuleDataFor(
module.modname, module.modname,
module, module,
courseId, courseId,

View File

@ -520,7 +520,7 @@ export class CoreCourseProvider {
const params: CoreCourseGetCourseModuleWSParams = { const params: CoreCourseGetCourseModuleWSParams = {
cmid: moduleId, cmid: moduleId,
}; };
const preSets = { const preSets: CoreSiteWSPreSets = {
cacheKey: this.getModuleCacheKey(moduleId), cacheKey: this.getModuleCacheKey(moduleId),
updateFrequency: CoreSite.FREQUENCY_RARELY, updateFrequency: CoreSite.FREQUENCY_RARELY,
}; };
@ -528,11 +528,9 @@ export class CoreCourseProvider {
if (response.warnings && response.warnings.length) { if (response.warnings && response.warnings.length) {
throw new CoreWSError(response.warnings[0]); throw new CoreWSError(response.warnings[0]);
} else if (response.cm) {
return response.cm;
} }
throw Error('WS core_course_get_course_module failed.'); return response.cm;
} }
/** /**
@ -632,7 +630,7 @@ export class CoreCourseProvider {
* @param modicon The mod icon string to use in case we are not using a core activity. * @param modicon The mod icon string to use in case we are not using a core activity.
* @return The IMG src. * @return The IMG src.
*/ */
getModuleIconSrc(moduleName: string, modicon?: string): string { async getModuleIconSrc(moduleName: string, modicon?: string): Promise<string> {
if (this.CORE_MODULES.indexOf(moduleName) < 0) { if (this.CORE_MODULES.indexOf(moduleName) < 0) {
if (modicon) { if (modicon) {
return modicon; return modicon;

View File

@ -41,12 +41,12 @@ export class CoreCourseModuleDefaultHandler implements CoreCourseModuleHandler {
/** /**
* @inheritdoc * @inheritdoc
*/ */
getData( async getData(
module: CoreCourseAnyModuleData, module: CoreCourseAnyModuleData,
): CoreCourseModuleHandlerData { ): Promise<CoreCourseModuleHandlerData> {
// Return the default data. // Return the default data.
const defaultData: CoreCourseModuleHandlerData = { const defaultData: CoreCourseModuleHandlerData = {
icon: CoreCourse.getModuleIconSrc(module.modname, 'modicon' in module ? module.modicon : undefined), icon: await CoreCourse.getModuleIconSrc(module.modname, 'modicon' in module ? module.modicon : undefined),
title: module.name, title: module.name,
class: 'core-course-default-handler core-course-module-' + module.modname + '-handler', class: 'core-course-default-handler core-course-module-' + module.modname + '-handler',
action: (event: Event, module: CoreCourseModule, courseId: number, options?: CoreNavigationOptions) => { action: (event: Event, module: CoreCourseModule, courseId: number, options?: CoreNavigationOptions) => {

View File

@ -56,7 +56,7 @@ export interface CoreCourseModuleHandler extends CoreDelegateHandler {
courseId: number, courseId: number,
sectionId?: number, sectionId?: number,
forCoursePage?: boolean, forCoursePage?: boolean,
): CoreCourseModuleHandlerData; ): Promise<CoreCourseModuleHandlerData> | CoreCourseModuleHandlerData;
/** /**
* Get the component to render the module. This is needed to support singleactivity course format. * Get the component to render the module. This is needed to support singleactivity course format.
@ -82,7 +82,7 @@ export interface CoreCourseModuleHandler extends CoreDelegateHandler {
* *
* @return The icon src. * @return The icon src.
*/ */
getIconSrc?(): string | undefined; getIconSrc?(module: CoreCourseWSModule): Promise<string> | string | undefined;
/** /**
* Check if this type of module supports a certain feature. * Check if this type of module supports a certain feature.
@ -277,14 +277,14 @@ export class CoreCourseModuleDelegateService extends CoreDelegate<CoreCourseModu
* @param forCoursePage Whether the data will be used to render the course page. * @param forCoursePage Whether the data will be used to render the course page.
* @return Data to render the module. * @return Data to render the module.
*/ */
getModuleDataFor( async getModuleDataFor(
modname: string, modname: string,
module: CoreCourseAnyModuleData, module: CoreCourseAnyModuleData,
courseId: number, courseId: number,
sectionId?: number, sectionId?: number,
forCoursePage?: boolean, forCoursePage?: boolean,
): CoreCourseModuleHandlerData | undefined { ): Promise<CoreCourseModuleHandlerData | undefined> {
return this.executeFunctionOnEnabled<CoreCourseModuleHandlerData>( return await this.executeFunctionOnEnabled<CoreCourseModuleHandlerData>(
modname, modname,
'getData', 'getData',
[module, courseId, sectionId, forCoursePage], [module, courseId, sectionId, forCoursePage],
@ -343,12 +343,12 @@ export class CoreCourseModuleDelegateService extends CoreDelegate<CoreCourseModu
* *
* @param modname The name of the module type. * @param modname The name of the module type.
* @param modicon The mod icon string. * @param modicon The mod icon string.
* @return The icon src. * @return Promise resolved with the icon src.
*/ */
getModuleIconSrc(modname: string, modicon?: string): string { async getModuleIconSrc(modname: string, modicon?: string): Promise<string> {
return this.executeFunctionOnEnabled<string>(modname, 'getIconSrc') || const icon = await this.executeFunctionOnEnabled<Promise<string>>(modname, 'getIconSrc');
CoreCourse.getModuleIconSrc(modname, modicon) ||
''; return icon || await CoreCourse.getModuleIconSrc(modname, modicon) || '';
} }
/** /**

View File

@ -54,7 +54,7 @@ export class CoreGradesHelperProvider {
* @param tableRow JSON object representing row of grades table data. * @param tableRow JSON object representing row of grades table data.
* @return Formatted row object. * @return Formatted row object.
*/ */
protected formatGradeRow(tableRow: CoreGradesTableRow): CoreGradesFormattedRow { protected async formatGradeRow(tableRow: CoreGradesTableRow): Promise<CoreGradesFormattedRow> {
const row: CoreGradesFormattedRow = { const row: CoreGradesFormattedRow = {
rowclass: '', rowclass: '',
}; };
@ -68,7 +68,7 @@ export class CoreGradesHelperProvider {
let content = String(column.content); let content = String(column.content);
if (name == 'itemname') { if (name == 'itemname') {
this.setRowIcon(row, content); await this.setRowIcon(row, content);
row.link = this.getModuleLink(content); row.link = this.getModuleLink(content);
row.rowclass += column.class.indexOf('hidden') >= 0 ? ' hidden' : ''; row.rowclass += column.class.indexOf('hidden') >= 0 ? ' hidden' : '';
row.rowclass += column.class.indexOf('dimmed_text') >= 0 ? ' dimmed_text' : ''; row.rowclass += column.class.indexOf('dimmed_text') >= 0 ? ' dimmed_text' : '';
@ -95,7 +95,7 @@ export class CoreGradesHelperProvider {
* @param tableRow JSON object representing row of grades table data. * @param tableRow JSON object representing row of grades table data.
* @return Formatted row object. * @return Formatted row object.
*/ */
protected formatGradeRowForTable(tableRow: CoreGradesTableRow): CoreGradesFormattedTableRow { protected async formatGradeRowForTable(tableRow: CoreGradesTableRow): Promise<CoreGradesFormattedTableRow> {
const row: CoreGradesFormattedTableRow = {}; const row: CoreGradesFormattedTableRow = {};
for (let name in tableRow) { for (let name in tableRow) {
const column: CoreGradesTableColumn = tableRow[name]; const column: CoreGradesTableColumn = tableRow[name];
@ -113,7 +113,7 @@ export class CoreGradesHelperProvider {
row.colspan = itemNameColumn.colspan; row.colspan = itemNameColumn.colspan;
row.rowspan = tableRow.leader?.rowspan || 1; row.rowspan = tableRow.leader?.rowspan || 1;
this.setRowIcon(row, content); await this.setRowIcon(row, content);
row.rowclass = itemNameColumn.class.indexOf('leveleven') < 0 ? 'odd' : 'even'; row.rowclass = itemNameColumn.class.indexOf('leveleven') < 0 ? 'odd' : 'even';
row.rowclass += itemNameColumn.class.indexOf('hidden') >= 0 ? ' hidden' : ''; row.rowclass += itemNameColumn.class.indexOf('hidden') >= 0 ? ' hidden' : '';
row.rowclass += itemNameColumn.class.indexOf('dimmed_text') >= 0 ? ' dimmed_text' : ''; row.rowclass += itemNameColumn.class.indexOf('dimmed_text') >= 0 ? ' dimmed_text' : '';
@ -158,7 +158,7 @@ export class CoreGradesHelperProvider {
* @param table JSON object representing a table with data. * @param table JSON object representing a table with data.
* @return Formatted HTML table. * @return Formatted HTML table.
*/ */
formatGradesTable(table: CoreGradesTable): CoreGradesFormattedTable { async formatGradesTable(table: CoreGradesTable): Promise<CoreGradesFormattedTable> {
const maxDepth = table.maxdepth; const maxDepth = table.maxdepth;
const formatted: CoreGradesFormattedTable = { const formatted: CoreGradesFormattedTable = {
columns: [], columns: [],
@ -178,7 +178,7 @@ export class CoreGradesHelperProvider {
feedback: false, feedback: false,
contributiontocoursetotal: false, contributiontocoursetotal: false,
}; };
formatted.rows = table.tabledata.map(row => this.formatGradeRowForTable(row)); formatted.rows = await Promise.all(table.tabledata.map(row => this.formatGradeRowForTable(row)));
// Get a row with some info. // Get a row with some info.
let normalRow = formatted.rows.find( let normalRow = formatted.rows.find(
@ -382,7 +382,7 @@ export class CoreGradesHelperProvider {
* @param gradeId Grade Object identifier. * @param gradeId Grade Object identifier.
* @return Formatted HTML table. * @return Formatted HTML table.
*/ */
getGradesTableRow(table: CoreGradesTable, gradeId: number): CoreGradesFormattedRow | null { async getGradesTableRow(table: CoreGradesTable, gradeId: number): Promise<CoreGradesFormattedRow | null> {
if (table.tabledata) { if (table.tabledata) {
const selectedRow = table.tabledata.find( const selectedRow = table.tabledata.find(
(row) => (row) =>
@ -393,7 +393,7 @@ export class CoreGradesHelperProvider {
); );
if (selectedRow) { if (selectedRow) {
return this.formatGradeRow(selectedRow); return await this.formatGradeRow(selectedRow);
} }
} }
@ -408,7 +408,7 @@ export class CoreGradesHelperProvider {
* @return Formatted HTML table. * @return Formatted HTML table.
* @deprecated since app 4.0 * @deprecated since app 4.0
*/ */
getModuleGradesTableRows(table: CoreGradesTable, moduleId: number): CoreGradesFormattedRow[] { async getModuleGradesTableRows(table: CoreGradesTable, moduleId: number): Promise<CoreGradesFormattedRow[]> {
if (!table.tabledata) { if (!table.tabledata) {
return []; return [];
} }
@ -416,7 +416,7 @@ export class CoreGradesHelperProvider {
// Find href containing "/mod/xxx/xxx.php". // Find href containing "/mod/xxx/xxx.php".
const regex = /href="([^"]*\/mod\/[^"|^/]*\/[^"|^.]*\.php[^"]*)/; const regex = /href="([^"]*\/mod\/[^"|^/]*\/[^"|^.]*\.php[^"]*)/;
return table.tabledata.filter((row) => { return await Promise.all(table.tabledata.filter((row) => {
if (row.itemname && row.itemname.content) { if (row.itemname && row.itemname.content) {
const matches = row.itemname.content.match(regex); const matches = row.itemname.content.match(regex);
@ -428,7 +428,7 @@ export class CoreGradesHelperProvider {
} }
return false; return false;
}).map((row) => this.formatGradeRow(row)); }).map((row) => this.formatGradeRow(row)));
} }
/** /**
@ -534,7 +534,7 @@ export class CoreGradesHelperProvider {
* @param text HTML where the image will be rendered. * @param text HTML where the image will be rendered.
* @return Row object with the image. * @return Row object with the image.
*/ */
protected setRowIcon<T extends CoreGradesFormattedRowCommonData>(row: T, text: string): T { protected async setRowIcon<T extends CoreGradesFormattedRowCommonData>(row: T, text: string): Promise<T> {
text = text.replace('%2F', '/').replace('%2f', '/'); text = text.replace('%2F', '/').replace('%2f', '/');
if (text.indexOf('/agg_mean') > -1) { if (text.indexOf('/agg_mean') > -1) {
row.itemtype = 'agg_mean'; row.itemtype = 'agg_mean';
@ -566,7 +566,7 @@ export class CoreGradesHelperProvider {
row.itemtype = 'mod'; row.itemtype = 'mod';
row.itemmodule = module[1]; row.itemmodule = module[1];
row.iconAlt = CoreCourse.translateModuleName(row.itemmodule) || ''; row.iconAlt = CoreCourse.translateModuleName(row.itemmodule) || '';
row.image = CoreCourse.getModuleIconSrc( row.image = await CoreCourse.getModuleIconSrc(
module[1], module[1],
CoreDomUtils.convertToElement(text).querySelector('img')?.getAttribute('src') ?? undefined, CoreDomUtils.convertToElement(text).querySelector('img')?.getAttribute('src') ?? undefined,
); );

View File

@ -17,7 +17,7 @@ import { IonRefresher } from '@ionic/angular';
import { Params } from '@angular/router'; import { Params } from '@angular/router';
import { CoreSite, CoreSiteConfig } from '@classes/site'; import { CoreSite, CoreSiteConfig } from '@classes/site';
import { CoreCourse, CoreCourseModuleBasicInfo, CoreCourseWSSection } from '@features/course/services/course'; import { CoreCourse, CoreCourseWSModule, CoreCourseWSSection } from '@features/course/services/course';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreSiteHome } from '@features/sitehome/services/sitehome'; import { CoreSiteHome } from '@features/sitehome/services/sitehome';
@ -48,7 +48,7 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy {
hasContent = false; hasContent = false;
items: string[] = []; items: string[] = [];
siteHomeId = 1; siteHomeId = 1;
currentSite?: CoreSite; currentSite!: CoreSite;
searchEnabled = false; searchEnabled = false;
downloadEnabled = false; downloadEnabled = false;
downloadCourseEnabled = false; downloadCourseEnabled = false;
@ -75,7 +75,7 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy {
this.switchDownload(this.downloadEnabled && this.downloadCourseEnabled && this.downloadCoursesEnabled); this.switchDownload(this.downloadEnabled && this.downloadCourseEnabled && this.downloadCoursesEnabled);
}, CoreSites.getCurrentSiteId()); }, CoreSites.getCurrentSiteId());
this.currentSite = CoreSites.getCurrentSite()!; this.currentSite = CoreSites.getRequiredCurrentSite();
this.siteHomeId = CoreSites.getCurrentSiteHomeId(); this.siteHomeId = CoreSites.getCurrentSiteHomeId();
const module = CoreNavigator.getRouteParam<CoreCourseModule>('module'); const module = CoreNavigator.getRouteParam<CoreCourseModule>('module');
@ -97,7 +97,7 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy {
protected async loadContent(): Promise<void> { protected async loadContent(): Promise<void> {
this.hasContent = false; this.hasContent = false;
const config = this.currentSite!.getStoredConfig() || { numsections: 1, frontpageloggedin: undefined }; const config = this.currentSite.getStoredConfig() || { numsections: 1, frontpageloggedin: undefined };
this.items = await CoreSiteHome.getFrontPageItems(config.frontpageloggedin); this.items = await CoreSiteHome.getFrontPageItems(config.frontpageloggedin);
this.hasContent = this.items.length > 0; this.hasContent = this.items.length > 0;
@ -105,13 +105,13 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy {
if (this.items.some((item) => item == 'NEWS_ITEMS')) { if (this.items.some((item) => item == 'NEWS_ITEMS')) {
// Get the news forum. // Get the news forum.
try { try {
const forum = await CoreSiteHome.getNewsForum(); const forum = await CoreSiteHome.getNewsForum(this.siteHomeId);
this.newsForumModule = await CoreCourse.getModuleBasicInfo(forum.cmid); this.newsForumModule = await CoreCourse.getModule(forum.cmid, forum.course);
this.newsForumModule.handlerData = CoreCourseModuleDelegate.getModuleDataFor( this.newsForumModule.handlerData = await CoreCourseModuleDelegate.getModuleDataFor(
this.newsForumModule.modname, this.newsForumModule.modname,
this.newsForumModule, this.newsForumModule,
this.siteHomeId, this.siteHomeId,
this.newsForumModule.section, undefined,
true, true,
); );
} catch { } catch {
@ -120,7 +120,7 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy {
} }
try { try {
const sections = await CoreCourse.getSections(this.siteHomeId!, false, true); const sections = await CoreCourse.getSections(this.siteHomeId, false, true);
// Check "Include a topic section" setting from numsections. // Check "Include a topic section" setting from numsections.
this.section = config.numsections ? sections.find((section) => section.section == 1) : undefined; this.section = config.numsections ? sections.find((section) => section.section == 1) : undefined;
@ -137,10 +137,10 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy {
// Add log in Moodle. // Add log in Moodle.
CoreCourse.logView( CoreCourse.logView(
this.siteHomeId!, this.siteHomeId,
undefined, undefined,
undefined, undefined,
this.currentSite!.getInfo()?.sitename, this.currentSite.getInfo()?.sitename,
).catch(() => { ).catch(() => {
// Ignore errors. // Ignore errors.
}); });
@ -157,11 +157,11 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy {
doRefresh(refresher?: IonRefresher): void { doRefresh(refresher?: IonRefresher): void {
const promises: Promise<unknown>[] = []; const promises: Promise<unknown>[] = [];
promises.push(CoreCourse.invalidateSections(this.siteHomeId!)); promises.push(CoreCourse.invalidateSections(this.siteHomeId));
promises.push(this.currentSite!.invalidateConfig().then(async () => { promises.push(this.currentSite.invalidateConfig().then(async () => {
// Config invalidated, fetch it again. // Config invalidated, fetch it again.
const config: CoreSiteConfig = await this.currentSite!.getConfig(); const config: CoreSiteConfig = await this.currentSite.getConfig();
this.currentSite!.setConfig(config); this.currentSite.setConfig(config);
return; return;
})); }));
@ -251,6 +251,6 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy {
} }
type NewsForum = CoreCourseModuleBasicInfo & { type NewsForum = CoreCourseWSModule & {
handlerData?: CoreCourseModuleHandlerData; handlerData?: CoreCourseModuleHandlerData;
}; };

View File

@ -20,6 +20,7 @@ import { makeSingleton } from '@singletons';
import { CoreCourse } from '../../course/services/course'; import { CoreCourse } from '../../course/services/course';
import { CoreCourses } from '../../courses/services/courses'; import { CoreCourses } from '../../courses/services/courses';
import { AddonModForum, AddonModForumData } from '@addons/mod/forum/services/forum'; import { AddonModForum, AddonModForumData } from '@addons/mod/forum/services/forum';
import { CoreError } from '@classes/errors/error';
/** /**
* Items with index 1 and 3 were removed on 2.5 and not being supported in the app. * Items with index 1 and 3 were removed on 2.5 and not being supported in the app.
@ -57,7 +58,7 @@ export class CoreSiteHomeProvider {
return forum; return forum;
} }
throw null; throw new CoreError('No news forum found');
} }
/** /**