From 52e10ea15dad9239d6664fefa1278f99c489861c Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Tue, 15 Feb 2022 12:45:54 +0100 Subject: [PATCH] MOBILE-3980 book: Open book contents when clicking link --- .../assign/services/handlers/push-click.ts | 5 +- .../mod/book/services/handlers/index-link.ts | 29 ++++-- .../feedback/services/handlers/push-click.ts | 5 +- .../lesson/services/handlers/grade-link.ts | 6 +- .../lesson/services/handlers/index-link.ts | 16 +++- .../mod/quiz/services/handlers/push-click.ts | 5 +- .../classes/module-grade-handler.ts | 9 +- .../classes/module-index-handler.ts | 51 +++++++--- src/core/features/course/pages/index/index.ts | 18 +++- .../features/course/services/course-helper.ts | 96 +++++++++++-------- .../features/sitehome/pages/index/index.ts | 13 ++- upgrade.txt | 1 + 12 files changed, 178 insertions(+), 76 deletions(-) diff --git a/src/addons/mod/assign/services/handlers/push-click.ts b/src/addons/mod/assign/services/handlers/push-click.ts index 1973435e2..1b5714c8c 100644 --- a/src/addons/mod/assign/services/handlers/push-click.ts +++ b/src/addons/mod/assign/services/handlers/push-click.ts @@ -54,7 +54,10 @@ export class AddonModAssignPushClickHandlerService implements CorePushNotificati const moduleId = Number(contextUrlParams.id); await CoreUtils.ignoreErrors(AddonModAssign.invalidateContent(moduleId, courseId, notification.site)); - await CoreCourseHelper.navigateToModule(moduleId, notification.site, courseId); + await CoreCourseHelper.navigateToModule(moduleId, { + courseId, + siteId: notification.site, + }); } } diff --git a/src/addons/mod/book/services/handlers/index-link.ts b/src/addons/mod/book/services/handlers/index-link.ts index c0b5389ce..83015b7ef 100644 --- a/src/addons/mod/book/services/handlers/index-link.ts +++ b/src/addons/mod/book/services/handlers/index-link.ts @@ -15,6 +15,7 @@ import { Injectable } from '@angular/core'; import { Params } from '@angular/router'; import { CoreContentLinksModuleIndexHandler } from '@features/contentlinks/classes/module-index-handler'; +import { CoreNavigationOptions } from '@services/navigator'; import { makeSingleton } from '@singletons'; import { AddonModBook } from '../book'; @@ -31,20 +32,32 @@ export class AddonModBookIndexLinkHandlerService extends CoreContentLinksModuleI } /** - * Get the mod params necessary to open an activity. - * - * @param url The URL to treat. - * @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1} - * @return List of params to pass to navigateToModule / navigateToModuleByInstance. + * @inheritdoc + */ + getModNavOptions(url: string, params: Record): CoreNavigationOptions { + const chapterId = params.chapterid ? parseInt(params.chapterid, 10) : undefined; + + return { + nextNavigation: { + path: 'contents', + options: { + params: { + chapterId, + }, + }, + }, + }; + } + + /** + * @inheritdoc */ getPageParams(url: string, params: Record): Params { return params.chapterid ? { chapterId: parseInt(params.chapterid, 10) } : {}; } /** - * Check if the handler is enabled for a certain site (site + user) and a URL. - * - * @return Whether the handler is enabled for the URL and site. + * @inheritdoc */ isEnabled(siteId: string): Promise { return AddonModBook.isPluginEnabled(siteId); diff --git a/src/addons/mod/feedback/services/handlers/push-click.ts b/src/addons/mod/feedback/services/handlers/push-click.ts index e736768db..02ad4aedb 100644 --- a/src/addons/mod/feedback/services/handlers/push-click.ts +++ b/src/addons/mod/feedback/services/handlers/push-click.ts @@ -55,7 +55,10 @@ export class AddonModFeedbackPushClickHandlerService implements CorePushNotifica if (notification.name == 'submission') { return AddonModFeedbackHelper.handleShowEntriesLink(contextUrlParams, notification.site); } else { - return CoreCourseHelper.navigateToModule(moduleId, notification.site, courseId); + return CoreCourseHelper.navigateToModule(moduleId, { + courseId, + siteId: notification.site, + }); } } diff --git a/src/addons/mod/lesson/services/handlers/grade-link.ts b/src/addons/mod/lesson/services/handlers/grade-link.ts index bc16a1ef5..c1da1506d 100644 --- a/src/addons/mod/lesson/services/handlers/grade-link.ts +++ b/src/addons/mod/lesson/services/handlers/grade-link.ts @@ -76,7 +76,11 @@ export class AddonModLessonGradeLinkHandlerService extends CoreContentLinksModul ); } else { // User cannot view the report, go to lesson index. - CoreCourseHelper.navigateToModule(moduleId, siteId, module.course, module.section); + CoreCourseHelper.navigateToModule(moduleId, { + courseId: module.course, + sectionId: module.section, + siteId, + }); } } catch (error) { CoreDomUtils.showErrorModalDefault(error, 'core.course.errorgetmodule', true); diff --git a/src/addons/mod/lesson/services/handlers/index-link.ts b/src/addons/mod/lesson/services/handlers/index-link.ts index 21be65658..5c0f88f6a 100644 --- a/src/addons/mod/lesson/services/handlers/index-link.ts +++ b/src/addons/mod/lesson/services/handlers/index-link.ts @@ -61,7 +61,10 @@ export class AddonModLessonIndexLinkHandlerService extends CoreContentLinksModul if (params.userpassword) { this.navigateToModuleWithPassword(parseInt(params.id, 10), courseId!, params.userpassword, siteId); } else { - CoreCourseHelper.navigateToModule(parseInt(params.id, 10), siteId, courseId); + CoreCourseHelper.navigateToModule(parseInt(params.id, 10), { + courseId, + siteId, + }); } }, }]; @@ -94,10 +97,17 @@ export class AddonModLessonIndexLinkHandlerService extends CoreContentLinksModul // Store the password so it's automatically used. await CoreUtils.ignoreErrors(AddonModLesson.storePassword(module.instance, password, siteId)); - await CoreCourseHelper.navigateToModule(moduleId, siteId, module.course, module.section); + await CoreCourseHelper.navigateToModule(moduleId, { + courseId: module.course, + sectionId: module.section, + siteId, + }); } catch { // Error, go to index page. - await CoreCourseHelper.navigateToModule(moduleId, siteId, courseId); + await CoreCourseHelper.navigateToModule(moduleId, { + courseId, + siteId, + }); } finally { modal.dismiss(); } diff --git a/src/addons/mod/quiz/services/handlers/push-click.ts b/src/addons/mod/quiz/services/handlers/push-click.ts index 7144d7a03..05492395a 100644 --- a/src/addons/mod/quiz/services/handlers/push-click.ts +++ b/src/addons/mod/quiz/services/handlers/push-click.ts @@ -72,7 +72,10 @@ export class AddonModQuizPushClickHandlerService implements CorePushNotification await CoreUtils.ignoreErrors(AddonModQuiz.invalidateContent(moduleId, courseId, notification.site)); - return CoreCourseHelper.navigateToModule(moduleId, notification.site, courseId); + return CoreCourseHelper.navigateToModule(moduleId, { + courseId, + siteId: notification.site, + }); } } diff --git a/src/core/features/contentlinks/classes/module-grade-handler.ts b/src/core/features/contentlinks/classes/module-grade-handler.ts index 1b3b8f29b..cce3bad41 100644 --- a/src/core/features/contentlinks/classes/module-grade-handler.ts +++ b/src/core/features/contentlinks/classes/module-grade-handler.ts @@ -78,10 +78,11 @@ export class CoreContentLinksModuleGradeHandler extends CoreContentLinksHandlerB // No user specified or current user. Navigate to module. CoreCourseHelper.navigateToModule( Number(params.id), - siteId, - courseId, - undefined, - this.useModNameToGetModule ? this.modName : undefined, + { + courseId, + modName: this.useModNameToGetModule ? this.modName : undefined, + siteId, + }, ); } else if (this.canReview) { // Use the goToReview function. diff --git a/src/core/features/contentlinks/classes/module-index-handler.ts b/src/core/features/contentlinks/classes/module-index-handler.ts index 5efc4c83a..384d37155 100644 --- a/src/core/features/contentlinks/classes/module-index-handler.ts +++ b/src/core/features/contentlinks/classes/module-index-handler.ts @@ -16,6 +16,7 @@ import { CoreContentLinksHandlerBase } from './base-handler'; import { Params } from '@angular/router'; import { CoreContentLinksAction } from '../services/contentlinks-delegate'; import { CoreCourseHelper } from '@features/course/services/course-helper'; +import { CoreNavigationOptions } from '@services/navigator'; /** * Handler to handle URLs pointing to the index of a module. @@ -58,12 +59,27 @@ export class CoreContentLinksModuleIndexHandler extends CoreContentLinksHandlerB * @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1} * @param courseId Course ID related to the URL. Optional but recommended. * @return List of params to pass to navigateToModule / navigateToModuleByInstance. + * @deprecated since 4.0 */ // eslint-disable-next-line @typescript-eslint/no-unused-vars getPageParams(url: string, params: Record, courseId?: number): Params { return {}; } + /** + * Get the navigation options to open the module. + * + * @param url The URL to treat. + * @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1} + * @param siteId The site ID. + * @param courseId Course ID related to the URL. Optional but recommended. + * @return Navigation options to open the module. + */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + getModNavOptions(url: string, params: Record, siteId: string, courseId?: number): CoreNavigationOptions { + return {}; + } + /** * Get the list of actions for a link (url). * @@ -81,7 +97,18 @@ export class CoreContentLinksModuleIndexHandler extends CoreContentLinksHandlerB ): CoreContentLinksAction[] | Promise { courseId = Number(courseId || params.courseid || params.cid); - const pageParams = this.getPageParams(url, params, courseId); + const getModNavOptions = (siteId: string): CoreNavigationOptions => { + let modNavOptions = this.getModNavOptions(url, params, siteId, courseId); + if (!modNavOptions) { + // Use the old function, currently deprecated. + const pageParams = this.getPageParams(url, params, courseId); + if (pageParams && Object.keys(pageParams).length > 0) { + modNavOptions = { params: pageParams }; + } + } + + return modNavOptions; + }; if (this.instanceIdParam && params[this.instanceIdParam] !== undefined) { const instanceId = parseInt(params[this.instanceIdParam], 10); @@ -91,11 +118,12 @@ export class CoreContentLinksModuleIndexHandler extends CoreContentLinksHandlerB CoreCourseHelper.navigateToModuleByInstance( instanceId, this.modName, - siteId, - courseId, - undefined, - this.useModNameToGetModule, - pageParams, + { + courseId, + useModNameToGetModule: this.useModNameToGetModule, + modNavOptions: getModNavOptions(siteId), + siteId, + }, ); }, }]; @@ -105,11 +133,12 @@ export class CoreContentLinksModuleIndexHandler extends CoreContentLinksHandlerB action: (siteId) => { CoreCourseHelper.navigateToModule( parseInt(params.id, 10), - siteId, - courseId, - undefined, - this.useModNameToGetModule ? this.modName : undefined, - pageParams, + { + courseId, + modName: this.useModNameToGetModule ? this.modName : undefined, + modNavOptions: getModNavOptions(siteId), + siteId, + }, ); }, }]; diff --git a/src/core/features/course/pages/index/index.ts b/src/core/features/course/pages/index/index.ts index 449058e33..9991c008d 100644 --- a/src/core/features/course/pages/index/index.ts +++ b/src/core/features/course/pages/index/index.ts @@ -24,7 +24,7 @@ import { CoreCourse, CoreCourseModuleCompletionStatus, CoreCourseWSSection } fro import { CoreCourseHelper, CoreCourseModuleData } from '@features/course/services/course-helper'; import { CoreUtils } from '@services/utils/utils'; import { CoreTextUtils } from '@services/utils/text'; -import { CoreNavigator } from '@services/navigator'; +import { CoreNavigationOptions, CoreNavigator } from '@services/navigator'; import { CONTENTS_PAGE_NAME } from '@features/course/course.module'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreCollapsibleHeaderDirective } from '@directives/collapsible-header'; @@ -57,7 +57,7 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy { protected sections: CoreCourseWSSection[] = []; // List of course sections. protected firstTabName?: string; protected module?: CoreCourseModuleData; - protected modParams?: Params; + protected modNavOptions?: CoreNavigationOptions; protected isGuest = false; protected contentsTab: CoreTabsOutletTab & { pageParams: Params } = { page: CONTENTS_PAGE_NAME, @@ -136,8 +136,15 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy { this.firstTabName = CoreNavigator.getRouteParam('selectedTab'); this.module = CoreNavigator.getRouteParam('module'); - this.modParams = CoreNavigator.getRouteParam('modParams'); this.isGuest = !!CoreNavigator.getRouteBooleanParam('isGuest'); + this.modNavOptions = CoreNavigator.getRouteParam('modNavOptions'); + if (!this.modNavOptions) { + // Fallback to old way of passing params. @deprecated since 4.0. + const modParams = CoreNavigator.getRouteParam('modParams'); + if (modParams) { + this.modNavOptions = { params: modParams }; + } + } this.currentPagePath = CoreNavigator.getCurrentPath(); this.contentsTab.page = CoreTextUtils.concatenatePaths(this.currentPagePath, this.contentsTab.page); @@ -171,7 +178,10 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy { return; } // Now that the first tab has been selected we can load the module. - CoreCourseHelper.openModule(this.module, this.course.id, this.contentsTab.pageParams.sectionId, this.modParams); + CoreCourseHelper.openModule(this.module, this.course.id, { + sectionId: this.contentsTab.pageParams.sectionId, + modNavOptions: this.modNavOptions, + }); delete this.module; } diff --git a/src/core/features/course/services/course-helper.ts b/src/core/features/course/services/course-helper.ts index d0e16d0c2..93c8b0ca6 100644 --- a/src/core/features/course/services/course-helper.ts +++ b/src/core/features/course/services/course-helper.ts @@ -1573,36 +1573,27 @@ export class CoreCourseHelperProvider { * * @param instanceId Activity instance ID. * @param modName Module name of the activity. - * @param siteId Site ID. If not defined, current site. - * @param courseId Course ID. If not defined we'll try to retrieve it from the site. - * @param sectionId Section the module belongs to. If not defined we'll try to retrieve it from the site. - * @param useModNameToGetModule If true, the app will retrieve all modules of this type with a single WS call. This reduces the - * number of WS calls, but it isn't recommended for modules that can return a lot of contents. - * @param modParams Params to pass to the module + * @param options Other options. * @return Promise resolved when done. */ async navigateToModuleByInstance( instanceId: number, modName: string, - siteId?: string, - courseId?: number, - sectionId?: number, - useModNameToGetModule: boolean = false, - modParams?: Params, + options: CoreCourseNavigateToModuleByInstanceOptions = {}, ): Promise { const modal = await CoreDomUtils.showModalLoading(); try { - const module = await CoreCourse.getModuleBasicInfoByInstance(instanceId, modName, { siteId }); + const module = await CoreCourse.getModuleBasicInfoByInstance(instanceId, modName, { siteId: options.siteId }); this.navigateToModule( module.id, - siteId, - module.course, - sectionId, - useModNameToGetModule ? modName : undefined, - modParams, + { + ...options, + courseId: module.course, + modName: options.useModNameToGetModule ? modName : undefined, + }, ); } catch (error) { CoreDomUtils.showErrorModalDefault(error, 'core.course.errorgetmodule', true); @@ -1616,23 +1607,16 @@ export class CoreCourseHelperProvider { * Navigate to a module. * * @param moduleId Module's ID. - * @param siteId Site ID. If not defined, current site. - * @param courseId Course ID. If not defined we'll try to retrieve it from the site. - * @param sectionId Section the module belongs to. If not defined we'll try to retrieve it from the site. - * @param modName If set, the app will retrieve all modules of this type with a single WS call. This reduces the - * number of WS calls, but it isn't recommended for modules that can return a lot of contents. - * @param modParams Params to pass to the module + * @param options Other options. * @return Promise resolved when done. */ async navigateToModule( moduleId: number, - siteId?: string, - courseId?: number, - sectionId?: number, - modName?: string, - modParams?: Params, + options: CoreCourseNavigateToModuleOptions = {}, ): Promise { - siteId = siteId || CoreSites.getCurrentSiteId(); + const siteId = options.siteId || CoreSites.getCurrentSiteId(); + let courseId = options.courseId; + let sectionId = options.sectionId; const modal = await CoreDomUtils.showModalLoading(); @@ -1651,10 +1635,9 @@ export class CoreCourseHelperProvider { const site = await CoreSites.getSite(siteId); // Get the module. - const module = - await CoreCourse.getModule(moduleId, courseId, sectionId, false, false, siteId, modName); + const module = await CoreCourse.getModule(moduleId, courseId, sectionId, false, false, siteId, options.modName); - if (CoreSites.getCurrentSiteId() == site.getId()) { + if (CoreSites.getCurrentSiteId() === site.getId()) { // Try to use the module's handler to navigate cleanly. module.handlerData = await CoreCourseModuleDelegate.getModuleDataFor( module.modname, @@ -1667,7 +1650,7 @@ export class CoreCourseHelperProvider { if (module.handlerData?.action) { modal.dismiss(); - return module.handlerData.action(new Event('click'), module, courseId, { params: modParams }); + return module.handlerData.action(new Event('click'), module, courseId, options.modNavOptions); } } @@ -1675,7 +1658,7 @@ export class CoreCourseHelperProvider { course: { id: courseId }, module, sectionId, - modParams, + modNavOptions: options.modNavOptions, }; if (courseId == site.getSiteHomeId()) { @@ -1704,23 +1687,25 @@ export class CoreCourseHelperProvider { * * @param module The module to open. * @param courseId The course ID of the module. - * @param sectionId The section ID of the module. - * @param modParams Params to pass to the module + * @param options Other options. * @param True if module can be opened, false otherwise. */ - async openModule(module: CoreCourseModuleData, courseId: number, sectionId?: number, modParams?: Params): Promise { + async openModule(module: CoreCourseModuleData, courseId: number, options: CoreCourseOpenModuleOptions = {}): Promise { if (!module.handlerData) { module.handlerData = await CoreCourseModuleDelegate.getModuleDataFor( module.modname, module, courseId, - sectionId, + options.sectionId, false, ); } if (module.handlerData?.action) { - module.handlerData.action(new Event('click'), module, courseId, { animated: false, params: modParams }); + module.handlerData.action(new Event('click'), module, courseId, { + animated: false, + ...options.modNavOptions, + }); return true; } @@ -2206,6 +2191,39 @@ export type CoreCourseConfirmPrefetchCoursesOptions = CoreCoursePrefetchCoursesO onProgress?: (data: CoreCourseCoursesProgress) => void; }; +/** + * Common options for navigate to module functions. + */ +type CoreCourseNavigateToModuleCommonOptions = { + courseId?: number; // Course ID. If not defined we'll try to retrieve it from the site. + sectionId?: number; // Section the module belongs to. If not defined we'll try to retrieve it from the site. + modNavOptions?: CoreNavigationOptions; // Navigation options to open the module, including params to pass to the module. + siteId?: string; // Site ID. If not defined, current site. +}; + +/** + * Options for navigate to module by instance function. + */ +export type CoreCourseNavigateToModuleByInstanceOptions = CoreCourseNavigateToModuleCommonOptions & { + // True to retrieve all instances with a single WS call. Not recommended if can return a lot of contents. + useModNameToGetModule?: boolean; +}; + +/** + * Options for navigate to module function. + */ +export type CoreCourseNavigateToModuleOptions = CoreCourseNavigateToModuleCommonOptions & { + modName?: string; // To retrieve all instances with a single WS call. Not recommended if can return a lot of contents. +}; + +/** + * Options for open module function. + */ +export type CoreCourseOpenModuleOptions = { + sectionId?: number; // Section the module belongs to. + modNavOptions?: CoreNavigationOptions; // Navigation options to open the module, including params to pass to the module. +}; + type ComponentWithContextMenu = { prefetchStatusIcon?: string; isDestroyed?: boolean; diff --git a/src/core/features/sitehome/pages/index/index.ts b/src/core/features/sitehome/pages/index/index.ts index b58998e07..087589a5d 100644 --- a/src/core/features/sitehome/pages/index/index.ts +++ b/src/core/features/sitehome/pages/index/index.ts @@ -26,7 +26,7 @@ import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreCourseHelper, CoreCourseModuleData } from '@features/course/services/course-helper'; import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate'; import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate'; -import { CoreNavigator } from '@services/navigator'; +import { CoreNavigationOptions, CoreNavigator } from '@services/navigator'; import { CoreBlockHelper } from '@features/block/services/block-helper'; import { CoreUtils } from '@services/utils/utils'; @@ -73,8 +73,15 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy { const module = CoreNavigator.getRouteParam('module'); if (module) { - const modParams = CoreNavigator.getRouteParam('modParams'); - CoreCourseHelper.openModule(module, this.siteHomeId, undefined, modParams); + let modNavOptions = CoreNavigator.getRouteParam('modNavOptions'); + if (!modNavOptions) { + // Fallback to old way of passing params. @deprecated since 4.0. + const modParams = CoreNavigator.getRouteParam('modParams'); + if (modParams) { + modNavOptions = { params: modParams }; + } + } + CoreCourseHelper.openModule(module, this.siteHomeId, { modNavOptions }); } this.loadContent().finally(() => { diff --git a/upgrade.txt b/upgrade.txt index e943d0f93..4755f12ea 100644 --- a/upgrade.txt +++ b/upgrade.txt @@ -19,6 +19,7 @@ information provided here is intended especially for developers. - displaySectionSelector has been deprecated on CoreCourseFormatHandler, use displayCourseIndex instead. - Most of the functions or callbacks that handle redirects/deeplinks have been modified to accept an object instead of just path + options. E.g.: CoreLoginHelper.isSiteLoggedOut, CoreLoginHelper.openBrowserForSSOLogin, CoreLoginHelper.openBrowserForOAuthLogin, CoreLoginHelper.prepareForSSOLogin, CoreApp.storeRedirect, CoreSites.loadSite. - Course preview page route has changed from course/:courseId/preview to course/:courseId/summary to match with the page name and characteristics. +- The parameters of the following functions in CoreCourseHelper have changed: navigateToModuleByInstance, navigateToModule, openModule. === 3.9.5 ===