diff --git a/scripts/langindex.json b/scripts/langindex.json
index db5d12893..e96142599 100644
--- a/scripts/langindex.json
+++ b/scripts/langindex.json
@@ -1478,6 +1478,7 @@
"core.coursenogroups": "local_moodlemobileapp",
"core.courses.addtofavourites": "block_myoverview",
"core.courses.allowguests": "enrol_guest",
+ "core.courses.aria:coursecategory": "course",
"core.courses.aria:coursename": "course",
"core.courses.aria:courseprogress": "block_myoverview",
"core.courses.aria:favourite": "course",
@@ -1740,10 +1741,12 @@
"core.hour": "moodle",
"core.hours": "moodle",
"core.humanreadablesize": "local_moodlemobileapp",
+ "core.iframehelp": "local_moodlemobileapp",
"core.image": "local_moodlemobileapp",
"core.imageviewer": "local_moodlemobileapp",
"core.info": "moodle",
"core.invalidformdata": "error",
+ "core.ioscookieshelp": "local_moodlemobileapp",
"core.labelsep": "langconfig",
"core.lastaccess": "moodle",
"core.lastdownloaded": "local_moodlemobileapp",
@@ -1950,6 +1953,7 @@
"core.openfullimage": "local_moodlemobileapp",
"core.openinbrowser": "local_moodlemobileapp",
"core.openmodinbrowser": "local_moodlemobileapp",
+ "core.opensettings": "local_moodlemobileapp",
"core.othergroups": "group",
"core.pagea": "moodle",
"core.parentlanguage": "langconfig",
@@ -2059,6 +2063,8 @@
"core.settings.fontsizecharacter": "block_accessibility/char",
"core.settings.forcedsetting": "local_moodlemobileapp",
"core.settings.general": "moodle",
+ "core.settings.ioscookies": "local_moodlemobileapp",
+ "core.settings.ioscookiesdescription": "local_moodlemobileapp",
"core.settings.language": "moodle",
"core.settings.license": "moodle",
"core.settings.localnotifavailable": "local_moodlemobileapp",
diff --git a/src/core/components/iframe/core-iframe.html b/src/core/components/iframe/core-iframe.html
index 1c05ee6e4..def2619f3 100644
--- a/src/core/components/iframe/core-iframe.html
+++ b/src/core/components/iframe/core-iframe.html
@@ -5,7 +5,13 @@
[attr.allowfullscreen]="allowFullscreen ? 'allowfullscreen' : null">
+
+
+ {{ 'core.iframehelp' | translate }}
+
+
+
-
\ No newline at end of file
+
diff --git a/src/core/components/iframe/iframe.ts b/src/core/components/iframe/iframe.ts
index bc4c7a656..cb1ecd059 100644
--- a/src/core/components/iframe/iframe.ts
+++ b/src/core/components/iframe/iframe.ts
@@ -40,6 +40,7 @@ export class CoreIframeComponent implements OnChanges {
loading?: boolean;
safeUrl?: SafeResourceUrl;
+ displayHelp = false;
protected readonly IFRAME_TIMEOUT = 15000;
protected logger: CoreLogger;
@@ -100,6 +101,7 @@ export class CoreIframeComponent implements OnChanges {
async ngOnChanges(changes: {[name: string]: SimpleChange }): Promise {
if (changes.src) {
const url = CoreUrlUtils.getYoutubeEmbedUrl(changes.src.currentValue) || changes.src.currentValue;
+ this.displayHelp = CoreIframeUtils.shouldDisplayHelpForUrl(url);
await CoreIframeUtils.fixIframeCookies(url);
@@ -112,4 +114,11 @@ export class CoreIframeComponent implements OnChanges {
}
}
+ /**
+ * Open help modal for iframes.
+ */
+ openIframeHelpModal(): void {
+ CoreIframeUtils.openIframeHelpModal();
+ }
+
}
diff --git a/src/core/directives/format-text.ts b/src/core/directives/format-text.ts
index 4ceb07fea..0b1e0c388 100644
--- a/src/core/directives/format-text.ts
+++ b/src/core/directives/format-text.ts
@@ -682,6 +682,10 @@ export class CoreFormatTextDirective implements OnChanges {
this.addMediaAdaptClass(iframe);
+ if (CoreIframeUtils.shouldDisplayHelpForUrl(src)) {
+ this.addIframeHelp(iframe);
+ }
+
if (currentSite?.containsUrl(src)) {
// URL points to current site, try to use auto-login.
const finalUrl = await currentSite.getAutoLoginUrl(src, false);
@@ -757,6 +761,32 @@ export class CoreFormatTextDirective implements OnChanges {
CoreIframeUtils.treatFrame(iframe, false);
}
+ /**
+ * Add iframe help option.
+ *
+ * @param iframe Iframe.
+ */
+ protected addIframeHelp(iframe: HTMLIFrameElement): void {
+ const helpDiv = document.createElement('div');
+
+ helpDiv.classList.add('ion-text-center');
+ helpDiv.classList.add('ion-text-wrap');
+ helpDiv.classList.add('core-iframe-help');
+
+ const button = document.createElement('ion-button');
+ button.setAttribute('fill', 'clear');
+ button.setAttribute('aria-haspopup', 'dialog');
+ button.innerHTML = Translate.instant('core.iframehelp');
+
+ button.addEventListener('click', () => {
+ CoreIframeUtils.openIframeHelpModal();
+ });
+
+ helpDiv.appendChild(button);
+
+ iframe.after(helpDiv);
+ }
+
/**
* Convert window.open to window.openWindowSafely inside HTML tags.
*
diff --git a/src/core/features/settings/lang.json b/src/core/features/settings/lang.json
index 9252a449f..b1580a355 100644
--- a/src/core/features/settings/lang.json
+++ b/src/core/features/settings/lang.json
@@ -42,6 +42,8 @@
"fontsizecharacter": "A",
"forcedsetting": "This setting has been forced by your site configuration.",
"general": "General",
+ "ioscookies": "Cross-Website Tracking",
+ "ioscookiesdescription": "Embedded content from the site might require cross-site cookies to work. To enable it, please go to the app's iOS settings and enable 'Allow Cross-Website Tracking'.",
"language": "Language",
"license": "Licence",
"localnotifavailable": "Local notifications available",
diff --git a/src/core/features/settings/pages/general/general.html b/src/core/features/settings/pages/general/general.html
index bb88ee283..c16a1e80c 100644
--- a/src/core/features/settings/pages/general/general.html
+++ b/src/core/features/settings/pages/general/general.html
@@ -54,6 +54,15 @@
+
+
+ {{ 'core.settings.ioscookies' | translate }}
+ {{ 'core.settings.ioscookiesdescription' | translate }}
+
+ {{ 'core.opensettings' | translate }}
+
+
+
{{ 'core.settings.debugdisplay' | translate }}
diff --git a/src/core/features/settings/pages/general/general.ts b/src/core/features/settings/pages/general/general.ts
index ff2270908..344164a37 100644
--- a/src/core/features/settings/pages/general/general.ts
+++ b/src/core/features/settings/pages/general/general.ts
@@ -21,6 +21,8 @@ import { CoreDomUtils } from '@services/utils/dom';
import { CorePushNotifications } from '@features/pushnotifications/services/pushnotifications';
import { CoreSettingsHelper, CoreColorScheme, CoreZoomLevel } from '../../services/settings-helper';
import { CoreApp } from '@services/app';
+import { CoreIframeUtils } from '@services/utils/iframe';
+import { Diagnostic } from '@singletons';
/**
* Page that displays the general settings.
@@ -44,6 +46,7 @@ export class CoreSettingsGeneralPage {
selectedScheme: CoreColorScheme = CoreColorScheme.LIGHT;
colorSchemeDisabled = false;
isAndroid = false;
+ displayIframeHelp = false;
constructor() {
this.asyncInit();
@@ -98,6 +101,8 @@ export class CoreSettingsGeneralPage {
if (this.analyticsSupported) {
this.analyticsEnabled = await CoreConfig.get(CoreConstants.SETTINGS_ANALYTICS_ENABLED, true);
}
+
+ this.displayIframeHelp = CoreIframeUtils.shouldDisplayHelp();
}
/**
@@ -155,4 +160,11 @@ export class CoreSettingsGeneralPage {
CoreConfig.set(CoreConstants.SETTINGS_ANALYTICS_ENABLED, this.analyticsEnabled ? 1 : 0);
}
+ /**
+ * Open native settings.
+ */
+ openNativeSettings(): void {
+ Diagnostic.switchToSettings();
+ }
+
}
diff --git a/src/core/lang.json b/src/core/lang.json
index a2b8c14b5..bc1cf8e64 100644
--- a/src/core/lang.json
+++ b/src/core/lang.json
@@ -129,10 +129,12 @@
"hour": "hour",
"hours": "hours",
"humanreadablesize": "{{size}} {{unit}}",
+ "iframehelp": "Is this content not working?",
"image": "Image",
"imageviewer": "Image viewer",
"info": "Information",
"invalidformdata": "Incorrect form data",
+ "ioscookieshelp": "Embedded content might require cookies to work. Please go to the app's iOS settings, enable 'Allow Cross-Website Tracking' and try again.",
"labelsep": ":",
"filter": "Filter",
"lastaccess": "Last access",
@@ -213,6 +215,7 @@
"openfullimage": "Click here to display the full size image",
"openinbrowser": "Open in browser",
"openmodinbrowser": "Open {{$a}} in browser",
+ "opensettings": "Open settings",
"othergroups": "Other groups",
"pagea": "Page {{$a}}",
"parentlanguage": "",
diff --git a/src/core/services/utils/iframe.ts b/src/core/services/utils/iframe.ts
index 064f24380..35e17cfbb 100644
--- a/src/core/services/utils/iframe.ts
+++ b/src/core/services/utils/iframe.ts
@@ -25,7 +25,7 @@ import { CoreTextUtils } from '@services/utils/text';
import { CoreUrlUtils } from '@services/utils/url';
import { CoreUtils } from '@services/utils/utils';
-import { makeSingleton, Network, Platform, NgZone, Translate } from '@singletons';
+import { makeSingleton, Network, Platform, NgZone, Translate, Diagnostic } from '@singletons';
import { CoreLogger } from '@singletons/logger';
import { CoreUrl } from '@singletons/url';
import { CoreWindow } from '@singletons/window';
@@ -558,6 +558,47 @@ export class CoreIframeUtilsProvider {
}
}
+ /**
+ * Check whether the help should be displayed in current OS.
+ *
+ * @return Boolean.
+ */
+ shouldDisplayHelp(): boolean {
+ return CoreApp.isIOS() && CoreApp.getPlatformMajorVersion() >= 14;
+ }
+
+ /**
+ * Check whether the help should be displayed for a certain iframe.
+ *
+ * @param url Iframe URL.
+ * @return Boolean.
+ */
+ shouldDisplayHelpForUrl(url: string): boolean {
+ return this.shouldDisplayHelp() && !CoreUrlUtils.isLocalFileUrl(url);
+ }
+
+ /**
+ * Open help modal for iframes.
+ */
+ openIframeHelpModal(): void {
+ CoreDomUtils.showAlertWithOptions({
+ header: Translate.instant('core.settings.ioscookies'),
+ message: Translate.instant('core.ioscookieshelp'),
+ buttons: [
+ {
+ text: Translate.instant('core.cancel'),
+ role: 'cancel',
+ },
+ {
+ text: Translate.instant('core.opensettings'),
+ handler: (): void => {
+ Diagnostic.switchToSettings();
+ },
+ },
+ ],
+ });
+ }
+
}
export const CoreIframeUtils = makeSingleton(CoreIframeUtilsProvider);
diff --git a/src/theme/theme.base.scss b/src/theme/theme.base.scss
index 65735f44e..1e33ab0ef 100644
--- a/src/theme/theme.base.scss
+++ b/src/theme/theme.base.scss
@@ -526,3 +526,9 @@ img.core-media-adapt-width {
audio.core-media-adapt-width {
width: 100%;
}
+
+.core-iframe-help ion-button {
+ text-transform: none;
+ text-decoration: underline;
+ --color: initial;
+}