Upstream version 5.34.98.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / src / ui.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 base.exportTo('ui', function() {
8
9   /**
10    * Decorates elements as an instance of a class.
11    * @param {string|!Element} source The way to find the element(s) to decorate.
12    *     If this is a string then {@code querySeletorAll} is used to find the
13    *     elements to decorate.
14    * @param {!Function} constr The constructor to decorate with. The constr
15    *     needs to have a {@code decorate} function.
16    */
17   function decorate(source, constr) {
18     var elements;
19     if (typeof source == 'string')
20       elements = base.doc.querySelectorAll(source);
21     else
22       elements = [source];
23
24     for (var i = 0, el; el = elements[i]; i++) {
25       if (!(el instanceof constr))
26         constr.decorate(el);
27     }
28   }
29
30   /**
31    * Defines a tracing UI component, a function that can be called to construct
32    * the component.
33    *
34    * Base class:
35    * <pre>
36    * var List = ui.define('list');
37    * List.prototype = {
38    *   __proto__: HTMLUListElement.prototype,
39    *   decorate: function() {
40    *     ...
41    *   },
42    *   ...
43    * };
44    * </pre>
45    *
46    * Derived class:
47    * <pre>
48    * var CustomList = ui.define('custom-list', List);
49    * CustomList.prototype = {
50    *   __proto__: List.prototype,
51    *   decorate: function() {
52    *     ...
53    *   },
54    *   ...
55    * };
56    * </pre>
57    *
58    * @param {string} tagName The tagName of the newly created subtype. If
59    *     subclassing, this is used for debugging. If not subclassing, then it is
60    *     the tag name that will be created by the component.
61    * @param {function=} opt_parentConstructor The parent class for this new
62    *     element, if subclassing is desired. If provided, the parent class must
63    *     be also a function created by ui.define.
64    * @return {function(Object=):Element} The newly created component
65    *     constructor.
66    */
67   function define(tagName, opt_parentConstructor) {
68     if (typeof tagName == 'function') {
69       throw new Error('Passing functions as tagName is deprecated. Please ' +
70                       'use (tagName, opt_parentConstructor) to subclass');
71     }
72
73     var tagName = tagName.toLowerCase();
74     if (opt_parentConstructor && !opt_parentConstructor.tagName)
75       throw new Error('opt_parentConstructor was not created by ui.define');
76
77     /**
78      * Creates a new UI element constructor.
79      * Arguments passed to the constuctor are provided to the decorate method.
80      * You will need to call the parent elements decorate method from within
81      * your decorate method and pass any required parameters.
82      * @constructor
83      */
84     function f() {
85       if (opt_parentConstructor &&
86           f.prototype.__proto__ != opt_parentConstructor.prototype) {
87         throw new Error(
88             tagName + ' prototye\'s __proto__ field is messed up. ' +
89             'It MUST be the prototype of ' + opt_parentConstructor.tagName);
90       }
91
92       // Walk up the parent constructors until we can find the type of tag
93       // to create.
94       var tag = tagName;
95       if (opt_parentConstructor) {
96         var parent = opt_parentConstructor;
97         while (parent && parent.tagName) {
98           tag = parent.tagName;
99           parent = parent.parentConstructor;
100         }
101       }
102
103       var el = base.doc.createElement(tag);
104       f.decorate.call(this, el, arguments);
105       return el;
106     }
107
108     try {
109       // f.name is not directly writable. So make it writable anyway.
110       Object.defineProperty(
111           f, 'name',
112           {value: tagName, writable: false, configurable: false});
113     } catch (e) {
114       // defineProperty throws a TypeError about name already being defined
115       // although, it also correctly sets the value to tagName.
116     }
117
118     /**
119      * Decorates an element as a UI element class.
120      * @param {!Element} el The element to decorate.
121      */
122     f.decorate = function(el) {
123       el.__proto__ = f.prototype;
124       el.decorate.apply(el, arguments[1]);
125       el.constructor = f;
126     };
127
128     f.tagName = tagName;
129     f.parentConstructor = (opt_parentConstructor ? opt_parentConstructor :
130                                                    undefined);
131     f.toString = function() {
132       if (!f.parentConstructor)
133         return f.tagName;
134       return f.parentConstructor.toString() + '::' + f.tagName;
135     };
136
137     return f;
138   }
139
140   function elementIsChildOf(el, potentialParent) {
141     if (el == potentialParent)
142       return false;
143
144     var cur = el;
145     while (cur.parentNode) {
146       if (cur == potentialParent)
147         return true;
148       cur = cur.parentNode;
149     }
150     return false;
151   };
152
153   return {
154     decorate: decorate,
155     define: define,
156     elementIsChildOf: elementIsChildOf
157   };
158 });