diff --git a/src/core/features/siteplugins/classes/compile-init-component.ts b/src/core/features/siteplugins/classes/compile-init-component.ts index e53b2263241..a163f6b02e4 100644 --- a/src/core/features/siteplugins/classes/compile-init-component.ts +++ b/src/core/features/siteplugins/classes/compile-init-component.ts @@ -27,6 +27,8 @@ export class CoreSitePluginsCompileInitComponent { extraImports: Type[] = []; protected handlerSchema?: CoreSitePluginsInitHandlerData; // The handler data. + stylesPath?: string; // Styles to apply to the component. + /** * Function called when the component is created. * @@ -42,18 +44,18 @@ export class CoreSitePluginsCompileInitComponent { /** * Get the handler data. * - * @param name The name of the handler. + * @param handlerName The name of the handler. */ - getHandlerData(name: string): void { + async getHandlerData(handlerName: string): Promise { // Retrieve the handler data. - const handler = CoreSitePlugins.getSitePluginHandler(name); - - this.handlerSchema = handler?.handlerSchema; + const handler = CoreSitePlugins.getSitePluginHandler(handlerName); - if (!this.handlerSchema) { + if (!handler?.handlerSchema) { return; } + this.handlerSchema = handler.handlerSchema; + // Load first template. if (this.handlerSchema.methodTemplates?.length) { this.content = this.handlerSchema.methodTemplates[0].html; @@ -72,6 +74,8 @@ export class CoreSitePluginsCompileInitComponent { if (this.handlerSchema.methodJSResult) { this.jsData.CONTENT_JS_RESULT = this.handlerSchema.methodJSResult; } + + this.stylesPath = await CoreSitePlugins.getHandlerDownloadedStyles(handlerName); } } diff --git a/src/core/features/siteplugins/classes/handlers/course-option-handler.ts b/src/core/features/siteplugins/classes/handlers/course-option-handler.ts index 891478241b9..dc860e7ed5b 100644 --- a/src/core/features/siteplugins/classes/handlers/course-option-handler.ts +++ b/src/core/features/siteplugins/classes/handlers/course-option-handler.ts @@ -71,23 +71,28 @@ export class CoreSitePluginsCourseOptionHandler extends CoreSitePluginsBaseHandl /** * @inheritdoc */ - getDisplayData(): CoreCourseOptionsHandlerData { + async getDisplayData(): Promise { + const stylesPath = await this.handlerSchema.styles?.downloadedStyles; + return { title: this.title, class: this.handlerSchema.displaydata?.class, page: `siteplugins/${this.name}`, - pageParams: {}, + pageParams: { + stylesPath, + }, }; } /** * @inheritdoc */ - getMenuDisplayData(course: CoreCourseAnyCourseDataWithOptions): CoreCourseOptionsMenuHandlerData { + async getMenuDisplayData(course: CoreCourseAnyCourseDataWithOptions): Promise { const args = { courseid: course.id, }; const hash = Md5.hashAsciiStr(JSON.stringify(args)); + const stylesPath = await this.handlerSchema.styles?.downloadedStyles; return { title: this.title, @@ -101,6 +106,7 @@ export class CoreSitePluginsCourseOptionHandler extends CoreSitePluginsBaseHandl ptrEnabled: this.handlerSchema.ptrenabled, contextLevel: 'course', contextInstanceId: course.id, + stylesPath, }, }; } diff --git a/src/core/features/siteplugins/classes/handlers/main-menu-handler.ts b/src/core/features/siteplugins/classes/handlers/main-menu-handler.ts index 1d06b9beaa8..ff87384deb9 100644 --- a/src/core/features/siteplugins/classes/handlers/main-menu-handler.ts +++ b/src/core/features/siteplugins/classes/handlers/main-menu-handler.ts @@ -14,6 +14,7 @@ import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '@features/mainmenu/services/mainmenu-delegate'; import { + CoreSitePlugins, CoreSitePluginsContent, CoreSitePluginsMainMenuHandlerData, CoreSitePluginsPlugin, @@ -43,6 +44,8 @@ export class CoreSitePluginsMainMenuHandler extends CoreSitePluginsBaseHandler i * @inheritdoc */ getDisplayData(): CoreMainMenuHandlerData { + const handlerName = CoreSitePlugins.getHandlerNameFromUniqueName(this.name, this.plugin.addon); + return { title: this.title, icon: this.handlerSchema.displaydata?.icon || 'fas-question', @@ -52,6 +55,7 @@ export class CoreSitePluginsMainMenuHandler extends CoreSitePluginsBaseHandler i title: this.title, initResult: this.initResult, ptrEnabled: this.handlerSchema.ptrenabled, + handlerName, }, onlyInMore: true, }; diff --git a/src/core/features/siteplugins/classes/handlers/message-output-handler.ts b/src/core/features/siteplugins/classes/handlers/message-output-handler.ts index 07db9433668..06ce1f49f77 100644 --- a/src/core/features/siteplugins/classes/handlers/message-output-handler.ts +++ b/src/core/features/siteplugins/classes/handlers/message-output-handler.ts @@ -14,6 +14,7 @@ import { AddonMessageOutputHandler, AddonMessageOutputHandlerData } from '@addons/messageoutput/services/messageoutput-delegate'; import { + CoreSitePlugins, CoreSitePluginsContent, CoreSitePluginsMessageOutputHandlerData, CoreSitePluginsPlugin, @@ -40,6 +41,8 @@ export class CoreSitePluginsMessageOutputHandler extends CoreSitePluginsBaseHand * @inheritdoc */ getDisplayData(): AddonMessageOutputHandlerData { + const handlerName = CoreSitePlugins.getHandlerNameFromUniqueName(this.name, this.plugin.addon); + return { priority: this.handlerSchema.priority || 0, label: this.title, @@ -49,6 +52,7 @@ export class CoreSitePluginsMessageOutputHandler extends CoreSitePluginsBaseHand title: this.title, initResult: this.initResult, ptrEnabled: this.handlerSchema.ptrenabled, + handlerName, }, }; } diff --git a/src/core/features/siteplugins/classes/handlers/settings-handler.ts b/src/core/features/siteplugins/classes/handlers/settings-handler.ts index 3328f39c2ae..1d2b733f11d 100644 --- a/src/core/features/siteplugins/classes/handlers/settings-handler.ts +++ b/src/core/features/siteplugins/classes/handlers/settings-handler.ts @@ -14,6 +14,7 @@ import { CoreSettingsHandler, CoreSettingsHandlerData } from '@features/settings/services/settings-delegate'; import { + CoreSitePlugins, CoreSitePluginsContent, CoreSitePluginsPlugin, CoreSitePluginsSettingsHandlerData, @@ -45,6 +46,8 @@ export class CoreSitePluginsSettingsHandler extends CoreSitePluginsBaseHandler i * @returns Data. */ getDisplayData(): CoreSettingsHandlerData { + const handlerName = CoreSitePlugins.getHandlerNameFromUniqueName(this.name, this.plugin.addon); + return { title: this.title, icon: this.handlerSchema.displaydata?.icon, @@ -54,6 +57,7 @@ export class CoreSitePluginsSettingsHandler extends CoreSitePluginsBaseHandler i title: this.title, initResult: this.initResult, ptrEnabled: this.handlerSchema.ptrenabled, + handlerName, }, }; } diff --git a/src/core/features/siteplugins/classes/handlers/user-handler.ts b/src/core/features/siteplugins/classes/handlers/user-handler.ts index ff0095ea9a9..2afcfd8df7a 100644 --- a/src/core/features/siteplugins/classes/handlers/user-handler.ts +++ b/src/core/features/siteplugins/classes/handlers/user-handler.ts @@ -86,6 +86,7 @@ export class CoreSitePluginsUserProfileHandler extends CoreSitePluginsBaseHandle * @inheritdoc */ getDisplayData(): CoreUserProfileHandlerData { + return { title: this.title, icon: this.handlerSchema.displaydata?.icon, @@ -94,6 +95,8 @@ export class CoreSitePluginsUserProfileHandler extends CoreSitePluginsBaseHandle event.preventDefault(); event.stopPropagation(); + const handlerName = CoreSitePlugins.getHandlerNameFromUniqueName(this.name, this.plugin.addon); + const args = { courseid: contextId, userid: user.id, @@ -110,6 +113,7 @@ export class CoreSitePluginsUserProfileHandler extends CoreSitePluginsBaseHandle ptrEnabled: this.handlerSchema.ptrenabled, contextLevel: 'user', contextInstanceId: user.id, + handlerName, }, }, ); diff --git a/src/core/features/siteplugins/components/assign-feedback/assign-feedback.ts b/src/core/features/siteplugins/components/assign-feedback/assign-feedback.ts index 01654455dc5..817b91cf8ed 100644 --- a/src/core/features/siteplugins/components/assign-feedback/assign-feedback.ts +++ b/src/core/features/siteplugins/components/assign-feedback/assign-feedback.ts @@ -61,7 +61,7 @@ export class CoreSitePluginsAssignFeedbackComponent extends CoreSitePluginsCompi this.extraImports = await getModAssignComponentModules(); if (this.plugin) { - this.getHandlerData(AddonModAssignFeedbackDelegate.getHandlerName(this.plugin.type)); + await this.getHandlerData(AddonModAssignFeedbackDelegate.getHandlerName(this.plugin.type)); } } diff --git a/src/core/features/siteplugins/components/assign-feedback/core-siteplugins-assign-feedback.html b/src/core/features/siteplugins/components/assign-feedback/core-siteplugins-assign-feedback.html index 79830e9acf0..60d35b04ef9 100644 --- a/src/core/features/siteplugins/components/assign-feedback/core-siteplugins-assign-feedback.html +++ b/src/core/features/siteplugins/components/assign-feedback/core-siteplugins-assign-feedback.html @@ -1 +1 @@ - + diff --git a/src/core/features/siteplugins/components/assign-submission/assign-submission.ts b/src/core/features/siteplugins/components/assign-submission/assign-submission.ts index d4e55cd4fb5..62c20e11659 100644 --- a/src/core/features/siteplugins/components/assign-submission/assign-submission.ts +++ b/src/core/features/siteplugins/components/assign-submission/assign-submission.ts @@ -59,7 +59,7 @@ export class CoreSitePluginsAssignSubmissionComponent extends CoreSitePluginsCom this.extraImports = await getModAssignComponentModules(); if (this.plugin) { - this.getHandlerData(AddonModAssignSubmissionDelegate.getHandlerName(this.plugin.type)); + await this.getHandlerData(AddonModAssignSubmissionDelegate.getHandlerName(this.plugin.type)); } } diff --git a/src/core/features/siteplugins/components/assign-submission/core-siteplugins-assign-submission.html b/src/core/features/siteplugins/components/assign-submission/core-siteplugins-assign-submission.html index 79830e9acf0..d38494852cd 100644 --- a/src/core/features/siteplugins/components/assign-submission/core-siteplugins-assign-submission.html +++ b/src/core/features/siteplugins/components/assign-submission/core-siteplugins-assign-submission.html @@ -1 +1 @@ - + \ No newline at end of file diff --git a/src/core/features/siteplugins/components/block/block.ts b/src/core/features/siteplugins/components/block/block.ts index 8d83575cb91..a6c23742b07 100644 --- a/src/core/features/siteplugins/components/block/block.ts +++ b/src/core/features/siteplugins/components/block/block.ts @@ -42,15 +42,16 @@ export class CoreSitePluginsBlockComponent extends CoreBlockBaseComponent implem args?: Record; jsData?: Record; // Data to pass to the component. initResult?: CoreSitePluginsContent | null; + stylesPath?: string; // Styles to apply to the component. constructor() { super('CoreSitePluginsBlockComponent'); } /** - * Detect changes on input properties. + * @inheritdoc */ - ngOnChanges(): void { + async ngOnChanges(): Promise { if (this.component) { return; } @@ -73,12 +74,12 @@ export class CoreSitePluginsBlockComponent extends CoreBlockBaseComponent implem block: this.block, }; this.initResult = handler.initResult; + + this.stylesPath = await CoreSitePlugins.getHandlerDownloadedStyles(handlerName); } /** - * Invalidate block data. - * - * @returns Promise resolved when done. + * @inheritdoc */ async invalidateContent(): Promise { if (!this.component || !this.method) { diff --git a/src/core/features/siteplugins/components/block/core-siteplugins-block.html b/src/core/features/siteplugins/components/block/core-siteplugins-block.html index 8058a93f3e1..7f5ea76c330 100644 --- a/src/core/features/siteplugins/components/block/core-siteplugins-block.html +++ b/src/core/features/siteplugins/components/block/core-siteplugins-block.html @@ -1,2 +1,2 @@ + [initResult]="initResult" [data]="jsData" contextLevel="block" [contextInstanceId]="block.instanceid" [stylesPath]="stylesPath" /> diff --git a/src/core/features/siteplugins/components/course-format/core-siteplugins-course-format.html b/src/core/features/siteplugins/components/course-format/core-siteplugins-course-format.html index c4f60e1e34f..5786bb53e36 100644 --- a/src/core/features/siteplugins/components/course-format/core-siteplugins-course-format.html +++ b/src/core/features/siteplugins/components/course-format/core-siteplugins-course-format.html @@ -1,2 +1,2 @@ + [initResult]="initResult" [data]="data" contextLevel="course" [contextInstanceId]="course?.id" [stylesPath]="stylesPath" /> diff --git a/src/core/features/siteplugins/components/course-format/course-format.ts b/src/core/features/siteplugins/components/course-format/course-format.ts index 4979d730510..f68add9e763 100644 --- a/src/core/features/siteplugins/components/course-format/course-format.ts +++ b/src/core/features/siteplugins/components/course-format/course-format.ts @@ -55,11 +55,12 @@ export class CoreSitePluginsCourseFormatComponent implements OnChanges { args?: Record; initResult?: CoreSitePluginsContent | null; data?: Record; + stylesPath?: string; // Styles to apply to the component. /** * @inheritdoc */ - ngOnChanges(): void { + async ngOnChanges(): Promise { if (!this.course || !this.course.format) { return; } @@ -76,6 +77,8 @@ export class CoreSitePluginsCourseFormatComponent implements OnChanges { courseid: this.course.id, }; this.initResult = handler.initResult; + + this.stylesPath = await CoreSitePlugins.getHandlerDownloadedStyles(handlerName); } } diff --git a/src/core/features/siteplugins/components/module-index/core-siteplugins-module-index.html b/src/core/features/siteplugins/components/module-index/core-siteplugins-module-index.html index 17a625ae98c..ab8b19ab0a4 100644 --- a/src/core/features/siteplugins/components/module-index/core-siteplugins-module-index.html +++ b/src/core/features/siteplugins/components/module-index/core-siteplugins-module-index.html @@ -19,7 +19,7 @@ + (onLoadingContent)="contentLoading()" [stylesPath]="stylesPath" /> diff --git a/src/core/features/siteplugins/components/module-index/module-index.ts b/src/core/features/siteplugins/components/module-index/module-index.ts index fbe71c01888..5292e0014e0 100644 --- a/src/core/features/siteplugins/components/module-index/module-index.ts +++ b/src/core/features/siteplugins/components/module-index/module-index.ts @@ -81,13 +81,14 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C isDestroyed = false; jsData?: Record; // Data to pass to the component. + stylesPath?: string; // Styles to apply to the component. constructor(@Optional() public courseContentsPage?: CoreCourseContentsPage) {} /** * @inheritdoc */ - ngOnInit(): void { + async ngOnInit(): Promise { if (!this.module) { return; } @@ -120,6 +121,8 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C this.ptrEnabled = !CoreUtils.isFalseOrZero(handlerSchema.ptrenabled); this.collapsibleFooterAppearOnBottom = !CoreUtils.isFalseOrZero(handlerSchema.isresource); + + this.stylesPath = await CoreSitePlugins.getHandlerDownloadedStyles(handlerName); } // Get the data for the context menu. @@ -142,6 +145,8 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C /** * Function called when the data of the site plugin content is loaded. + * + * @param data Data received. */ contentLoaded(data: CoreSitePluginsPluginContentLoadedData): void { this.addDefaultModuleInfo = !data.content.includes(' handler.handlerSchema).ptrenabled, contextLevel: 'block', contextInstanceId: this.instanceId, + handlerName, }, }, ); diff --git a/src/core/features/siteplugins/components/plugin-content/core-siteplugins-plugin-content.html b/src/core/features/siteplugins/components/plugin-content/core-siteplugins-plugin-content.html index 4ae340d7691..4e13a42e1a0 100644 --- a/src/core/features/siteplugins/components/plugin-content/core-siteplugins-plugin-content.html +++ b/src/core/features/siteplugins/components/plugin-content/core-siteplugins-plugin-content.html @@ -1,3 +1,4 @@ - + diff --git a/src/core/features/siteplugins/components/plugin-content/plugin-content.ts b/src/core/features/siteplugins/components/plugin-content/plugin-content.ts index b14f45b8b97..aceae903a08 100644 --- a/src/core/features/siteplugins/components/plugin-content/plugin-content.ts +++ b/src/core/features/siteplugins/components/plugin-content/plugin-content.ts @@ -62,6 +62,7 @@ export class CoreSitePluginsPluginContentComponent implements OnInit, DoCheck { @Input() args?: Record; @Input() initResult?: CoreSitePluginsContent | null; // Result of the init WS call of the handler. @Input() data: Record = {}; // Data to pass to the component. + @Input() stylesPath = ''; // Styles. @Input() preSets?: CoreSiteWSPreSets; // The preSets for the WS call. @Input() pageTitle?: string; // Current page title. It can be used by the "new-content" directives. @Input() contextLevel?: ContextLevel; // The context level to filter text. Can be used by some directives. @@ -145,7 +146,8 @@ export class CoreSitePluginsPluginContentComponent implements OnInit, DoCheck { jsData?: Record | boolean, preSets?: CoreSiteWSPreSets, ptrEnabled?: boolean, - ) => this.openContent(title, args, component, method, jsData, preSets, ptrEnabled); + stylesPath?: string, + ) => this.openContent(title, args, component, method, jsData, preSets, ptrEnabled, stylesPath); this.jsData.refreshContent = (showSpinner?: boolean) => this.refreshContent(showSpinner); this.jsData.updateContent = ( args?: Record, @@ -181,6 +183,7 @@ export class CoreSitePluginsPluginContentComponent implements OnInit, DoCheck { * If true is supplied instead of an object, all initial variables from current page will be copied. * @param preSets The preSets for the WS call of the new content. * @param ptrEnabled Whether PTR should be enabled in the new page. Defaults to true. + * @param stylesPath Styles to apply to the component. */ openContent( title: string, @@ -191,6 +194,7 @@ export class CoreSitePluginsPluginContentComponent implements OnInit, DoCheck { preSets?: CoreSiteWSPreSets, ptrEnabled?: boolean, filterOptions?: FilterOptions, + stylesPath?: string, ): void { if (jsData === true) { jsData = this.data; @@ -211,6 +215,7 @@ export class CoreSitePluginsPluginContentComponent implements OnInit, DoCheck { contextLevel: filterOptions?.contextLevel || this.contextLevel, contextInstanceId: filterOptions?.contextInstanceId || this.contextInstanceId, courseId: filterOptions?.courseId || this.courseId, + stylesPath, }, }); } diff --git a/src/core/features/siteplugins/components/question-behaviour/core-siteplugins-question-behaviour.html b/src/core/features/siteplugins/components/question-behaviour/core-siteplugins-question-behaviour.html index 79830e9acf0..60d35b04ef9 100644 --- a/src/core/features/siteplugins/components/question-behaviour/core-siteplugins-question-behaviour.html +++ b/src/core/features/siteplugins/components/question-behaviour/core-siteplugins-question-behaviour.html @@ -1 +1 @@ - + diff --git a/src/core/features/siteplugins/components/question-behaviour/question-behaviour.ts b/src/core/features/siteplugins/components/question-behaviour/question-behaviour.ts index edb13da73cd..d997854541a 100644 --- a/src/core/features/siteplugins/components/question-behaviour/question-behaviour.ts +++ b/src/core/features/siteplugins/components/question-behaviour/question-behaviour.ts @@ -72,7 +72,7 @@ export class CoreSitePluginsQuestionBehaviourComponent extends CoreSitePluginsCo this.jsData.onAbort = this.onAbort; if (this.question) { - this.getHandlerData(CoreQuestionBehaviourDelegate.getHandlerName(this.preferredBehaviour || '')); + await this.getHandlerData(CoreQuestionBehaviourDelegate.getHandlerName(this.preferredBehaviour || '')); } } diff --git a/src/core/features/siteplugins/components/question/core-siteplugins-question.html b/src/core/features/siteplugins/components/question/core-siteplugins-question.html index 79830e9acf0..60d35b04ef9 100644 --- a/src/core/features/siteplugins/components/question/core-siteplugins-question.html +++ b/src/core/features/siteplugins/components/question/core-siteplugins-question.html @@ -1 +1 @@ - + diff --git a/src/core/features/siteplugins/components/quiz-access-rule/core-siteplugins-quiz-access-rule.html b/src/core/features/siteplugins/components/quiz-access-rule/core-siteplugins-quiz-access-rule.html index 79830e9acf0..60d35b04ef9 100644 --- a/src/core/features/siteplugins/components/quiz-access-rule/core-siteplugins-quiz-access-rule.html +++ b/src/core/features/siteplugins/components/quiz-access-rule/core-siteplugins-quiz-access-rule.html @@ -1 +1 @@ - + diff --git a/src/core/features/siteplugins/components/quiz-access-rule/quiz-access-rule.ts b/src/core/features/siteplugins/components/quiz-access-rule/quiz-access-rule.ts index c2c1baff0e1..6c9da00a4b3 100644 --- a/src/core/features/siteplugins/components/quiz-access-rule/quiz-access-rule.ts +++ b/src/core/features/siteplugins/components/quiz-access-rule/quiz-access-rule.ts @@ -57,7 +57,7 @@ export class CoreSitePluginsQuizAccessRuleComponent extends CoreSitePluginsCompi this.jsData.form = this.form; if (this.rule) { - this.getHandlerData(AddonModQuizAccessRuleDelegate.getHandlerName(this.rule)); + await this.getHandlerData(AddonModQuizAccessRuleDelegate.getHandlerName(this.rule)); } } diff --git a/src/core/features/siteplugins/components/user-profile-field/core-siteplugins-user-profile-field.html b/src/core/features/siteplugins/components/user-profile-field/core-siteplugins-user-profile-field.html index 469fc233ee0..823da036b30 100644 --- a/src/core/features/siteplugins/components/user-profile-field/core-siteplugins-user-profile-field.html +++ b/src/core/features/siteplugins/components/user-profile-field/core-siteplugins-user-profile-field.html @@ -1 +1 @@ - + diff --git a/src/core/features/siteplugins/components/user-profile-field/user-profile-field.ts b/src/core/features/siteplugins/components/user-profile-field/user-profile-field.ts index dfcf9f87d68..406cad8e43a 100644 --- a/src/core/features/siteplugins/components/user-profile-field/user-profile-field.ts +++ b/src/core/features/siteplugins/components/user-profile-field/user-profile-field.ts @@ -52,7 +52,7 @@ export class CoreSitePluginsUserProfileFieldComponent extends CoreSitePluginsCom /** * @inheritdoc */ - ngOnInit(): void { + async ngOnInit(): Promise { // Pass the input data to the component. this.jsData.field = this.field; this.jsData.signup = this.signup; @@ -63,7 +63,7 @@ export class CoreSitePluginsUserProfileFieldComponent extends CoreSitePluginsCom if (this.field) { const type = 'type' in this.field ? this.field.type : this.field.datatype; - this.getHandlerData(CoreUserProfileFieldDelegate.getHandlerName(type || '')); + await this.getHandlerData(CoreUserProfileFieldDelegate.getHandlerName(type || '')); } } diff --git a/src/core/features/siteplugins/components/workshop-assessment-strategy/core-siteplugins-workshop-assessment-strategy.html b/src/core/features/siteplugins/components/workshop-assessment-strategy/core-siteplugins-workshop-assessment-strategy.html index 79830e9acf0..60d35b04ef9 100644 --- a/src/core/features/siteplugins/components/workshop-assessment-strategy/core-siteplugins-workshop-assessment-strategy.html +++ b/src/core/features/siteplugins/components/workshop-assessment-strategy/core-siteplugins-workshop-assessment-strategy.html @@ -1 +1 @@ - + diff --git a/src/core/features/siteplugins/components/workshop-assessment-strategy/workshop-assessment-strategy.ts b/src/core/features/siteplugins/components/workshop-assessment-strategy/workshop-assessment-strategy.ts index b9e57594e96..974875fbd95 100644 --- a/src/core/features/siteplugins/components/workshop-assessment-strategy/workshop-assessment-strategy.ts +++ b/src/core/features/siteplugins/components/workshop-assessment-strategy/workshop-assessment-strategy.ts @@ -60,7 +60,7 @@ export class CoreSitePluginsWorkshopAssessmentStrategyComponent extends CoreSite this.extraImports = await getModWorkshopComponentModules(); - this.getHandlerData(AddonWorkshopAssessmentStrategyDelegate.getHandlerName(this.strategy)); + await this.getHandlerData(AddonWorkshopAssessmentStrategyDelegate.getHandlerName(this.strategy)); } } diff --git a/src/core/features/siteplugins/directives/call-ws-new-content.ts b/src/core/features/siteplugins/directives/call-ws-new-content.ts index 8bfc5e7a991..ed48b62f13e 100644 --- a/src/core/features/siteplugins/directives/call-ws-new-content.ts +++ b/src/core/features/siteplugins/directives/call-ws-new-content.ts @@ -117,6 +117,7 @@ export class CoreSitePluginsCallWSNewContentDirective extends CoreSitePluginsCal contextLevel: this.contextLevel ?? this.parentContent?.contextLevel, contextInstanceId: this.contextInstanceId ?? this.parentContent?.contextInstanceId, courseId: this.courseId ?? this.parentContent?.courseId ?? args.courseid, + stylesPath: this.parentContent?.stylesPath, }, }); } diff --git a/src/core/features/siteplugins/directives/new-content.ts b/src/core/features/siteplugins/directives/new-content.ts index 2ab0bcaa9d8..c8357f9b875 100644 --- a/src/core/features/siteplugins/directives/new-content.ts +++ b/src/core/features/siteplugins/directives/new-content.ts @@ -116,6 +116,7 @@ export class CoreSitePluginsNewContentDirective implements OnInit { contextLevel: this.contextLevel ?? this.parentContent?.contextLevel, contextInstanceId: this.contextInstanceId ?? this.parentContent?.contextInstanceId, courseId: this.courseId ?? this.parentContent?.courseId ?? args.courseid, + stylesPath: this.parentContent?.stylesPath, }, }); } diff --git a/src/core/features/siteplugins/pages/course-option/core-siteplugins-course-option.html b/src/core/features/siteplugins/pages/course-option/core-siteplugins-course-option.html index 260b9e16e6f..9f1fe7d40eb 100644 --- a/src/core/features/siteplugins/pages/course-option/core-siteplugins-course-option.html +++ b/src/core/features/siteplugins/pages/course-option/core-siteplugins-course-option.html @@ -3,5 +3,5 @@ + [initResult]="initResult" contextLevel="course" [contextInstanceId]="courseId" [stylesPath]="stylesPath" /> diff --git a/src/core/features/siteplugins/pages/course-option/course-option.ts b/src/core/features/siteplugins/pages/course-option/course-option.ts index 05c4abefe11..e4d822d3c65 100644 --- a/src/core/features/siteplugins/pages/course-option/course-option.ts +++ b/src/core/features/siteplugins/pages/course-option/course-option.ts @@ -36,26 +36,25 @@ export default class CoreSitePluginsCourseOptionPage implements OnInit { @ViewChild(CoreSitePluginsPluginContentComponent) content?: CoreSitePluginsPluginContentComponent; - courseId?: number; - handlerUniqueName?: string; component?: string; method?: string; args?: Record; initResult?: CoreSitePluginsContent | null; ptrEnabled = true; + stylesPath?: string; // Styles to apply to the component. /** * @inheritdoc */ - ngOnInit(): void { - this.courseId = CoreNavigator.getRouteNumberParam('courseId'); - this.handlerUniqueName = CoreNavigator.getRouteParam('handlerUniqueName'); + async ngOnInit(): Promise { + const courseId = CoreNavigator.getRouteNumberParam('courseId'); + const handlerName = CoreNavigator.getRouteParam('handlerUniqueName'); - if (!this.handlerUniqueName) { + if (!handlerName) { return; } - const handler = CoreSitePlugins.getSitePluginHandler(this.handlerUniqueName); + const handler = CoreSitePlugins.getSitePluginHandler(handlerName); if (!handler) { return; } @@ -63,11 +62,13 @@ export default class CoreSitePluginsCourseOptionPage implements OnInit { this.component = handler.plugin.component; this.method = handler.handlerSchema.method; this.args = { - courseid: this.courseId, + courseid: courseId, }; this.initResult = handler.initResult; this.ptrEnabled = !('ptrenabled' in handler.handlerSchema) || !CoreUtils.isFalseOrZero(handler.handlerSchema.ptrenabled); + + this.stylesPath = await CoreSitePlugins.getHandlerDownloadedStyles(handlerName); } /** diff --git a/src/core/features/siteplugins/pages/plugin/plugin.html b/src/core/features/siteplugins/pages/plugin/plugin.html index 02bf6198576..45cc4b55afb 100644 --- a/src/core/features/siteplugins/pages/plugin/plugin.html +++ b/src/core/features/siteplugins/pages/plugin/plugin.html @@ -18,5 +18,5 @@

+ [data]="jsData" [pageTitle]="title" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId" [stylesPath]="stylesPath" /> diff --git a/src/core/features/siteplugins/pages/plugin/plugin.ts b/src/core/features/siteplugins/pages/plugin/plugin.ts index a7ff1a06216..5a5daad7daf 100644 --- a/src/core/features/siteplugins/pages/plugin/plugin.ts +++ b/src/core/features/siteplugins/pages/plugin/plugin.ts @@ -14,7 +14,7 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; -import { CoreSitePluginsContent } from '@features/siteplugins/services/siteplugins'; +import { CoreSitePlugins, CoreSitePluginsContent } from '@features/siteplugins/services/siteplugins'; import { CanLeave } from '@guards/can-leave'; import { CoreNavigator } from '@services/navigator'; import { CoreUtils } from '@singletons/utils'; @@ -49,11 +49,12 @@ export default class CoreSitePluginsPluginPage implements OnInit, CanLeave { contextLevel?: ContextLevel; // The context level to filter text. contextInstanceId?: number; // The instance ID related to the context. courseId?: number; // Course ID the text belongs to. It can be used to improve performance with filters. + stylesPath?: string; // Styles to apply to the component. /** * @inheritdoc */ - ngOnInit(): void { + async ngOnInit(): Promise { this.title = CoreNavigator.getRouteParam('title'); this.component = CoreNavigator.getRouteParam('component'); this.method = CoreNavigator.getRouteParam('method'); @@ -65,6 +66,12 @@ export default class CoreSitePluginsPluginPage implements OnInit, CanLeave { this.contextLevel = CoreNavigator.getRouteParam('contextLevel'); this.contextInstanceId = CoreNavigator.getRouteNumberParam('contextInstanceId'); this.courseId = CoreNavigator.getRouteNumberParam('courseId'); + + this.stylesPath = CoreNavigator.getRouteParam('stylesPath'); + if (!this.stylesPath) { + const handlerName = CoreNavigator.getRouteParam('handlerName'); + this.stylesPath = await CoreSitePlugins.getHandlerDownloadedStyles(handlerName); + } } /** diff --git a/src/core/features/siteplugins/services/siteplugins-init.ts b/src/core/features/siteplugins/services/siteplugins-init.ts index f8d5276c761..ab66eedd8fc 100644 --- a/src/core/features/siteplugins/services/siteplugins-init.ts +++ b/src/core/features/siteplugins/services/siteplugins-init.ts @@ -89,6 +89,7 @@ import { CoreEnrolAction, CoreEnrolDelegate } from '@features/enrol/services/enr import { CoreSitePluginsEnrolHandler } from '../classes/handlers/enrol-handler'; import { CORE_SITE_PLUGINS_COMPONENT } from '../constants'; import { CORE_COURSES_MY_COURSES_CHANGED_EVENT } from '@features/courses/constants'; +import { CorePromisedValue } from '@classes/promised-value'; /** * Helper service to provide functionalities regarding site plugins. It basically has the features to load and register site @@ -154,68 +155,110 @@ export class CoreSitePluginsInitService { * @param handlerName Name of the handler in the plugin. * @param handlerSchema Data about the handler. * @param siteId Site ID. If not provided, current site. - * @returns Promise resolved with the CSS code. */ protected async downloadStyles( plugin: CoreSitePluginsPlugin, handlerName: string, handlerSchema: CoreSitePluginsHandlerData, - siteId?: string, - ): Promise { - const site = await CoreSites.getSite(siteId); + siteId: string, + ): Promise { + try { + if (handlerSchema.styles?.downloadedStyles) { + return; + } - // Make sure it's an absolute URL. Do not use toAbsoluteURL because it can change the behaviour and break plugin styles. - let url = handlerSchema.styles?.url; - if (url && !CoreUrl.isAbsoluteURL(url)) { - url = CorePath.concatenatePaths(site.getURL(), url); - } + if (url && handlerSchema.styles?.version) { + // Add the version to the URL to prevent getting a cached file. + url += `${url.indexOf('?') != -1 ? '&' : '?'}version=${handlerSchema.styles.version}`; + } - if (url && handlerSchema.styles?.version) { - // Add the version to the URL to prevent getting a cached file. - url += `${url.indexOf('?') != -1 ? '&' : '?'}version=${handlerSchema.styles.version}`; - } + const uniqueName = CoreSitePlugins.getHandlerUniqueName(plugin, handlerName); + const componentId = `${uniqueName}#main`; - const uniqueName = CoreSitePlugins.getHandlerUniqueName(plugin, handlerName); - const componentId = `${uniqueName}#main`; + if (!handlerSchema.styles?.url) { + // No styles. Clear previous styles if any. + await this.clearPreviousStyles(componentId, siteId); + + if (handlerSchema.styles) { + handlerSchema.styles = undefined; + } + + return; + } + + const site = await CoreSites.getSite(siteId); + siteId = site.getId(); + + // Make sure it's an absolute URL. Do not use toAbsoluteURL because it can change the behaviour and break plugin styles. + let fileUrl = handlerSchema.styles.url; + const version = handlerSchema.styles.version; + + if (!CoreUrl.isAbsoluteURL(fileUrl)) { + fileUrl = CorePath.concatenatePaths(site.getURL(), fileUrl); + } + + if (version) { + // Add the version to the URL to prevent getting a cached file. + fileUrl = CoreUrl.addParamsToUrl(fileUrl, { version }); + } + + await this.clearPreviousStyles(componentId, siteId, fileUrl); + + handlerSchema.styles.downloadedStyles = new CorePromisedValue(); + // Download the file if not downloaded or the version changed. + const path = await CoreFilepool.downloadUrl( + siteId, + fileUrl, + false, + CORE_SITE_PLUGINS_COMPONENT, + componentId, + 0, + undefined, + undefined, + undefined, + handlerSchema.styles.version, + ); + + const cssCode = await CoreWS.getText(path); + + await CorePromiseUtils.ignoreErrors( + CoreFilepool.treatCSSCode(siteId, fileUrl, cssCode, CORE_SITE_PLUGINS_COMPONENT, uniqueName, version), + ); + + handlerSchema.styles.downloadedStyles.resolve(path); + } catch (error) { + this.logger.error('Error getting styles for plugin', handlerName, handlerSchema, error); + if (handlerSchema.styles?.downloadedStyles) { + handlerSchema.styles.downloadedStyles.reject(error); + } + } + } + + /** + * Clear previous styles for a handler. + * This function will remove all the CSS files for the handler that aren't used anymore. + * + * @param componentId Component ID. + * @param siteId Site ID. + * @param url URL of the current CSS file. If not provided, all the CSS files for the handler will be removed. + */ + protected async clearPreviousStyles( + componentId: string, + siteId: string, + url?: string, + ): Promise { // Remove the CSS files for this handler that aren't used anymore. Don't block the call for this. const files = await CorePromiseUtils.ignoreErrors( - CoreFilepool.getFilesByComponent(site.getId(), CORE_SITE_PLUGINS_COMPONENT, componentId), + CoreFilepool.getFilesByComponent(siteId, CORE_SITE_PLUGINS_COMPONENT, componentId), ); files?.forEach((file) => { if (file.url !== url) { // It's not the current file, delete it. - CorePromiseUtils.ignoreErrors(CoreFilepool.removeFileByUrl(site.getId(), file.url)); + CorePromiseUtils.ignoreErrors(CoreFilepool.removeFileByUrl(siteId, file.url)); } }); - - if (!url) { - // No styles. - return ''; - } - - // Update the schema with the final CSS URL. - if (handlerSchema.styles) { - handlerSchema.styles.url = url; - } - - // Download the file if not downloaded or the version changed. - const path = await CoreFilepool.downloadUrl( - site.getId(), - url, - false, - CORE_SITE_PLUGINS_COMPONENT, - componentId, - 0, - undefined, - undefined, - undefined, - handlerSchema.styles?.version, - ); - - // File is downloaded, get the contents. - return CoreWS.getText(path); } /** @@ -390,21 +433,28 @@ export class CoreSitePluginsInitService { * * @param plugin Data of the plugin. * @param handlerName Name of the handler in the plugin. - * @param fileUrl CSS file URL. - * @param cssCode CSS code. - * @param version Styles version. + * @param handlerSchema Data about the handler. * @param siteId Site ID. If not provided, current site. */ - protected loadStyles( + protected async loadStyles( plugin: CoreSitePluginsPlugin, handlerName: string, - fileUrl: string, - cssCode: string, - version?: number, + handlerSchema: CoreSitePluginsHandlerData, siteId?: string, - ): void { + ): Promise { siteId = siteId || CoreSites.getCurrentSiteId(); + this.downloadStyles(plugin, handlerName, handlerSchema, siteId); + + const path = await CoreSitePlugins.getHandlerDownloadedStyles(handlerName); + if (!path || !handlerSchema.styles?.url) { + return; + } + const fileUrl = handlerSchema.styles.url; + const version = handlerSchema.styles.version; + + const cssCode = await CoreWS.getText(path); + // Create the style and add it to the header. const styleEl = document.createElement('style'); const uniqueName = CoreSitePlugins.getHandlerUniqueName(plugin, handlerName); @@ -450,12 +500,7 @@ export class CoreSitePluginsInitService { const siteId = CoreSites.getCurrentSiteId(); try { - const [initResult, cssCode] = await Promise.all([ - this.executeHandlerInit(plugin, handlerSchema), - this.downloadStyles(plugin, handlerName, handlerSchema, siteId).catch((error) => { - this.logger.error('Error getting styles for plugin', handlerName, handlerSchema, error); - }), - ]); + const initResult = await this.executeHandlerInit(plugin, handlerSchema); if (initResult?.disabled) { // This handler is disabled for the current user, stop. @@ -464,10 +509,7 @@ export class CoreSitePluginsInitService { return; } - if (cssCode && handlerSchema.styles?.url) { - // Load the styles. - this.loadStyles(plugin, handlerName, handlerSchema.styles.url, cssCode, handlerSchema.styles.version, siteId); - } + let loadStyles = true; let uniqueName: string | undefined; @@ -541,7 +583,16 @@ export class CoreSitePluginsInitService { break; default: + loadStyles = false; // Nothing to do. + this.loadStyles(plugin, handlerName, handlerSchema, siteId); + } + + if (loadStyles) { + // Load the styles without waiting for them to be downloaded. + this.downloadStyles(plugin, handlerName, handlerSchema, siteId); + } else { + handlerSchema.styles = undefined; } if (uniqueName) { diff --git a/src/core/features/siteplugins/services/siteplugins.ts b/src/core/features/siteplugins/services/siteplugins.ts index f69ccdecec1..d954f7eb7bc 100644 --- a/src/core/features/siteplugins/services/siteplugins.ts +++ b/src/core/features/siteplugins/services/siteplugins.ts @@ -696,6 +696,35 @@ export class CoreSitePluginsProvider { this.moduleHandlerInstances[modName] = handler; } + /** + * Get the path to the downloaded styles of a handler. + * + * @param handlerName Handler's name. + * @returns Path to the downloaded styles. + */ + async getHandlerDownloadedStyles(handlerName?: string): Promise { + if (!handlerName) { + return ''; + } + const handler = this.getSitePluginHandler(handlerName); + if (!handler?.handlerSchema.styles?.downloadedStyles) { + return ''; + } + + return await handler.handlerSchema.styles.downloadedStyles; + } + + /** + * Get the name of the handler from a unique name. + * + * @param uniqueName Unique name of the handler. + * @param addon Addon name. + * @returns Handler name. + */ + getHandlerNameFromUniqueName(uniqueName: string, addon: string): string { + return uniqueName.replace(addon + '_', ''); + } + } export const CoreSitePlugins = makeSingleton(CoreSitePluginsProvider); @@ -835,6 +864,7 @@ export type CoreSitePluginsHandlerCommonData = { styles?: { url?: string; version?: number; + downloadedStyles?: CorePromisedValue; // Added in the app. Path resolved when styles are downloaded. }; moodlecomponent?: string; };