1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 * @fileoverview Provides dialog-like behaviors for the tracing UI.
8 cr.define('cr.ui.overlay', function() {
10 * Gets the top, visible overlay. It makes the assumption that if multiple
11 * overlays are visible, the last in the byte order is topmost.
12 * TODO(estade): rely on aria-visibility instead?
13 * @return {HTMLElement} The overlay.
15 function getTopOverlay() {
16 var overlays = document.querySelectorAll('.overlay:not([hidden])');
17 return overlays[overlays.length - 1];
21 * Returns a visible default button of the overlay, if it has one. If the
22 * overlay has more than one, the first one will be returned.
24 * @param {HTMLElement} overlay The .overlay.
25 * @return {HTMLElement} The default button.
27 function getDefaultButton(overlay) {
28 function isHidden(node) { return node.hidden; }
30 overlay.querySelectorAll('.page .button-strip > .default-button');
31 for (var i = 0; i < defaultButtons.length; i++) {
32 if (!findAncestor(defaultButtons[i], isHidden))
33 return defaultButtons[i];
38 /** @type {boolean} */
39 var globallyInitialized = false;
42 * Makes initializations which must hook at the document level.
44 function globalInitialization() {
45 if (!globallyInitialized) {
46 document.addEventListener('keydown', function(e) {
47 var overlay = getTopOverlay();
51 // Close the overlay on escape.
52 if (e.keyIdentifier == 'U+001B')
53 cr.dispatchSimpleEvent(overlay, 'cancelOverlay');
55 // Execute the overlay's default button on enter, unless focus is on an
56 // element that has standard behavior for the enter key.
57 var forbiddenTagNames = /^(A|BUTTON|SELECT|TEXTAREA)$/;
58 if (e.keyIdentifier == 'Enter' &&
59 !forbiddenTagNames.test(document.activeElement.tagName)) {
60 var button = getDefaultButton(overlay);
63 // Executing the default button may result in focus moving to a
64 // different button. Calling preventDefault is necessary to not have
65 // that button execute as well.
71 window.addEventListener('resize', setMaxHeightAllPages);
72 globallyInitialized = true;
75 setMaxHeightAllPages();
79 * Sets the max-height of all pages in all overlays, based on the window
82 function setMaxHeightAllPages() {
83 var pages = document.querySelectorAll(
84 '.overlay .page:not(.not-resizable)');
86 var maxHeight = Math.min(0.9 * window.innerHeight, 640) + 'px';
87 for (var i = 0; i < pages.length; i++)
88 pages[i].style.maxHeight = maxHeight;
92 * Adds behavioral hooks for the given overlay.
93 * @param {HTMLElement} overlay The .overlay.
95 function setupOverlay(overlay) {
96 // Close the overlay on clicking any of the pages' close buttons.
97 var closeButtons = overlay.querySelectorAll('.page > .close-button');
98 for (var i = 0; i < closeButtons.length; i++) {
99 closeButtons[i].addEventListener('click', function(e) {
100 cr.dispatchSimpleEvent(overlay, 'cancelOverlay');
104 // Remove the 'pulse' animation any time the overlay is hidden or shown.
105 overlay.__defineSetter__('hidden', function(value) {
106 this.classList.remove('pulse');
108 this.setAttribute('hidden', true);
110 this.removeAttribute('hidden');
112 overlay.__defineGetter__('hidden', function() {
113 return this.hasAttribute('hidden');
116 // Shake when the user clicks away.
117 overlay.addEventListener('click', function(e) {
118 // Only pulse if the overlay was the target of the click.
119 if (this != e.target)
122 // This may be null while the overlay is closing.
123 var overlayPage = this.querySelector('.page:not([hidden])');
125 overlayPage.classList.add('pulse');
127 overlay.addEventListener('webkitAnimationEnd', function(e) {
128 e.target.classList.remove('pulse');
133 globalInitialization: globalInitialization,
134 setupOverlay: setupOverlay,