@@ -9,30 +9,28 @@ import scala.scalajs.js.UndefOr
9
9
object KeyboardPolyfill {
10
10
11
11
/**
12
- * Primarily it allows you to abandon onpress events that have cross-browser incompatible behavior and
13
- * that are to be deprecated in favor of beforeinput events in W3C DOM4. Calling polyfill method on keydown/keyup event
14
- * gives you normalized keyCode across platforms and browsers and estimated charCode in case of a key representing
15
- * printable character. pfKeyCode & optional pfCharCode properties are added to Event object for possible latter use
16
- */
12
+ * Primarily it allows you to abandon onpress events that have cross-browser incompatible behavior and
13
+ * that are to be deprecated in favor of beforeinput events in W3C DOM4. Calling polyfill method on keydown/keyup event
14
+ * gives you normalized keyCode across platforms and browsers and estimated charCode in case of a key representing
15
+ * printable character. pfKeyCode & optional pfCharCode properties are added to Event object for possible latter use
16
+ */
17
17
implicit class PfEvent (e : KeyboardEvent ) {
18
- import KCode ._
19
- import ChCode ._
20
18
21
19
/** to retrieve polyfilled code later */
22
20
def pfKeyCode : Option [Int ] = getDynamic(" pfKeyCode" )
23
21
def pfCharCode : Option [Int ] = getDynamic(" pfCharCode" )
24
22
25
23
/**
26
- * Basically attempts to unite keyCodes across variety of platforms and browsers and
27
- * find a corresponding charCode in case of a printable unicode point
28
- * @return (keyCode, Option[charCode])
29
- */
24
+ * Basically attempts to unite keyCodes across variety of platforms and browsers and
25
+ * find a corresponding charCode in case of a printable unicode point
26
+ * @return (keyCode, Option[charCode])
27
+ */
30
28
def polyfill (): (Int , Option [Int ]) = {
31
29
require(e.`type` != " keypress" , " This polyfill only works with keydown/keyup events" )
32
30
val keyCode = normalize(e.keyCode)
33
- val result = shiftableKey2Char.lift(keyCode) match {
31
+ val result = ChCode . shiftableKey2Char.lift(keyCode) match {
34
32
case Some (shift) => (keyCode, Option (shift(e.shiftKey)))
35
- case None => (keyCode, key2char.lift(keyCode))
33
+ case None => (keyCode, ChCode . key2char.lift(keyCode))
36
34
}
37
35
pfKeyCode(keyCode)
38
36
result._2.foreach(pfCharCode(_))
@@ -46,63 +44,92 @@ object KeyboardPolyfill {
46
44
private def pfCharCode (charCode : Int ) = setDynamic(" pfCharCode" , charCode)
47
45
48
46
/**
49
- * To be improved continuously, most of the other stuff concerns Mac atypical keyboard layout and ancient browsers
50
- * You're welcome to contribute
51
- */
47
+ * To be improved continuously, most of the other stuff concerns Mac atypical keyboard layout and ancient browsers
48
+ * You're welcome to contribute
49
+ */
52
50
private def normalize (keyCode : Int ): Int = {
53
51
if (Device .isGecko)
54
52
keyCode match {
55
- case 173 => Dash
56
- case 59 => Semicolon
57
- case 61 => Equals
58
- case 0 => Win
53
+ case 173 => KCode . Dash
54
+ case 59 => KCode . Semicolon
55
+ case 61 => KCode . Equals
56
+ case 0 => KCode . Win
59
57
case other => keyCode
60
58
}
61
59
else if (Device .isMac)
62
60
keyCode match {
63
- case 224 => Meta
64
- case 12 => NumLock
61
+ case 224 => KCode . Meta
62
+ case 12 => KCode . NumLock
65
63
case other => keyCode
66
64
}
67
65
else
68
66
keyCode
69
67
}
70
68
}
69
+
70
+ object Device {
71
+ val IOSRegex = " iPhone|iPod|iPad" .r
72
+
73
+ val userAgent = dom.window.navigator.userAgent
74
+ val platform = dom.window.navigator.platform
75
+
76
+ val isIOS = IOSRegex .findFirstIn(userAgent).isDefined
77
+ val isIPad = userAgent.contains(" iPad" )
78
+ val isIPod = userAgent.contains(" iPod" )
79
+ val isIPhone = userAgent.contains(" iPhone" )
80
+ val isAndroid = userAgent.contains(" Android" )
81
+
82
+ val isGecko = userAgent.contains(" Gecko/" )
83
+ val isWebKit = userAgent.contains(" WebKit/" )
84
+ val isIE = userAgent.contains(" Trident/" )
85
+ val isOpera = userAgent.contains(" Opera/" )
86
+ val isChrome = userAgent.contains(" Chrome/" )
87
+
88
+ val isLinux = platform.contains(" Linux" )
89
+ val isWin = platform.contains(" Win" )
90
+ val isMac = platform.contains(" Mac" )
91
+ val isChrOS = platform.contains(" CrOS" )
92
+
93
+ val isTouchable = isIOS || isAndroid
94
+ }
71
95
}
72
96
97
+ /**
98
+ * @note ([0-9] * + - / .) are the only characters shared by 2 keys on keyboard, this duplication is caused by existence of numpad.
99
+ */
73
100
object ChCode {
74
101
import KCode ._
75
102
76
103
/** shift changes charCode */
77
104
private def > (w : Int , wo : Int )(shift : Boolean ) = if (shift) w else wo
78
105
/** add offset to a lower case letter which gives you it's char code */
79
- private def >> (keyCode : Int )(shift : Boolean ) = if (shift) keyCode else keyCode + charSizeOffset
106
+ private def >> (keyCode : Int )(shift : Boolean ) = if (shift) keyCode else letterKeyToLowerCaseCharCode( keyCode)
80
107
81
108
/** keys that have different charCode representation when shift key is pressed */
82
109
private val letterKey2Char = for (letterKeyCode <- A to Z ) yield (letterKeyCode, >> (letterKeyCode)_)
83
- private implicit def Char2Int (ch : Char ) = ch.toInt
110
+ private implicit def Char2Int (ch : Char ): Int = ch.toInt
84
111
val shiftableKey2Char = Map [Int , Boolean => Int ](
85
- (Num0 , > (')' , Num0 )),
86
- (Num1 , > ('!' , Num1 )),
87
- (Num2 , > ('@' , Num2 )),
88
- (Num3 , > ('#' , Num3 )),
89
- (Num4 , > ('$' , Num4 )),
90
- (Num5 , > ('%' , Num5 )),
91
- (Num6 , > ('^' , Num6 )),
92
- (Num7 , > ('&' , Num7 )),
93
- (Num8 , > ('*' , Num8 )),
94
- (Num9 , > ('(' , Num9 )),
95
- (Comma , > ('<' , ',' )),
96
- (Dash , > ('_' , '-' )),
97
- (Period , > ('>' , '.' )),
98
- (Slash , > ('?' , '/' )),
99
- (GraveAccent , > ('~' , '`' )),
100
- (SquareBracketOpen , > ('{' , '[' )),
101
- (Backslash , > ('|' , '\\ ' )),
102
- (SquareBracketClose , > ('}' , ']' )),
103
- (SingleQuote , > ('"' , ''' )),
104
- (Semicolon , > (':' , ';' )),
105
- (Equals , > ('+' , '=' ))
112
+ (Num0 , > (')' , Num0 )),
113
+ (Num1 , > ('!' , Num1 )),
114
+ (Num2 , > ('@' , Num2 )),
115
+ (Num3 , > ('#' , Num3 )),
116
+ (Num4 , > ('$' , Num4 )),
117
+ (Num5 , > ('%' , Num5 )),
118
+ (Num6 , > ('^' , Num6 )),
119
+ (Num7 , > ('&' , Num7 )),
120
+ (Num8 , > ('*' , Num8 )),
121
+ (Num9 , > ('(' , Num9 )),
122
+ (Comma , > ('<' , ',' )),
123
+ (Dash , > ('_' , '-' )),
124
+ (Period , > ('>' , '.' )),
125
+ (Slash , > ('?' , '/' )),
126
+ (Backtick , > ('~' , '`' )),
127
+ (SquareBracketOpen , > ('{' , '[' )),
128
+ (Backslash , > ('|' , '\\ ' )),
129
+ (SquareBracketClose , > ('}' , ']' )),
130
+ (SingleQuote , > ('"' , ''' )),
131
+ (Semicolon , > (':' , ';' )),
132
+ (Equals , > ('+' , '=' ))
106
133
) ++ letterKey2Char
107
134
108
135
val key2char = Map [Int , Int ](
@@ -144,8 +171,10 @@ object KCode {
144
171
/** [A-Z] charCode is equal to [a-z] keyCode, thus I won't duplicate constants */
145
172
val charSizeOffset = 'a' .toInt - 'A' .toInt
146
173
147
- def isLetter (keyCode : Int ) = keyCode >= A && keyCode <= Z
148
- def isUpperCaseLetter (charCode : Int ) = isLetter(charCode)
174
+ def isLetterKey (keyCode : Int ) = keyCode >= A && keyCode <= Z
175
+ def isUpperCaseLetter (charCode : Int ) = isLetterKey(charCode)
176
+ def letterKeyToLowerCaseCharCode (keyCode : Int ) = keyCode + charSizeOffset
177
+ def letterKeyToUpperCaseCharCode (keyCode : Int ) = keyCode // informative method
149
178
150
179
/** Upper case letters have CharCode equal to KeyCode */
151
180
val A = 'A' .toInt // 65
@@ -175,22 +204,22 @@ object KCode {
175
204
val Y = 'Y' .toInt // 89
176
205
val Z = 'Z' .toInt // 90
177
206
178
- /** Space & Enter have KeyCode equal to CharCode */
179
- val Space = ' ' .toInt // 32 both charCode and keyCode
180
- val Enter = 13 // kind of
181
-
182
207
val Comma = 188
183
208
val Dash = 189
184
209
val Period = 190
185
210
val Slash = 191
186
- val GraveAccent = 192
211
+ val Backtick = 192
187
212
val SquareBracketOpen = 219
188
213
val Backslash = 220
189
214
val SquareBracketClose = 221
190
215
val SingleQuote = 222
191
216
val Semicolon = 186
192
217
val Equals = 187
193
218
219
+ /** Space & Enter have KeyCode equal to CharCode */
220
+ val Space = 32 // both charCode and keyCode
221
+ val Enter = 13 // both charCode and keyCode
222
+
194
223
/** Numpad numbers share common numbers charCode */
195
224
val Numpad0 = (96 , Num0 )
196
225
val Numpad1 = (97 , Num1 )
@@ -242,30 +271,4 @@ object KCode {
242
271
val F11 = 122
243
272
val F12 = 123
244
273
val NumLock = 144
245
- }
246
-
247
- object Device {
248
- val IOSRegex = " iPhone|iPod|iPad" .r
249
-
250
- val userAgent = dom.window.navigator.userAgent
251
- val platform = dom.window.navigator.platform
252
-
253
- val isIOS = IOSRegex .findFirstIn(userAgent).isDefined
254
- val isIPad = userAgent.contains(" iPad" )
255
- val isIPod = userAgent.contains(" iPod" )
256
- val isIPhone = userAgent.contains(" iPhone" )
257
- val isAndroid = userAgent.contains(" Android" )
258
-
259
- val isGecko = userAgent.contains(" Gecko/" )
260
- val isWebKit = userAgent.contains(" WebKit/" )
261
- val isIE = userAgent.contains(" Trident/" )
262
- val isOpera = userAgent.contains(" Opera/" )
263
- val isChrome = userAgent.contains(" Chrome/" )
264
-
265
- val isLinux = platform.contains(" Linux" )
266
- val isWin = platform.contains(" Win" )
267
- val isMac = platform.contains(" Mac" )
268
- val isChrOS = platform.contains(" CrOS" )
269
-
270
- val isTouchable = isIOS || isAndroid
271
274
}
0 commit comments