Source: models/render-tree.js

import RenderNode from 'mobiledoc-kit/models/render-node';
import ElementMap from '../utils/element-map';

export default class RenderTree {
  constructor(rootPostNode) {
    this._rootNode = this.buildRenderNode(rootPostNode);
    this._elements = new ElementMap();
  }
  /*
   * @return {RenderNode} The root render node in this tree
   */
  get rootNode() {
    return this._rootNode;
  }
  /**
   * @return {Boolean}
   */
  get isDirty() {
    return this.rootNode && this.rootNode.isDirty;
  }
  /*
   * @return {DOMNode} The root DOM element in this tree
   */
  get rootElement() {
    return this.rootNode.element;
  }
  /*
   * @param {DOMNode} element
   * @return {RenderNode} The renderNode for this element, if any
   */
  getElementRenderNode(element) {
    return this._elements.get(element);
  }
  setElementRenderNode(element, renderNode) {
    this._elements.set(element, renderNode);
  }
  removeElementRenderNode(element) {
    this._elements.remove(element);
  }
  /**
   * @param {DOMNode} element
   * Walk up from the dom element until we find a renderNode element
   */
  findRenderNodeFromElement(element, conditionFn=()=>true) {
    let renderNode;
    while (element) {
      renderNode = this.getElementRenderNode(element);
      if (renderNode && conditionFn(renderNode)) {
        return renderNode;
      }

      // continue loop
      element = element.parentNode;

      // stop if we are at the root element
      if (element === this.rootElement) {
        if (conditionFn(this.rootNode)) {
          return this.rootNode;
        } else {
          return;
        }
      }
    }
  }
  buildRenderNode(postNode) {
    const renderNode = new RenderNode(postNode, this);
    postNode.renderNode = renderNode;
    return renderNode;
  }
}