MOBILE-3101 core: Fix embedded files
parent
38e3e88ed6
commit
47decde520
|
@ -17,6 +17,7 @@ import {
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
|
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
|
||||||
import { NavController } from 'ionic-angular';
|
import { NavController } from 'ionic-angular';
|
||||||
|
import { CoreFileProvider } from '@providers/file';
|
||||||
import { CoreLoggerProvider } from '@providers/logger';
|
import { CoreLoggerProvider } from '@providers/logger';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { CoreUrlUtilsProvider } from '@providers/utils/url';
|
import { CoreUrlUtilsProvider } from '@providers/utils/url';
|
||||||
|
@ -49,7 +50,8 @@ export class CoreIframeComponent implements OnInit, OnChanges {
|
||||||
protected navCtrl: NavController,
|
protected navCtrl: NavController,
|
||||||
protected urlUtils: CoreUrlUtilsProvider,
|
protected urlUtils: CoreUrlUtilsProvider,
|
||||||
protected utils: CoreUtilsProvider,
|
protected utils: CoreUtilsProvider,
|
||||||
@Optional() protected svComponent: CoreSplitViewComponent) {
|
@Optional() protected svComponent: CoreSplitViewComponent,
|
||||||
|
protected fileProvider: CoreFileProvider) {
|
||||||
|
|
||||||
this.logger = logger.getInstance('CoreIframe');
|
this.logger = logger.getInstance('CoreIframe');
|
||||||
this.loaded = new EventEmitter<HTMLIFrameElement>();
|
this.loaded = new EventEmitter<HTMLIFrameElement>();
|
||||||
|
@ -93,8 +95,8 @@ export class CoreIframeComponent implements OnInit, OnChanges {
|
||||||
*/
|
*/
|
||||||
ngOnChanges(changes: {[name: string]: SimpleChange }): void {
|
ngOnChanges(changes: {[name: string]: SimpleChange }): void {
|
||||||
if (changes.src) {
|
if (changes.src) {
|
||||||
const youtubeUrl = this.urlUtils.getYoutubeEmbedUrl(changes.src.currentValue);
|
const url = this.urlUtils.getYoutubeEmbedUrl(changes.src.currentValue) || changes.src.currentValue;
|
||||||
this.safeUrl = this.sanitizer.bypassSecurityTrustResourceUrl(youtubeUrl || changes.src.currentValue);
|
this.safeUrl = this.sanitizer.bypassSecurityTrustResourceUrl(this.fileProvider.convertFileSrc(url));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,5 +93,6 @@
|
||||||
"statusbarbgremotetheme": "#000000",
|
"statusbarbgremotetheme": "#000000",
|
||||||
"statusbarlighttextremotetheme": true,
|
"statusbarlighttextremotetheme": true,
|
||||||
"enableanalytics": false,
|
"enableanalytics": false,
|
||||||
"forceColorScheme": ""
|
"forceColorScheme": "",
|
||||||
|
"webviewscheme": "moodleappfs"
|
||||||
}
|
}
|
|
@ -16,6 +16,7 @@ import { Directive, Input, AfterViewInit, ElementRef, OnChanges, SimpleChange, O
|
||||||
import { Platform } from 'ionic-angular';
|
import { Platform } from 'ionic-angular';
|
||||||
import { CoreAppProvider } from '@providers/app';
|
import { CoreAppProvider } from '@providers/app';
|
||||||
import { CoreLoggerProvider } from '@providers/logger';
|
import { CoreLoggerProvider } from '@providers/logger';
|
||||||
|
import { CoreFile } from '@providers/file';
|
||||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
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';
|
||||||
|
@ -52,9 +53,15 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges {
|
||||||
|
|
||||||
invalid = false;
|
invalid = false;
|
||||||
|
|
||||||
constructor(element: ElementRef, logger: CoreLoggerProvider, private filepoolProvider: CoreFilepoolProvider,
|
constructor(element: ElementRef,
|
||||||
private platform: Platform, private sitesProvider: CoreSitesProvider, private domUtils: CoreDomUtilsProvider,
|
logger: CoreLoggerProvider,
|
||||||
private urlUtils: CoreUrlUtilsProvider, private appProvider: CoreAppProvider, private utils: CoreUtilsProvider) {
|
protected filepoolProvider: CoreFilepoolProvider,
|
||||||
|
protected platform: Platform,
|
||||||
|
protected sitesProvider: CoreSitesProvider,
|
||||||
|
protected domUtils: CoreDomUtilsProvider,
|
||||||
|
protected urlUtils: CoreUrlUtilsProvider,
|
||||||
|
protected appProvider: CoreAppProvider,
|
||||||
|
protected 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');
|
||||||
|
@ -179,7 +186,7 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges {
|
||||||
* @param siteId Site ID.
|
* @param siteId Site ID.
|
||||||
* @return Promise resolved if the element is successfully treated.
|
* @return Promise resolved if the element is successfully treated.
|
||||||
*/
|
*/
|
||||||
protected handleExternalContent(targetAttr: string, url: string, siteId?: string): Promise<any> {
|
protected async handleExternalContent(targetAttr: string, url: string, siteId?: string): Promise<any> {
|
||||||
|
|
||||||
const tagName = this.element.tagName;
|
const tagName = this.element.tagName;
|
||||||
|
|
||||||
|
@ -214,72 +221,70 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges {
|
||||||
this.addSource(url);
|
this.addSource(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.reject(null);
|
throw 'Non-downloadable URL';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the webservice pluginfile URL, we ignore failures here.
|
const site = await this.sitesProvider.getSite(siteId);
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
|
||||||
if (!site.canDownloadFiles() && this.urlUtils.isPluginFileUrl(url)) {
|
|
||||||
this.element.parentElement.removeChild(this.element); // Remove element since it'll be broken.
|
|
||||||
|
|
||||||
return Promise.reject(null);
|
if (!site.canDownloadFiles() && this.urlUtils.isPluginFileUrl(url)) {
|
||||||
|
this.element.parentElement.removeChild(this.element); // Remove element since it'll be broken.
|
||||||
|
|
||||||
|
throw 'Site doesn\'t allow downloading files.';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download images, tracks and posters if size is unknown.
|
||||||
|
const dwnUnknown = tagName == 'IMG' || tagName == 'TRACK' || targetAttr == 'poster';
|
||||||
|
let finalUrl: string;
|
||||||
|
|
||||||
|
if (targetAttr === 'src' && tagName !== 'SOURCE' && tagName !== 'TRACK' && tagName !== 'VIDEO' && tagName !== 'AUDIO') {
|
||||||
|
finalUrl = await this.filepoolProvider.getSrcByUrl(siteId, url, this.component, this.componentId, 0, true, dwnUnknown);
|
||||||
|
} else {
|
||||||
|
finalUrl = await this.filepoolProvider.getUrlByUrl(siteId, url, this.component, this.componentId, 0, true, dwnUnknown);
|
||||||
|
|
||||||
|
finalUrl = CoreFile.instance.convertFileSrc(finalUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (finalUrl.match(/^https?:\/\//i)) {
|
||||||
|
/* In iOS, if we use the same URL in embedded file and background download then the download only
|
||||||
|
downloads a few bytes (cached ones). Add a hash to the URL so both URLs are different. */
|
||||||
|
finalUrl = finalUrl + '#moodlemobile-embedded';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.debug('Using URL ' + finalUrl + ' for ' + url);
|
||||||
|
if (tagName === 'SOURCE') {
|
||||||
|
// The browser does not catch changes in SRC, we need to add a new source.
|
||||||
|
this.addSource(finalUrl);
|
||||||
|
} else {
|
||||||
|
if (tagName === 'IMG') {
|
||||||
|
this.loaded = false;
|
||||||
|
this.waitForLoad();
|
||||||
|
}
|
||||||
|
this.element.setAttribute(targetAttr, finalUrl);
|
||||||
|
this.element.setAttribute('data-original-' + targetAttr, url);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set events to download big files (not downloaded automatically).
|
||||||
|
if (finalUrl.indexOf('http') === 0 && targetAttr != 'poster' &&
|
||||||
|
(tagName == 'VIDEO' || tagName == 'AUDIO' || tagName == 'A' || tagName == 'SOURCE')) {
|
||||||
|
const eventName = tagName == 'A' ? 'click' : 'play';
|
||||||
|
let clickableEl = this.element;
|
||||||
|
|
||||||
|
if (tagName == 'SOURCE') {
|
||||||
|
clickableEl = <HTMLElement> this.domUtils.closest(this.element, 'video,audio');
|
||||||
|
if (!clickableEl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Download images, tracks and posters if size is unknown.
|
clickableEl.addEventListener(eventName, () => {
|
||||||
const dwnUnknown = tagName == 'IMG' || tagName == 'TRACK' || targetAttr == 'poster';
|
// User played media or opened a downloadable link.
|
||||||
let promise;
|
// Download the file if in wifi and it hasn't been downloaded already (for big files).
|
||||||
|
if (this.appProvider.isWifi()) {
|
||||||
if (targetAttr === 'src' && tagName !== 'SOURCE' && tagName !== 'TRACK' && tagName !== 'VIDEO' &&
|
// We aren't using the result, so it doesn't matter which of the 2 functions we call.
|
||||||
tagName !== 'AUDIO') {
|
this.filepoolProvider.getUrlByUrl(siteId, url, this.component, this.componentId, 0, false);
|
||||||
promise = this.filepoolProvider.getSrcByUrl(siteId, url, this.component, this.componentId, 0, true, dwnUnknown);
|
|
||||||
} else {
|
|
||||||
promise = this.filepoolProvider.getUrlByUrl(siteId, url, this.component, this.componentId, 0, true, dwnUnknown);
|
|
||||||
}
|
|
||||||
|
|
||||||
return promise.then((finalUrl) => {
|
|
||||||
if (finalUrl.match(/^https?:\/\//i)) {
|
|
||||||
/* In iOS, if we use the same URL in embedded file and background download then the download only
|
|
||||||
downloads a few bytes (cached ones). Add a hash to the URL so both URLs are different. */
|
|
||||||
finalUrl = finalUrl + '#moodlemobile-embedded';
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logger.debug('Using URL ' + finalUrl + ' for ' + url);
|
|
||||||
if (tagName === 'SOURCE') {
|
|
||||||
// The browser does not catch changes in SRC, we need to add a new source.
|
|
||||||
this.addSource(finalUrl);
|
|
||||||
} else {
|
|
||||||
if (tagName === 'IMG') {
|
|
||||||
this.loaded = false;
|
|
||||||
this.waitForLoad();
|
|
||||||
}
|
|
||||||
this.element.setAttribute(targetAttr, finalUrl);
|
|
||||||
this.element.setAttribute('data-original-' + targetAttr, url);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set events to download big files (not downloaded automatically).
|
|
||||||
if (finalUrl.indexOf('http') === 0 && targetAttr != 'poster' &&
|
|
||||||
(tagName == 'VIDEO' || tagName == 'AUDIO' || tagName == 'A' || tagName == 'SOURCE')) {
|
|
||||||
const eventName = tagName == 'A' ? 'click' : 'play';
|
|
||||||
let clickableEl = this.element;
|
|
||||||
|
|
||||||
if (tagName == 'SOURCE') {
|
|
||||||
clickableEl = <HTMLElement> this.domUtils.closest(this.element, 'video,audio');
|
|
||||||
if (!clickableEl) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clickableEl.addEventListener(eventName, () => {
|
|
||||||
// User played media or opened a downloadable link.
|
|
||||||
// Download the file if in wifi and it hasn't been downloaded already (for big files).
|
|
||||||
if (this.appProvider.isWifi()) {
|
|
||||||
// We aren't using the result, so it doesn't matter which of the 2 functions we call.
|
|
||||||
this.filepoolProvider.getUrlByUrl(siteId, url, this.component, this.componentId, 0, false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -74,26 +74,27 @@ export class CoreFormatTextDirective implements OnChanges {
|
||||||
protected loadingChangedListener;
|
protected loadingChangedListener;
|
||||||
|
|
||||||
constructor(element: ElementRef,
|
constructor(element: ElementRef,
|
||||||
private sitesProvider: CoreSitesProvider,
|
protected sitesProvider: CoreSitesProvider,
|
||||||
private domUtils: CoreDomUtilsProvider,
|
protected domUtils: CoreDomUtilsProvider,
|
||||||
private textUtils: CoreTextUtilsProvider,
|
protected textUtils: CoreTextUtilsProvider,
|
||||||
private translate: TranslateService,
|
protected translate: TranslateService,
|
||||||
private platform: Platform,
|
protected platform: Platform,
|
||||||
private utils: CoreUtilsProvider,
|
protected utils: CoreUtilsProvider,
|
||||||
private urlUtils: CoreUrlUtilsProvider,
|
protected urlUtils: CoreUrlUtilsProvider,
|
||||||
private loggerProvider: CoreLoggerProvider,
|
protected loggerProvider: CoreLoggerProvider,
|
||||||
private filepoolProvider: CoreFilepoolProvider,
|
protected filepoolProvider: CoreFilepoolProvider,
|
||||||
private appProvider: CoreAppProvider,
|
protected appProvider: CoreAppProvider,
|
||||||
private contentLinksHelper: CoreContentLinksHelperProvider,
|
protected contentLinksHelper: CoreContentLinksHelperProvider,
|
||||||
@Optional() private navCtrl: NavController,
|
@Optional() protected navCtrl: NavController,
|
||||||
@Optional() private content: Content, @Optional()
|
@Optional() protected content: Content, @Optional()
|
||||||
private svComponent: CoreSplitViewComponent,
|
protected svComponent: CoreSplitViewComponent,
|
||||||
private iframeUtils: CoreIframeUtilsProvider,
|
protected iframeUtils: CoreIframeUtilsProvider,
|
||||||
private eventsProvider: CoreEventsProvider,
|
protected eventsProvider: CoreEventsProvider,
|
||||||
private filterProvider: CoreFilterProvider,
|
protected filterProvider: CoreFilterProvider,
|
||||||
private filterHelper: CoreFilterHelperProvider,
|
protected filterHelper: CoreFilterHelperProvider,
|
||||||
private filterDelegate: CoreFilterDelegate,
|
protected filterDelegate: CoreFilterDelegate,
|
||||||
private viewContainerRef: ViewContainerRef) {
|
protected viewContainerRef: ViewContainerRef,
|
||||||
|
) {
|
||||||
|
|
||||||
this.element = element.nativeElement;
|
this.element = element.nativeElement;
|
||||||
this.element.classList.add('opacity-hide'); // Hide contents until they're treated.
|
this.element.classList.add('opacity-hide'); // Hide contents until they're treated.
|
||||||
|
|
|
@ -92,7 +92,7 @@ export class CoreLinkDirective implements OnInit {
|
||||||
protected navigate(href: string): void {
|
protected navigate(href: string): void {
|
||||||
const contentLinksScheme = CoreConfigConstants.customurlscheme + '://link=';
|
const contentLinksScheme = CoreConfigConstants.customurlscheme + '://link=';
|
||||||
|
|
||||||
if (href.indexOf('cdvfile://') === 0 || href.indexOf('file://') === 0 || href.indexOf('filesystem:') === 0) {
|
if (this.urlUtils.isLocalFileUrl(href)) {
|
||||||
// We have a local file.
|
// We have a local file.
|
||||||
this.utils.openFile(href).catch((error) => {
|
this.utils.openFile(href).catch((error) => {
|
||||||
this.domUtils.showErrorModal(error);
|
this.domUtils.showErrorModal(error);
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { CoreAppProvider } from './app';
|
||||||
import { CoreLoggerProvider } from './logger';
|
import { CoreLoggerProvider } from './logger';
|
||||||
import { CoreMimetypeUtilsProvider } from './utils/mimetype';
|
import { CoreMimetypeUtilsProvider } from './utils/mimetype';
|
||||||
import { CoreTextUtilsProvider } from './utils/text';
|
import { CoreTextUtilsProvider } from './utils/text';
|
||||||
|
import { CoreConfigConstants } from '../configconstants';
|
||||||
import { Zip } from '@ionic-native/zip';
|
import { Zip } from '@ionic-native/zip';
|
||||||
import { makeSingleton } from '@singletons/core.singletons';
|
import { makeSingleton } from '@singletons/core.singletons';
|
||||||
|
|
||||||
|
@ -946,6 +947,7 @@ export class CoreFileProvider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the internal URL of a file.
|
* Get the internal URL of a file.
|
||||||
|
* Please notice that with WKWebView these URLs no longer work in mobile. Use fileEntry.toURL() along with convertFileSrc.
|
||||||
*
|
*
|
||||||
* @param fileEntry File Entry.
|
* @param fileEntry File Entry.
|
||||||
* @return Internal URL.
|
* @return Internal URL.
|
||||||
|
@ -1270,6 +1272,31 @@ export class CoreFileProvider {
|
||||||
|
|
||||||
return window.location.href;
|
return window.location.href;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to call Ionic WebView convertFileSrc only in the needed platforms.
|
||||||
|
* This is needed to make files work with the Ionic WebView plugin.
|
||||||
|
*
|
||||||
|
* @param src Source to convert.
|
||||||
|
* @return Converted src.
|
||||||
|
*/
|
||||||
|
convertFileSrc(src: string): string {
|
||||||
|
return this.appProvider.isMobile() ? (<any> window).Ionic.WebView.convertFileSrc(src) : src;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undo the conversion of convertFileSrc.
|
||||||
|
*
|
||||||
|
* @param src Source to unconvert.
|
||||||
|
* @return Unconverted src.
|
||||||
|
*/
|
||||||
|
unconvertFileSrc(src: string): string {
|
||||||
|
if (!this.appProvider.isMobile()) {
|
||||||
|
return src;
|
||||||
|
}
|
||||||
|
|
||||||
|
return src.replace(CoreConfigConstants.webviewscheme + '://localhost/_app_file_', 'file://');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CoreFile extends makeSingleton(CoreFileProvider) {}
|
export class CoreFile extends makeSingleton(CoreFileProvider) {}
|
||||||
|
|
|
@ -412,11 +412,21 @@ export class CoreFilepoolProvider {
|
||||||
protected packagesPromises = {};
|
protected packagesPromises = {};
|
||||||
protected filePromises: { [s: string]: { [s: string]: Promise<any> } } = {};
|
protected filePromises: { [s: string]: { [s: string]: Promise<any> } } = {};
|
||||||
|
|
||||||
constructor(logger: CoreLoggerProvider, private appProvider: CoreAppProvider, private fileProvider: CoreFileProvider,
|
constructor(logger: CoreLoggerProvider,
|
||||||
private sitesProvider: CoreSitesProvider, private wsProvider: CoreWSProvider, private textUtils: CoreTextUtilsProvider,
|
protected appProvider: CoreAppProvider,
|
||||||
private utils: CoreUtilsProvider, private mimeUtils: CoreMimetypeUtilsProvider, private urlUtils: CoreUrlUtilsProvider,
|
protected fileProvider: CoreFileProvider,
|
||||||
private timeUtils: CoreTimeUtilsProvider, private eventsProvider: CoreEventsProvider, initDelegate: CoreInitDelegate,
|
protected sitesProvider: CoreSitesProvider,
|
||||||
network: Network, private pluginFileDelegate: CorePluginFileDelegate, private domUtils: CoreDomUtilsProvider,
|
protected wsProvider: CoreWSProvider,
|
||||||
|
protected textUtils: CoreTextUtilsProvider,
|
||||||
|
protected utils: CoreUtilsProvider,
|
||||||
|
protected mimeUtils: CoreMimetypeUtilsProvider,
|
||||||
|
protected urlUtils: CoreUrlUtilsProvider,
|
||||||
|
protected timeUtils: CoreTimeUtilsProvider,
|
||||||
|
protected eventsProvider: CoreEventsProvider,
|
||||||
|
initDelegate: CoreInitDelegate,
|
||||||
|
network: Network,
|
||||||
|
protected pluginFileDelegate: CorePluginFileDelegate,
|
||||||
|
protected domUtils: CoreDomUtilsProvider,
|
||||||
zone: NgZone) {
|
zone: NgZone) {
|
||||||
this.logger = logger.getInstance('CoreFilepoolProvider');
|
this.logger = logger.getInstance('CoreFilepoolProvider');
|
||||||
|
|
||||||
|
@ -1796,8 +1806,7 @@ export class CoreFilepoolProvider {
|
||||||
if (this.fileProvider.isAvailable()) {
|
if (this.fileProvider.isAvailable()) {
|
||||||
return Promise.resolve(this.getFilePath(siteId, fileId)).then((path) => {
|
return Promise.resolve(this.getFilePath(siteId, fileId)).then((path) => {
|
||||||
return this.fileProvider.getFile(path).then((fileEntry) => {
|
return this.fileProvider.getFile(path).then((fileEntry) => {
|
||||||
// We use toInternalURL so images are loaded in iOS8 using img HTML tags.
|
return this.fileProvider.convertFileSrc(fileEntry.toURL());
|
||||||
return this.fileProvider.getInternalURL(fileEntry);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -225,7 +225,7 @@ export class CoreIframeUtilsProvider {
|
||||||
} else {
|
} else {
|
||||||
element.setAttribute('src', url);
|
element.setAttribute('src', url);
|
||||||
}
|
}
|
||||||
} else if (url.indexOf('cdvfile://') === 0 || url.indexOf('file://') === 0) {
|
} else if (this.urlUtils.isLocalFileUrl(url)) {
|
||||||
// It's a local file.
|
// It's a local file.
|
||||||
this.utils.openFile(url).catch((error) => {
|
this.utils.openFile(url).catch((error) => {
|
||||||
this.domUtils.showErrorModal(error);
|
this.domUtils.showErrorModal(error);
|
||||||
|
@ -353,16 +353,14 @@ export class CoreIframeUtilsProvider {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scheme && scheme != 'file' && scheme != 'filesystem') {
|
if (!this.urlUtils.isLocalFileUrlScheme(scheme)) {
|
||||||
// Scheme suggests it's an external resource.
|
// Scheme suggests it's an external resource.
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
const frameSrc = (<HTMLFrameElement> element).src || (<HTMLObjectElement> element).data,
|
const frameSrc = (<HTMLFrameElement> element).src || (<HTMLObjectElement> element).data;
|
||||||
frameScheme = this.urlUtils.getUrlScheme(frameSrc);
|
|
||||||
|
|
||||||
// If the frame is not local, check the target to identify how to treat the link.
|
// If the frame is not local, check the target to identify how to treat the link.
|
||||||
if (frameScheme && frameScheme != 'file' && frameScheme != 'filesystem' &&
|
if (!this.urlUtils.isLocalFileUrl(frameSrc) && (!link.target || link.target == '_self')) {
|
||||||
(!link.target || link.target == '_self')) {
|
|
||||||
// Load the link inside the frame itself.
|
// Load the link inside the frame itself.
|
||||||
if (element.tagName.toLowerCase() == 'object') {
|
if (element.tagName.toLowerCase() == 'object') {
|
||||||
element.setAttribute('data', link.href);
|
element.setAttribute('data', link.href);
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { CoreFile } from '../file';
|
||||||
import { CoreLoggerProvider } from '../logger';
|
import { CoreLoggerProvider } from '../logger';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { CoreTextUtilsProvider } from './text';
|
import { CoreTextUtilsProvider } from './text';
|
||||||
|
@ -165,7 +166,7 @@ export class CoreMimetypeUtilsProvider {
|
||||||
if (this.canBeEmbedded(ext)) {
|
if (this.canBeEmbedded(ext)) {
|
||||||
file.embedType = this.getExtensionType(ext);
|
file.embedType = this.getExtensionType(ext);
|
||||||
|
|
||||||
path = path || file.fileurl || (file.toURL && file.toURL());
|
path = CoreFile.instance.convertFileSrc(path || file.fileurl || (file.toURL && file.toURL()));
|
||||||
|
|
||||||
if (file.embedType == 'image') {
|
if (file.embedType == 'image') {
|
||||||
return '<img src="' + path + '">';
|
return '<img src="' + path + '">';
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { Injectable } from '@angular/core';
|
||||||
import { CoreLangProvider } from '../lang';
|
import { CoreLangProvider } from '../lang';
|
||||||
import { CoreTextUtilsProvider } from './text';
|
import { CoreTextUtilsProvider } from './text';
|
||||||
import { makeSingleton } from '@singletons/core.singletons';
|
import { makeSingleton } from '@singletons/core.singletons';
|
||||||
|
import { CoreConfigConstants } from '../../configconstants';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "Utils" service with helper functions for URLs.
|
* "Utils" service with helper functions for URLs.
|
||||||
|
@ -424,6 +425,26 @@ export class CoreUrlUtilsProvider {
|
||||||
return /^https?\:\/\/.+/i.test(url);
|
return /^https?\:\/\/.+/i.test(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether an URL belongs to a local file.
|
||||||
|
*
|
||||||
|
* @param url URL to check.
|
||||||
|
* @return Whether the URL belongs to a local file.
|
||||||
|
*/
|
||||||
|
isLocalFileUrl(url: string): boolean {
|
||||||
|
return this.isLocalFileUrlScheme(this.getUrlScheme(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a URL scheme belongs to a local file.
|
||||||
|
*
|
||||||
|
* @param scheme Scheme to check.
|
||||||
|
* @return Whether the scheme belongs to a local file.
|
||||||
|
*/
|
||||||
|
isLocalFileUrlScheme(scheme: string): boolean {
|
||||||
|
return scheme == 'cdvfile' || scheme == 'file' || scheme == 'filesystem' || scheme == CoreConfigConstants.webviewscheme;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns if a URL is a pluginfile URL.
|
* Returns if a URL is a pluginfile URL.
|
||||||
*
|
*
|
||||||
|
|
|
@ -27,6 +27,7 @@ import { CoreLoggerProvider } from '../logger';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { CoreLangProvider } from '../lang';
|
import { CoreLangProvider } from '../lang';
|
||||||
import { CoreWSProvider, CoreWSError } from '../ws';
|
import { CoreWSProvider, CoreWSError } from '../ws';
|
||||||
|
import { CoreFile } from '../file';
|
||||||
import { makeSingleton } from '@singletons/core.singletons';
|
import { makeSingleton } from '@singletons/core.singletons';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -863,8 +864,11 @@ export class CoreUtilsProvider {
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
openFile(path: string): Promise<any> {
|
openFile(path: string): Promise<any> {
|
||||||
const extension = this.mimetypeUtils.getFileExtension(path),
|
// Convert the path to a native path if needed.
|
||||||
mimetype = this.mimetypeUtils.getMimeType(extension);
|
path = CoreFile.instance.unconvertFileSrc(path);
|
||||||
|
|
||||||
|
const extension = this.mimetypeUtils.getFileExtension(path);
|
||||||
|
const mimetype = this.mimetypeUtils.getMimeType(extension);
|
||||||
|
|
||||||
// Path needs to be decoded, the file won't be opened if the path has %20 instead of spaces and so.
|
// Path needs to be decoded, the file won't be opened if the path has %20 instead of spaces and so.
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Reference in New Issue