From 1c0a86d045a14439c42d390d34912bc988e24606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Mon, 27 Sep 2021 16:46:43 +0200 Subject: [PATCH 1/4] MOBILE-2748 icon: Make getModuleIconSrc async --- .../activitymodules/activitymodules.ts | 4 +- .../services/recentlyaccesseditems.ts | 6 +- .../timeline/components/events/events.ts | 14 ++--- .../calendar/components/calendar/calendar.ts | 57 ++++++++++--------- .../upcoming-events/upcoming-events.ts | 2 +- src/addons/calendar/pages/day/day.page.ts | 2 +- src/addons/calendar/pages/event/event.page.ts | 2 +- .../calendar/services/calendar-helper.ts | 6 +- .../mod/forum/services/handlers/module.ts | 4 +- .../mod/label/services/handlers/module.ts | 2 +- .../mod/lti/services/handlers/module.ts | 6 +- .../mod/resource/services/handlers/module.ts | 8 +-- .../mod/url/services/handlers/module.ts | 8 +-- .../course/classes/module-base-handler.ts | 6 +- .../course/pages/contents/contents.ts | 8 +-- .../features/course/services/course-helper.ts | 10 ++-- src/core/features/course/services/course.ts | 8 +-- .../services/handlers/default-module.ts | 6 +- .../course/services/module-delegate.ts | 20 +++---- .../features/grades/services/grades-helper.ts | 26 ++++----- .../features/sitehome/pages/index/index.ts | 32 +++++------ .../features/sitehome/services/sitehome.ts | 3 +- 22 files changed, 123 insertions(+), 117 deletions(-) diff --git a/src/addons/block/activitymodules/components/activitymodules/activitymodules.ts b/src/addons/block/activitymodules/components/activitymodules/activitymodules.ts index c377040b5..fdeb9a967 100644 --- a/src/addons/block/activitymodules/components/activitymodules/activitymodules.ts +++ b/src/addons/block/activitymodules/components/activitymodules/activitymodules.ts @@ -99,9 +99,9 @@ export class AddonBlockActivityModulesComponent extends CoreBlockBaseComponent i let icon: string; if (modName === 'resources') { - icon = CoreCourse.getModuleIconSrc('page', modIcons['page']); + icon = await CoreCourse.getModuleIconSrc('page', modIcons['page']); } else { - icon = CoreCourseModuleDelegate.getModuleIconSrc(modName, modIcons[modName]) || ''; + icon = await CoreCourseModuleDelegate.getModuleIconSrc(modName, modIcons[modName]); } this.entries.push({ diff --git a/src/addons/block/recentlyaccesseditems/services/recentlyaccesseditems.ts b/src/addons/block/recentlyaccesseditems/services/recentlyaccesseditems.ts index f2b50bc92..8261f24d3 100644 --- a/src/addons/block/recentlyaccesseditems/services/recentlyaccesseditems.ts +++ b/src/addons/block/recentlyaccesseditems/services/recentlyaccesseditems.ts @@ -52,14 +52,14 @@ export class AddonBlockRecentlyAccessedItemsProvider { const items: AddonBlockRecentlyAccessedItemsItem[] = 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'); - 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'); return item; - }); + })); } /** diff --git a/src/addons/block/timeline/components/events/events.ts b/src/addons/block/timeline/components/events/events.ts index f4266f50c..bf77da586 100644 --- a/src/addons/block/timeline/components/events/events.ts +++ b/src/addons/block/timeline/components/events/events.ts @@ -51,12 +51,12 @@ export class AddonBlockTimelineEventsComponent implements OnChanges { /** * Detect changes on input properties. */ - ngOnChanges(changes: {[name: string]: SimpleChange}): void { + async ngOnChanges(changes: {[name: string]: SimpleChange}): Promise { this.showCourse = CoreUtils.isTrueOrOne(this.showCourse); if (changes.events || changes.from || changes.to) { 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; const eventsByDay: Record = {}; @@ -92,22 +92,22 @@ export class AddonBlockTimelineEventsComponent implements OnChanges { * @param end Number of days after the start. * @return Filtered events. */ - protected filterEventsByTime(start: number, end?: number): AddonBlockTimelineEvent[] { + protected async filterEventsByTime(start: number, end?: number): Promise { start = moment().add(start, 'days').startOf('day').unix(); 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) { return start <= event.timesort && event.timesort < end; } return start <= event.timesort; - }).map((event) => { - event.iconUrl = CoreCourse.getModuleIconSrc(event.icon.component); + }).map(async (event) => { + event.iconUrl = await CoreCourse.getModuleIconSrc(event.icon.component); event.iconTitle = event.modulename && CoreCourse.translateModuleName(event.modulename); return event; - }); + })); } /** diff --git a/src/addons/calendar/components/calendar/calendar.ts b/src/addons/calendar/components/calendar/calendar.ts index c6e97072a..5575e917c 100644 --- a/src/addons/calendar/components/calendar/calendar.ts +++ b/src/addons/calendar/components/calendar/calendar.ts @@ -68,8 +68,8 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro isCurrentMonth = false; isPastMonth = false; - protected year?: number; - protected month?: number; + protected year: number; + protected month: number; protected categoriesRetrieved = false; protected categories: { [id: number]: CoreCategoryData } = {}; protected currentSiteId: string; @@ -121,16 +121,19 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro ); this.differ = differs.find([]).create(); + + const now = new Date(); + + this.year = now.getFullYear(); + this.month = now.getMonth() + 1; } /** * Component loaded. */ ngOnInit(): void { - const now = new Date(); - - this.year = this.initialYear ? this.initialYear : now.getFullYear(); - this.month = this.initialMonth ? this.initialMonth : now.getMonth() + 1; + this.year = this.initialYear ? this.initialYear : this.year; + this.month = this.initialMonth ? this.initialMonth : this.month; this.calculateIsCurrentMonth(); @@ -211,11 +214,11 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro // Don't pass courseId and categoryId, we'll filter them locally. let result: { daynames: Partial[]; weeks: Partial[] }; try { - result = await AddonCalendar.getMonthlyEvents(this.year!, this.month!); + result = await AddonCalendar.getMonthlyEvents(this.year, this.month); } catch (error) { if (!CoreApp.isOnline()) { // 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 { 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. this.periodName = CoreTimeUtils.userDate( - new Date(this.year!, this.month! - 1).getTime(), + new Date(this.year, this.month - 1).getTime(), 'core.strftimemonthyear', ); this.weekDays = AddonCalendar.getWeekDays(result.daynames[0].dayno); this.weeks = result.weeks as AddonCalendarWeek[]; this.calculateIsCurrentMonth(); - this.weeks.forEach((week) => { - week.days.forEach((day) => { + await Promise.all(this.weeks.map(async (week) => { + await Promise.all(week.days.map(async (day) => { 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', ); day.eventsFormated = day.eventsFormated || []; day.filteredEvents = day.filteredEvents || []; - day.events.forEach((event) => { - /// Format online events. - day.eventsFormated!.push(AddonCalendarHelper.formatEventData(event)); - }); - }); - }); + // Format online events. + const onlineEventsFormatted = await Promise.all( + day.events.map(async (event) => AddonCalendarHelper.formatEventData(event)), + ); + + day.eventsFormated = day.eventsFormated.concat(onlineEventsFormatted); + })); + })); if (this.isCurrentMonth) { 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. 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(AddonCalendar.invalidateTimeFormat()); @@ -386,7 +391,7 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro * @param day Day. */ 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.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 { if (this.month === 1) { this.month = 12; - this.year!--; + this.year--; } else { - this.month!--; + this.month--; } } @@ -444,9 +449,9 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro protected increaseMonth(): void { if (this.month === 12) { this.month = 1; - this.year!++; + this.year++; } else { - this.month!++; + this.month++; } } @@ -455,7 +460,7 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro */ protected mergeEvents(): void { 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) => { week.days.forEach((day) => { diff --git a/src/addons/calendar/components/upcoming-events/upcoming-events.ts b/src/addons/calendar/components/upcoming-events/upcoming-events.ts index ae0448d60..7566c6d14 100644 --- a/src/addons/calendar/components/upcoming-events/upcoming-events.ts +++ b/src/addons/calendar/components/upcoming-events/upcoming-events.ts @@ -173,7 +173,7 @@ export class AddonCalendarUpcomingEventsComponent implements OnInit, DoCheck, On async fetchEvents(): Promise { // Don't pass courseId and categoryId, we'll filter them locally. 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. AddonCalendar.scheduleEventsNotifications(this.onlineEvents); // Merge the online events with offline data. diff --git a/src/addons/calendar/pages/day/day.page.ts b/src/addons/calendar/pages/day/day.page.ts index 2d26cf281..f02bc54d1 100644 --- a/src/addons/calendar/pages/day/day.page.ts +++ b/src/addons/calendar/pages/day/day.page.ts @@ -333,7 +333,7 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy { try { // Don't pass courseId and categoryId, we'll filter them locally. 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) { if (CoreApp.isOnline()) { throw error; diff --git a/src/addons/calendar/pages/event/event.page.ts b/src/addons/calendar/pages/event/event.page.ts index 88d4597f9..9ddc41f58 100644 --- a/src/addons/calendar/pages/event/event.page.ts +++ b/src/addons/calendar/pages/event/event.page.ts @@ -207,7 +207,7 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy { try { // Get the event data. const event = await AddonCalendar.getEventById(this.eventId); - this.event = AddonCalendarHelper.formatEventData(event); + this.event = await AddonCalendarHelper.formatEventData(event); try { const offlineEvent = AddonCalendarHelper.formatOfflineEventData( diff --git a/src/addons/calendar/services/calendar-helper.ts b/src/addons/calendar/services/calendar-helper.ts index d457e4c05..447745701 100644 --- a/src/addons/calendar/services/calendar-helper.ts +++ b/src/addons/calendar/services/calendar-helper.ts @@ -161,7 +161,9 @@ export class AddonCalendarHelperProvider { * * @param event Event to format. */ - formatEventData(event: AddonCalendarEvent | AddonCalendarEventBase | AddonCalendarGetEventsEvent): AddonCalendarEventToDisplay { + async formatEventData( + event: AddonCalendarEvent | AddonCalendarEventBase | AddonCalendarGetEventsEvent, + ): Promise { const eventFormatted: AddonCalendarEventToDisplay = { ...event, @@ -176,7 +178,7 @@ export class AddonCalendarHelperProvider { }; if (event.modulename) { - eventFormatted.eventIcon = CoreCourse.getModuleIconSrc(event.modulename); + eventFormatted.eventIcon = await CoreCourse.getModuleIconSrc(event.modulename); eventFormatted.moduleIcon = eventFormatted.eventIcon; eventFormatted.iconTitle = CoreCourse.translateModuleName(event.modulename); } diff --git a/src/addons/mod/forum/services/handlers/module.ts b/src/addons/mod/forum/services/handlers/module.ts index 3b7327923..7418879ca 100644 --- a/src/addons/mod/forum/services/handlers/module.ts +++ b/src/addons/mod/forum/services/handlers/module.ts @@ -53,8 +53,8 @@ export class AddonModForumModuleHandlerService extends CoreModuleHandlerBase imp /** * @inheritdoc */ - getData(module: CoreCourseAnyModuleData, courseId: number): CoreCourseModuleHandlerData { - const data = super.getData(module, courseId); + async getData(module: CoreCourseAnyModuleData, courseId: number): Promise { + const data = await super.getData(module, courseId); if ('afterlink' in module && !!module.afterlink) { data.extraBadgeColor = ''; diff --git a/src/addons/mod/label/services/handlers/module.ts b/src/addons/mod/label/services/handlers/module.ts index 9fd176d90..c51a15fa0 100644 --- a/src/addons/mod/label/services/handlers/module.ts +++ b/src/addons/mod/label/services/handlers/module.ts @@ -44,7 +44,7 @@ export class AddonModLabelModuleHandlerService extends CoreModuleHandlerBase imp /** * @inheritdoc */ - getData(module: CoreCourseWSModule): CoreCourseModuleHandlerData { + async getData(module: CoreCourseWSModule): Promise { // Remove the description from the module so it isn't rendered twice. const title = module.description || ''; module.description = ''; diff --git a/src/addons/mod/lti/services/handlers/module.ts b/src/addons/mod/lti/services/handlers/module.ts index 6d5e78673..79d1b90a1 100644 --- a/src/addons/mod/lti/services/handlers/module.ts +++ b/src/addons/mod/lti/services/handlers/module.ts @@ -54,13 +54,13 @@ export class AddonModLtiModuleHandlerService extends CoreModuleHandlerBase imple /** * @inheritdoc */ - getData( + async getData( module: CoreCourseAnyModuleData, courseId: number, sectionId?: number, forCoursePage?: boolean, - ): CoreCourseModuleHandlerData { - const data = super.getData(module, courseId, sectionId, forCoursePage); + ): Promise { + const data = await super.getData(module, courseId, sectionId, forCoursePage); data.showDownloadButton = false; data.buttons = [{ diff --git a/src/addons/mod/resource/services/handlers/module.ts b/src/addons/mod/resource/services/handlers/module.ts index e2639eeea..f9ed3f2c2 100644 --- a/src/addons/mod/resource/services/handlers/module.ts +++ b/src/addons/mod/resource/services/handlers/module.ts @@ -63,12 +63,12 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase /** * @inheritdoc */ - getData( + async getData( module: CoreCourseAnyModuleData, courseId: number, sectionId?: number, forCoursePage?: boolean, - ): CoreCourseModuleHandlerData { + ): Promise { const updateStatus = (status: string): void => { if (!handlerData.buttons) { return; @@ -79,7 +79,7 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase }; 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.buttons = [{ hidden: true, @@ -233,7 +233,7 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase // No previously set, just set the 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; diff --git a/src/addons/mod/url/services/handlers/module.ts b/src/addons/mod/url/services/handlers/module.ts index bd5f28b2c..94634f181 100644 --- a/src/addons/mod/url/services/handlers/module.ts +++ b/src/addons/mod/url/services/handlers/module.ts @@ -54,7 +54,7 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple /** * @inheritdoc */ - getData(module: CoreCourseAnyModuleData, courseId: number): CoreCourseModuleHandlerData { + async getData(module: CoreCourseAnyModuleData, courseId: number): Promise { /** * Open the URL. @@ -77,7 +77,7 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple }; 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, class: 'addon-mod_url-handler', 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) { return; } @@ -121,7 +121,7 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple if (module.contents && module.contents[0]) { // Calculate the icon to use. 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; diff --git a/src/core/features/course/classes/module-base-handler.ts b/src/core/features/course/classes/module-base-handler.ts index 16ab933ed..d44bc8238 100644 --- a/src/core/features/course/classes/module-base-handler.ts +++ b/src/core/features/course/classes/module-base-handler.ts @@ -34,14 +34,14 @@ export class CoreModuleHandlerBase implements Partial { /** * @inheritdoc */ - getData( + async getData( module: CoreCourseAnyModuleData, courseId: 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 - ): CoreCourseModuleHandlerData { + ): Promise { 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, class: 'addon-mod_' + module.modname + '-handler', showDownloadButton: true, diff --git a/src/core/features/course/pages/contents/contents.ts b/src/core/features/course/pages/contents/contents.ts index 2cccc6ecb..3a95835d6 100644 --- a/src/core/features/course/pages/contents/contents.ts +++ b/src/core/features/course/pages/contents/contents.ts @@ -89,16 +89,16 @@ export class CoreCourseContentsPage implements OnInit, OnDestroy { * Component being initialized. */ async ngOnInit(): Promise { - const course = CoreNavigator.getRouteParam('course'); - if (!course) { - CoreDomUtils.showErrorModal('Missing required course parameter.'); + try { + this.course = CoreNavigator.getRequiredRouteParam('course'); + } catch (error) { + CoreDomUtils.showErrorModal(error); CoreNavigator.back(); return; } - this.course = course; this.sectionId = CoreNavigator.getRouteNumberParam('sectionId'); this.sectionNumber = CoreNavigator.getRouteNumberParam('sectionNumber'); this.moduleId = CoreNavigator.getRouteNumberParam('moduleId'); diff --git a/src/core/features/course/services/course-helper.ts b/src/core/features/course/services/course-helper.ts index 5b322d60d..b87b0ab95 100644 --- a/src/core/features/course/services/course-helper.ts +++ b/src/core/features/course/services/course-helper.ts @@ -190,8 +190,8 @@ export class CoreCourseHelperProvider { hasContent = true; - section.modules.forEach((module) => { - module.handlerData = CoreCourseModuleDelegate.getModuleDataFor( + section.modules.forEach(async (module) => { + module.handlerData = await CoreCourseModuleDelegate.getModuleDataFor( module.modname, module, courseId, @@ -1610,7 +1610,7 @@ export class CoreCourseHelperProvider { if (CoreSites.getCurrentSiteId() == site.getId()) { // Try to use the module's handler to navigate cleanly. - module.handlerData = CoreCourseModuleDelegate.getModuleDataFor( + module.handlerData = await CoreCourseModuleDelegate.getModuleDataFor( module.modname, module, courseId, @@ -1664,9 +1664,9 @@ export class CoreCourseHelperProvider { * @param modParams Params to pass to the module * @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 { if (!module.handlerData) { - module.handlerData = CoreCourseModuleDelegate.getModuleDataFor( + module.handlerData = await CoreCourseModuleDelegate.getModuleDataFor( module.modname, module, courseId, diff --git a/src/core/features/course/services/course.ts b/src/core/features/course/services/course.ts index c714008fa..0e7f38649 100644 --- a/src/core/features/course/services/course.ts +++ b/src/core/features/course/services/course.ts @@ -520,7 +520,7 @@ export class CoreCourseProvider { const params: CoreCourseGetCourseModuleWSParams = { cmid: moduleId, }; - const preSets = { + const preSets: CoreSiteWSPreSets = { cacheKey: this.getModuleCacheKey(moduleId), updateFrequency: CoreSite.FREQUENCY_RARELY, }; @@ -528,11 +528,9 @@ export class CoreCourseProvider { if (response.warnings && response.warnings.length) { 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. * @return The IMG src. */ - getModuleIconSrc(moduleName: string, modicon?: string): string { + async getModuleIconSrc(moduleName: string, modicon?: string): Promise { if (this.CORE_MODULES.indexOf(moduleName) < 0) { if (modicon) { return modicon; diff --git a/src/core/features/course/services/handlers/default-module.ts b/src/core/features/course/services/handlers/default-module.ts index 75dfd0586..d6f7d9637 100644 --- a/src/core/features/course/services/handlers/default-module.ts +++ b/src/core/features/course/services/handlers/default-module.ts @@ -41,12 +41,12 @@ export class CoreCourseModuleDefaultHandler implements CoreCourseModuleHandler { /** * @inheritdoc */ - getData( + async getData( module: CoreCourseAnyModuleData, - ): CoreCourseModuleHandlerData { + ): Promise { // Return the default data. 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, class: 'core-course-default-handler core-course-module-' + module.modname + '-handler', action: (event: Event, module: CoreCourseModule, courseId: number, options?: CoreNavigationOptions) => { diff --git a/src/core/features/course/services/module-delegate.ts b/src/core/features/course/services/module-delegate.ts index 072188859..e7165da57 100644 --- a/src/core/features/course/services/module-delegate.ts +++ b/src/core/features/course/services/module-delegate.ts @@ -56,7 +56,7 @@ export interface CoreCourseModuleHandler extends CoreDelegateHandler { courseId: number, sectionId?: number, forCoursePage?: boolean, - ): CoreCourseModuleHandlerData; + ): Promise | CoreCourseModuleHandlerData; /** * 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. */ - getIconSrc?(): string | undefined; + getIconSrc?(module: CoreCourseWSModule): Promise | string | undefined; /** * Check if this type of module supports a certain feature. @@ -277,14 +277,14 @@ export class CoreCourseModuleDelegateService extends CoreDelegate( + ): Promise { + return await this.executeFunctionOnEnabled( modname, 'getData', [module, courseId, sectionId, forCoursePage], @@ -343,12 +343,12 @@ export class CoreCourseModuleDelegateService extends CoreDelegate(modname, 'getIconSrc') || - CoreCourse.getModuleIconSrc(modname, modicon) || - ''; + async getModuleIconSrc(modname: string, modicon?: string): Promise { + const icon = await this.executeFunctionOnEnabled>(modname, 'getIconSrc'); + + return icon || await CoreCourse.getModuleIconSrc(modname, modicon) || ''; } /** diff --git a/src/core/features/grades/services/grades-helper.ts b/src/core/features/grades/services/grades-helper.ts index 3d003415b..319dc9313 100644 --- a/src/core/features/grades/services/grades-helper.ts +++ b/src/core/features/grades/services/grades-helper.ts @@ -54,7 +54,7 @@ export class CoreGradesHelperProvider { * @param tableRow JSON object representing row of grades table data. * @return Formatted row object. */ - protected formatGradeRow(tableRow: CoreGradesTableRow): CoreGradesFormattedRow { + protected async formatGradeRow(tableRow: CoreGradesTableRow): Promise { const row: CoreGradesFormattedRow = { rowclass: '', }; @@ -68,7 +68,7 @@ export class CoreGradesHelperProvider { let content = String(column.content); if (name == 'itemname') { - this.setRowIcon(row, content); + await this.setRowIcon(row, content); row.link = this.getModuleLink(content); row.rowclass += column.class.indexOf('hidden') >= 0 ? ' hidden' : ''; 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. * @return Formatted row object. */ - protected formatGradeRowForTable(tableRow: CoreGradesTableRow): CoreGradesFormattedTableRow { + protected async formatGradeRowForTable(tableRow: CoreGradesTableRow): Promise { const row: CoreGradesFormattedTableRow = {}; for (let name in tableRow) { const column: CoreGradesTableColumn = tableRow[name]; @@ -113,7 +113,7 @@ export class CoreGradesHelperProvider { row.colspan = itemNameColumn.colspan; 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('hidden') >= 0 ? ' hidden' : ''; 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. * @return Formatted HTML table. */ - formatGradesTable(table: CoreGradesTable): CoreGradesFormattedTable { + async formatGradesTable(table: CoreGradesTable): Promise { const maxDepth = table.maxdepth; const formatted: CoreGradesFormattedTable = { columns: [], @@ -178,7 +178,7 @@ export class CoreGradesHelperProvider { feedback: 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. let normalRow = formatted.rows.find( @@ -382,7 +382,7 @@ export class CoreGradesHelperProvider { * @param gradeId Grade Object identifier. * @return Formatted HTML table. */ - getGradesTableRow(table: CoreGradesTable, gradeId: number): CoreGradesFormattedRow | null { + async getGradesTableRow(table: CoreGradesTable, gradeId: number): Promise { if (table.tabledata) { const selectedRow = table.tabledata.find( (row) => @@ -393,7 +393,7 @@ export class CoreGradesHelperProvider { ); if (selectedRow) { - return this.formatGradeRow(selectedRow); + return await this.formatGradeRow(selectedRow); } } @@ -408,7 +408,7 @@ export class CoreGradesHelperProvider { * @return Formatted HTML table. * @deprecated since app 4.0 */ - getModuleGradesTableRows(table: CoreGradesTable, moduleId: number): CoreGradesFormattedRow[] { + async getModuleGradesTableRows(table: CoreGradesTable, moduleId: number): Promise { if (!table.tabledata) { return []; } @@ -416,7 +416,7 @@ export class CoreGradesHelperProvider { // Find href containing "/mod/xxx/xxx.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) { const matches = row.itemname.content.match(regex); @@ -428,7 +428,7 @@ export class CoreGradesHelperProvider { } 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. * @return Row object with the image. */ - protected setRowIcon(row: T, text: string): T { + protected async setRowIcon(row: T, text: string): Promise { text = text.replace('%2F', '/').replace('%2f', '/'); if (text.indexOf('/agg_mean') > -1) { row.itemtype = 'agg_mean'; @@ -566,7 +566,7 @@ export class CoreGradesHelperProvider { row.itemtype = 'mod'; row.itemmodule = module[1]; row.iconAlt = CoreCourse.translateModuleName(row.itemmodule) || ''; - row.image = CoreCourse.getModuleIconSrc( + row.image = await CoreCourse.getModuleIconSrc( module[1], CoreDomUtils.convertToElement(text).querySelector('img')?.getAttribute('src') ?? undefined, ); diff --git a/src/core/features/sitehome/pages/index/index.ts b/src/core/features/sitehome/pages/index/index.ts index 8976ef25e..7f59dae6d 100644 --- a/src/core/features/sitehome/pages/index/index.ts +++ b/src/core/features/sitehome/pages/index/index.ts @@ -17,7 +17,7 @@ import { IonRefresher } from '@ionic/angular'; import { Params } from '@angular/router'; 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 { CoreSites } from '@services/sites'; import { CoreSiteHome } from '@features/sitehome/services/sitehome'; @@ -48,7 +48,7 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy { hasContent = false; items: string[] = []; siteHomeId = 1; - currentSite?: CoreSite; + currentSite!: CoreSite; searchEnabled = false; downloadEnabled = false; downloadCourseEnabled = false; @@ -75,7 +75,7 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy { this.switchDownload(this.downloadEnabled && this.downloadCourseEnabled && this.downloadCoursesEnabled); }, CoreSites.getCurrentSiteId()); - this.currentSite = CoreSites.getCurrentSite()!; + this.currentSite = CoreSites.getRequiredCurrentSite(); this.siteHomeId = CoreSites.getCurrentSiteHomeId(); const module = CoreNavigator.getRouteParam('module'); @@ -97,7 +97,7 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy { protected async loadContent(): Promise { 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.hasContent = this.items.length > 0; @@ -105,13 +105,13 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy { if (this.items.some((item) => item == 'NEWS_ITEMS')) { // Get the news forum. try { - const forum = await CoreSiteHome.getNewsForum(); - this.newsForumModule = await CoreCourse.getModuleBasicInfo(forum.cmid); - this.newsForumModule.handlerData = CoreCourseModuleDelegate.getModuleDataFor( + const forum = await CoreSiteHome.getNewsForum(this.siteHomeId); + this.newsForumModule = await CoreCourse.getModule(forum.cmid, forum.course); + this.newsForumModule.handlerData = await CoreCourseModuleDelegate.getModuleDataFor( this.newsForumModule.modname, this.newsForumModule, this.siteHomeId, - this.newsForumModule.section, + undefined, true, ); } catch { @@ -120,7 +120,7 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy { } 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. 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. CoreCourse.logView( - this.siteHomeId!, + this.siteHomeId, undefined, undefined, - this.currentSite!.getInfo()?.sitename, + this.currentSite.getInfo()?.sitename, ).catch(() => { // Ignore errors. }); @@ -157,11 +157,11 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy { doRefresh(refresher?: IonRefresher): void { const promises: Promise[] = []; - promises.push(CoreCourse.invalidateSections(this.siteHomeId!)); - promises.push(this.currentSite!.invalidateConfig().then(async () => { + promises.push(CoreCourse.invalidateSections(this.siteHomeId)); + promises.push(this.currentSite.invalidateConfig().then(async () => { // Config invalidated, fetch it again. - const config: CoreSiteConfig = await this.currentSite!.getConfig(); - this.currentSite!.setConfig(config); + const config: CoreSiteConfig = await this.currentSite.getConfig(); + this.currentSite.setConfig(config); return; })); @@ -251,6 +251,6 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy { } -type NewsForum = CoreCourseModuleBasicInfo & { +type NewsForum = CoreCourseWSModule & { handlerData?: CoreCourseModuleHandlerData; }; diff --git a/src/core/features/sitehome/services/sitehome.ts b/src/core/features/sitehome/services/sitehome.ts index 8cb52346d..3de9e2ef9 100644 --- a/src/core/features/sitehome/services/sitehome.ts +++ b/src/core/features/sitehome/services/sitehome.ts @@ -20,6 +20,7 @@ import { makeSingleton } from '@singletons'; import { CoreCourse } from '../../course/services/course'; import { CoreCourses } from '../../courses/services/courses'; 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. @@ -57,7 +58,7 @@ export class CoreSiteHomeProvider { return forum; } - throw null; + throw new CoreError('No news forum found'); } /** From aa8c6136de59d2ce3a31a3ac922cdee3b18f8308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Wed, 22 Sep 2021 14:25:02 +0200 Subject: [PATCH 2/4] MOBILE-2748 mod: Use more specific type on module handlers --- src/addons/mod/forum/services/handlers/module.ts | 4 ++-- src/addons/mod/label/services/handlers/module.ts | 4 ++-- src/addons/mod/lti/services/handlers/module.ts | 5 ++--- src/addons/mod/resource/services/handlers/module.ts | 12 ++++++------ src/addons/mod/url/services/handlers/module.ts | 12 ++++++------ .../features/course/classes/module-base-handler.ts | 6 +++--- .../course/services/handlers/default-module.ts | 6 +++--- src/core/features/course/services/module-delegate.ts | 4 ++-- 8 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/addons/mod/forum/services/handlers/module.ts b/src/addons/mod/forum/services/handlers/module.ts index 7418879ca..98b81258b 100644 --- a/src/addons/mod/forum/services/handlers/module.ts +++ b/src/addons/mod/forum/services/handlers/module.ts @@ -14,7 +14,6 @@ import { Injectable, Type } from '@angular/core'; import { AddonModForum, AddonModForumProvider } from '../forum'; -import { CoreCourseAnyModuleData } from '@features/course/services/course'; import { makeSingleton, Translate } from '@singletons'; import { CoreEvents } from '@singletons/events'; import { CoreSites } from '@services/sites'; @@ -23,6 +22,7 @@ import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/ import { CoreConstants } from '@/core/constants'; import { AddonModForumIndexComponent } from '../../components/index'; import { CoreModuleHandlerBase } from '@features/course/classes/module-base-handler'; +import { CoreCourseModule } from '@features/course/services/course-helper'; /** * Handler to support forum modules. @@ -53,7 +53,7 @@ export class AddonModForumModuleHandlerService extends CoreModuleHandlerBase imp /** * @inheritdoc */ - async getData(module: CoreCourseAnyModuleData, courseId: number): Promise { + async getData(module: CoreCourseModule, courseId: number): Promise { const data = await super.getData(module, courseId); if ('afterlink' in module && !!module.afterlink) { diff --git a/src/addons/mod/label/services/handlers/module.ts b/src/addons/mod/label/services/handlers/module.ts index c51a15fa0..fe1306f3e 100644 --- a/src/addons/mod/label/services/handlers/module.ts +++ b/src/addons/mod/label/services/handlers/module.ts @@ -15,7 +15,7 @@ import { CoreConstants } from '@/core/constants'; import { Injectable } from '@angular/core'; import { CoreModuleHandlerBase } from '@features/course/classes/module-base-handler'; -import { CoreCourseWSModule } from '@features/course/services/course'; +import { CoreCourseModule } from '@features/course/services/course-helper'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate'; import { makeSingleton } from '@singletons'; @@ -44,7 +44,7 @@ export class AddonModLabelModuleHandlerService extends CoreModuleHandlerBase imp /** * @inheritdoc */ - async getData(module: CoreCourseWSModule): Promise { + async getData(module: CoreCourseModule): Promise { // Remove the description from the module so it isn't rendered twice. const title = module.description || ''; module.description = ''; diff --git a/src/addons/mod/lti/services/handlers/module.ts b/src/addons/mod/lti/services/handlers/module.ts index 79d1b90a1..6213d8c9a 100644 --- a/src/addons/mod/lti/services/handlers/module.ts +++ b/src/addons/mod/lti/services/handlers/module.ts @@ -16,7 +16,6 @@ import { Injectable, Type } from '@angular/core'; import { CoreConstants } from '@/core/constants'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate'; -import { CoreCourseAnyModuleData } from '@features/course/services/course'; import { CoreCourseModule } from '@features/course/services/course-helper'; import { CoreApp } from '@services/app'; import { CoreFilepool } from '@services/filepool'; @@ -55,7 +54,7 @@ export class AddonModLtiModuleHandlerService extends CoreModuleHandlerBase imple * @inheritdoc */ async getData( - module: CoreCourseAnyModuleData, + module: CoreCourseModule, courseId: number, sectionId?: number, forCoursePage?: boolean, @@ -87,7 +86,7 @@ export class AddonModLtiModuleHandlerService extends CoreModuleHandlerBase imple * @return Promise resolved when done. */ protected async loadCustomIcon( - module: CoreCourseAnyModuleData, + module: CoreCourseModule, courseId: number, handlerData: CoreCourseModuleHandlerData, ): Promise { diff --git a/src/addons/mod/resource/services/handlers/module.ts b/src/addons/mod/resource/services/handlers/module.ts index f9ed3f2c2..3c6030331 100644 --- a/src/addons/mod/resource/services/handlers/module.ts +++ b/src/addons/mod/resource/services/handlers/module.ts @@ -15,7 +15,7 @@ import { CoreConstants } from '@/core/constants'; import { Injectable, Type } from '@angular/core'; import { CoreModuleHandlerBase } from '@features/course/classes/module-base-handler'; -import { CoreCourse, CoreCourseAnyModuleData, CoreCourseModuleContentFile } from '@features/course/services/course'; +import { CoreCourse, CoreCourseModuleContentFile } from '@features/course/services/course'; import { CoreCourseModule } from '@features/course/services/course-helper'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate'; import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate'; @@ -64,7 +64,7 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase * @inheritdoc */ async getData( - module: CoreCourseAnyModuleData, + module: CoreCourseModule, courseId: number, sectionId?: number, forCoursePage?: boolean, @@ -94,7 +94,7 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase }]; this.getResourceData(module, courseId, handlerData).then((data) => { - handlerData.icon = data.icon; + handlerData.icon = handlerData.icon || data.icon; handlerData.extraBadge = data.extra; handlerData.extraBadgeColor = 'light'; @@ -113,7 +113,7 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase * @param courseId The course ID. * @return Resolved when done. */ - protected async hideOpenButton(module: CoreCourseAnyModuleData, courseId: number): Promise { + protected async hideOpenButton(module: CoreCourseModule, courseId: number): Promise { if (!('contentsinfo' in module) || !module.contentsinfo) { await CoreCourse.loadModuleContents(module, courseId, undefined, false, false, undefined, this.modName); } @@ -131,7 +131,7 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase * @return Resource data. */ protected async getResourceData( - module: CoreCourseAnyModuleData, + module: CoreCourseModule, courseId: number, handlerData: CoreCourseModuleHandlerData, ): Promise { @@ -233,7 +233,7 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase // No previously set, just set the icon. if (resourceData.icon == '') { - resourceData.icon = await CoreCourse.getModuleIconSrc(module.modname, 'modicon' in module ? module.modicon : undefined); + resourceData.icon = await CoreCourse.getModuleIconSrc(module.modname, module.modicon); } return resourceData; diff --git a/src/addons/mod/url/services/handlers/module.ts b/src/addons/mod/url/services/handlers/module.ts index 94634f181..b1cdfaf9e 100644 --- a/src/addons/mod/url/services/handlers/module.ts +++ b/src/addons/mod/url/services/handlers/module.ts @@ -16,7 +16,7 @@ import { CoreConstants } from '@/core/constants'; import { Injectable, Type } from '@angular/core'; import { CoreContentLinksHelper } from '@features/contentlinks/services/contentlinks-helper'; import { CoreModuleHandlerBase } from '@features/course/classes/module-base-handler'; -import { CoreCourse, CoreCourseAnyModuleData } from '@features/course/services/course'; +import { CoreCourse } from '@features/course/services/course'; import { CoreCourseModule } from '@features/course/services/course-helper'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate'; import { CoreNavigationOptions, CoreNavigator } from '@services/navigator'; @@ -54,7 +54,7 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple /** * @inheritdoc */ - async getData(module: CoreCourseAnyModuleData, courseId: number): Promise { + async getData(module: CoreCourseModule, courseId: number): Promise { /** * Open the URL. @@ -77,7 +77,7 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple }; const handlerData: CoreCourseModuleHandlerData = { - icon: await CoreCourse.getModuleIconSrc(module.modname, 'modicon' in module ? module.modicon : undefined), + icon: await CoreCourse.getModuleIconSrc(module.modname, module.modicon), title: module.name, class: 'addon-mod_url-handler', showDownloadButton: false, @@ -120,8 +120,8 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple if (module.contents && module.contents[0]) { // Calculate the icon to use. - handlerData.icon = AddonModUrl.guessIcon(module.contents[0].fileurl) || - await CoreCourse.getModuleIconSrc(module.modname, 'modicon' in module ? module.modicon : undefined); + handlerData.icon = await CoreCourse.getModuleIconSrc(module.modname, module.modicon) || + AddonModUrl.guessIcon(module.contents[0].fileurl); } return; @@ -139,7 +139,7 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple * @param courseId The course ID. * @return Resolved when done. */ - protected async hideLinkButton(module: CoreCourseAnyModuleData, courseId: number): Promise { + protected async hideLinkButton(module: CoreCourseModule, courseId: number): Promise { try { const contents = await CoreCourse.getModuleContents(module, courseId, undefined, false, false, undefined, this.modName); diff --git a/src/core/features/course/classes/module-base-handler.ts b/src/core/features/course/classes/module-base-handler.ts index d44bc8238..f45aa6a53 100644 --- a/src/core/features/course/classes/module-base-handler.ts +++ b/src/core/features/course/classes/module-base-handler.ts @@ -13,7 +13,7 @@ // limitations under the License. import { CoreNavigationOptions, CoreNavigator } from '@services/navigator'; -import { CoreCourse, CoreCourseAnyModuleData } from '../services/course'; +import { CoreCourse } from '../services/course'; import { CoreCourseModule } from '../services/course-helper'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '../services/module-delegate'; @@ -35,13 +35,13 @@ export class CoreModuleHandlerBase implements Partial { * @inheritdoc */ async getData( - module: CoreCourseAnyModuleData, + module: CoreCourseModule, courseId: 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 ): Promise { return { - icon: await CoreCourse.getModuleIconSrc(module.modname, 'modicon' in module ? module.modicon : undefined), + icon: await CoreCourse.getModuleIconSrc(module.modname, module.modicon), title: module.name, class: 'addon-mod_' + module.modname + '-handler', showDownloadButton: true, diff --git a/src/core/features/course/services/handlers/default-module.ts b/src/core/features/course/services/handlers/default-module.ts index d6f7d9637..25bf41663 100644 --- a/src/core/features/course/services/handlers/default-module.ts +++ b/src/core/features/course/services/handlers/default-module.ts @@ -16,7 +16,7 @@ import { Injectable, Type } from '@angular/core'; import { CoreSites } from '@services/sites'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '../module-delegate'; -import { CoreCourse, CoreCourseAnyModuleData } from '../course'; +import { CoreCourse } from '../course'; import { CoreCourseModule } from '../course-helper'; import { CoreCourseUnsupportedModuleComponent } from '@features/course/components/unsupported-module/unsupported-module'; import { CoreNavigationOptions, CoreNavigator } from '@services/navigator'; @@ -42,11 +42,11 @@ export class CoreCourseModuleDefaultHandler implements CoreCourseModuleHandler { * @inheritdoc */ async getData( - module: CoreCourseAnyModuleData, + module: CoreCourseModule, ): Promise { // Return the default data. const defaultData: CoreCourseModuleHandlerData = { - icon: await CoreCourse.getModuleIconSrc(module.modname, 'modicon' in module ? module.modicon : undefined), + icon: await CoreCourse.getModuleIconSrc(module.modname, module.modicon), title: module.name, class: 'core-course-default-handler core-course-module-' + module.modname + '-handler', action: (event: Event, module: CoreCourseModule, courseId: number, options?: CoreNavigationOptions) => { diff --git a/src/core/features/course/services/module-delegate.ts b/src/core/features/course/services/module-delegate.ts index e7165da57..9ff01b011 100644 --- a/src/core/features/course/services/module-delegate.ts +++ b/src/core/features/course/services/module-delegate.ts @@ -52,7 +52,7 @@ export interface CoreCourseModuleHandler extends CoreDelegateHandler { * @return Data to render the module. */ getData( - module: CoreCourseAnyModuleData, + module: CoreCourseModule, courseId: number, sectionId?: number, forCoursePage?: boolean, @@ -279,7 +279,7 @@ export class CoreCourseModuleDelegateService extends CoreDelegate Date: Mon, 27 Sep 2021 16:44:24 +0200 Subject: [PATCH 3/4] MOBILE-2748 mod: Create a new module icon component --- .../addon-block-activitymodules.html | 3 +- .../addon-block-recentlyaccesseditems.html | 4 +- .../events/addon-block-timeline-events.html | 6 +- .../timeline/components/events/events.ts | 3 +- src/addons/calendar/calendar-common.scss | 7 +- .../calendar/addon-calendar-calendar.html | 5 +- .../components/calendar/calendar.scss | 8 +- .../addon-calendar-upcoming-events.html | 4 +- src/addons/calendar/pages/day/day.html | 5 +- src/addons/calendar/pages/event/event.html | 3 +- src/addons/calendar/pages/event/event.scss | 3 +- .../pages/competency/competency.html | 3 +- .../coursecompetencies.html | 4 +- .../mod/lti/services/handlers/module.ts | 50 +---------- .../mod/resource/services/handlers/module.ts | 39 +++----- .../mod/url/services/handlers/module.ts | 5 +- .../pages/course-storage/course-storage.html | 5 +- .../pages/course-storage/course-storage.ts | 2 - src/core/components/components.module.ts | 3 + src/core/components/mod-icon/mod-icon.html | 19 ++++ src/core/components/mod-icon/mod-icon.scss | 37 ++++++++ src/core/components/mod-icon/mod-icon.ts | 88 +++++++++++++++++++ .../components/user-avatar/user-avatar.scss | 5 ++ src/core/directives/external-content.ts | 3 +- .../components/module/core-course-module.html | 5 +- src/core/features/course/services/course.ts | 19 ++-- .../course/services/module-delegate.ts | 2 +- .../features/grades/pages/course/course.html | 5 +- .../grades/pages/course/course.page.ts | 4 +- .../features/grades/pages/course/course.scss | 10 +++ .../features/grades/pages/grade/grade.html | 9 +- .../tag/components/feed/core-tag-feed.html | 4 +- src/theme/theme.base.scss | 26 ------ 33 files changed, 251 insertions(+), 147 deletions(-) create mode 100644 src/core/components/mod-icon/mod-icon.html create mode 100644 src/core/components/mod-icon/mod-icon.scss create mode 100644 src/core/components/mod-icon/mod-icon.ts diff --git a/src/addons/block/activitymodules/components/activitymodules/addon-block-activitymodules.html b/src/addons/block/activitymodules/components/activitymodules/addon-block-activitymodules.html index 1f39261b4..2306e3b4b 100644 --- a/src/addons/block/activitymodules/components/activitymodules/addon-block-activitymodules.html +++ b/src/addons/block/activitymodules/components/activitymodules/addon-block-activitymodules.html @@ -6,7 +6,8 @@ - + + {{ entry.name }} diff --git a/src/addons/block/recentlyaccesseditems/components/recentlyaccesseditems/addon-block-recentlyaccesseditems.html b/src/addons/block/recentlyaccesseditems/components/recentlyaccesseditems/addon-block-recentlyaccesseditems.html index 4990142ad..73e52969f 100644 --- a/src/addons/block/recentlyaccesseditems/components/recentlyaccesseditems/addon-block-recentlyaccesseditems.html +++ b/src/addons/block/recentlyaccesseditems/components/recentlyaccesseditems/addon-block-recentlyaccesseditems.html @@ -17,7 +17,9 @@ - + + {{ item.iconTitle }} diff --git a/src/addons/block/timeline/components/events/addon-block-timeline-events.html b/src/addons/block/timeline/components/events/addon-block-timeline-events.html index 022dcc211..0622e2e0b 100644 --- a/src/addons/block/timeline/components/events/addon-block-timeline-events.html +++ b/src/addons/block/timeline/components/events/addon-block-timeline-events.html @@ -5,10 +5,10 @@ - + + - - {{ event.iconTitle }}

diff --git a/src/addons/block/timeline/components/events/events.ts b/src/addons/block/timeline/components/events/events.ts index bf77da586..b0db9c8a0 100644 --- a/src/addons/block/timeline/components/events/events.ts +++ b/src/addons/block/timeline/components/events/events.ts @@ -104,7 +104,8 @@ export class AddonBlockTimelineEventsComponent implements OnChanges { return start <= event.timesort; }).map(async (event) => { event.iconUrl = await CoreCourse.getModuleIconSrc(event.icon.component); - event.iconTitle = event.modulename && CoreCourse.translateModuleName(event.modulename); + event.modulename = event.modulename || event.icon.component; + event.iconTitle = CoreCourse.translateModuleName(event.modulename); return event; })); diff --git a/src/addons/calendar/calendar-common.scss b/src/addons/calendar/calendar-common.scss index 771f1987e..8fdaaeefe 100644 --- a/src/addons/calendar/calendar-common.scss +++ b/src/addons/calendar/calendar-common.scss @@ -9,6 +9,10 @@ padding: 6px; } + > core-mod-icon { + padding: 6px; + } + &.addon-calendar-eventtype-category > ion-icon { background-color: var(--addon-calendar-event-category-color); } @@ -25,4 +29,5 @@ background-color: var(--addon-calendar-event-site-color); } } -} + +} \ No newline at end of file diff --git a/src/addons/calendar/components/calendar/addon-calendar-calendar.html b/src/addons/calendar/components/calendar/addon-calendar-calendar.html index 93d477d00..570926c23 100644 --- a/src/addons/calendar/components/calendar/addon-calendar-calendar.html +++ b/src/addons/calendar/components/calendar/addon-calendar-calendar.html @@ -88,8 +88,9 @@ {{ event.timestart * 1000 | coreFormatDate: timeFormat }} - + + {{ 'addon.calendar.type' + event.formattedType | translate }} diff --git a/src/addons/calendar/components/calendar/calendar.scss b/src/addons/calendar/components/calendar/calendar.scss index 4d9303f3b..acbcccf6b 100644 --- a/src/addons/calendar/components/calendar/calendar.scss +++ b/src/addons/calendar/components/calendar/calendar.scss @@ -144,15 +144,15 @@ } } - .core-module-icon { + core-mod-icon { margin-right: 1px; margin-left: 1px; --size: 16px; display: inline-block; vertical-align: bottom; - } - .core-module-icon[slot="start"] { - padding: 6px; + ::ng-deep img { + display: block; + } } } diff --git a/src/addons/calendar/components/upcoming-events/addon-calendar-upcoming-events.html b/src/addons/calendar/components/upcoming-events/addon-calendar-upcoming-events.html index 315e8e624..30c9c2224 100644 --- a/src/addons/calendar/components/upcoming-events/addon-calendar-upcoming-events.html +++ b/src/addons/calendar/components/upcoming-events/addon-calendar-upcoming-events.html @@ -6,8 +6,8 @@ - + diff --git a/src/addons/calendar/pages/day/day.html b/src/addons/calendar/pages/day/day.html index 9f4b23431..c0e8bb1d7 100644 --- a/src/addons/calendar/pages/day/day.html +++ b/src/addons/calendar/pages/day/day.html @@ -61,8 +61,9 @@ - + + diff --git a/src/addons/calendar/pages/event/event.html b/src/addons/calendar/pages/event/event.html index 6244bc546..493b41712 100644 --- a/src/addons/calendar/pages/event/event.html +++ b/src/addons/calendar/pages/event/event.html @@ -4,7 +4,8 @@

- + diff --git a/src/addons/calendar/pages/event/event.scss b/src/addons/calendar/pages/event/event.scss index bc2bb8cb3..5403de162 100644 --- a/src/addons/calendar/pages/event/event.scss +++ b/src/addons/calendar/pages/event/event.scss @@ -2,8 +2,9 @@ ion-card ion-note { font-size: 1.6rem; } - h1 ion-icon, h1 img { + h1 ion-icon, h1 img, h1 core-mod-icon { margin-left: 10px; margin-right: 10px; + display: inline-block; } } diff --git a/src/addons/competency/pages/competency/competency.html b/src/addons/competency/pages/competency/competency.html index 0406897e2..cc34b86b0 100644 --- a/src/addons/competency/pages/competency/competency.html +++ b/src/addons/competency/pages/competency/competency.html @@ -77,8 +77,7 @@

- + diff --git a/src/addons/competency/pages/coursecompetencies/coursecompetencies.html b/src/addons/competency/pages/coursecompetencies/coursecompetencies.html index de2b0bb59..a0e2f63e3 100644 --- a/src/addons/competency/pages/coursecompetencies/coursecompetencies.html +++ b/src/addons/competency/pages/coursecompetencies/coursecompetencies.html @@ -114,8 +114,8 @@

- + + diff --git a/src/addons/mod/lti/services/handlers/module.ts b/src/addons/mod/lti/services/handlers/module.ts index 6213d8c9a..1692ec173 100644 --- a/src/addons/mod/lti/services/handlers/module.ts +++ b/src/addons/mod/lti/services/handlers/module.ts @@ -17,13 +17,8 @@ import { Injectable, Type } from '@angular/core'; import { CoreConstants } from '@/core/constants'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate'; import { CoreCourseModule } from '@features/course/services/course-helper'; -import { CoreApp } from '@services/app'; -import { CoreFilepool } from '@services/filepool'; -import { CoreSites } from '@services/sites'; -import { CoreUtils } from '@services/utils/utils'; -import { DomSanitizer, makeSingleton } from '@singletons'; +import { makeSingleton } from '@singletons'; import { AddonModLtiHelper } from '../lti-helper'; -import { AddonModLti, AddonModLtiProvider } from '../lti'; import { AddonModLtiIndexComponent } from '../../components/index'; import { CoreModuleHandlerBase } from '@features/course/classes/module-base-handler'; @@ -62,6 +57,9 @@ export class AddonModLtiModuleHandlerService extends CoreModuleHandlerBase imple const data = await super.getData(module, courseId, sectionId, forCoursePage); data.showDownloadButton = false; + // Handle custom icons. + data.icon = module.modicon; + data.buttons = [{ icon: 'fas-external-link-alt', label: 'addon.mod_lti.launchactivity', @@ -71,49 +69,9 @@ export class AddonModLtiModuleHandlerService extends CoreModuleHandlerBase imple }, }]; - // Handle custom icons. - CoreUtils.ignoreErrors(this.loadCustomIcon(module, courseId, data)); - return data; } - /** - * Load the custom icon. - * - * @param module Module. - * @param courseId Course ID. - * @param data Handler data. - * @return Promise resolved when done. - */ - protected async loadCustomIcon( - module: CoreCourseModule, - courseId: number, - handlerData: CoreCourseModuleHandlerData, - ): Promise { - const lti = await AddonModLti.getLti(courseId, module.id); - - const icon = lti.secureicon || lti.icon; - if (!icon) { - return; - } - - const siteId = CoreSites.getCurrentSiteId(); - - try { - await CoreFilepool.downloadUrl(siteId, icon, false, AddonModLtiProvider.COMPONENT, module.id); - - // Get the internal URL. - const url = await CoreFilepool.getSrcByUrl(siteId, icon, AddonModLtiProvider.COMPONENT, module.id); - - handlerData.icon = DomSanitizer.bypassSecurityTrustUrl(url); - } catch { - // Error downloading. If we're online we'll set the online url. - if (CoreApp.isOnline()) { - handlerData.icon = DomSanitizer.bypassSecurityTrustUrl(icon); - } - } - } - /** * @inheritdoc */ diff --git a/src/addons/mod/resource/services/handlers/module.ts b/src/addons/mod/resource/services/handlers/module.ts index 3c6030331..69a3d2ce8 100644 --- a/src/addons/mod/resource/services/handlers/module.ts +++ b/src/addons/mod/resource/services/handlers/module.ts @@ -15,7 +15,7 @@ import { CoreConstants } from '@/core/constants'; import { Injectable, Type } from '@angular/core'; import { CoreModuleHandlerBase } from '@features/course/classes/module-base-handler'; -import { CoreCourse, CoreCourseModuleContentFile } from '@features/course/services/course'; +import { CoreCourse } from '@features/course/services/course'; import { CoreCourseModule } from '@features/course/services/course-helper'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate'; import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate'; @@ -23,7 +23,6 @@ import { CoreFileHelper } from '@services/file-helper'; import { CoreMimetypeUtils } from '@services/utils/mimetype'; import { CoreTextUtils } from '@services/utils/text'; import { CoreTimeUtils } from '@services/utils/time'; -import { CoreWSFile } from '@services/ws'; import { makeSingleton, Translate } from '@singletons'; import { AddonModResourceIndexComponent } from '../../components/index'; import { AddonModResource, AddonModResourceCustomData } from '../resource'; @@ -94,7 +93,7 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase }]; this.getResourceData(module, courseId, handlerData).then((data) => { - handlerData.icon = handlerData.icon || data.icon; + handlerData.icon = data.icon; handlerData.extraBadge = data.extra; handlerData.extraBadgeColor = 'light'; @@ -136,7 +135,6 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase handlerData: CoreCourseModuleHandlerData, ): Promise { const promises: Promise[] = []; - let infoFiles: CoreWSFile[] = []; let options: AddonModResourceCustomData = {}; // Check if the button needs to be shown or not. @@ -150,12 +148,11 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase return; })); - if ('customdata' in module && typeof module.customdata != 'undefined') { + if ('customdata' in module && module.customdata !== undefined) { options = CoreTextUtils.unserialize(CoreTextUtils.parseJSON(module.customdata)); } else { // Get the resource data. promises.push(AddonModResource.getResourceData(courseId, module.id).then((info) => { - infoFiles = info.contentfiles; options = CoreTextUtils.unserialize(info.displayoptions); return; @@ -164,28 +161,22 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase await Promise.all(promises); - const files: (CoreCourseModuleContentFile | CoreWSFile)[] = module.contents && module.contents.length - ? module.contents - : infoFiles; - - const resourceData: AddonResourceHandlerData = { - icon: '', - extra: '', - }; + let mimetypeIcon = ''; const extra: string[] = []; if ('contentsinfo' in module && module.contentsinfo) { // No need to use the list of files. const mimetype = module.contentsinfo.mimetypes[0]; if (mimetype) { - resourceData.icon = CoreMimetypeUtils.getMimetypeIcon(mimetype); + mimetypeIcon = CoreMimetypeUtils.getMimetypeIcon(mimetype); } - resourceData.extra = CoreTextUtils.cleanTags(module.afterlink); + extra.push(CoreTextUtils.cleanTags(module.afterlink)); - } else if (files && files.length) { + } else if (module.contents && module.contents[0]) { + const files = module.contents; const file = files[0]; - resourceData.icon = CoreMimetypeUtils.getFileIcon(file.filename || ''); + mimetypeIcon = CoreMimetypeUtils.getFileIcon(file.filename || ''); if (options.showsize) { const size = options.filedetails @@ -227,16 +218,12 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase )); } } - - resourceData.extra += extra.join(' '); } - // No previously set, just set the icon. - if (resourceData.icon == '') { - resourceData.icon = await CoreCourse.getModuleIconSrc(module.modname, module.modicon); - } - - return resourceData; + return { + icon: await CoreCourse.getModuleIconSrc(module.modname, module.modicon, mimetypeIcon), + extra: extra.join(' '), + }; } /** diff --git a/src/addons/mod/url/services/handlers/module.ts b/src/addons/mod/url/services/handlers/module.ts index b1cdfaf9e..e6257f845 100644 --- a/src/addons/mod/url/services/handlers/module.ts +++ b/src/addons/mod/url/services/handlers/module.ts @@ -119,9 +119,10 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple handlerData.buttons[0].hidden = hideButton; if (module.contents && module.contents[0]) { + const icon = AddonModUrl.guessIcon(module.contents[0].fileurl); + // Calculate the icon to use. - handlerData.icon = await CoreCourse.getModuleIconSrc(module.modname, module.modicon) || - AddonModUrl.guessIcon(module.contents[0].fileurl); + handlerData.icon = await CoreCourse.getModuleIconSrc(module.modname, module.modicon, icon); } return; diff --git a/src/addons/storagemanager/pages/course-storage/course-storage.html b/src/addons/storagemanager/pages/course-storage/course-storage.html index 1220ca816..a2417b7ac 100644 --- a/src/addons/storagemanager/pages/course-storage/course-storage.html +++ b/src/addons/storagemanager/pages/course-storage/course-storage.html @@ -45,8 +45,9 @@ - + +

{{ module.name }} diff --git a/src/addons/storagemanager/pages/course-storage/course-storage.ts b/src/addons/storagemanager/pages/course-storage/course-storage.ts index 752059a7a..e52ddb0e0 100644 --- a/src/addons/storagemanager/pages/course-storage/course-storage.ts +++ b/src/addons/storagemanager/pages/course-storage/course-storage.ts @@ -63,7 +63,6 @@ export class AddonStorageManagerCourseStoragePage implements OnInit { section.modules.forEach((module) => { module.parentSection = section; module.totalSize = 0; - module.modNameTranslated = CoreCourse.translateModuleName(module.modname) || ''; // Note: This function only gets the size for modules which are downloadable. // For other modules it always returns 0, even if they have downloaded some files. @@ -235,5 +234,4 @@ type AddonStorageManagerCourseSection = Omit & { type AddonStorageManagerModule = CoreCourseModule & { parentSection?: AddonStorageManagerCourseSection; totalSize?: number; - modNameTranslated?: string; }; diff --git a/src/core/components/components.module.ts b/src/core/components/components.module.ts index ee3d02b2e..b055bad15 100644 --- a/src/core/components/components.module.ts +++ b/src/core/components/components.module.ts @@ -40,6 +40,7 @@ import { CoreInputErrorsComponent } from './input-errors/input-errors'; import { CoreLoadingComponent } from './loading/loading'; import { CoreLocalFileComponent } from './local-file/local-file'; import { CoreMarkRequiredComponent } from './mark-required/mark-required'; +import { CoreModIconComponent } from './mod-icon/mod-icon'; import { CoreNavBarButtonsComponent } from './navbar-buttons/navbar-buttons'; import { CoreNavigationBarComponent } from './navigation-bar/navigation-bar'; import { CoreProgressBarComponent } from './progress-bar/progress-bar'; @@ -81,6 +82,7 @@ import { CoreButtonWithSpinnerComponent } from './button-with-spinner/button-wit CoreLoadingComponent, CoreLocalFileComponent, CoreMarkRequiredComponent, + CoreModIconComponent, CoreNavBarButtonsComponent, CoreNavigationBarComponent, CoreProgressBarComponent, @@ -128,6 +130,7 @@ import { CoreButtonWithSpinnerComponent } from './button-with-spinner/button-wit CoreLoadingComponent, CoreLocalFileComponent, CoreMarkRequiredComponent, + CoreModIconComponent, CoreNavBarButtonsComponent, CoreNavigationBarComponent, CoreProgressBarComponent, diff --git a/src/core/components/mod-icon/mod-icon.html b/src/core/components/mod-icon/mod-icon.html new file mode 100644 index 000000000..4ce9eef5c --- /dev/null +++ b/src/core/components/mod-icon/mod-icon.html @@ -0,0 +1,19 @@ + + \ No newline at end of file diff --git a/src/core/components/mod-icon/mod-icon.scss b/src/core/components/mod-icon/mod-icon.scss new file mode 100644 index 000000000..e8cbb5754 --- /dev/null +++ b/src/core/components/mod-icon/mod-icon.scss @@ -0,0 +1,37 @@ +:host { + --size: var(--module-icon-size); + --margin-end: 0px; + --margin-vertical: 0px; + + margin-top: var(--margin-vertical); + margin-bottom: var(--margin-vertical); + margin-right: var(--margin-end); +} + +img { + width: var(--size); + height: var(--size); + max-width: var(--size); + max-height: var(--size); + + &[alt] { + text-indent: -999999px; + white-space: nowrap; + overflow: hidden; + } +} + +:host-context(ion-item) { + --margin-vertical: 12px; + --margin-end: 32px; +} + +:host-context(ion-card ion-item) { + --margin-vertical: 12px; + --margin-end: 12px; +} + +:host-context([dir=rtl]) { + margin-right: unset; + margin-left: var(--margin-end); +} \ No newline at end of file diff --git a/src/core/components/mod-icon/mod-icon.ts b/src/core/components/mod-icon/mod-icon.ts new file mode 100644 index 000000000..eba805215 --- /dev/null +++ b/src/core/components/mod-icon/mod-icon.ts @@ -0,0 +1,88 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, Input, OnChanges, OnInit, SimpleChange } from '@angular/core'; +import { CoreCourse } from '@features/course/services/course'; + +const assetsPath = 'assets/img/mod/'; +const fallbackModName = 'external-tool'; + +/** + * Component to handle a module icon. + */ +@Component({ + selector: 'core-mod-icon', + templateUrl: 'mod-icon.html', + styleUrls: ['mod-icon.scss'], +}) +export class CoreModIconComponent implements OnInit, OnChanges { + + @Input() modname?; // The module name. Used also as component if set. + @Input() componentId?; // Component Id for external icons. + @Input() modicon?: string; // Module icon url or local url. + @Input() showAlt = true; // Show alt otherwise it's only presentation icon. + + icon = ''; + modNameTranslated = ''; + isLocalUrl = true; + linkIconWithComponent = false; + + /** + * @inheritdoc + */ + async ngOnInit(): Promise { + this.modNameTranslated = this.modname ? CoreCourse.translateModuleName(this.modname) || '' : ''; + + this.setIcon(); + } + + /** + * @inheritdoc + */ + ngOnChanges(changes: { [name: string]: SimpleChange }): void { + if (changes && changes.modicon && changes.modicon.previousValue) { + this.setIcon(); + } + } + + /** + * Set icon. + */ + setIcon(): void { + this.icon = this.modicon || this.icon; + this.isLocalUrl = this.icon.startsWith(assetsPath); + + // Cache icon if the url is not the theme generic one. + // If modname is not set icon won't be cached. + // Also if the url matches the regexp (the theme will manage the image so it's not cached). + this.linkIconWithComponent = + this.modname && + this.componentId && + !this.isLocalUrl && + !this.icon.match('/theme/image.php/[^/]+/' + this.modname + '/[-0-9]*/'); + } + + /** + * Icon to load on error. + */ + loadFallbackIcon(): void { + this.isLocalUrl = true; + const moduleName = !this.modname || CoreCourse.CORE_MODULES.indexOf(this.modname) < 0 + ? fallbackModName + : this.modname; + + this.icon = assetsPath + moduleName + '.svg'; + } + +} diff --git a/src/core/components/user-avatar/user-avatar.scss b/src/core/components/user-avatar/user-avatar.scss index 6ae01b259..5d99ba41d 100644 --- a/src/core/components/user-avatar/user-avatar.scss +++ b/src/core/components/user-avatar/user-avatar.scss @@ -79,3 +79,8 @@ left: 0; right: unset; } + +:host-context(ion-item) { + margin-top: 12px; + margin-bottom: 12px; +} \ No newline at end of file diff --git a/src/core/directives/external-content.ts b/src/core/directives/external-content.ts index 4dd8f719f..4d84f6845 100644 --- a/src/core/directives/external-content.ts +++ b/src/core/directives/external-content.ts @@ -113,8 +113,7 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges { * Get the URL that should be handled and, if valid, handle it. */ protected async checkAndHandleExternalContent(): Promise { - const currentSite = CoreSites.getCurrentSite(); - const siteId = this.siteId || currentSite?.getId(); + const siteId = this.siteId || CoreSites.getRequiredCurrentSite().getId(); const tagName = this.element.tagName.toUpperCase(); let targetAttr; let url; diff --git a/src/core/features/course/components/module/core-course-module.html b/src/core/features/course/components/module/core-course-module.html index bbfebb68c..630c19e11 100644 --- a/src/core/features/course/components/module/core-course-module.html +++ b/src/core/features/course/components/module/core-course-module.html @@ -13,8 +13,9 @@ [button]="module.handlerData.action && module.uservisible" detail="false"> - + +

diff --git a/src/core/features/course/services/course.ts b/src/core/features/course/services/course.ts index 0e7f38649..81505df14 100644 --- a/src/core/features/course/services/course.ts +++ b/src/core/features/course/services/course.ts @@ -83,7 +83,7 @@ export class CoreCourseProvider { static readonly COMPONENT = 'CoreCourse'; - protected readonly CORE_MODULES = [ + readonly CORE_MODULES = [ 'assign', 'assignment', 'book', 'chat', 'choice', 'data', 'database', 'date', 'external-tool', 'feedback', 'file', 'folder', 'forum', 'glossary', 'ims', 'imscp', 'label', 'lesson', 'lti', 'page', 'quiz', 'resource', 'scorm', 'survey', 'url', 'wiki', 'workshop', 'h5pactivity', @@ -402,15 +402,16 @@ export class CoreCourseProvider { ): Promise => { const params: CoreCourseGetContentsParams = { courseid: courseId!, - options: [], }; + params.options = []; + const preSets: CoreSiteWSPreSets = { omitExpires: preferCache, updateFrequency: CoreSite.FREQUENCY_RARELY, }; if (includeStealth) { - params.options!.push({ + params.options.push({ name: 'includestealthmodules', value: true, }); @@ -418,13 +419,13 @@ export class CoreCourseProvider { // If modName is set, retrieve all modules of that type. Otherwise get only the module. if (modName) { - params.options!.push({ + params.options.push({ name: 'modname', value: modName, }); preSets.cacheKey = this.getModuleByModNameCacheKey(modName); } else { - params.options!.push({ + params.options.push({ name: 'cmid', value: moduleId, }); @@ -630,7 +631,11 @@ export class CoreCourseProvider { * @param modicon The mod icon string to use in case we are not using a core activity. * @return The IMG src. */ - async getModuleIconSrc(moduleName: string, modicon?: string): Promise { + async getModuleIconSrc(moduleName: string, modicon?: string, mimetypeIcon = ''): Promise { + if (mimetypeIcon) { + return mimetypeIcon; + } + if (this.CORE_MODULES.indexOf(moduleName) < 0) { if (modicon) { return modicon; @@ -1489,7 +1494,7 @@ export type CoreCourseWSModule = { label: string; timestamp: number; }[]; // @since 3.11. Activity dates. - contentsinfo?: { // Contents summary information. + contentsinfo?: { // @since v3.7.6 Contents summary information. filescount: number; // Total number of files. filessize: number; // Total files size. lastmodified: number; // Last time files were modified. diff --git a/src/core/features/course/services/module-delegate.ts b/src/core/features/course/services/module-delegate.ts index 9ff01b011..f967c89a5 100644 --- a/src/core/features/course/services/module-delegate.ts +++ b/src/core/features/course/services/module-delegate.ts @@ -20,7 +20,7 @@ import { CoreSite } from '@classes/site'; import { CoreCourseModuleDefaultHandler } from './handlers/default-module'; import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate'; import { CoreCourseAnyCourseData } from '@features/courses/services/courses'; -import { CoreCourse, CoreCourseAnyModuleData, CoreCourseWSModule } from './course'; +import { CoreCourse, CoreCourseWSModule } from './course'; import { CoreSites } from '@services/sites'; import { makeSingleton } from '@singletons'; import { CoreCourseModule } from './course-helper'; diff --git a/src/core/features/grades/pages/course/course.html b/src/core/features/grades/pages/course/course.html index c4d8ee0fd..3883ca2d3 100644 --- a/src/core/features/grades/pages/course/course.html +++ b/src/core/features/grades/pages/course/course.html @@ -52,8 +52,11 @@ > - + + diff --git a/src/core/features/grades/pages/course/course.page.ts b/src/core/features/grades/pages/course/course.page.ts index ee13e8248..224d9369b 100644 --- a/src/core/features/grades/pages/course/course.page.ts +++ b/src/core/features/grades/pages/course/course.page.ts @@ -114,7 +114,7 @@ export class CoreGradesCoursePage implements AfterViewInit, OnDestroy { * Update the table of grades. */ private async fetchGrades(): Promise { - const table = await CoreGrades.getCourseGradesTable(this.grades.courseId!, this.grades.userId); + const table = await CoreGrades.getCourseGradesTable(this.grades.courseId, this.grades.userId); const formattedTable = await CoreGradesHelper.formatGradesTable(table); this.grades.setTable(formattedTable); @@ -192,7 +192,7 @@ class CoreGradesCourseManager extends CorePageItemsListManager { - await CoreGrades.logCourseGradesView(this.courseId!, this.userId!); + await CoreGrades.logCourseGradesView(this.courseId, this.userId); } /** diff --git a/src/core/features/grades/pages/course/course.scss b/src/core/features/grades/pages/course/course.scss index aca518a0f..2f0239c09 100644 --- a/src/core/features/grades/pages/course/course.scss +++ b/src/core/features/grades/pages/course/course.scss @@ -82,6 +82,11 @@ height: 16px; } + core-mod-icon { + --size: 16px; + } + + ion-icon { color: var(--icon-color); } @@ -119,6 +124,11 @@ background-color: var(--cell-hover); } } + + th, td { + height: var(--a11y-min-target-size); + vertical-align: middle; + } } } diff --git a/src/core/features/grades/pages/grade/grade.html b/src/core/features/grades/pages/grade/grade.html index 4b3198ee2..9abe2b1f3 100644 --- a/src/core/features/grades/pages/grade/grade.html +++ b/src/core/features/grades/pages/grade/grade.html @@ -17,8 +17,9 @@ - + + +

@@ -27,7 +28,9 @@ - + + +

diff --git a/src/core/features/tag/components/feed/core-tag-feed.html b/src/core/features/tag/components/feed/core-tag-feed.html index b0f626f67..1be13ee74 100644 --- a/src/core/features/tag/components/feed/core-tag-feed.html +++ b/src/core/features/tag/components/feed/core-tag-feed.html @@ -3,8 +3,8 @@ - + +

{{ item.heading }}

{{ text }}

diff --git a/src/theme/theme.base.scss b/src/theme/theme.base.scss index ef149d2ca..0253a989c 100644 --- a/src/theme/theme.base.scss +++ b/src/theme/theme.base.scss @@ -527,36 +527,10 @@ img[core-external-content]:not([src]) { visibility: hidden; } -// Activity modules -.core-module-icon { - --size: var(--module-icon-size); - width: var(--size); - height: var(--size); - max-width: var(--size); - max-height: var(--size); -} - -ion-item img.core-module-icon[slot="start"] { - margin-top: 12px; - margin-bottom: 12px; - margin-right: 32px; -} - -ion-card ion-item img.core-module-icon[slot="start"] { - margin-top: 12px; - margin-bottom: 12px; - margin-right: 12px; -} - ion-card ion-item:only-child { --inner-border-width: 0; } -[dir=rtl] ion-item img.core-module-icon[slot="start"] { - margin-right: unset; - margin-left: 32px; -} - .core-course-module-handler:not(.addon-mod-label-handler) .item-heading .filter_mathjaxloader_equation div { display: inline !important; } From eb34039be905990a008defe208a1eff0e8189e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Tue, 28 Sep 2021 12:17:17 +0200 Subject: [PATCH 4/4] MOBILE-2748 github: Ignore warnings during linter on testing --- .github/workflows/testing.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 5b10f13a3..6e5aed17e 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -51,8 +51,8 @@ jobs: echo "Found $found missing langkeys" exit 1 fi - - name: Run Linter - run: npm run lint + - name: Run Linter (ignore warnings) + run: npm run lint -- --quiet - name: Run tests run: npm run test:ci - name: Production builds