Skip to content

Commit dee3fdd

Browse files
committed
Merge pull request #99 from aurelijusb/feature/touchEvents
Added Touch event attributes and example with Touch events
2 parents 3b06d64 + 8ea96c9 commit dee3fdd

File tree

4 files changed

+167
-1
lines changed

4 files changed

+167
-1
lines changed

core/src/main/scala/japgolly/scalajs/react/vdom/HtmlAttrs.scala

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,34 @@ trait HtmlAttrs {
189189
* MDN
190190
*/
191191
final val onMouseUp = "onMouseUp".attr
192+
/**
193+
* Event indicating that the touch point has been canceled or disrupted.
194+
*
195+
* For example, when popup menu is shown.
196+
*
197+
* @see [[japgolly.scalajs.react.ReactTouchEvent]]
198+
*/
199+
final val onTouchCancel = "onTouchCancel".attr
200+
/**
201+
* Event indicating that the touch point does not exist any more.
202+
*
203+
* For example, whn you release your finger.
204+
*
205+
* @see [[japgolly.scalajs.react.ReactTouchEvent]]
206+
*/
207+
final val onTouchEnd = "onTouchEnd".attr
208+
/**
209+
* Event indicating that the touch point has moved along the plane.
210+
*
211+
* @see [[japgolly.scalajs.react.ReactTouchEvent]]
212+
*/
213+
final val onTouchMove = "onTouchMove".attr
214+
/**
215+
* Event indicating that the user has touched the plane.
216+
*
217+
* @see [[japgolly.scalajs.react.ReactTouchEvent]]
218+
*/
219+
final val onTouchStart = "onTouchStart".attr
192220
/**
193221
* The select event only fires when text inside a text input or textarea is
194222
* selected. The event is fired after the text has been selected.

doc/CHANGELOG-0.8.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# 0.8.3 ([commit log](https://github.com/japgolly/scalajs-react/compare/v0.8.2...v0.8.3))
22

3+
* Added Touch event attributes:
4+
* `onTouchCancel`
5+
* `onTouchEnd`
6+
* `onTouchMove`
7+
* `onTouchStart`
8+
* Added example for Touch events. ([Live demo](http://japgolly.github.io/scalajs-react/))
39
* Added new styles:
410
* `alignSelf`
511
* `alignContent`
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package ghpages.examples
2+
3+
import ghpages.examples.util.SingleSide
4+
import japgolly.scalajs.react._
5+
import japgolly.scalajs.react.vdom.prefix_<^._
6+
import org.scalajs.dom
7+
8+
/**
9+
* Example of using Touch events.
10+
*
11+
* TouchList is JavaScript collection, so it is converted to Scala IndexedSeq.
12+
* Showing only top 10 events, so mobile phone will not crash.
13+
* Preventing default events, so move and zoom events could also be tested
14+
*/
15+
object TouchExample {
16+
17+
def content = SingleSide.Content(source, TouchExampleApp())
18+
19+
val source =
20+
"""
21+
|// Recommended to test with real Touch screens or with Chrome "Emulate touch screen"
22+
|
23+
|/** Keeping history of events **/
24+
|case class State(log: List[String] = List()) {
25+
| def withEntry(name: String) = copy(log = name :: log)
26+
|
27+
| def limit(max: Int) = if (log.size > max) copy(log = log.init) else this
28+
|}
29+
|
30+
|/** Saving touch event details to state */
31+
|class Backend(val $: BackendScope[Unit, State]) {
32+
| def debugEvent(e: ReactTouchEvent): Unit = preventDefault(e) { state =>
33+
| state withEntry s"${e.nativeEvent.`type`}: ${formatTouches(e.changedTouches)}" limit 10
34+
| }
35+
|
36+
| private def preventDefault(e: ReactTouchEvent)(transformer: State => State): Unit = {
37+
| e.preventDefault()
38+
| $.modState(transformer)
39+
| }
40+
|
41+
| private def formatTouches(touches: dom.TouchList) =
42+
| toSeq(touches).map(formatCoordinates).mkString(" | ")
43+
|
44+
| private def toSeq[A](list: dom.DOMList[A]) =
45+
| for(i <- 0 to list.length - 1) yield list.item(i)
46+
|
47+
| private def formatCoordinates(touch: dom.Touch) =
48+
| s"${touch.screenX}x${touch.screenY}: ${touch.radiusX}x${touch.radiusY}"
49+
|}
50+
|
51+
|/** Rendering touch area and history of events */
52+
|val TouchExampleApp = ReactComponentB[Unit]("TouchExample")
53+
| .initialState(new State)
54+
| .backend(new Backend(_))
55+
| .render { (P, S, B) =>
56+
|
57+
| <.div(
58+
| <.div(
59+
| "Area to test touch events",
60+
| ^.width := 200, // Basic style
61+
| ^.height := 200,
62+
| ^.border := "1px solid blue",
63+
| ^.onTouchStart ==> B.debugEvent, // Forwarding touch events
64+
| ^.onTouchMove ==> B.debugEvent,
65+
| ^.onTouchEnd ==> B.debugEvent,
66+
| ^.onTouchCancel ==> B.debugEvent
67+
| ),
68+
| <.ul ( // Rendering history of events
69+
| S.log.map(
70+
| <.li(_)
71+
| )
72+
| )
73+
| )
74+
|
75+
|}.buildU
76+
|""".stripMargin
77+
78+
/** Keeping history of events **/
79+
case class State(log: List[String] = List()) {
80+
def withEntry(name: String) = copy(log = name :: log)
81+
82+
def limit(max: Int) = if (log.size > max) copy(log = log.init) else this
83+
}
84+
85+
/** Saving touch event details to state */
86+
class Backend(val $: BackendScope[Unit, State]) {
87+
def debugEvent(e: ReactTouchEvent): Unit = preventDefault(e) { state =>
88+
state withEntry s"${e.nativeEvent.`type`}: ${formatTouches(e.changedTouches)}" limit 10
89+
}
90+
91+
private def preventDefault(e: ReactTouchEvent)(transformer: State => State): Unit = {
92+
e.preventDefault()
93+
$.modState(transformer)
94+
}
95+
96+
private def formatTouches(touches: dom.TouchList) =
97+
toSeq(touches).map(formatCoordinates).mkString(" | ")
98+
99+
private def toSeq[A](list: dom.DOMList[A]) =
100+
for(i <- 0 to list.length - 1) yield list.item(i)
101+
102+
private def formatCoordinates(touch: dom.Touch) =
103+
s"${touch.screenX}x${touch.screenY}: ${touch.radiusX}x${touch.radiusY}"
104+
}
105+
106+
/** Rendering touch area and history of events */
107+
val TouchExampleApp = ReactComponentB[Unit]("TouchExample")
108+
.initialState(new State)
109+
.backend(new Backend(_))
110+
.render { (P, S, B) =>
111+
112+
<.div(
113+
<.div(
114+
"Area to test touch events",
115+
^.width := 200, // Basic style
116+
^.height := 200,
117+
^.border := "1px solid blue",
118+
^.onTouchStart ==> B.debugEvent, // Forwarding touch events
119+
^.onTouchMove ==> B.debugEvent,
120+
^.onTouchEnd ==> B.debugEvent,
121+
^.onTouchCancel ==> B.debugEvent
122+
),
123+
<.ul ( // Rendering history of events
124+
S.log.map(
125+
<.li(_)
126+
)
127+
)
128+
)
129+
130+
}.buildU
131+
}

gh-pages/src/main/scala/ghpages/pages/ExamplesPage.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ object Example {
1717
case object Animation extends Example("Animation", AnimationExample.content)
1818
case object PictureApp extends Example("AjaxPictureApp", PictureAppExample.content)
1919
case object Scalaz extends Example("Todo List (Scalaz)", ScalazExample.content)
20+
case object Touch extends Example("Touch events", TouchExample.content)
2021
case object ExternalVar extends Example("ExternalVar", ExternalVarExample.content)
2122

22-
val values = Vector[Example](Hello, Timer, Todo, Scalaz, Refs, ExternalVar, ProductTable, Animation, PictureApp)
23+
val values = Vector[Example](Hello, Timer, Todo, Scalaz, Touch, Refs, ExternalVar, ProductTable, Animation, PictureApp)
2324
}
2425

2526
object ExamplesPage {

0 commit comments

Comments
 (0)