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 @@
// eslint-disable-next-line no-unused-vars
var cca = {
mojo: {},
nav: {},
perf: {},
proxy: {},
state: {},
......
......@@ -2,173 +2,145 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
'use strict';
/**
* Namespace for the Camera app.
*/
var cca = cca || {};
/**
* Namespace for navigation of views.
*/
cca.nav = cca.nav || {};
cca.App = cca.App || {};
import {assertInstanceof} from './chrome_util.js';
import {browserProxy} from './browser_proxy/browser_proxy.js';
import {DeviceOperator} from './mojo/device_operator.js';
import * as state from './state.js';
import * as toast from './toast.js';
import * as util from './util.js';
import {View} from './views/view.js'; // eslint-disable-line no-unused-vars
/**
* All views stacked in ascending z-order (DOM order) for navigation, and only
* 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.
* @type {number}
*/
cca.nav.topmostIndex_ = -1;
let topmostIndex = -1;
/**
* 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) {
cca.nav.views_ = views;
// Manage all tabindex usages in cca.nav for navigation.
export function setup(views) {
allViews = views;
// Manage all tabindex usages in for navigation.
document.querySelectorAll('[tabindex]')
.forEach(
(element) => cca.util.makeUnfocusableByMouse(
/** @type {!HTMLElement} */ (element)));
(element) => util.makeUnfocusableByMouse(
assertInstanceof(element, HTMLElement)));
document.body.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
cca.state.set('tab-navigation', true);
state.set('tab-navigation', true);
}
});
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.
* @param {string} id View identifier.
* @return {number} Index of the view found; otherwise, -1.
* @private
* Activates the view to be focusable.
* @param {number} index Index of the view.
*/
cca.nav.findIndex_ = function(id) {
return cca.nav.views_.findIndex((view) => view.root.id === id);
};
function activate(index) {
// 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.
* @return {number} Index of the view found; otherwise, -1.
* @private
* Inactivates the view to be unfocusable.
* @param {number} index Index of the view.
*/
cca.nav.findNextTopmostIndex_ = function() {
for (var i = cca.nav.topmostIndex_ - 1; i >= 0; i--) {
if (cca.nav.isShown_(i)) {
return i;
}
}
return -1;
};
function inactivate(index) {
const view = allViews[index];
view.root.setAttribute('aria-hidden', 'true');
view.root.querySelectorAll('[tabindex]').forEach((element) => {
element.dataset.tabindex = element.getAttribute('tabindex');
element.setAttribute('tabindex', '-1');
});
document.activeElement.blur();
}
/**
* Checks if the view is already shown.
* @param {number} index Index of the view.
* @return {boolean} Whether the view is shown or not.
* @private
*/
cca.nav.isShown_ = function(index) {
return cca.state.get(cca.nav.views_[index].root.id);
};
function isShown(index) {
return state.get(allViews[index].root.id);
}
/**
* Shows the view indexed in the stacked views and activates the view only if
* it becomes the topmost visible view.
* @param {number} index Index of the view.
* @return {cca.views.View} View shown.
* @private
* @return {View} View shown.
*/
cca.nav.show_ = function(index) {
var view = cca.nav.views_[index];
if (!cca.nav.isShown_(index)) {
cca.state.set(view.root.id, true);
function show(index) {
const view = allViews[index];
if (!isShown(index)) {
state.set(view.root.id, true);
view.layout();
if (index > cca.nav.topmostIndex_) {
if (cca.nav.topmostIndex_ >= 0) {
cca.nav.inactivate_(cca.nav.topmostIndex_);
if (index > topmostIndex) {
if (topmostIndex >= 0) {
inactivate(topmostIndex);
}
cca.nav.activate_(index);
cca.nav.topmostIndex_ = index;
activate(index);
topmostIndex = index;
}
}
return view;
};
}
/**
* 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.
* @private
* Finds the next topmost visible view in the stacked views.
* @return {number} Index of the view found; otherwise, -1.
*/
cca.nav.hide_ = function(index) {
if (index === cca.nav.topmostIndex_) {
cca.nav.inactivate_(index);
var next = cca.nav.findNextTopmostIndex_();
if (next >= 0) {
cca.nav.activate_(next);
function findNextTopmostIndex() {
for (let i = topmostIndex - 1; i >= 0; i--) {
if (isShown(i)) {
return i;
}
cca.nav.topmostIndex_ = next;
}
cca.state.set(cca.nav.views_[index].root.id, false);
};
/**
* 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();
};
return -1;
}
/**
* 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.
*/
cca.nav.inactivate_ = function(index) {
var view = cca.nav.views_[index];
view.root.setAttribute('aria-hidden', 'true');
view.root.querySelectorAll('[tabindex]').forEach((element) => {
element.dataset.tabindex = element.getAttribute('tabindex');
element.setAttribute('tabindex', '-1');
});
document.activeElement.blur();
};
function hide(index) {
if (index === topmostIndex) {
inactivate(index);
const next = findNextTopmostIndex();
if (next >= 0) {
activate(next);
}
topmostIndex = next;
}
state.set(allViews[index].root.id, false);
}
/**
* Sets the element's tabindex on the view.
* @param {cca.views.View} view View that the element is on.
* @param {HTMLElement} element Element whose tabindex to be set.
* @param {number} tabIndex Tab-index of the element.
* Finds the view by its id in the stacked views.
* @param {string} id View identifier.
* @return {number} Index of the view found; otherwise, -1.
*/
cca.nav.setTabIndex = function(view, element, tabIndex) {
if ((cca.nav.topmostIndex_ >= 0) &&
(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 + '';
}
};
function findIndex(id) {
return allViews.findIndex((view) => view.root.id === id);
}
/**
* 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) {
* @param {...*} args Optional rest parameters for entering the view.
* @return {!Promise<*>} Promise for the operation or result.
*/
cca.nav.open = function(id, ...args) {
var index = cca.nav.findIndex_(id);
return cca.nav.show_(index).enter(...args).finally(() => {
cca.nav.hide_(index);
export function open(id, ...args) {
const index = findIndex(id);
return show(index).enter(...args).finally(() => {
hide(index);
});
};
}
/**
* Closes the current navigation session of the view by leaving it.
......@@ -190,18 +162,18 @@ cca.nav.open = function(id, ...args) {
* @param {*=} condition Optional condition for leaving the view.
* @return {boolean} Whether successfully leaving the view or not.
*/
cca.nav.close = function(id, condition) {
var index = cca.nav.findIndex_(id);
return cca.nav.views_[index].leave(condition);
};
export function close(id, condition) {
const index = findIndex(id);
return allViews[index].leave(condition);
}
/**
* Handles key pressed event.
* @param {Event} event Key press event.
*/
cca.nav.onKeyPressed = function(event) {
var key = cca.util.getShortcutIdentifier(event);
var openInspector = (type) => chrome.fileManagerPrivate &&
export function onKeyPressed(event) {
const key = util.getShortcutIdentifier(event);
const openInspector = (type) => chrome.fileManagerPrivate &&
chrome.fileManagerPrivate.openInspector(type);
switch (key) {
case 'BrowserBack':
......@@ -218,32 +190,42 @@ cca.nav.onKeyPressed = function(event) {
break;
case 'Ctrl-Shift-E':
(async () => {
if (!await cca.mojo.DeviceOperator.isSupported()) {
cca.toast.show('error_msg_expert_mode_not_supported');
if (!await DeviceOperator.isSupported()) {
toast.show('error_msg_expert_mode_not_supported');
return;
}
const newState = !cca.state.get('expert');
cca.state.set('expert', newState);
cca.proxy.browserProxy.localStorageSet({expert: newState});
const newState = !state.get('expert');
state.set('expert', newState);
browserProxy.localStorageSet({expert: newState});
})();
break;
default:
// Make the topmost visible view handle the pressed key.
if (cca.nav.topmostIndex_ >= 0 &&
cca.nav.views_[cca.nav.topmostIndex_].onKeyPressed(key)) {
if (topmostIndex >= 0 && allViews[topmostIndex].onKeyPressed(key)) {
event.preventDefault();
}
}
};
}
/**
* 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.
for (var i = cca.nav.views_.length - 1; i >= 0; i--) {
if (cca.nav.isShown_(i)) {
cca.nav.views_[i].layout();
for (let i = allViews.length - 1; i >= 0; i--) {
if (isShown(i)) {
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 @@
<script defer src="../js/views/dialog.js"></script>
<script defer src="../js/views/settings.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>
</head>
<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