Merge pull request #4276 from dpalou/MOBILE-4018
MOBILE-4018 iframe: Make open iframe links more consistentmain
commit
b130e32423
|
@ -21,12 +21,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redefine window.open.
|
// Redefine window.open.
|
||||||
|
const originalWindowOpen = window.open;
|
||||||
window.open = function(url, name, specs) {
|
window.open = function(url, name, specs) {
|
||||||
if (name == '_self') {
|
if (name == '_self') {
|
||||||
// Link should be loaded in the same frame.
|
// Link will be opened in the same frame, no need to treat it.
|
||||||
location.href = toAbsolute(url);
|
return originalWindowOpen(url, name, specs);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getRootWindow(window).postMessage({
|
getRootWindow(window).postMessage({
|
||||||
|
@ -34,7 +33,7 @@
|
||||||
context: 'iframe',
|
context: 'iframe',
|
||||||
action: 'window_open',
|
action: 'window_open',
|
||||||
frameUrl: location.href,
|
frameUrl: location.href,
|
||||||
url: url,
|
url: toAbsolute(url),
|
||||||
name: name,
|
name: name,
|
||||||
specs: specs,
|
specs: specs,
|
||||||
}, '*');
|
}, '*');
|
||||||
|
@ -164,24 +163,19 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const linkScheme = getUrlScheme(link.href);
|
if (!link.target || link.target == '_self') {
|
||||||
const pageScheme = getUrlScheme(location.href);
|
// Link needs to be opened in the same iframe. This is already handled properly, we don't need to do anything else.
|
||||||
const isTargetSelf = !link.target || link.target == '_self';
|
// Links opened in the same iframe won't be captured by the app.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!link.href || linkScheme == 'javascript') {
|
if (!link.href || getUrlScheme(link.href) == 'javascript') {
|
||||||
// Links with no URL and Javascript links are ignored.
|
// Links with no URL and Javascript links are ignored.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if (isTargetSelf && (isLocalFileUrlScheme(linkScheme) || !isLocalFileUrlScheme(pageScheme))) {
|
|
||||||
// Link should be loaded in the same frame. Don't do it if link is online and frame is local.
|
|
||||||
location.href = toAbsolute(link.href);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
getRootWindow(window).postMessage({
|
getRootWindow(window).postMessage({
|
||||||
environment: 'moodleapp',
|
environment: 'moodleapp',
|
||||||
context: 'iframe',
|
context: 'iframe',
|
||||||
|
|
|
@ -18,7 +18,6 @@ import { WKWebViewCookiesWindow } from 'cordova-plugin-wkwebview-cookies';
|
||||||
|
|
||||||
import { CoreNetwork } from '@services/network';
|
import { CoreNetwork } from '@services/network';
|
||||||
import { CoreFile } from '@services/file';
|
import { CoreFile } from '@services/file';
|
||||||
import { CoreFileHelper } from '@services/file-helper';
|
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreUrl } from '@singletons/url';
|
import { CoreUrl } from '@singletons/url';
|
||||||
|
@ -313,7 +312,13 @@ export class CoreIframeUtilsProvider {
|
||||||
): void {
|
): void {
|
||||||
if (contentWindow) {
|
if (contentWindow) {
|
||||||
// Intercept window.open.
|
// Intercept window.open.
|
||||||
|
const originalWindowOpen = contentWindow.open;
|
||||||
contentWindow.open = (url: string, name: string) => {
|
contentWindow.open = (url: string, name: string) => {
|
||||||
|
if (name === '_self') {
|
||||||
|
// Link will be opened in the same frame, no need to treat it.
|
||||||
|
return originalWindowOpen(url, name);
|
||||||
|
}
|
||||||
|
|
||||||
this.windowOpen(url, name, element);
|
this.windowOpen(url, name, element);
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
@ -410,7 +415,7 @@ export class CoreIframeUtilsProvider {
|
||||||
|
|
||||||
// Add click listener to the link, this way if the iframe has added a listener to the link it will be executed first.
|
// Add click listener to the link, this way if the iframe has added a listener to the link it will be executed first.
|
||||||
link.treated = true;
|
link.treated = true;
|
||||||
link.addEventListener('click', event => this.linkClicked(link, element, event));
|
link.addEventListener('click', event => this.linkClicked(link, event));
|
||||||
}, {
|
}, {
|
||||||
capture: true, // Use capture to fix this listener not called if the element clicked is too deep in the DOM.
|
capture: true, // Use capture to fix this listener not called if the element clicked is too deep in the DOM.
|
||||||
});
|
});
|
||||||
|
@ -447,26 +452,11 @@ export class CoreIframeUtilsProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name == '_self') {
|
try {
|
||||||
// Link should be loaded in the same frame.
|
// It's an external link or a local file, check if it can be opened in the app.
|
||||||
if (!element) {
|
await CoreWindow.open(url, name);
|
||||||
this.logger.warn('Cannot load URL in iframe because the element was not supplied', url);
|
} catch (error) {
|
||||||
|
CoreDomUtils.showErrorModal(error);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element.tagName.toLowerCase() === 'object') {
|
|
||||||
element.setAttribute('data', url);
|
|
||||||
} else {
|
|
||||||
element.setAttribute('src', url);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
// It's an external link or a local file, check if it can be opened in the app.
|
|
||||||
await CoreWindow.open(url, name);
|
|
||||||
} catch (error) {
|
|
||||||
CoreDomUtils.showErrorModal(error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,13 +464,11 @@ export class CoreIframeUtilsProvider {
|
||||||
* A link inside a frame was clicked.
|
* A link inside a frame was clicked.
|
||||||
*
|
*
|
||||||
* @param link Link clicked, or data of the link clicked.
|
* @param link Link clicked, or data of the link clicked.
|
||||||
* @param element Frame element.
|
|
||||||
* @param event Click event.
|
* @param event Click event.
|
||||||
* @returns Promise resolved when done.
|
* @returns Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected async linkClicked(
|
protected async linkClicked(
|
||||||
link: CoreIframeHTMLAnchorElement | {href: string; target?: string; originalHref?: string},
|
link: CoreIframeHTMLAnchorElement | {href: string; target?: string; originalHref?: string},
|
||||||
element?: CoreFrameElement,
|
|
||||||
event?: Event,
|
event?: Event,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (event && event.defaultPrevented) {
|
if (event && event.defaultPrevented) {
|
||||||
|
@ -488,69 +476,24 @@ export class CoreIframeUtilsProvider {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!link.target || link.target === '_self') {
|
||||||
|
// Link needs to be opened in the same iframe. This is already handled properly, we don't need to do anything else.
|
||||||
|
// Links opened in the same iframe won't be captured by the app.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const urlParts = CoreUrl.parse(link.href);
|
const urlParts = CoreUrl.parse(link.href);
|
||||||
const originalHref = 'getAttribute' in link ? link.getAttribute('href') : link.originalHref;
|
const originalHref = 'getAttribute' in link ? link.getAttribute('href') : link.originalHref;
|
||||||
if (!link.href || !originalHref || originalHref == '#' || !urlParts || urlParts.protocol === 'javascript') {
|
if (!link.href || !originalHref || originalHref === '#' || !urlParts || urlParts.protocol === 'javascript') {
|
||||||
// Links with no URL and Javascript links are ignored.
|
// Links with no URL and Javascript links are ignored.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (urlParts.protocol && !CoreUrl.isLocalFileUrlScheme(urlParts.protocol, urlParts.domain || '')) {
|
try {
|
||||||
// Scheme suggests it's an external resource.
|
event?.preventDefault();
|
||||||
event && event.preventDefault();
|
await CoreWindow.open(link.href, link.target);
|
||||||
|
} catch (error) {
|
||||||
const frameSrc = element && ((<HTMLIFrameElement> element).src || (<HTMLObjectElement> element).data);
|
CoreDomUtils.showErrorModal(error);
|
||||||
|
|
||||||
// If the frame is not local, check the target to identify how to treat the link.
|
|
||||||
if (
|
|
||||||
element &&
|
|
||||||
frameSrc &&
|
|
||||||
!CoreUrl.isLocalFileUrl(frameSrc) &&
|
|
||||||
(!link.target || link.target == '_self')
|
|
||||||
) {
|
|
||||||
// Load the link inside the frame itself.
|
|
||||||
if (element.tagName.toLowerCase() === 'object') {
|
|
||||||
element.setAttribute('data', link.href);
|
|
||||||
} else {
|
|
||||||
element.setAttribute('src', link.href);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The frame is local or the link needs to be opened in a new window. Open in browser.
|
|
||||||
if (!CoreSites.isLoggedIn()) {
|
|
||||||
CoreOpener.openInBrowser(link.href);
|
|
||||||
} else {
|
|
||||||
await CoreSites.getCurrentSite()?.openInBrowserWithAutoLogin(link.href);
|
|
||||||
}
|
|
||||||
} else if (link.target == '_parent' || link.target == '_top' || link.target == '_blank') {
|
|
||||||
// Opening links with _parent, _top or _blank can break the app. We'll open it in InAppBrowser.
|
|
||||||
event && event.preventDefault();
|
|
||||||
|
|
||||||
const filename = link.href.substring(link.href.lastIndexOf('/') + 1);
|
|
||||||
|
|
||||||
if (!CoreFileHelper.isOpenableInApp({ filename })) {
|
|
||||||
try {
|
|
||||||
await CoreFileHelper.showConfirmOpenUnsupportedFile(false, { filename });
|
|
||||||
} catch (error) {
|
|
||||||
return; // Cancelled, stop.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await CoreOpener.openFile(link.href);
|
|
||||||
} catch (error) {
|
|
||||||
CoreDomUtils.showErrorModal(error);
|
|
||||||
}
|
|
||||||
} else if (CorePlatform.isIOS() && (!link.target || link.target == '_self') && element) {
|
|
||||||
// In cordova ios 4.1.0 links inside iframes stopped working. We'll manually treat them.
|
|
||||||
event && event.preventDefault();
|
|
||||||
if (element.tagName.toLowerCase() === 'object') {
|
|
||||||
element.setAttribute('data', link.href);
|
|
||||||
} else {
|
|
||||||
element.setAttribute('src', link.href);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ export class CoreWindow {
|
||||||
} else {
|
} else {
|
||||||
let treated = false;
|
let treated = false;
|
||||||
|
|
||||||
if (name != '_system') {
|
if (name !== '_system') {
|
||||||
// Check if it can be opened in the app.
|
// Check if it can be opened in the app.
|
||||||
treated = await CoreContentLinksHelper.handleLink(url, undefined, true, true);
|
treated = await CoreContentLinksHelper.handleLink(url, undefined, true, true);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue