diff --git a/core/components/component.js b/core/components/component.js deleted file mode 100644 index cca8285d5..000000000 --- a/core/components/component.js +++ /dev/null @@ -1,554 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Definition of the Blockly.Component class. - * This class is similar to Closure's goog.ui.Component class. - * @author samelh@google.com (Sam El-Husseini) - */ -'use strict'; - -goog.provide('Blockly.Component'); - -goog.provide('Blockly.Component.Error'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.IdGenerator'); -goog.require('Blockly.utils.style'); - - -/** - * Default implementation of a UI component. - * Similar to Closure's goog.ui.Component. - * - * @constructor - */ -Blockly.Component = function() { - - /** - * Whether the component is rendered right-to-left. - * @type {boolean} - * @protected - */ - this.rightToLeft_ = Blockly.Component.defaultRightToLeft; - - /** - * Unique ID of the component, lazily initialized in {@link - * Blockly.Component#getId} if needed. This property is strictly private and - * must not be accessed directly outside of this class! - * @type {?string} - * @private - */ - this.id_ = null; - - /** - * Whether the component is in the document. - * @type {boolean} - * @private - */ - this.inDocument_ = false; - - /** - * The DOM element for the component. - * @type {?Element} - * @private - */ - this.element_ = null; - - /** - * Parent component to which events will be propagated. This property is - * strictly private and must not be accessed directly outside of this class! - * @type {?Blockly.Component} - * @private - */ - this.parent_ = null; - - /** - * Array of child components. - * Must be kept in sync with `childIndex_`. This property is strictly - * private and must not be accessed directly outside of this class! - * @type {?Array.} - * @private - */ - this.children_ = []; - - /** - * Map of child component IDs to child components. Used for constant-time - * random access to child components by ID. - * Must be kept in sync with `children_`. This property is strictly - * private and must not be accessed directly outside of this class! - * - * @type {?Object} - * @private - */ - this.childIndex_ = {}; - - /** - * Whether or not the component has been disposed. - * @type {boolean} - * @private - */ - this.disposed_ = false; -}; - - -/** - * The default right to left value. - * @type {boolean} - * @package - */ -Blockly.Component.defaultRightToLeft = false; - -/** - * Errors thrown by the component. - * @enum {string} - */ -Blockly.Component.Error = { - /** - * Error when the component is already rendered and another render attempt is - * made. - */ - ALREADY_RENDERED: 'Component already rendered', - - /** - * Error when an attempt is made to set the parent of a component in a way - * that would result in an inconsistent object graph. - */ - PARENT_UNABLE_TO_BE_SET: 'Unable to set parent component', - - /** - * Error when an attempt is made to add a child component at an out-of-bounds - * index. We don't support sparse child arrays. - */ - CHILD_INDEX_OUT_OF_BOUNDS: 'Child component index out of bounds', - - /** - * Error when calling an abstract method that should be overriden. - */ - ABSTRACT_METHOD: 'Unimplemented abstract method' -}; - -/** - * Gets the unique ID for the instance of this component. If the instance - * doesn't already have an ID, generates one on the fly. - * @return {string} Unique component ID. - * @package - */ -Blockly.Component.prototype.getId = function() { - return this.id_ || (this.id_ = Blockly.utils.IdGenerator.getNextUniqueId()); -}; - -/** - * Gets the component's element. - * @return {Element} The element for the component. - * @package - */ -Blockly.Component.prototype.getElement = function() { - return this.element_; -}; - -/** - * Sets the component's root element to the given element. Considered - * protected and final. - * - * This should generally only be called during createDom. Setting the element - * does not actually change which element is rendered, only the element that is - * associated with this UI component. - * - * This should only be used by subclasses and its associated renderers. - * - * @param {Element} element Root element for the component. - * @protected - */ -Blockly.Component.prototype.setElementInternal = function(element) { - this.element_ = element; -}; - -/** - * Sets the parent of this component to use for event bubbling. Throws an error - * if the component already has a parent or if an attempt is made to add a - * component to itself as a child. - * @param {Blockly.Component} parent The parent component. - * @protected - */ -Blockly.Component.prototype.setParent = function(parent) { - if (this == parent) { - // Attempting to add a child to itself is an error. - throw Error(Blockly.Component.Error.PARENT_UNABLE_TO_BE_SET); - } - - if (parent && this.parent_ && this.id_ && this.parent_.getChild(this.id_) && - this.parent_ != parent) { - // This component is already the child of some parent. - throw Error(Blockly.Component.Error.PARENT_UNABLE_TO_BE_SET); - } - - this.parent_ = parent; -}; - -/** - * Returns the component's parent, if any. - * @return {?Blockly.Component} The parent component. - * @protected - */ -Blockly.Component.prototype.getParent = function() { - return this.parent_; -}; - -/** - * Determines whether the component has been added to the document. - * @return {boolean} TRUE if rendered. Otherwise, FALSE. - * @protected - */ -Blockly.Component.prototype.isInDocument = function() { - return this.inDocument_; -}; - -/** - * Creates the initial DOM representation for the component. - * @protected - */ -Blockly.Component.prototype.createDom = function() { - throw Error(Blockly.Component.Error.ABSTRACT_METHOD); -}; - -/** - * Renders the component. If a parent element is supplied, the component's - * element will be appended to it. If there is no optional parent element and - * the element doesn't have a parentNode then it will be appended to the - * document body. - * - * If this component has a parent component, and the parent component is - * not in the document already, then this will not call `enterDocument` - * on this component. - * - * Throws an Error if the component is already rendered. - * - * @param {Element=} opt_parentElement Optional parent element to render the - * component into. - * @package - */ -Blockly.Component.prototype.render = function(opt_parentElement) { - this.render_(opt_parentElement); -}; - -/** - * Renders the component. If a parent element is supplied, the component's - * element will be appended to it. If there is no optional parent element and - * the element doesn't have a parentNode then it will be appended to the - * document body. - * - * If this component has a parent component, and the parent component is - * not in the document already, then this will not call `enterDocument` - * on this component. - * - * Throws an Error if the component is already rendered. - * - * @param {Element=} opt_parentElement Optional parent element to render the - * component into. - * @param {Node=} opt_beforeNode Node before which the component is to - * be rendered. If left out the node is appended to the parent element. - * @private - */ -Blockly.Component.prototype.render_ = function( - opt_parentElement, opt_beforeNode) { - if (this.inDocument_) { - throw Error(Blockly.Component.Error.ALREADY_RENDERED); - } - - if (!this.element_) { - this.createDom(); - } - - if (opt_parentElement) { - opt_parentElement.insertBefore(this.element_, opt_beforeNode || null); - } else { - document.body.appendChild(this.element_); - } - - // If this component has a parent component that isn't in the document yet, - // we don't call enterDocument() here. Instead, when the parent component - // enters the document, the enterDocument() call will propagate to its - // children, including this one. If the component doesn't have a parent - // or if the parent is already in the document, we call enterDocument(). - if (!this.parent_ || this.parent_.isInDocument()) { - this.enterDocument(); - } -}; - -/** - * Called when the component's element is known to be in the document. Anything - * using document.getElementById etc. should be done at this stage. - * - * If the component contains child components, this call is propagated to its - * children. - * @protected - */ -Blockly.Component.prototype.enterDocument = function() { - this.inDocument_ = true; - - // Propagate enterDocument to child components that have a DOM, if any. - // If a child was decorated before entering the document (permitted when - // Blockly.Component.ALLOW_DETACHED_DECORATION is true), its enterDocument - // will be called here. - this.forEachChild(function(child) { - if (!child.isInDocument() && child.getElement()) { - child.enterDocument(); - } - }); -}; - -/** - * Called by dispose to clean up the elements and listeners created by a - * component, or by a parent component/application who has removed the - * component from the document but wants to reuse it later. - * - * If the component contains child components, this call is propagated to its - * children. - * - * It should be possible for the component to be rendered again once this method - * has been called. - * @protected - */ -Blockly.Component.prototype.exitDocument = function() { - // Propagate exitDocument to child components that have been rendered, if any. - this.forEachChild(function(child) { - if (child.isInDocument()) { - child.exitDocument(); - } - }); - - this.inDocument_ = false; -}; - -/** - * Disposes of the object. If the object hasn't already been disposed of, calls - * {@link #disposeInternal}. - * @package - */ -Blockly.Component.prototype.dispose = function() { - if (!this.disposed_) { - // Set disposed_ to true first, in case during the chain of disposal this - // gets disposed recursively. - this.disposed_ = true; - this.disposeInternal(); - } -}; - -/** - * Disposes of the component. Calls `exitDocument`, which is expected to - * remove event handlers and clean up the component. Propagates the call to - * the component's children, if any. Removes the component's DOM from the - * document. - * @protected - */ -Blockly.Component.prototype.disposeInternal = function() { - if (this.inDocument_) { - this.exitDocument(); - } - - // Disposes of the component's children, if any. - this.forEachChild(function(child) { child.dispose(); }); - - // Detach the component's element from the DOM. - if (this.element_) { - Blockly.utils.dom.removeNode(this.element_); - } - - this.children_ = null; - this.childIndex_ = null; - this.element_ = null; - this.parent_ = null; -}; - -/** - * Adds the specified component as the last child of this component. See - * {@link Blockly.Component#addChildAt} for detailed semantics. - * - * @see Blockly.Component#addChildAt - * @param {Blockly.Component} child The new child component. - * @param {boolean=} opt_render If true, the child component will be rendered - * into the parent. - * @package - */ -Blockly.Component.prototype.addChild = function(child, opt_render) { - this.addChildAt(child, this.getChildCount(), opt_render); -}; - -/** - * Adds the specified component as a child of this component at the given - * 0-based index. - * - * Both `addChild` and `addChildAt` assume the following contract - * between parent and child components: - *