MOBILE-2364 format-text: Download inline styles files

main
Dani Palou 2018-08-13 16:31:24 +02:00
parent e6c5607463
commit c4221f1367
2 changed files with 57 additions and 6 deletions

View File

@ -20,6 +20,7 @@ import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUrlUtilsProvider } from '@providers/utils/url'; import { CoreUrlUtilsProvider } from '@providers/utils/url';
import { CoreUtilsProvider } from '@providers/utils/utils';
/** /**
* Directive to handle external content. * Directive to handle external content.
@ -28,6 +29,8 @@ import { CoreUrlUtilsProvider } from '@providers/utils/url';
* which we want to have available when the app is offline. Typically media and links. * which we want to have available when the app is offline. Typically media and links.
* *
* If a file is downloaded, its URL will be replaced by the local file URL. * If a file is downloaded, its URL will be replaced by the local file URL.
*
* From v3.5.2 this directive will also download inline styles, so it can be used in any element as long as it has inline styles.
*/ */
@Directive({ @Directive({
selector: '[core-external-content]' selector: '[core-external-content]'
@ -42,7 +45,7 @@ export class CoreExternalContentDirective implements AfterViewInit {
constructor(element: ElementRef, logger: CoreLoggerProvider, private filepoolProvider: CoreFilepoolProvider, constructor(element: ElementRef, logger: CoreLoggerProvider, private filepoolProvider: CoreFilepoolProvider,
private platform: Platform, private sitesProvider: CoreSitesProvider, private domUtils: CoreDomUtilsProvider, private platform: Platform, private sitesProvider: CoreSitesProvider, private domUtils: CoreDomUtilsProvider,
private urlUtils: CoreUrlUtilsProvider, private appProvider: CoreAppProvider) { private urlUtils: CoreUrlUtilsProvider, private appProvider: CoreAppProvider, private utils: CoreUtilsProvider) {
// This directive can be added dynamically. In that case, the first param is the HTMLElement. // This directive can be added dynamically. In that case, the first param is the HTMLElement.
this.element = element.nativeElement || element; this.element = element.nativeElement || element;
this.logger = logger.getInstance('CoreExternalContentDirective'); this.logger = logger.getInstance('CoreExternalContentDirective');
@ -58,6 +61,11 @@ export class CoreExternalContentDirective implements AfterViewInit {
let targetAttr, let targetAttr,
sourceAttr; sourceAttr;
// Always handle inline styles (if any).
this.handleInlineStyles(siteId).catch((error) => {
this.logger.error('Error treating inline styles.', this.element);
});
if (tagName === 'A') { if (tagName === 'A') {
targetAttr = 'href'; targetAttr = 'href';
sourceAttr = 'href'; sourceAttr = 'href';
@ -81,9 +89,6 @@ export class CoreExternalContentDirective implements AfterViewInit {
} }
} else { } else {
// Unsupported tag.
this.logger.warn('Directive attached to non-supported tag: ' + tagName);
return; return;
} }
@ -217,4 +222,39 @@ export class CoreExternalContentDirective implements AfterViewInit {
}); });
}); });
} }
/**
* Handle inline styles, trying to download referenced files.
*
* @param {string} siteId Site ID.
* @return {Promise<any>} Promise resolved if the element is successfully treated.
*/
protected handleInlineStyles(siteId: string): Promise<any> {
let inlineStyles = this.element.getAttribute('style');
if (!inlineStyles) {
return Promise.resolve();
}
let urls = inlineStyles.match(/https?:\/\/[^"'\) ;]*/g);
if (!urls || !urls.length) {
return Promise.resolve();
}
const promises = [];
urls = this.utils.uniqueArray(urls); // Remove duplicates.
urls.forEach((url) => {
promises.push(this.filepoolProvider.getUrlByUrl(siteId, url, this.component, this.componentId, 0, true, true)
.then((finalUrl) => {
this.logger.debug('Using URL ' + finalUrl + ' for ' + url + ' in inline styles');
inlineStyles = inlineStyles.replace(new RegExp(url, 'gi'), finalUrl);
}));
});
return this.utils.allPromises(promises).then(() => {
this.element.setAttribute('style', inlineStyles);
});
}
} }

View File

@ -87,7 +87,7 @@ export class CoreFormatTextDirective implements OnChanges {
protected addExternalContent(element: HTMLElement): void { protected addExternalContent(element: HTMLElement): void {
// Angular 2 doesn't let adding directives dynamically. Create the CoreExternalContentDirective manually. // Angular 2 doesn't let adding directives dynamically. Create the CoreExternalContentDirective manually.
const extContent = new CoreExternalContentDirective(<any> element, this.loggerProvider, this.filepoolProvider, const extContent = new CoreExternalContentDirective(<any> element, this.loggerProvider, this.filepoolProvider,
this.platform, this.sitesProvider, this.domUtils, this.urlUtils, this.appProvider); this.platform, this.sitesProvider, this.domUtils, this.urlUtils, this.appProvider, this.utils);
extContent.component = this.component; extContent.component = this.component;
extContent.componentId = this.componentId; extContent.componentId = this.componentId;
@ -313,7 +313,8 @@ export class CoreFormatTextDirective implements OnChanges {
audios, audios,
videos, videos,
iframes, iframes,
buttons; buttons,
elementsWithInlineStyles;
div.innerHTML = formatted; div.innerHTML = formatted;
images = Array.from(div.querySelectorAll('img')); images = Array.from(div.querySelectorAll('img'));
@ -322,6 +323,7 @@ export class CoreFormatTextDirective implements OnChanges {
videos = Array.from(div.querySelectorAll('video')); videos = Array.from(div.querySelectorAll('video'));
iframes = Array.from(div.querySelectorAll('iframe')); iframes = Array.from(div.querySelectorAll('iframe'));
buttons = Array.from(div.querySelectorAll('.button')); buttons = Array.from(div.querySelectorAll('.button'));
elementsWithInlineStyles = Array.from(div.querySelectorAll('*[style]'));
// Walk through the content to find the links and add our directive to it. // Walk through the content to find the links and add our directive to it.
// Important: We need to look for links first because in 'img' we add new links without core-link. // Important: We need to look for links first because in 'img' we add new links without core-link.
@ -370,6 +372,15 @@ export class CoreFormatTextDirective implements OnChanges {
} }
}); });
// Handle inline styles.
elementsWithInlineStyles.forEach((el: HTMLElement) => {
// Only add external content for tags that haven't been treated already.
if (el.tagName != 'A' && el.tagName != 'IMG' && el.tagName != 'AUDIO' && el.tagName != 'VIDEO'
&& el.tagName != 'SOURCE' && el.tagName != 'TRACK') {
this.addExternalContent(el);
}
});
return div; return div;
}); });
} }