All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.raquo.laminar.nodes.ChildNode.scala Maven / Gradle / Ivy

The newest version!
package com.raquo.laminar.nodes

import com.raquo.laminar.modifiers.Modifier
import org.scalajs.dom

import scala.annotation.tailrec
import scala.scalajs.js

trait ChildNode[+Ref <: dom.Node]
extends ReactiveNode[Ref]
with Modifier[ReactiveElement[dom.Element]] {

  private var _maybeParent: Option[ParentNode.Base] = None

  def maybeParent: Option[ParentNode.Base] = _maybeParent

  /** Note: Make sure to call [[willSetParent]] before calling this method manually */
  private[nodes] def setParent(maybeNextParent: Option[ParentNode.Base]): Unit = {
    _maybeParent = maybeNextParent
  }

  /** This is called as a notification, BEFORE changes to the real DOM or to the Scala DOM tree are applied.
    * - Corollary: When this is called, this node's maybeParent reference has not been updated yet.
    *
    * Default implementation is a noop. You can override this to implement DOM lifecycle hooks similar to
    * React's `componentWillUnmount`.
    *
    * Note: This method is NOT automatically called inside [[setParent]] because [[setParent]] is called
    *       AFTER the real DOM was modified. Therefore, IF you call [[setParent]] directly, you need to
    *       also call [[willSetParent]] before that, if you plan to implement that method. However, if you
    *       only call [[setParent]] indirectly, via the methods defined in [[ParentNode]], those methods
    *       take care of calling [[willSetParent]] for you.
    *
    * @param maybeNextParent  `None` means this node is about to be detached form its parent
    */
  @inline private[nodes] def willSetParent(maybeNextParent: Option[ParentNode.Base]): Unit = ()

  override def apply(parentNode: ReactiveElement.Base): Unit = {
    ParentNode.appendChild(parent = parentNode, child = this, hooks = js.undefined)
  }

}

object ChildNode {

  type Base = ChildNode[dom.Node]

  /** Note: This walks up Laminar's element tree, not the real DOM tree.
    * See [[com.raquo.laminar.DomApi.isDescendantOf]] if you want to check the real DOM tree.
    */
  @tailrec final def isDescendantOf(
    child: ChildNode.Base,
    parent: ParentNode.Base
  ): Boolean = {
    child.maybeParent match {
      case Some(`parent`) => true
      case Some(intermediateParent: ChildNode.Base) => isDescendantOf(intermediateParent, parent)
      case _ => false
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy