Upstream version 11.40.271.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / trace_viewer / base / ui / overlay.html
1 <!DOCTYPE html>
2 <!--
3 Copyright (c) 2014 The Chromium Authors. All rights reserved.
4 Use of this source code is governed by a BSD-style license that can be
5 found in the LICENSE file.
6 -->
7
8 <link rel="import" href="/base/utils.html">
9 <link rel="import" href="/base/properties.html">
10 <link rel="import" href="/base/events.html">
11 <link rel="import" href="/base/ui.html">
12
13 <template id="overlay-template">
14   <style>
15     overlay-mask {
16       left: 0;
17       padding: 8px;
18       position: absolute;
19       top: 0;
20       z-index: 1000;
21       font-family: sans-serif;
22       -webkit-justify-content: center;
23       background: rgba(0, 0, 0, 0.8);
24       display: -webkit-flex;
25       height: 100%;
26       left: 0;
27       position: fixed;
28       top: 0;
29       width: 100%;
30     }
31     overlay-mask:focus {
32       outline: none;
33     }
34     overlay-vertical-centering-container {
35       -webkit-justify-content: center;
36       -webkit-flex-direction: column;
37       display: -webkit-flex;
38     }
39     overlay-frame {
40       z-index: 1100;
41       background: rgb(255, 255, 255);
42       border: 1px solid #ccc;
43       margin: 75px;
44       display: -webkit-flex;
45       -webkit-flex-direction: column;
46     }
47     title-bar {
48       -webkit-align-items: center;
49       -webkit-flex-direction: row;
50       border-bottom: 1px solid #ccc;
51       background-color: #ddd;
52       display: -webkit-flex;
53       padding: 5px;
54       -webkit-flex: 0 0 auto;
55     }
56     title {
57       display: inline;
58       font-weight: bold;
59       -webkit-box-flex: 1;
60       -webkit-flex: 1 1 auto;
61     }
62     close-button {
63       -webkit-align-self: flex-end;
64       border: 1px solid #eee;
65       background-color: #999;
66       font-size: 10pt;
67       font-weight: bold;
68       padding: 2px;
69       text-align: center;
70       width: 16px;
71     }
72     close-button:hover {
73       background-color: #ddd;
74       border-color: black;
75       cursor: pointer;
76     }
77     overlay-content {
78       display: -webkit-flex;
79       -webkit-flex: 1 1 auto;
80       -webkit-flex-direction: column;
81       overflow-y: auto;
82       padding: 10px;
83       min-width: 300px;
84     }
85     button-bar {
86       -webkit-align-items: baseline;
87       border-top: 1px solid #ccc;
88       display: -webkit-flex;
89       -webkit-flex: 0 0 auto;
90       -webkit-flex-direction: row-reverse;
91       padding: 4px;
92     }
93   </style>
94
95   <overlay-mask>
96     <overlay-vertical-centering-container>
97       <overlay-frame>
98         <title-bar>
99           <title></title>
100           <close-button>&#x2715</close-button>
101         </title-bar>
102         <overlay-content>
103           <content></content>
104         </overlay-content>
105         <button-bar></button-bar>
106       </overlay-frame>
107     </overlay-vertical-centering-container>
108   </overlay-mask>
109 </template>
110
111 <script>
112 'use strict';
113
114 /**
115  * @fileoverview Implements an element that is hidden by default, but
116  * when shown, dims and (attempts to) disable the main document.
117  *
118  * You can turn any div into an overlay. Note that while an
119  * overlay element is shown, its parent is changed. Hiding the overlay
120  * restores its original parentage.
121  *
122  */
123 tv.exportTo('tv.ui', function() {
124   var THIS_DOC = document.currentScript.ownerDocument;
125
126   /**
127    * Creates a new overlay element. It will not be visible until shown.
128    * @constructor
129    * @extends {HTMLDivElement}
130    */
131   var Overlay = tv.ui.define('overlay');
132
133   Overlay.prototype = {
134     __proto__: HTMLDivElement.prototype,
135
136     /**
137      * Initializes the overlay element.
138      */
139     decorate: function() {
140       this.classList.add('overlay');
141
142       this.parentEl_ = this.ownerDocument.body;
143
144       this.visible_ = false;
145       this.userCanClose_ = true;
146
147       this.onKeyDown_ = this.onKeyDown_.bind(this);
148       this.onClick_ = this.onClick_.bind(this);
149       this.onFocusIn_ = this.onFocusIn_.bind(this);
150       this.onDocumentClick_ = this.onDocumentClick_.bind(this);
151       this.onClose_ = this.onClose_.bind(this);
152
153       this.addEventListener('visibleChange',
154           tv.ui.Overlay.prototype.onVisibleChange_.bind(this), true);
155
156       // Setup the shadow root
157       var createShadowRoot = this.createShadowRoot ||
158           this.webkitCreateShadowRoot;
159       this.shadow_ = createShadowRoot.call(this);
160       this.shadow_.appendChild(tv.instantiateTemplate('#overlay-template',
161                                                         THIS_DOC));
162
163       this.closeBtn_ = this.shadow_.querySelector('close-button');
164       this.closeBtn_.addEventListener('click', this.onClose_);
165
166       this.shadow_
167           .querySelector('overlay-frame')
168           .addEventListener('click', this.onClick_);
169
170       this.observer_ = new WebKitMutationObserver(
171           this.didButtonBarMutate_.bind(this));
172       this.observer_.observe(this.shadow_.querySelector('button-bar'),
173                              { childList: true });
174
175       // title is a variable on regular HTMLElements. However, we want to
176       // use it for something more useful.
177       Object.defineProperty(
178           this, 'title', {
179             get: function() {
180               return this.shadow_.querySelector('title').textContent;
181             },
182             set: function(title) {
183               this.shadow_.querySelector('title').textContent = title;
184             }
185           });
186     },
187
188     set userCanClose(userCanClose) {
189       this.userCanClose_ = userCanClose;
190       this.closeBtn_.style.display =
191           userCanClose ? 'block' : 'none';
192     },
193
194     get buttons() {
195       return this.shadow_.querySelector('button-bar');
196     },
197
198     get visible() {
199       return this.visible_;
200     },
201
202     set visible(newValue) {
203       if (this.visible_ === newValue)
204         return;
205
206       tv.setPropertyAndDispatchChange(this, 'visible', newValue);
207     },
208
209     onVisibleChange_: function() {
210       this.visible_ ? this.show_() : this.hide_();
211     },
212
213     show_: function() {
214       this.parentEl_.appendChild(this);
215
216       if (this.userCanClose_) {
217         document.addEventListener('keydown', this.onKeyDown_);
218         document.addEventListener('click', this.onDocumentClick_);
219       }
220
221       this.parentEl_.addEventListener('focusin', this.onFocusIn_);
222       this.tabIndex = 0;
223
224       // Focus the first thing we find that makes sense. (Skip the close button
225       // as it doesn't make sense as the first thing to focus.)
226       var focusEl = undefined;
227       var elList = this.querySelectorAll('button, input, list, select, a');
228       if (elList.length > 0) {
229         if (elList[0] === this.closeBtn_) {
230           if (elList.length > 1)
231             focusEl = elList[1];
232         } else {
233           focusEl = elList[0];
234         }
235       }
236       if (focusEl === undefined)
237         focusEl = this;
238       focusEl.focus();
239     },
240
241     hide_: function() {
242       this.parentEl_.removeChild(this);
243
244       this.parentEl_.removeEventListener('focusin', this.onFocusIn_);
245
246       if (this.closeBtn_)
247         this.closeBtn_.removeEventListener(this.onClose_);
248
249       document.removeEventListener('keydown', this.onKeyDown_);
250       document.removeEventListener('click', this.onDocumentClick_);
251     },
252
253     onClose_: function(e) {
254       this.visible = false;
255       if (e.type != 'keydown')
256         e.stopPropagation();
257       e.preventDefault();
258       tv.dispatchSimpleEvent(this, 'closeclick');
259     },
260
261     onFocusIn_: function(e) {
262       if (e.target === this)
263         return;
264
265       window.setTimeout(function() { this.focus(); }, 0);
266       e.preventDefault();
267       e.stopPropagation();
268     },
269
270     didButtonBarMutate_: function(e) {
271       var hasButtons = this.buttons.children.length > 0;
272       if (hasButtons)
273         this.shadow_.querySelector('button-bar').style.display = undefined;
274       else
275         this.shadow_.querySelector('button-bar').style.display = 'none';
276     },
277
278     onKeyDown_: function(e) {
279       // Disallow shift-tab back to another element.
280       if (e.keyCode === 9 &&  // tab
281           e.shiftKey &&
282           e.target === this) {
283         e.preventDefault();
284         return;
285       }
286
287       if (e.keyCode !== 27)  // escape
288         return;
289
290       this.onClose_(e);
291     },
292
293     onClick_: function(e) {
294       e.stopPropagation();
295     },
296
297     onDocumentClick_: function(e) {
298       if (!this.userCanClose_)
299         return;
300
301       this.onClose_(e);
302     }
303   };
304
305   Overlay.showError = function(msg, opt_err) {
306     var o = new Overlay();
307     o.title = 'Error';
308     o.textContent = msg;
309     if (opt_err) {
310       var e = tv.normalizeException(opt_err);
311
312       var stackDiv = document.createElement('pre');
313       stackDiv.textContent = e.stack;
314       stackDiv.style.paddingLeft = '8px';
315       stackDiv.style.margin = 0;
316       o.appendChild(stackDiv);
317     }
318     var b = document.createElement('button');
319     b.textContent = 'OK';
320     b.addEventListener('click', function() {
321       o.visible = false;
322     });
323     o.buttons.appendChild(b);
324     o.visible = true;
325     return o;
326   }
327
328   return {
329     Overlay: Overlay
330   };
331 });
332 </script>