- add third_party src.
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / src / ui / overlay.js
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.
4
5 'use strict';
6
7 /**
8  * @fileoverview Implements an element that is hidden by default, but
9  * when shown, dims and (attempts to) disable the main document.
10  *
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.
14  *
15  */
16 base.requireTemplate('ui.overlay');
17
18 base.require('base.utils');
19 base.require('base.properties');
20 base.require('base.events');
21 base.require('ui');
22
23 base.exportTo('ui', function() {
24   /**
25    * Creates a new overlay element. It will not be visible until shown.
26    * @constructor
27    * @extends {HTMLDivElement}
28    */
29   var Overlay = ui.define('overlay');
30
31   Overlay.prototype = {
32     __proto__: HTMLDivElement.prototype,
33
34     /**
35      * Initializes the overlay element.
36      */
37     decorate: function() {
38       this.classList.add('overlay');
39
40       this.parentEl_ = this.ownerDocument.body;
41
42       this.visible_ = false;
43       this.userCanClose_ = true;
44
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);
50
51       this.addEventListener('visibleChange',
52           ui.Overlay.prototype.onVisibleChange_.bind(this), true);
53
54       // Setup the shadow root
55       this.shadow_ = this.webkitCreateShadowRoot();
56       this.shadow_.appendChild(base.instantiateTemplate('#overlay-template'));
57
58       this.closeBtn_ = this.shadow_.querySelector('close-button');
59       this.closeBtn_.addEventListener('click', this.onClose_);
60
61       this.shadow_
62           .querySelector('overlay-frame')
63           .addEventListener('click', this.onClick_);
64
65       this.observer_ = new WebKitMutationObserver(
66           this.didButtonBarMutate_.bind(this));
67       this.observer_.observe(this.shadow_.querySelector('button-bar'),
68                              { childList: true });
69
70       // title is a variable on regular HTMLElements. However, we want to
71       // use it for something more useful.
72       Object.defineProperty(
73           this, 'title', {
74             get: function() {
75               return this.shadow_.querySelector('title').textContent;
76             },
77             set: function(title) {
78               this.shadow_.querySelector('title').textContent = title;
79             }
80           });
81     },
82
83     set userCanClose(userCanClose) {
84       this.userCanClose_ = userCanClose;
85       this.closeBtn_.style.display =
86           userCanClose ? 'block' : 'none';
87     },
88
89     get leftButtons() {
90       return this.shadow_.querySelector('left-buttons');
91     },
92
93     get rightButtons() {
94       return this.shadow_.querySelector('right-buttons');
95     },
96
97     get visible() {
98       return this.visible_;
99     },
100
101     set visible(newValue) {
102       if (this.visible_ === newValue)
103         return;
104
105       base.setPropertyAndDispatchChange(this, 'visible', newValue);
106     },
107
108     onVisibleChange_: function() {
109       this.visible_ ? this.show_() : this.hide_();
110     },
111
112     show_: function() {
113       this.parentEl_.appendChild(this);
114
115       if (this.userCanClose_) {
116         document.addEventListener('keydown', this.onKeyDown_);
117         document.addEventListener('click', this.onDocumentClick_);
118       }
119
120       this.parentEl_.addEventListener('focusin', this.onFocusIn_);
121       this.tabIndex = 0;
122
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)
130             focusEl = elList[1];
131         } else {
132           focusEl = elList[0];
133         }
134       }
135       if (focusEl === undefined)
136         focusEl = this;
137       focusEl.focus();
138     },
139
140     hide_: function() {
141       this.parentEl_.removeChild(this);
142
143       this.parentEl_.removeEventListener('focusin', this.onFocusIn_);
144
145       if (this.closeBtn_)
146         this.closeBtn_.removeEventListener(this.onClose_);
147
148       document.removeEventListener('keydown', this.onKeyDown_);
149       document.removeEventListener('click', this.onDocumentClick_);
150     },
151
152     onClose_: function(e) {
153       this.visible = false;
154       e.stopPropagation();
155       e.preventDefault();
156     },
157
158     onFocusIn_: function(e) {
159       if (e.target === this)
160         return;
161
162       window.setTimeout(function() { this.focus(); }, 0);
163       e.preventDefault();
164       e.stopPropagation();
165     },
166
167     didButtonBarMutate_: function(e) {
168       var hasButtons = this.leftButtons.children.length +
169           this.rightButtons.children.length > 0;
170       if (hasButtons)
171         this.shadow_.querySelector('button-bar').style.display = undefined;
172       else
173         this.shadow_.querySelector('button-bar').style.display = 'none';
174     },
175
176     onKeyDown_: function(e) {
177       // Disallow shift-tab back to another element.
178       if (e.keyCode === 9 &&  // tab
179           e.shiftKey &&
180           e.target === this) {
181         e.preventDefault();
182         return;
183       }
184
185       if (e.keyCode !== 27)  // escape
186         return;
187
188       this.visible = false;
189       e.preventDefault();
190     },
191
192     onClick_: function(e) {
193       e.stopPropagation();
194     },
195
196     onDocumentClick_: function(e) {
197       if (!this.userCanClose_)
198         return;
199
200       this.visible = false;
201       e.preventDefault();
202       e.stopPropagation();
203     }
204   };
205
206   return {
207     Overlay: Overlay
208   };
209 });