Add more JS commands

This commit is contained in:
Paul-Henri Froidmont 2025-09-17 04:31:48 +02:00
parent b0caefd0f4
commit 66c2ac5d71
Signed by: phfroidmont
GPG key ID: BE948AFD7E7873BE

View file

@ -14,13 +14,182 @@ object JSCommands:
given JsonEncoder[JSCommand] = given JsonEncoder[JSCommand] =
JsonEncoder[Json].contramap(ops => Json.Arr(ops.reverse*)) JsonEncoder[Json].contramap(ops => Json.Arr(ops.reverse*))
private def classNames(names: String) = names.split("\\s+") private def classNames(names: String): Seq[String] = names.split("\\s+")
private def transitionClasses(names: String | (String, String, String))
: Option[Seq[Seq[String]]] =
names match
case "" => None
case names: String => Some(Seq(classNames(names), Seq.empty, Seq.empty))
case t: (String, String, String) => Some(t.toList.map(classNames))
extension (ops: JSCommand) extension (ops: JSCommand)
private def addOp[A: JsonEncoder](kind: String, args: A) = private def addOp[A: JsonEncoder](kind: String, args: A): JSCommand =
(kind, args).toJsonAST.getOrElse(throw new IllegalArgumentException()) :: ops (kind, args).toJsonAST.fold(e => throw new IllegalArgumentException(e), identity) :: ops
def toggleClass( def addClass = ClassOp("add_class", ops)
def toggleClass = ClassOp("toggle_class", ops)
def removeClass = ClassOp("remove_class", ops)
def dispatch(
event: String,
to: String = "",
detail: Map[String, String] = Map.empty,
bubbles: Boolean = true,
blocking: Boolean = false
) =
ops.addOp(
"dispatch",
Args.Dispatch(
event,
Option.when(to.nonEmpty)(to),
Option.when(detail.nonEmpty)(detail),
Option.when(!bubbles)(bubbles),
Option.when(blocking)(blocking)
)
)
def exec(attr: String, to: String = "") =
ops.addOp(
"exec",
Args.Attr(
attr,
Option.when(to.nonEmpty)(to)
)
)
def focus(to: String = "") =
ops.addOp(
"focus",
Args.To(Option.when(to.nonEmpty)(to))
)
def focusFirst(to: String = "") =
ops.addOp(
"focus_first",
Args.To(Option.when(to.nonEmpty)(to))
)
def hide(
to: String = "",
transition: String | (String, String, String) = "",
time: Int = 200,
blocking: Boolean = true
) =
ops.addOp(
"hide",
Args.Hide(
Option.when(to.nonEmpty)(to),
transitionClasses(transition),
Option.when(time != 200)(time),
Option.when(!blocking)(blocking)
)
)
def ignoreAttributes(to: String = "") =
ops.addOp("ignore_attributes", Args.To(Option.when(to.nonEmpty)(to)))
def navigate(href: String, replace: Boolean = false) =
ops.addOp("navigate", Args.Href(href, Option.when(replace)(replace)))
def patch(href: String, replace: Boolean = false) =
ops.addOp(
"patch",
Args.Href(href, Option.when(replace)(replace))
)
def popFocus() =
ops.addOp("pop_focus", Json.Obj.empty)
def push() = ???
def pushFocus(to: String = "") =
ops.addOp("push_focus", Args.To(Option.when(to.nonEmpty)(to)))
def removeAttribute(attr: String, to: String = "") =
ops.addOp(
"remove_attribute",
Args.Attr(
attr,
Option.when(to.nonEmpty)(to)
)
)
def setAttribute(arg: (String, String), to: String = "") =
ops.addOp("set_attribute", Args.SetAttribute(arg, Option.when(to.nonEmpty)(to)))
def show(
to: String = "",
transition: String | (String, String, String) = "",
time: Int = 200,
blocking: Boolean = true,
display: String = "block"
) =
ops.addOp(
"show",
Args.Show(
Option.when(to.nonEmpty)(to),
transitionClasses(transition),
Option.when(time != 200)(time),
Option.when(!blocking)(blocking),
Option.when(display != "block")(display)
)
)
def toggle(
to: String = "",
in: String | (String, String, String) = "",
out: String | (String, String, String) = "",
time: Int = 200,
blocking: Boolean = true,
display: String = "block"
) =
ops.addOp(
"toggle",
Args.Toggle(
Option.when(to.nonEmpty)(to),
transitionClasses(in),
transitionClasses(out),
Option.when(time != 200)(time),
Option.when(!blocking)(blocking),
Option.when(display != "block")(display)
)
)
def toggleAttribute(
name: String,
value: String,
altValue: String = "",
to: String = ""
) =
ops.addOp(
"toggle_attribute",
Args.ToggleAttribute(
Seq(name, value).appendedAll(Option.when(altValue.nonEmpty)(altValue)),
Option.when(to.nonEmpty)(to)
)
)
def transition(
transition: String | (String, String, String) = "",
to: String = "",
time: Int = 200,
blocking: Boolean = true
) =
ops.addOp(
"transition",
Args.Transition(
transition match
case names: String => Seq(classNames(names), Seq.empty, Seq.empty)
case t: (String, String, String) => t.toList.map(classNames),
Option.when(to.nonEmpty)(to),
Option.when(time != 200)(time),
Option.when(!blocking)(blocking)
)
)
end extension
final private[scalive] class ClassOp(kind: String, ops: JSCommand):
def apply(
names: String, names: String,
to: String = "", to: String = "",
transition: String | (String, String, String) = "", transition: String | (String, String, String) = "",
@ -28,26 +197,66 @@ object JSCommands:
blocking: Boolean = true blocking: Boolean = true
) = ) =
ops.addOp( ops.addOp(
"toggle_class", kind,
Args.ToggleClass( Args.ClassChange(
classNames(names), classNames(names),
Some(to).filterNot(_.isBlank), Option.when(to.nonEmpty)(to),
transition match transitionClasses(transition),
case "" => None Option.when(time != 200)(time),
case names: String => Some(classNames(names)) Option.when(!blocking)(blocking)
case t: (String, String, String) => Some(t.toList),
Some(time).filterNot(_ == 200),
Some(blocking).filterNot(_ == true)
) )
) )
private object Args: private object Args:
final case class ToggleClass( final case class ClassChange(
names: Seq[String], names: Seq[String],
to: Option[String], to: Option[String],
transition: Option[Seq[String]], transition: Option[Seq[Seq[String]]],
time: Option[Int], time: Option[Int],
blocking: Option[Boolean]) blocking: Option[Boolean])
derives JsonEncoder derives JsonEncoder
final case class Dispatch(
event: String,
to: Option[String],
detail: Option[Map[String, String]],
bubbles: Option[Boolean],
blocking: Option[Boolean])
derives JsonEncoder
final case class Attr(attr: String, to: Option[String]) derives JsonEncoder
final case class To(to: Option[String]) derives JsonEncoder
final case class Hide(
to: Option[String],
transition: Option[Seq[Seq[String]]],
time: Option[Int],
blocking: Option[Boolean])
derives JsonEncoder
final case class SetAttribute(
arg: (String, String),
to: Option[String])
derives JsonEncoder
final case class Href(href: String, replace: Option[Boolean]) derives JsonEncoder
final case class Show(
to: Option[String],
transition: Option[Seq[Seq[String]]],
time: Option[Int],
blocking: Option[Boolean],
display: Option[String])
derives JsonEncoder
final case class Toggle(
to: Option[String],
in: Option[Seq[Seq[String]]],
out: Option[Seq[Seq[String]]],
time: Option[Int],
blocking: Option[Boolean],
display: Option[String])
derives JsonEncoder
final case class ToggleAttribute(arg: Seq[String], to: Option[String]) derives JsonEncoder
final case class Transition(
transition: Seq[Seq[String]],
to: Option[String],
time: Option[Int],
blocking: Option[Boolean])
derives JsonEncoder
end Args
end JSCommands end JSCommands