2018-02-13 08:25:52 +01:00
|
|
|
// (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 } from '@angular/core';
|
2018-02-20 13:24:01 +01:00
|
|
|
import { Platform } from 'ionic-angular';
|
|
|
|
import { CoreAppProvider } from '../../../providers/app';
|
2018-02-23 15:53:45 +01:00
|
|
|
import { CoreFilepoolProvider } from '../../../providers/filepool';
|
2018-02-14 10:29:12 +01:00
|
|
|
import { CoreLangProvider } from '../../../providers/lang';
|
2018-02-13 08:25:52 +01:00
|
|
|
import { CoreLoggerProvider } from '../../../providers/logger';
|
2018-02-16 11:34:29 +01:00
|
|
|
import { CoreSite, CoreSiteWSPreSets } from '../../../classes/site';
|
2018-02-13 08:25:52 +01:00
|
|
|
import { CoreSitesProvider } from '../../../providers/sites';
|
|
|
|
import { CoreUtilsProvider } from '../../../providers/utils/utils';
|
2018-02-14 10:29:12 +01:00
|
|
|
import { CoreConfigConstants } from '../../../configconstants';
|
2018-02-13 08:25:52 +01:00
|
|
|
|
2018-02-15 14:57:18 +01:00
|
|
|
/**
|
2018-02-21 16:18:03 +01:00
|
|
|
* Handler of a site addon.
|
2018-02-15 14:57:18 +01:00
|
|
|
*/
|
2018-02-21 16:18:03 +01:00
|
|
|
export interface CoreSiteAddonsHandler {
|
2018-02-15 14:57:18 +01:00
|
|
|
/**
|
|
|
|
* The site addon data.
|
|
|
|
* @type {any}
|
|
|
|
*/
|
|
|
|
addon: any;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Name of the handler.
|
|
|
|
* @type {string}
|
|
|
|
*/
|
|
|
|
handlerName: string;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data of the handler.
|
|
|
|
* @type {any}
|
|
|
|
*/
|
|
|
|
handlerSchema: any;
|
2018-02-21 16:18:03 +01:00
|
|
|
|
|
|
|
/**
|
2018-03-01 13:08:27 +01:00
|
|
|
* Result of the bootstrap WS call.
|
2018-02-21 16:18:03 +01:00
|
|
|
* @type {any}
|
|
|
|
*/
|
|
|
|
bootstrapResult?: any;
|
2018-02-15 14:57:18 +01:00
|
|
|
}
|
|
|
|
|
2018-02-13 08:25:52 +01:00
|
|
|
/**
|
|
|
|
* Service to provide functionalities regarding site addons.
|
|
|
|
*/
|
|
|
|
@Injectable()
|
|
|
|
export class CoreSiteAddonsProvider {
|
|
|
|
protected ROOT_CACHE_KEY = 'CoreSiteAddons:';
|
|
|
|
|
|
|
|
protected logger;
|
2018-02-21 16:18:03 +01:00
|
|
|
protected siteAddons: {[name: string]: CoreSiteAddonsHandler} = {}; // Site addons registered.
|
2018-02-13 08:25:52 +01:00
|
|
|
|
|
|
|
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider,
|
2018-02-23 15:53:45 +01:00
|
|
|
private langProvider: CoreLangProvider, private appProvider: CoreAppProvider, private platform: Platform,
|
|
|
|
private filepoolProvider: CoreFilepoolProvider) {
|
2018-02-13 08:25:52 +01:00
|
|
|
this.logger = logger.getInstance('CoreUserProvider');
|
|
|
|
}
|
|
|
|
|
2018-02-20 13:24:01 +01:00
|
|
|
/**
|
|
|
|
* Add some params that will always be sent for get content.
|
|
|
|
*
|
|
|
|
* @param {any} args Original params.
|
|
|
|
* @param {CoreSite} [site] Site. If not defined, current site.
|
|
|
|
* @return {Promise<any>} Promise resolved with the new params.
|
|
|
|
*/
|
|
|
|
protected addDefaultArgs(args: any, site?: CoreSite): Promise<any> {
|
|
|
|
args = args || {};
|
|
|
|
site = site || this.sitesProvider.getCurrentSite();
|
|
|
|
|
|
|
|
return this.langProvider.getCurrentLanguage().then((lang) => {
|
|
|
|
|
|
|
|
// Clone the object so the original one isn't modified.
|
|
|
|
const argsToSend = this.utils.clone(args);
|
|
|
|
|
|
|
|
argsToSend.userid = args.userid || site.getUserId();
|
|
|
|
argsToSend.appid = CoreConfigConstants.app_id;
|
|
|
|
argsToSend.appversioncode = CoreConfigConstants.versioncode;
|
|
|
|
argsToSend.appversionname = CoreConfigConstants.versionname;
|
|
|
|
argsToSend.applang = lang;
|
|
|
|
argsToSend.appcustomurlscheme = CoreConfigConstants.customurlscheme;
|
|
|
|
argsToSend.appisdesktop = this.appProvider.isDesktop();
|
|
|
|
argsToSend.appismobile = this.appProvider.isMobile();
|
|
|
|
argsToSend.appiswide = this.appProvider.isWide();
|
|
|
|
|
|
|
|
if (argsToSend.appisdevice) {
|
|
|
|
if (this.platform.is('ios')) {
|
|
|
|
argsToSend.appplatform = 'ios';
|
|
|
|
} else {
|
|
|
|
argsToSend.appplatform = 'android';
|
|
|
|
}
|
|
|
|
} else if (argsToSend.appisdesktop) {
|
|
|
|
if (this.appProvider.isMac()) {
|
|
|
|
argsToSend.appplatform = 'mac';
|
|
|
|
} else if (this.appProvider.isLinux()) {
|
|
|
|
argsToSend.appplatform = 'linux';
|
|
|
|
} else {
|
|
|
|
argsToSend.appplatform = 'windows';
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
argsToSend.appplatform = 'browser';
|
|
|
|
}
|
|
|
|
|
|
|
|
return argsToSend;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-02-16 11:34:29 +01:00
|
|
|
/**
|
|
|
|
* Call a WS for a site addon.
|
|
|
|
*
|
|
|
|
* @param {string} method WS method to use.
|
|
|
|
* @param {any} data Data to send to the WS.
|
|
|
|
* @param {CoreSiteWSPreSets} [preSets] Extra options.
|
|
|
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
|
|
|
* @return {Promise<any>} Promise resolved with the response.
|
|
|
|
*/
|
|
|
|
callWS(method: string, data: any, preSets?: CoreSiteWSPreSets, siteId?: string): Promise<any> {
|
|
|
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
|
|
|
preSets = preSets || {};
|
|
|
|
preSets.cacheKey = preSets.cacheKey || this.getCallWSCacheKey(method, data);
|
|
|
|
|
|
|
|
return site.read(method, data, preSets);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-03-01 13:08:27 +01:00
|
|
|
/**
|
|
|
|
* Given the result of a bootstrap get_content and, optionally, the result of another get_content,
|
|
|
|
* build an object with the data to pass to the JS of the get_content.
|
|
|
|
*
|
|
|
|
* @param {any} bootstrapResult Result of the bootstrap WS call.
|
|
|
|
* @param {any} [contentResult] Result of the content WS call (if any).
|
|
|
|
* @return {any} An object with the data to pass to the JS.
|
|
|
|
*/
|
|
|
|
createDataForJS(bootstrapResult: any, contentResult?: any): any {
|
|
|
|
// First of all, add the data returned by the bootstrap JS (if any).
|
|
|
|
const data = this.utils.clone(bootstrapResult.jsResult || {});
|
|
|
|
|
|
|
|
// Now add some data returned by the bootstrap WS call.
|
|
|
|
data.BOOTSTRAP_TEMPLATES = this.utils.objectToKeyValueMap(bootstrapResult.templates, 'id', 'html');
|
|
|
|
data.BOOTSTRAP_OTHERDATA = bootstrapResult.otherdata;
|
|
|
|
|
|
|
|
if (contentResult) {
|
|
|
|
// Now add the data returned by the content WS call.
|
|
|
|
data.CONTENT_TEMPLATES = this.utils.objectToKeyValueMap(contentResult.templates, 'id', 'html');
|
|
|
|
data.CONTENT_OTHERDATA = contentResult.otherdata;
|
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2018-02-16 11:34:29 +01:00
|
|
|
/**
|
|
|
|
* Get cache key for a WS call.
|
|
|
|
*
|
|
|
|
* @param {string} method Name of the method.
|
|
|
|
* @param {any} data Data to identify the WS call.
|
|
|
|
* @return {string} Cache key.
|
|
|
|
*/
|
|
|
|
getCallWSCacheKey(method: string, data: any): string {
|
|
|
|
return this.getCallWSCommonCacheKey(method) + ':' + this.utils.sortAndStringify(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get common cache key for a WS call.
|
|
|
|
*
|
|
|
|
* @param {string} method Name of the method.
|
|
|
|
* @return {string} Cache key.
|
|
|
|
*/
|
|
|
|
protected getCallWSCommonCacheKey(method: string): string {
|
2018-02-20 13:24:01 +01:00
|
|
|
return this.ROOT_CACHE_KEY + 'ws:' + method;
|
2018-02-16 11:34:29 +01:00
|
|
|
}
|
|
|
|
|
2018-02-14 10:29:12 +01:00
|
|
|
/**
|
|
|
|
* Get a certain content for a site addon.
|
|
|
|
*
|
|
|
|
* @param {string} component Component where the class is. E.g. mod_assign.
|
|
|
|
* @param {string} method Method to execute in the class.
|
|
|
|
* @param {any} args The params for the method.
|
2018-02-21 16:18:03 +01:00
|
|
|
* @param {CoreSiteWSPreSets} [preSets] Extra options.
|
2018-02-14 10:29:12 +01:00
|
|
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
2018-02-23 12:28:36 +01:00
|
|
|
* @return {Promise<any>} Promise resolved with the result.
|
2018-02-14 10:29:12 +01:00
|
|
|
*/
|
2018-02-23 12:28:36 +01:00
|
|
|
getContent(component: string, method: string, args: any, preSets?: CoreSiteWSPreSets, siteId?: string): Promise<any> {
|
2018-02-14 10:29:12 +01:00
|
|
|
this.logger.debug(`Get content for component '${component}' and method '${method}'`);
|
|
|
|
|
|
|
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
|
|
|
|
2018-02-20 13:24:01 +01:00
|
|
|
// Add some params that will always be sent.
|
|
|
|
return this.addDefaultArgs(args, site).then((argsToSend) => {
|
2018-02-14 10:29:12 +01:00
|
|
|
// Now call the WS.
|
|
|
|
const data = {
|
|
|
|
component: component,
|
|
|
|
method: method,
|
|
|
|
args: this.utils.objectToArrayOfObjects(argsToSend, 'name', 'value', true)
|
|
|
|
};
|
|
|
|
|
2018-02-21 16:18:03 +01:00
|
|
|
preSets = preSets || {};
|
|
|
|
preSets.cacheKey = this.getContentCacheKey(component, method, args);
|
|
|
|
|
2018-02-14 10:29:12 +01:00
|
|
|
return this.sitesProvider.getCurrentSite().read('tool_mobile_get_content', data, preSets);
|
2018-02-19 09:26:56 +01:00
|
|
|
}).then((result) => {
|
|
|
|
if (result.otherdata) {
|
|
|
|
try {
|
2018-03-01 13:08:27 +01:00
|
|
|
result.otherdata = JSON.parse(result.otherdata) || {};
|
2018-02-19 09:26:56 +01:00
|
|
|
} catch (ex) {
|
|
|
|
// Ignore errors.
|
|
|
|
}
|
2018-03-01 13:08:27 +01:00
|
|
|
} else {
|
|
|
|
result.otherdata = {};
|
2018-02-19 09:26:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
2018-02-14 10:29:12 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get cache key for get content WS calls.
|
|
|
|
*
|
|
|
|
* @param {string} component Component where the class is. E.g. mod_assign.
|
|
|
|
* @param {string} method Method to execute in the class.
|
|
|
|
* @param {any} args The params for the method.
|
|
|
|
* @return {string} Cache key.
|
|
|
|
*/
|
|
|
|
protected getContentCacheKey(component: string, method: string, args: any): string {
|
2018-02-16 11:34:29 +01:00
|
|
|
return this.ROOT_CACHE_KEY + 'content:' + component + ':' + method + ':' + this.utils.sortAndStringify(args);
|
2018-02-14 10:29:12 +01:00
|
|
|
}
|
|
|
|
|
2018-02-23 15:53:45 +01:00
|
|
|
/**
|
|
|
|
* Get the value of a WS param for prefetch.
|
|
|
|
*
|
|
|
|
* @param {string} component The component of the handler.
|
|
|
|
* @param {string} paramName Name of the param as defined by the handler.
|
|
|
|
* @param {number} [courseId] Course ID (if prefetching a course).
|
|
|
|
* @param {any} [module] The module object returned by WS (if prefetching a module).
|
|
|
|
* @return {any} The value.
|
|
|
|
*/
|
|
|
|
protected getDownloadParam(component: string, paramName: string, courseId?: number, module?: any): any {
|
|
|
|
switch (paramName) {
|
|
|
|
case 'courseids':
|
|
|
|
// The WS needs the list of course IDs. Create the list.
|
|
|
|
return [courseId];
|
|
|
|
|
|
|
|
case component + 'id':
|
|
|
|
// The WS needs the instance id.
|
|
|
|
return module && module.instance;
|
|
|
|
|
|
|
|
default:
|
|
|
|
// No more params supported for now.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-14 12:39:19 +01:00
|
|
|
/**
|
2018-02-21 16:18:03 +01:00
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
getHandlerUniqueName(addon: any, handlerName: string): string {
|
|
|
|
return addon.addon + '_' + handlerName;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a site addon handler.
|
2018-02-14 12:39:19 +01:00
|
|
|
*
|
2018-02-21 16:18:03 +01:00
|
|
|
* @param {string} name Unique name of the handler.
|
|
|
|
* @return {CoreSiteAddonsHandler} Handler.
|
2018-02-14 12:39:19 +01:00
|
|
|
*/
|
2018-02-21 16:18:03 +01:00
|
|
|
getSiteAddonHandler(name: string): CoreSiteAddonsHandler {
|
|
|
|
return this.siteAddons[name];
|
2018-02-13 08:25:52 +01:00
|
|
|
}
|
|
|
|
|
2018-02-16 11:34:29 +01:00
|
|
|
/**
|
|
|
|
* Invalidate all WS call to a certain method.
|
|
|
|
*
|
|
|
|
* @param {string} method WS method to use.
|
|
|
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
|
|
|
* @return {Promise<any>} Promise resolved when the data is invalidated.
|
|
|
|
*/
|
|
|
|
invalidateAllCallWSForMethod(method: string, siteId?: string): Promise<any> {
|
|
|
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
|
|
|
return site.invalidateWsCacheForKeyStartingWith(this.getCallWSCommonCacheKey(method));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Invalidate a WS call.
|
|
|
|
*
|
|
|
|
* @param {string} method WS method to use.
|
|
|
|
* @param {any} data Data to send to the WS.
|
2018-02-20 13:24:01 +01:00
|
|
|
* @param {CoreSiteWSPreSets} [preSets] Extra options.
|
2018-02-16 11:34:29 +01:00
|
|
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
|
|
|
* @return {Promise<any>} Promise resolved when the data is invalidated.
|
|
|
|
*/
|
2018-02-20 13:24:01 +01:00
|
|
|
invalidateCallWS(method: string, data: any, preSets?: CoreSiteWSPreSets, siteId?: string): Promise<any> {
|
2018-02-16 11:34:29 +01:00
|
|
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
2018-02-20 13:24:01 +01:00
|
|
|
return site.invalidateWsCacheForKey(preSets.cacheKey || this.getCallWSCacheKey(method, data));
|
2018-02-16 11:34:29 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-02-14 10:29:12 +01:00
|
|
|
/**
|
|
|
|
* Invalidate a page content.
|
|
|
|
*
|
|
|
|
* @param {string} component Component where the class is. E.g. mod_assign.
|
|
|
|
* @param {string} method Method to execute in the class.
|
|
|
|
* @param {any} args The params for the method.
|
|
|
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
|
|
|
* @return {Promise<any>} Promise resolved when the data is invalidated.
|
|
|
|
*/
|
2018-02-15 14:57:18 +01:00
|
|
|
invalidateContent(component: string, callback: string, args: any, siteId?: string): Promise<any> {
|
2018-02-14 10:29:12 +01:00
|
|
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
|
|
|
return site.invalidateWsCacheForKey(this.getContentCacheKey(component, callback, args));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if the get content WS is available.
|
|
|
|
*
|
|
|
|
* @param {CoreSite} site The site to check. If not defined, current site.
|
|
|
|
*/
|
|
|
|
isGetContentAvailable(site?: CoreSite): boolean {
|
|
|
|
site = site || this.sitesProvider.getCurrentSite();
|
|
|
|
|
|
|
|
return site.wsAvailable('tool_mobile_get_content');
|
|
|
|
}
|
|
|
|
|
2018-02-20 13:24:01 +01:00
|
|
|
/**
|
|
|
|
* Load other data into args as determined by useOtherData list.
|
|
|
|
* If useOtherData is undefined, it won't add any data.
|
|
|
|
* If useOtherData is defined but empty (null, false or empty string) it will copy all the data from otherData to args.
|
|
|
|
* If useOtherData is an array, it will only copy the properties whose names are in the array.
|
|
|
|
*
|
|
|
|
* @param {any} args The current args.
|
|
|
|
* @param {any} otherData All the other data.
|
|
|
|
* @param {any[]} useOtherData Names of the attributes to include.
|
|
|
|
* @return {any} New args.
|
|
|
|
*/
|
|
|
|
loadOtherDataInArgs(args: any, otherData: any, useOtherData: any[]): any {
|
|
|
|
if (!args) {
|
|
|
|
args = {};
|
|
|
|
} else {
|
|
|
|
args = this.utils.clone(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
otherData = otherData || {};
|
|
|
|
|
|
|
|
if (typeof useOtherData == 'undefined') {
|
|
|
|
// No need to add other data, return args as they are.
|
|
|
|
return args;
|
|
|
|
} else if (!useOtherData) {
|
|
|
|
// Use other data is defined but empty. Add all the data to args.
|
|
|
|
for (const name in otherData) {
|
|
|
|
args[name] = otherData[name];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (const i in useOtherData) {
|
|
|
|
const name = useOtherData[i];
|
|
|
|
args[name] = otherData[name];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return args;
|
|
|
|
}
|
|
|
|
|
2018-02-23 15:53:45 +01:00
|
|
|
/**
|
|
|
|
* Prefetch offline functions for a site addon handler.
|
|
|
|
*
|
|
|
|
* @param {string} component The component of the handler.
|
|
|
|
* @param {any} args Params to send to the get_content calls.
|
|
|
|
* @param {any} handlerSchema The handler schema.
|
|
|
|
* @param {number} [courseId] Course ID (if prefetching a course).
|
|
|
|
* @param {any} [module] The module object returned by WS (if prefetching a module).
|
|
|
|
* @param {boolean} [prefetch] True to prefetch, false to download right away.
|
|
|
|
* @param {string} [dirPath] Path of the directory where to store all the content files.
|
|
|
|
* @param {CoreSite} [site] Site. If not defined, current site.
|
|
|
|
* @return {Promise<any>} Promise resolved when done.
|
|
|
|
*/
|
|
|
|
prefetchFunctions(component: string, args: any, handlerSchema: any, courseId?: number, module?: any, prefetch?: boolean,
|
|
|
|
dirPath?: string, site?: CoreSite): Promise<any> {
|
|
|
|
site = site || this.sitesProvider.getCurrentSite();
|
|
|
|
|
|
|
|
const promises = [];
|
|
|
|
|
|
|
|
for (const method in handlerSchema.offlinefunctions) {
|
|
|
|
if (site.wsAvailable(method)) {
|
|
|
|
// The method is a WS.
|
|
|
|
const paramsList = handlerSchema.offlinefunctions[method],
|
|
|
|
cacheKey = this.getCallWSCacheKey(method, args);
|
|
|
|
let params = {};
|
|
|
|
|
|
|
|
if (!paramsList.length) {
|
|
|
|
// No params defined, send the default ones.
|
|
|
|
params = args;
|
|
|
|
} else {
|
|
|
|
for (const i in paramsList) {
|
|
|
|
const paramName = paramsList[i];
|
|
|
|
|
|
|
|
if (typeof args[paramName] != 'undefined') {
|
|
|
|
params[paramName] = args[paramName];
|
|
|
|
} else {
|
|
|
|
// The param is not one of the default ones. Try to calculate the param to use.
|
|
|
|
const value = this.getDownloadParam(component, paramName, courseId, module);
|
|
|
|
if (typeof value != 'undefined') {
|
|
|
|
params[paramName] = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
promises.push(this.callWS(method, params, {cacheKey: cacheKey}));
|
|
|
|
} else {
|
|
|
|
// It's a method to get content.
|
|
|
|
promises.push(this.getContent(component, method, args).then((result) => {
|
|
|
|
const subPromises = [];
|
|
|
|
|
|
|
|
// Prefetch the files in the content.
|
|
|
|
if (result.files && result.files.length) {
|
|
|
|
subPromises.push(this.filepoolProvider.downloadOrPrefetchFiles(site.id, result.files, prefetch, false,
|
|
|
|
component, module.id, dirPath));
|
|
|
|
}
|
|
|
|
|
|
|
|
return Promise.all(subPromises);
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Promise.all(promises);
|
|
|
|
}
|
|
|
|
|
2018-02-13 08:25:52 +01:00
|
|
|
/**
|
2018-02-21 16:18:03 +01:00
|
|
|
* Store a site addon handler.
|
2018-02-13 08:25:52 +01:00
|
|
|
*
|
2018-02-21 16:18:03 +01:00
|
|
|
* @param {string} name A unique name to identify the handler.
|
|
|
|
* @param {CoreSiteAddonsHandler} handler Handler to set.
|
2018-02-13 08:25:52 +01:00
|
|
|
*/
|
2018-02-21 16:18:03 +01:00
|
|
|
setSiteAddonHandler(name: string, handler: CoreSiteAddonsHandler): void {
|
|
|
|
this.siteAddons[name] = handler;
|
2018-02-13 08:25:52 +01:00
|
|
|
}
|
|
|
|
}
|