diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 61b44dd53..937bc5166 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -26,7 +26,6 @@ import { } from '@angular/router'; import { CoreArray } from '@singletons/array'; -import { CoreRedirectGuard } from '@guards/redirect'; /** * Build app routes. @@ -35,16 +34,7 @@ import { CoreRedirectGuard } from '@guards/redirect'; * @return App routes. */ function buildAppRoutes(injector: Injector): Routes { - const appRoutes = CoreArray.flatten(injector.get(APP_ROUTES, [])); - - return appRoutes.map(route => { - route.canLoad = route.canLoad ?? []; - route.canActivate = route.canActivate ?? []; - route.canLoad.push(CoreRedirectGuard); - route.canActivate.push(CoreRedirectGuard); - - return route; - }); + return CoreArray.flatten(injector.get(APP_ROUTES, [])); } /** diff --git a/src/core/features/contentlinks/services/contentlinks-helper.ts b/src/core/features/contentlinks/services/contentlinks-helper.ts index 6e7d52cfd..306ac53d5 100644 --- a/src/core/features/contentlinks/services/contentlinks-helper.ts +++ b/src/core/features/contentlinks/services/contentlinks-helper.ts @@ -56,7 +56,7 @@ export class CoreContentLinksHelperProvider { } /** - * Get the first valid action in the list of possible actions to do for a URL. + * Get the first valid action for a URL. * * @param url URL to handle. * @param courseId Course ID related to the URL. Optional but recommended. @@ -75,6 +75,16 @@ export class CoreContentLinksHelperProvider { return; } + return this.getFirstValidAction(actions); + } + + /** + * Get the first valid action in a list of possible actions. + * + * @param actions Actions. + * @return First valid action if any. + */ + getFirstValidAction(actions: CoreContentLinksAction[]): CoreContentLinksAction | undefined { return actions.find((action) => action && action.sites && action.sites.length); } diff --git a/src/core/features/course/components/format/format.ts b/src/core/features/course/components/format/format.ts index 5fb0b0c53..2187defbd 100644 --- a/src/core/features/course/components/format/format.ts +++ b/src/core/features/course/components/format/format.ts @@ -311,11 +311,8 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy { this.sectionChanged(sections[0]); } else if (this.initialSectionId || this.initialSectionNumber) { // We have an input indicating the section ID to load. Search the section. - const section = sections.find((section) => { - if (section.id != this.initialSectionId && (!section.section || section.section != this.initialSectionNumber)) { - return false; - } - }); + const section = sections.find((section) => + section.id == this.initialSectionId || (section.section && section.section == this.initialSectionNumber)); // Don't load the section if it cannot be viewed by the user. if (section && this.canViewSection(section)) { diff --git a/src/core/features/course/pages/index/index.html b/src/core/features/course/pages/index/index.html index f436abd88..18d3d7dda 100644 --- a/src/core/features/course/pages/index/index.html +++ b/src/core/features/course/pages/index/index.html @@ -11,5 +11,5 @@ - + diff --git a/src/core/features/course/pages/index/index.page.ts b/src/core/features/course/pages/index/index.page.ts index 8629eb6a6..6ba057186 100644 --- a/src/core/features/course/pages/index/index.page.ts +++ b/src/core/features/course/pages/index/index.page.ts @@ -46,6 +46,8 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy { protected currentPagePath = ''; protected selectTabObserver: CoreEventObserver; protected firstTabName?: string; + protected module?: CoreCourseWSModule; + protected modParams?: Params; protected contentsTab: CoreTabsOutletTab = { page: CONTENTS_PAGE_NAME, title: 'core.course.contents', @@ -82,8 +84,8 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy { // Get params. this.course = CoreNavigator.getRouteParam('course'); this.firstTabName = CoreNavigator.getRouteParam('selectedTab'); - const module = CoreNavigator.getRouteParam('module'); - const modParams = CoreNavigator.getRouteParam('modParams'); + this.module = CoreNavigator.getRouteParam('module'); + this.modParams = CoreNavigator.getRouteParam('modParams'); this.currentPagePath = CoreNavigator.getCurrentPath(); this.contentsTab.page = CoreTextUtils.concatenatePaths(this.currentPagePath, this.contentsTab.page); @@ -93,9 +95,8 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy { sectionNumber: CoreNavigator.getRouteNumberParam('sectionNumber'), }; - if (module) { - this.contentsTab.pageParams!.moduleId = module.id; - CoreCourseHelper.openModule(module, this.course!.id, this.contentsTab.pageParams!.sectionId, modParams); + if (this.module) { + this.contentsTab.pageParams!.moduleId = this.module.id; } this.tabs.push(this.contentsTab); @@ -107,6 +108,18 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy { ]); } + /** + * A tab was selected. + */ + tabSelected(): void { + if (this.module) { + // 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); + + delete this.module; + } + } + /** * Load course option handlers. * diff --git a/src/core/features/login/login.module.ts b/src/core/features/login/login.module.ts index 8525d25b7..75a8e77c7 100644 --- a/src/core/features/login/login.module.ts +++ b/src/core/features/login/login.module.ts @@ -17,6 +17,7 @@ import { Routes } from '@angular/router'; import { AppRoutingModule } from '@/app/app-routing.module'; import { CoreLoginHelperProvider } from './services/login-helper'; +import { CoreRedirectGuard } from '@guards/redirect'; export const CORE_LOGIN_SERVICES = [ CoreLoginHelperProvider, @@ -26,6 +27,8 @@ const appRoutes: Routes = [ { path: 'login', loadChildren: () => import('./login-lazy.module').then(m => m.CoreLoginLazyModule), + canActivate: [CoreRedirectGuard], + canLoad: [CoreRedirectGuard], }, ]; diff --git a/src/core/features/mainmenu/pages/home/home.html b/src/core/features/mainmenu/pages/home/home.html index 0605add72..1430ba018 100644 --- a/src/core/features/mainmenu/pages/home/home.html +++ b/src/core/features/mainmenu/pages/home/home.html @@ -14,7 +14,8 @@ - + diff --git a/src/core/features/mainmenu/pages/home/home.ts b/src/core/features/mainmenu/pages/home/home.ts index 0b1707bf3..50fe9f604 100644 --- a/src/core/features/mainmenu/pages/home/home.ts +++ b/src/core/features/mainmenu/pages/home/home.ts @@ -20,6 +20,12 @@ import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreTabsOutletComponent, CoreTabsOutletTab } from '@components/tabs-outlet/tabs-outlet'; import { CoreMainMenuHomeDelegate, CoreMainMenuHomeHandlerToDisplay } from '../../services/home-delegate'; import { CoreUtils } from '@services/utils/utils'; +import { ActivatedRoute } from '@angular/router'; +import { CoreNavigator, CoreRedirectPayload } from '@services/navigator'; +import { CoreCourseHelper } from '@features/course/services/course-helper'; +import { CoreCourse } from '@features/course/services/course'; +import { CoreContentLinksDelegate } from '@features/contentlinks/services/contentlinks-delegate'; +import { CoreContentLinksHelper } from '@features/contentlinks/services/contentlinks-helper'; /** * Page that displays the Home. @@ -40,11 +46,29 @@ export class CoreMainMenuHomePage implements OnInit { protected subscription?: Subscription; protected updateSiteObserver?: CoreEventObserver; + protected pendingRedirect?: CoreRedirectPayload; + protected urlToOpen?: string; + + constructor( + protected route: ActivatedRoute, + ) { + } /** * Initialize the component. */ ngOnInit(): void { + this.route.queryParams.subscribe((params: Partial & { urlToOpen?: string }) => { + this.urlToOpen = params.urlToOpen; + + if (params.redirectPath) { + this.pendingRedirect = { + redirectPath: params.redirectPath, + redirectParams: params.redirectParams, + }; + } + }); + this.loadSiteName(); this.subscription = CoreMainMenuHomeDelegate.getHandlersObservable().subscribe((handlers) => { @@ -111,6 +135,57 @@ export class CoreMainMenuHomePage implements OnInit { this.siteName = CoreSites.getCurrentSite()!.getSiteName(); } + /** + * Handle a redirect. + * + * @param data Data received. + */ + protected handleRedirect(data: CoreRedirectPayload): void { + const params = data.redirectParams; + const coursePathMatches = data.redirectPath.match(/^course\/(\d+)\/?$/); + + if (coursePathMatches) { + if (!params?.course) { + CoreCourseHelper.getAndOpenCourse(Number(coursePathMatches[1]), params); + } else { + CoreCourse.openCourse(params.course, params); + } + } else { + CoreNavigator.navigateToSitePath(data.redirectPath, { + params: data.redirectParams, + preferCurrentTab: false, + }); + } + } + + /** + * Handle a URL to open. + * + * @param url URL to open. + */ + protected async handleUrlToOpen(url: string): Promise { + const actions = await CoreContentLinksDelegate.getActionsFor(url, undefined); + + const action = CoreContentLinksHelper.getFirstValidAction(actions); + if (action) { + action.action(action.sites![0]); + } + } + + /** + * Tab was selected. + */ + tabSelected(): void { + if (this.pendingRedirect) { + this.handleRedirect(this.pendingRedirect); + } else if (this.urlToOpen) { + this.handleUrlToOpen(this.urlToOpen); + } + + delete this.pendingRedirect; + delete this.urlToOpen; + } + /** * User entered the page. */ diff --git a/src/core/features/mainmenu/pages/menu/menu.ts b/src/core/features/mainmenu/pages/menu/menu.ts index 9dd61a115..3d2005371 100644 --- a/src/core/features/mainmenu/pages/menu/menu.ts +++ b/src/core/features/mainmenu/pages/menu/menu.ts @@ -19,14 +19,12 @@ import { BackButtonEvent } from '@ionic/core'; import { Subscription } from 'rxjs'; import { CoreApp } from '@services/app'; -import { CoreSites } from '@services/sites'; import { CoreTextUtils } from '@services/utils/text'; import { CoreEvents, CoreEventObserver } from '@singletons/events'; import { CoreMainMenu, CoreMainMenuProvider } from '../../services/mainmenu'; import { CoreMainMenuDelegate, CoreMainMenuHandlerToDisplay } from '../../services/mainmenu-delegate'; import { CoreDomUtils } from '@services/utils/dom'; import { Translate } from '@singletons'; -import { CoreNavigator, CoreRedirectPayload } from '@services/navigator'; /** * Page that displays the main menu of the app. @@ -47,9 +45,6 @@ export class CoreMainMenuPage implements OnInit, OnDestroy { morePageName = CoreMainMenuProvider.MORE_PAGE_NAME; protected subscription?: Subscription; - protected redirectObs?: CoreEventObserver; - protected pendingRedirect?: CoreRedirectPayload; - protected urlToOpen?: string; protected keyboardObserver?: CoreEventObserver; protected resizeFunction: () => void; protected backButtonFunction: (event: BackButtonEvent) => void; @@ -72,24 +67,6 @@ export class CoreMainMenuPage implements OnInit, OnDestroy { * Initialize the component. */ ngOnInit(): void { - // @TODO this should be handled by route guards and can be removed - if (!CoreSites.isLoggedIn()) { - CoreNavigator.navigate('/login/init', { reset: true }); - - return; - } - - this.route.queryParams.subscribe((params: Partial & { urlToOpen?: string }) => { - if (params.redirectPath) { - this.pendingRedirect = { - redirectPath: params.redirectPath, - redirectParams: params.redirectParams, - }; - } - - this.urlToOpen = params.urlToOpen; - }); - this.showTabs = true; this.subscription = CoreMainMenuDelegate.getHandlersObservable().subscribe((handlers) => { @@ -97,16 +74,6 @@ export class CoreMainMenuPage implements OnInit, OnDestroy { this.allHandlers = handlers.filter((handler) => !handler.onlyInMore); this.initHandlers(); - - if (this.loaded && this.pendingRedirect) { - // Wait for tabs to be initialized and then handle the redirect. - setTimeout(() => { - if (this.pendingRedirect) { - this.handleRedirect(this.pendingRedirect); - delete this.pendingRedirect; - } - }); - } }); window.addEventListener('resize', this.resizeFunction); @@ -158,18 +125,6 @@ export class CoreMainMenuPage implements OnInit, OnDestroy { this.tabs.sort((a, b) => (b.priority || 0) - (a.priority || 0)); this.loaded = CoreMainMenuDelegate.areHandlersLoaded(); - - if (this.loaded && this.mainTabs && !this.mainTabs.getSelected()) { - // Select the first tab. - setTimeout(() => { - this.mainTabs!.select(this.tabs[0]?.page || this.morePageName); - }); - } - } - - if (this.urlToOpen) { - // There's a content link to open. - // @todo: Treat URL. } } @@ -189,36 +144,11 @@ export class CoreMainMenuPage implements OnInit, OnDestroy { } } - /** - * Handle a redirect. - * - * @param data Data received. - */ - protected handleRedirect(data: CoreRedirectPayload): void { - // Check if the redirect page is the root page of any of the tabs. - const i = this.tabs.findIndex((tab) => tab.page == data.redirectPath); - - if (i >= 0) { - // Tab found. Open it with the params. - CoreNavigator.navigate(data.redirectPath, { - params: data.redirectParams, - animated: false, - }); - } else { - // Tab not found, use a phantom tab. - // @todo - } - - // Force change detection, otherwise sometimes the tab was selected before the params were applied. - this.changeDetector.detectChanges(); - } - /** * Page destroyed. */ ngOnDestroy(): void { this.subscription?.unsubscribe(); - this.redirectObs?.off(); window.removeEventListener('resize', this.resizeFunction); document.removeEventListener('ionBackButton', this.backButtonFunction); this.keyboardObserver?.off(); diff --git a/src/core/guards/redirect.ts b/src/core/guards/redirect.ts index dad98c2fd..0f3fb750a 100644 --- a/src/core/guards/redirect.ts +++ b/src/core/guards/redirect.ts @@ -40,52 +40,48 @@ export class CoreRedirectGuard implements CanLoad, CanActivate { * Check if there is a pending redirect and trigger it. */ private async guard(): Promise { - const redirect = CoreApp.getRedirect(); + const redirect = CoreApp.consumeRedirect(); if (!redirect) { return true; } - try { - // Only accept the redirect if it was stored less than 20 seconds ago. - if (!redirect.timemodified || Date.now() - redirect.timemodified < 20000) { - return true; - } + // Only accept the redirect if it was stored less than 20 seconds ago. + if (!redirect.timemodified || Date.now() - redirect.timemodified > 20000) { + return true; + } - // Redirect to site path. - if (redirect.siteId && redirect.siteId !== CoreConstants.NO_SITE_ID) { - const loggedIn = await CoreSites.loadSite( - redirect.siteId, - redirect.page, - redirect.params, - ); - const route = Router.parseUrl('/main'); - - route.queryParams = { - redirectPath: redirect.page, - redirectParams: redirect.params, - }; - - return loggedIn ? route : true; - } - - // Abort redirect. - if (!redirect.page) { - return true; - } - - // Redirect to non-site path. - const route = Router.parseUrl(redirect.page); + // Redirect to site path. + if (redirect.siteId && redirect.siteId !== CoreConstants.NO_SITE_ID) { + const loggedIn = await CoreSites.loadSite( + redirect.siteId, + redirect.page, + redirect.params, + ); + const route = Router.parseUrl('/main/home'); route.queryParams = { redirectPath: redirect.page, redirectParams: redirect.params, }; - return route; - } finally { - CoreApp.forgetRedirect(); + return loggedIn ? route : true; } + + // Abort redirect. + if (!redirect.page) { + return true; + } + + // Redirect to non-site path. + const route = Router.parseUrl(redirect.page); + + route.queryParams = { + redirectPath: redirect.page, + redirectParams: redirect.params, + }; + + return route; } } diff --git a/src/core/services/app.ts b/src/core/services/app.ts index 3859c2236..7a5365563 100644 --- a/src/core/services/app.ts +++ b/src/core/services/app.ts @@ -549,6 +549,19 @@ export class CoreAppProvider { } } + /** + * Retrieve and forget redirect data. + * + * @return Redirect data if any. + */ + consumeRedirect(): CoreRedirectData | null { + const redirect = this.getRedirect(); + + this.forgetRedirect(); + + return redirect; + } + /** * Forget redirect data. */ @@ -559,7 +572,7 @@ export class CoreAppProvider { /** * Retrieve redirect data. * - * @return Object with siteid, state, params and timemodified. + * @return Redirect data if any. */ getRedirect(): CoreRedirectData | null { return this.redirect || null; diff --git a/src/core/services/navigator.ts b/src/core/services/navigator.ts index ab361fcfa..e1c23827f 100644 --- a/src/core/services/navigator.ts +++ b/src/core/services/navigator.ts @@ -30,6 +30,7 @@ import { makeSingleton, NavController, Router } from '@singletons'; import { CoreScreen } from './screen'; import { filter } from 'rxjs/operators'; import { CoreApp } from './app'; +import { CoreSitePlugins } from '@features/siteplugins/services/siteplugins'; const DEFAULT_MAIN_MENU_TAB = CoreMainMenuHomeHandlerService.PAGE_NAME; @@ -208,7 +209,14 @@ export class CoreNavigatorService { // If we are logged into a different site, log out first. if (CoreSites.isLoggedIn() && CoreSites.getCurrentSiteId() !== siteId) { - // @todo: Check site plugins and store redirect. + if (CoreSitePlugins.hasSitePluginsLoaded) { + // The site has site plugins so the app will be restarted. Store the data and logout. + CoreApp.instance.storeRedirect(siteId, path, options.params || {}); + + await CoreSites.logout(); + + return true; + } await CoreSites.logout(); }