diff --git a/src/app/app.component.html b/src/app/app.component.html index 94c506c21..9b06aaff5 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,5 +1,3 @@ - - diff --git a/src/core/classes/tabs.ts b/src/core/classes/tabs.ts index 041f192de..f48fae07b 100644 --- a/src/core/classes/tabs.ts +++ b/src/core/classes/tabs.ts @@ -520,12 +520,12 @@ export class CoreTabsBaseComponent implements OnInit, Aft * @return Promise resolved when done. */ async selectByIndex(index: number, e?: Event): Promise { + e?.preventDefault(); + e?.stopPropagation(); + if (index < 0 || index >= this.tabs.length) { if (this.selected) { // Invalid index do not change tab. - e?.preventDefault(); - e?.stopPropagation(); - return; } @@ -536,9 +536,6 @@ export class CoreTabsBaseComponent implements OnInit, Aft const tabToSelect = this.tabs[index]; if (!tabToSelect || !tabToSelect.enabled || tabToSelect.id == this.selected) { // Already selected or not enabled. - e?.preventDefault(); - e?.stopPropagation(); - return; } diff --git a/src/core/components/split-view/split-view.ts b/src/core/components/split-view/split-view.ts index 101719d7d..75868e2d1 100644 --- a/src/core/components/split-view/split-view.ts +++ b/src/core/components/split-view/split-view.ts @@ -18,7 +18,7 @@ import { IonRouterOutlet } from '@ionic/angular'; import { CoreScreen } from '@services/screen'; import { BehaviorSubject, Observable, Subscription } from 'rxjs'; -enum CoreSplitViewMode { +export enum CoreSplitViewMode { MenuOnly = 'menu-only', // Hides content. ContentOnly = 'content-only', // Hides menu. MenuAndContent = 'menu-and-content', // Shows both menu and content. @@ -34,6 +34,7 @@ export class CoreSplitViewComponent implements AfterViewInit, OnDestroy { @ViewChild(IonRouterOutlet) outlet!: IonRouterOutlet; @HostBinding('class') classes = ''; @Input() placeholderText = 'core.emptysplit'; + @Input() mode?: CoreSplitViewMode; isNested = false; private outletRouteSubject: BehaviorSubject = new BehaviorSubject(null); @@ -100,6 +101,10 @@ export class CoreSplitViewComponent implements AfterViewInit, OnDestroy { * @return Split view mode. */ private getCurrentMode(): CoreSplitViewMode { + if (this.mode) { + return this.mode; + } + if (this.isNested) { return CoreSplitViewMode.MenuOnly; } diff --git a/src/core/components/tabs-outlet/tabs-outlet.ts b/src/core/components/tabs-outlet/tabs-outlet.ts index d4df2c488..7567f4619 100644 --- a/src/core/components/tabs-outlet/tabs-outlet.ts +++ b/src/core/components/tabs-outlet/tabs-outlet.ts @@ -43,8 +43,8 @@ import { CoreTabBase, CoreTabsBaseComponent } from '@classes/tabs'; * * Tab contents will only be shown if that tab is selected. * - * @todo: Test behaviour when tabs are added late. * @todo: Test RTL and tab history. + * @todo: This should behave like the split-view in relation to routing (maybe we could reuse some code from CoreItemsListManager). */ @Component({ selector: 'core-tabs-outlet', diff --git a/src/core/features/course/pages/index/index.ts b/src/core/features/course/pages/index/index.ts index 9c5b834e4..3723a5360 100644 --- a/src/core/features/course/pages/index/index.ts +++ b/src/core/features/course/pages/index/index.ts @@ -115,7 +115,7 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy { // Load the course handlers. const handlers = await CoreCourseOptionsDelegate.instance.getHandlersToDisplay(this.course!, false, false); - this.tabs.concat(handlers.map(handler => handler.data)); + this.tabs = [...this.tabs, ...handlers.map(handler => handler.data)]; let tabToLoad: number | undefined; diff --git a/src/core/features/grades/grades-course-lazy.module.ts b/src/core/features/grades/grades-course-lazy.module.ts new file mode 100644 index 000000000..e6164e920 --- /dev/null +++ b/src/core/features/grades/grades-course-lazy.module.ts @@ -0,0 +1,38 @@ +// (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 { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { CoreGradesCoursePage } from './pages/course/course.page'; +import { CoreGradesCoursePageModule } from './pages/course/course.module'; + +const routes: Routes = [ + { + path: '', + component: CoreGradesCoursePage, + data: { + useSplitView: false, + outsideGradesTab: true, + }, + }, +]; + +@NgModule({ + imports: [ + RouterModule.forChild(routes), + CoreGradesCoursePageModule, + ], +}) +export class CoreGradesCourseLazyModule {} diff --git a/src/core/features/grades/grades-lazy.module.ts b/src/core/features/grades/grades-lazy.module.ts index 5b22bbb13..5a4ac60e5 100644 --- a/src/core/features/grades/grades-lazy.module.ts +++ b/src/core/features/grades/grades-lazy.module.ts @@ -18,13 +18,14 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { TranslateModule } from '@ngx-translate/core'; -import { CoreSharedModule } from '@/core/shared.module'; +import { conditionalRoutes } from '@/app/app-routing.module'; import { CoreScreen } from '@services/screen'; +import { CoreSharedModule } from '@/core/shared.module'; -import { CoreGradesCoursePage } from './pages/course/course'; +import { CoreGradesCoursePage } from './pages/course/course.page'; +import { CoreGradesCoursePageModule } from './pages/course/course.module'; import { CoreGradesCoursesPage } from './pages/courses/courses'; import { CoreGradesGradePage } from './pages/grade/grade'; -import { conditionalRoutes } from '@/app/app-routing.module'; const mobileRoutes: Routes = [ { @@ -76,10 +77,10 @@ const routes: Routes = [ IonicModule, TranslateModule.forChild(), CoreSharedModule, + CoreGradesCoursePageModule, ], declarations: [ CoreGradesCoursesPage, - CoreGradesCoursePage, CoreGradesGradePage, ], }) diff --git a/src/core/features/grades/grades.module.ts b/src/core/features/grades/grades.module.ts index 94ea4f04d..eea8feb79 100644 --- a/src/core/features/grades/grades.module.ts +++ b/src/core/features/grades/grades.module.ts @@ -15,6 +15,7 @@ import { APP_INITIALIZER, NgModule } from '@angular/core'; import { Routes } from '@angular/router'; import { CoreContentLinksDelegate } from '@features/contentlinks/services/contentlinks-delegate'; +import { CoreCourseIndexRoutingModule } from '@features/course/pages/index/index-routing.module'; import { CoreCourseOptionsDelegate } from '@features/course/services/course-options-delegate'; import { CoreMainMenuRoutingModule } from '@features/mainmenu/mainmenu-routing.module'; import { CoreMainMenuTabRoutingModule } from '@features/mainmenu/mainmenu-tab-routing.module'; @@ -33,10 +34,18 @@ const routes: Routes = [ }, ]; +const courseIndexRoutes: Routes = [ + { + path: 'grades', + loadChildren: () => import('@features/grades/grades-course-lazy.module').then(m => m.CoreGradesCourseLazyModule), + }, +]; + @NgModule({ imports: [ CoreMainMenuTabRoutingModule.forChild(routes), CoreMainMenuRoutingModule.forChild({ children: routes }), + CoreCourseIndexRoutingModule.forChild({ children: courseIndexRoutes }), ], providers: [ { diff --git a/src/core/features/grades/pages/course/course.html b/src/core/features/grades/pages/course/course.html index f732a8470..579fffc6d 100644 --- a/src/core/features/grades/pages/course/course.html +++ b/src/core/features/grades/pages/course/course.html @@ -7,7 +7,7 @@ - + diff --git a/src/core/features/grades/pages/course/course.module.ts b/src/core/features/grades/pages/course/course.module.ts new file mode 100644 index 000000000..d098cd9c8 --- /dev/null +++ b/src/core/features/grades/pages/course/course.module.ts @@ -0,0 +1,35 @@ +// (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 { CommonModule } from '@angular/common'; +import { IonicModule } from '@ionic/angular'; +import { NgModule } from '@angular/core'; +import { TranslateModule } from '@ngx-translate/core'; + +import { CoreSharedModule } from '@/core/shared.module'; + +import { CoreGradesCoursePage } from './course.page'; + +@NgModule({ + imports: [ + CommonModule, + IonicModule, + TranslateModule.forChild(), + CoreSharedModule, + ], + declarations: [ + CoreGradesCoursePage, + ], +}) +export class CoreGradesCoursePageModule {} diff --git a/src/core/features/grades/pages/course/course.ts b/src/core/features/grades/pages/course/course.page.ts similarity index 84% rename from src/core/features/grades/pages/course/course.ts rename to src/core/features/grades/pages/course/course.page.ts index ae9367d28..b0cb64d33 100644 --- a/src/core/features/grades/pages/course/course.ts +++ b/src/core/features/grades/pages/course/course.page.ts @@ -27,9 +27,10 @@ import { } from '@features/grades/services/grades-helper'; import { CoreSites } from '@services/sites'; import { CoreUtils } from '@services/utils/utils'; -import { CoreSplitViewComponent } from '@components/split-view/split-view'; +import { CoreSplitViewComponent, CoreSplitViewMode } from '@components/split-view/split-view'; import { CoreObject } from '@singletons/object'; import { CorePageItemsListManager } from '@classes/page-items-list-manager'; +import { CoreNavigator } from '@services/navigator'; /** * Page that displays a course grades. @@ -42,14 +43,18 @@ import { CorePageItemsListManager } from '@classes/page-items-list-manager'; export class CoreGradesCoursePage implements AfterViewInit, OnDestroy { grades: CoreGradesCourseManager; + splitViewMode?: CoreSplitViewMode; @ViewChild(CoreSplitViewComponent) splitView!: CoreSplitViewComponent; constructor(route: ActivatedRoute) { - const courseId = parseInt(route.snapshot.params.courseId); + const courseId = parseInt(route.snapshot.params.courseId ?? route.snapshot.queryParams.courseId); const userId = parseInt(route.snapshot.queryParams.userId ?? CoreSites.instance.getCurrentSiteUserId()); + const useSplitView = route.snapshot.data.useSplitView ?? true; + const outsideGradesTab = route.snapshot.data.outsideGradesTab ?? false; - this.grades = new CoreGradesCourseManager(CoreGradesCoursePage, courseId, userId); + this.splitViewMode = useSplitView ? undefined : CoreSplitViewMode.MenuOnly; + this.grades = new CoreGradesCourseManager(CoreGradesCoursePage, courseId, userId, outsideGradesTab); } /** @@ -118,11 +123,14 @@ class CoreGradesCourseManager extends CorePageItemsListManager { + if (this.outsideGradesTab) { + await CoreNavigator.instance.navigateToSitePath(`/grades/${this.courseId}/${row.id}`); + + return; + } + + return super.select(row); + } + /** * @inheritdoc */ diff --git a/src/core/features/grades/services/handlers/course-option.ts b/src/core/features/grades/services/handlers/course-option.ts index 9dcb7cb61..dae804c8a 100644 --- a/src/core/features/grades/services/handlers/course-option.ts +++ b/src/core/features/grades/services/handlers/course-option.ts @@ -83,19 +83,14 @@ export class CoreGradesCourseOptionHandlerService implements CoreCourseOptionsHa } /** - * Returns the data needed to render the handler. - * - * @return Data or promise resolved with the data. + * @inheritdoc */ getDisplayData(): CoreCourseOptionsHandlerData | Promise { - throw new Error('CoreGradesCourseOptionHandler.getDisplayData is not implemented'); - - // @todo - // return { - // title: 'core.grades.grades', - // class: 'core-grades-course-handler', - // component: CoreGradesCourseComponent, - // }; + return { + title: 'core.grades.grades', + class: 'core-grades-course-handler', + page: 'grades', + }; } /**