OLD | NEW |
(Empty) | |
| 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 cr.define('print_preview', function() { |
| 6 'use strict'; |
| 7 |
| 8 /** |
| 9 * Class that represents a UI component. |
| 10 * @constructor |
| 11 * @extends {cr.EventTarget} |
| 12 */ |
| 13 function Component() { |
| 14 cr.EventTarget.call(this); |
| 15 |
| 16 /** |
| 17 * Component's HTML element. |
| 18 * @type {Element} |
| 19 * @private |
| 20 */ |
| 21 this.element_ = null; |
| 22 |
| 23 this.isInDocument_ = false; |
| 24 |
| 25 /** |
| 26 * Component's event tracker. |
| 27 * @type {EventTracker} |
| 28 * @private |
| 29 */ |
| 30 this.tracker_ = new EventTracker(); |
| 31 |
| 32 /** |
| 33 * Child components of the component. |
| 34 * @type {Array.<print_preview.Component>} |
| 35 * @private |
| 36 */ |
| 37 this.children_ = []; |
| 38 }; |
| 39 |
| 40 Component.prototype = { |
| 41 __proto__: cr.EventTarget.prototype, |
| 42 |
| 43 /** Gets the component's element. */ |
| 44 getElement: function() { |
| 45 return this.element_; |
| 46 }, |
| 47 |
| 48 /** @return {EventTracker} Component's event tracker. */ |
| 49 get tracker() { |
| 50 return this.tracker_; |
| 51 }, |
| 52 |
| 53 /** |
| 54 * @return {boolean} Whether the element of the component is already in the |
| 55 * HTML document. |
| 56 */ |
| 57 get isInDocument() { |
| 58 return this.isInDocument_; |
| 59 }, |
| 60 |
| 61 /** |
| 62 * Creates the root element of the component. Sub-classes should override |
| 63 * this method. |
| 64 */ |
| 65 createDom: function() { |
| 66 this.element_ = cr.doc.createElement('div'); |
| 67 }, |
| 68 |
| 69 /** |
| 70 * Called when the component's element is known to be in the document. |
| 71 * Anything using document.getElementById etc. should be done at this stage. |
| 72 * Sub-classes should extend this method and attach listeners. |
| 73 */ |
| 74 enterDocument: function() { |
| 75 this.isInDocument_ = true; |
| 76 for (var child, i = 0; child = this.children_[i]; i++) { |
| 77 if (!child.isInDocument && child.getElement()) { |
| 78 child.enterDocument(); |
| 79 } |
| 80 } |
| 81 }, |
| 82 |
| 83 /** Removes all event listeners. */ |
| 84 exitDocument: function() { |
| 85 for (var child, i = 0; child = this.children_[i]; i++) { |
| 86 if (child.isInDocument) { |
| 87 child.exitDocument(); |
| 88 } |
| 89 } |
| 90 this.tracker_.removeAll(); |
| 91 this.isInDocument_ = false; |
| 92 }, |
| 93 |
| 94 /** |
| 95 * Renders this UI component and appends the element to the given parent |
| 96 * element. |
| 97 * @param {!Element} parentElement Element to render the component's |
| 98 * element into. |
| 99 */ |
| 100 render: function(parentElement) { |
| 101 assert(!this.isInDocument, 'Component is already in the document'); |
| 102 if (!this.element_) { |
| 103 this.createDom(); |
| 104 } |
| 105 parentElement.appendChild(this.element_); |
| 106 this.enterDocument(); |
| 107 }, |
| 108 |
| 109 /** |
| 110 * Decorates an existing DOM element. Sub-classes should override the |
| 111 * override the decorateInternal method. |
| 112 * @param {Element} element Element to decorate. |
| 113 */ |
| 114 decorate: function(element) { |
| 115 assert(!this.isInDocument, 'Component is already in the document'); |
| 116 this.setElementInternal(element); |
| 117 this.decorateInternal(); |
| 118 this.enterDocument(); |
| 119 }, |
| 120 |
| 121 /** |
| 122 * @param {print_preview.Component} child Component to add as a child of |
| 123 * this component. |
| 124 */ |
| 125 addChild: function(child) { |
| 126 this.children_.push(child); |
| 127 }, |
| 128 |
| 129 /** |
| 130 * @param {!print_preview.Component} child Component to remove from this |
| 131 * component's children. |
| 132 */ |
| 133 removeChild: function(child) { |
| 134 var childIdx = this.children_.indexOf(child); |
| 135 if (childIdx != -1) { |
| 136 this.children_.splice(childIdx, 1); |
| 137 } |
| 138 if (child.isInDocument) { |
| 139 child.exitDocument(); |
| 140 if (child.getElement()) { |
| 141 child.getElement().parentNode.removeChild(child.getElement()); |
| 142 } |
| 143 } |
| 144 }, |
| 145 |
| 146 /** Removes all of the component's children. */ |
| 147 removeChildren: function() { |
| 148 while (this.children_.length > 0) { |
| 149 this.removeChild(this.children_[0]); |
| 150 } |
| 151 }, |
| 152 |
| 153 /** |
| 154 * Sets the component's element. |
| 155 * @param {Element} element HTML element to set as the component's element. |
| 156 * @protected |
| 157 */ |
| 158 setElementInternal: function(element) { |
| 159 this.element_ = element; |
| 160 }, |
| 161 |
| 162 /** |
| 163 * Decorates the given element for use as the element of the component. |
| 164 * @protected |
| 165 */ |
| 166 decorateInternal: function() { /*abstract*/ }, |
| 167 |
| 168 /** |
| 169 * Clones a template HTML DOM tree. |
| 170 * @param {string} templateId Template element ID. |
| 171 * @param {boolean=} opt_keepHidden Whether to leave the cloned template |
| 172 * hidden after cloning. |
| 173 * @return {Element} Cloned element with its 'id' attribute stripped. |
| 174 * @protected |
| 175 */ |
| 176 cloneTemplateInternal: function(templateId, opt_keepHidden) { |
| 177 var templateEl = $(templateId); |
| 178 assert(templateEl != null, |
| 179 'Could not find element with ID: ' + templateId); |
| 180 var el = templateEl.cloneNode(true); |
| 181 el.id = ''; |
| 182 if (!opt_keepHidden) { |
| 183 setIsVisible(el, true); |
| 184 } |
| 185 return el; |
| 186 } |
| 187 }; |
| 188 |
| 189 return { |
| 190 Component: Component |
| 191 }; |
| 192 }); |
OLD | NEW |