Upstream version 5.34.98.0
[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       if (e.type != 'keydown')
155         e.stopPropagation();
156       e.preventDefault();
157       base.dispatchSimpleEvent(this, 'closeclick');
158     },
159
160     onFocusIn_: function(e) {
161       if (e.target === this)
162         return;
163
164       window.setTimeout(function() { this.focus(); }, 0);
165       e.preventDefault();
166       e.stopPropagation();
167     },
168
169     didButtonBarMutate_: function(e) {
170       var hasButtons = this.leftButtons.children.length +
171           this.rightButtons.children.length > 0;
172       if (hasButtons)
173         this.shadow_.querySelector('button-bar').style.display = undefined;
174       else
175         this.shadow_.querySelector('button-bar').style.display = 'none';
176     },
177
178     onKeyDown_: function(e) {
179       // Disallow shift-tab back to another element.
180       if (e.keyCode === 9 &&  // tab
181           e.shiftKey &&
182           e.target === this) {
183         e.preventDefault();
184         return;
185       }
186
187       if (e.keyCode !== 27)  // escape
188         return;
189
190       this.onClose_(e);
191     },
192
193     onClick_: function(e) {
194       e.stopPropagation();
195     },
196
197     onDocumentClick_: function(e) {
198       if (!this.userCanClose_)
199         return;
200
201       this.onClose_(e);
202     }
203   };
204
205   Overlay.showError = function(msg, opt_err) {
206     var o = new Overlay();
207     o.title = 'Error';
208     o.textContent = msg;
209     if (opt_err) {
210       var e = base.normalizeException(opt_err);
211
212       var stackDiv = document.createElement('pre');
213       stackDiv.textContent = e.stack;
214       stackDiv.style.paddingLeft = '8px';
215       stackDiv.style.margin = 0;
216       o.appendChild(stackDiv);
217     }
218     var b = document.createElement('button');
219     b.textContent = 'OK';
220     b.addEventListener('click', function() {
221       o.visible = false;
222     });
223     o.rightButtons.appendChild(b);
224     o.visible = true;
225     return o;
226   }
227
228   return {
229     Overlay: Overlay
230   };
231 });