Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / chrome / browser / resources / print_preview / component.js
blob3c18829a22e2e16a445447b69bc77a467f05dc62
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      * @return {!Array<!print_preview.Component>} Child components of this
123      *     component.
124      */
125     get children() {
126       return this.children_;
127     },
129     /**
130      * @param {!print_preview.Component} child Component to add as a child of
131      *     this component.
132      */
133     addChild: function(child) {
134       this.children_.push(child);
135     },
137     /**
138      * @param {!print_preview.Component} child Component to remove from this
139      *     component's children.
140      */
141     removeChild: function(child) {
142       var childIdx = this.children_.indexOf(child);
143       if (childIdx != -1) {
144         this.children_.splice(childIdx, 1);
145       }
146       if (child.isInDocument) {
147         child.exitDocument();
148         if (child.getElement()) {
149           child.getElement().parentNode.removeChild(child.getElement());
150         }
151       }
152     },
154     /** Removes all of the component's children. */
155     removeChildren: function() {
156       while (this.children_.length > 0) {
157         this.removeChild(this.children_[0]);
158       }
159     },
161     /**
162      * @param {string} query Selector query to select an element starting from
163      *     the component's root element using a depth first search for the first
164      *     element that matches the query.
165      * @return {HTMLElement} Element selected by the given query.
166      * TODO(alekseys): Check all call sites and rename this function to
167      *     something like getRequiredChildElement.
168      */
169     getChildElement: function(query) {
170       return this.element_.querySelector(query);
171     },
173     /**
174      * Sets the component's element.
175      * @param {Element} element HTML element to set as the component's element.
176      * @protected
177      */
178     setElementInternal: function(element) {
179       this.element_ = element;
180     },
182     /**
183      * Decorates the given element for use as the element of the component.
184      * @protected
185      */
186     decorateInternal: function() { /*abstract*/ },
188     /**
189      * Clones a template HTML DOM tree.
190      * @param {string} templateId Template element ID.
191      * @param {boolean=} opt_keepHidden Whether to leave the cloned template
192      *     hidden after cloning.
193      * @return {Element} Cloned element with its 'id' attribute stripped.
194      * @protected
195      */
196     cloneTemplateInternal: function(templateId, opt_keepHidden) {
197       var templateEl = $(templateId);
198       assert(templateEl != null,
199              'Could not find element with ID: ' + templateId);
200       var el = assertInstanceof(templateEl.cloneNode(true), HTMLElement);
201       el.id = '';
202       if (!opt_keepHidden) {
203         setIsVisible(el, true);
204       }
205       return el;
206     }
207   };
209   return {
210     Component: Component
211   };