Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / resources / print_preview / component.js
blob2baa4c8f89439419ec04d462c24a98593355443c
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.
5 cr.define('print_preview', function() {
6   'use strict';
8   /**
9    * Class that represents a UI component.
10    * @constructor
11    * @extends {cr.EventTarget}
12    */
13   function Component() {
14     cr.EventTarget.call(this);
16     /**
17      * Component's HTML element.
18      * @type {Element}
19      * @private
20      */
21     this.element_ = null;
23     this.isInDocument_ = false;
25     /**
26      * Component's event tracker.
27      * @type {EventTracker}
28      * @private
29      */
30      this.tracker_ = new EventTracker();
32     /**
33      * Child components of the component.
34      * @type {Array.<print_preview.Component>}
35      * @private
36      */
37     this.children_ = [];
38   };
40   Component.prototype = {
41     __proto__: cr.EventTarget.prototype,
43     /** Gets the component's element. */
44     getElement: function() {
45       return this.element_;
46     },
48     /** @return {EventTracker} Component's event tracker. */
49     get tracker() {
50       return this.tracker_;
51     },
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     },
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     },
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       this.children_.forEach(function(child) {
77         if (!child.isInDocument && child.getElement()) {
78           child.enterDocument();
79         }
80       });
81     },
83     /** Removes all event listeners. */
84     exitDocument: function() {
85       this.children_.forEach(function(child) {
86         if (child.isInDocument) {
87           child.exitDocument();
88         }
89       });
90       this.tracker_.removeAll();
91       this.isInDocument_ = false;
92     },
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     },
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     },
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     },
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     },
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     },
153     /**
154      * @param {string} query Selector query to select an element starting from
155      *     the component's root element using a depth first search for the first
156      *     element that matches the query.
157      * @return {HTMLElement} Element selected by the given query.
158      */
159     getChildElement: function(query) {
160       return this.element_.querySelector(query);
161     },
163     /**
164      * Sets the component's element.
165      * @param {Element} element HTML element to set as the component's element.
166      * @protected
167      */
168     setElementInternal: function(element) {
169       this.element_ = element;
170     },
172     /**
173      * Decorates the given element for use as the element of the component.
174      * @protected
175      */
176     decorateInternal: function() { /*abstract*/ },
178     /**
179      * Clones a template HTML DOM tree.
180      * @param {string} templateId Template element ID.
181      * @param {boolean=} opt_keepHidden Whether to leave the cloned template
182      *     hidden after cloning.
183      * @return {Element} Cloned element with its 'id' attribute stripped.
184      * @protected
185      */
186     cloneTemplateInternal: function(templateId, opt_keepHidden) {
187       var templateEl = $(templateId);
188       assert(templateEl != null,
189              'Could not find element with ID: ' + templateId);
190       var el = templateEl.cloneNode(true);
191       el.id = '';
192       if (!opt_keepHidden) {
193         setIsVisible(el, true);
194       }
195       return el;
196     }
197   };
199   return {
200     Component: Component
201   };