Better detection of device orientation based on browser feature availability (#5172)

* Update Agent.isPortrait() utility method (#4875)
* Properly feature detect for orientation APIs (#4875)
* Use Agent to detect device orientation (#4875)
* Tests for display orientation detection (#4875)

Co-authored-by: Andrew Henry <akhenry@gmail.com>
This commit is contained in:
Jesse Mazzella 2022-05-20 12:31:59 -07:00 committed by GitHub
parent 48916564e4
commit 037886aa01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 51 additions and 11 deletions

View File

@ -52,7 +52,6 @@ export default (agent, document) => {
if (agent.isMobile()) { if (agent.isMobile()) {
const mediaQuery = window.matchMedia("(orientation: landscape)"); const mediaQuery = window.matchMedia("(orientation: landscape)");
function eventHandler(event) { function eventHandler(event) {
console.log("changed");
if (event.matches) { if (event.matches) {
body.classList.remove("portrait"); body.classList.remove("portrait");
body.classList.add("landscape"); body.classList.add("landscape");

View File

@ -177,7 +177,7 @@ export default {
SearchResults, SearchResults,
Sidebar Sidebar
}, },
inject: ['openmct', 'snapshotContainer'], inject: ['agent', 'openmct', 'snapshotContainer'],
props: { props: {
domainObject: { domainObject: {
type: Object, type: Object,
@ -455,12 +455,9 @@ export default {
- tablet portrait - tablet portrait
- in a layout frame (within .c-so-view) - in a layout frame (within .c-so-view)
*/ */
const classList = document.querySelector('body').classList; const isPhone = this.agent.isPhone();
const isPhone = Array.from(classList).includes('phone'); const isTablet = this.agent.isTablet();
const isTablet = Array.from(classList).includes('tablet'); const isPortrait = this.agent.isPortrait();
// address in https://github.com/nasa/openmct/issues/4875
// eslint-disable-next-line compat/compat
const isPortrait = window.screen.orientation.type.includes('portrait');
const isInLayout = Boolean(this.$el.closest('.c-so-view')); const isInLayout = Boolean(this.$el.closest('.c-so-view'));
const sidebarCoversEntries = (isPhone || (isTablet && isPortrait) || isInLayout); const sidebarCoversEntries = (isPhone || (isTablet && isPortrait) || isInLayout);
this.sidebarCoversEntries = sidebarCoversEntries; this.sidebarCoversEntries = sidebarCoversEntries;

View File

@ -8,6 +8,7 @@ import { notebookImageMigration, IMAGE_MIGRATION_VER } from '../notebook/utils/n
import { NOTEBOOK_TYPE } from './notebook-constants'; import { NOTEBOOK_TYPE } from './notebook-constants';
import Vue from 'vue'; import Vue from 'vue';
import Agent from '@/utils/agent/Agent';
export default function NotebookPlugin() { export default function NotebookPlugin() {
return function install(openmct) { return function install(openmct) {
@ -18,7 +19,7 @@ export default function NotebookPlugin() {
} }
openmct.actions.register(new CopyToNotebookAction(openmct)); openmct.actions.register(new CopyToNotebookAction(openmct));
const agent = new Agent(window);
const notebookType = { const notebookType = {
name: 'Notebook', name: 'Notebook',
description: 'Create and save timestamped notes with embedded object snapshots.', description: 'Create and save timestamped notes with embedded object snapshots.',
@ -142,6 +143,7 @@ export default function NotebookPlugin() {
Notebook Notebook
}, },
provide: { provide: {
agent,
openmct, openmct,
snapshotContainer snapshotContainer
}, },

View File

@ -89,7 +89,21 @@ export default class Agent {
* @returns {boolean} true in portrait mode * @returns {boolean} true in portrait mode
*/ */
isPortrait() { isPortrait() {
return this.window.innerWidth < this.window.innerHeight; const { screen } = this.window;
const hasScreenOrientation = screen && Object.prototype.hasOwnProperty.call(screen, 'orientation');
const hasWindowOrientation = Object.prototype.hasOwnProperty.call(this.window, 'orientation');
if (hasScreenOrientation) {
return screen.orientation.type.includes('portrait');
} else if (hasWindowOrientation) {
// Use window.orientation API if available (e.g. Safari mobile)
// which returns [-90, 0, 90, 180] based on device orientation.
const { orientation } = this.window;
return Math.abs(orientation / 90) % 2 === 0;
} else {
return this.window.innerWidth < this.window.innerHeight;
}
} }
/** /**
* Check if the user's device is in a landscape-style * Check if the user's device is in a landscape-style

View File

@ -68,7 +68,7 @@ describe("The Agent", function () {
expect(agent.isTablet()).toBeTruthy(); expect(agent.isTablet()).toBeTruthy();
}); });
it("detects display orientation", function () { it("detects display orientation by innerHeight and innerWidth", function () {
agent = new Agent(testWindow); agent = new Agent(testWindow);
testWindow.innerWidth = 1024; testWindow.innerWidth = 1024;
testWindow.innerHeight = 400; testWindow.innerHeight = 400;
@ -80,6 +80,34 @@ describe("The Agent", function () {
expect(agent.isLandscape()).toBeFalsy(); expect(agent.isLandscape()).toBeFalsy();
}); });
it("detects display orientation by screen.orientation", function () {
agent = new Agent(testWindow);
testWindow.screen = {
orientation: {
type: "landscape-primary"
}
};
expect(agent.isPortrait()).toBeFalsy();
expect(agent.isLandscape()).toBeTruthy();
testWindow.screen = {
orientation: {
type: "portrait-primary"
}
};
expect(agent.isPortrait()).toBeTruthy();
expect(agent.isLandscape()).toBeFalsy();
});
it("detects display orientation by window.orientation", function () {
agent = new Agent(testWindow);
testWindow.orientation = 90;
expect(agent.isPortrait()).toBeFalsy();
expect(agent.isLandscape()).toBeTruthy();
testWindow.orientation = 0;
expect(agent.isPortrait()).toBeTruthy();
expect(agent.isLandscape()).toBeFalsy();
});
it("detects touch support", function () { it("detects touch support", function () {
testWindow.ontouchstart = null; testWindow.ontouchstart = null;
expect(new Agent(testWindow).isTouch()).toBe(true); expect(new Agent(testWindow).isTouch()).toBe(true);