From 4d43a34e4ab09f350906d7f6459a33cecf2bdb8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Pit-Claudel?= <clement.pit-claudel@epfl.ch> Date: Sun, 8 Dec 2024 01:18:08 +0100 Subject: [PATCH] client: Clean up TextClientAppInstance implementation --- .../graphics/TextClientAppInstance.scala | 96 +++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/js/src/main/scala/cs214/webapp/client/graphics/TextClientAppInstance.scala b/js/src/main/scala/cs214/webapp/client/graphics/TextClientAppInstance.scala index 9511474..95b889c 100644 --- a/js/src/main/scala/cs214/webapp/client/graphics/TextClientAppInstance.scala +++ b/js/src/main/scala/cs214/webapp/client/graphics/TextClientAppInstance.scala @@ -48,7 +48,33 @@ case class TextSegment( cssProperties: CSSProperties = Map(), htmlAttributes: Map[HTMLAttribute, String] = Map(), modifiers: Modifier* -) +): + def toFrag: Frag = + val css = cssProperties.toCSS() + span( + text, + conditionalModifier(HTMLAttribute.style, style, if css.isEmpty then None else Some(css)), + conditionalModifier(HTMLAttribute.cls, cls, None), + modifiers, + bindMouseEvents(onMouseEvent) + ) + + private def bindMouseEvents[T](handler: Option[MouseEvent => Unit]): Modifier = + handler match + case None => frag() + case Some(fn) => Seq( + onclick := { (e: dom.MouseEvent) => fn(MouseEvent.Click(MouseButton.from(e.button))) }, + onmousedown := { (e: dom.MouseEvent) => fn(MouseEvent.MouseDown(MouseButton.from(e.button))) }, + onmouseup := { (e: dom.MouseEvent) => fn(MouseEvent.MouseUp(MouseButton.from(e.button))) }, + onmouseover := { (e: dom.MouseEvent) => fn(MouseEvent.HoverEnter) }, + onmouseout := { (e: dom.MouseEvent) => fn(MouseEvent.HoverLeave) } + ) + + private def conditionalModifier(attr: HTMLAttribute, target: Attr, default: => Option[String] = None): Modifier = + htmlAttributes.get(attr).orElse(default) match + case None => frag() + case Some(v) => target := v + /** Text-based UI. Detects mouse events and has an integrated text field. */ abstract class TextClientAppInstance[Event, View]( @@ -87,38 +113,7 @@ abstract class TextClientAppInstance[Event, View]( cls := "textapp", div( cls := "console", - pre( - style := "white-space: pre-wrap;", - for textSegment <- renderView(userId, view) - yield span( - textSegment.text, - style := textSegment.htmlAttributes.getOrElse(HTMLAttribute.style, textSegment.cssProperties.toCSS()), - cls := textSegment.htmlAttributes.getOrElse(HTMLAttribute.cls, ""), - textSegment.modifiers, - margin := "0", - height := "1em", - onclick := { - (e: dom.MouseEvent) => - if textSegment.onMouseEvent.isDefined then - textSegment.onMouseEvent.get(MouseEvent.Click(MouseButton.from(e.button))) - }, - onmousedown := { - (e: dom.MouseEvent) => - if textSegment.onMouseEvent.isDefined then - textSegment.onMouseEvent.get(MouseEvent.MouseDown(MouseButton.from(e.button))) - }, - onmouseup := { (e: dom.MouseEvent) => - if textSegment.onMouseEvent.isDefined then - textSegment.onMouseEvent.get(MouseEvent.MouseUp(MouseButton.from(e.button))) - }, - onmouseover := { (_: dom.MouseEvent) => - if textSegment.onMouseEvent.isDefined then - textSegment.onMouseEvent.get(MouseEvent.HoverEnter) }, - onmouseout := { (_: dom.MouseEvent) => - if textSegment.onMouseEvent.isDefined then - textSegment.onMouseEvent.get(MouseEvent.HoverLeave) } - ) - ) + pre(renderView(userId, view).map(_.toFrag)) ), input( `type` := "text", @@ -160,19 +155,24 @@ abstract class TextClientAppInstance[Event, View]( | border: solid 1px black; | box-sizing: border-box; | } - | - | .textapp .console { - | overflow: hidden; - | padding: 0.5em; - | font-size: 1em; - | display: flex; - | flex-direction: column; - | justify-content: center; - | align-items: start; - | border: solid 1px black; - | } - | - | .textapp .console span { - | box-sizing: border-box; - | } + | + | .textapp .console { + | overflow: hidden; + | padding: 0.5em; + | font-size: 1em; + | display: flex; + | flex-direction: column; + | justify-content: center; + | align-items: start; + | border: solid 1px black; + | } + | + | .textapp .console pre { + | white-space: pre-wrap; + | margin: 0; + | } + | + | .textapp .console span { + | box-sizing: border-box; + | } """.stripMargin -- GitLab