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.
8 * @fileoverview Implements an element that is hidden by default, but
9 * when shown, dims and (attempts to) disable the main document.
11 * You can turn any div into an overlay. Note that while an
12 * overlay element is shown, its parent is changed. Hiding the overlay
13 * restores its original parentage.
16 base.requireTemplate('ui.overlay');
18 base.require('base.utils');
19 base.require('base.properties');
20 base.require('base.events');
23 base.exportTo('ui', function() {
25 * Creates a new overlay element. It will not be visible until shown.
27 * @extends {HTMLDivElement}
29 var Overlay = ui.define('overlay');
32 __proto__: HTMLDivElement.prototype,
35 * Initializes the overlay element.
37 decorate: function() {
38 this.classList.add('overlay');
40 this.parentEl_ = this.ownerDocument.body;
42 this.visible_ = false;
43 this.userCanClose_ = true;
45 this.onKeyDown_ = this.onKeyDown_.bind(this);
46 this.onClick_ = this.onClick_.bind(this);
47 this.onFocusIn_ = this.onFocusIn_.bind(this);
48 this.onDocumentClick_ = this.onDocumentClick_.bind(this);
49 this.onClose_ = this.onClose_.bind(this);
51 this.addEventListener('visibleChange',
52 ui.Overlay.prototype.onVisibleChange_.bind(this), true);
54 // Setup the shadow root
55 this.shadow_ = this.webkitCreateShadowRoot();
56 this.shadow_.appendChild(base.instantiateTemplate('#overlay-template'));
58 this.closeBtn_ = this.shadow_.querySelector('close-button');
59 this.closeBtn_.addEventListener('click', this.onClose_);
62 .querySelector('overlay-frame')
63 .addEventListener('click', this.onClick_);
65 this.observer_ = new WebKitMutationObserver(
66 this.didButtonBarMutate_.bind(this));
67 this.observer_.observe(this.shadow_.querySelector('button-bar'),
70 // title is a variable on regular HTMLElements. However, we want to
71 // use it for something more useful.
72 Object.defineProperty(
75 return this.shadow_.querySelector('title').textContent;
77 set: function(title) {
78 this.shadow_.querySelector('title').textContent = title;
83 set userCanClose(userCanClose) {
84 this.userCanClose_ = userCanClose;
85 this.closeBtn_.style.display =
86 userCanClose ? 'block' : 'none';
90 return this.shadow_.querySelector('left-buttons');
94 return this.shadow_.querySelector('right-buttons');
101 set visible(newValue) {
102 if (this.visible_ === newValue)
105 base.setPropertyAndDispatchChange(this, 'visible', newValue);
108 onVisibleChange_: function() {
109 this.visible_ ? this.show_() : this.hide_();
113 this.parentEl_.appendChild(this);
115 if (this.userCanClose_) {
116 document.addEventListener('keydown', this.onKeyDown_);
117 document.addEventListener('click', this.onDocumentClick_);
120 this.parentEl_.addEventListener('focusin', this.onFocusIn_);
123 // Focus the first thing we find that makes sense. (Skip the close button
124 // as it doesn't make sense as the first thing to focus.)
125 var focusEl = undefined;
126 var elList = this.querySelectorAll('button, input, list, select, a');
127 if (elList.length > 0) {
128 if (elList[0] === this.closeBtn_) {
129 if (elList.length > 1)
135 if (focusEl === undefined)
141 this.parentEl_.removeChild(this);
143 this.parentEl_.removeEventListener('focusin', this.onFocusIn_);
146 this.closeBtn_.removeEventListener(this.onClose_);
148 document.removeEventListener('keydown', this.onKeyDown_);
149 document.removeEventListener('click', this.onDocumentClick_);
152 onClose_: function(e) {
153 this.visible = false;
158 onFocusIn_: function(e) {
159 if (e.target === this)
162 window.setTimeout(function() { this.focus(); }, 0);
167 didButtonBarMutate_: function(e) {
168 var hasButtons = this.leftButtons.children.length +
169 this.rightButtons.children.length > 0;
171 this.shadow_.querySelector('button-bar').style.display = undefined;
173 this.shadow_.querySelector('button-bar').style.display = 'none';
176 onKeyDown_: function(e) {
177 // Disallow shift-tab back to another element.
178 if (e.keyCode === 9 && // tab
185 if (e.keyCode !== 27) // escape
188 this.visible = false;
192 onClick_: function(e) {
196 onDocumentClick_: function(e) {
197 if (!this.userCanClose_)
200 this.visible = false;