From 2c625850bcb3a505662e454afab009359ef370bf Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Fri, 26 Feb 2021 08:41:00 +0100 Subject: [PATCH] MOBILE-3708 iframe: Display warning in offline --- src/core/services/utils/iframe.ts | 90 +++++++++++++++++++++++++------ src/core/singletons/index.ts | 2 +- src/theme/theme.base.scss | 10 +++- 3 files changed, 83 insertions(+), 19 deletions(-) diff --git a/src/core/services/utils/iframe.ts b/src/core/services/utils/iframe.ts index 587759265..f14a84b34 100644 --- a/src/core/services/utils/iframe.ts +++ b/src/core/services/utils/iframe.ts @@ -25,10 +25,11 @@ import { CoreTextUtils } from '@services/utils/text'; import { CoreUrlUtils } from '@services/utils/url'; import { CoreUtils } from '@services/utils/utils'; -import { makeSingleton, Network, Platform, NgZone } from '@singletons'; +import { makeSingleton, Network, Platform, NgZone, Translate } from '@singletons'; import { CoreLogger } from '@singletons/logger'; import { CoreUrl } from '@singletons/url'; import { CoreWindow } from '@singletons/window'; +import { CoreContentLinksHelper } from '@features/contentlinks/services/contentlinks-helper'; /** * Possible types of frame elements. @@ -74,21 +75,7 @@ export class CoreIframeUtilsProvider { } // The frame has an online URL but the app is offline. Show a warning, or a link if the URL can be opened in the app. - const div = document.createElement('div'); - - div.setAttribute('text-center', ''); - div.setAttribute('padding', ''); - div.classList.add('core-iframe-offline-warning'); - - // @todo Handle link - - // Add a class to specify that the iframe is hidden. - element.classList.add('core-iframe-offline-disabled'); - - if (isSubframe) { - // We cannot apply CSS styles in subframes, just hide the iframe. - element.style.display = 'none'; - } + this.addOfflineWarning(element, src, isSubframe); // If the network changes, check it again. const subscription = Network.onConnect().subscribe(() => { @@ -124,6 +111,77 @@ export class CoreIframeUtilsProvider { return false; } + /** + * Add an offline warning message. + * + * @param element The frame to check (iframe, embed, ...). + * @param src Frame src. + * @param isSubframe Whether it's a frame inside another frame. + * @return Promise resolved when done. + */ + protected async addOfflineWarning(element: HTMLElement, src: string, isSubframe?: boolean): Promise { + const site = CoreSites.getCurrentSite(); + const username = site ? site.getInfo()?.username : undefined; + + const div = document.createElement('div'); + div.classList.add('core-iframe-offline-warning', 'ion-padding', 'ion-text-center'); + + // Add a class to specify that the iframe is hidden. + element.classList.add('core-iframe-offline-disabled'); + if (isSubframe) { + // We cannot apply CSS styles in subframes, just hide the iframe. + element.style.display = 'none'; + } + + const canHandleLink = await CoreContentLinksHelper.canHandleLink(src, undefined, username); + + if (!canHandleLink) { + // @todo: The not connected icon isn't seen due to the div's height. Also, it's quite big. + div.innerHTML = (isSubframe ? '' : '
') + + '

' + Translate.instant('core.networkerroriframemsg') + '

'; + + element.parentElement?.insertBefore(div, element); + + return; + } + + let link: HTMLElement | undefined; + + if (isSubframe) { + // Ionic styles are not available in subframes, adding some minimal inline styles. + link = document.createElement('a'); + link.style.display = 'block'; + link.style.padding = '1em'; + link.style.fontWeight = '500'; + link.style.textAlign = 'center'; + link.style.textTransform = 'uppercase'; + link.style.cursor = 'pointer'; + } else { + link = document.createElement('ion-button'); + link.setAttribute('expand', 'block'); + link.setAttribute('size', 'default'); + link.classList.add( + 'button', + 'button-block', + 'button-default', + 'button-solid', + 'ion-activatable', + 'ion-focusable', + ); + } + + link.innerHTML = Translate.instant('core.viewembeddedcontent'); + + link.onclick = (event: Event): void => { + CoreContentLinksHelper.handleLink(src, username); + event.preventDefault(); + }; + + div.appendChild(link); + + element.parentElement?.insertBefore(div, element); + } + /** * Given an element, return the content window and document. * Please notice that the element should be an iframe, embed or similar. diff --git a/src/core/singletons/index.ts b/src/core/singletons/index.ts index 7cf4d1e73..6999ef29c 100644 --- a/src/core/singletons/index.ts +++ b/src/core/singletons/index.ts @@ -252,4 +252,4 @@ export const NavController = makeSingleton(NavControllerService); export const Router = makeSingleton(RouterService, ['routerState', 'url']); // Convert external libraries injectables. -export const Translate = makeSingleton(TranslateService, ['onLangChange']); +export const Translate = makeSingleton(TranslateService, ['onLangChange', 'translations']); diff --git a/src/theme/theme.base.scss b/src/theme/theme.base.scss index a8c693a6f..43dfa088c 100644 --- a/src/theme/theme.base.scss +++ b/src/theme/theme.base.scss @@ -95,7 +95,8 @@ ion-button.button-small ion-icon.faicon[slot] { } // Ionic alert. -ion-alert.core-alert-network-error .alert-head { +ion-alert.core-alert-network-error .alert-head, +div.core-iframe-network-error { position: relative; content: " "; background: url("/assets/fonts/font-awesome/solid/wifi.svg") no-repeat 50% 50%; @@ -113,7 +114,8 @@ ion-alert.core-alert-network-error .alert-head { mask: url("/assets/fonts/font-awesome/solid/exclamation-triangle.svg") no-repeat 50% 50%; } } -[dir=rtl] ion-alert.core-alert-network-error .alert-head::after { +[dir=rtl] ion-alert.core-alert-network-error .alert-head::after, +[dir=rtl] div.core-iframe-network-error::after { right: unset; left: -15%; } @@ -442,3 +444,7 @@ ion-button.core-button-select { .core-monospaced { font-family: Andale Mono,Monaco,Courier New,DejaVu Sans Mono,monospace; } + +.core-iframe-offline-disabled { + display: none !important; +}