MOBILE-3098 iframe: Open in app links inside iframes

main
Dani Palou 2019-07-16 08:22:58 +02:00
parent ea7caaed20
commit 8d64fea2af
4 changed files with 43 additions and 26 deletions

View File

@ -12,11 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, Output, OnInit, ViewChild, ElementRef, EventEmitter, OnChanges, SimpleChange } from '@angular/core';
import {
Component, Input, Output, OnInit, ViewChild, ElementRef, EventEmitter, OnChanges, SimpleChange, Optional
} from '@angular/core';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
import { NavController } from 'ionic-angular';
import { CoreLoggerProvider } from '@providers/logger';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreIframeUtilsProvider } from '@providers/utils/iframe';
import { CoreSplitViewComponent } from '@components/split-view/split-view';
/**
*/
@ -38,7 +42,9 @@ export class CoreIframeComponent implements OnInit, OnChanges {
protected IFRAME_TIMEOUT = 15000;
constructor(logger: CoreLoggerProvider, private iframeUtils: CoreIframeUtilsProvider, private domUtils: CoreDomUtilsProvider,
private sanitizer: DomSanitizer) {
private sanitizer: DomSanitizer, private navCtrl: NavController,
@Optional() private svComponent: CoreSplitViewComponent) {
this.logger = logger.getInstance('CoreIframe');
this.loaded = new EventEmitter<HTMLIFrameElement>();
}
@ -55,7 +61,8 @@ export class CoreIframeComponent implements OnInit, OnChanges {
// Show loading only with external URLs.
this.loading = !this.src || !!this.src.match(/^https?:\/\//i);
this.iframeUtils.treatFrame(iframe);
const navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl;
this.iframeUtils.treatFrame(iframe, false, navCtrl);
if (this.loading) {
iframe.addEventListener('load', () => {

View File

@ -27,7 +27,7 @@ import { CoreBlockDelegate } from '@core/block/providers/delegate';
})
export class CoreSitePluginsBlockComponent extends CoreBlockBaseComponent implements OnChanges {
@Input() block: any;
@Input() contextLevel: number;
@Input() contextLevel: string;
@Input() instanceId: number;
@ViewChild(CoreSitePluginsPluginContentComponent) content: CoreSitePluginsPluginContentComponent;

View File

@ -352,7 +352,8 @@ export class CoreFormatTextDirective implements OnChanges {
this.utils.isTrueOrOne(this.singleLine), undefined, this.highlight);
}).then((formatted) => {
const div = document.createElement('div'),
canTreatVimeo = site && site.isVersionGreaterEqualThan(['3.3.4', '3.4']);
canTreatVimeo = site && site.isVersionGreaterEqualThan(['3.3.4', '3.4']),
navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl;
let images,
anchors,
audios,
@ -405,12 +406,12 @@ export class CoreFormatTextDirective implements OnChanges {
});
videos.forEach((video) => {
this.treatVideoFilters(video);
this.treatVideoFilters(video, navCtrl);
this.treatMedia(video);
});
iframes.forEach((iframe) => {
this.treatIframe(iframe, site, canTreatVimeo);
this.treatIframe(iframe, site, canTreatVimeo, navCtrl);
});
// Handle buttons with inner links.
@ -439,7 +440,7 @@ export class CoreFormatTextDirective implements OnChanges {
// Handle all kind of frames.
frames.forEach((frame: any) => {
this.iframeUtils.treatFrame(frame);
this.iframeUtils.treatFrame(frame, false, navCtrl);
});
this.domUtils.handleBootstrapTooltips(div);
@ -508,8 +509,9 @@ export class CoreFormatTextDirective implements OnChanges {
* Treat video filters. Currently only treating youtube video using video JS.
*
* @param {HTMLElement} el Video element.
* @param {NavController} navCtrl NavController to use.
*/
protected treatVideoFilters(video: HTMLElement): void {
protected treatVideoFilters(video: HTMLElement, navCtrl: NavController): void {
// Treat Video JS Youtube video links and translate them to iframes.
if (!video.classList.contains('video-js')) {
return;
@ -534,7 +536,7 @@ export class CoreFormatTextDirective implements OnChanges {
// Replace video tag by the iframe.
video.parentNode.replaceChild(iframe, video);
this.iframeUtils.treatFrame(iframe);
this.iframeUtils.treatFrame(iframe, false, navCtrl);
}
/**
@ -571,8 +573,9 @@ export class CoreFormatTextDirective implements OnChanges {
* @param {HTMLIFrameElement} iframe Iframe to treat.
* @param {CoreSite} site Site instance.
* @param {boolean} canTreatVimeo Whether Vimeo videos can be treated in the site.
* @param {NavController} navCtrl NavController to use.
*/
protected treatIframe(iframe: HTMLIFrameElement, site: CoreSite, canTreatVimeo: boolean): void {
protected treatIframe(iframe: HTMLIFrameElement, site: CoreSite, canTreatVimeo: boolean, navCtrl: NavController): void {
const src = iframe.src,
currentSite = this.sitesProvider.getCurrentSite();
@ -583,7 +586,7 @@ export class CoreFormatTextDirective implements OnChanges {
currentSite.getAutoLoginUrl(src, false).then((finalUrl) => {
iframe.src = finalUrl;
this.iframeUtils.treatFrame(iframe);
this.iframeUtils.treatFrame(iframe, false, navCtrl);
});
return;
@ -644,7 +647,7 @@ export class CoreFormatTextDirective implements OnChanges {
}
}
this.iframeUtils.treatFrame(iframe);
this.iframeUtils.treatFrame(iframe, false, navCtrl);
}
/**

View File

@ -13,7 +13,7 @@
// limitations under the License.
import { Injectable, NgZone } from '@angular/core';
import { Config, Platform } from 'ionic-angular';
import { Config, Platform, NavController } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { Network } from '@ionic-native/network';
import { CoreAppProvider } from '../app';
@ -191,8 +191,9 @@ export class CoreIframeUtilsProvider {
* @param {any} element Element to treat (iframe, embed, ...).
* @param {Window} contentWindow The window of the element contents.
* @param {Document} contentDocument The document of the element contents.
* @param {NavController} [navCtrl] NavController to use if a link can be opened in the app.
*/
redefineWindowOpen(element: any, contentWindow: Window, contentDocument: Document): void {
redefineWindowOpen(element: any, contentWindow: Window, contentDocument: Document, navCtrl?: NavController): void {
if (contentWindow) {
// Intercept window.open.
contentWindow.open = (url: string, target: string): Window => {
@ -229,13 +230,18 @@ export class CoreIframeUtilsProvider {
this.domUtils.showErrorModal(error);
});
} else {
// It's an external link, we will open with browser. Check if we need to auto-login.
if (!this.sitesProvider.isLoggedIn()) {
// Not logged in, cannot auto-login.
this.utils.openInBrowser(url);
} else {
this.sitesProvider.getCurrentSite().openInBrowserWithAutoLoginIfSameSite(url);
}
// It's an external link, check if it can be opened in the app.
this.contentLinksHelper.handleLink(url, undefined, navCtrl, true, true).then((treated) => {
if (!treated) {
// Not opened in the app, open with browser. Check if we need to auto-login
if (!this.sitesProvider.isLoggedIn()) {
// Not logged in, cannot auto-login.
this.utils.openInBrowser(url);
} else {
this.sitesProvider.getCurrentSite().openInBrowserWithAutoLoginIfSameSite(url);
}
}
});
}
// We cannot create new Window objects directly, return null which is a valid return value for Window.open().
@ -248,7 +254,7 @@ export class CoreIframeUtilsProvider {
CoreIframeUtilsProvider.FRAME_TAGS.forEach((tag) => {
const elements = Array.from(contentDocument.querySelectorAll(tag));
elements.forEach((subElement) => {
this.treatFrame(subElement, true);
this.treatFrame(subElement, true, navCtrl);
});
});
}
@ -260,14 +266,15 @@ export class CoreIframeUtilsProvider {
*
* @param {any} element Element to treat (iframe, embed, ...).
* @param {boolean} [isSubframe] Whether it's a frame inside another frame.
* @param {NavController} [navCtrl] NavController to use if a link can be opened in the app.
*/
treatFrame(element: any, isSubframe?: boolean): void {
treatFrame(element: any, isSubframe?: boolean, navCtrl?: NavController): void {
if (element) {
this.checkOnlineFrameInOffline(element, isSubframe);
let winAndDoc = this.getContentWindowAndDocument(element);
// Redefine window.open in this element and sub frames, it might have been loaded already.
this.redefineWindowOpen(element, winAndDoc.window, winAndDoc.document);
this.redefineWindowOpen(element, winAndDoc.window, winAndDoc.document, navCtrl);
// Treat links.
this.treatFrameLinks(element, winAndDoc.document);
@ -276,7 +283,7 @@ export class CoreIframeUtilsProvider {
// Element loaded, redefine window.open and treat links again.
winAndDoc = this.getContentWindowAndDocument(element);
this.redefineWindowOpen(element, winAndDoc.window, winAndDoc.document);
this.redefineWindowOpen(element, winAndDoc.window, winAndDoc.document, navCtrl);
this.treatFrameLinks(element, winAndDoc.document);
if (winAndDoc.window) {