diff --git a/src/components/iframe/iframe.ts b/src/components/iframe/iframe.ts index 0bc3cabde..e1c8dd430 100644 --- a/src/components/iframe/iframe.ts +++ b/src/components/iframe/iframe.ts @@ -24,9 +24,6 @@ import { CoreUrlUtilsProvider } from '@providers/utils/url'; import { CoreIframeUtilsProvider } from '@providers/utils/iframe'; import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreSplitViewComponent } from '@components/split-view/split-view'; -import { CoreUrl } from '@singletons/url'; -import { CoreApp } from '@providers/app'; -import { WKWebViewCookiesWindow } from 'cordova-plugin-wkwebview-cookies'; @Component({ selector: 'core-iframe', @@ -107,24 +104,7 @@ export class CoreIframeComponent implements OnChanges { if (changes.src) { const url = this.urlUtils.getYoutubeEmbedUrl(changes.src.currentValue) || changes.src.currentValue; - if (CoreApp.instance.isIOS() && url && !this.urlUtils.isLocalFileUrl(url)) { - // Save a "fake" cookie for the iframe's domain to fix a bug in WKWebView. - try { - const win = window; - const urlParts = CoreUrl.parse(url); - - if (urlParts.domain) { - await win.WKWebViewCookies.setCookie({ - name: 'MoodleAppCookieForWKWebView', - value: '1', - domain: urlParts.domain, - }); - } - } catch (err) { - // Ignore errors. - this.logger.error('Error setting cookie', err); - } - } + await this.iframeUtils.fixIframeCookies(url); this.safeUrl = this.sanitizer.bypassSecurityTrustResourceUrl(CoreFile.instance.convertFileSrc(url)); diff --git a/src/directives/format-text.ts b/src/directives/format-text.ts index 6cc11c983..79f0f85e3 100644 --- a/src/directives/format-text.ts +++ b/src/directives/format-text.ts @@ -450,6 +450,7 @@ export class CoreFormatTextDirective implements OnChanges { const div = document.createElement('div'), canTreatVimeo = site && site.isVersionGreaterEqualThan(['3.3.4', '3.4']), navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl; + const promises = []; div.innerHTML = formatted; @@ -504,7 +505,7 @@ export class CoreFormatTextDirective implements OnChanges { }); iframes.forEach((iframe) => { - this.treatIframe(iframe, site, canTreatVimeo, navCtrl); + promises.push(this.treatIframe(iframe, site, canTreatVimeo, navCtrl)); }); svgImages.forEach((image) => { @@ -543,10 +544,9 @@ export class CoreFormatTextDirective implements OnChanges { this.domUtils.handleBootstrapTooltips(div); // Wait for images to load. - let promise: Promise = null; if (externalImages.length) { // Automatically reject the promise after 5 seconds to prevent blocking the user forever. - promise = this.utils.timeoutPromise(this.utils.allPromises(externalImages.map((externalImage): any => { + promises.push(this.utils.timeoutPromise(this.utils.allPromises(externalImages.map((externalImage): any => { if (externalImage.loaded) { // Image has already been loaded, no need to wait. return Promise.resolve(); @@ -558,12 +558,10 @@ export class CoreFormatTextDirective implements OnChanges { resolve(); }); }); - })), 5000); - } else { - promise = Promise.resolve(); + })), 5000)); } - return promise.catch(() => { + return Promise.all(promises).catch(() => { // Ignore errors. So content gets always shown. }).then(() => { result.div = div; @@ -665,7 +663,8 @@ export class CoreFormatTextDirective implements OnChanges { * @param canTreatVimeo Whether Vimeo videos can be treated in the site. * @param navCtrl NavController to use. */ - protected treatIframe(iframe: HTMLIFrameElement, site: CoreSite, canTreatVimeo: boolean, navCtrl: NavController): void { + protected async treatIframe(iframe: HTMLIFrameElement, site: CoreSite, canTreatVimeo: boolean, navCtrl: NavController) + : Promise { const src = iframe.src, currentSite = this.sitesProvider.getCurrentSite(); @@ -673,15 +672,19 @@ export class CoreFormatTextDirective implements OnChanges { if (currentSite && currentSite.containsUrl(src)) { // URL points to current site, try to use auto-login. - currentSite.getAutoLoginUrl(src, false).then((finalUrl) => { - iframe.src = finalUrl; + const finalUrl = await currentSite.getAutoLoginUrl(src, false); - this.iframeUtils.treatFrame(iframe, false, navCtrl); - }); + await this.iframeUtils.fixIframeCookies(finalUrl); + + iframe.src = finalUrl; + + this.iframeUtils.treatFrame(iframe, false, navCtrl); return; } + await this.iframeUtils.fixIframeCookies(src); + if (src && canTreatVimeo) { // Check if it's a Vimeo video. If it is, use the wsplayer script instead to make restricted videos work. const matches = iframe.src.match(/https?:\/\/player\.vimeo\.com\/video\/([0-9]+)/); @@ -714,6 +717,9 @@ export class CoreFormatTextDirective implements OnChanges { if (site && !site.isVersionGreaterEqualThan('3.7')) { newUrl += '&width=' + width + '&height=' + height; } + + await this.iframeUtils.fixIframeCookies(newUrl); + iframe.src = newUrl; if (!iframe.width) { diff --git a/src/providers/utils/iframe.ts b/src/providers/utils/iframe.ts index 0fdc5af74..56c5e11c8 100644 --- a/src/providers/utils/iframe.ts +++ b/src/providers/utils/iframe.ts @@ -30,6 +30,7 @@ import { makeSingleton } from '@singletons/core.singletons'; import { CoreUrl } from '@singletons/url'; import { CoreWindow } from '@singletons/window'; import { WKUserScriptWindow, WKUserScriptInjectionTime } from 'cordova-plugin-wkuserscript'; +import { WKWebViewCookiesWindow } from 'cordova-plugin-wkwebview-cookies'; /* * "Utils" service with helper functions for iframes, embed and similar. @@ -488,6 +489,36 @@ export class CoreIframeUtilsProvider { } } } + + /** + * Fix cookies for an iframe URL. + * + * @param url URL of the iframe. + * @return Promise resolved when done. + */ + async fixIframeCookies(url: string): Promise { + if (!CoreApp.instance.isIOS() || !url || this.urlUtils.isLocalFileUrl(url)) { + // No need to fix cookies. + return; + } + + // Save a "fake" cookie for the iframe's domain to fix a bug in WKWebView. + try { + const win = window; + const urlParts = CoreUrl.parse(url); + + if (urlParts.domain) { + await win.WKWebViewCookies.setCookie({ + name: 'MoodleAppCookieForWKWebView', + value: '1', + domain: urlParts.domain, + }); + } + } catch (err) { + // Ignore errors. + this.logger.error('Error setting cookie', err); + } + } } export class CoreIframeUtils extends makeSingleton(CoreIframeUtilsProvider) {}