MOBILE-3098 iframe: Open in app links inside iframes
parent
ea7caaed20
commit
8d64fea2af
|
@ -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', () => {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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,7 +230,10 @@ 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.
|
||||
// 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);
|
||||
|
@ -237,6 +241,8 @@ export class CoreIframeUtilsProvider {
|
|||
this.sitesProvider.getCurrentSite().openInBrowserWithAutoLoginIfSameSite(url);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// We cannot create new Window objects directly, return null which is a valid return value for Window.open().
|
||||
return null;
|
||||
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue