diff --git a/config.xml b/config.xml
index 3260607d7..ae353eb0d 100644
--- a/config.xml
+++ b/config.xml
@@ -47,7 +47,7 @@
-
+
diff --git a/src/core/components/iframe/iframe.ts b/src/core/components/iframe/iframe.ts
index 522d46867..116b672d6 100644
--- a/src/core/components/iframe/iframe.ts
+++ b/src/core/components/iframe/iframe.ts
@@ -57,9 +57,13 @@ export class CoreIframeComponent implements OnChanges, OnDestroy {
protected style?: HTMLStyleElement;
protected orientationObs?: CoreEventObserver;
protected navSubscription?: Subscription;
+ protected messageListenerFunction: (event: MessageEvent) => Promise;
constructor(protected elementRef: ElementRef) {
this.loaded = new EventEmitter();
+
+ // Listen for messages from the iframe.
+ window.addEventListener('message', this.messageListenerFunction = (event) => this.onIframeMessage(event));
}
/**
@@ -177,12 +181,13 @@ export class CoreIframeComponent implements OnChanges, OnDestroy {
ngOnDestroy(): void {
this.orientationObs?.off();
this.navSubscription?.unsubscribe();
+ window.removeEventListener('message', this.messageListenerFunction);
}
/**
* Toggle fullscreen mode.
*/
- toggleFullscreen(enable?: boolean): void {
+ toggleFullscreen(enable?: boolean, notifyIframe = true): void {
if (enable !== undefined) {
this.fullscreen = enable;
} else {
@@ -200,6 +205,27 @@ export class CoreIframeComponent implements OnChanges, OnDestroy {
}
document.body.classList.toggle('core-iframe-fullscreen', this.fullscreen);
+
+ if (notifyIframe && this.iframe?.nativeElement) {
+ ( this.iframe.nativeElement).contentWindow?.postMessage(
+ this.fullscreen ? 'enterFullScreen' : 'exitFullScreen',
+ '*',
+ );
+ }
+ }
+
+ /**
+ * Treat an iframe message event.
+ *
+ * @param event Event.
+ * @return Promise resolved when done.
+ */
+ protected async onIframeMessage(event: MessageEvent): Promise {
+ if (event.data == 'enterFullScreen' && this.showFullscreenOnToolbar && !this.fullscreen) {
+ this.toggleFullscreen(true, false);
+ } else if (event.data == 'exitFullScreen' && this.fullscreen) {
+ this.toggleFullscreen(false, false);
+ }
}
}
diff --git a/src/core/features/h5p/assets/js/h5p.js b/src/core/features/h5p/assets/js/h5p.js
index 424ac842f..7cb831751 100644
--- a/src/core/features/h5p/assets/js/h5p.js
+++ b/src/core/features/h5p/assets/js/h5p.js
@@ -22,6 +22,11 @@ H5P.$window = H5P.jQuery(window);
*/
H5P.instances = [];
+function isIOS() {
+ return ['iPad Simulator', 'iPhone Simulator', 'iPod Simulator', 'iPad', 'iPhone', 'iPod'].includes(navigator.platform)
+ || (navigator.userAgent.includes("Mac") && "ontouchend" in document);
+}
+
// Detect if we support fullscreen, and what prefix to use.
if (document.documentElement.requestFullScreen) {
/**
@@ -32,23 +37,23 @@ if (document.documentElement.requestFullScreen) {
H5P.fullScreenBrowserPrefix = '';
}
else if (document.documentElement.webkitRequestFullScreen) {
- // This code has been changed to allow full screen in Moodle app.
- H5P.fullScreenBrowserPrefix = 'webkit';
- H5P.safariBrowser = 0;
+ H5P.safariBrowser = navigator.userAgent.match(/version\/([.\d]+)/i);
+ H5P.safariBrowser = (H5P.safariBrowser === null ? 0 : parseInt(H5P.safariBrowser[1]));
- // H5P.safariBrowser = navigator.userAgent.match(/version\/([.\d]+)/i);
- // H5P.safariBrowser = (H5P.safariBrowser === null ? 0 : parseInt(H5P.safariBrowser[1]));
-
- // // Do not allow fullscreen for safari < 7.
- // if (H5P.safariBrowser === 0 || H5P.safariBrowser > 6) {
- // H5P.fullScreenBrowserPrefix = 'webkit';
- // }
+ // Do not allow fullscreen for safari < 7.
+ if (H5P.safariBrowser === 0 || H5P.safariBrowser > 6) {
+ H5P.fullScreenBrowserPrefix = 'webkit';
+ }
}
else if (document.documentElement.mozRequestFullScreen) {
H5P.fullScreenBrowserPrefix = 'moz';
}
else if (document.documentElement.msRequestFullscreen) {
H5P.fullScreenBrowserPrefix = 'ms';
+} else if (isIOS()) {
+ // This code has been added to allow a "fake" full screen in Moodle app.
+ H5P.fullScreenBrowserPrefix = 'webkit';
+ H5P.safariBrowser = 0;
}
/**
@@ -165,6 +170,17 @@ H5P.init = function (target) {
}
})
;
+
+ if (isIOS()) {
+ // Register message listener to enter fullscreen.
+ window.addEventListener('message', function receiveMessage(event) {
+ if (event.data == 'enterFullScreen') {
+ H5P.fullScreen($container, instance);
+ } else if (event.data == 'exitFullScreen') {
+ H5P.exitFullScreen();
+ }
+ }, false);
+ }
}
/**
@@ -587,7 +603,7 @@ H5P.fullScreen = function ($element, instance, exitCallback, body, forceSemiFull
};
H5P.isFullscreen = true;
- if (H5P.fullScreenBrowserPrefix === undefined || forceSemiFullScreen === true) {
+ if (forceSemiFullScreen === true) {
// Create semi fullscreen.
if (H5P.isFramed) {
@@ -666,7 +682,13 @@ H5P.fullScreen = function ($element, instance, exitCallback, body, forceSemiFull
else {
var method = (H5P.fullScreenBrowserPrefix === 'ms' ? 'msRequestFullscreen' : H5P.fullScreenBrowserPrefix + 'RequestFullScreen');
var params = (H5P.fullScreenBrowserPrefix === 'webkit' && H5P.safariBrowser === 0 ? Element.ALLOW_KEYBOARD_INPUT : undefined);
- $element[0][method](params);
+
+ if (isIOS()) {
+ before('h5p-fullscreen-ios');
+ window.parent.postMessage('enterFullScreen', '*');
+ } else {
+ $element[0][method](params);
+ }
}
// Allows everone to exit
@@ -678,12 +700,28 @@ H5P.fullScreen = function ($element, instance, exitCallback, body, forceSemiFull
document.mozCancelFullScreen();
}
else {
- document[H5P.fullScreenBrowserPrefix + 'ExitFullscreen']();
+ done('h5p-fullscreen');
+ document[H5P.fullScreenBrowserPrefix + 'ExitFullscreen'] && document[H5P.fullScreenBrowserPrefix + 'ExitFullscreen']();
+ if (isIOS()) {
+ done('h5p-fullscreen-ios');
+ window.parent.postMessage('exitFullScreen', '*');
+ }
}
};
}
};
+if (isIOS()) {
+ // Pass fullscreen messages to child iframes.
+ window.addEventListener('message', function receiveMessage(event) {
+ if (event.data === 'enterFullScreen' || event.data === 'exitFullScreen') {
+ Array.from(document.querySelectorAll('iframe')).forEach(function (iframe) {
+ iframe.contentWindow && iframe.contentWindow.postMessage(event.data, '*');
+ });
+ }
+ }, false);
+}
+
(function () {
/**
* Helper for adding a query parameter to an existing path that may already