Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / third_party / tvcm / src / tvcm / 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 tvcm.requireTemplate('tvcm.ui.overlay');
17
18 tvcm.require('tvcm.utils');
19 tvcm.require('tvcm.properties');
20 tvcm.require('tvcm.events');
21 tvcm.require('tvcm.ui');
22
23 tvcm.exportTo('tvcm.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 = tvcm.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           tvcm.ui.Overlay.prototype.onVisibleChange_.bind(this), true);
53
54       // Setup the shadow root
55       var createShadowRoot = this.createShadowRoot ||
56           this.webkitCreateShadowRoot;
57       this.shadow_ = createShadowRoot.call(this);
58       this.shadow_.appendChild(tvcm.instantiateTemplate('#overlay-template'));
59
60       this.closeBtn_ = this.shadow_.querySelector('close-button');
61       this.closeBtn_.addEventListener('click', this.onClose_);
62
63       this.shadow_
64           .querySelector('overlay-frame')
65           .addEventListener('click', this.onClick_);
66
67       this.observer_ = new WebKitMutationObserver(
68           this.didButtonBarMutate_.bind(this));
69       this.observer_.observe(this.shadow_.querySelector('button-bar'),
70                              { childList: true });
71
72       // title is a variable on regular HTMLElements. However, we want to
73       // use it for something more useful.
74       Object.defineProperty(
75           this, 'title', {
76             get: function() {
77               return this.shadow_.querySelector('title').textContent;
78             },
79             set: function(title) {
80               this.shadow_.querySelector('title').textContent = title;
81             }
82           });
83     },
84
85     set userCanClose(userCanClose) {
86       this.userCanClose_ = userCanClose;
87       this.closeBtn_.style.display =
88           userCanClose ? 'block' : 'none';
89     },
90
91     get leftButtons() {
92       return this.shadow_.querySelector('left-buttons');
93     },
94
95     get rightButtons() {
96       return this.shadow_.querySelector('right-buttons');
97     },
98
99     get visible() {
100       return this.visible_;
101     },
102
103     set visible(newValue) {
104       if (this.visible_ === newValue)
105         return;
106
107       tvcm.setPropertyAndDispatchChange(this, 'visible', newValue);
108     },
109
110     onVisibleChange_: function() {
111       this.visible_ ? this.show_() : this.hide_();
112     },
113
114     show_: function() {
115       this.parentEl_.appendChild(this);
116
117       if (this.userCanClose_) {
118         document.addEventListener('keydown', this.onKeyDown_);
119         document.addEventListener('click', this.onDocumentClick_);
120       }
121
122       this.parentEl_.addEventListener('focusin', this.onFocusIn_);
123       this.tabIndex = 0;
124
125       // Focus the first thing we find that makes sense. (Skip the close button
126       // as it doesn't make sense as the first thing to focus.)
127       var focusEl = undefined;
128       var elList = this.querySelectorAll('button, input, list, select, a');
129       if (elList.length > 0) {
130         if (elList[0] === this.closeBtn_) {
131           if (elList.length > 1)
132             focusEl = elList[1];
133         } else {
134           focusEl = elList[0];
135         }
136       }
137       if (focusEl === undefined)
138         focusEl = this;
139       focusEl.focus();
140     },
141
142     hide_: function() {
143       this.parentEl_.removeChild(this);
144
145       this.parentEl_.removeEventListener('focusin', this.onFocusIn_);
146
147       if (this.closeBtn_)
148         this.closeBtn_.removeEventListener(this.onClose_);
149
150       document.removeEventListener('keydown', this.onKeyDown_);
151       document.removeEventListener('click', this.onDocumentClick_);
152     },
153
154     onClose_: function(e) {
155       this.visible = false;
156       if (e.type != 'keydown')
157         e.stopPropagation();
158       e.preventDefault();
159       tvcm.dispatchSimpleEvent(this, 'closeclick');
160     },
161
162     onFocusIn_: function(e) {
163       if (e.target === this)
164         return;
165
166       window.setTimeout(function() { this.focus(); }, 0);
167       e.preventDefault();
168       e.stopPropagation();
169     },
170
171     didButtonBarMutate_: function(e) {
172       var hasButtons = this.leftButtons.children.length +
173           this.rightButtons.children.length > 0;
174       if (hasButtons)
175         this.shadow_.querySelector('button-bar').style.display = undefined;
176       else
177         this.shadow_.querySelector('button-bar').style.display = 'none';
178     },
179
180     onKeyDown_: function(e) {
181       // Disallow shift-tab back to another element.
182       if (e.keyCode === 9 &&  // tab
183           e.shiftKey &&
184           e.target === this) {
185         e.preventDefault();
186         return;
187       }
188
189       if (e.keyCode !== 27)  // escape
190         return;
191
192       this.onClose_(e);
193     },
194
195     onClick_: function(e) {
196       e.stopPropagation();
197     },
198
199     onDocumentClick_: function(e) {
200       if (!this.userCanClose_)
201         return;
202
203       this.onClose_(e);
204     }
205   };
206
207   Overlay.showError = function(msg, opt_err) {
208     var o = new Overlay();
209     o.title = 'Error';
210     o.textContent = msg;
211     if (opt_err) {
212       var e = tvcm.normalizeException(opt_err);
213
214       var stackDiv = document.createElement('pre');
215       stackDiv.textContent = e.stack;
216       stackDiv.style.paddingLeft = '8px';
217       stackDiv.style.margin = 0;
218       o.appendChild(stackDiv);
219     }
220     var b = document.createElement('button');
221     b.textContent = 'OK';
222     b.addEventListener('click', function() {
223       o.visible = false;
224     });
225     o.rightButtons.appendChild(b);
226     o.visible = true;
227     return o;
228   }
229
230   return {
231     Overlay: Overlay
232   };
233 });