MOBILE-2333 siteaddons: Run bootstrap JS and pass result to content JS

main
Dani Palou 2018-02-21 16:18:03 +01:00
parent 823ea35b69
commit 8e87a1ade9
19 changed files with 488 additions and 279 deletions

View File

@ -67,6 +67,7 @@ import { CoreUserModule } from '@core/user/user.module';
import { CoreGradesModule } from '@core/grades/grades.module'; import { CoreGradesModule } from '@core/grades/grades.module';
import { CoreSettingsModule } from '@core/settings/settings.module'; import { CoreSettingsModule } from '@core/settings/settings.module';
import { CoreSiteAddonsModule } from '@core/siteaddons/siteaddons.module'; import { CoreSiteAddonsModule } from '@core/siteaddons/siteaddons.module';
import { CoreCompileModule } from '@core/compile/compile.module';
// Addon modules. // Addon modules.
import { AddonCalendarModule } from '@addon/calendar/calendar.module'; import { AddonCalendarModule } from '@addon/calendar/calendar.module';
@ -146,6 +147,7 @@ export const CORE_PROVIDERS: any[] = [
CoreGradesModule, CoreGradesModule,
CoreSettingsModule, CoreSettingsModule,
CoreSiteAddonsModule, CoreSiteAddonsModule,
CoreCompileModule,
AddonCalendarModule, AddonCalendarModule,
AddonUserProfileFieldModule, AddonUserProfileFieldModule,
AddonFilesModule, AddonFilesModule,

View File

@ -1,200 +0,0 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 {
Component, NgModule, Input, OnInit, OnChanges, OnDestroy, ViewContainerRef, Compiler, ViewChild, ComponentRef, Injector,
SimpleChange, ChangeDetectorRef
} from '@angular/core';
import {
IonicModule, NavController, Platform, ActionSheetController, AlertController, LoadingController, ModalController,
PopoverController, ToastController
} from 'ionic-angular';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { CoreLoggerProvider } from '../../providers/logger';
// Import all modules that define components, directives and pipes.
import { CoreComponentsModule } from '../components.module';
import { CoreDirectivesModule } from '../../directives/directives.module';
import { CorePipesModule } from '../../pipes/pipes.module';
import { CoreCourseComponentsModule } from '../../core/course/components/components.module';
import { CoreCourseDirectivesModule } from '../../core/course/directives/directives.module';
import { CoreCoursesComponentsModule } from '../../core/courses/components/components.module';
import { CoreSiteAddonsDirectivesModule } from '../../core/siteaddons/directives/directives.module';
import { CoreSiteHomeComponentsModule } from '../../core/sitehome/components/components.module';
import { CoreUserComponentsModule } from '../../core/user/components/components.module';
// Import core providers.
import { CORE_PROVIDERS } from '../../app/app.module';
import { CORE_CONTENTLINKS_PROVIDERS } from '../../core/contentlinks/contentlinks.module';
import { CORE_COURSE_PROVIDERS } from '../../core/course/course.module';
import { CORE_COURSES_PROVIDERS } from '../../core/courses/courses.module';
import { CORE_FILEUPLOADER_PROVIDERS } from '../../core/fileuploader/fileuploader.module';
import { CORE_GRADES_PROVIDERS } from '../../core/grades/grades.module';
import { CORE_LOGIN_PROVIDERS } from '../../core/login/login.module';
import { CORE_MAINMENU_PROVIDERS } from '../../core/mainmenu/mainmenu.module';
import { CORE_SHAREDFILES_PROVIDERS } from '../../core/sharedfiles/sharedfiles.module';
import { CORE_SITEADDONS_PROVIDERS } from '../../core/siteaddons/siteaddons.module';
import { CORE_SITEHOME_PROVIDERS } from '../../core/sitehome/sitehome.module';
import { CORE_USER_PROVIDERS } from '../../core/user/user.module';
import { IONIC_NATIVE_PROVIDERS } from '../../core/emulator/emulator.module';
// Import other libraries and providers.
import { DomSanitizer } from '@angular/platform-browser';
import { FormBuilder, Validators } from '@angular/forms';
import { Http } from '@angular/http';
import { HttpClient } from '@angular/common/http';
import { CoreConfigConstants } from '../../configconstants';
import { CoreConstants } from '../../core/constants';
import * as moment from 'moment';
import { Md5 } from 'ts-md5/dist/md5';
/**
* This component has a behaviour similar to $compile for AngularJS. Given an HTML code, it will compile it so all its
* components and directives are instantiated.
*
* IMPORTANT: Use this component only if it is a must. It will create and compile a new component and module everytime this
* component is used, so it can slow down the app.
*
* This component isn't part of CoreComponentsModule to prevent circular dependencies. If you want to use it,
* you need to import CoreCompileHtmlComponentsModule.
*
* You can provide some Javascript code (as text) to be executed inside the component. The context of the javascript code (this)
* will be the component instance created to compile the template. This means your javascript code can interact with the template.
* The component instance will have most of the providers so you can use them in the javascript code. E.g. if you want to use
* CoreAppProvider, you can do it with "this.CoreAppProvider".
*/
@Component({
selector: 'core-compile-html',
template: '<ng-container #dynamicComponent></ng-container>'
})
export class CoreCompileHtmlComponent implements OnChanges, OnDestroy {
// List of imports for dynamic module. Since the template can have any component we need to import all core components modules.
protected IMPORTS = [
IonicModule, TranslateModule.forChild(), CoreComponentsModule, CoreDirectivesModule, CorePipesModule,
CoreCourseComponentsModule, CoreCoursesComponentsModule, CoreSiteHomeComponentsModule, CoreUserComponentsModule,
CoreCourseDirectivesModule, CoreSiteAddonsDirectivesModule
];
// Other Ionic/Angular providers that don't depend on where they are injected.
protected OTHER_PROVIDERS = [
TranslateService, Http, HttpClient, Platform, DomSanitizer, ActionSheetController, AlertController, LoadingController,
ModalController, PopoverController, ToastController, FormBuilder
];
@Input() text: string; // The HTML text to display.
@Input() javascript: string; // The javascript to execute in the component.
// Get the container where to put the content.
@ViewChild('dynamicComponent', { read: ViewContainerRef }) container: ViewContainerRef;
protected componentRef: ComponentRef<any>;
protected logger;
constructor(logger: CoreLoggerProvider, protected compiler: Compiler, protected injector: Injector,
protected cdr: ChangeDetectorRef, protected navCtrl: NavController) {
this.logger = logger.getInstance('CoreCompileHtmlComponent');
}
/**
* Detect changes on input properties.
*/
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
if ((changes.text || changes.javascript) && this.text) {
// Create a new component and a new module.
const component = this.createComponent(),
module = NgModule({imports: this.IMPORTS, declarations: [component]})(class {});
// Compile the module and the component.
this.compiler.compileModuleAndAllComponentsAsync(module).then((factories) => {
// Search the factory of the component we just created.
let componentFactory;
for (const i in factories.componentFactories) {
const factory = factories.componentFactories[i];
if (factory.componentType == component) {
componentFactory = factory;
break;
}
}
// Destroy previous components.
this.componentRef && this.componentRef.destroy();
// Create the component.
this.componentRef = this.container.createComponent(componentFactory);
});
}
}
/**
* Component destroyed.
*/
ngOnDestroy(): void {
this.componentRef && this.componentRef.destroy();
}
/**
* Create a dynamic component to compile the HTML and run the javascript.
*
* @return {any} The component class.
*/
protected createComponent(): any {
// tslint:disable: no-this-assignment
const compileInstance = this,
providers = (<any[]> CORE_PROVIDERS).concat(CORE_CONTENTLINKS_PROVIDERS).concat(CORE_COURSE_PROVIDERS)
.concat(CORE_COURSES_PROVIDERS).concat(CORE_FILEUPLOADER_PROVIDERS).concat(CORE_GRADES_PROVIDERS)
.concat(CORE_LOGIN_PROVIDERS).concat(CORE_MAINMENU_PROVIDERS).concat(CORE_SHAREDFILES_PROVIDERS)
.concat(CORE_SITEHOME_PROVIDERS).concat(CORE_SITEADDONS_PROVIDERS).concat(CORE_USER_PROVIDERS)
.concat(IONIC_NATIVE_PROVIDERS).concat(this.OTHER_PROVIDERS);
// Create the component, using the text as the template.
return Component({
template: this.text
})
(class CoreCompileHtmlFakeComponent implements OnInit {
constructor() {
// We cannot inject anything to this constructor. Use the Injector to inject all the providers into the instance.
for (const i in providers) {
const providerDef = providers[i];
if (typeof providerDef == 'function' && providerDef.name) {
try {
// Inject the provider to the instance. We use the class name as the property name.
this[providerDef.name] = compileInstance.injector.get(providerDef);
} catch (ex) {
compileInstance.logger.warn('Error injecting provider', providerDef.name, ex);
}
}
}
// Add some final components and providers.
this['ChangeDetectorRef'] = compileInstance.cdr;
this['NavController'] = compileInstance.navCtrl;
this['Validators'] = Validators;
this['CoreConfigConstants'] = CoreConfigConstants;
this['CoreConstants'] = CoreConstants;
this['moment'] = moment;
this['Md5'] = Md5;
this['componentContainer'] = compileInstance.container;
}
ngOnInit(): void {
// If there is some javascript to run, do it now.
if (compileInstance.javascript) {
// tslint:disable: no-eval
eval(compileInstance.javascript);
}
}
});
}
}

View File

@ -0,0 +1,27 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { CoreCompileProvider } from './providers/compile';
@NgModule({
declarations: [
],
imports: [
],
providers: [
CoreCompileProvider
]
})
export class CoreCompileModule { }

View File

@ -27,4 +27,4 @@ import { CoreCompileHtmlComponent } from './compile-html';
CoreCompileHtmlComponent CoreCompileHtmlComponent
] ]
}) })
export class CoreCompileHtmlComponentsModule {} export class CoreCompileHtmlComponentModule {}

View File

@ -0,0 +1,150 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 {
Component, NgModule, Input, OnInit, OnChanges, OnDestroy, ViewContainerRef, Compiler, ViewChild, ComponentRef,
SimpleChange, ChangeDetectorRef
} from '@angular/core';
import { IonicModule, NavController } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreCompileProvider } from '../../../compile/providers/compile';
// Import all modules that define components, directives and pipes.
import { CoreComponentsModule } from '../../../../components/components.module';
import { CoreDirectivesModule } from '../../../../directives/directives.module';
import { CorePipesModule } from '../../../../pipes/pipes.module';
import { CoreCourseComponentsModule } from '../../../course/components/components.module';
import { CoreCourseDirectivesModule } from '../../../course/directives/directives.module';
import { CoreCoursesComponentsModule } from '../../../courses/components/components.module';
import { CoreSiteAddonsDirectivesModule } from '../../../siteaddons/directives/directives.module';
import { CoreSiteHomeComponentsModule } from '../../../sitehome/components/components.module';
import { CoreUserComponentsModule } from '../../../user/components/components.module';
/**
* This component has a behaviour similar to $compile for AngularJS. Given an HTML code, it will compile it so all its
* components and directives are instantiated.
*
* IMPORTANT: Use this component only if it is a must. It will create and compile a new component and module everytime this
* component is used, so it can slow down the app.
*
* This component has its own module to prevent circular dependencies. If you want to use it,
* you need to import CoreCompileHtmlComponentModule.
*
* You can provide some Javascript code (as text) to be executed inside the component. The context of the javascript code (this)
* will be the component instance created to compile the template. This means your javascript code can interact with the template.
* The component instance will have most of the providers so you can use them in the javascript code. E.g. if you want to use
* CoreAppProvider, you can do it with "this.CoreAppProvider".
*/
@Component({
selector: 'core-compile-html',
template: '<ng-container #dynamicComponent></ng-container>'
})
export class CoreCompileHtmlComponent implements OnChanges, OnDestroy {
// List of imports for dynamic module. Since the template can have any component we need to import all core components modules.
protected IMPORTS = [
IonicModule, TranslateModule.forChild(), CoreComponentsModule, CoreDirectivesModule, CorePipesModule,
CoreCourseComponentsModule, CoreCoursesComponentsModule, CoreSiteHomeComponentsModule, CoreUserComponentsModule,
CoreCourseDirectivesModule, CoreSiteAddonsDirectivesModule
];
@Input() text: string; // The HTML text to display.
@Input() javascript: string; // The Javascript to execute in the component.
@Input() jsData; // Data to pass to the fake component.
// Get the container where to put the content.
@ViewChild('dynamicComponent', { read: ViewContainerRef }) container: ViewContainerRef;
protected componentRef: ComponentRef<any>;
constructor(protected compileProvider: CoreCompileProvider, protected compiler: Compiler,
protected cdr: ChangeDetectorRef, protected navCtrl: NavController) { }
/**
* Detect changes on input properties.
*/
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
if ((changes.text || changes.javascript) && this.text) {
// Create a new component and a new module.
const component = this.createComponent(),
module = NgModule({imports: this.IMPORTS, declarations: [component]})(class {});
// Compile the module and the component.
this.compiler.compileModuleAndAllComponentsAsync(module).then((factories) => {
// Search the factory of the component we just created.
let componentFactory;
for (const i in factories.componentFactories) {
const factory = factories.componentFactories[i];
if (factory.componentType == component) {
componentFactory = factory;
break;
}
}
// Destroy previous components.
this.componentRef && this.componentRef.destroy();
// Create the component.
this.componentRef = this.container.createComponent(componentFactory);
});
}
}
/**
* Component destroyed.
*/
ngOnDestroy(): void {
this.componentRef && this.componentRef.destroy();
}
/**
* Create a dynamic component to compile the HTML and run the javascript.
*
* @return {any} The component class.
*/
protected createComponent(): any {
// tslint:disable: no-this-assignment
const compileInstance = this;
// Create the component, using the text as the template.
return Component({
template: this.text
})
(class CoreCompileHtmlFakeComponent implements OnInit {
constructor() {
// If there is some javascript to run, prepare the instance.
if (compileInstance.javascript) {
compileInstance.compileProvider.injectLibraries(this);
// Add some more components and classes.
this['ChangeDetectorRef'] = compileInstance.cdr;
this['NavController'] = compileInstance.navCtrl;
this['componentContainer'] = compileInstance.container;
// Add the data passed to the component.
for (const name in compileInstance.jsData) {
this[name] = compileInstance.jsData[name];
}
}
}
ngOnInit(): void {
// If there is some javascript to run, do it now.
if (compileInstance.javascript) {
compileInstance.compileProvider.executeJavascript(this, compileInstance.javascript);
}
}
});
}
}

View File

@ -0,0 +1,142 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { Injectable, Injector } from '@angular/core';
import {
Platform, ActionSheetController, AlertController, LoadingController, ModalController, PopoverController, ToastController
} from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { CoreLoggerProvider } from '../../../providers/logger';
// Import core providers.
import { CORE_PROVIDERS } from '../../../app/app.module';
import { CORE_CONTENTLINKS_PROVIDERS } from '../../contentlinks/contentlinks.module';
import { CORE_COURSE_PROVIDERS } from '../../course/course.module';
import { CORE_COURSES_PROVIDERS } from '../../courses/courses.module';
import { CORE_FILEUPLOADER_PROVIDERS } from '../../fileuploader/fileuploader.module';
import { CORE_GRADES_PROVIDERS } from '../../grades/grades.module';
import { CORE_LOGIN_PROVIDERS } from '../../login/login.module';
import { CORE_MAINMENU_PROVIDERS } from '../../mainmenu/mainmenu.module';
import { CORE_SHAREDFILES_PROVIDERS } from '../../sharedfiles/sharedfiles.module';
import { CORE_SITEHOME_PROVIDERS } from '../../sitehome/sitehome.module';
import { CORE_USER_PROVIDERS } from '../../user/user.module';
import { IONIC_NATIVE_PROVIDERS } from '../../emulator/emulator.module';
// Import only this provider to prevent circular dependencies.
import { CoreSiteAddonsProvider } from '../../siteaddons/providers/siteaddons';
// Import other libraries and providers.
import { DomSanitizer } from '@angular/platform-browser';
import { FormBuilder, Validators } from '@angular/forms';
import { Http } from '@angular/http';
import { HttpClient } from '@angular/common/http';
import { CoreConfigConstants } from '../../../configconstants';
import { CoreConstants } from '../../constants';
import * as moment from 'moment';
import { Md5 } from 'ts-md5/dist/md5';
// Import core classes that can be useful for site addons.
import { CoreSyncBaseProvider } from '../../../classes/base-sync';
import { CoreCache } from '../../../classes/cache';
import { CoreDelegate } from '../../../classes/delegate';
import { CoreContentLinksHandlerBase } from '../../contentlinks/classes/base-handler';
import { CoreContentLinksModuleGradeHandler } from '../../contentlinks/classes/module-grade-handler';
import { CoreContentLinksModuleIndexHandler } from '../../contentlinks/classes/module-index-handler';
import { CoreCourseModulePrefetchHandlerBase } from '../../course/classes/module-prefetch-handler';
/**
* Service to provide functionalities regarding compiling dynamic HTML and Javascript.
*/
@Injectable()
export class CoreCompileProvider {
protected logger;
// Other Ionic/Angular providers that don't depend on where they are injected.
protected OTHER_PROVIDERS = [
TranslateService, Http, HttpClient, Platform, DomSanitizer, ActionSheetController, AlertController, LoadingController,
ModalController, PopoverController, ToastController, FormBuilder
];
constructor(protected injector: Injector, logger: CoreLoggerProvider) {
this.logger = logger.getInstance('CoreCompileProvider');
}
/**
* Eval some javascript using the context of the function.
*
* @param {string} javascript The javascript to eval.
* @return {any} Result of the eval.
*/
protected evalInContext(javascript: string): any {
// tslint:disable: no-eval
return eval(javascript);
}
/**
* Execute some javascript code, using a certain instance as the context.
*
* @param {any} instance Instance to use as the context. In the JS code, "this" will be this instance.
* @param {string} javascript The javascript code to eval.
* @return {any} Result of the javascript execution.
*/
executeJavascript(instance: any, javascript: string): any {
try {
return this.evalInContext.call(instance, javascript);
} catch (ex) {
this.logger.error('Error evaluating javascript', ex);
}
}
/**
* Inject all the core libraries in a certain object.
*
* @param {any} instance The instance where to inject the libraries.
*/
injectLibraries(instance: any): void {
const providers = (<any[]> CORE_PROVIDERS).concat(CORE_CONTENTLINKS_PROVIDERS).concat(CORE_COURSE_PROVIDERS)
.concat(CORE_COURSES_PROVIDERS).concat(CORE_FILEUPLOADER_PROVIDERS).concat(CORE_GRADES_PROVIDERS)
.concat(CORE_LOGIN_PROVIDERS).concat(CORE_MAINMENU_PROVIDERS).concat(CORE_SHAREDFILES_PROVIDERS)
.concat(CORE_SITEHOME_PROVIDERS).concat([CoreSiteAddonsProvider]).concat(CORE_USER_PROVIDERS)
.concat(IONIC_NATIVE_PROVIDERS).concat(this.OTHER_PROVIDERS);
// We cannot inject anything to this constructor. Use the Injector to inject all the providers into the instance.
for (const i in providers) {
const providerDef = providers[i];
if (typeof providerDef == 'function' && providerDef.name) {
try {
// Inject the provider to the instance. We use the class name as the property name.
instance[providerDef.name] = this.injector.get(providerDef);
} catch (ex) {
this.logger.warn('Error injecting provider', providerDef.name, ex);
}
}
}
// Add some final classes.
instance['injector'] = this.injector;
instance['Validators'] = Validators;
instance['CoreConfigConstants'] = CoreConfigConstants;
instance['CoreConstants'] = CoreConstants;
instance['moment'] = moment;
instance['Md5'] = Md5;
instance['CoreSyncBaseProvider'] = CoreSyncBaseProvider;
instance['CoreCache'] = CoreCache;
instance['CoreDelegate'] = CoreDelegate;
instance['CoreContentLinksHandlerBase'] = CoreContentLinksHandlerBase;
instance['CoreContentLinksModuleGradeHandler'] = CoreContentLinksModuleGradeHandler;
instance['CoreContentLinksModuleIndexHandler'] = CoreContentLinksModuleIndexHandler;
instance['CoreCourseModulePrefetchHandlerBase'] = CoreCourseModulePrefetchHandlerBase;
}
}

View File

@ -1,3 +1,3 @@
<core-loading [hideUntil]="dataLoaded"> <core-loading [hideUntil]="dataLoaded">
<core-compile-html [text]="content" [javascript]="javascript"></core-compile-html> <core-compile-html [text]="content" [javascript]="javascript" [jsData]="bootstrapResult"></core-compile-html>
</core-loading> </core-loading>

View File

@ -28,6 +28,7 @@ export class CoreSiteAddonsAddonContentComponent implements OnInit {
@Input() component: string; @Input() component: string;
@Input() method: string; @Input() method: string;
@Input() args: any; @Input() args: any;
@Input() bootstrapResult: any; // Result of the bootstrap JS of the handler.
@Output() onContentLoaded?: EventEmitter<boolean>; // Emits an event when the content is loaded. @Output() onContentLoaded?: EventEmitter<boolean>; // Emits an event when the content is loaded.
@Output() onLoadingContent?: EventEmitter<boolean>; // Emits an event when starts to load the content. @Output() onLoadingContent?: EventEmitter<boolean>; // Emits an event when starts to load the content.

View File

@ -17,7 +17,7 @@ import { CommonModule } from '@angular/common';
import { IonicModule } from 'ionic-angular'; import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '../../../components/components.module'; import { CoreComponentsModule } from '../../../components/components.module';
import { CoreCompileHtmlComponentsModule } from '../../../components/compile-html/compile-html.module'; import { CoreCompileHtmlComponentModule } from '../../compile/components/compile-html/compile-html.module';
import { CoreSiteAddonsAddonContentComponent } from './addon-content/addon-content'; import { CoreSiteAddonsAddonContentComponent } from './addon-content/addon-content';
import { CoreSiteAddonsModuleIndexComponent } from './module-index/module-index'; import { CoreSiteAddonsModuleIndexComponent } from './module-index/module-index';
@ -30,7 +30,7 @@ import { CoreSiteAddonsModuleIndexComponent } from './module-index/module-index'
CommonModule, CommonModule,
IonicModule, IonicModule,
CoreComponentsModule, CoreComponentsModule,
CoreCompileHtmlComponentsModule, CoreCompileHtmlComponentModule,
TranslateModule.forChild() TranslateModule.forChild()
], ],
providers: [ providers: [

View File

@ -9,4 +9,4 @@
</core-context-menu> </core-context-menu>
</core-navbar-buttons> </core-navbar-buttons>
<core-site-addons-addon-content *ngIf="component && method" [component]="component" [method]="method" [args]="args" (onContentLoaded)="contentLoaded($event)" (onLoadingContent)="contentLoading($event)"></core-site-addons-addon-content> <core-site-addons-addon-content *ngIf="component && method" [component]="component" [method]="method" [args]="args" [bootstrapResult]="bootstrapResult" (onContentLoaded)="contentLoaded($event)" (onLoadingContent)="contentLoading($event)"></core-site-addons-addon-content>

View File

@ -37,6 +37,7 @@ export class CoreSiteAddonsModuleIndexComponent implements OnInit, OnDestroy, Co
component: string; component: string;
method: string; method: string;
args: any; args: any;
bootstrapResult: any;
// Data for context menu. // Data for context menu.
externalUrl: string; externalUrl: string;
@ -60,7 +61,7 @@ export class CoreSiteAddonsModuleIndexComponent implements OnInit, OnDestroy, Co
this.refreshIcon = 'spinner'; this.refreshIcon = 'spinner';
if (this.module) { if (this.module) {
const handler = this.siteAddonsProvider.getModuleSiteAddonHandler(this.module.modname); const handler = this.siteAddonsProvider.getSiteAddonHandler(this.module.modname);
if (handler) { if (handler) {
this.component = handler.addon.component; this.component = handler.addon.component;
this.method = handler.handlerSchema.method; this.method = handler.handlerSchema.method;
@ -68,6 +69,7 @@ export class CoreSiteAddonsModuleIndexComponent implements OnInit, OnDestroy, Co
courseid: this.courseId, courseid: this.courseId,
cmid: this.module.id cmid: this.module.id
}; };
this.bootstrapResult = handler.bootstrapResult;
} }
// Get the data for the context menu. // Get the data for the context menu.

View File

@ -91,7 +91,8 @@ export class CoreSiteAddonsCallWSNewContentDirective extends CoreSiteAddonsCallW
title: this.title, title: this.title,
component: this.component, component: this.component,
method: this.method, method: this.method,
args: args args: args,
bootstrapResult: this.parentContent && this.parentContent.bootstrapResult
}); });
} }
} }

View File

@ -88,7 +88,8 @@ export class CoreSiteAddonsNewContentDirective implements OnInit {
title: this.title, title: this.title,
component: this.component, component: this.component,
method: this.method, method: this.method,
args: args args: args,
bootstrapResult: this.parentContent && this.parentContent.bootstrapResult
}); });
} }
}); });

View File

@ -11,5 +11,5 @@
<ion-refresher [enabled]="content && content.dataLoaded" (ionRefresh)="refreshData($event)"> <ion-refresher [enabled]="content && content.dataLoaded" (ionRefresh)="refreshData($event)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher> </ion-refresher>
<core-site-addons-addon-content [component]="component" [method]="method" [args]="args"></core-site-addons-addon-content> <core-site-addons-addon-content [component]="component" [method]="method" [args]="args" [bootstrapResult]="bootstrapResult"></core-site-addons-addon-content>
</ion-content> </ion-content>

View File

@ -32,12 +32,14 @@ export class CoreSiteAddonsAddonPage {
component: string; component: string;
method: string; method: string;
args: any; args: any;
bootstrapResult: any;
constructor(params: NavParams) { constructor(params: NavParams) {
this.title = params.get('title'); this.title = params.get('title');
this.component = params.get('component'); this.component = params.get('component');
this.method = params.get('method'); this.method = params.get('method');
this.args = params.get('args'); this.args = params.get('args');
this.bootstrapResult = params.get('bootstrapResult');
} }
/** /**

View File

@ -18,16 +18,18 @@ import { CoreLangProvider } from '../../../providers/lang';
import { CoreLoggerProvider } from '../../../providers/logger'; import { CoreLoggerProvider } from '../../../providers/logger';
import { CoreSite } from '../../../classes/site'; import { CoreSite } from '../../../classes/site';
import { CoreSitesProvider } from '../../../providers/sites'; import { CoreSitesProvider } from '../../../providers/sites';
import { CoreMainMenuDelegate, CoreMainMenuHandler, CoreMainMenuHandlerData } from '../../../core/mainmenu/providers/delegate'; import { CoreUtilsProvider } from '../../../providers/utils/utils';
import { CoreMainMenuDelegate, CoreMainMenuHandler, CoreMainMenuHandlerData } from '../../mainmenu/providers/delegate';
import { import {
CoreCourseModuleDelegate, CoreCourseModuleHandler, CoreCourseModuleHandlerData CoreCourseModuleDelegate, CoreCourseModuleHandler, CoreCourseModuleHandlerData
} from '../../../core/course/providers/module-delegate'; } from '../../course/providers/module-delegate';
import { CoreCourseModulePrefetchDelegate } from '../../../core/course/providers/module-prefetch-delegate'; import { CoreCourseModulePrefetchDelegate } from '../../course/providers/module-prefetch-delegate';
import { CoreUserDelegate, CoreUserProfileHandler, CoreUserProfileHandlerData } from '../../../core/user/providers/user-delegate'; import { CoreUserDelegate, CoreUserProfileHandler, CoreUserProfileHandlerData } from '../../user/providers/user-delegate';
import { CoreDelegateHandler } from '../../../classes/delegate'; import { CoreDelegateHandler } from '../../../classes/delegate';
import { CoreSiteAddonsModuleIndexComponent } from '../components/module-index/module-index'; import { CoreSiteAddonsModuleIndexComponent } from '../components/module-index/module-index';
import { CoreSiteAddonsProvider } from './siteaddons'; import { CoreSiteAddonsProvider } from './siteaddons';
import { CoreSiteAddonsModulePrefetchHandler } from '../classes/module-prefetch-handler'; import { CoreSiteAddonsModulePrefetchHandler } from '../classes/module-prefetch-handler';
import { CoreCompileProvider } from '../../compile/providers/compile';
/** /**
* Helper service to provide functionalities regarding site addons. It basically has the features to load and register site * Helper service to provide functionalities regarding site addons. It basically has the features to load and register site
@ -42,10 +44,42 @@ export class CoreSiteAddonsHelperProvider {
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private injector: Injector, constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private injector: Injector,
private mainMenuDelegate: CoreMainMenuDelegate, private moduleDelegate: CoreCourseModuleDelegate, private mainMenuDelegate: CoreMainMenuDelegate, private moduleDelegate: CoreCourseModuleDelegate,
private userDelegate: CoreUserDelegate, private langProvider: CoreLangProvider, private userDelegate: CoreUserDelegate, private langProvider: CoreLangProvider,
private siteAddonsProvider: CoreSiteAddonsProvider, private prefetchDelegate: CoreCourseModulePrefetchDelegate) { private siteAddonsProvider: CoreSiteAddonsProvider, private prefetchDelegate: CoreCourseModulePrefetchDelegate,
private compileProvider: CoreCompileProvider, private utils: CoreUtilsProvider) {
this.logger = logger.getInstance('CoreSiteAddonsHelperProvider'); this.logger = logger.getInstance('CoreSiteAddonsHelperProvider');
} }
/**
* Bootstrap a handler if it has some bootstrap JS.
*
* @param {any} addon Data of the addon.
* @param {string} handlerName Name of the handler in the addon.
* @param {any} handlerSchema Data about the handler.
* @return {Promise<any>} Promise resolved when done. The resolve param is the result of the javascript execution (if any).
*/
protected bootstrapHandler(addon: any, handlerName: string, handlerSchema: any): Promise<any> {
if (!handlerSchema.bootstrap) {
return Promise.resolve();
}
const siteId = this.sitesProvider.getCurrentSiteId(),
preSets = {getFromCache: false}; // Try to ignore cache.
return this.siteAddonsProvider.getContent(addon.component, handlerSchema.bootstrap, {}, preSets).then((result) => {
if (!result.javascript || this.sitesProvider.getCurrentSiteId() != siteId) {
// No javascript or site has changed, stop.
return;
}
// Create a "fake" instance to hold all the libraries.
const instance = {};
this.compileProvider.injectLibraries(instance);
// Now execute the javascript using this instance.
return this.compileProvider.executeJavascript(instance, result.javascript);
});
}
/** /**
* Create a base handler for a site addon. * Create a base handler for a site addon.
* *
@ -86,17 +120,6 @@ export class CoreSiteAddonsHelperProvider {
return this.getHandlerPrefixForStrings(handlerName) + key; return this.getHandlerPrefixForStrings(handlerName) + key;
} }
/**
* Get the unique name of a handler (addon + handler).
*
* @param {any} addon Data of the addon.
* @param {string} handlerName Name of the handler inside the addon.
* @return {string} Unique name.
*/
protected getHandlerUniqueName(addon: any, handlerName: string): string {
return addon.addon + '_' + handlerName;
}
/** /**
* Check if a certain addon is a site addon and it's enabled in a certain site. * Check if a certain addon is a site addon and it's enabled in a certain site.
* *
@ -134,7 +157,7 @@ export class CoreSiteAddonsHelperProvider {
} }
for (const lang in handlerSchema.lang) { for (const lang in handlerSchema.lang) {
const prefix = this.getHandlerPrefixForStrings(this.getHandlerUniqueName(addon, handlerName)); const prefix = this.getHandlerPrefixForStrings(this.siteAddonsProvider.getHandlerUniqueName(addon, handlerName));
this.langProvider.addSiteAddonsStrings(lang, handlerSchema.lang[lang], prefix); this.langProvider.addSiteAddonsStrings(lang, handlerSchema.lang[lang], prefix);
} }
@ -144,8 +167,11 @@ export class CoreSiteAddonsHelperProvider {
* Load a site addon. * Load a site addon.
* *
* @param {any} addon Data of the addon. * @param {any} addon Data of the addon.
* @return {Promise<any>} Promise resolved when loaded.
*/ */
loadSiteAddon(addon: any): void { loadSiteAddon(addon: any): Promise<any> {
const promises = [];
try { try {
if (!addon.parsedHandlers) { if (!addon.parsedHandlers) {
addon.parsedHandlers = JSON.parse(addon.handlers); addon.parsedHandlers = JSON.parse(addon.handlers);
@ -153,11 +179,13 @@ export class CoreSiteAddonsHelperProvider {
// Register all the handlers. // Register all the handlers.
for (const name in addon.parsedHandlers) { for (const name in addon.parsedHandlers) {
this.registerHandler(addon, name, addon.parsedHandlers[name]); promises.push(this.registerHandler(addon, name, addon.parsedHandlers[name]));
} }
} catch (ex) { } catch (ex) {
this.logger.warn('Error parsing site addon', ex); this.logger.warn('Error parsing site addon', ex);
} }
return this.utils.allPromises(promises);
} }
/** /**
@ -166,26 +194,42 @@ export class CoreSiteAddonsHelperProvider {
* @param {any} addon Data of the addon. * @param {any} addon Data of the addon.
* @param {string} handlerName Name of the handler in the addon. * @param {string} handlerName Name of the handler in the addon.
* @param {any} handlerSchema Data about the handler. * @param {any} handlerSchema Data about the handler.
* @return {Promise<any>} Promise resolved when done.
*/ */
registerHandler(addon: any, handlerName: string, handlerSchema: any): void { registerHandler(addon: any, handlerName: string, handlerSchema: any): Promise<any> {
this.loadHandlerLangStrings(addon, handlerName, handlerSchema); this.loadHandlerLangStrings(addon, handlerName, handlerSchema);
switch (handlerSchema.delegate) { // Wait for the bootstrap JS to be executed.
case 'CoreMainMenuDelegate': return this.bootstrapHandler(addon, handlerName, handlerSchema).then((result) => {
this.registerMainMenuHandler(addon, handlerName, handlerSchema); let uniqueName;
break;
case 'CoreCourseModuleDelegate': switch (handlerSchema.delegate) {
this.registerModuleHandler(addon, handlerName, handlerSchema); case 'CoreMainMenuDelegate':
break; uniqueName = this.registerMainMenuHandler(addon, handlerName, handlerSchema, result);
break;
case 'CoreUserDelegate': case 'CoreCourseModuleDelegate':
this.registerUserProfileHandler(addon, handlerName, handlerSchema); uniqueName = this.registerModuleHandler(addon, handlerName, handlerSchema, result);
break; break;
default: case 'CoreUserDelegate':
// Nothing to do. uniqueName = this.registerUserProfileHandler(addon, handlerName, handlerSchema, result);
} break;
default:
// Nothing to do.
}
if (uniqueName) {
// Store the handler data.
this.siteAddonsProvider.setSiteAddonHandler(uniqueName, {
addon: addon,
handlerName: handlerName,
handlerSchema: handlerSchema,
bootstrapResult: result
});
}
});
} }
/** /**
@ -194,15 +238,18 @@ export class CoreSiteAddonsHelperProvider {
* @param {any} addon Data of the addon. * @param {any} addon Data of the addon.
* @param {string} handlerName Name of the handler in the addon. * @param {string} handlerName Name of the handler in the addon.
* @param {any} handlerSchema Data about the handler. * @param {any} handlerSchema Data about the handler.
* @param {any} [bootstrapResult] Result of executing the bootstrap JS.
* @return {string} A string to identify the handler.
*/ */
protected registerMainMenuHandler(addon: any, handlerName: string, handlerSchema: any): void { protected registerMainMenuHandler(addon: any, handlerName: string, handlerSchema: any, bootstrapResult?: any): string {
if (!handlerSchema || !handlerSchema.displaydata) { if (!handlerSchema || !handlerSchema.displaydata) {
// Required data not provided, stop. // Required data not provided, stop.
return; return;
} }
// Create the base handler. // Create the base handler.
const baseHandler = this.getBaseHandler(this.getHandlerUniqueName(addon, handlerName)), const uniqueName = this.siteAddonsProvider.getHandlerUniqueName(addon, handlerName),
baseHandler = this.getBaseHandler(uniqueName),
prefixedTitle = this.getHandlerPrefixedString(baseHandler.name, handlerSchema.displaydata.title); prefixedTitle = this.getHandlerPrefixedString(baseHandler.name, handlerSchema.displaydata.title);
let mainMenuHandler: CoreMainMenuHandler; let mainMenuHandler: CoreMainMenuHandler;
@ -219,12 +266,15 @@ export class CoreSiteAddonsHelperProvider {
title: prefixedTitle, title: prefixedTitle,
component: addon.component, component: addon.component,
method: handlerSchema.method, method: handlerSchema.method,
bootstrapResult: bootstrapResult
} }
}; };
} }
}); });
this.mainMenuDelegate.registerHandler(mainMenuHandler); this.mainMenuDelegate.registerHandler(mainMenuHandler);
return uniqueName;
} }
/** /**
@ -233,8 +283,10 @@ export class CoreSiteAddonsHelperProvider {
* @param {any} addon Data of the addon. * @param {any} addon Data of the addon.
* @param {string} handlerName Name of the handler in the addon. * @param {string} handlerName Name of the handler in the addon.
* @param {any} handlerSchema Data about the handler. * @param {any} handlerSchema Data about the handler.
* @param {any} [bootstrapResult] Result of executing the bootstrap JS.
* @return {string} A string to identify the handler.
*/ */
protected registerModuleHandler(addon: any, handlerName: string, handlerSchema: any): void { protected registerModuleHandler(addon: any, handlerName: string, handlerSchema: any, bootstrapResult?: any): string {
if (!handlerSchema || !handlerSchema.displaydata) { if (!handlerSchema || !handlerSchema.displaydata) {
// Required data not provided, stop. // Required data not provided, stop.
return; return;
@ -243,16 +295,10 @@ export class CoreSiteAddonsHelperProvider {
// Create the base handler. // Create the base handler.
const modName = addon.component.replace('mod_', ''), const modName = addon.component.replace('mod_', ''),
baseHandler = this.getBaseHandler(modName), baseHandler = this.getBaseHandler(modName),
hasOfflineFunctions = !!(handlerSchema.offlinefunctions && Object.keys(handlerSchema.offlinefunctions).length); hasOfflineFunctions = !!(handlerSchema.offlinefunctions && Object.keys(handlerSchema.offlinefunctions).length),
showDowloadButton = handlerSchema.downloadbutton;
let moduleHandler: CoreCourseModuleHandler; let moduleHandler: CoreCourseModuleHandler;
// Store the handler data.
this.siteAddonsProvider.setModuleSiteAddonHandler(modName, {
addon: addon,
handlerName: handlerName,
handlerSchema: handlerSchema
});
// Extend the base handler, adding the properties required by the delegate. // Extend the base handler, adding the properties required by the delegate.
moduleHandler = Object.assign(baseHandler, { moduleHandler = Object.assign(baseHandler, {
getData: (module: any, courseId: number, sectionId: number): CoreCourseModuleHandlerData => { getData: (module: any, courseId: number, sectionId: number): CoreCourseModuleHandlerData => {
@ -260,7 +306,7 @@ export class CoreSiteAddonsHelperProvider {
title: module.name, title: module.name,
icon: handlerSchema.displaydata.icon, icon: handlerSchema.displaydata.icon,
class: handlerSchema.displaydata.class, class: handlerSchema.displaydata.class,
showDownloadButton: hasOfflineFunctions, showDownloadButton: typeof showDowloadButton != 'undefined' ? showDowloadButton : hasOfflineFunctions,
action: (event: Event, navCtrl: NavController, module: any, courseId: number, options: NavOptions): void => { action: (event: Event, navCtrl: NavController, module: any, courseId: number, options: NavOptions): void => {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
@ -285,6 +331,8 @@ export class CoreSiteAddonsHelperProvider {
} }
this.moduleDelegate.registerHandler(moduleHandler); this.moduleDelegate.registerHandler(moduleHandler);
return modName;
} }
/** /**
@ -293,15 +341,18 @@ export class CoreSiteAddonsHelperProvider {
* @param {any} addon Data of the addon. * @param {any} addon Data of the addon.
* @param {string} handlerName Name of the handler in the addon. * @param {string} handlerName Name of the handler in the addon.
* @param {any} handlerSchema Data about the handler. * @param {any} handlerSchema Data about the handler.
* @param {any} [bootstrapResult] Result of executing the bootstrap JS.
* @return {string} A string to identify the handler.
*/ */
protected registerUserProfileHandler(addon: any, handlerName: string, handlerSchema: any): void { protected registerUserProfileHandler(addon: any, handlerName: string, handlerSchema: any, bootstrapResult?: any): string {
if (!handlerSchema || !handlerSchema.displaydata) { if (!handlerSchema || !handlerSchema.displaydata) {
// Required data not provided, stop. // Required data not provided, stop.
return; return;
} }
// Create the base handler. // Create the base handler.
const baseHandler = this.getBaseHandler(this.getHandlerUniqueName(addon, handlerName)), const uniqueName = this.siteAddonsProvider.getHandlerUniqueName(addon, handlerName),
baseHandler = this.getBaseHandler(uniqueName),
prefixedTitle = this.getHandlerPrefixedString(baseHandler.name, handlerSchema.displaydata.title); prefixedTitle = this.getHandlerPrefixedString(baseHandler.name, handlerSchema.displaydata.title);
let userHandler: CoreUserProfileHandler; let userHandler: CoreUserProfileHandler;
@ -332,7 +383,8 @@ export class CoreSiteAddonsHelperProvider {
args: { args: {
courseid: courseId, courseid: courseId,
userid: user.id userid: user.id
} },
bootstrapResult: bootstrapResult
}); });
} }
}; };
@ -340,5 +392,7 @@ export class CoreSiteAddonsHelperProvider {
}); });
this.userDelegate.registerHandler(userHandler); this.userDelegate.registerHandler(userHandler);
return uniqueName;
} }
} }

View File

@ -23,9 +23,9 @@ import { CoreUtilsProvider } from '../../../providers/utils/utils';
import { CoreConfigConstants } from '../../../configconstants'; import { CoreConfigConstants } from '../../../configconstants';
/** /**
* Handler of a site addon representing a module. * Handler of a site addon.
*/ */
export interface CoreSiteAddonsModuleHandler { export interface CoreSiteAddonsHandler {
/** /**
* The site addon data. * The site addon data.
* @type {any} * @type {any}
@ -43,6 +43,12 @@ export interface CoreSiteAddonsModuleHandler {
* @type {any} * @type {any}
*/ */
handlerSchema: any; handlerSchema: any;
/**
* Result of executing the bootstrap JS.
* @type {any}
*/
bootstrapResult?: any;
} }
export interface CoreSiteAddonsGetContentResult { export interface CoreSiteAddonsGetContentResult {
@ -79,7 +85,7 @@ export class CoreSiteAddonsProvider {
protected ROOT_CACHE_KEY = 'CoreSiteAddons:'; protected ROOT_CACHE_KEY = 'CoreSiteAddons:';
protected logger; protected logger;
protected moduleSiteAddons: {[modName: string]: CoreSiteAddonsModuleHandler} = {}; protected siteAddons: {[name: string]: CoreSiteAddonsHandler} = {}; // Site addons registered.
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider, constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider,
private langProvider: CoreLangProvider, private appProvider: CoreAppProvider, private platform: Platform) { private langProvider: CoreLangProvider, private appProvider: CoreAppProvider, private platform: Platform) {
@ -179,10 +185,12 @@ export class CoreSiteAddonsProvider {
* @param {string} component Component where the class is. E.g. mod_assign. * @param {string} component Component where the class is. E.g. mod_assign.
* @param {string} method Method to execute in the class. * @param {string} method Method to execute in the class.
* @param {any} args The params for the method. * @param {any} args The params for the method.
* @param {CoreSiteWSPreSets} [preSets] Extra options.
* @param {string} [siteId] Site ID. If not defined, current site. * @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<CoreSiteAddonsGetContentResult>} Promise resolved with the result. * @return {Promise<CoreSiteAddonsGetContentResult>} Promise resolved with the result.
*/ */
getContent(component: string, method: string, args: any, siteId?: string): Promise<CoreSiteAddonsGetContentResult> { getContent(component: string, method: string, args: any, preSets?: CoreSiteWSPreSets, siteId?: string)
: Promise<CoreSiteAddonsGetContentResult> {
this.logger.debug(`Get content for component '${component}' and method '${method}'`); this.logger.debug(`Get content for component '${component}' and method '${method}'`);
return this.sitesProvider.getSite(siteId).then((site) => { return this.sitesProvider.getSite(siteId).then((site) => {
@ -194,10 +202,11 @@ export class CoreSiteAddonsProvider {
component: component, component: component,
method: method, method: method,
args: this.utils.objectToArrayOfObjects(argsToSend, 'name', 'value', true) args: this.utils.objectToArrayOfObjects(argsToSend, 'name', 'value', true)
}, preSets = {
cacheKey: this.getContentCacheKey(component, method, args)
}; };
preSets = preSets || {};
preSets.cacheKey = this.getContentCacheKey(component, method, args);
return this.sitesProvider.getCurrentSite().read('tool_mobile_get_content', data, preSets); return this.sitesProvider.getCurrentSite().read('tool_mobile_get_content', data, preSets);
}).then((result) => { }).then((result) => {
if (result.otherdata) { if (result.otherdata) {
@ -226,13 +235,24 @@ export class CoreSiteAddonsProvider {
} }
/** /**
* Get the site addon handler for a certain module. * Get the unique name of a handler (addon + handler).
* *
* @param {string} modName Name of the module. * @param {any} addon Data of the addon.
* @return {CoreSiteAddonsModuleHandler} Handler. * @param {string} handlerName Name of the handler inside the addon.
* @return {string} Unique name.
*/ */
getModuleSiteAddonHandler(modName: string): CoreSiteAddonsModuleHandler { getHandlerUniqueName(addon: any, handlerName: string): string {
return this.moduleSiteAddons[modName]; return addon.addon + '_' + handlerName;
}
/**
* Get a site addon handler.
*
* @param {string} name Unique name of the handler.
* @return {CoreSiteAddonsHandler} Handler.
*/
getSiteAddonHandler(name: string): CoreSiteAddonsHandler {
return this.siteAddons[name];
} }
/** /**
@ -328,12 +348,12 @@ export class CoreSiteAddonsProvider {
} }
/** /**
* Set the site addon handler for a certain module. * Store a site addon handler.
* *
* @param {string} modName Name of the module. * @param {string} name A unique name to identify the handler.
* @param {CoreSiteAddonsModuleHandler} handler Handler to set. * @param {CoreSiteAddonsHandler} handler Handler to set.
*/ */
setModuleSiteAddonHandler(modName: string, handler: CoreSiteAddonsModuleHandler): void { setSiteAddonHandler(name: string, handler: CoreSiteAddonsHandler): void {
this.moduleSiteAddons[modName] = handler; this.siteAddons[name] = handler;
} }
} }

View File

@ -13,7 +13,6 @@
// limitations under the License. // limitations under the License.
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { Platform } from 'ionic-angular';
import { CoreSiteAddonsProvider } from './providers/siteaddons'; import { CoreSiteAddonsProvider } from './providers/siteaddons';
import { CoreSiteAddonsHelperProvider } from './providers/helper'; import { CoreSiteAddonsHelperProvider } from './providers/helper';
import { CoreSiteAddonsComponentsModule } from './components/components.module'; import { CoreSiteAddonsComponentsModule } from './components/components.module';

View File

@ -17,6 +17,7 @@ import { CoreEventsProvider } from './events';
import { CoreLoggerProvider } from './logger'; import { CoreLoggerProvider } from './logger';
import { CoreSitesProvider } from './sites'; import { CoreSitesProvider } from './sites';
import { CoreSiteWSPreSets } from '../classes/site'; import { CoreSiteWSPreSets } from '../classes/site';
import { CoreUtilsProvider } from './utils/utils';
import { CoreSiteAddonsProvider } from '../core/siteaddons/providers/siteaddons'; import { CoreSiteAddonsProvider } from '../core/siteaddons/providers/siteaddons';
import { CoreSiteAddonsHelperProvider } from '../core/siteaddons/providers/helper'; import { CoreSiteAddonsHelperProvider } from '../core/siteaddons/providers/helper';
@ -29,7 +30,8 @@ export class CoreAddonManagerProvider {
protected logger; protected logger;
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider, constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider,
private siteAddonsProvider: CoreSiteAddonsProvider, private siteAddonsHelperProvider: CoreSiteAddonsHelperProvider) { private siteAddonsProvider: CoreSiteAddonsProvider, private siteAddonsHelperProvider: CoreSiteAddonsHelperProvider,
private utils: CoreUtilsProvider) {
logger = logger.getInstance('CoreAddonManagerProvider'); logger = logger.getInstance('CoreAddonManagerProvider');
// Fetch the addons on login. // Fetch the addons on login.
@ -39,9 +41,10 @@ export class CoreAddonManagerProvider {
// Addons fetched, check that site hasn't changed. // Addons fetched, check that site hasn't changed.
if (siteId == this.sitesProvider.getCurrentSiteId() && addons.length) { if (siteId == this.sitesProvider.getCurrentSiteId() && addons.length) {
// Site is still the same. Load the addons and trigger the event. // Site is still the same. Load the addons and trigger the event.
this.loadSiteAddons(addons); this.loadSiteAddons(addons).then(() => {
eventsProvider.trigger(CoreEventsProvider.SITE_ADDONS_LOADED, {}, siteId);
});
eventsProvider.trigger(CoreEventsProvider.SITE_ADDONS_LOADED, {}, siteId);
} }
}); });
}); });
@ -85,10 +88,15 @@ export class CoreAddonManagerProvider {
* Load site addons. * Load site addons.
* *
* @param {any[]} addons The addons to load. * @param {any[]} addons The addons to load.
* @return {Promise<any>} Promise resolved when loaded.
*/ */
loadSiteAddons(addons: any[]): void { loadSiteAddons(addons: any[]): Promise<any> {
const promises = [];
addons.forEach((addon) => { addons.forEach((addon) => {
this.siteAddonsHelperProvider.loadSiteAddon(addon); promises.push(this.siteAddonsHelperProvider.loadSiteAddon(addon));
}); });
return this.utils.allPromises(promises);
} }
} }