Commit 05d97565 authored by Kuo Jen Wei's avatar Kuo Jen Wei Committed by Commit Bot

[CCA] Convert nav.js into ES6 module.

Bug: 141518780
Test: Pass closure compiler check, tast run <DUT> 'camera.CCAUI*' and
manually validate tooltips function of CCA works correctly.

Change-Id: I6551d3ca4b9a00ea08a2f7c0965a3e32dad899b1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1981522
Commit-Queue: Kuo Jen Wei <inker@chromium.org>
Reviewed-by: default avatarShik Chen <shik@chromium.org>
Auto-Submit: Kuo Jen Wei <inker@chromium.org>
Cr-Commit-Position: refs/heads/master@{#727439}
parent 588bd9a6
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
var cca = { var cca = {
mojo: {}, mojo: {},
nav: {},
perf: {}, perf: {},
proxy: {}, proxy: {},
state: {}, state: {},
......
...@@ -2,173 +2,145 @@ ...@@ -2,173 +2,145 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
'use strict'; import {assertInstanceof} from './chrome_util.js';
import {browserProxy} from './browser_proxy/browser_proxy.js';
/** import {DeviceOperator} from './mojo/device_operator.js';
* Namespace for the Camera app. import * as state from './state.js';
*/ import * as toast from './toast.js';
var cca = cca || {}; import * as util from './util.js';
import {View} from './views/view.js'; // eslint-disable-line no-unused-vars
/**
* Namespace for navigation of views.
*/
cca.nav = cca.nav || {};
cca.App = cca.App || {};
/** /**
* All views stacked in ascending z-order (DOM order) for navigation, and only * All views stacked in ascending z-order (DOM order) for navigation, and only
* the topmost visible view is active (clickable/focusable). * the topmost visible view is active (clickable/focusable).
* @type {Array<cca.views.View>} * @type {!Array<!View>}
*/ */
cca.nav.views_ = []; let allViews = [];
/** /**
* Index of the current topmost visible view in the stacked views. * Index of the current topmost visible view in the stacked views.
* @type {number} * @type {number}
*/ */
cca.nav.topmostIndex_ = -1; let topmostIndex = -1;
/** /**
* Sets up navigation for all views, e.g. camera-view, dialog-view, etc. * Sets up navigation for all views, e.g. camera-view, dialog-view, etc.
* @param {Array<cca.views.View>} views All views in ascending z-order. * @param {!Array<!View>} views All views in ascending z-order.
*/ */
cca.nav.setup = function(views) { export function setup(views) {
cca.nav.views_ = views; allViews = views;
// Manage all tabindex usages in cca.nav for navigation. // Manage all tabindex usages in for navigation.
document.querySelectorAll('[tabindex]') document.querySelectorAll('[tabindex]')
.forEach( .forEach(
(element) => cca.util.makeUnfocusableByMouse( (element) => util.makeUnfocusableByMouse(
/** @type {!HTMLElement} */ (element))); assertInstanceof(element, HTMLElement)));
document.body.addEventListener('keydown', (e) => { document.body.addEventListener('keydown', (e) => {
if (e.key === 'Tab') { if (e.key === 'Tab') {
cca.state.set('tab-navigation', true); state.set('tab-navigation', true);
} }
}); });
document.body.addEventListener( document.body.addEventListener(
'pointerdown', () => cca.state.set('tab-navigation', false)); 'pointerdown', () => state.set('tab-navigation', false));
}; }
/** /**
* Finds the view by its id in the stacked views. * Activates the view to be focusable.
* @param {string} id View identifier. * @param {number} index Index of the view.
* @return {number} Index of the view found; otherwise, -1.
* @private
*/ */
cca.nav.findIndex_ = function(id) { function activate(index) {
return cca.nav.views_.findIndex((view) => view.root.id === id); // Restore the view's child elements' tabindex and then focus the view.
}; const view = allViews[index];
view.root.setAttribute('aria-hidden', 'false');
view.root.querySelectorAll('[data-tabindex]').forEach((element) => {
element.setAttribute('tabindex', element.dataset.tabindex);
element.removeAttribute('data-tabindex');
});
view.focus();
}
/** /**
* Finds the next topmost visible view in the stacked views. * Inactivates the view to be unfocusable.
* @return {number} Index of the view found; otherwise, -1. * @param {number} index Index of the view.
* @private
*/ */
cca.nav.findNextTopmostIndex_ = function() { function inactivate(index) {
for (var i = cca.nav.topmostIndex_ - 1; i >= 0; i--) { const view = allViews[index];
if (cca.nav.isShown_(i)) { view.root.setAttribute('aria-hidden', 'true');
return i; view.root.querySelectorAll('[tabindex]').forEach((element) => {
} element.dataset.tabindex = element.getAttribute('tabindex');
} element.setAttribute('tabindex', '-1');
return -1; });
}; document.activeElement.blur();
}
/** /**
* Checks if the view is already shown. * Checks if the view is already shown.
* @param {number} index Index of the view. * @param {number} index Index of the view.
* @return {boolean} Whether the view is shown or not. * @return {boolean} Whether the view is shown or not.
* @private
*/ */
cca.nav.isShown_ = function(index) { function isShown(index) {
return cca.state.get(cca.nav.views_[index].root.id); return state.get(allViews[index].root.id);
}; }
/** /**
* Shows the view indexed in the stacked views and activates the view only if * Shows the view indexed in the stacked views and activates the view only if
* it becomes the topmost visible view. * it becomes the topmost visible view.
* @param {number} index Index of the view. * @param {number} index Index of the view.
* @return {cca.views.View} View shown. * @return {View} View shown.
* @private
*/ */
cca.nav.show_ = function(index) { function show(index) {
var view = cca.nav.views_[index]; const view = allViews[index];
if (!cca.nav.isShown_(index)) { if (!isShown(index)) {
cca.state.set(view.root.id, true); state.set(view.root.id, true);
view.layout(); view.layout();
if (index > cca.nav.topmostIndex_) { if (index > topmostIndex) {
if (cca.nav.topmostIndex_ >= 0) { if (topmostIndex >= 0) {
cca.nav.inactivate_(cca.nav.topmostIndex_); inactivate(topmostIndex);
} }
cca.nav.activate_(index); activate(index);
cca.nav.topmostIndex_ = index; topmostIndex = index;
} }
} }
return view; return view;
}; }
/** /**
* Hides the view indexed in the stacked views and inactivate the view if it was * Finds the next topmost visible view in the stacked views.
* the topmost visible view. * @return {number} Index of the view found; otherwise, -1.
* @param {number} index Index of the view.
* @private
*/ */
cca.nav.hide_ = function(index) { function findNextTopmostIndex() {
if (index === cca.nav.topmostIndex_) { for (let i = topmostIndex - 1; i >= 0; i--) {
cca.nav.inactivate_(index); if (isShown(i)) {
var next = cca.nav.findNextTopmostIndex_(); return i;
if (next >= 0) {
cca.nav.activate_(next);
} }
cca.nav.topmostIndex_ = next;
} }
cca.state.set(cca.nav.views_[index].root.id, false); return -1;
}; }
/**
* Activates the view to be focusable.
* @param {number} index Index of the view.
*/
cca.nav.activate_ = function(index) {
// Restore the view's child elements' tabindex and then focus the view.
var view = cca.nav.views_[index];
view.root.setAttribute('aria-hidden', 'false');
view.root.querySelectorAll('[data-tabindex]').forEach((element) => {
element.setAttribute('tabindex', element.dataset.tabindex);
element.removeAttribute('data-tabindex');
});
view.focus();
};
/** /**
* Inactivates the view to be unfocusable. * Hides the view indexed in the stacked views and inactivate the view if it was
* the topmost visible view.
* @param {number} index Index of the view. * @param {number} index Index of the view.
*/ */
cca.nav.inactivate_ = function(index) { function hide(index) {
var view = cca.nav.views_[index]; if (index === topmostIndex) {
view.root.setAttribute('aria-hidden', 'true'); inactivate(index);
view.root.querySelectorAll('[tabindex]').forEach((element) => { const next = findNextTopmostIndex();
element.dataset.tabindex = element.getAttribute('tabindex'); if (next >= 0) {
element.setAttribute('tabindex', '-1'); activate(next);
}); }
document.activeElement.blur(); topmostIndex = next;
}; }
state.set(allViews[index].root.id, false);
}
/** /**
* Sets the element's tabindex on the view. * Finds the view by its id in the stacked views.
* @param {cca.views.View} view View that the element is on. * @param {string} id View identifier.
* @param {HTMLElement} element Element whose tabindex to be set. * @return {number} Index of the view found; otherwise, -1.
* @param {number} tabIndex Tab-index of the element.
*/ */
cca.nav.setTabIndex = function(view, element, tabIndex) { function findIndex(id) {
if ((cca.nav.topmostIndex_ >= 0) && return allViews.findIndex((view) => view.root.id === id);
(cca.nav.views_[cca.nav.topmostIndex_] === view)) { }
element.tabIndex = tabIndex;
} else {
// Remember tabindex by data attribute if the view isn't active.
element.tabIndex = -1;
element.dataset.tabindex = tabIndex + '';
}
};
/** /**
* Opens a navigation session of the view; shows the view before entering it and * Opens a navigation session of the view; shows the view before entering it and
...@@ -177,12 +149,12 @@ cca.nav.setTabIndex = function(view, element, tabIndex) { ...@@ -177,12 +149,12 @@ cca.nav.setTabIndex = function(view, element, tabIndex) {
* @param {...*} args Optional rest parameters for entering the view. * @param {...*} args Optional rest parameters for entering the view.
* @return {!Promise<*>} Promise for the operation or result. * @return {!Promise<*>} Promise for the operation or result.
*/ */
cca.nav.open = function(id, ...args) { export function open(id, ...args) {
var index = cca.nav.findIndex_(id); const index = findIndex(id);
return cca.nav.show_(index).enter(...args).finally(() => { return show(index).enter(...args).finally(() => {
cca.nav.hide_(index); hide(index);
}); });
}; }
/** /**
* Closes the current navigation session of the view by leaving it. * Closes the current navigation session of the view by leaving it.
...@@ -190,18 +162,18 @@ cca.nav.open = function(id, ...args) { ...@@ -190,18 +162,18 @@ cca.nav.open = function(id, ...args) {
* @param {*=} condition Optional condition for leaving the view. * @param {*=} condition Optional condition for leaving the view.
* @return {boolean} Whether successfully leaving the view or not. * @return {boolean} Whether successfully leaving the view or not.
*/ */
cca.nav.close = function(id, condition) { export function close(id, condition) {
var index = cca.nav.findIndex_(id); const index = findIndex(id);
return cca.nav.views_[index].leave(condition); return allViews[index].leave(condition);
}; }
/** /**
* Handles key pressed event. * Handles key pressed event.
* @param {Event} event Key press event. * @param {Event} event Key press event.
*/ */
cca.nav.onKeyPressed = function(event) { export function onKeyPressed(event) {
var key = cca.util.getShortcutIdentifier(event); const key = util.getShortcutIdentifier(event);
var openInspector = (type) => chrome.fileManagerPrivate && const openInspector = (type) => chrome.fileManagerPrivate &&
chrome.fileManagerPrivate.openInspector(type); chrome.fileManagerPrivate.openInspector(type);
switch (key) { switch (key) {
case 'BrowserBack': case 'BrowserBack':
...@@ -218,32 +190,42 @@ cca.nav.onKeyPressed = function(event) { ...@@ -218,32 +190,42 @@ cca.nav.onKeyPressed = function(event) {
break; break;
case 'Ctrl-Shift-E': case 'Ctrl-Shift-E':
(async () => { (async () => {
if (!await cca.mojo.DeviceOperator.isSupported()) { if (!await DeviceOperator.isSupported()) {
cca.toast.show('error_msg_expert_mode_not_supported'); toast.show('error_msg_expert_mode_not_supported');
return; return;
} }
const newState = !cca.state.get('expert'); const newState = !state.get('expert');
cca.state.set('expert', newState); state.set('expert', newState);
cca.proxy.browserProxy.localStorageSet({expert: newState}); browserProxy.localStorageSet({expert: newState});
})(); })();
break; break;
default: default:
// Make the topmost visible view handle the pressed key. // Make the topmost visible view handle the pressed key.
if (cca.nav.topmostIndex_ >= 0 && if (topmostIndex >= 0 && allViews[topmostIndex].onKeyPressed(key)) {
cca.nav.views_[cca.nav.topmostIndex_].onKeyPressed(key)) {
event.preventDefault(); event.preventDefault();
} }
} }
}; }
/** /**
* Handles resized window on current all visible views. * Handles resized window on current all visible views.
*/ */
cca.nav.onWindowResized = function() { export function onWindowResized() {
// All visible views need being relayout after window is resized. // All visible views need being relayout after window is resized.
for (var i = cca.nav.views_.length - 1; i >= 0; i--) { for (let i = allViews.length - 1; i >= 0; i--) {
if (cca.nav.isShown_(i)) { if (isShown(i)) {
cca.nav.views_[i].layout(); allViews[i].layout();
} }
} }
}; }
/** @const */
cca.nav.setup = setup;
/** @const */
cca.nav.open = open;
/** @const */
cca.nav.close = close;
/** @const */
cca.nav.onKeyPressed = onKeyPressed;
/** @const */
cca.nav.onWindowResized = onWindowResized;
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
<script defer src="../js/views/dialog.js"></script> <script defer src="../js/views/dialog.js"></script>
<script defer src="../js/views/settings.js"></script> <script defer src="../js/views/settings.js"></script>
<script defer src="../js/views/warning.js"></script> <script defer src="../js/views/warning.js"></script>
<script defer src="../js/nav.js"></script> <script type="module" src="../js/nav.js"></script>
<script defer src="../js/main.js"></script> <script defer src="../js/main.js"></script>
</head> </head>
<body class="sound mirror mic _3x3"> <body class="sound mirror mic _3x3">
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment