MOBILE-4669 scorm: Fix height problems in online player
parent
bab16335d0
commit
20a39bbcb5
|
@ -980,10 +980,7 @@
|
|||
"addon.mod_scorm.errorcreateofflineattempt": "local_moodlemobileapp",
|
||||
"addon.mod_scorm.errordownloadscorm": "local_moodlemobileapp",
|
||||
"addon.mod_scorm.errorgetscorm": "local_moodlemobileapp",
|
||||
"addon.mod_scorm.errorinvalidversion": "local_moodlemobileapp",
|
||||
"addon.mod_scorm.errornotdownloadable": "local_moodlemobileapp",
|
||||
"addon.mod_scorm.errornovalidsco": "local_moodlemobileapp",
|
||||
"addon.mod_scorm.errorpackagefile": "local_moodlemobileapp",
|
||||
"addon.mod_scorm.errorsyncscorm": "local_moodlemobileapp",
|
||||
"addon.mod_scorm.exceededmaxattempts": "scorm",
|
||||
"addon.mod_scorm.failed": "scorm",
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<ion-content>
|
||||
<core-loading [hideUntil]="loaded">
|
||||
<core-iframe *ngIf="loaded" id="scorm_object" [src]="src" [iframeWidth]="scormWidth" [iframeHeight]="scormHeight"
|
||||
[showFullscreenOnToolbar]="true" [autoFullscreenOnRotate]="true" />
|
||||
[showFullscreenOnToolbar]="true" [autoFullscreenOnRotate]="enableFullScreenOnRotate" (loaded)="iframeLoaded()" />
|
||||
|
||||
<p *ngIf="!src && errorMessage">{{ errorMessage | translate }}</p>
|
||||
</core-loading>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreSitesReadingStrategy } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
|
@ -31,6 +31,8 @@ import { Subscription } from 'rxjs';
|
|||
import { CoreNetwork } from '@services/network';
|
||||
import { NgZone, Translate } from '@singletons';
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
import { CoreWait } from '@singletons/wait';
|
||||
import { CoreIframeComponent } from '@components/iframe/iframe';
|
||||
|
||||
/**
|
||||
* Page that allows playing a SCORM in online, served from the server.
|
||||
|
@ -45,6 +47,8 @@ import { CoreError } from '@classes/errors/error';
|
|||
})
|
||||
export default class AddonModScormOnlinePlayerPage implements OnInit, OnDestroy {
|
||||
|
||||
@ViewChild(CoreIframeComponent) iframe?: CoreIframeComponent;
|
||||
|
||||
scorm!: AddonModScormScorm; // The SCORM object.
|
||||
loaded = false; // Whether the data has been loaded.
|
||||
src?: string; // Iframe src.
|
||||
|
@ -53,6 +57,7 @@ export default class AddonModScormOnlinePlayerPage implements OnInit, OnDestroy
|
|||
scormHeight?: number; // Height applied to scorm iframe.
|
||||
cmId!: number; // Course module ID.
|
||||
courseId!: number; // Course ID.
|
||||
enableFullScreenOnRotate = false;
|
||||
|
||||
protected mode!: AddonModScormMode; // Mode to play the SCORM.
|
||||
protected moduleUrl!: string; // Module URL.
|
||||
|
@ -73,9 +78,9 @@ export default class AddonModScormOnlinePlayerPage implements OnInit, OnDestroy
|
|||
|
||||
if (!isOnline && wasOnline) {
|
||||
// User lost connection while playing an online package. Show an error.
|
||||
CoreDomUtils.showErrorModal(new CoreError(Translate.instant('core.course.changesofflinemaybelost'))); // , {
|
||||
// title: Translate.instant('core.youreoffline'),
|
||||
// }));
|
||||
CoreDomUtils.showErrorModal(new CoreError(Translate.instant('core.course.changesofflinemaybelost'), {
|
||||
title: Translate.instant('core.youreoffline'),
|
||||
}));
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -114,7 +119,6 @@ export default class AddonModScormOnlinePlayerPage implements OnInit, OnDestroy
|
|||
} finally {
|
||||
this.loaded = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -275,4 +279,21 @@ export default class AddonModScormOnlinePlayerPage implements OnInit, OnDestroy
|
|||
CoreEvents.trigger(CoreEvents.ACTIVITY_DATA_SENT, { module: 'scorm' });
|
||||
}
|
||||
|
||||
/**
|
||||
* SCORM iframe has been loaded.
|
||||
*/
|
||||
async iframeLoaded(): Promise<void> {
|
||||
// When using online player, some packages don't calculate the right height. Sending a 'resize' event doesn't fix it, but
|
||||
// changing the iframe size makes the SCORM recalculate the size.
|
||||
// Wait 1 second (to let inner iframes load) and then force full screen to make the SCORM recalculate the size.
|
||||
await CoreWait.wait(1000);
|
||||
|
||||
if (this.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.iframe?.toggleFullscreen(true);
|
||||
this.enableFullScreenOnRotate = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -159,13 +159,27 @@ Feature: Test basic usage of SCORM activity in app
|
|||
# And I go back in the app
|
||||
# Then I should find "1" within "Number of attempts you have made" "ion-item" in the app
|
||||
|
||||
Scenario: Unsupported SCORM
|
||||
Scenario: SCORM 2004 works online
|
||||
Given the following "activities" exist:
|
||||
| activity | name | course | idnumber | packagefilepath |
|
||||
| scorm | SCORM 1.2 | C1 | scorm | mod/scorm/tests/packages/RuntimeBasicCalls_SCORM20043rdEdition.zip |
|
||||
| scorm | SCORM 2004 | C1 | scorm | mod/scorm/tests/packages/RuntimeBasicCalls_SCORM20043rdEdition.zip |
|
||||
And I entered the course "Course 1" as "student1" in the app
|
||||
When I press "SCORM 1.2" in the app
|
||||
Then I should find "Sorry, the application only supports SCORM 1.2." in the app
|
||||
When I press "SCORM 2004" in the app
|
||||
Then I should be able to press "Enter" in the app
|
||||
|
||||
When I switch network connection to offline
|
||||
Then I should find "This activity is not available offline" in the app
|
||||
And I should not be able to press "Enter" in the app
|
||||
|
||||
When I switch network connection to wifi
|
||||
And I press "Enter" in the app
|
||||
And I press "Disable fullscreen" in the app
|
||||
Then I should not be able to press "TOC" in the app
|
||||
|
||||
When I switch network connection to offline
|
||||
Then I should find "Any changes you make to this activity while offline may not be saved" in the app
|
||||
|
||||
# TODO: When iframes are fixed, test that the iframe actually works. However, the Golf 2004 SCORM has some issues.
|
||||
|
||||
Scenario: Hidden SCOs not displayed in TOC
|
||||
Given the following "activities" exist:
|
||||
|
|
|
@ -64,6 +64,7 @@ export class CoreIframeComponent implements OnChanges, OnDestroy {
|
|||
|
||||
initialized = false;
|
||||
|
||||
protected fullScreenInitialized = false;
|
||||
protected iframe?: HTMLIFrameElement;
|
||||
protected style?: HTMLStyleElement;
|
||||
protected orientationObs?: CoreEventObserver;
|
||||
|
@ -87,36 +88,6 @@ export class CoreIframeComponent implements OnChanges, OnDestroy {
|
|||
|
||||
this.initialized = true;
|
||||
|
||||
if (this.showFullscreenOnToolbar || this.autoFullscreenOnRotate) {
|
||||
// Leave fullscreen when navigating.
|
||||
this.navSubscription = Router.events
|
||||
.pipe(filter(event => event instanceof NavigationStart))
|
||||
.subscribe(async () => {
|
||||
if (this.fullscreen) {
|
||||
this.toggleFullscreen(false);
|
||||
}
|
||||
});
|
||||
|
||||
const shadow =
|
||||
this.elementRef.nativeElement.closest('.ion-page')?.querySelector('ion-header ion-toolbar')?.shadowRoot;
|
||||
if (shadow) {
|
||||
this.style = document.createElement('style');
|
||||
shadow.appendChild(this.style);
|
||||
}
|
||||
|
||||
if (this.autoFullscreenOnRotate) {
|
||||
this.toggleFullscreen(CoreScreen.isLandscape);
|
||||
|
||||
this.orientationObs = CoreEvents.on(CoreEvents.ORIENTATION_CHANGE, (data) => {
|
||||
if (this.isInHiddenPage()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.toggleFullscreen(data.orientation == CoreScreenOrientation.LANDSCAPE);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Show loading only with external URLs.
|
||||
this.loading = !this.src || !CoreUrl.isLocalFileUrl(this.src);
|
||||
|
||||
|
@ -127,6 +98,72 @@ export class CoreIframeComponent implements OnChanges, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure fullscreen based on the inputs.
|
||||
*/
|
||||
protected configureFullScreen(): void {
|
||||
if (!this.showFullscreenOnToolbar && !this.autoFullscreenOnRotate) {
|
||||
// Full screen disabled, stop watchers if enabled.
|
||||
this.navSubscription?.unsubscribe();
|
||||
this.orientationObs?.off();
|
||||
this.style?.remove();
|
||||
this.navSubscription = undefined;
|
||||
this.orientationObs = undefined;
|
||||
this.style = undefined;
|
||||
this.fullScreenInitialized = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.navSubscription) {
|
||||
// Leave fullscreen when navigating.
|
||||
this.navSubscription = Router.events
|
||||
.pipe(filter(event => event instanceof NavigationStart))
|
||||
.subscribe(async () => {
|
||||
if (this.fullscreen) {
|
||||
this.toggleFullscreen(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!this.style) {
|
||||
const shadow = this.elementRef.nativeElement.closest('.ion-page')?.querySelector('ion-header ion-toolbar')?.shadowRoot;
|
||||
if (shadow) {
|
||||
this.style = document.createElement('style');
|
||||
shadow.appendChild(this.style);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.autoFullscreenOnRotate) {
|
||||
this.orientationObs?.off();
|
||||
this.orientationObs = undefined;
|
||||
this.fullScreenInitialized = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.orientationObs) {
|
||||
this.fullScreenInitialized = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.fullScreenInitialized) {
|
||||
// Only change full screen value if it's being initialized.
|
||||
this.toggleFullscreen(CoreScreen.isLandscape);
|
||||
}
|
||||
|
||||
this.orientationObs = CoreEvents.on(CoreEvents.ORIENTATION_CHANGE, (data) => {
|
||||
if (this.isInHiddenPage()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.toggleFullscreen(data.orientation == CoreScreenOrientation.LANDSCAPE);
|
||||
});
|
||||
|
||||
this.fullScreenInitialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize things related to the iframe element.
|
||||
*/
|
||||
|
@ -170,6 +207,10 @@ export class CoreIframeComponent implements OnChanges, OnDestroy {
|
|||
}
|
||||
|
||||
if (!changes.src) {
|
||||
if (changes.showFullscreenOnToolbar || changes.autoFullscreenOnRotate) {
|
||||
this.configureFullScreen();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -212,6 +253,9 @@ export class CoreIframeComponent implements OnChanges, OnDestroy {
|
|||
// Now that the URL has been set, initialize the iframe. Wait for the iframe to the added to the DOM.
|
||||
setTimeout(() => {
|
||||
this.init();
|
||||
if (changes.showFullscreenOnToolbar || changes.autoFullscreenOnRotate) {
|
||||
this.configureFullScreen();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -229,6 +273,12 @@ export class CoreIframeComponent implements OnChanges, OnDestroy {
|
|||
this.orientationObs?.off();
|
||||
this.navSubscription?.unsubscribe();
|
||||
window.removeEventListener('message', this.messageListenerFunction);
|
||||
|
||||
if (this.fullscreen) {
|
||||
// Make sure to leave fullscreen mode when the iframe is destroyed. This can happen if there's a race condition
|
||||
// between clicking back button and some code toggling the fullscreen on.
|
||||
this.toggleFullscreen(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue