commit
c02e134c58
|
@ -18,8 +18,6 @@ import { CoreFileProvider } from '@providers/file';
|
||||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||||
import { CoreLoggerProvider } from '@providers/logger';
|
import { CoreLoggerProvider } from '@providers/logger';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
|
||||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
|
||||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
import { CoreConstants } from '@core/constants';
|
import { CoreConstants } from '@core/constants';
|
||||||
import { Md5 } from 'ts-md5/dist/md5';
|
import { Md5 } from 'ts-md5/dist/md5';
|
||||||
|
@ -36,8 +34,7 @@ export class AddonRemoteThemesProvider {
|
||||||
protected stylesEls: {[siteId: string]: {element: HTMLStyleElement, hash: string}} = {};
|
protected stylesEls: {[siteId: string]: {element: HTMLStyleElement, hash: string}} = {};
|
||||||
|
|
||||||
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private fileProvider: CoreFileProvider,
|
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private fileProvider: CoreFileProvider,
|
||||||
private filepoolProvider: CoreFilepoolProvider, private http: Http, private utils: CoreUtilsProvider,
|
private filepoolProvider: CoreFilepoolProvider, private http: Http, private utils: CoreUtilsProvider) {
|
||||||
private domUtils: CoreDomUtilsProvider, private textUtils: CoreTextUtilsProvider) {
|
|
||||||
this.logger = logger.getInstance('AddonRemoteThemesProvider');
|
this.logger = logger.getInstance('AddonRemoteThemesProvider');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +222,8 @@ export class AddonRemoteThemesProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Styles have been loaded, now treat the CSS.
|
// Styles have been loaded, now treat the CSS.
|
||||||
this.treatCSSCode(siteId, data.fileUrl, data.styles).catch(() => {
|
this.filepoolProvider.treatCSSCode(siteId, data.fileUrl, data.styles, AddonRemoteThemesProvider.COMPONENT, 2)
|
||||||
|
.catch(() => {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -304,56 +302,6 @@ export class AddonRemoteThemesProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Search for files in a CSS code and try to download them. Once downloaded, replace their URLs
|
|
||||||
* and store the result in the CSS file.
|
|
||||||
*
|
|
||||||
* @param {string} siteId Site ID.
|
|
||||||
* @param {string} fileUrl CSS file URL.
|
|
||||||
* @param {string} cssCode CSS code.
|
|
||||||
* @return {Promise<string>} Promise resolved with the CSS code.
|
|
||||||
*/
|
|
||||||
protected treatCSSCode(siteId: string, fileUrl: string, cssCode: string): Promise<string> {
|
|
||||||
if (!this.fileProvider.isAvailable()) {
|
|
||||||
return Promise.reject(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
const urls = this.domUtils.extractUrlsFromCSS(cssCode),
|
|
||||||
promises = [];
|
|
||||||
let filePath,
|
|
||||||
updated = false;
|
|
||||||
|
|
||||||
// Get the path of the CSS file.
|
|
||||||
promises.push(this.filepoolProvider.getFilePathByUrl(siteId, fileUrl).then((path) => {
|
|
||||||
filePath = path;
|
|
||||||
}));
|
|
||||||
|
|
||||||
urls.forEach((url) => {
|
|
||||||
// Download the file only if it's an online URL.
|
|
||||||
if (url.indexOf('http') == 0) {
|
|
||||||
promises.push(this.filepoolProvider.downloadUrl(siteId, url, false, AddonRemoteThemesProvider.COMPONENT, 2)
|
|
||||||
.then((fileUrl) => {
|
|
||||||
if (fileUrl != url) {
|
|
||||||
cssCode = cssCode.replace(new RegExp(this.textUtils.escapeForRegex(url), 'g'), fileUrl);
|
|
||||||
updated = true;
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
// It shouldn't happen. Ignore errors.
|
|
||||||
this.logger.warn('Error treating file ', url, error);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all(promises).then(() => {
|
|
||||||
// All files downloaded. Store the result if it has changed.
|
|
||||||
if (updated) {
|
|
||||||
return this.fileProvider.writeFile(filePath, cssCode);
|
|
||||||
}
|
|
||||||
}).then(() => {
|
|
||||||
return cssCode;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unload styles for a temporary site.
|
* Unload styles for a temporary site.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -78,6 +78,12 @@ export interface CoreSiteWSPreSets {
|
||||||
*/
|
*/
|
||||||
getEmergencyCacheUsingCacheKey?: boolean;
|
getEmergencyCacheUsingCacheKey?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, the cache entry will be deleted if the WS call returns an exception.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
deleteCacheIfWSError?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether it should only be 1 entry for this cache key (all entries with same key will be deleted).
|
* Whether it should only be 1 entry for this cache key (all entries with same key will be deleted).
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
|
@ -633,6 +639,15 @@ export class CoreSite {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (preSets.deleteCacheIfWSError && this.utils.isWebServiceError(error)) {
|
||||||
|
// Delete the cache entry and return the entry. Don't block the user with the delete.
|
||||||
|
this.deleteFromCache(method, data, preSets).catch(() => {
|
||||||
|
// Ignore errors.
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
|
||||||
this.logger.debug(`WS call '${method}' failed. Trying to use the emergency cache.`);
|
this.logger.debug(`WS call '${method}' failed. Trying to use the emergency cache.`);
|
||||||
preSets.omitExpires = true;
|
preSets.omitExpires = true;
|
||||||
preSets.getFromCache = true;
|
preSets.getFromCache = true;
|
||||||
|
|
|
@ -107,9 +107,25 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
|
||||||
if (this.getIndex(tab) == -1) {
|
if (this.getIndex(tab) == -1) {
|
||||||
this.tabs.push(tab);
|
this.tabs.push(tab);
|
||||||
this.sortTabs();
|
this.sortTabs();
|
||||||
|
|
||||||
|
if (this.initialized && this.tabs.length > 1 && this.tabBarHeight == 0) {
|
||||||
|
// Calculate the tabBarHeight again now that there is more than 1 tab and the bar will be seen.
|
||||||
|
// Use timeout to wait for the view to be rendered. 0 ms should be enough, use 50 to be sure.
|
||||||
|
setTimeout(() => {
|
||||||
|
this.calculateTabBarHeight();
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the tab bar height.
|
||||||
|
*/
|
||||||
|
calculateTabBarHeight(): void {
|
||||||
|
this.tabBarHeight = this.topTabsElement.offsetHeight;
|
||||||
|
this.originalTabsContainer.style.paddingBottom = this.tabBarHeight + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the index of tab.
|
* Get the index of tab.
|
||||||
*
|
*
|
||||||
|
@ -161,8 +177,7 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup tab scrolling.
|
// Setup tab scrolling.
|
||||||
this.tabBarHeight = this.topTabsElement.offsetHeight;
|
this.calculateTabBarHeight();
|
||||||
this.originalTabsContainer.style.paddingBottom = this.tabBarHeight + 'px';
|
|
||||||
if (this.content) {
|
if (this.content) {
|
||||||
if (!this.parentScrollable) {
|
if (!this.parentScrollable) {
|
||||||
// Parent scroll element (if core-tabs is inside a ion-content).
|
// Parent scroll element (if core-tabs is inside a ion-content).
|
||||||
|
@ -184,6 +199,11 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
|
||||||
* @param {any} e Scroll event.
|
* @param {any} e Scroll event.
|
||||||
*/
|
*/
|
||||||
showHideTabs(e: any): void {
|
showHideTabs(e: any): void {
|
||||||
|
if (!this.tabBarHeight) {
|
||||||
|
// We don't have the tab bar height, this means the tab bar isn't shown.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.tabsShown && e.target.scrollTop - this.tabBarHeight > this.tabBarHeight) {
|
if (this.tabsShown && e.target.scrollTop - this.tabBarHeight > this.tabBarHeight) {
|
||||||
this.tabBarElement.classList.add('tabs-hidden');
|
this.tabBarElement.classList.add('tabs-hidden');
|
||||||
this.tabsShown = false;
|
this.tabsShown = false;
|
||||||
|
|
|
@ -25,7 +25,7 @@ export class CoreSitePluginsCourseOptionHandler extends CoreSitePluginsBaseHandl
|
||||||
priority: number;
|
priority: number;
|
||||||
|
|
||||||
constructor(name: string, protected title: string, protected plugin: any, protected handlerSchema: any,
|
constructor(name: string, protected title: string, protected plugin: any, protected handlerSchema: any,
|
||||||
protected bootstrapResult: any, protected sitePluginsProvider: CoreSitePluginsProvider) {
|
protected initResult: any, protected sitePluginsProvider: CoreSitePluginsProvider) {
|
||||||
super(name);
|
super(name);
|
||||||
|
|
||||||
this.priority = handlerSchema.priority;
|
this.priority = handlerSchema.priority;
|
||||||
|
@ -42,7 +42,7 @@ export class CoreSitePluginsCourseOptionHandler extends CoreSitePluginsBaseHandl
|
||||||
*/
|
*/
|
||||||
isEnabledForCourse(courseId: number, accessData: any, navOptions?: any, admOptions?: any): boolean | Promise<boolean> {
|
isEnabledForCourse(courseId: number, accessData: any, navOptions?: any, admOptions?: any): boolean | Promise<boolean> {
|
||||||
return this.sitePluginsProvider.isHandlerEnabledForCourse(
|
return this.sitePluginsProvider.isHandlerEnabledForCourse(
|
||||||
courseId, this.handlerSchema.restricttoenrolledcourses, this.bootstrapResult.restrict);
|
courseId, this.handlerSchema.restricttoenrolledcourses, this.initResult.restrict);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -22,7 +22,7 @@ export class CoreSitePluginsMainMenuHandler extends CoreSitePluginsBaseHandler i
|
||||||
priority: number;
|
priority: number;
|
||||||
|
|
||||||
constructor(name: string, protected title: string, protected plugin: any, protected handlerSchema: any,
|
constructor(name: string, protected title: string, protected plugin: any, protected handlerSchema: any,
|
||||||
protected bootstrapResult: any) {
|
protected initResult: any) {
|
||||||
super(name);
|
super(name);
|
||||||
|
|
||||||
this.priority = handlerSchema.priority;
|
this.priority = handlerSchema.priority;
|
||||||
|
@ -43,7 +43,7 @@ export class CoreSitePluginsMainMenuHandler extends CoreSitePluginsBaseHandler i
|
||||||
title: this.title,
|
title: this.title,
|
||||||
component: this.plugin.component,
|
component: this.plugin.component,
|
||||||
method: this.handlerSchema.method,
|
method: this.handlerSchema.method,
|
||||||
bootstrapResult: this.bootstrapResult
|
initResult: this.initResult
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ export class CoreSitePluginsUserProfileHandler extends CoreSitePluginsBaseHandle
|
||||||
type: string;
|
type: string;
|
||||||
|
|
||||||
constructor(name: string, protected title: string, protected plugin: any, protected handlerSchema: any,
|
constructor(name: string, protected title: string, protected plugin: any, protected handlerSchema: any,
|
||||||
protected bootstrapResult: any, protected sitePluginsProvider: CoreSitePluginsProvider) {
|
protected initResult: any, protected sitePluginsProvider: CoreSitePluginsProvider) {
|
||||||
super(name);
|
super(name);
|
||||||
|
|
||||||
this.priority = handlerSchema.priority;
|
this.priority = handlerSchema.priority;
|
||||||
|
@ -59,14 +59,14 @@ export class CoreSitePluginsUserProfileHandler extends CoreSitePluginsBaseHandle
|
||||||
isEnabledForUser(user: any, courseId: number, navOptions?: any, admOptions?: any): boolean | Promise<boolean> {
|
isEnabledForUser(user: any, courseId: number, navOptions?: any, admOptions?: any): boolean | Promise<boolean> {
|
||||||
// First check if it's enabled for the user.
|
// First check if it's enabled for the user.
|
||||||
const enabledForUser = this.sitePluginsProvider.isHandlerEnabledForUser(user.id, this.handlerSchema.restricttocurrentuser,
|
const enabledForUser = this.sitePluginsProvider.isHandlerEnabledForUser(user.id, this.handlerSchema.restricttocurrentuser,
|
||||||
this.bootstrapResult.restrict);
|
this.initResult.restrict);
|
||||||
if (!enabledForUser) {
|
if (!enabledForUser) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enabled for user, check if it's enabled for the course.
|
// Enabled for user, check if it's enabled for the course.
|
||||||
return this.sitePluginsProvider.isHandlerEnabledForCourse(
|
return this.sitePluginsProvider.isHandlerEnabledForCourse(
|
||||||
courseId, this.handlerSchema.restricttoenrolledcourses, this.bootstrapResult.restrict);
|
courseId, this.handlerSchema.restricttoenrolledcourses, this.initResult.restrict);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -92,7 +92,7 @@ export class CoreSitePluginsUserProfileHandler extends CoreSitePluginsBaseHandle
|
||||||
courseid: courseId,
|
courseid: courseId,
|
||||||
userid: user.id
|
userid: user.id
|
||||||
},
|
},
|
||||||
bootstrapResult: this.bootstrapResult
|
initResult: this.initResult
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<core-site-plugins-plugin-content *ngIf="component && method" [component]="component" [method]="method" [args]="args" [bootstrapResult]="bootstrapResult"></core-site-plugins-plugin-content>
|
<core-site-plugins-plugin-content *ngIf="component && method" [component]="component" [method]="method" [args]="args" [initResult]="initResult"></core-site-plugins-plugin-content>
|
|
@ -33,7 +33,7 @@ export class CoreSitePluginsCourseFormatComponent implements OnInit {
|
||||||
component: string;
|
component: string;
|
||||||
method: string;
|
method: string;
|
||||||
args: any;
|
args: any;
|
||||||
bootstrapResult: any;
|
initResult: any;
|
||||||
|
|
||||||
constructor(protected sitePluginsProvider: CoreSitePluginsProvider) { }
|
constructor(protected sitePluginsProvider: CoreSitePluginsProvider) { }
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ export class CoreSitePluginsCourseFormatComponent implements OnInit {
|
||||||
courseid: this.course.id,
|
courseid: this.course.id,
|
||||||
downloadenabled: this.downloadEnabled
|
downloadenabled: this.downloadEnabled
|
||||||
};
|
};
|
||||||
this.bootstrapResult = handler.bootstrapResult;
|
this.initResult = handler.initResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,6 @@ export class CoreSitePluginsCourseFormatComponent implements OnInit {
|
||||||
* @return {Promise<any>} Promise resolved when done.
|
* @return {Promise<any>} Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
doRefresh(refresher?: any, done?: () => void): Promise<any> {
|
doRefresh(refresher?: any, done?: () => void): Promise<any> {
|
||||||
return Promise.resolve(this.content.refreshData());
|
return Promise.resolve(this.content.refreshContent(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,5 +2,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-plugins-plugin-content *ngIf="component && method" [component]="component" [method]="method" [args]="args" [bootstrapResult]="bootstrapResult"></core-site-plugins-plugin-content>
|
<core-site-plugins-plugin-content *ngIf="component && method" [component]="component" [method]="method" [args]="args" [initResult]="initResult"></core-site-plugins-plugin-content>
|
||||||
</ion-content>
|
</ion-content>
|
|
@ -32,7 +32,7 @@ export class CoreSitePluginsCourseOptionComponent implements OnInit {
|
||||||
component: string;
|
component: string;
|
||||||
method: string;
|
method: string;
|
||||||
args: any;
|
args: any;
|
||||||
bootstrapResult: any;
|
initResult: any;
|
||||||
|
|
||||||
constructor(protected sitePluginsProvider: CoreSitePluginsProvider) { }
|
constructor(protected sitePluginsProvider: CoreSitePluginsProvider) { }
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ export class CoreSitePluginsCourseOptionComponent implements OnInit {
|
||||||
this.args = {
|
this.args = {
|
||||||
courseid: this.courseId,
|
courseid: this.courseId,
|
||||||
};
|
};
|
||||||
this.bootstrapResult = handler.bootstrapResult;
|
this.initResult = handler.initResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ export class CoreSitePluginsCourseOptionComponent implements OnInit {
|
||||||
* @param {any} refresher Refresher.
|
* @param {any} refresher Refresher.
|
||||||
*/
|
*/
|
||||||
refreshData(refresher: any): void {
|
refreshData(refresher: any): void {
|
||||||
this.content.refreshData().finally(() => {
|
this.content.refreshContent(false).finally(() => {
|
||||||
refresher.complete();
|
refresher.complete();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,4 +9,4 @@
|
||||||
</core-context-menu>
|
</core-context-menu>
|
||||||
</core-navbar-buttons>
|
</core-navbar-buttons>
|
||||||
|
|
||||||
<core-site-plugins-plugin-content *ngIf="component && method" [component]="component" [method]="method" [args]="args" [bootstrapResult]="bootstrapResult" (onContentLoaded)="contentLoaded($event)" (onLoadingContent)="contentLoading($event)"></core-site-plugins-plugin-content>
|
<core-site-plugins-plugin-content *ngIf="component && method" [component]="component" [method]="method" [args]="args" [initResult]="initResult" (onContentLoaded)="contentLoaded($event)" (onLoadingContent)="contentLoading($event)"></core-site-plugins-plugin-content>
|
||||||
|
|
|
@ -37,7 +37,7 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C
|
||||||
component: string;
|
component: string;
|
||||||
method: string;
|
method: string;
|
||||||
args: any;
|
args: any;
|
||||||
bootstrapResult: any;
|
initResult: any;
|
||||||
|
|
||||||
// Data for context menu.
|
// Data for context menu.
|
||||||
externalUrl: string;
|
externalUrl: string;
|
||||||
|
@ -69,7 +69,7 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C
|
||||||
courseid: this.courseId,
|
courseid: this.courseId,
|
||||||
cmid: this.module.id
|
cmid: this.module.id
|
||||||
};
|
};
|
||||||
this.bootstrapResult = handler.bootstrapResult;
|
this.initResult = handler.initResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the data for the context menu.
|
// Get the data for the context menu.
|
||||||
|
@ -89,7 +89,7 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C
|
||||||
if (this.content) {
|
if (this.content) {
|
||||||
this.refreshIcon = 'spinner';
|
this.refreshIcon = 'spinner';
|
||||||
|
|
||||||
return Promise.resolve(this.content.refreshData()).finally(() => {
|
return Promise.resolve(this.content.refreshContent(false)).finally(() => {
|
||||||
refresher && refresher.complete();
|
refresher && refresher.complete();
|
||||||
done && done();
|
done && done();
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
import { Component, OnInit, Input, Output, EventEmitter, Optional } from '@angular/core';
|
||||||
|
import { NavController } from 'ionic-angular';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { CoreSitePluginsProvider } from '../../providers/siteplugins';
|
import { CoreSitePluginsProvider } from '../../providers/siteplugins';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
|
@ -28,7 +29,7 @@ export class CoreSitePluginsPluginContentComponent 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 WS call of the handler.
|
@Input() initResult: any; // Result of the init WS call 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.
|
||||||
|
|
||||||
|
@ -39,7 +40,8 @@ export class CoreSitePluginsPluginContentComponent implements OnInit {
|
||||||
invalidateObservable: Subject<void>; // An observable to notify observers when to invalidate data.
|
invalidateObservable: Subject<void>; // An observable to notify observers when to invalidate data.
|
||||||
jsData: any; // Data to pass to the component.
|
jsData: any; // Data to pass to the component.
|
||||||
|
|
||||||
constructor(protected domUtils: CoreDomUtilsProvider, protected sitePluginsProvider: CoreSitePluginsProvider) {
|
constructor(protected domUtils: CoreDomUtilsProvider, protected sitePluginsProvider: CoreSitePluginsProvider,
|
||||||
|
@Optional() protected navCtrl: NavController) {
|
||||||
this.onContentLoaded = new EventEmitter();
|
this.onContentLoaded = new EventEmitter();
|
||||||
this.onLoadingContent = new EventEmitter();
|
this.onLoadingContent = new EventEmitter();
|
||||||
this.invalidateObservable = new Subject<void>();
|
this.invalidateObservable = new Subject<void>();
|
||||||
|
@ -65,7 +67,12 @@ export class CoreSitePluginsPluginContentComponent implements OnInit {
|
||||||
this.content = result.templates.length ? result.templates[0].html : ''; // Load first template.
|
this.content = result.templates.length ? result.templates[0].html : ''; // Load first template.
|
||||||
this.javascript = result.javascript;
|
this.javascript = result.javascript;
|
||||||
this.otherData = result.otherdata;
|
this.otherData = result.otherdata;
|
||||||
this.jsData = this.sitePluginsProvider.createDataForJS(this.bootstrapResult, result);
|
this.jsData = this.sitePluginsProvider.createDataForJS(this.initResult, result);
|
||||||
|
|
||||||
|
// Pass some methods as jsData so they can be called from the template too.
|
||||||
|
this.jsData.openContent = this.openContent.bind(this);
|
||||||
|
this.jsData.refreshContent = this.refreshContent.bind(this);
|
||||||
|
this.jsData.updateContent = this.updateContent.bind(this);
|
||||||
|
|
||||||
this.onContentLoaded.emit(refresh);
|
this.onContentLoaded.emit(refresh);
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
|
@ -75,12 +82,30 @@ export class CoreSitePluginsPluginContentComponent implements OnInit {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a new page with a new content.
|
||||||
|
*
|
||||||
|
* @param {string} title The title to display with the new content.
|
||||||
|
* @param {any} args New params.
|
||||||
|
* @param {string} [component] New component. If not provided, current component
|
||||||
|
* @param {string} [method] New method. If not provided, current method
|
||||||
|
*/
|
||||||
|
openContent(title: string, args: any, component?: string, method?: string): void {
|
||||||
|
this.navCtrl.push('CoreSitePluginsPluginPage', {
|
||||||
|
title: title,
|
||||||
|
component: component || this.component,
|
||||||
|
method: method || this.method,
|
||||||
|
args: args,
|
||||||
|
initResult: this.initResult
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh the data.
|
* Refresh the data.
|
||||||
*
|
*
|
||||||
* @param {boolean} [showSpinner] Whether to show spinner while refreshing.
|
* @param {boolean} [showSpinner=true] Whether to show spinner while refreshing.
|
||||||
*/
|
*/
|
||||||
refreshData(showSpinner?: boolean): Promise<any> {
|
refreshContent(showSpinner: boolean = true): Promise<any> {
|
||||||
if (showSpinner) {
|
if (showSpinner) {
|
||||||
this.dataLoaded = false;
|
this.dataLoaded = false;
|
||||||
}
|
}
|
||||||
|
@ -95,13 +120,13 @@ export class CoreSitePluginsPluginContentComponent implements OnInit {
|
||||||
/**
|
/**
|
||||||
* Update the content, usually with a different method or params.
|
* Update the content, usually with a different method or params.
|
||||||
*
|
*
|
||||||
* @param {string} component New component.
|
|
||||||
* @param {string} method New method.
|
|
||||||
* @param {any} args New params.
|
* @param {any} args New params.
|
||||||
|
* @param {string} [component] New component. If not provided, current component
|
||||||
|
* @param {string} [method] New method. If not provided, current method
|
||||||
*/
|
*/
|
||||||
updateContent(component: string, method: string, args: any): void {
|
updateContent(args: any, component?: string, method?: string): void {
|
||||||
this.component = component;
|
this.component = component || this.component;
|
||||||
this.method = method;
|
this.method = method || this.method;
|
||||||
this.args = args;
|
this.args = args;
|
||||||
this.dataLoaded = false;
|
this.dataLoaded = false;
|
||||||
|
|
||||||
|
|
|
@ -53,8 +53,8 @@ import { CoreSitePluginsPluginContentComponent } from '../components/plugin-cont
|
||||||
selector: '[core-site-plugins-call-ws-new-content]'
|
selector: '[core-site-plugins-call-ws-new-content]'
|
||||||
})
|
})
|
||||||
export class CoreSitePluginsCallWSNewContentDirective extends CoreSitePluginsCallWSOnClickBaseDirective {
|
export class CoreSitePluginsCallWSNewContentDirective extends CoreSitePluginsCallWSOnClickBaseDirective {
|
||||||
@Input() component: string; // The component of the new content.
|
@Input() component: string; // The component of the new content. If not provided, use the same component as current page.
|
||||||
@Input() method: string; // The method to get the new content.
|
@Input() method: string; // The method to get the new content. If not provided, use the same method as current page.
|
||||||
@Input() args: any; // The params to get the new content.
|
@Input() args: any; // The params to get the new content.
|
||||||
@Input() title: string; // The title to display with the new content. Only if samePage=false.
|
@Input() title: string; // The title to display with the new content. Only if samePage=false.
|
||||||
@Input() samePage: boolean | string; // Whether to display the content in same page or open a new one. Defaults to new page.
|
@Input() samePage: boolean | string; // Whether to display the content in same page or open a new one. Defaults to new page.
|
||||||
|
@ -84,15 +84,15 @@ export class CoreSitePluginsCallWSNewContentDirective extends CoreSitePluginsCal
|
||||||
if (this.utils.isTrueOrOne(this.samePage)) {
|
if (this.utils.isTrueOrOne(this.samePage)) {
|
||||||
// Update the parent content (if it exists).
|
// Update the parent content (if it exists).
|
||||||
if (this.parentContent) {
|
if (this.parentContent) {
|
||||||
this.parentContent.updateContent(this.component, this.method, args);
|
this.parentContent.updateContent(args, this.component, this.method);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.navCtrl.push('CoreSitePluginsPluginPage', {
|
this.navCtrl.push('CoreSitePluginsPluginPage', {
|
||||||
title: this.title,
|
title: this.title,
|
||||||
component: this.component,
|
component: this.component || (this.parentContent && this.parentContent.component),
|
||||||
method: this.method,
|
method: this.method || (this.parentContent && this.parentContent.method),
|
||||||
args: args,
|
args: args,
|
||||||
bootstrapResult: this.parentContent && this.parentContent.bootstrapResult
|
initResult: this.parentContent && this.parentContent.initResult
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ export class CoreSitePluginsCallWSDirective extends CoreSitePluginsCallWSOnClick
|
||||||
if (this.utils.isTrueOrOne(this.goBackOnSuccess)) {
|
if (this.utils.isTrueOrOne(this.goBackOnSuccess)) {
|
||||||
this.navCtrl.pop();
|
this.navCtrl.pop();
|
||||||
} else if (this.utils.isTrueOrOne(this.refreshOnSuccess) && this.parentContent) {
|
} else if (this.utils.isTrueOrOne(this.refreshOnSuccess) && this.parentContent) {
|
||||||
this.parentContent.refreshData(true);
|
this.parentContent.refreshContent(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,8 +43,8 @@ import { CoreSitePluginsPluginContentComponent } from '../components/plugin-cont
|
||||||
selector: '[core-site-plugins-new-content]'
|
selector: '[core-site-plugins-new-content]'
|
||||||
})
|
})
|
||||||
export class CoreSitePluginsNewContentDirective implements OnInit {
|
export class CoreSitePluginsNewContentDirective implements OnInit {
|
||||||
@Input() component: string; // The component of the new content.
|
@Input() component: string; // The component of the new content. If not provided, use the same component as current page.
|
||||||
@Input() method: string; // The method to get the new content.
|
@Input() method: string; // The method to get the new content. If not provided, use the same method as current page.
|
||||||
@Input() args: any; // The params to get the new content.
|
@Input() args: any; // The params to get the new content.
|
||||||
@Input() title: string; // The title to display with the new content. Only if samePage=false.
|
@Input() title: string; // The title to display with the new content. Only if samePage=false.
|
||||||
@Input() samePage: boolean | string; // Whether to display the content in same page or open a new one. Defaults to new page.
|
@Input() samePage: boolean | string; // Whether to display the content in same page or open a new one. Defaults to new page.
|
||||||
|
@ -81,15 +81,15 @@ export class CoreSitePluginsNewContentDirective implements OnInit {
|
||||||
if (this.utils.isTrueOrOne(this.samePage)) {
|
if (this.utils.isTrueOrOne(this.samePage)) {
|
||||||
// Update the parent content (if it exists).
|
// Update the parent content (if it exists).
|
||||||
if (this.parentContent) {
|
if (this.parentContent) {
|
||||||
this.parentContent.updateContent(this.component, this.method, args);
|
this.parentContent.updateContent(args, this.component, this.method);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.navCtrl.push('CoreSitePluginsPluginPage', {
|
this.navCtrl.push('CoreSitePluginsPluginPage', {
|
||||||
title: this.title,
|
title: this.title,
|
||||||
component: this.component,
|
component: this.component || (this.parentContent && this.parentContent.component),
|
||||||
method: this.method,
|
method: this.method || (this.parentContent && this.parentContent.method),
|
||||||
args: args,
|
args: args,
|
||||||
bootstrapResult: this.parentContent && this.parentContent.bootstrapResult
|
initResult: this.parentContent && this.parentContent.initResult
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -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-plugins-plugin-content [component]="component" [method]="method" [args]="args" [bootstrapResult]="bootstrapResult"></core-site-plugins-plugin-content>
|
<core-site-plugins-plugin-content [component]="component" [method]="method" [args]="args" [initResult]="initResult"></core-site-plugins-plugin-content>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|
|
@ -32,14 +32,14 @@ export class CoreSitePluginsPluginPage {
|
||||||
component: string;
|
component: string;
|
||||||
method: string;
|
method: string;
|
||||||
args: any;
|
args: any;
|
||||||
bootstrapResult: any;
|
initResult: 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');
|
this.initResult = params.get('initResult');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,7 +48,7 @@ export class CoreSitePluginsPluginPage {
|
||||||
* @param {any} refresher Refresher.
|
* @param {any} refresher Refresher.
|
||||||
*/
|
*/
|
||||||
refreshData(refresher: any): void {
|
refreshData(refresher: any): void {
|
||||||
this.content.refreshData().finally(() => {
|
this.content.refreshContent(false).finally(() => {
|
||||||
refresher.complete();
|
refresher.complete();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,12 +13,15 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Injectable, Injector } from '@angular/core';
|
import { Injectable, Injector } from '@angular/core';
|
||||||
|
import { Http } from '@angular/http';
|
||||||
import { CoreEventsProvider } from '@providers/events';
|
import { CoreEventsProvider } from '@providers/events';
|
||||||
|
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||||
import { CoreLangProvider } from '@providers/lang';
|
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 { CoreTextUtilsProvider } from '@providers/utils/text';
|
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||||
|
import { CoreUrlUtilsProvider } from '@providers/utils/url';
|
||||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
import { CoreSitePluginsProvider } from './siteplugins';
|
import { CoreSitePluginsProvider } from './siteplugins';
|
||||||
import { CoreCompileProvider } from '@core/compile/providers/compile';
|
import { CoreCompileProvider } from '@core/compile/providers/compile';
|
||||||
|
@ -56,12 +59,12 @@ export class CoreSitePluginsHelperProvider {
|
||||||
|
|
||||||
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 http: Http,
|
||||||
private sitePluginsProvider: CoreSitePluginsProvider, private prefetchDelegate: CoreCourseModulePrefetchDelegate,
|
private sitePluginsProvider: CoreSitePluginsProvider, private prefetchDelegate: CoreCourseModulePrefetchDelegate,
|
||||||
private compileProvider: CoreCompileProvider, private utils: CoreUtilsProvider,
|
private compileProvider: CoreCompileProvider, private utils: CoreUtilsProvider, private urlUtils: CoreUrlUtilsProvider,
|
||||||
private courseOptionsDelegate: CoreCourseOptionsDelegate, eventsProvider: CoreEventsProvider,
|
private courseOptionsDelegate: CoreCourseOptionsDelegate, eventsProvider: CoreEventsProvider,
|
||||||
private courseFormatDelegate: CoreCourseFormatDelegate, private profileFieldDelegate: CoreUserProfileFieldDelegate,
|
private courseFormatDelegate: CoreCourseFormatDelegate, private profileFieldDelegate: CoreUserProfileFieldDelegate,
|
||||||
private textUtils: CoreTextUtilsProvider) {
|
private textUtils: CoreTextUtilsProvider, private filepoolProvider: CoreFilepoolProvider) {
|
||||||
this.logger = logger.getInstance('CoreSitePluginsHelperProvider');
|
this.logger = logger.getInstance('CoreSitePluginsHelperProvider');
|
||||||
|
|
||||||
// Fetch the plugins on login.
|
// Fetch the plugins on login.
|
||||||
|
@ -89,19 +92,77 @@ export class CoreSitePluginsHelperProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bootstrap a handler if it has some bootstrap method.
|
* Download the styles for a handler (if any).
|
||||||
|
*
|
||||||
|
* @param {any} plugin Data of the plugin.
|
||||||
|
* @param {string} handlerName Name of the handler in the plugin.
|
||||||
|
* @param {any} handlerSchema Data about the handler.
|
||||||
|
* @param {string} [siteId] Site ID. If not provided, current site.
|
||||||
|
* @return {Promise<string>} Promise resolved with the CSS code.
|
||||||
|
*/
|
||||||
|
downloadStyles(plugin: any, handlerName: string, handlerSchema: any, siteId?: string): Promise<string> {
|
||||||
|
|
||||||
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
// Get the absolute URL. If it's a relative URL, add the site URL to it.
|
||||||
|
let url = handlerSchema.styles && handlerSchema.styles.url;
|
||||||
|
if (url && !this.urlUtils.isAbsoluteURL(url)) {
|
||||||
|
url = this.textUtils.concatenatePaths(site.getURL(), url);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uniqueName = this.sitePluginsProvider.getHandlerUniqueName(plugin, handlerName),
|
||||||
|
componentId = uniqueName + '#main';
|
||||||
|
|
||||||
|
// Remove the CSS files for this handler that aren't used anymore. Don't block the call for this.
|
||||||
|
this.filepoolProvider.getFilesByComponent(site.id, CoreSitePluginsProvider.COMPONENT, componentId).then((files) => {
|
||||||
|
files.forEach((file) => {
|
||||||
|
if (file.url != url) {
|
||||||
|
// It's not the current file, delete it.
|
||||||
|
this.filepoolProvider.removeFileByUrl(site.id, file.url).catch(() => {
|
||||||
|
// Ignore errors.
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).catch(() => {
|
||||||
|
// Ignore errors.
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!url) {
|
||||||
|
// No styles.
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download the file if not downloaded or the version changed.
|
||||||
|
return this.filepoolProvider.downloadUrl(site.id, url, false, CoreSitePluginsProvider.COMPONENT, componentId, 0,
|
||||||
|
undefined, undefined, undefined, handlerSchema.styles.version).then((url) => {
|
||||||
|
|
||||||
|
// File is downloaded, get the contents.
|
||||||
|
return this.http.get(url).toPromise();
|
||||||
|
}).then((response): any => {
|
||||||
|
const text = response && response.text();
|
||||||
|
|
||||||
|
if (typeof text == 'string') {
|
||||||
|
return text;
|
||||||
|
} else {
|
||||||
|
return Promise.reject(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a handler's init method if it has any.
|
||||||
*
|
*
|
||||||
* @param {any} plugin Data of the plugin.
|
* @param {any} plugin Data of the plugin.
|
||||||
* @param {any} handlerSchema Data about the handler.
|
* @param {any} handlerSchema Data about the handler.
|
||||||
* @return {Promise<any>} Promise resolved when done. It returns the results of the getContent call and the data returned by
|
* @return {Promise<any>} Promise resolved when done. It returns the results of the getContent call and the data returned by
|
||||||
* the bootstrap JS (if any).
|
* the init JS (if any).
|
||||||
*/
|
*/
|
||||||
protected bootstrapHandler(plugin: any, handlerSchema: any): Promise<any> {
|
protected executeHandlerInit(plugin: any, handlerSchema: any): Promise<any> {
|
||||||
if (!handlerSchema.bootstrap) {
|
if (!handlerSchema.init) {
|
||||||
return Promise.resolve({});
|
return Promise.resolve({});
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.executeMethodAndJS(plugin, handlerSchema.bootstrap);
|
return this.executeMethodAndJS(plugin, handlerSchema.init, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -109,12 +170,16 @@ export class CoreSitePluginsHelperProvider {
|
||||||
*
|
*
|
||||||
* @param {any} plugin Data of the plugin.
|
* @param {any} plugin Data of the plugin.
|
||||||
* @param {string} method The method to call.
|
* @param {string} method The method to call.
|
||||||
|
* @param {boolean} [isInit] Whether it's the init method.
|
||||||
* @return {Promise<any>} Promise resolved when done. It returns the results of the getContent call and the data returned by
|
* @return {Promise<any>} Promise resolved when done. It returns the results of the getContent call and the data returned by
|
||||||
* the JS (if any).
|
* the JS (if any).
|
||||||
*/
|
*/
|
||||||
protected executeMethodAndJS(plugin: any, method: string): Promise<any> {
|
protected executeMethodAndJS(plugin: any, method: string, isInit?: boolean): Promise<any> {
|
||||||
const siteId = this.sitesProvider.getCurrentSiteId(),
|
const siteId = this.sitesProvider.getCurrentSiteId(),
|
||||||
preSets = {getFromCache: false}; // Try to ignore cache.
|
preSets = {
|
||||||
|
getFromCache: false, // Try to ignore cache.
|
||||||
|
deleteCacheIfWSError: isInit // If the init WS call returns an exception we won't use cached data.
|
||||||
|
};
|
||||||
|
|
||||||
return this.sitePluginsProvider.getContent(plugin.component, method, {}, preSets).then((result) => {
|
return this.sitePluginsProvider.getContent(plugin.component, method, {}, preSets).then((result) => {
|
||||||
if (!result.javascript || this.sitesProvider.getCurrentSiteId() != siteId) {
|
if (!result.javascript || this.sitesProvider.getCurrentSiteId() != siteId) {
|
||||||
|
@ -280,6 +345,35 @@ export class CoreSitePluginsHelperProvider {
|
||||||
return this.utils.allPromises(promises);
|
return this.utils.allPromises(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the styles for a handler.
|
||||||
|
*
|
||||||
|
* @param {any} plugin Data of the plugin.
|
||||||
|
* @param {string} handlerName Name of the handler in the plugin.
|
||||||
|
* @param {string} fileUrl CSS file URL.
|
||||||
|
* @param {string} cssCode CSS code.
|
||||||
|
* @param {number} [version] Styles version.
|
||||||
|
* @param {string} [siteId] Site ID. If not provided, current site.
|
||||||
|
*/
|
||||||
|
loadStyles(plugin: any, handlerName: string, fileUrl: string, cssCode: string, version?: number, siteId?: string): void {
|
||||||
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
|
// Create the style and add it to the header.
|
||||||
|
const styleEl = document.createElement('style'),
|
||||||
|
uniqueName = this.sitePluginsProvider.getHandlerUniqueName(plugin, handlerName);
|
||||||
|
|
||||||
|
styleEl.setAttribute('id', 'siteplugin-' + uniqueName);
|
||||||
|
styleEl.innerHTML = cssCode;
|
||||||
|
|
||||||
|
document.head.appendChild(styleEl);
|
||||||
|
|
||||||
|
// Styles have been loaded, now treat the CSS.
|
||||||
|
this.filepoolProvider.treatCSSCode(siteId, fileUrl, cssCode, CoreSitePluginsProvider.COMPONENT, uniqueName, version)
|
||||||
|
.catch(() => {
|
||||||
|
// Ignore errors.
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a site plugin handler in the right delegate.
|
* Register a site plugin handler in the right delegate.
|
||||||
*
|
*
|
||||||
|
@ -290,8 +384,28 @@ export class CoreSitePluginsHelperProvider {
|
||||||
*/
|
*/
|
||||||
registerHandler(plugin: any, handlerName: string, handlerSchema: any): Promise<any> {
|
registerHandler(plugin: any, handlerName: string, handlerSchema: any): Promise<any> {
|
||||||
|
|
||||||
// Wait for the bootstrap JS to be executed.
|
// Wait for the init JS to be executed and for the styles to be downloaded.
|
||||||
return this.bootstrapHandler(plugin, handlerSchema).then((result) => {
|
const promises = [],
|
||||||
|
siteId = this.sitesProvider.getCurrentSiteId();
|
||||||
|
let result,
|
||||||
|
cssCode;
|
||||||
|
|
||||||
|
promises.push(this.downloadStyles(plugin, handlerName, handlerSchema, siteId).then((code) => {
|
||||||
|
cssCode = code;
|
||||||
|
}).catch((error) => {
|
||||||
|
this.logger.error('Error getting styles for plugin', handlerName, handlerSchema, error);
|
||||||
|
}));
|
||||||
|
|
||||||
|
promises.push(this.executeHandlerInit(plugin, handlerSchema).then((initResult) => {
|
||||||
|
result = initResult;
|
||||||
|
}));
|
||||||
|
|
||||||
|
return Promise.all(promises).then(() => {
|
||||||
|
if (cssCode) {
|
||||||
|
// Load the styles.
|
||||||
|
this.loadStyles(plugin, handlerName, handlerSchema.styles.url, cssCode, handlerSchema.styles.version, siteId);
|
||||||
|
}
|
||||||
|
|
||||||
let promise;
|
let promise;
|
||||||
|
|
||||||
switch (handlerSchema.delegate) {
|
switch (handlerSchema.delegate) {
|
||||||
|
@ -331,12 +445,12 @@ export class CoreSitePluginsHelperProvider {
|
||||||
plugin: plugin,
|
plugin: plugin,
|
||||||
handlerName: handlerName,
|
handlerName: handlerName,
|
||||||
handlerSchema: handlerSchema,
|
handlerSchema: handlerSchema,
|
||||||
bootstrapResult: result
|
initResult: result
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
this.logger.error('Error executing bootstrap method', handlerSchema.bootstrap, err);
|
this.logger.error('Error executing init method', handlerSchema.init, err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,11 +460,11 @@ export class CoreSitePluginsHelperProvider {
|
||||||
* @param {any} plugin Data of the plugin.
|
* @param {any} plugin Data of the plugin.
|
||||||
* @param {string} handlerName Name of the handler in the plugin.
|
* @param {string} handlerName Name of the handler in the plugin.
|
||||||
* @param {any} handlerSchema Data about the handler.
|
* @param {any} handlerSchema Data about the handler.
|
||||||
* @param {any} bootstrapResult Result of the bootstrap WS call.
|
* @param {any} initResult Result of the init WS call.
|
||||||
* @return {string} A string to identify the handler.
|
* @return {string} A string to identify the handler.
|
||||||
*/
|
*/
|
||||||
protected registerCourseFormatHandler(plugin: any, handlerName: string, handlerSchema: any, bootstrapResult: any): string {
|
protected registerCourseFormatHandler(plugin: any, handlerName: string, handlerSchema: any, initResult: any): string {
|
||||||
this.logger.debug('Register site plugin in course format delegate:', plugin, handlerSchema, bootstrapResult);
|
this.logger.debug('Register site plugin in course format delegate:', plugin, handlerSchema, initResult);
|
||||||
|
|
||||||
// Create and register the handler.
|
// Create and register the handler.
|
||||||
const uniqueName = this.sitePluginsProvider.getHandlerUniqueName(plugin, handlerName),
|
const uniqueName = this.sitePluginsProvider.getHandlerUniqueName(plugin, handlerName),
|
||||||
|
@ -366,10 +480,10 @@ export class CoreSitePluginsHelperProvider {
|
||||||
* @param {any} plugin Data of the plugin.
|
* @param {any} plugin Data of the plugin.
|
||||||
* @param {string} handlerName Name of the handler in the plugin.
|
* @param {string} handlerName Name of the handler in the plugin.
|
||||||
* @param {any} handlerSchema Data about the handler.
|
* @param {any} handlerSchema Data about the handler.
|
||||||
* @param {any} bootstrapResult Result of the bootstrap WS call.
|
* @param {any} initResult Result of the init WS call.
|
||||||
* @return {string} A string to identify the handler.
|
* @return {string} A string to identify the handler.
|
||||||
*/
|
*/
|
||||||
protected registerCourseOptionHandler(plugin: any, handlerName: string, handlerSchema: any, bootstrapResult: any): string {
|
protected registerCourseOptionHandler(plugin: any, handlerName: string, handlerSchema: any, initResult: any): string {
|
||||||
if (!handlerSchema.displaydata) {
|
if (!handlerSchema.displaydata) {
|
||||||
// Required data not provided, stop.
|
// Required data not provided, stop.
|
||||||
this.logger.warn('Ignore site plugin because it doesn\'t provide displaydata', plugin, handlerSchema);
|
this.logger.warn('Ignore site plugin because it doesn\'t provide displaydata', plugin, handlerSchema);
|
||||||
|
@ -377,14 +491,14 @@ export class CoreSitePluginsHelperProvider {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.debug('Register site plugin in course option delegate:', plugin, handlerSchema, bootstrapResult);
|
this.logger.debug('Register site plugin in course option delegate:', plugin, handlerSchema, initResult);
|
||||||
|
|
||||||
// Create and register the handler.
|
// Create and register the handler.
|
||||||
const uniqueName = this.sitePluginsProvider.getHandlerUniqueName(plugin, handlerName),
|
const uniqueName = this.sitePluginsProvider.getHandlerUniqueName(plugin, handlerName),
|
||||||
prefixedTitle = this.getPrefixedString(plugin.addon, handlerSchema.displaydata.title);
|
prefixedTitle = this.getPrefixedString(plugin.addon, handlerSchema.displaydata.title);
|
||||||
|
|
||||||
this.courseOptionsDelegate.registerHandler(new CoreSitePluginsCourseOptionHandler(uniqueName, prefixedTitle, plugin,
|
this.courseOptionsDelegate.registerHandler(new CoreSitePluginsCourseOptionHandler(uniqueName, prefixedTitle, plugin,
|
||||||
handlerSchema, bootstrapResult, this.sitePluginsProvider));
|
handlerSchema, initResult, this.sitePluginsProvider));
|
||||||
|
|
||||||
return uniqueName;
|
return uniqueName;
|
||||||
}
|
}
|
||||||
|
@ -395,10 +509,10 @@ export class CoreSitePluginsHelperProvider {
|
||||||
* @param {any} plugin Data of the plugin.
|
* @param {any} plugin Data of the plugin.
|
||||||
* @param {string} handlerName Name of the handler in the plugin.
|
* @param {string} handlerName Name of the handler in the plugin.
|
||||||
* @param {any} handlerSchema Data about the handler.
|
* @param {any} handlerSchema Data about the handler.
|
||||||
* @param {any} bootstrapResult Result of the bootstrap WS call.
|
* @param {any} initResult Result of the init WS call.
|
||||||
* @return {string} A string to identify the handler.
|
* @return {string} A string to identify the handler.
|
||||||
*/
|
*/
|
||||||
protected registerMainMenuHandler(plugin: any, handlerName: string, handlerSchema: any, bootstrapResult: any): string {
|
protected registerMainMenuHandler(plugin: any, handlerName: string, handlerSchema: any, initResult: any): string {
|
||||||
if (!handlerSchema.displaydata) {
|
if (!handlerSchema.displaydata) {
|
||||||
// Required data not provided, stop.
|
// Required data not provided, stop.
|
||||||
this.logger.warn('Ignore site plugin because it doesn\'t provide displaydata', plugin, handlerSchema);
|
this.logger.warn('Ignore site plugin because it doesn\'t provide displaydata', plugin, handlerSchema);
|
||||||
|
@ -406,14 +520,14 @@ export class CoreSitePluginsHelperProvider {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.debug('Register site plugin in main menu delegate:', plugin, handlerSchema, bootstrapResult);
|
this.logger.debug('Register site plugin in main menu delegate:', plugin, handlerSchema, initResult);
|
||||||
|
|
||||||
// Create and register the handler.
|
// Create and register the handler.
|
||||||
const uniqueName = this.sitePluginsProvider.getHandlerUniqueName(plugin, handlerName),
|
const uniqueName = this.sitePluginsProvider.getHandlerUniqueName(plugin, handlerName),
|
||||||
prefixedTitle = this.getPrefixedString(plugin.addon, handlerSchema.displaydata.title);
|
prefixedTitle = this.getPrefixedString(plugin.addon, handlerSchema.displaydata.title);
|
||||||
|
|
||||||
this.mainMenuDelegate.registerHandler(
|
this.mainMenuDelegate.registerHandler(
|
||||||
new CoreSitePluginsMainMenuHandler(uniqueName, prefixedTitle, plugin, handlerSchema, bootstrapResult));
|
new CoreSitePluginsMainMenuHandler(uniqueName, prefixedTitle, plugin, handlerSchema, initResult));
|
||||||
|
|
||||||
return uniqueName;
|
return uniqueName;
|
||||||
}
|
}
|
||||||
|
@ -424,10 +538,10 @@ export class CoreSitePluginsHelperProvider {
|
||||||
* @param {any} plugin Data of the plugin.
|
* @param {any} plugin Data of the plugin.
|
||||||
* @param {string} handlerName Name of the handler in the plugin.
|
* @param {string} handlerName Name of the handler in the plugin.
|
||||||
* @param {any} handlerSchema Data about the handler.
|
* @param {any} handlerSchema Data about the handler.
|
||||||
* @param {any} bootstrapResult Result of the bootstrap WS call.
|
* @param {any} initResult Result of the init WS call.
|
||||||
* @return {string} A string to identify the handler.
|
* @return {string} A string to identify the handler.
|
||||||
*/
|
*/
|
||||||
protected registerModuleHandler(plugin: any, handlerName: string, handlerSchema: any, bootstrapResult: any): string {
|
protected registerModuleHandler(plugin: any, handlerName: string, handlerSchema: any, initResult: any): string {
|
||||||
if (!handlerSchema.displaydata) {
|
if (!handlerSchema.displaydata) {
|
||||||
// Required data not provided, stop.
|
// Required data not provided, stop.
|
||||||
this.logger.warn('Ignore site plugin because it doesn\'t provide displaydata', plugin, handlerSchema);
|
this.logger.warn('Ignore site plugin because it doesn\'t provide displaydata', plugin, handlerSchema);
|
||||||
|
@ -435,7 +549,7 @@ export class CoreSitePluginsHelperProvider {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.debug('Register site plugin in module delegate:', plugin, handlerSchema, bootstrapResult);
|
this.logger.debug('Register site plugin in module delegate:', plugin, handlerSchema, initResult);
|
||||||
|
|
||||||
// Create and register the handler.
|
// Create and register the handler.
|
||||||
const uniqueName = this.sitePluginsProvider.getHandlerUniqueName(plugin, handlerName),
|
const uniqueName = this.sitePluginsProvider.getHandlerUniqueName(plugin, handlerName),
|
||||||
|
@ -458,10 +572,10 @@ export class CoreSitePluginsHelperProvider {
|
||||||
* @param {any} plugin Data of the plugin.
|
* @param {any} plugin Data of the plugin.
|
||||||
* @param {string} handlerName Name of the handler in the plugin.
|
* @param {string} handlerName Name of the handler in the plugin.
|
||||||
* @param {any} handlerSchema Data about the handler.
|
* @param {any} handlerSchema Data about the handler.
|
||||||
* @param {any} bootstrapResult Result of the bootstrap WS call.
|
* @param {any} initResult Result of the init WS call.
|
||||||
* @return {string} A string to identify the handler.
|
* @return {string} A string to identify the handler.
|
||||||
*/
|
*/
|
||||||
protected registerUserProfileHandler(plugin: any, handlerName: string, handlerSchema: any, bootstrapResult: any): string {
|
protected registerUserProfileHandler(plugin: any, handlerName: string, handlerSchema: any, initResult: any): string {
|
||||||
if (!handlerSchema.displaydata) {
|
if (!handlerSchema.displaydata) {
|
||||||
// Required data not provided, stop.
|
// Required data not provided, stop.
|
||||||
this.logger.warn('Ignore site plugin because it doesn\'t provide displaydata', plugin, handlerSchema);
|
this.logger.warn('Ignore site plugin because it doesn\'t provide displaydata', plugin, handlerSchema);
|
||||||
|
@ -469,14 +583,14 @@ export class CoreSitePluginsHelperProvider {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.debug('Register site plugin in user profile delegate:', plugin, handlerSchema, bootstrapResult);
|
this.logger.debug('Register site plugin in user profile delegate:', plugin, handlerSchema, initResult);
|
||||||
|
|
||||||
// Create and register the handler.
|
// Create and register the handler.
|
||||||
const uniqueName = this.sitePluginsProvider.getHandlerUniqueName(plugin, handlerName),
|
const uniqueName = this.sitePluginsProvider.getHandlerUniqueName(plugin, handlerName),
|
||||||
prefixedTitle = this.getPrefixedString(plugin.addon, handlerSchema.displaydata.title);
|
prefixedTitle = this.getPrefixedString(plugin.addon, handlerSchema.displaydata.title);
|
||||||
|
|
||||||
this.userDelegate.registerHandler(new CoreSitePluginsUserProfileHandler(uniqueName, prefixedTitle, plugin, handlerSchema,
|
this.userDelegate.registerHandler(new CoreSitePluginsUserProfileHandler(uniqueName, prefixedTitle, plugin, handlerSchema,
|
||||||
bootstrapResult, this.sitePluginsProvider));
|
initResult, this.sitePluginsProvider));
|
||||||
|
|
||||||
return uniqueName;
|
return uniqueName;
|
||||||
}
|
}
|
||||||
|
@ -487,10 +601,10 @@ export class CoreSitePluginsHelperProvider {
|
||||||
* @param {any} plugin Data of the plugin.
|
* @param {any} plugin Data of the plugin.
|
||||||
* @param {string} handlerName Name of the handler in the plugin.
|
* @param {string} handlerName Name of the handler in the plugin.
|
||||||
* @param {any} handlerSchema Data about the handler.
|
* @param {any} handlerSchema Data about the handler.
|
||||||
* @param {any} bootstrapResult Result of the bootstrap WS call.
|
* @param {any} initResult Result of the init WS call.
|
||||||
* @return {string|Promise<string>} A string (or a promise resolved with a string) to identify the handler.
|
* @return {string|Promise<string>} A string (or a promise resolved with a string) to identify the handler.
|
||||||
*/
|
*/
|
||||||
protected registerUserProfileFieldHandler(plugin: any, handlerName: string, handlerSchema: any, bootstrapResult: any)
|
protected registerUserProfileFieldHandler(plugin: any, handlerName: string, handlerSchema: any, initResult: any)
|
||||||
: string | Promise<string> {
|
: string | Promise<string> {
|
||||||
if (!handlerSchema.method) {
|
if (!handlerSchema.method) {
|
||||||
// Required data not provided, stop.
|
// Required data not provided, stop.
|
||||||
|
@ -499,7 +613,7 @@ export class CoreSitePluginsHelperProvider {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.debug('Register site plugin in user profile field delegate:', plugin, handlerSchema, bootstrapResult);
|
this.logger.debug('Register site plugin in user profile field delegate:', plugin, handlerSchema, initResult);
|
||||||
|
|
||||||
// Execute the main method and its JS. The template returned will be used in the profile field component.
|
// Execute the main method and its JS. The template returned will be used in the profile field component.
|
||||||
return this.executeMethodAndJS(plugin, handlerSchema.method).then((result) => {
|
return this.executeMethodAndJS(plugin, handlerSchema.method).then((result) => {
|
||||||
|
|
|
@ -47,10 +47,10 @@ export interface CoreSitePluginsHandler {
|
||||||
handlerSchema: any;
|
handlerSchema: any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Result of the bootstrap WS call.
|
* Result of the init WS call.
|
||||||
* @type {any}
|
* @type {any}
|
||||||
*/
|
*/
|
||||||
bootstrapResult?: any;
|
initResult?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -58,6 +58,8 @@ export interface CoreSitePluginsHandler {
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CoreSitePluginsProvider {
|
export class CoreSitePluginsProvider {
|
||||||
|
static COMPONENT = 'CoreSitePlugins';
|
||||||
|
|
||||||
protected ROOT_CACHE_KEY = 'CoreSitePlugins:';
|
protected ROOT_CACHE_KEY = 'CoreSitePlugins:';
|
||||||
|
|
||||||
protected logger;
|
protected logger;
|
||||||
|
@ -137,23 +139,23 @@ export class CoreSitePluginsProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given the result of a bootstrap get_content and, optionally, the result of another get_content,
|
* Given the result of a init 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.
|
* 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} initResult Result of the init WS call.
|
||||||
* @param {any} [contentResult] Result of the content WS call (if any).
|
* @param {any} [contentResult] Result of the content WS call (if any).
|
||||||
* @return {any} An object with the data to pass to the JS.
|
* @return {any} An object with the data to pass to the JS.
|
||||||
*/
|
*/
|
||||||
createDataForJS(bootstrapResult: any, contentResult?: any): any {
|
createDataForJS(initResult: any, contentResult?: any): any {
|
||||||
// First of all, add the data returned by the bootstrap JS (if any).
|
// First of all, add the data returned by the init JS (if any).
|
||||||
let data = this.utils.clone(bootstrapResult.jsResult || {});
|
let data = this.utils.clone(initResult.jsResult || {});
|
||||||
if (typeof data == 'boolean') {
|
if (typeof data == 'boolean') {
|
||||||
data = {};
|
data = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now add some data returned by the bootstrap WS call.
|
// Now add some data returned by the init WS call.
|
||||||
data.BOOTSTRAP_TEMPLATES = this.utils.objectToKeyValueMap(bootstrapResult.templates, 'id', 'html');
|
data.INIT_TEMPLATES = this.utils.objectToKeyValueMap(initResult.templates, 'id', 'html');
|
||||||
data.BOOTSTRAP_OTHERDATA = bootstrapResult.otherdata;
|
data.INIT_OTHERDATA = initResult.otherdata;
|
||||||
|
|
||||||
if (contentResult) {
|
if (contentResult) {
|
||||||
// Now add the data returned by the content WS call.
|
// Now add the data returned by the content WS call.
|
||||||
|
|
|
@ -22,6 +22,7 @@ import { CoreLoggerProvider } from './logger';
|
||||||
import { CorePluginFileDelegate } from './plugin-file-delegate';
|
import { CorePluginFileDelegate } from './plugin-file-delegate';
|
||||||
import { CoreSitesProvider } from './sites';
|
import { CoreSitesProvider } from './sites';
|
||||||
import { CoreWSProvider } from './ws';
|
import { CoreWSProvider } from './ws';
|
||||||
|
import { CoreDomUtilsProvider } from './utils/dom';
|
||||||
import { CoreMimetypeUtilsProvider } from './utils/mimetype';
|
import { CoreMimetypeUtilsProvider } from './utils/mimetype';
|
||||||
import { CoreTextUtilsProvider } from './utils/text';
|
import { CoreTextUtilsProvider } from './utils/text';
|
||||||
import { CoreTimeUtilsProvider } from './utils/time';
|
import { CoreTimeUtilsProvider } from './utils/time';
|
||||||
|
@ -435,7 +436,7 @@ export class CoreFilepoolProvider {
|
||||||
private sitesProvider: CoreSitesProvider, private wsProvider: CoreWSProvider, private textUtils: CoreTextUtilsProvider,
|
private sitesProvider: CoreSitesProvider, private wsProvider: CoreWSProvider, private textUtils: CoreTextUtilsProvider,
|
||||||
private utils: CoreUtilsProvider, private mimeUtils: CoreMimetypeUtilsProvider, private urlUtils: CoreUrlUtilsProvider,
|
private utils: CoreUtilsProvider, private mimeUtils: CoreMimetypeUtilsProvider, private urlUtils: CoreUrlUtilsProvider,
|
||||||
private timeUtils: CoreTimeUtilsProvider, private eventsProvider: CoreEventsProvider, initDelegate: CoreInitDelegate,
|
private timeUtils: CoreTimeUtilsProvider, private eventsProvider: CoreEventsProvider, initDelegate: CoreInitDelegate,
|
||||||
network: Network, private pluginFileDelegate: CorePluginFileDelegate) {
|
network: Network, private pluginFileDelegate: CorePluginFileDelegate, private domUtils: CoreDomUtilsProvider) {
|
||||||
this.logger = logger.getInstance('CoreFilepoolProvider');
|
this.logger = logger.getInstance('CoreFilepoolProvider');
|
||||||
|
|
||||||
this.appDB = this.appProvider.getDB();
|
this.appDB = this.appProvider.getDB();
|
||||||
|
@ -625,13 +626,14 @@ export class CoreFilepoolProvider {
|
||||||
* @param {Function} [onProgress] Function to call on progress.
|
* @param {Function} [onProgress] Function to call on progress.
|
||||||
* @param {number} [priority=0] The priority this file should get in the queue (range 0-999).
|
* @param {number} [priority=0] The priority this file should get in the queue (range 0-999).
|
||||||
* @param {any} [options] Extra options (isexternalfile, repositorytype).
|
* @param {any} [options] Extra options (isexternalfile, repositorytype).
|
||||||
|
* @param {number} [revision] File revision. If not defined, it will be calculated using the URL.
|
||||||
* @return {Promise} Resolved on success.
|
* @return {Promise} Resolved on success.
|
||||||
*/
|
*/
|
||||||
addToQueueByUrl(siteId: string, fileUrl: string, component?: string, componentId?: string | number, timemodified: number = 0,
|
addToQueueByUrl(siteId: string, fileUrl: string, component?: string, componentId?: string | number, timemodified: number = 0,
|
||||||
filePath?: string, onProgress?: (event: any) => any, priority: number = 0, options: any = {}): Promise<any> {
|
filePath?: string, onProgress?: (event: any) => any, priority: number = 0, options: any = {}, revision?: number)
|
||||||
|
: Promise<any> {
|
||||||
let fileId,
|
let fileId,
|
||||||
link,
|
link,
|
||||||
revision,
|
|
||||||
queueDeferred;
|
queueDeferred;
|
||||||
|
|
||||||
if (!this.fileProvider.isAvailable()) {
|
if (!this.fileProvider.isAvailable()) {
|
||||||
|
@ -646,7 +648,7 @@ export class CoreFilepoolProvider {
|
||||||
return this.fixPluginfileURL(siteId, fileUrl).then((fileUrl) => {
|
return this.fixPluginfileURL(siteId, fileUrl).then((fileUrl) => {
|
||||||
const primaryKey = { siteId: siteId, fileId: fileId };
|
const primaryKey = { siteId: siteId, fileId: fileId };
|
||||||
|
|
||||||
revision = this.getRevisionFromUrl(fileUrl);
|
revision = revision || this.getRevisionFromUrl(fileUrl);
|
||||||
fileId = this.getFileIdByUrl(fileUrl);
|
fileId = this.getFileIdByUrl(fileUrl);
|
||||||
|
|
||||||
// Set up the component.
|
// Set up the component.
|
||||||
|
@ -747,10 +749,12 @@ export class CoreFilepoolProvider {
|
||||||
* @param {boolean} [downloadUnknown] True to download file in WiFi if their size is unknown, false otherwise.
|
* @param {boolean} [downloadUnknown] True to download file in WiFi if their size is unknown, false otherwise.
|
||||||
* Ignored if checkSize=false.
|
* Ignored if checkSize=false.
|
||||||
* @param {any} [options] Extra options (isexternalfile, repositorytype).
|
* @param {any} [options] Extra options (isexternalfile, repositorytype).
|
||||||
|
* @param {number} [revision] File revision. If not defined, it will be calculated using the URL.
|
||||||
* @return {Promise<any>} Promise resolved when the file is downloaded.
|
* @return {Promise<any>} Promise resolved when the file is downloaded.
|
||||||
*/
|
*/
|
||||||
protected addToQueueIfNeeded(siteId: string, fileUrl: string, component: string, componentId?: string | number,
|
protected addToQueueIfNeeded(siteId: string, fileUrl: string, component: string, componentId?: string | number,
|
||||||
timemodified: number = 0, checkSize: boolean = true, downloadUnknown?: boolean, options: any = {}): Promise<any> {
|
timemodified: number = 0, checkSize: boolean = true, downloadUnknown?: boolean, options: any = {}, revision?: number)
|
||||||
|
: Promise<any> {
|
||||||
let promise;
|
let promise;
|
||||||
|
|
||||||
if (checkSize) {
|
if (checkSize) {
|
||||||
|
@ -779,16 +783,17 @@ export class CoreFilepoolProvider {
|
||||||
if (sizeUnknown) {
|
if (sizeUnknown) {
|
||||||
if (downloadUnknown && isWifi) {
|
if (downloadUnknown && isWifi) {
|
||||||
return this.addToQueueByUrl(
|
return this.addToQueueByUrl(
|
||||||
siteId, fileUrl, component, componentId, timemodified, undefined, undefined, 0, options);
|
siteId, fileUrl, component, componentId, timemodified, undefined, undefined, 0, options, revision);
|
||||||
}
|
}
|
||||||
} else if (size <= this.DOWNLOAD_THRESHOLD || (isWifi && size <= this.WIFI_DOWNLOAD_THRESHOLD)) {
|
} else if (size <= this.DOWNLOAD_THRESHOLD || (isWifi && size <= this.WIFI_DOWNLOAD_THRESHOLD)) {
|
||||||
return this.addToQueueByUrl(
|
return this.addToQueueByUrl(
|
||||||
siteId, fileUrl, component, componentId, timemodified, undefined, undefined, 0, options);
|
siteId, fileUrl, component, componentId, timemodified, undefined, undefined, 0, options, revision);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// No need to check size, just add it to the queue.
|
// No need to check size, just add it to the queue.
|
||||||
return this.addToQueueByUrl(siteId, fileUrl, component, componentId, timemodified, undefined, undefined, 0, options);
|
return this.addToQueueByUrl(siteId, fileUrl, component, componentId, timemodified, undefined, undefined, 0, options,
|
||||||
|
revision);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1155,6 +1160,7 @@ export class CoreFilepoolProvider {
|
||||||
* @param {number} [timemodified=0] The time this file was modified. Can be used to check file state.
|
* @param {number} [timemodified=0] The time this file was modified. Can be used to check file state.
|
||||||
* @param {string} [filePath] Filepath to download the file to. If not defined, download to the filepool folder.
|
* @param {string} [filePath] Filepath to download the file to. If not defined, download to the filepool folder.
|
||||||
* @param {any} [options] Extra options (isexternalfile, repositorytype).
|
* @param {any} [options] Extra options (isexternalfile, repositorytype).
|
||||||
|
* @param {number} [revision] File revision. If not defined, it will be calculated using the URL.
|
||||||
* @return {Promise<any>} Resolved with internal URL on success, rejected otherwise.
|
* @return {Promise<any>} Resolved with internal URL on success, rejected otherwise.
|
||||||
* @description
|
* @description
|
||||||
* Downloads a file on the spot.
|
* Downloads a file on the spot.
|
||||||
|
@ -1164,7 +1170,8 @@ export class CoreFilepoolProvider {
|
||||||
* invalidateFileByUrl to trigger a download.
|
* invalidateFileByUrl to trigger a download.
|
||||||
*/
|
*/
|
||||||
downloadUrl(siteId: string, fileUrl: string, ignoreStale?: boolean, component?: string, componentId?: string | number,
|
downloadUrl(siteId: string, fileUrl: string, ignoreStale?: boolean, component?: string, componentId?: string | number,
|
||||||
timemodified: number = 0, onProgress?: (event: any) => any, filePath?: string, options: any = {}): Promise<any> {
|
timemodified: number = 0, onProgress?: (event: any) => any, filePath?: string, options: any = {}, revision?: number)
|
||||||
|
: Promise<any> {
|
||||||
let fileId,
|
let fileId,
|
||||||
promise;
|
promise;
|
||||||
|
|
||||||
|
@ -1174,7 +1181,7 @@ export class CoreFilepoolProvider {
|
||||||
|
|
||||||
options = Object.assign({}, options); // Create a copy to prevent modifying the original object.
|
options = Object.assign({}, options); // Create a copy to prevent modifying the original object.
|
||||||
options.timemodified = timemodified || 0;
|
options.timemodified = timemodified || 0;
|
||||||
options.revision = this.getRevisionFromUrl(fileUrl);
|
options.revision = revision || this.getRevisionFromUrl(fileUrl);
|
||||||
fileId = this.getFileIdByUrl(fileUrl);
|
fileId = this.getFileIdByUrl(fileUrl);
|
||||||
|
|
||||||
return this.hasFileInPool(siteId, fileId).then((fileObject) => {
|
return this.hasFileInPool(siteId, fileId).then((fileObject) => {
|
||||||
|
@ -1585,15 +1592,16 @@ export class CoreFilepoolProvider {
|
||||||
* @param {string} fileUrl File URL.
|
* @param {string} fileUrl File URL.
|
||||||
* @param {number} [timemodified=0] The time this file was modified.
|
* @param {number} [timemodified=0] The time this file was modified.
|
||||||
* @param {string} [filePath] Filepath to download the file to. If defined, no extension will be added.
|
* @param {string} [filePath] Filepath to download the file to. If defined, no extension will be added.
|
||||||
|
* @param {number} [revision] File revision. If not defined, it will be calculated using the URL.
|
||||||
* @return {Promise<string>} Promise resolved with the file state.
|
* @return {Promise<string>} Promise resolved with the file state.
|
||||||
*/
|
*/
|
||||||
getFileStateByUrl(siteId: string, fileUrl: string, timemodified: number = 0, filePath?: string): Promise<string> {
|
getFileStateByUrl(siteId: string, fileUrl: string, timemodified: number = 0, filePath?: string, revision?: number)
|
||||||
let fileId,
|
: Promise<string> {
|
||||||
revision;
|
let fileId;
|
||||||
|
|
||||||
return this.fixPluginfileURL(siteId, fileUrl).then((fixedUrl) => {
|
return this.fixPluginfileURL(siteId, fileUrl).then((fixedUrl) => {
|
||||||
fileUrl = fixedUrl;
|
fileUrl = fixedUrl;
|
||||||
revision = this.getRevisionFromUrl(fileUrl);
|
revision = revision || this.getRevisionFromUrl(fileUrl);
|
||||||
fileId = this.getFileIdByUrl(fileUrl);
|
fileId = this.getFileIdByUrl(fileUrl);
|
||||||
|
|
||||||
// Check if the file is in queue (waiting to be downloaded).
|
// Check if the file is in queue (waiting to be downloaded).
|
||||||
|
@ -1638,6 +1646,7 @@ export class CoreFilepoolProvider {
|
||||||
* @param {boolean} [downloadUnknown] True to download file in WiFi if their size is unknown, false otherwise.
|
* @param {boolean} [downloadUnknown] True to download file in WiFi if their size is unknown, false otherwise.
|
||||||
* Ignored if checkSize=false.
|
* Ignored if checkSize=false.
|
||||||
* @param {any} [options] Extra options (isexternalfile, repositorytype).
|
* @param {any} [options] Extra options (isexternalfile, repositorytype).
|
||||||
|
* @param {number} [revision] File revision. If not defined, it will be calculated using the URL.
|
||||||
* @return {Promise<string>} Resolved with the URL to use.
|
* @return {Promise<string>} Resolved with the URL to use.
|
||||||
* @description
|
* @description
|
||||||
* This will return a URL pointing to the content of the requested URL.
|
* This will return a URL pointing to the content of the requested URL.
|
||||||
|
@ -1647,21 +1656,20 @@ export class CoreFilepoolProvider {
|
||||||
*/
|
*/
|
||||||
protected getFileUrlByUrl(siteId: string, fileUrl: string, component: string, componentId?: string | number,
|
protected getFileUrlByUrl(siteId: string, fileUrl: string, component: string, componentId?: string | number,
|
||||||
mode: string = 'url', timemodified: number = 0, checkSize: boolean = true, downloadUnknown?: boolean,
|
mode: string = 'url', timemodified: number = 0, checkSize: boolean = true, downloadUnknown?: boolean,
|
||||||
options: any = {}): Promise<string> {
|
options: any = {}, revision?: number): Promise<string> {
|
||||||
|
|
||||||
let fileId,
|
let fileId;
|
||||||
revision;
|
|
||||||
const addToQueue = (fileUrl): void => {
|
const addToQueue = (fileUrl): void => {
|
||||||
// Add the file to queue if needed and ignore errors.
|
// Add the file to queue if needed and ignore errors.
|
||||||
this.addToQueueIfNeeded(siteId, fileUrl, component, componentId, timemodified, checkSize,
|
this.addToQueueIfNeeded(siteId, fileUrl, component, componentId, timemodified, checkSize,
|
||||||
downloadUnknown, options).catch(() => {
|
downloadUnknown, options, revision).catch(() => {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.fixPluginfileURL(siteId, fileUrl).then((fixedUrl) => {
|
return this.fixPluginfileURL(siteId, fileUrl).then((fixedUrl) => {
|
||||||
fileUrl = fixedUrl;
|
fileUrl = fixedUrl;
|
||||||
revision = this.getRevisionFromUrl(fileUrl);
|
revision = revision || this.getRevisionFromUrl(fileUrl);
|
||||||
fileId = this.getFileIdByUrl(fileUrl);
|
fileId = this.getFileIdByUrl(fileUrl);
|
||||||
|
|
||||||
return this.hasFileInPool(siteId, fileId).then((entry) => {
|
return this.hasFileInPool(siteId, fileId).then((entry) => {
|
||||||
|
@ -2083,15 +2091,16 @@ export class CoreFilepoolProvider {
|
||||||
* @param {boolean} [downloadUnknown] True to download file in WiFi if their size is unknown, false otherwise.
|
* @param {boolean} [downloadUnknown] True to download file in WiFi if their size is unknown, false otherwise.
|
||||||
* Ignored if checkSize=false.
|
* Ignored if checkSize=false.
|
||||||
* @param {any} [options] Extra options (isexternalfile, repositorytype).
|
* @param {any} [options] Extra options (isexternalfile, repositorytype).
|
||||||
|
* @param {number} [revision] File revision. If not defined, it will be calculated using the URL.
|
||||||
* @return {Promise<string>} Resolved with the URL to use.
|
* @return {Promise<string>} Resolved with the URL to use.
|
||||||
* @description
|
* @description
|
||||||
* This will return a URL pointing to the content of the requested URL.
|
* This will return a URL pointing to the content of the requested URL.
|
||||||
* The URL returned is compatible to use with IMG tags.
|
* The URL returned is compatible to use with IMG tags.
|
||||||
*/
|
*/
|
||||||
getSrcByUrl(siteId: string, fileUrl: string, component: string, componentId?: string | number, timemodified: number = 0,
|
getSrcByUrl(siteId: string, fileUrl: string, component: string, componentId?: string | number, timemodified: number = 0,
|
||||||
checkSize: boolean = true, downloadUnknown?: boolean, options: any = {}): Promise<string> {
|
checkSize: boolean = true, downloadUnknown?: boolean, options: any = {}, revision?: number): Promise<string> {
|
||||||
return this.getFileUrlByUrl(siteId, fileUrl, component, componentId, 'src',
|
return this.getFileUrlByUrl(siteId, fileUrl, component, componentId, 'src',
|
||||||
timemodified, checkSize, downloadUnknown, options);
|
timemodified, checkSize, downloadUnknown, options, revision);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2125,15 +2134,16 @@ export class CoreFilepoolProvider {
|
||||||
* @param {boolean} [downloadUnknown] True to download file in WiFi if their size is unknown, false otherwise.
|
* @param {boolean} [downloadUnknown] True to download file in WiFi if their size is unknown, false otherwise.
|
||||||
* Ignored if checkSize=false.
|
* Ignored if checkSize=false.
|
||||||
* @param {any} [options] Extra options (isexternalfile, repositorytype).
|
* @param {any} [options] Extra options (isexternalfile, repositorytype).
|
||||||
|
* @param {number} [revision] File revision. If not defined, it will be calculated using the URL.
|
||||||
* @return {Promise<string>} Resolved with the URL to use.
|
* @return {Promise<string>} Resolved with the URL to use.
|
||||||
* @description
|
* @description
|
||||||
* This will return a URL pointing to the content of the requested URL.
|
* This will return a URL pointing to the content of the requested URL.
|
||||||
* The URL returned is compatible to use with a local browser.
|
* The URL returned is compatible to use with a local browser.
|
||||||
*/
|
*/
|
||||||
getUrlByUrl(siteId: string, fileUrl: string, component: string, componentId?: string | number, timemodified: number = 0,
|
getUrlByUrl(siteId: string, fileUrl: string, component: string, componentId?: string | number, timemodified: number = 0,
|
||||||
checkSize: boolean = true, downloadUnknown?: boolean, options: any = {}): Promise<string> {
|
checkSize: boolean = true, downloadUnknown?: boolean, options: any = {}, revision?: number): Promise<string> {
|
||||||
return this.getFileUrlByUrl(siteId, fileUrl, component, componentId, 'url',
|
return this.getFileUrlByUrl(siteId, fileUrl, component, componentId, 'url',
|
||||||
timemodified, checkSize, downloadUnknown, options);
|
timemodified, checkSize, downloadUnknown, options, revision);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2803,6 +2813,58 @@ export class CoreFilepoolProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search for files in a CSS code and try to download them. Once downloaded, replace their URLs
|
||||||
|
* and store the result in the CSS file.
|
||||||
|
*
|
||||||
|
* @param {string} siteId Site ID.
|
||||||
|
* @param {string} fileUrl CSS file URL.
|
||||||
|
* @param {string} cssCode CSS code.
|
||||||
|
* @param {string} [component] The component to link the file to.
|
||||||
|
* @param {string|number} [componentId] An ID to use in conjunction with the component.
|
||||||
|
* @param {number} [revision] Revision to use in all files. If not defined, it will be calculated using the URL of each file.
|
||||||
|
* @return {Promise<string>} Promise resolved with the CSS code.
|
||||||
|
*/
|
||||||
|
treatCSSCode(siteId: string, fileUrl: string, cssCode: string, component?: string, componentId?: string | number,
|
||||||
|
revision?: number): Promise<string> {
|
||||||
|
|
||||||
|
const urls = this.domUtils.extractUrlsFromCSS(cssCode),
|
||||||
|
promises = [];
|
||||||
|
let filePath,
|
||||||
|
updated = false;
|
||||||
|
|
||||||
|
// Get the path of the CSS file.
|
||||||
|
promises.push(this.getFilePathByUrl(siteId, fileUrl).then((path) => {
|
||||||
|
filePath = path;
|
||||||
|
}));
|
||||||
|
|
||||||
|
urls.forEach((url) => {
|
||||||
|
// Download the file only if it's an online URL.
|
||||||
|
if (url.indexOf('http') == 0) {
|
||||||
|
promises.push(this.downloadUrl(siteId, url, false, component, componentId, 0, undefined, undefined, undefined,
|
||||||
|
revision).then((fileUrl) => {
|
||||||
|
|
||||||
|
if (fileUrl != url) {
|
||||||
|
cssCode = cssCode.replace(new RegExp(this.textUtils.escapeForRegex(url), 'g'), fileUrl);
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
}).catch((error) => {
|
||||||
|
// It shouldn't happen. Ignore errors.
|
||||||
|
this.logger.warn('Error treating file ', url, error);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises).then(() => {
|
||||||
|
// All files downloaded. Store the result if it has changed.
|
||||||
|
if (updated) {
|
||||||
|
return this.fileProvider.writeFile(filePath, cssCode);
|
||||||
|
}
|
||||||
|
}).then(() => {
|
||||||
|
return cssCode;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove extension from fileId in queue, used to migrate from previous file handling.
|
* Remove extension from fileId in queue, used to migrate from previous file handling.
|
||||||
*
|
*
|
||||||
|
|
|
@ -626,7 +626,11 @@ export class CoreUtilsProvider {
|
||||||
* @return {boolean} Whether the error was returned by the WebService.
|
* @return {boolean} Whether the error was returned by the WebService.
|
||||||
*/
|
*/
|
||||||
isWebServiceError(error: any): boolean {
|
isWebServiceError(error: any): boolean {
|
||||||
return typeof error.errorcode == 'undefined' && typeof error.warningcode == 'undefined';
|
return typeof error.warningcode != 'undefined' || (typeof error.errorcode != 'undefined' &&
|
||||||
|
error.errorcode != 'invalidtoken' && error.errorcode != 'userdeleted' && error.errorcode != 'upgraderunning' &&
|
||||||
|
error.errorcode != 'forcepasswordchangenotice' && error.errorcode != 'usernotfullysetup' &&
|
||||||
|
error.errorcode != 'sitepolicynotagreed' && error.errorcode != 'sitemaintenance' &&
|
||||||
|
(error.errorcode != 'accessexception' || error.message.indexOf('Invalid token - token expired') == -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue