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.
7 <link rel="import" href="/tvcm.html">
11 tvcm.exportTo('tvcm.ui', function() {
14 * Decorates elements as an instance of a class.
15 * @param {string|!Element} source The way to find the element(s) to decorate.
16 * If this is a string then {@code querySeletorAll} is used to find the
17 * elements to decorate.
18 * @param {!Function} constr The constructor to decorate with. The constr
19 * needs to have a {@code decorate} function.
21 function decorate(source, constr) {
23 if (typeof source == 'string')
24 elements = tvcm.doc.querySelectorAll(source);
28 for (var i = 0, el; el = elements[i]; i++) {
29 if (!(el instanceof constr))
35 * Defines a tracing UI component, a function that can be called to construct
40 * var List = tvcm.ui.define('list');
42 * __proto__: HTMLUListElement.prototype,
43 * decorate: function() {
52 * var CustomList = tvcm.ui.define('custom-list', List);
53 * CustomList.prototype = {
54 * __proto__: List.prototype,
55 * decorate: function() {
62 * @param {string} className The className of the newly created subtype. If
63 * subclassing by passing in opt_parentConstructor, this is used for
64 * debugging. If not subclassing, then it is the tag name that will be
65 * created by the component.
67 * @param {function=} opt_parentConstructor The parent class for this new
68 * element, if subclassing is desired. If provided, the parent class must
69 * be also a function created by tvcm.ui.define.
71 * @param {string=} opt_tagNS The namespace in which to create the base
72 * element. Has no meaning when opt_parentConstructor is passed and must
73 * either be undefined or the same namespace as the parent class.
75 * @return {function(Object=):Element} The newly created component
78 function define(className, opt_parentConstructor, opt_tagNS) {
79 if (typeof className == 'function') {
80 throw new Error('Passing functions as className is deprecated. Please ' +
81 'use (className, opt_parentConstructor) to subclass');
84 var className = className.toLowerCase();
85 if (opt_parentConstructor && !opt_parentConstructor.tagName)
86 throw new Error('opt_parentConstructor was not ' +
87 'created by tvcm.ui.define');
89 // Walk up the parent constructors until we can find the type of tag
91 var tagName = className;
92 var tagNS = undefined;
93 if (opt_parentConstructor) {
95 throw new Error('Must not specify tagNS if parentConstructor is given');
96 var parent = opt_parentConstructor;
97 while (parent && parent.tagName) {
98 tagName = parent.tagName;
100 parent = parent.parentConstructor;
107 * Creates a new UI element constructor.
108 * Arguments passed to the constuctor are provided to the decorate method.
109 * You will need to call the parent elements decorate method from within
110 * your decorate method and pass any required parameters.
114 if (opt_parentConstructor &&
115 f.prototype.__proto__ != opt_parentConstructor.prototype) {
117 className + ' prototye\'s __proto__ field is messed up. ' +
118 'It MUST be the prototype of ' + opt_parentConstructor.tagName);
122 if (tagNS === undefined)
123 el = tvcm.doc.createElement(tagName);
125 el = tvcm.doc.createElementNS(tagNS, tagName);
126 f.decorate.call(this, el, arguments);
131 * Decorates an element as a UI element class.
132 * @param {!Element} el The element to decorate.
134 f.decorate = function(el) {
135 el.__proto__ = f.prototype;
136 el.decorate.apply(el, arguments[1]);
140 f.className = className;
143 f.parentConstructor = (opt_parentConstructor ? opt_parentConstructor :
145 f.toString = function() {
146 if (!f.parentConstructor)
148 return f.parentConstructor.toString() + '::' + f.className;
154 function elementIsChildOf(el, potentialParent) {
155 if (el == potentialParent)
159 while (cur.parentNode) {
160 if (cur == potentialParent)
162 cur = cur.parentNode;
170 elementIsChildOf: elementIsChildOf