diff --git a/src/core/classes/tabs.ts b/src/core/classes/tabs.ts index 8cc91af13..c04bea315 100644 --- a/src/core/classes/tabs.ts +++ b/src/core/classes/tabs.ts @@ -23,6 +23,7 @@ import { AfterViewInit, ViewChild, ElementRef, + SimpleChange, } from '@angular/core'; import { IonSlides } from '@ionic/angular'; import { BackButtonEvent } from '@ionic/core'; @@ -153,7 +154,8 @@ export class CoreTabsBaseComponent implements OnInit, Aft /** * Detect changes on input properties. */ - ngOnChanges(): void { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + ngOnChanges(changes: Record): void { // Wait for ngAfterViewInit so it works in the case that each tab has its own component. if (!this.initialized && this.hideUntil && this.afterViewInitTriggered) { // Tabs should be shown, initialize them. diff --git a/src/core/components/tabs-outlet/tabs-outlet.ts b/src/core/components/tabs-outlet/tabs-outlet.ts index 0fd52aaa9..963cb3ced 100644 --- a/src/core/components/tabs-outlet/tabs-outlet.ts +++ b/src/core/components/tabs-outlet/tabs-outlet.ts @@ -21,6 +21,7 @@ import { AfterViewInit, ViewChild, ElementRef, + SimpleChange, } from '@angular/core'; import { IonTabs } from '@ionic/angular'; import { Subscription } from 'rxjs'; @@ -70,17 +71,6 @@ export class CoreTabsOutletComponent extends CoreTabsBaseComponent { - super.ngOnInit(); - - this.tabs.forEach((tab) => { - this.initTab(tab); - }); - } - /** * Init tab info. * @@ -117,12 +107,16 @@ export class CoreTabsOutletComponent extends CoreTabsBaseComponent { - this.initTab(tab); - }); + ngOnChanges(changes: Record): void { + if (changes.tabs) { + this.tabs.forEach((tab) => { + this.initTab(tab); + }); - super.ngOnChanges(); + this.calculateSlides(); + } + + super.ngOnChanges(changes); } /** diff --git a/src/core/features/siteplugins/classes/handlers/main-menu-home-handler.ts b/src/core/features/siteplugins/classes/handlers/main-menu-home-handler.ts new file mode 100644 index 000000000..1e2904b9d --- /dev/null +++ b/src/core/features/siteplugins/classes/handlers/main-menu-home-handler.ts @@ -0,0 +1,58 @@ +// (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 { CoreMainMenuHomeHandler, CoreMainMenuHomeHandlerData } from '@features/mainmenu/services/home-delegate'; +import { + CoreSitePluginsContent, + CoreSitePluginsMainMenuHomeHandlerData, + CoreSitePluginsPlugin, +} from '@features/siteplugins/services/siteplugins'; +import { CoreSitePluginsBaseHandler } from './base-handler'; + +/** + * Handler to display a site plugin in the main menu. + */ +export class CoreSitePluginsMainMenuHomeHandler extends CoreSitePluginsBaseHandler implements CoreMainMenuHomeHandler { + + priority: number; + + constructor( + name: string, + protected title: string, + protected plugin: CoreSitePluginsPlugin, + protected handlerSchema: CoreSitePluginsMainMenuHomeHandlerData, + protected initResult: CoreSitePluginsContent | null, + ) { + super(name); + + this.priority = handlerSchema.priority || 0; + } + + /** + * @inheritdoc + */ + getDisplayData(): CoreMainMenuHomeHandlerData { + return { + title: this.title, + class: this.handlerSchema.displaydata?.class, + page: `siteplugins/${this.plugin.component}/${this.handlerSchema.method}/0`, + pageParams: { + title: this.title, + initResult: this.initResult, + ptrEnabled: this.handlerSchema.ptrenabled, + }, + }; + } + +} diff --git a/src/core/features/siteplugins/services/siteplugins-helper.ts b/src/core/features/siteplugins/services/siteplugins-helper.ts index 3c4c06eeb..439340e14 100644 --- a/src/core/features/siteplugins/services/siteplugins-helper.ts +++ b/src/core/features/siteplugins/services/siteplugins-helper.ts @@ -74,8 +74,11 @@ import { CoreSitePluginsBlockHandlerData, CoreSitePluginsHandlerCommonData, CoreSitePluginsInitHandlerData, + CoreSitePluginsMainMenuHomeHandlerData, } from './siteplugins'; import { makeSingleton } from '@singletons'; +import { CoreMainMenuHomeDelegate } from '@features/mainmenu/services/home-delegate'; +import { CoreSitePluginsMainMenuHomeHandler } from '../classes/handlers/main-menu-home-handler'; const HANDLER_DISABLED = 'core_site_plugins_helper_handler_disabled'; @@ -535,6 +538,10 @@ export class CoreSitePluginsHelperProvider { uniqueName = await this.registerWorkshopAssessmentStrategyHandler(plugin, handlerName, handlerSchema); break; + case 'CoreMainMenuHomeDelegate': + uniqueName = await this.registerMainMenuHomeHandler(plugin, handlerName, handlerSchema, initResult); + break; + default: // Nothing to do. } @@ -1130,6 +1137,41 @@ export class CoreSitePluginsHelperProvider { CoreEvents.trigger(CoreEvents.SITE_PLUGINS_COURSE_RESTRICT_UPDATED, {}); } + /** + * Given a handler in a plugin, register it in the main menu home delegate. + * + * @param plugin Data of the plugin. + * @param handlerName Name of the handler in the plugin. + * @param handlerSchema Data about the handler. + * @param initResult Result of the init WS call. + * @return A string to identify the handler. + */ + protected registerMainMenuHomeHandler( + plugin: CoreSitePluginsPlugin, + handlerName: string, + handlerSchema: CoreSitePluginsMainMenuHomeHandlerData, + initResult: CoreSitePluginsContent | null, + ): string | undefined { + if (!handlerSchema.displaydata) { + // Required data not provided, stop. + this.logger.warn('Ignore site plugin because it doesn\'t provide displaydata', plugin, handlerSchema); + + return; + } + + this.logger.debug('Register site plugin in main menu home delegate:', plugin, handlerSchema, initResult); + + // Create and register the handler. + const uniqueName = CoreSitePlugins.getHandlerUniqueName(plugin, handlerName); + const prefixedTitle = this.getPrefixedString(plugin.addon, handlerSchema.displaydata.title || 'pluginname'); + + CoreMainMenuHomeDelegate.registerHandler( + new CoreSitePluginsMainMenuHomeHandler(uniqueName, prefixedTitle, plugin, handlerSchema, initResult), + ); + + return uniqueName; + } + } export const CoreSitePluginsHelper = makeSingleton(CoreSitePluginsHelperProvider); diff --git a/src/core/features/siteplugins/services/siteplugins.ts b/src/core/features/siteplugins/services/siteplugins.ts index 1110755ef..cbbfbea40 100644 --- a/src/core/features/siteplugins/services/siteplugins.ts +++ b/src/core/features/siteplugins/services/siteplugins.ts @@ -784,7 +784,7 @@ export type CoreSitePluginsPlugin = CoreSitePluginsWSPlugin & { export type CoreSitePluginsHandlerData = CoreSitePluginsInitHandlerData | CoreSitePluginsCourseOptionHandlerData | CoreSitePluginsMainMenuHandlerData | CoreSitePluginsCourseModuleHandlerData | CoreSitePluginsCourseFormatHandlerData | CoreSitePluginsUserHandlerData | CoreSitePluginsSettingsHandlerData | CoreSitePluginsMessageOutputHandlerData | -CoreSitePluginsBlockHandlerData; +CoreSitePluginsBlockHandlerData | CoreSitePluginsMainMenuHomeHandlerData; /** * Plugin handler data common to all delegates. @@ -920,3 +920,15 @@ export type CoreSitePluginsInitHandlerData = CoreSitePluginsHandlerCommonData & methodJSResult?: any; // eslint-disable-line @typescript-eslint/no-explicit-any methodOtherdata?: Record; }; + +/** + * Main menu home handler specific data. + */ +export type CoreSitePluginsMainMenuHomeHandlerData = CoreSitePluginsHandlerCommonData & { + displaydata?: { + title?: string; + class?: string; + }; + priority?: number; + ptrenabled?: boolean; +}; diff --git a/src/core/features/siteplugins/siteplugins.module.ts b/src/core/features/siteplugins/siteplugins.module.ts index 154e3feb0..730d504e2 100644 --- a/src/core/features/siteplugins/siteplugins.module.ts +++ b/src/core/features/siteplugins/siteplugins.module.ts @@ -17,6 +17,7 @@ import { Routes } from '@angular/router'; import { CoreCourseIndexRoutingModule } from '@features/course/pages/index/index-routing.module'; import { CoreMainMenuTabRoutingModule } from '@features/mainmenu/mainmenu-tab-routing.module'; +import { CoreMainMenuHomeRoutingModule } from '@features/mainmenu/pages/home/home-routing.module'; import { CoreSitePluginsComponentsModule } from './components/components.module'; import { CoreSitePluginsHelper } from './services/siteplugins-helper'; @@ -39,6 +40,7 @@ const courseIndexRoutes: Routes = [ imports: [ CoreMainMenuTabRoutingModule.forChild(routes), CoreCourseIndexRoutingModule.forChild({ children: courseIndexRoutes }), + CoreMainMenuHomeRoutingModule.forChild({ children: routes }), CoreSitePluginsComponentsModule, ], providers: [