MOBILE-2333 siteaddons: Display site addon page
parent
ec4b76b439
commit
5cb8437936
|
@ -13,7 +13,8 @@
|
|||
// limitations under the License.
|
||||
|
||||
import {
|
||||
Component, NgModule, Input, OnInit, OnDestroy, ViewContainerRef, Compiler, ViewChild, ComponentRef, Injector, ChangeDetectorRef
|
||||
Component, NgModule, Input, OnInit, OnChanges, OnDestroy, ViewContainerRef, Compiler, ViewChild, ComponentRef, Injector,
|
||||
SimpleChange, ChangeDetectorRef
|
||||
} from '@angular/core';
|
||||
import {
|
||||
IonicModule, NavController, Platform, ActionSheetController, AlertController, LoadingController, ModalController,
|
||||
|
@ -75,7 +76,7 @@ import { Md5 } from 'ts-md5/dist/md5';
|
|||
selector: 'core-compile-html',
|
||||
template: '<ng-container #dynamicComponent></ng-container>'
|
||||
})
|
||||
export class CoreCompileHtmlComponent implements OnInit, OnDestroy {
|
||||
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,
|
||||
|
@ -103,10 +104,10 @@ export class CoreCompileHtmlComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
/**
|
||||
* Component being initialized.
|
||||
* Detect changes on input properties.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
if (this.text) {
|
||||
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 {});
|
||||
|
@ -123,6 +124,9 @@ export class CoreCompileHtmlComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
// Destroy previous components.
|
||||
this.componentRef && this.componentRef.destroy();
|
||||
|
||||
// Create the component.
|
||||
this.componentRef = this.container.createComponent(componentFactory);
|
||||
});
|
||||
|
|
|
@ -88,6 +88,8 @@ export class CoreLoginReconnectPage {
|
|||
|
||||
return site.getPublicConfig().then((config) => {
|
||||
this.logoUrl = config.logourl || config.compactlogourl;
|
||||
}).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
}
|
||||
}).catch(() => {
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>{{ title }}</ion-title>
|
||||
|
||||
<ion-buttons end>
|
||||
<!-- If the site addon defines some buttons, they will be added here. -->
|
||||
</ion-buttons>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-refresher [enabled]="dataLoaded" (ionRefresh)="refreshData($event)">
|
||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||
</ion-refresher>
|
||||
<core-loading [hideUntil]="dataLoaded">
|
||||
<core-compile-html [text]="content"></core-compile-html>
|
||||
</core-loading>
|
||||
</ion-content>
|
|
@ -0,0 +1,36 @@
|
|||
// (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 { IonicPageModule } from 'ionic-angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreSiteAddonsAddonPage } from './addon-page';
|
||||
import { CoreComponentsModule } from '../../../../components/components.module';
|
||||
import { CoreCompileHtmlComponentsModule } from '../../../../components/compile-html/compile-html.module';
|
||||
|
||||
/**
|
||||
* Module to lazy load the page.
|
||||
*/
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CoreSiteAddonsAddonPage
|
||||
],
|
||||
imports: [
|
||||
CoreComponentsModule,
|
||||
CoreCompileHtmlComponentsModule,
|
||||
IonicPageModule.forChild(CoreSiteAddonsAddonPage),
|
||||
TranslateModule.forChild()
|
||||
]
|
||||
})
|
||||
export class CoreSiteAddonsAddonPageModule {}
|
|
@ -0,0 +1,78 @@
|
|||
// (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 } from '@angular/core';
|
||||
import { IonicPage, NavParams } from 'ionic-angular';
|
||||
import { CoreDomUtilsProvider } from '../../../../providers/utils/dom';
|
||||
import { CoreSiteAddonsProvider } from '../../providers/siteaddons';
|
||||
|
||||
/**
|
||||
* Page to render a site addon page.
|
||||
*/
|
||||
@IonicPage({ segment: 'core-site-addons-addon-page' })
|
||||
@Component({
|
||||
selector: 'page-core-site-addons-addon',
|
||||
templateUrl: 'addon-page.html',
|
||||
})
|
||||
export class CoreSiteAddonsAddonPage {
|
||||
title: string; // Page title.
|
||||
content: string; // Page content.
|
||||
dataLoaded: boolean;
|
||||
|
||||
protected component: string;
|
||||
protected method: string;
|
||||
protected args: any;
|
||||
|
||||
constructor(params: NavParams, protected domUtils: CoreDomUtilsProvider, protected siteAddonsProvider: CoreSiteAddonsProvider) {
|
||||
this.title = params.get('title');
|
||||
this.component = params.get('component');
|
||||
this.method = params.get('method');
|
||||
this.args = params.get('args');
|
||||
}
|
||||
|
||||
/**
|
||||
* View loaded.
|
||||
*/
|
||||
ionViewDidLoad(): void {
|
||||
this.fetchContent().finally(() => {
|
||||
this.dataLoaded = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the content of the page.
|
||||
*
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
fetchContent(): Promise<any> {
|
||||
return this.siteAddonsProvider.getContent(this.component, this.method, this.args).then((result) => {
|
||||
this.content = result.html;
|
||||
}).catch((error) => {
|
||||
this.domUtils.showErrorModalDefault(error, 'core.errorloadingcontent', true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the data.
|
||||
*
|
||||
* @param {any} refresher Refresher.
|
||||
*/
|
||||
refreshData(refresher: any): void {
|
||||
this.siteAddonsProvider.invalidatePageContent(this.component, this.method, this.args).finally(() => {
|
||||
this.fetchContent().finally(() => {
|
||||
refresher.complete();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { NavController, NavOptions } from 'ionic-angular';
|
||||
import { CoreLangProvider } from '../../../providers/lang';
|
||||
import { CoreLoggerProvider } from '../../../providers/logger';
|
||||
import { CoreSite } from '../../../classes/site';
|
||||
import { CoreSitesProvider } from '../../../providers/sites';
|
||||
|
@ -24,6 +25,7 @@ import {
|
|||
} from '../../../core/course/providers/module-delegate';
|
||||
import { CoreUserDelegate, CoreUserProfileHandler, CoreUserProfileHandlerData } from '../../../core/user/providers/user-delegate';
|
||||
import { CoreDelegateHandler } from '../../../classes/delegate';
|
||||
import { CoreConfigConstants } from '../../../configconstants';
|
||||
|
||||
/**
|
||||
* Service to provide functionalities regarding site addons.
|
||||
|
@ -36,7 +38,7 @@ export class CoreSiteAddonsProvider {
|
|||
|
||||
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider,
|
||||
private mainMenuDelegate: CoreMainMenuDelegate, private moduleDelegate: CoreCourseModuleDelegate,
|
||||
private userDelegate: CoreUserDelegate) {
|
||||
private userDelegate: CoreUserDelegate, private langProvider: CoreLangProvider) {
|
||||
this.logger = logger.getInstance('CoreUserProvider');
|
||||
}
|
||||
|
||||
|
@ -55,6 +57,54 @@ export class CoreSiteAddonsProvider {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @return {Promise<{html: string, javascript: string}>} Promise resolved with the content and the javascript.
|
||||
*/
|
||||
getContent(component: string, method: string, args: any, siteId?: string): Promise<{html: string, javascript: string}> {
|
||||
this.logger.debug(`Get content for component '${component}' and method '${method}'`);
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
// Get current language to be added to params.
|
||||
return this.langProvider.getCurrentLanguage().then((lang) => {
|
||||
// Add some params that will always be sent. 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.versionname = CoreConfigConstants.versionname;
|
||||
argsToSend.lang = lang;
|
||||
|
||||
// Now call the WS.
|
||||
const data = {
|
||||
component: component,
|
||||
method: method,
|
||||
args: this.utils.objectToArrayOfObjects(argsToSend, 'name', 'value', true)
|
||||
}, preSets = {
|
||||
cacheKey: this.getContentCacheKey(component, method, args)
|
||||
};
|
||||
|
||||
return this.sitesProvider.getCurrentSite().read('tool_mobile_get_content', data, preSets);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
return this.ROOT_CACHE_KEY + 'content:' + component + ':' + method + ':' + JSON.stringify(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a handler's unique name and the key of a string, return the full string key (prefixed).
|
||||
*
|
||||
|
@ -81,6 +131,32 @@ export class CoreSiteAddonsProvider {
|
|||
return addon.addon + '_' + handlerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
invalidatePageContent(component: string, callback: string, args: any, siteId?: string): Promise<any> {
|
||||
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');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a certain addon is a site addon and it's enabled in a certain site.
|
||||
*
|
||||
|
@ -181,8 +257,7 @@ export class CoreSiteAddonsProvider {
|
|||
pageParams: {
|
||||
title: prefixedTitle,
|
||||
component: addon.component,
|
||||
callback: handlerSchema.mainfunction,
|
||||
contextId: handlerSchema.contextid
|
||||
method: handlerSchema.method,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -223,10 +298,9 @@ export class CoreSiteAddonsProvider {
|
|||
navCtrl.push('CoreSiteAddonsAddonPage', {
|
||||
title: module.name,
|
||||
component: addon.component,
|
||||
callback: handlerSchema.mainfunction,
|
||||
contextId: handlerSchema.contextid,
|
||||
method: handlerSchema.method,
|
||||
args: {
|
||||
course: courseId,
|
||||
courseid: courseId,
|
||||
cmid: module.id
|
||||
}
|
||||
}, options);
|
||||
|
@ -282,10 +356,9 @@ export class CoreSiteAddonsProvider {
|
|||
navCtrl.push('CoreSiteAddonsAddonPage', {
|
||||
title: prefixedTitle,
|
||||
component: addon.component,
|
||||
callback: handlerSchema.mainfunction,
|
||||
contextId: handlerSchema.contextid,
|
||||
method: handlerSchema.method,
|
||||
args: {
|
||||
course: courseId,
|
||||
courseid: courseId,
|
||||
userid: user.id
|
||||
}
|
||||
});
|
||||
|
|
|
@ -36,7 +36,7 @@ export class CoreAddonManagerProvider {
|
|||
const siteId = this.sitesProvider.getCurrentSiteId();
|
||||
this.fetchSiteAddons(siteId).then((addons) => {
|
||||
// Addons fetched, check that site hasn't changed.
|
||||
if (siteId == this.sitesProvider.getCurrentSiteId()) {
|
||||
if (siteId == this.sitesProvider.getCurrentSiteId() && addons.length) {
|
||||
// Site is still the same. Load the addons and trigger the event.
|
||||
this.loadSiteAddons(addons);
|
||||
|
||||
|
@ -61,6 +61,11 @@ export class CoreAddonManagerProvider {
|
|||
const addons = [];
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
if (!this.siteAddonsProvider.isGetContentAvailable(site)) {
|
||||
// Cannot load site addons, so there's no point to fetch them.
|
||||
return addons;
|
||||
}
|
||||
|
||||
// Get the list of addons. Try not to use cache.
|
||||
return site.read('tool_mobile_get_plugins_supporting_mobile', {}, { getFromCache: false }).then((data) => {
|
||||
data.plugins.forEach((addon: any) => {
|
||||
|
|
Loading…
Reference in New Issue