MOBILE-3103 iframe: Manage orientation on iframes fullscreen
parent
d8cc67eab1
commit
a4f780b7b8
|
@ -77,7 +77,6 @@
|
|||
"cordova-plugin-media-capture": "^3.0.3",
|
||||
"cordova-plugin-network-information": "^2.0.2",
|
||||
"cordova-plugin-prevent-override": "^1.0.0",
|
||||
"cordova-plugin-screen-orientation": "^3.0.2",
|
||||
"cordova-plugin-splashscreen": "^6.0.0",
|
||||
"cordova-plugin-statusbar": "^2.4.3",
|
||||
"cordova-plugin-whitelist": "^1.3.4",
|
||||
|
@ -11201,18 +11200,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/cordova-plugin-screen-orientation": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/cordova-plugin-screen-orientation/-/cordova-plugin-screen-orientation-3.0.2.tgz",
|
||||
"integrity": "sha512-2w6CMC+HGvbhogJetalwGurL2Fx8DQCCPy3wlSZHN1/W7WoQ5n9ujVozcoKrY4VaagK6bxrPFih+ElkO8Uqfzg==",
|
||||
"engines": {
|
||||
"cordovaDependencies": {
|
||||
"4.0.0": {
|
||||
"cordova": ">100"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/cordova-plugin-splashscreen": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cordova-plugin-splashscreen/-/cordova-plugin-splashscreen-6.0.0.tgz",
|
||||
|
@ -12799,6 +12786,7 @@
|
|||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
|
||||
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"iconv-lite": "^0.6.2"
|
||||
}
|
||||
|
@ -12807,6 +12795,7 @@
|
|||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
|
||||
"integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
|
@ -39888,11 +39877,6 @@
|
|||
"resolved": "https://registry.npmjs.org/cordova-plugin-prevent-override/-/cordova-plugin-prevent-override-1.0.0.tgz",
|
||||
"integrity": "sha512-/+3q5r4K5RahCpiYVmZQBjq10x4jj+6CMjYtZyx9jdMWeV+yFE+ItFcO1NeUAEWd2iHC5YPD0P2tHiHx5kscsw=="
|
||||
},
|
||||
"cordova-plugin-screen-orientation": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/cordova-plugin-screen-orientation/-/cordova-plugin-screen-orientation-3.0.2.tgz",
|
||||
"integrity": "sha512-2w6CMC+HGvbhogJetalwGurL2Fx8DQCCPy3wlSZHN1/W7WoQ5n9ujVozcoKrY4VaagK6bxrPFih+ElkO8Uqfzg=="
|
||||
},
|
||||
"cordova-plugin-splashscreen": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cordova-plugin-splashscreen/-/cordova-plugin-splashscreen-6.0.0.tgz",
|
||||
|
@ -41147,6 +41131,7 @@
|
|||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
|
||||
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
|
||||
"devOptional": true,
|
||||
"requires": {
|
||||
"iconv-lite": "^0.6.2"
|
||||
},
|
||||
|
@ -41155,6 +41140,7 @@
|
|||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
|
||||
"integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==",
|
||||
"devOptional": true,
|
||||
"requires": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
}
|
||||
|
|
|
@ -106,7 +106,6 @@
|
|||
"cordova-plugin-media-capture": "^3.0.3",
|
||||
"cordova-plugin-network-information": "^2.0.2",
|
||||
"cordova-plugin-prevent-override": "^1.0.0",
|
||||
"cordova-plugin-screen-orientation": "^3.0.2",
|
||||
"cordova-plugin-splashscreen": "^6.0.0",
|
||||
"cordova-plugin-statusbar": "^2.4.3",
|
||||
"cordova-plugin-whitelist": "^1.3.4",
|
||||
|
@ -217,7 +216,6 @@
|
|||
},
|
||||
"cordova-plugin-network-information": {},
|
||||
"@moodlehq/cordova-plugin-qrscanner": {},
|
||||
"cordova-plugin-screen-orientation": {},
|
||||
"cordova-plugin-splashscreen": {},
|
||||
"cordova-plugin-statusbar": {},
|
||||
"cordova-plugin-whitelist": {},
|
||||
|
@ -247,4 +245,4 @@
|
|||
"optionalDependencies": {
|
||||
"keytar": "^7.2.0"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@
|
|||
<core-navigation-bar [previous]="previousSco" [next]="nextSco" (action)="loadSco($event)"></core-navigation-bar>
|
||||
|
||||
<core-iframe *ngIf="loaded && src" [src]="src" [iframeWidth]="scormWidth" [iframeHeight]="scormHeight"
|
||||
[showFullscreenOnToolbar]="true">
|
||||
[showFullscreenOnToolbar]="true" [autoFullscreenOnRotate]="true">
|
||||
</core-iframe>
|
||||
|
||||
<p *ngIf="!src && errorMessage">{{ errorMessage | translate }}</p>
|
||||
|
|
|
@ -63,7 +63,6 @@ export class AppComponent implements OnInit, AfterViewInit {
|
|||
* - IAB events listening.
|
||||
* - Platform pause/resume subscriptions.
|
||||
* - handleOpenURL and openWindowSafely.
|
||||
* - Screen orientation events (probably it can be removed).
|
||||
* - Back button registering to close modal first.
|
||||
* - Note: HideKeyboardFormAccessoryBar has been moved to config.xml.
|
||||
*/
|
||||
|
|
|
@ -22,7 +22,9 @@ import { CoreDomUtils } from '@services/utils/dom';
|
|||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreIframeUtils } from '@services/utils/iframe';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { DomSanitizer } from '@singletons';
|
||||
import { DomSanitizer, StatusBar } from '@singletons';
|
||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||
import { CoreScreen, CoreScreenOrientation } from '@services/screen';
|
||||
|
||||
@Component({
|
||||
selector: 'core-iframe',
|
||||
|
@ -39,6 +41,7 @@ export class CoreIframeComponent implements OnChanges, OnDestroy {
|
|||
@Input() iframeHeight?: string;
|
||||
@Input() allowFullscreen?: boolean | string;
|
||||
@Input() showFullscreenOnToolbar?: boolean | string;
|
||||
@Input() autoFullscreenOnRotate?: boolean | string;
|
||||
@Output() loaded: EventEmitter<HTMLIFrameElement> = new EventEmitter<HTMLIFrameElement>();
|
||||
|
||||
loading?: boolean;
|
||||
|
@ -49,6 +52,7 @@ export class CoreIframeComponent implements OnChanges, OnDestroy {
|
|||
initialized = false;
|
||||
|
||||
protected style?: HTMLStyleElement;
|
||||
protected orientationObs?: CoreEventObserver;
|
||||
|
||||
constructor() {
|
||||
this.loaded = new EventEmitter<HTMLIFrameElement>();
|
||||
|
@ -73,14 +77,23 @@ export class CoreIframeComponent implements OnChanges, OnDestroy {
|
|||
this.iframeHeight = (this.iframeHeight && CoreDomUtils.formatPixelsSize(this.iframeHeight)) || '100%';
|
||||
this.allowFullscreen = CoreUtils.isTrueOrOne(this.allowFullscreen);
|
||||
this.showFullscreenOnToolbar = CoreUtils.isTrueOrOne(this.showFullscreenOnToolbar);
|
||||
this.autoFullscreenOnRotate = CoreUtils.isTrueOrOne(this.autoFullscreenOnRotate);
|
||||
|
||||
if (this.showFullscreenOnToolbar) {
|
||||
if (this.showFullscreenOnToolbar || this.autoFullscreenOnRotate) {
|
||||
const shadow =
|
||||
iframe.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) => {
|
||||
this.toggleFullscreen(data.orientation == CoreScreenOrientation.LANDSCAPE);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Show loading only with external URLs.
|
||||
|
@ -136,6 +149,7 @@ export class CoreIframeComponent implements OnChanges, OnDestroy {
|
|||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.toggleFullscreen(false);
|
||||
this.orientationObs?.off();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -148,6 +162,8 @@ export class CoreIframeComponent implements OnChanges, OnDestroy {
|
|||
this.fullscreen = !this.fullscreen;
|
||||
}
|
||||
|
||||
this.fullscreen ? StatusBar.hide() : StatusBar.show();
|
||||
|
||||
if (this.style) {
|
||||
// Done this way because of the shadow DOM.
|
||||
this.style.textContent = this.fullscreen
|
||||
|
|
|
@ -16,4 +16,6 @@ import { CoreScreen } from '@services/screen';
|
|||
|
||||
export default function(): void {
|
||||
CoreScreen.watchViewport();
|
||||
|
||||
CoreScreen.watchOrientation();
|
||||
}
|
|
@ -17,6 +17,7 @@ import { BehaviorSubject, Observable } from 'rxjs';
|
|||
import { distinctUntilChanged, map } from 'rxjs/operators';
|
||||
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { CoreEvents } from '@singletons/events';
|
||||
|
||||
/**
|
||||
* Screen breakpoints.
|
||||
|
@ -48,6 +49,14 @@ export enum CoreScreenLayout {
|
|||
TABLET = 'tablet',
|
||||
}
|
||||
|
||||
/**
|
||||
* Screen orientation.
|
||||
*/
|
||||
export enum CoreScreenOrientation {
|
||||
LANDSCAPE = 'landscape',
|
||||
PORTRAIT = 'portrait',
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage application screen.
|
||||
*/
|
||||
|
@ -93,6 +102,32 @@ export class CoreScreenService {
|
|||
return this.layout === CoreScreenLayout.TABLET;
|
||||
}
|
||||
|
||||
get orientation(): CoreScreenOrientation {
|
||||
const mql = window.matchMedia('(orientation: portrait)');
|
||||
|
||||
return mql.matches ? CoreScreenOrientation.PORTRAIT : CoreScreenOrientation.LANDSCAPE;
|
||||
}
|
||||
|
||||
get isPortrait(): boolean {
|
||||
return this.orientation === CoreScreenOrientation.PORTRAIT;
|
||||
}
|
||||
|
||||
get isLandscape(): boolean {
|
||||
return this.orientation === CoreScreenOrientation.LANDSCAPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Watch orientation changes.
|
||||
*/
|
||||
watchOrientation(): void {
|
||||
// Listen media orientation CSS queries.
|
||||
window.matchMedia('(orientation: portrait)').addEventListener('change', (m) => {
|
||||
const orientation = m.matches ? CoreScreenOrientation.PORTRAIT : CoreScreenOrientation.LANDSCAPE;
|
||||
|
||||
CoreEvents.trigger(CoreEvents.ORIENTATION_CHANGE, { orientation });
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Watch viewport changes.
|
||||
*/
|
||||
|
|
|
@ -19,6 +19,7 @@ import { CoreSite, CoreSiteInfoResponse, CoreSitePublicConfigResponse } from '@c
|
|||
import { CoreFilepoolComponentFileEventData } from '@services/filepool';
|
||||
import { CoreNavigationOptions } from '@services/navigator';
|
||||
import { CoreCourseModuleCompletionData } from '@features/course/services/course-helper';
|
||||
import { CoreScreenOrientation } from '@services/screen';
|
||||
|
||||
/**
|
||||
* Observer instance to stop listening to an event.
|
||||
|
@ -55,6 +56,7 @@ export interface CoreEventsData {
|
|||
[CoreEvents.COMPONENT_FILE_ACTION]: CoreFilepoolComponentFileEventData;
|
||||
[CoreEvents.FILE_SHARED]: CoreEventFileSharedData;
|
||||
[CoreEvents.APP_LAUNCHED_URL]: CoreEventAppLaunchedData;
|
||||
[CoreEvents.ORIENTATION_CHANGE]: CoreEventOrientationData;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -387,3 +389,10 @@ export type CoreEventFileSharedData = {
|
|||
export type CoreEventAppLaunchedData = {
|
||||
url: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Data passed to ORIENTATION_CHANGE event.
|
||||
*/
|
||||
export type CoreEventOrientationData = {
|
||||
orientation: CoreScreenOrientation;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue