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

com.raquo.laminar.inserters.ChildrenCommandInserter.scala Maven / Gradle / Ivy

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

import com.raquo.airstream.core.EventStream
import com.raquo.laminar.DomApi
import com.raquo.laminar.modifiers.RenderableNode
import com.raquo.laminar.nodes.{ChildNode, ParentNode, ReactiveElement}

import scala.scalajs.js

/** Note: this is a low level inserter. It is the fastest one in certain cases,
  * but due to its rather imperative API, its usefulness is very limited.
  *
  * It's good for simple operations on voluminous data, like prepending new
  * log items to a big list, but not much else.
  *
  * Consider using `children <-- observable.split(...)` instead, it has
  * great performance and is much more convenient.
  */
object ChildrenCommandInserter {

  @deprecated("`ChildrenCommand` type alias is deprecated. Use CollectionCommand[Node]", "15.0.0-M5")
  type ChildrenCommand = CollectionCommand[ChildNode.Base]

  def apply[Component] (
    commands: EventStream[CollectionCommand[Component]],
    renderableNode: RenderableNode[Component],
    initialHooks: js.UndefOr[InserterHooks]
  ): DynamicInserter = {
    new DynamicInserter(
      preferStrictMode = true,
      insertFn = (ctx, owner, hooks) => {
        commands.foreach { command =>
          val nodeCountDiff = updateList(
            command,
            parentNode = ctx.parentNode,
            sentinelNode = ctx.sentinelNode,
            ctx.extraNodeCount,
            renderableNode,
            hooks
          )
          ctx.extraNodeCount += nodeCountDiff
        }(owner)
      },
      hooks = initialHooks
    )
  }

  def updateList[Component](
    command: CollectionCommand[Component],
    parentNode: ReactiveElement.Base,
    sentinelNode: ChildNode.Base,
    extraNodeCount: Int,
    renderableNode: RenderableNode[Component],
    hooks: js.UndefOr[InserterHooks]
  ): Int = {
    var nodeCountDiff = 0
    def findSentinelIndex(): Int = DomApi.indexOfChild(
      parent = parentNode.ref,
      child = sentinelNode.ref
    )

    command match {

      case CollectionCommand.Append(node) =>
        val inserted = ParentNode.insertChildAtIndex(
          parent = parentNode,
          child = renderableNode.asNode(node),
          index = findSentinelIndex() + extraNodeCount + 1,
          hooks
        )
        if (inserted) {
          nodeCountDiff = 1
        }
        nodeCountDiff = 1

      case CollectionCommand.Prepend(node) =>
        val inserted = ParentNode.insertChildAfter(
          parent = parentNode,
          newChild = renderableNode.asNode(node),
          referenceChild = sentinelNode,
          hooks
        )
        if (inserted) {
          nodeCountDiff = 1
        }

      case CollectionCommand.Insert(node, atIndex) =>
        val inserted = ParentNode.insertChildAtIndex(
          parent = parentNode,
          child = renderableNode.asNode(node),
          index = findSentinelIndex() + atIndex + 1,
          hooks
        )
        if (inserted) {
          nodeCountDiff = 1
        }

      case CollectionCommand.Remove(node) =>
        val removed = ParentNode.removeChild(
          parent = parentNode,
          child = renderableNode.asNode(node)
        )
        if (removed) {
          nodeCountDiff = -1
        }

      case CollectionCommand.Replace(node, withNode) =>
        ParentNode.replaceChild(
          parent = parentNode,
          oldChild = renderableNode.asNode(node),
          newChild = renderableNode.asNode(withNode),
          hooks
        )
    }

    nodeCountDiff
  }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy