15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cr.define('print_preview', function() {
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  'use strict';
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /**
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * Class that represents a UI component.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * @constructor
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * @extends {cr.EventTarget}
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   */
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  function Component() {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cr.EventTarget.call(this);
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Component's HTML element.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {Element}
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @private
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.element_ = null;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.isInDocument_ = false;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Component's event tracker.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {EventTracker}
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @private
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     this.tracker_ = new EventTracker();
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Child components of the component.
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {Array.<print_preview.Component>}
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @private
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.children_ = [];
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Component.prototype = {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    __proto__: cr.EventTarget.prototype,
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /** Gets the component's element. */
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    getElement: function() {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return this.element_;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /** @return {EventTracker} Component's event tracker. */
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    get tracker() {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return this.tracker_;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return {boolean} Whether the element of the component is already in the
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *     HTML document.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    get isInDocument() {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return this.isInDocument_;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Creates the root element of the component. Sub-classes should override
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * this method.
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    createDom: function() {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.element_ = cr.doc.createElement('div');
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Called when the component's element is known to be in the document.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Anything using document.getElementById etc. should be done at this stage.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Sub-classes should extend this method and attach listeners.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    enterDocument: function() {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.isInDocument_ = true;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.children_.forEach(function(child) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!child.isInDocument && child.getElement()) {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          child.enterDocument();
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      });
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /** Removes all event listeners. */
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    exitDocument: function() {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.children_.forEach(function(child) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (child.isInDocument) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          child.exitDocument();
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      });
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.tracker_.removeAll();
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.isInDocument_ = false;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Renders this UI component and appends the element to the given parent
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * element.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {!Element} parentElement Element to render the component's
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *     element into.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    render: function(parentElement) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert(!this.isInDocument, 'Component is already in the document');
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!this.element_) {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.createDom();
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parentElement.appendChild(this.element_);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.enterDocument();
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Decorates an existing DOM element. Sub-classes should override the
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * override the decorateInternal method.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {Element} element Element to decorate.
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    decorate: function(element) {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert(!this.isInDocument, 'Component is already in the document');
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.setElementInternal(element);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.decorateInternal();
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.enterDocument();
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {print_preview.Component} child Component to add as a child of
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *     this component.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    addChild: function(child) {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.children_.push(child);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {!print_preview.Component} child Component to remove from this
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *     component's children.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    removeChild: function(child) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var childIdx = this.children_.indexOf(child);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (childIdx != -1) {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.children_.splice(childIdx, 1);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (child.isInDocument) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        child.exitDocument();
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (child.getElement()) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          child.getElement().parentNode.removeChild(child.getElement());
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /** Removes all of the component's children. */
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    removeChildren: function() {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while (this.children_.length > 0) {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.removeChild(this.children_[0]);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {string} query Selector query to select an element starting from
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *     the component's root element using a depth first search for the first
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *     element that matches the query.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return {HTMLElement} Element selected by the given query.
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    getChildElement: function(query) {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return this.element_.querySelector(query);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Sets the component's element.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {Element} element HTML element to set as the component's element.
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @protected
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    setElementInternal: function(element) {
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.element_ = element;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Decorates the given element for use as the element of the component.
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @protected
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    decorateInternal: function() { /*abstract*/ },
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Clones a template HTML DOM tree.
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {string} templateId Template element ID.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {boolean=} opt_keepHidden Whether to leave the cloned template
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *     hidden after cloning.
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return {Element} Cloned element with its 'id' attribute stripped.
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @protected
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cloneTemplateInternal: function(templateId, opt_keepHidden) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var templateEl = $(templateId);
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert(templateEl != null,
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             'Could not find element with ID: ' + templateId);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var el = templateEl.cloneNode(true);
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      el.id = '';
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!opt_keepHidden) {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        setIsVisible(el, true);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return el;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Component: Component
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)});
203