package binding
Ordering
- Alphabetic
Visibility
- Public
- Protected
Type Members
- macro class html extends Annotation with StaticAnnotation
An annotation to convert XHTML literals to data-bindable DOM nodes.
An annotation to convert XHTML literals to data-bindable DOM nodes.
Author:
杨博 (Yang Bo) <[email protected]>
- Annotations
- @compileTimeOnly("enable macro paradise to expand macro annotations")
XHTML literals with text attributes
@html val mySpan = <span class="my-class" tabindex="42"></span> mySpan.value.nodeName should be("SPAN") mySpan.value.className should be("my-class") mySpan.value.tabIndex should be(42)
Nested XHTML literals with interpolation:
@html val mySpan2 = <span style="color: red;" tabIndex={99999} title="my title" class={"my-class"}><span>text</span><i style={"color: blue;"} tabIndex={99}></i><span innerHTML={"html"}></span><span></span>{mySpan.bind}</span> mySpan2.watch() mySpan2.value.outerHTML should be("""<span style="color: red;" tabindex="99999" title="my title" class="my-class"><span>text</span><i style="color: blue;" tabindex="99"></i><span>html</span><span></span><span class="my-class" tabindex="42"></span></span>""")
, Special character in attribute names
@html val myMeta = <meta http-equiv="refresh" content="30"/> myMeta.watch() myMeta.value.outerHTML should be("""<meta http-equiv="refresh" content="30">""")
, Opaque type aliases of HTMLInputElement
@html val myMeta = <input name="myInput" type="radio"/> myMeta.watch() myMeta.value.outerHTML should be("""<input name="myInput" type="radio">""")
, Element list of XHTML literals
@html val mySpans = <span></span><span title={"my title"} class=""></span><span class="my-class"></span> mySpans.watch() import org.scalajs.dom.html.Span inside(mySpans.value) { case collection.Seq(span1: Span, span2: Span, span3: Span) => span1.nodeName should be("SPAN") span1.hasAttribute("class") should be(false) span1.className should be("") span2.title should be("my title") span2.hasAttribute("class") should be(true) span2.className should be("") span3.className should be("my-class") }
, Text interpolation in an element
@html val monadicSpan = <span>{"text"}</span> monadicSpan.watch() assert(monadicSpan.value.outerHTML == "<span>text</span>")
, Changing text
import com.thoughtworks.binding.Binding.Var val v0 = Var("original text") @html val monadicSpan = <span> <i> {v0.bind} </i> </span> monadicSpan.watch() assert(monadicSpan.value.outerHTML == "<span> <i> original text </i> </span>") v0.value = "changed" assert(monadicSpan.value.outerHTML == "<span> <i> changed </i> </span>")
, for
/yield
expressions in XHTML interpolationimport com.thoughtworks.binding.Binding.Vars val v0 = Vars("original text 0","original text 1") @html val monadicSpan = <span> <i> { for (s <- v0) yield <b>{s}</b> } </i> </span> monadicSpan.watch() val span = monadicSpan.value assert(monadicSpan.value.outerHTML == "<span> <i> <b>original text 0</b><b>original text 1</b> </i> </span>") v0.value.prepend("prepended") assert(span eq monadicSpan.value) assert(monadicSpan.value.outerHTML == "<span> <i> <b>prepended</b><b>original text 0</b><b>original text 1</b> </i> </span>") v0.value.remove(1) assert(span eq monadicSpan.value) assert(monadicSpan.value.outerHTML == "<span> <i> <b>prepended</b><b>original text 1</b> </i> </span>")
, for
/yield
/if
expressions in XHTML interpolationimport com.thoughtworks.binding.Binding import com.thoughtworks.binding.Binding.Var import com.thoughtworks.binding.Binding.Vars final case class User(firstName: Var[String], lastName: Var[String], age: Var[Int]) val filterPattern = Var("") val users = Vars( User(Var("Steve"), Var("Jobs"), Var(10)), User(Var("Tim"), Var("Cook"), Var(12)), User(Var("Jeff"), Var("Lauren"), Var(13)) ) def shouldShow(user: User): Binding[Boolean] = Binding { val pattern = filterPattern.bind if (pattern == "") { true } else if (user.firstName.bind.toLowerCase.contains(pattern)) { true } else if (user.lastName.bind.toLowerCase.contains(pattern)) { true } else { false } } @html def tbodyBinding = { <tbody>{ for { user <- users if shouldShow(user).bind } yield <tr><td>{user.firstName.bind}</td><td>{user.lastName.bind}</td><td>{user.age.bind.toString}</td></tr> }</tbody> } @html val tableBinding = { <table class="my-table" title="My Tooltip"><thead><tr><td>First Name</td><td>Second Name</td><td>Age</td></tr></thead>{tbodyBinding.bind}</table> } tableBinding.watch() assert(tableBinding.value.outerHTML == """<table class="my-table" title="My Tooltip"><thead><tr><td>First Name</td><td>Second Name</td><td>Age</td></tr></thead><tbody><tr><td>Steve</td><td>Jobs</td><td>10</td></tr><tr><td>Tim</td><td>Cook</td><td>12</td></tr><tr><td>Jeff</td><td>Lauren</td><td>13</td></tr></tbody></table>""") filterPattern.value = "o" assert(tableBinding.value.outerHTML == """<table class="my-table" title="My Tooltip"><thead><tr><td>First Name</td><td>Second Name</td><td>Age</td></tr></thead><tbody><tr><td>Steve</td><td>Jobs</td><td>10</td></tr><tr><td>Tim</td><td>Cook</td><td>12</td></tr></tbody></table>""")
, Dynamc attributes
@html val myBr = <br data:toString="+©" data:applyDynamic="value"/> myBr.watch() myBr.value.outerHTML should be("""<br tostring="+©" applydynamic="value">""")
, Changing attribute values
import com.thoughtworks.binding.Binding.Var val id = Var("oldId") @html val myInput = <input data:applyDynamic={id.bind} data:custom={id.bind} name={id.bind} id={id.bind} onclick={ _: Any => id.value = "newId" }/> myInput.watch() assert(myInput.value.outerHTML == """<input applydynamic="oldId" custom="oldId" name="oldId" id="oldId">""") myInput.value.onclick(null) assert(myInput.value.outerHTML == """<input applydynamic="newId" custom="newId" name="newId" id="newId">""")
, A child node must not be inserted more than once
an[IllegalStateException] should be thrownBy { @html val child = <hr/> @html val parent = <span><i>{child.bind}</i><i>{child.bind}</i></span> parent.watch() }
, Seq in DOM
import org.scalajs.dom.document @html def mySelect = { <select>{Seq(<option>data1</option>, <option>data2</option>)}</select> } val span = document.createElement("span") html.render(span, mySelect) span.firstChild.childNodes.length should be(2)
, XHTML comments
import org.scalajs.dom.document @html def comment = <span></span> val span = document.createElement("span") html.render(span, comment) assert(span.innerHTML == "<span></span>")
, Escape
import org.scalajs.dom.document @html def escaped = <span> $minus</span> val span = document.createElement("span") html.render(span, escaped) assert(span.innerHTML == "<span> $minus</span>")
, Entity references
import org.scalajs.dom.document @html def entity = <span class="< > © λ my-class">my text < > © λ</span> val span = document.createElement("span") html.render(span, entity) assert(span.innerHTML == """<span class="< > © λ my-class">my text < > © λ</span>""")
, Process instructions
@html val myXmlStylesheet = <?my-instruction my data?> myXmlStylesheet.watch() myXmlStylesheet.value.target should be("my-instruction") myXmlStylesheet.value.data should be("my data")
, CDATA sections are not supported in HTML documents
import scala.scalajs.js a[js.JavaScriptException] should be thrownBy { @html val myCData = <![CDATA[my data]]> myCData.watch() }
, XML namespaces
import scala.language.dynamics import org.scalajs.dom.document import org.scalajs.dom.raw._ import com.thoughtworks.binding.Binding import com.thoughtworks.binding.Binding.BindingInstances.monadSyntax._ object svg { object texts extends Dynamic { @inline def selectDynamic(data: String) = new html.NodeBinding.Constant.TextBuilder(data) } object elements { object svg extends Curried { @inline def applyBegin = new html.NodeBinding.Constant.ElementBuilder(document.createElementNS("http://www.w3.org/2000/svg", "svg").asInstanceOf[SVGSVGElement]) } object text extends Curried { @inline def applyBegin = new html.NodeBinding.Constant.ElementBuilder(document.createElementNS("http://www.w3.org/2000/svg", "text").asInstanceOf[SVGTextElement]) } } @inline def interpolation = Binding object values { sealed trait FontStyle case object normal extends FontStyle case object italic extends FontStyle case object oblique extends FontStyle } object attributes { def font$minusstyle(value: values.FontStyle) = { new html.NodeBinding.Constant.AttributeBuilder.Untyped(_.setAttribute("font-style", value.toString)) } def font$minusstyle(binding: Binding[values.FontStyle]) = { new html.NodeBinding.Interpolated.AttributeBuilder( element => binding.map { value => element.setAttribute("font-style", value.toString) } ) } } } implicit final class SvgUriOps(uriFactory: html.autoImports.xml.uris.type) { @inline def http$colon$div$divwww$u002Ew3$u002Eorg$div2000$divsvg = svg } @html val mySvg1 = <svg xmlns="http://www.w3.org/2000/svg"><text font-style="normal">my text</text></svg> mySvg1.watch() mySvg1.value.outerHTML should be("""<svg><text font-style="normal">my text</text></svg>""") import svg.values.normal @html val mySvg2 = <svg:svg xmlns:svg="http://www.w3.org/2000/svg"><svg:text font-style={normal}>my text</svg:text></svg:svg> mySvg2.watch() mySvg2.value.outerHTML should be("""<svg><text font-style="normal">my text</text></svg>""")
Examples: