mirror of
https://github.com/hodgef/simple-keyboard.git
synced 2026-02-15 00:07:43 +08:00
Compare commits
478 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc47a8eeb7 | ||
|
|
feda87fca6 | ||
|
|
7126b449a8 | ||
|
|
b7ab48e082 | ||
|
|
1bb4dcc21a | ||
|
|
2e27aabe12 | ||
|
|
fd0c48390d | ||
|
|
44cdc2bbb0 | ||
|
|
07743c9ff8 | ||
|
|
e0ca526419 | ||
|
|
b7444baac3 | ||
|
|
139689cfa2 | ||
|
|
71b49a51e3 | ||
|
|
a211bc6d82 | ||
|
|
60aab8855f | ||
|
|
c77d6a1a7b | ||
|
|
b067b31574 | ||
|
|
f004dda2ef | ||
|
|
378f7e17a0 | ||
|
|
9499cd064e | ||
|
|
76a02f38a2 | ||
|
|
ef52bf7f2c | ||
|
|
ba0cb06f34 | ||
|
|
8c11512685 | ||
|
|
51df61bef8 | ||
|
|
4401f58005 | ||
|
|
0ac5078c80 | ||
|
|
67b7e31c35 | ||
|
|
62e11937ae | ||
|
|
b635d3bb96 | ||
|
|
b6cb8e3cbc | ||
|
|
dc474da2f9 | ||
|
|
736cc305a7 | ||
|
|
b067b7ef5e | ||
|
|
7cdb93d8d0 | ||
|
|
97f93c5773 | ||
|
|
a59328032c | ||
|
|
ced6f5076e | ||
|
|
d333d6df08 | ||
|
|
e52ede70fc | ||
|
|
8fb95ddcec | ||
|
|
acf0dbf06a | ||
|
|
08c6799568 | ||
|
|
52ab1b59b2 | ||
|
|
677433dc36 | ||
|
|
1f2bd1207c | ||
|
|
7f1514e2c5 | ||
|
|
b6b2478d3b | ||
|
|
6f0b300db0 | ||
|
|
55781a274f | ||
|
|
58ab648024 | ||
|
|
9af2222f41 | ||
|
|
e6c115f668 | ||
|
|
1dd847b802 | ||
|
|
530c43d8ed | ||
|
|
e2217e334e | ||
|
|
c2d8923140 | ||
|
|
4245dad14b | ||
|
|
468d7c39fd | ||
|
|
ee024b6e7e | ||
|
|
eaa35e3308 | ||
|
|
50cf115a5b | ||
|
|
144f2c1616 | ||
|
|
a5564f8d85 | ||
|
|
b0e9f58ff5 | ||
|
|
cc2d0b5722 | ||
|
|
e8595a3af9 | ||
|
|
db41d13302 | ||
|
|
8bd36b5b83 | ||
|
|
0de210d388 | ||
|
|
76ae4f86ee | ||
|
|
a0649070cb | ||
|
|
7aecbaab2f | ||
|
|
7006a94cfb | ||
|
|
6cf2061ea2 | ||
|
|
180e1d0553 | ||
|
|
153d17f78b | ||
|
|
d4ba63a9f5 | ||
|
|
a4be18f56e | ||
|
|
266fa42b1c | ||
|
|
01c0cea9f0 | ||
|
|
3191755c59 | ||
|
|
614becbf16 | ||
|
|
cc34a261fa | ||
|
|
5079fd5c39 | ||
|
|
261112aa01 | ||
|
|
5930f96150 | ||
|
|
af19eff60d | ||
|
|
56dbd1be93 | ||
|
|
8849e16996 | ||
|
|
558bdef7ac | ||
|
|
5029fa8f8d | ||
|
|
3cbfa033e3 | ||
|
|
0b9809385d | ||
|
|
74fc580c8d | ||
|
|
1f335f6b62 | ||
|
|
975978025d | ||
|
|
bbc2243ddf | ||
|
|
db5f9b2f5c | ||
|
|
2eaecf4aa1 | ||
|
|
fb08bb1bb3 | ||
|
|
e4fd5ce290 | ||
|
|
8f9706b25d | ||
|
|
608f08ff9d | ||
|
|
a56163535f | ||
|
|
bebd974cd6 | ||
|
|
9932c6ca4c | ||
|
|
51b38e83d7 | ||
|
|
260ca83921 | ||
|
|
17da101d18 | ||
|
|
022e76f688 | ||
|
|
e4e24d5c17 | ||
|
|
d99b1e79ab | ||
|
|
0689e57aa6 | ||
|
|
a2ec44033b | ||
|
|
7ce72414e4 | ||
|
|
50c40f1d35 | ||
|
|
3c916e08a4 | ||
|
|
73b8094625 | ||
|
|
89df887f9c | ||
|
|
251f395bad | ||
|
|
2a31f1dbaa | ||
|
|
2053118c56 | ||
|
|
9ad5218087 | ||
|
|
d99f72c6fa | ||
|
|
0acb02c6e6 | ||
|
|
b51ae715f4 | ||
|
|
bcd266af3f | ||
|
|
634f27f356 | ||
|
|
7a57f434ee | ||
|
|
96d354a33d | ||
|
|
0f719b3b00 | ||
|
|
6a63d0994c | ||
|
|
0e7b8585a5 | ||
|
|
c4a985b74f | ||
|
|
5b366e04d9 | ||
|
|
c711f4db80 | ||
|
|
477e4289c1 | ||
|
|
bccedcf5e2 | ||
|
|
c520ca9b9f | ||
|
|
38d8e3f162 | ||
|
|
74f7b1e8e3 | ||
|
|
dd1f1670da | ||
|
|
c996af2969 | ||
|
|
f7770f5a1b | ||
|
|
99444615ae | ||
|
|
78995e7796 | ||
|
|
df7d88d9fa | ||
|
|
e9c245326c | ||
|
|
5d4902930e | ||
|
|
358c38299b | ||
|
|
8d7d0c1a08 | ||
|
|
f384d92c6e | ||
|
|
5340e3dfaf | ||
|
|
db3b70d83e | ||
|
|
a81daa5ce5 | ||
|
|
bfac6634c3 | ||
|
|
c25a2a634e | ||
|
|
c3d04c3ac8 | ||
|
|
5e7f5aa67f | ||
|
|
f1c1093670 | ||
|
|
cbacb28c29 | ||
|
|
7636ca2399 | ||
|
|
65452a9a0a | ||
|
|
1d8c67ff1a | ||
|
|
894160e1ad | ||
|
|
3dbfd7be18 | ||
|
|
f9f31e3dd2 | ||
|
|
5ddff23b17 | ||
|
|
cba8d77fe6 | ||
|
|
1a1a0c9ff2 | ||
|
|
c4687fe62d | ||
|
|
dfe42f5c11 | ||
|
|
8eea72b52f | ||
|
|
bdde4a90b5 | ||
|
|
3d765289e7 | ||
|
|
c433d269cd | ||
|
|
9a63cdf04b | ||
|
|
bd0c4531a2 | ||
|
|
8d038dc517 | ||
|
|
2487cf48ed | ||
|
|
9fb9d6f3fc | ||
|
|
b4f0663e49 | ||
|
|
a577076763 | ||
|
|
e2ac695400 | ||
|
|
28112c2756 | ||
|
|
90c73648d8 | ||
|
|
e8c05f3a68 | ||
|
|
96ce90a3ac | ||
|
|
ed05ad6e0b | ||
|
|
c145641068 | ||
|
|
319c28b496 | ||
|
|
8b2b4f68de | ||
|
|
b5e7bb6d74 | ||
|
|
63bc3863c1 | ||
|
|
549aac69da | ||
|
|
1c8b3d94c8 | ||
|
|
3965464b2f | ||
|
|
7dd1ef594c | ||
|
|
4799397995 | ||
|
|
aea63fe8d2 | ||
|
|
49fb4a079d | ||
|
|
51138b43c4 | ||
|
|
fe4fa84b16 | ||
|
|
9b1dd52cc1 | ||
|
|
00d95f449e | ||
|
|
f76ab1a380 | ||
|
|
b581c5fbcd | ||
|
|
1810b66ca0 | ||
|
|
eda3f09a0f | ||
|
|
3a82ac7ce8 | ||
|
|
366bf241d2 | ||
|
|
90c54d4aa1 | ||
|
|
8c0b3e9f9d | ||
|
|
2adb80ea94 | ||
|
|
61b78dc2b6 | ||
|
|
c89832684b | ||
|
|
52b203a5c8 | ||
|
|
44df9cf358 | ||
|
|
863b02cbf7 | ||
|
|
05428a99ba | ||
|
|
8e2efcb6e9 | ||
|
|
9976091711 | ||
|
|
06220a66f8 | ||
|
|
55cceb4962 | ||
|
|
bb9458b053 | ||
|
|
5b18622c74 | ||
|
|
1bd50e2f4e | ||
|
|
7b96d7b0b4 | ||
|
|
121751f67b | ||
|
|
42567dd657 | ||
|
|
2fcc8af287 | ||
|
|
4366a666fe | ||
|
|
9f82f57825 | ||
|
|
c501e869d9 | ||
|
|
d53764729c | ||
|
|
cfef7b2448 | ||
|
|
691aec6c9a | ||
|
|
f8d9cc8f41 | ||
|
|
f1fb0bf458 | ||
|
|
942b3724d2 | ||
|
|
53b5f065d9 | ||
|
|
db5bab1d31 | ||
|
|
bb112d9864 | ||
|
|
5bf8f94982 | ||
|
|
476bf18676 | ||
|
|
98b4005c46 | ||
|
|
75222ee169 | ||
|
|
da7c84384b | ||
|
|
38847a2678 | ||
|
|
ff3479839c | ||
|
|
3282c5c2e6 | ||
|
|
30249f24f4 | ||
|
|
15d9d25012 | ||
|
|
bdd11b6f22 | ||
|
|
4ef0c9f4aa | ||
|
|
707f867488 | ||
|
|
6db66bbca5 | ||
|
|
3801aea892 | ||
|
|
672795bdb3 | ||
|
|
b6e2c22cbf | ||
|
|
71f27c4456 | ||
|
|
6c5c9cc17d | ||
|
|
b607537a77 | ||
|
|
810954e52e | ||
|
|
21088838a1 | ||
|
|
a0dd519aea | ||
|
|
2b58dfbf40 | ||
|
|
30a797dacc | ||
|
|
6d3a7d460a | ||
|
|
fe1792f443 | ||
|
|
ad1101c8c7 | ||
|
|
2f7aeaf797 | ||
|
|
501629585b | ||
|
|
1fa9a7c48e | ||
|
|
d5f360b3f0 | ||
|
|
8f8dceb392 | ||
|
|
7c4d227dff | ||
|
|
afcdae4b26 | ||
|
|
12f94ece63 | ||
|
|
25fb5e484c | ||
|
|
3aa23ce5c4 | ||
|
|
23e1a6bb73 | ||
|
|
39eef35a33 | ||
|
|
4efb79abc3 | ||
|
|
4cd95a4f4a | ||
|
|
7a949451e2 | ||
|
|
d4781e7300 | ||
|
|
5de872c930 | ||
|
|
0cecebc304 | ||
|
|
aae27fb0d5 | ||
|
|
c0c600355c | ||
|
|
9f3440f353 | ||
|
|
cc4bd44e3d | ||
|
|
e4de7ea18a | ||
|
|
b90239459e | ||
|
|
ccb1d36741 | ||
|
|
4a2a28f2c0 | ||
|
|
684ba0d2f0 | ||
|
|
5d36527894 | ||
|
|
490845a858 | ||
|
|
b165e24706 | ||
|
|
ada8f74f42 | ||
|
|
e551e0bb96 | ||
|
|
3feeb75762 | ||
|
|
b2bd7df592 | ||
|
|
0b6d327291 | ||
|
|
8161e5e397 | ||
|
|
2ed8d32d4b | ||
|
|
316f3fb160 | ||
|
|
2131ee8673 | ||
|
|
f31a509b21 | ||
|
|
bfb7cf296a | ||
|
|
4429af5a3b | ||
|
|
622afe3b1a | ||
|
|
9b60cb7ce4 | ||
|
|
cb6de59608 | ||
|
|
bc75dc601a | ||
|
|
6fe50bda12 | ||
|
|
dc618bbcbd | ||
|
|
788b064a36 | ||
|
|
c0bc286f58 | ||
|
|
daf222a950 | ||
|
|
1e1dfc9d89 | ||
|
|
9b09cfcfa6 | ||
|
|
3285421ee9 | ||
|
|
c22d99bbbc | ||
|
|
1c46adb9a0 | ||
|
|
5b2c66d07b | ||
|
|
36a3a141b1 | ||
|
|
83b41e0a4b | ||
|
|
10f64bccc9 | ||
|
|
b00c0bacad | ||
|
|
536b50a80c | ||
|
|
10d17ec93e | ||
|
|
c14804d30e | ||
|
|
12a2ee5ce5 | ||
|
|
6036246427 | ||
|
|
49167ff39d | ||
|
|
dd166f0e78 | ||
|
|
970bef4b2f | ||
|
|
2c8d5f4697 | ||
|
|
0f7c1bf932 | ||
|
|
b7c6f7dca3 | ||
|
|
e4be0c70ea | ||
|
|
42f13ea0c9 | ||
|
|
3ccd7e766b | ||
|
|
06ec0fdeb2 | ||
|
|
ae5f194902 | ||
|
|
48386c6469 | ||
|
|
e1c3c93917 | ||
|
|
2376a14e61 | ||
|
|
68fc9f1df4 | ||
|
|
8b5ac625ba | ||
|
|
e62d8940e1 | ||
|
|
26bb9bc212 | ||
|
|
0b64cb65da | ||
|
|
717943ef53 | ||
|
|
a6afaec93c | ||
|
|
4f7ffce9a4 | ||
|
|
a83dc6d098 | ||
|
|
c306249b16 | ||
|
|
1dcd7bb384 | ||
|
|
f85f38594d | ||
|
|
b4b394a0cc | ||
|
|
051e79879a | ||
|
|
2a920ad56c | ||
|
|
d21ff3ce81 | ||
|
|
b4d59e3bd3 | ||
|
|
40b70393d4 | ||
|
|
ab0c958d0b | ||
|
|
42c78bf64f | ||
|
|
6b02d30170 | ||
|
|
5e18bf1801 | ||
|
|
4e453bb3d5 | ||
|
|
d1c0f361fa | ||
|
|
793566ed4d | ||
|
|
97d0787ff2 | ||
|
|
6650b8469f | ||
|
|
b14d5ef6de | ||
|
|
f8a33420c5 | ||
|
|
9cbc8cc4d5 | ||
|
|
8034c66038 | ||
|
|
ddcf79c14b | ||
|
|
16498ad3c3 | ||
|
|
9942016484 | ||
|
|
fa666ad1a9 | ||
|
|
12b46646f8 | ||
|
|
3b24af2368 | ||
|
|
4df55d33c1 | ||
|
|
4b5ee39eb3 | ||
|
|
b42b8bd907 | ||
|
|
4bc530fa27 | ||
|
|
f33e3498a1 | ||
|
|
25dc7b620a | ||
|
|
2394510f92 | ||
|
|
eb0411d057 | ||
|
|
2c13e41f63 | ||
|
|
7097c39610 | ||
|
|
54d384f7fb | ||
|
|
c68a72120f | ||
|
|
63a2aa0ab5 | ||
|
|
7f3797cba2 | ||
|
|
6692ba79c4 | ||
|
|
33b78a58ef | ||
|
|
e0d1c67518 | ||
|
|
426ee38eb4 | ||
|
|
e6fcd1aa44 | ||
|
|
18e474b741 | ||
|
|
d7ab569074 | ||
|
|
20dc331ce2 | ||
|
|
a885bb89d9 | ||
|
|
7878c33674 | ||
|
|
8e5cd43928 | ||
|
|
4b3b967826 | ||
|
|
d53271979a | ||
|
|
94397ba07f | ||
|
|
5e700f1528 | ||
|
|
b9a4e6ad33 | ||
|
|
6c0257f8e8 | ||
|
|
001a3d3fcf | ||
|
|
293b3ec120 | ||
|
|
58db95a307 | ||
|
|
d5bf72dc1a | ||
|
|
53bef2143e | ||
|
|
3631a09b30 | ||
|
|
ad9fd8ae40 | ||
|
|
3bffe67b36 | ||
|
|
ae3c6be8bf | ||
|
|
52ab2a4a86 | ||
|
|
a54d352aa9 | ||
|
|
9681bc5b57 | ||
|
|
bbb434b9aa | ||
|
|
2a38098283 | ||
|
|
b7bf209f68 | ||
|
|
3276f10b09 | ||
|
|
3df390a6a7 | ||
|
|
42e652481f | ||
|
|
7f9784ab4b | ||
|
|
29e2163de7 | ||
|
|
5eb2399ca2 | ||
|
|
42d7903fab | ||
|
|
3079afa824 | ||
|
|
13a41e75ae | ||
|
|
8337819b23 | ||
|
|
05de713725 | ||
|
|
1bfbef2260 | ||
|
|
0485cc6b5b | ||
|
|
bd517a4830 | ||
|
|
7db7717279 | ||
|
|
62963b3616 | ||
|
|
0df4f6a3f5 | ||
|
|
2adef5de94 | ||
|
|
2e34da71a5 | ||
|
|
2b935eb4ce | ||
|
|
8c52b2102e | ||
|
|
9672c8b2e1 | ||
|
|
1aa840729c | ||
|
|
fd241cb527 | ||
|
|
469d40695a | ||
|
|
5ae040935b | ||
|
|
6b09ce462e | ||
|
|
a2f9a4aef9 | ||
|
|
50e976d491 | ||
|
|
339bbfeaec | ||
|
|
66a8c1e3fa | ||
|
|
718afba327 | ||
|
|
7aa006b557 | ||
|
|
691f0b2f48 | ||
|
|
af6f001cc0 | ||
|
|
0dabeab1d3 | ||
|
|
de408eaaae | ||
|
|
fe3e165472 | ||
|
|
223dc74701 | ||
|
|
238896d6f4 | ||
|
|
ab38841447 | ||
|
|
5c50be4376 | ||
|
|
b44078327a |
@@ -29,6 +29,7 @@
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"jasmine": true,
|
||||
"jest": true
|
||||
"jest": true,
|
||||
"es6": true
|
||||
}
|
||||
}
|
||||
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
github: hodgef
|
||||
32
README.md
32
README.md
@@ -30,15 +30,15 @@
|
||||
|
||||
<blockquote>The slick virtual keyboard for Javascript. Compatible with your JS, React, Angular or Vue projects.</blockquote>
|
||||
|
||||
## 🚀 Demo
|
||||
## Demo 🚀
|
||||
[Demo Showcase (Vanilla, Angular, React, Vue)](https://simple-keyboard.com/demo)
|
||||
|
||||
## 📦 Installation & Usage
|
||||
## Installation & Usage 📦
|
||||
You can use simple-keyboard as a `<script>` tag from a CDN, or install it from npm.
|
||||
|
||||
Check out the [Getting Started](https://simple-keyboard.com/getting-started) docs to begin.
|
||||
|
||||
## 📖 Documentation
|
||||
## Documentation 📖
|
||||
Check out the [simple-keyboard documentation](https://simple-keyboard.com/documentation) site.
|
||||
|
||||
Feel free to browse the [Questions & Answers (FAQ)](https://simple-keyboard.com/qa-use-cases/) page for common use-cases.
|
||||
@@ -57,29 +57,29 @@ Feel free to browse the [Questions & Answers (FAQ)](https://simple-keyboard.com/
|
||||
* [Angular](https://simple-keyboard.com/demo)
|
||||
* [Vue.js](https://simple-keyboard.com/demo)
|
||||
|
||||
### Questions?
|
||||
### Questions? Join the chat
|
||||
|
||||
<a href="http://franciscohodge.com/simple-keyboard/chat/join" title="Join our Discord chat" target="_blank"><img src="https://franciscohodge.com/project-pages/simple-keyboard/images/discord.png" align="center" width="200"></a>
|
||||
<a href="https://discordapp.com/invite/SJexsCG" title="Join our Discord chat" target="_blank"><img src="https://discordapp.com/api/guilds/498978399801573396/widget.png?style=banner2" align="center"></a>
|
||||
|
||||
## ✳️ Modules
|
||||
## Modules ✳️
|
||||
|
||||
You can extend simple-keyboard's functionality with [modules](https://franciscohodge.com/projects/simple-keyboard/modules/). Such as:
|
||||
You can extend simple-keyboard's functionality with [modules](https://hodgef.com/simple-keyboard/modules/). Such as:
|
||||
|
||||
* [Autocorrect](https://franciscohodge.com/projects/simple-keyboard/demo-showcase/module-autocorrect/)
|
||||
* [Input Mask](https://franciscohodge.com/projects/simple-keyboard/demo-showcase/module-input-mask/)
|
||||
* [Key Navigation](https://franciscohodge.com/projects/simple-keyboard/demo-showcase/module-key-navigation/)
|
||||
* [Swipe Keyboard](https://franciscohodge.com/projects/simple-keyboard/demo-showcase/module-swipe-keyboard/)
|
||||
* [Autocorrect](https://hodgef.com/simple-keyboard/modules/autocorrect/)
|
||||
* [Input Mask](https://hodgef.com/simple-keyboard/modules/input-mask/)
|
||||
* [Key Navigation](https://hodgef.com/simple-keyboard/modules/key-navigation/)
|
||||
* [Swipe Keyboard](https://hodgef.com/simple-keyboard/modules/swipe-keyboard/)
|
||||
|
||||
Want to create your own module? Check out the [Modules page](https://franciscohodge.com/projects/simple-keyboard/modules/) for instructions.
|
||||
Want to create your own module? Check out the [Modules page](https://hodgef.com/simple-keyboard/modules/) for instructions.
|
||||
|
||||
## 🎯 Compatibility
|
||||
## Compatibility 🎯
|
||||
|
||||
> Simple-keyboard is intended for modern, standards-compliant browsers.
|
||||
> Internet Explorer is sadly not one of them, and since its market-share is negligible (~2% for IE11), resources won't be spent in trying to support it.
|
||||
>
|
||||
> To learn more about the rationale for not supporting IE, check out [this link](https://techcommunity.microsoft.com/t5/Windows-IT-Pro-Blog/The-perils-of-using-Internet-Explorer-as-your-default-browser/ba-p/331732).
|
||||
> For more information, check out [this Q&A entry](https://hodgef.com/simple-keyboard/questions-answers/internet-explorer-not-supported/).
|
||||
|
||||
## ✅ Contributing
|
||||
## Contributing ✅
|
||||
|
||||
PR's and issues are welcome. Feel free to submit any issues you have at:
|
||||
PRs and issues are always welcome. Feel free to submit any issues you have at:
|
||||
[https://github.com/hodgef/simple-keyboard/issues](https://github.com/hodgef/simple-keyboard/issues)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
*
|
||||
* simple-keyboard v2.29.1
|
||||
* simple-keyboard v2.30.1
|
||||
* https://github.com/hodgef/simple-keyboard
|
||||
*
|
||||
* Copyright (c) Francisco Hodge (https://github.com/hodgef)
|
||||
@@ -8,5 +8,5 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/.hg-theme-default{width:100%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;box-sizing:border-box;overflow:hidden;touch-action:manipulation}.hg-theme-default .hg-button span{pointer-events:none}.hg-theme-default button.hg-button{border-width:0;outline:0;font-size:inherit}.hg-theme-default{font-family:HelveticaNeue-Light,Helvetica Neue Light,Helvetica Neue,Helvetica,Arial,Lucida Grande,sans-serif;background-color:#ececec;padding:5px;border-radius:5px}.hg-theme-default .hg-button{display:inline-block;flex-grow:1}.hg-theme-default .hg-row{display:flex}.hg-theme-default .hg-row:not(:last-child){margin-bottom:5px}.hg-theme-default .hg-row .hg-button-container,.hg-theme-default .hg-row .hg-button:not(:last-child){margin-right:5px}.hg-theme-default .hg-row>div:last-child{margin-right:0}.hg-theme-default .hg-row .hg-button-container{display:flex}.hg-theme-default .hg-button{box-shadow:0 0 3px -1px rgba(0,0,0,.3);height:40px;border-radius:5px;box-sizing:border-box;padding:5px;background:#fff;border-bottom:1px solid #b5b5b5;cursor:pointer;display:flex;align-items:center;justify-content:center;-webkit-tap-highlight-color:rgba(0,0,0,0)}.hg-theme-default .hg-button.hg-activeButton{background:#efefef}.hg-theme-default.hg-layout-numeric .hg-button{width:33.3%;height:60px;align-items:center;display:flex;justify-content:center}.hg-theme-default .hg-button.hg-button-numpadadd,.hg-theme-default .hg-button.hg-button-numpadenter{height:85px}.hg-theme-default .hg-button.hg-button-numpad0{width:105px}.hg-theme-default .hg-button.hg-button-com{max-width:85px}.hg-theme-default .hg-button.hg-standardBtn.hg-button-at{max-width:45px}.hg-theme-default .hg-button.hg-selectedButton{background:rgba(5,25,70,.53);color:#fff}.hg-theme-default .hg-button.hg-standardBtn[data-skbtn=".com"]{max-width:82px}.hg-theme-default .hg-button.hg-standardBtn[data-skbtn="@"]{max-width:60px}
|
||||
*/.hg-theme-default{width:100%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;box-sizing:border-box;overflow:hidden;touch-action:manipulation}.hg-theme-default .hg-button span{pointer-events:none}.hg-theme-default button.hg-button{border-width:0;outline:0;font-size:inherit}.hg-theme-default{font-family:"HelveticaNeue-Light","Helvetica Neue Light","Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;background-color:#ececec;padding:5px;border-radius:5px}.hg-theme-default .hg-button{display:inline-block;flex-grow:1}.hg-theme-default .hg-row{display:flex}.hg-theme-default .hg-row:not(:last-child){margin-bottom:5px}.hg-theme-default .hg-row .hg-button-container,.hg-theme-default .hg-row .hg-button:not(:last-child){margin-right:5px}.hg-theme-default .hg-row>div:last-child{margin-right:0}.hg-theme-default .hg-row .hg-button-container{display:flex}.hg-theme-default .hg-button{box-shadow:0 0 3px -1px rgba(0,0,0,.3);height:40px;border-radius:5px;box-sizing:border-box;padding:5px;background:#fff;border-bottom:1px solid #b5b5b5;cursor:pointer;display:flex;align-items:center;justify-content:center;-webkit-tap-highlight-color:rgba(0,0,0,0)}.hg-theme-default .hg-button.hg-activeButton{background:#efefef}.hg-theme-default.hg-layout-numeric .hg-button{width:33.3%;height:60px;align-items:center;display:flex;justify-content:center}.hg-theme-default .hg-button.hg-button-numpadadd,.hg-theme-default .hg-button.hg-button-numpadenter{height:85px}.hg-theme-default .hg-button.hg-button-numpad0{width:105px}.hg-theme-default .hg-button.hg-button-com{max-width:85px}.hg-theme-default .hg-button.hg-standardBtn.hg-button-at{max-width:45px}.hg-theme-default .hg-button.hg-selectedButton{background:rgba(5,25,70,.53);color:#fff}.hg-theme-default .hg-button.hg-standardBtn[data-skbtn=".com"]{max-width:82px}.hg-theme-default .hg-button.hg-standardBtn[data-skbtn="@"]{max-width:60px}
|
||||
/*# sourceMappingURL=index.css.map */
|
||||
File diff suppressed because one or more lines are too long
30
build/index.d.ts
vendored
30
build/index.d.ts
vendored
@@ -1,7 +1,5 @@
|
||||
declare module 'simple-keyboard' {
|
||||
interface KeyboardLayoutObject {
|
||||
default: string[];
|
||||
shift?: any;
|
||||
[key: string]: string[];
|
||||
}
|
||||
|
||||
@@ -188,6 +186,11 @@ declare module 'simple-keyboard' {
|
||||
* Module classes to be loaded by simple-keyboard.
|
||||
*/
|
||||
modules?: any[];
|
||||
|
||||
/**
|
||||
* Module options can have any format
|
||||
*/
|
||||
[name: string]: any;
|
||||
}
|
||||
|
||||
class Keyboard {
|
||||
@@ -210,6 +213,29 @@ declare module 'simple-keyboard' {
|
||||
*/
|
||||
caretPosition?: number;
|
||||
|
||||
|
||||
/**
|
||||
* caretPositionEnd
|
||||
*/
|
||||
caretPositionEnd?: number;
|
||||
|
||||
/**
|
||||
* Changes the internal caret position
|
||||
* @param {number} position The caret's start position
|
||||
* @param {number} positionEnd The caret's end position
|
||||
*/
|
||||
setCaretPosition(position: number, positionEnd?: number): void;
|
||||
|
||||
/**
|
||||
* Retrieves the internal caret position
|
||||
*/
|
||||
getCaretPosition(): number;
|
||||
|
||||
/**
|
||||
* Retrieves the internal end caret position
|
||||
*/
|
||||
getCaretPositionEnd(): number;
|
||||
|
||||
/**
|
||||
* Adds/Modifies an entry to the `buttonTheme`. Basically a way to add a class to a button.
|
||||
* @param {string} buttons List of buttons to select (separated by a space).
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -15,7 +15,7 @@ if (!NODE_ENV) {
|
||||
}
|
||||
|
||||
// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
|
||||
var dotenvFiles = [
|
||||
const dotenvFiles = [
|
||||
`${paths.dotenv}.${NODE_ENV}.local`,
|
||||
`${paths.dotenv}.${NODE_ENV}`,
|
||||
// Don't include `.env.local` for `test` environment
|
||||
@@ -46,7 +46,7 @@ dotenvFiles.forEach(dotenvFile => {
|
||||
// It works similar to `NODE_PATH` in Node itself:
|
||||
// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
|
||||
// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
|
||||
// Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims.
|
||||
// Otherwise, we risk importing Node.js core modules into an app instead of webpack shims.
|
||||
// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
|
||||
// We also resolve them to make sure all tools using them work consistently.
|
||||
const appDirectory = fs.realpathSync(process.cwd());
|
||||
@@ -57,7 +57,7 @@ process.env.NODE_PATH = (process.env.NODE_PATH || '')
|
||||
.join(path.delimiter);
|
||||
|
||||
// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
|
||||
// injected into the application via DefinePlugin in Webpack configuration.
|
||||
// injected into the application via DefinePlugin in webpack configuration.
|
||||
const REACT_APP = /^REACT_APP_/i;
|
||||
|
||||
function getClientEnvironment(publicUrl) {
|
||||
@@ -77,9 +77,17 @@ function getClientEnvironment(publicUrl) {
|
||||
// This should only be used as an escape hatch. Normally you would put
|
||||
// images into the `src` and `import` them in code to get their paths.
|
||||
PUBLIC_URL: publicUrl,
|
||||
// We support configuring the sockjs pathname during development.
|
||||
// These settings let a developer run multiple simultaneous projects.
|
||||
// They are used as the connection `hostname`, `pathname` and `port`
|
||||
// in webpackHotDevClient. They are used as the `sockHost`, `sockPath`
|
||||
// and `sockPort` options in webpack-dev-server.
|
||||
WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST,
|
||||
WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,
|
||||
WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT,
|
||||
}
|
||||
);
|
||||
// Stringify all values so we can feed into Webpack DefinePlugin
|
||||
// Stringify all values so we can feed into webpack DefinePlugin
|
||||
const stringified = {
|
||||
'process.env': Object.keys(raw).reduce((env, key) => {
|
||||
env[key] = JSON.stringify(raw[key]);
|
||||
|
||||
66
config/getHttpsConfig.js
Normal file
66
config/getHttpsConfig.js
Normal file
@@ -0,0 +1,66 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const crypto = require('crypto');
|
||||
const chalk = require('react-dev-utils/chalk');
|
||||
const paths = require('./paths');
|
||||
|
||||
// Ensure the certificate and key provided are valid and if not
|
||||
// throw an easy to debug error
|
||||
function validateKeyAndCerts({ cert, key, keyFile, crtFile }) {
|
||||
let encrypted;
|
||||
try {
|
||||
// publicEncrypt will throw an error with an invalid cert
|
||||
encrypted = crypto.publicEncrypt(cert, Buffer.from('test'));
|
||||
} catch (err) {
|
||||
throw new Error(
|
||||
`The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}`
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
// privateDecrypt will throw an error with an invalid key
|
||||
crypto.privateDecrypt(key, encrypted);
|
||||
} catch (err) {
|
||||
throw new Error(
|
||||
`The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${
|
||||
err.message
|
||||
}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Read file and throw an error if it doesn't exist
|
||||
function readEnvFile(file, type) {
|
||||
if (!fs.existsSync(file)) {
|
||||
throw new Error(
|
||||
`You specified ${chalk.cyan(
|
||||
type
|
||||
)} in your env, but the file "${chalk.yellow(file)}" can't be found.`
|
||||
);
|
||||
}
|
||||
return fs.readFileSync(file);
|
||||
}
|
||||
|
||||
// Get the https config
|
||||
// Return cert files if provided in env, otherwise just true or false
|
||||
function getHttpsConfig() {
|
||||
const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env;
|
||||
const isHttps = HTTPS === 'true';
|
||||
|
||||
if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) {
|
||||
const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE);
|
||||
const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE);
|
||||
const config = {
|
||||
cert: readEnvFile(crtFile, 'SSL_CRT_FILE'),
|
||||
key: readEnvFile(keyFile, 'SSL_KEY_FILE'),
|
||||
};
|
||||
|
||||
validateKeyAndCerts({ ...config, keyFile, crtFile });
|
||||
return config;
|
||||
}
|
||||
return isHttps;
|
||||
}
|
||||
|
||||
module.exports = getHttpsConfig;
|
||||
@@ -13,10 +13,10 @@ module.exports = {
|
||||
if (filename.match(/\.svg$/)) {
|
||||
// Based on how SVGR generates a component name:
|
||||
// https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6
|
||||
const pascalCaseFileName = camelcase(path.parse(filename).name, {
|
||||
const pascalCaseFilename = camelcase(path.parse(filename).name, {
|
||||
pascalCase: true,
|
||||
});
|
||||
const componentName = `Svg${pascalCaseFileName}`;
|
||||
const componentName = `Svg${pascalCaseFilename}`;
|
||||
return `const React = require('react');
|
||||
module.exports = {
|
||||
__esModule: true,
|
||||
|
||||
@@ -7,7 +7,7 @@ const chalk = require('react-dev-utils/chalk');
|
||||
const resolve = require('resolve');
|
||||
|
||||
/**
|
||||
* Get the baseUrl of a compilerOptions object.
|
||||
* Get additional module paths based on the baseUrl of a compilerOptions object.
|
||||
*
|
||||
* @param {Object} options
|
||||
*/
|
||||
@@ -38,6 +38,15 @@ function getAdditionalModulePaths(options = {}) {
|
||||
return [paths.appSrc];
|
||||
}
|
||||
|
||||
// If the path is equal to the root directory we ignore it here.
|
||||
// We don't want to allow importing from the root directly as source files are
|
||||
// not transpiled outside of `src`. We do allow importing them with the
|
||||
// absolute path (e.g. `src/Components/Button.js`) but we set that up with
|
||||
// an alias.
|
||||
if (path.relative(paths.appPath, baseUrlResolved) === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Otherwise, throw an error.
|
||||
throw new Error(
|
||||
chalk.red.bold(
|
||||
@@ -47,6 +56,48 @@ function getAdditionalModulePaths(options = {}) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get webpack aliases based on the baseUrl of a compilerOptions object.
|
||||
*
|
||||
* @param {*} options
|
||||
*/
|
||||
function getWebpackAliases(options = {}) {
|
||||
const baseUrl = options.baseUrl;
|
||||
|
||||
if (!baseUrl) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
|
||||
|
||||
if (path.relative(paths.appPath, baseUrlResolved) === '') {
|
||||
return {
|
||||
src: paths.appSrc,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get jest aliases based on the baseUrl of a compilerOptions object.
|
||||
*
|
||||
* @param {*} options
|
||||
*/
|
||||
function getJestAliases(options = {}) {
|
||||
const baseUrl = options.baseUrl;
|
||||
|
||||
if (!baseUrl) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
|
||||
|
||||
if (path.relative(paths.appPath, baseUrlResolved) === '') {
|
||||
return {
|
||||
'^src/(.*)$': '<rootDir>/src/$1',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function getModules() {
|
||||
// Check if TypeScript is setup
|
||||
const hasTsConfig = fs.existsSync(paths.appTsConfig);
|
||||
@@ -81,6 +132,8 @@ function getModules() {
|
||||
|
||||
return {
|
||||
additionalModulePaths: additionalModulePaths,
|
||||
webpackAliases: getWebpackAliases(options),
|
||||
jestAliases: getJestAliases(options),
|
||||
hasTsConfig,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,42 +1,22 @@
|
||||
'use strict';
|
||||
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const url = require('url');
|
||||
const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath');
|
||||
|
||||
// Make sure any symlinks in the project folder are resolved:
|
||||
// https://github.com/facebook/create-react-app/issues/637
|
||||
const appDirectory = fs.realpathSync(process.cwd());
|
||||
const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
|
||||
|
||||
const envPublicUrl = process.env.PUBLIC_URL;
|
||||
|
||||
function ensureSlash(inputPath, needsSlash) {
|
||||
const hasSlash = inputPath.endsWith('/');
|
||||
if (hasSlash && !needsSlash) {
|
||||
return inputPath.substr(0, inputPath.length - 1);
|
||||
} else if (!hasSlash && needsSlash) {
|
||||
return `${inputPath}/`;
|
||||
} else {
|
||||
return inputPath;
|
||||
}
|
||||
}
|
||||
|
||||
const getPublicUrl = appPackageJson =>
|
||||
envPublicUrl || require(appPackageJson).homepage;
|
||||
|
||||
// We use `PUBLIC_URL` environment variable or "homepage" field to infer
|
||||
// "public path" at which the app is served.
|
||||
// Webpack needs to know it to put the right <script> hrefs into HTML even in
|
||||
// webpack needs to know it to put the right <script> hrefs into HTML even in
|
||||
// single-page apps that may serve index.html for nested URLs like /todos/42.
|
||||
// We can't use a relative path in HTML because we don't want to load something
|
||||
// like /todos/42/static/js/bundle.7289d.js. We have to know the root.
|
||||
function getServedPath(appPackageJson) {
|
||||
const publicUrl = getPublicUrl(appPackageJson);
|
||||
const servedUrl =
|
||||
envPublicUrl || (publicUrl ? url.parse(publicUrl).pathname : '/');
|
||||
return ensureSlash(servedUrl, true);
|
||||
}
|
||||
const publicUrlOrPath = '/';
|
||||
|
||||
const moduleFileExtensions = [
|
||||
'web.mjs',
|
||||
@@ -87,9 +67,7 @@ module.exports = {
|
||||
testsSetup: resolveModule(resolveApp, 'src/setupTests'),
|
||||
proxySetup: resolveApp('src/setupProxy.js'),
|
||||
appNodeModules: resolveApp('node_modules'),
|
||||
publicUrl: getPublicUrl(resolveApp('package.json')),
|
||||
//servedPath: getServedPath(resolveApp('package.json')),
|
||||
servedPath: ''
|
||||
publicUrlOrPath
|
||||
};
|
||||
|
||||
module.exports.moduleFileExtensions = moduleFileExtensions;
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const isWsl = require('is-wsl');
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const resolve = require('resolve');
|
||||
@@ -38,6 +35,8 @@ const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
|
||||
// makes for a smoother build process.
|
||||
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false';
|
||||
|
||||
const isExtendingEslintConfig = process.env.EXTEND_ESLINT === 'true';
|
||||
|
||||
const imageInlineSizeLimit = parseInt(
|
||||
process.env.IMAGE_INLINE_SIZE_LIMIT || '10000'
|
||||
);
|
||||
@@ -57,20 +56,16 @@ module.exports = function(webpackEnv) {
|
||||
const isEnvDevelopment = webpackEnv === 'development';
|
||||
const isEnvProduction = webpackEnv === 'production';
|
||||
|
||||
// Webpack uses `publicPath` to determine where the app is being served from.
|
||||
// It requires a trailing slash, or the file assets will get an incorrect path.
|
||||
// In development, we always serve from the root. This makes config easier.
|
||||
const publicPath = paths.servedPath
|
||||
// Some apps do not use client-side routing with pushState.
|
||||
// For these, "homepage" can be set to "." to enable relative asset paths.
|
||||
const shouldUseRelativeAssetPaths = publicPath === './';
|
||||
// Variable used for enabling profiling in Production
|
||||
// passed into alias object. Uses a flag if passed into the build command
|
||||
const isEnvProductionProfile =
|
||||
isEnvProduction && process.argv.includes('--profile');
|
||||
|
||||
// `publicUrl` is just like `publicPath`, but we will provide it to our app
|
||||
// We will provide `paths.publicUrlOrPath` to our app
|
||||
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
|
||||
// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
|
||||
const publicUrl = publicPath.slice(0, -1);
|
||||
// Get environment variables to inject into our app.
|
||||
const env = getClientEnvironment(publicUrl);
|
||||
const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));
|
||||
|
||||
// common function to get style loaders
|
||||
const getStyleLoaders = (cssOptions, preProcessor) => {
|
||||
@@ -78,7 +73,11 @@ module.exports = function(webpackEnv) {
|
||||
isEnvDevelopment && require.resolve('style-loader'),
|
||||
isEnvProduction && {
|
||||
loader: MiniCssExtractPlugin.loader,
|
||||
options: shouldUseRelativeAssetPaths ? { publicPath: '../../' } : {},
|
||||
// css is located in `static/css`, use '../../' to locate index.html folder
|
||||
// in production `paths.publicUrlOrPath` can be a relative path
|
||||
options: paths.publicUrlOrPath.startsWith('.')
|
||||
? { publicPath: '../../' }
|
||||
: {},
|
||||
},
|
||||
{
|
||||
loader: require.resolve('css-loader'),
|
||||
@@ -114,16 +113,16 @@ module.exports = function(webpackEnv) {
|
||||
loaders.push(
|
||||
{
|
||||
loader: require.resolve('resolve-url-loader'),
|
||||
options: {
|
||||
sourceMap: isEnvProduction && shouldUseSourceMap,
|
||||
},
|
||||
options: {
|
||||
sourceMap: isEnvProduction && shouldUseSourceMap,
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: require.resolve(preProcessor),
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
return loaders;
|
||||
@@ -170,10 +169,13 @@ module.exports = function(webpackEnv) {
|
||||
// TODO: remove this when upgrading to webpack 5
|
||||
futureEmitAssets: true,
|
||||
// There are also additional JS chunk files if you use code splitting.
|
||||
chunkFilename: 'static/js/[name].[contenthash:8].chunk.js',
|
||||
chunkFilename: isEnvProduction
|
||||
? 'static/js/[name].[contenthash:8].chunk.js'
|
||||
: isEnvDevelopment && 'static/js/[name].chunk.js',
|
||||
// webpack uses `publicPath` to determine where the app is being served from.
|
||||
// It requires a trailing slash, or the file assets will get an incorrect path.
|
||||
// We inferred the "public path" (such as / or /my-project) from homepage.
|
||||
// We use "/" in development.
|
||||
publicPath: publicPath,
|
||||
publicPath: paths.publicUrlOrPath,
|
||||
// Point sourcemap entries to original disk location (format as URL on Windows)
|
||||
devtoolModuleFilenameTemplate: isEnvProduction
|
||||
? info =>
|
||||
@@ -182,9 +184,12 @@ module.exports = function(webpackEnv) {
|
||||
.replace(/\\/g, '/')
|
||||
: isEnvDevelopment &&
|
||||
(info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),
|
||||
// Prevents conflicts when multiple Webpack runtimes (from different apps)
|
||||
// Prevents conflicts when multiple webpack runtimes (from different apps)
|
||||
// are used on the same page.
|
||||
jsonpFunction: `webpackJsonp${appPackageJson.name}`,
|
||||
// this defaults to 'window', but by setting it to 'this' then
|
||||
// module chunks which are built will work in web workers as well.
|
||||
globalObject: 'this',
|
||||
},
|
||||
optimization: {
|
||||
minimize: isEnvProduction,
|
||||
@@ -228,12 +233,6 @@ module.exports = function(webpackEnv) {
|
||||
ascii_only: true,
|
||||
},
|
||||
},
|
||||
// Use multi-process parallel running to improve the build speed
|
||||
// Default number of concurrent runs: os.cpus().length - 1
|
||||
// Disabled on WSL (Windows Subsystem for Linux) due to an issue with Terser
|
||||
// https://github.com/webpack-contrib/terser-webpack-plugin/issues/21
|
||||
parallel: !isWsl,
|
||||
// Enable file caching
|
||||
cache: true,
|
||||
sourceMap: shouldUseSourceMap,
|
||||
}),
|
||||
@@ -251,24 +250,26 @@ module.exports = function(webpackEnv) {
|
||||
}
|
||||
: false,
|
||||
},
|
||||
cssProcessorPluginOptions: {
|
||||
preset: ['default', { minifyFontValues: { removeQuotes: false } }],
|
||||
},
|
||||
}),
|
||||
],
|
||||
// Automatically split vendor and commons
|
||||
// https://twitter.com/wSokra/status/969633336732905474
|
||||
// https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
|
||||
splitChunks: {
|
||||
/*chunks: 'all',
|
||||
name: false,*/
|
||||
cacheGroups: {
|
||||
default: false,
|
||||
}
|
||||
cacheGroups: {
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
// Keep the runtime chunk separated to enable long term caching
|
||||
// https://twitter.com/wSokra/status/969679223278505985
|
||||
runtimeChunk: false,
|
||||
// https://github.com/facebook/create-react-app/issues/5358
|
||||
runtimeChunk: false,
|
||||
},
|
||||
resolve: {
|
||||
// This allows you to set a fallback for where Webpack should look for modules.
|
||||
// This allows you to set a fallback for where webpack should look for modules.
|
||||
// We placed these paths second because we want `node_modules` to "win"
|
||||
// if there are any conflicts. This matches Node resolution mechanism.
|
||||
// https://github.com/facebook/create-react-app/issues/253
|
||||
@@ -288,6 +289,12 @@ module.exports = function(webpackEnv) {
|
||||
// Support React Native Web
|
||||
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
|
||||
'react-native': 'react-native-web',
|
||||
// Allows for better profiling with ReactDevTools
|
||||
...(isEnvProductionProfile && {
|
||||
'react-dom$': 'react-dom/profiling',
|
||||
'scheduler/tracing': 'scheduler/tracing-profiling',
|
||||
}),
|
||||
...(modules.webpackAliases || {}),
|
||||
},
|
||||
plugins: [
|
||||
// Adds support for installing with Plug'n'Play, leading to faster installs and adding
|
||||
@@ -303,7 +310,7 @@ module.exports = function(webpackEnv) {
|
||||
},
|
||||
resolveLoader: {
|
||||
plugins: [
|
||||
// Also related to Plug'n'Play, but this time it tells Webpack to load its loaders
|
||||
// Also related to Plug'n'Play, but this time it tells webpack to load its loaders
|
||||
// from the current package.
|
||||
PnpWebpackPlugin.moduleLoader(module),
|
||||
],
|
||||
@@ -322,6 +329,7 @@ module.exports = function(webpackEnv) {
|
||||
use: [
|
||||
{
|
||||
options: {
|
||||
cache: true,
|
||||
formatter: require.resolve('react-dev-utils/eslintFormatter'),
|
||||
eslintPath: require.resolve('eslint'),
|
||||
resolvePluginsRelativeTo: __dirname,
|
||||
@@ -330,7 +338,7 @@ module.exports = function(webpackEnv) {
|
||||
loader: require.resolve('eslint-loader'),
|
||||
},
|
||||
],
|
||||
include: paths.appSrcDemo,
|
||||
include: paths.appSrcDemo,
|
||||
},
|
||||
{
|
||||
// "oneOf" will traverse all following loaders until one will
|
||||
@@ -352,7 +360,7 @@ module.exports = function(webpackEnv) {
|
||||
// The preset includes JSX, Flow, TypeScript, and some ESnext features.
|
||||
{
|
||||
test: /\.(js|mjs|jsx|ts|tsx)$/,
|
||||
include: paths.appSrcDemo,
|
||||
include: paths.appSrcDemo,
|
||||
loader: require.resolve('babel-loader'),
|
||||
options: {
|
||||
customize: require.resolve(
|
||||
@@ -365,7 +373,8 @@ module.exports = function(webpackEnv) {
|
||||
{
|
||||
loaderMap: {
|
||||
svg: {
|
||||
ReactComponent: '@svgr/webpack?-prettier,-svgo,+ref![path]',
|
||||
ReactComponent:
|
||||
'@svgr/webpack?-svgo,+titleProp,+ref![path]',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -375,7 +384,8 @@ module.exports = function(webpackEnv) {
|
||||
// It enables caching results in ./node_modules/.cache/babel-loader/
|
||||
// directory for faster rebuilds.
|
||||
cacheDirectory: true,
|
||||
cacheCompression: isEnvProduction,
|
||||
// See #6846 for context on why cacheCompression is disabled
|
||||
cacheCompression: false,
|
||||
compact: isEnvProduction,
|
||||
},
|
||||
},
|
||||
@@ -403,13 +413,14 @@ module.exports = function(webpackEnv) {
|
||||
]
|
||||
],
|
||||
cacheDirectory: true,
|
||||
cacheCompression: isEnvProduction,
|
||||
// See #6846 for context on why cacheCompression is disabled
|
||||
cacheCompression: false,
|
||||
|
||||
// If an error happens in a package, it's possible to be
|
||||
// because it was compiled. Thus, we don't want the browser
|
||||
// debugger to show the original code. Instead, the code
|
||||
// being evaluated would be much more helpful.
|
||||
sourceMaps: false,
|
||||
// Babel sourcemaps are needed for debugging into node_modules
|
||||
// code. Without the options below, debuggers like VSCode
|
||||
// show incorrect code and set breakpoints on the wrong lines.
|
||||
sourceMaps: shouldUseSourceMap,
|
||||
inputSourceMap: shouldUseSourceMap,
|
||||
},
|
||||
},
|
||||
// "postcss" loader applies autoprefixer to our CSS.
|
||||
@@ -439,8 +450,9 @@ module.exports = function(webpackEnv) {
|
||||
use: getStyleLoaders({
|
||||
importLoaders: 1,
|
||||
sourceMap: isEnvProduction && shouldUseSourceMap,
|
||||
modules: true,
|
||||
getLocalIdent: getCSSModuleLocalIdent,
|
||||
modules: {
|
||||
getLocalIdent: getCSSModuleLocalIdent,
|
||||
},
|
||||
}),
|
||||
},
|
||||
// Opt-in support for SASS (using .scss or .sass extensions).
|
||||
@@ -451,7 +463,7 @@ module.exports = function(webpackEnv) {
|
||||
exclude: sassModuleRegex,
|
||||
use: getStyleLoaders(
|
||||
{
|
||||
importLoaders: 2,
|
||||
importLoaders: 3,
|
||||
sourceMap: isEnvProduction && shouldUseSourceMap,
|
||||
},
|
||||
'sass-loader'
|
||||
@@ -468,10 +480,11 @@ module.exports = function(webpackEnv) {
|
||||
test: sassModuleRegex,
|
||||
use: getStyleLoaders(
|
||||
{
|
||||
importLoaders: 2,
|
||||
importLoaders: 3,
|
||||
sourceMap: isEnvProduction && shouldUseSourceMap,
|
||||
modules: true,
|
||||
getLocalIdent: getCSSModuleLocalIdent,
|
||||
modules: {
|
||||
getLocalIdent: getCSSModuleLocalIdent,
|
||||
},
|
||||
},
|
||||
'sass-loader'
|
||||
),
|
||||
@@ -505,7 +518,7 @@ module.exports = function(webpackEnv) {
|
||||
{},
|
||||
{
|
||||
inject: true,
|
||||
template: paths.appHtml
|
||||
template: paths.appHtml,
|
||||
},
|
||||
isEnvProduction
|
||||
? {
|
||||
@@ -527,15 +540,15 @@ module.exports = function(webpackEnv) {
|
||||
),
|
||||
// Inlines the webpack runtime script. This script is too small to warrant
|
||||
// a network request.
|
||||
// https://github.com/facebook/create-react-app/issues/5358
|
||||
isEnvProduction &&
|
||||
shouldInlineRuntimeChunk &&
|
||||
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime~.+[.]js/]),
|
||||
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime-.+[.]js/]),
|
||||
// Makes some environment variables available in index.html.
|
||||
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
|
||||
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
// In production, it will be an empty string unless you specify "homepage"
|
||||
// <link rel="icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
// It will be an empty string unless you specify "homepage"
|
||||
// in `package.json`, in which case it will be the pathname of that URL.
|
||||
// In development, this will be an empty string.
|
||||
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),
|
||||
// This gives some necessary context to module not found errors, such as
|
||||
// the requesting resource.
|
||||
@@ -553,7 +566,7 @@ module.exports = function(webpackEnv) {
|
||||
// See https://github.com/facebook/create-react-app/issues/240
|
||||
isEnvDevelopment && new CaseSensitivePathsPlugin(),
|
||||
// If you require a missing module and then `npm install` it, you still have
|
||||
// to restart the development server for Webpack to discover it. This plugin
|
||||
// to restart the development server for webpack to discover it. This plugin
|
||||
// makes the discovery automatic so you don't have to restart.
|
||||
// See https://github.com/facebook/create-react-app/issues/186
|
||||
isEnvDevelopment &&
|
||||
@@ -565,43 +578,52 @@ module.exports = function(webpackEnv) {
|
||||
filename: 'index.css',
|
||||
chunkFilename: 'index.[contenthash:8].chunk.css',
|
||||
}),
|
||||
// Generate a manifest file which contains a mapping of all asset filenames
|
||||
// to their corresponding output file so that tools can pick it up without
|
||||
// having to parse `index.html`.
|
||||
/*new ManifestPlugin({
|
||||
// Generate an asset manifest file with the following content:
|
||||
// - "files" key: Mapping of all asset filenames to their corresponding
|
||||
// output file so that tools can pick it up without having to parse
|
||||
// `index.html`
|
||||
// - "entrypoints" key: Array of files which are included in `index.html`,
|
||||
// can be used to reconstruct the HTML if necessary
|
||||
/*new ManifestPlugin({
|
||||
fileName: 'asset-manifest.json',
|
||||
publicPath: publicPath,
|
||||
generate: (seed, files) => {
|
||||
const manifestFiles = files.reduce(function(manifest, file) {
|
||||
publicPath: paths.publicUrlOrPath,
|
||||
generate: (seed, files, entrypoints) => {
|
||||
const manifestFiles = files.reduce((manifest, file) => {
|
||||
manifest[file.name] = file.path;
|
||||
return manifest;
|
||||
}, seed);
|
||||
const entrypointFiles = entrypoints.main.filter(
|
||||
fileName => !fileName.endsWith('.map')
|
||||
);
|
||||
|
||||
return {
|
||||
files: manifestFiles,
|
||||
entrypoints: entrypointFiles,
|
||||
};
|
||||
},
|
||||
}),*/
|
||||
// Moment.js is an extremely popular library that bundles large locale files
|
||||
// by default due to how Webpack interprets its code. This is a practical
|
||||
// by default due to how webpack interprets its code. This is a practical
|
||||
// solution that requires the user to opt into importing specific locales.
|
||||
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
|
||||
// You can remove this if you don't use Moment.js:
|
||||
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
|
||||
// Generate a service worker script that will precache, and keep up to date,
|
||||
// the HTML & assets that are part of the Webpack build.
|
||||
// the HTML & assets that are part of the webpack build.
|
||||
/*isEnvProduction &&
|
||||
new WorkboxWebpackPlugin.GenerateSW({
|
||||
clientsClaim: true,
|
||||
exclude: [/\.map$/, /asset-manifest\.json$/],
|
||||
importWorkboxFrom: 'cdn',
|
||||
navigateFallback: publicUrl + '/index.html',
|
||||
navigateFallback: paths.publicUrlOrPath + 'index.html',
|
||||
navigateFallbackBlacklist: [
|
||||
// Exclude URLs starting with /_, as they're likely an API call
|
||||
new RegExp('^/_'),
|
||||
// Exclude URLs containing a dot, as they're likely a resource in
|
||||
// public/ and not a SPA route
|
||||
new RegExp('/[^/]+\\.[^/]+$'),
|
||||
// Exclude any URLs whose last part seems to be a file extension
|
||||
// as they're likely a resource and not a SPA route.
|
||||
// URLs containing a "?" character won't be blacklisted as they're likely
|
||||
// a route with query params (e.g. auth callbacks).
|
||||
new RegExp('/[^/?]+\\.[^/]+$'),
|
||||
],
|
||||
}),*/
|
||||
// TypeScript type checking
|
||||
@@ -610,6 +632,7 @@ module.exports = function(webpackEnv) {
|
||||
typescript: resolve.sync('typescript', {
|
||||
basedir: paths.appNodeModules,
|
||||
}),
|
||||
async: isEnvDevelopment,
|
||||
useTypescriptIncrementalApi: true,
|
||||
checkSyntacticErrors: true,
|
||||
resolveModuleNameModule: process.versions.pnp
|
||||
@@ -633,7 +656,7 @@ module.exports = function(webpackEnv) {
|
||||
}),
|
||||
].filter(Boolean),
|
||||
// Some libraries import Node modules but don't use them in the browser.
|
||||
// Tell Webpack to provide empty mocks for them so importing them works.
|
||||
// Tell webpack to provide empty mocks for them so importing them works.
|
||||
node: {
|
||||
module: 'empty',
|
||||
dgram: 'empty',
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
const fs = require('fs');
|
||||
const isWsl = require('is-wsl');
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const resolve = require('resolve');
|
||||
@@ -11,7 +10,9 @@ const TerserPlugin = require('terser-webpack-plugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
||||
const safePostCssParser = require('postcss-safe-parser');
|
||||
const ManifestPlugin = require('webpack-manifest-plugin');
|
||||
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
|
||||
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
|
||||
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
|
||||
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
|
||||
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
|
||||
@@ -24,6 +25,7 @@ const typescriptFormatter = require('react-dev-utils/typescriptFormatter');
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
const getPackageJson = require('./getPackageJson');
|
||||
const PrettierPlugin = require("prettier-webpack-plugin");
|
||||
const eslint = require('eslint');
|
||||
const postcssNormalize = require('postcss-normalize');
|
||||
const appPackageJson = require(paths.appPackageJson);
|
||||
|
||||
@@ -33,6 +35,8 @@ const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
|
||||
// makes for a smoother build process.
|
||||
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false';
|
||||
|
||||
const isExtendingEslintConfig = process.env.EXTEND_ESLINT === 'true';
|
||||
|
||||
const imageInlineSizeLimit = parseInt(
|
||||
process.env.IMAGE_INLINE_SIZE_LIMIT || '10000'
|
||||
);
|
||||
@@ -70,24 +74,16 @@ module.exports = function(webpackEnv) {
|
||||
const isEnvDevelopment = webpackEnv === 'development';
|
||||
const isEnvProduction = webpackEnv === 'production';
|
||||
|
||||
// Webpack uses `publicPath` to determine where the app is being served from.
|
||||
// It requires a trailing slash, or the file assets will get an incorrect path.
|
||||
// In development, we always serve from the root. This makes config easier.
|
||||
const publicPath = isEnvProduction
|
||||
? paths.servedPath
|
||||
: isEnvDevelopment && '/';
|
||||
// Some apps do not use client-side routing with pushState.
|
||||
// For these, "homepage" can be set to "." to enable relative asset paths.
|
||||
const shouldUseRelativeAssetPaths = publicPath === './';
|
||||
// Variable used for enabling profiling in Production
|
||||
// passed into alias object. Uses a flag if passed into the build command
|
||||
const isEnvProductionProfile =
|
||||
isEnvProduction && process.argv.includes('--profile');
|
||||
|
||||
// `publicUrl` is just like `publicPath`, but we will provide it to our app
|
||||
// We will provide `paths.publicUrlOrPath` to our app
|
||||
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
|
||||
// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
|
||||
const publicUrl = isEnvProduction
|
||||
? publicPath.slice(0, -1)
|
||||
: isEnvDevelopment && '';
|
||||
// Get environment variables to inject into our app.
|
||||
const env = getClientEnvironment(publicUrl);
|
||||
const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));
|
||||
|
||||
// common function to get style loaders
|
||||
const getStyleLoaders = (cssOptions, preProcessor) => {
|
||||
@@ -95,7 +91,11 @@ module.exports = function(webpackEnv) {
|
||||
isEnvDevelopment && require.resolve('style-loader'),
|
||||
isEnvProduction && {
|
||||
loader: MiniCssExtractPlugin.loader,
|
||||
options: shouldUseRelativeAssetPaths ? { publicPath: '../../' } : {},
|
||||
// css is located in `static/css`, use '../../' to locate index.html folder
|
||||
// in production `paths.publicUrlOrPath` can be a relative path
|
||||
options: paths.publicUrlOrPath.startsWith('.')
|
||||
? { publicPath: '../../' }
|
||||
: {},
|
||||
},
|
||||
{
|
||||
loader: require.resolve('css-loader'),
|
||||
@@ -131,16 +131,16 @@ module.exports = function(webpackEnv) {
|
||||
loaders.push(
|
||||
{
|
||||
loader: require.resolve('resolve-url-loader'),
|
||||
options: {
|
||||
sourceMap: isEnvProduction && shouldUseSourceMap,
|
||||
},
|
||||
options: {
|
||||
sourceMap: isEnvProduction && shouldUseSourceMap,
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: require.resolve(preProcessor),
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
return loaders;
|
||||
@@ -192,9 +192,10 @@ module.exports = function(webpackEnv) {
|
||||
chunkFilename: isEnvProduction
|
||||
? 'static/js/[name].[contenthash:8].chunk.js'
|
||||
: isEnvDevelopment && 'static/js/[name].chunk.js',
|
||||
// webpack uses `publicPath` to determine where the app is being served from.
|
||||
// It requires a trailing slash, or the file assets will get an incorrect path.
|
||||
// We inferred the "public path" (such as / or /my-project) from homepage.
|
||||
// We use "/" in development.
|
||||
publicPath: publicPath,
|
||||
publicPath: paths.publicUrlOrPath,
|
||||
library: "SimpleKeyboard",
|
||||
libraryTarget: 'umd',
|
||||
umdNamedDefine: true,
|
||||
@@ -206,9 +207,12 @@ module.exports = function(webpackEnv) {
|
||||
.replace(/\\/g, '/')
|
||||
: isEnvDevelopment &&
|
||||
(info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),
|
||||
// Prevents conflicts when multiple Webpack runtimes (from different apps)
|
||||
// Prevents conflicts when multiple webpack runtimes (from different apps)
|
||||
// are used on the same page.
|
||||
jsonpFunction: `webpackJsonp${appPackageJson.name}`,
|
||||
// this defaults to 'window', but by setting it to 'this' then
|
||||
// module chunks which are built will work in web workers as well.
|
||||
globalObject: 'this',
|
||||
},
|
||||
optimization: {
|
||||
minimize: isEnvProduction,
|
||||
@@ -244,6 +248,9 @@ module.exports = function(webpackEnv) {
|
||||
keep_fnames: true,
|
||||
module: true
|
||||
},
|
||||
// Added for profiling in devtools
|
||||
keep_classnames: isEnvProductionProfile,
|
||||
keep_fnames: isEnvProductionProfile,
|
||||
output: {
|
||||
ecma: 5,
|
||||
comments: false,
|
||||
@@ -252,15 +259,10 @@ module.exports = function(webpackEnv) {
|
||||
ascii_only: true,
|
||||
},
|
||||
},
|
||||
// Use multi-process parallel running to improve the build speed
|
||||
// Default number of concurrent runs: os.cpus().length - 1
|
||||
// Disabled on WSL (Windows Subsystem for Linux) due to an issue with Terser
|
||||
// https://github.com/webpack-contrib/terser-webpack-plugin/issues/21
|
||||
parallel: !isWsl,
|
||||
// Enable file caching
|
||||
cache: true,
|
||||
sourceMap: shouldUseSourceMap,
|
||||
}),
|
||||
// This is only used in production mode
|
||||
new webpack.BannerPlugin({
|
||||
banner: banner,
|
||||
entryOnly: true
|
||||
@@ -279,23 +281,26 @@ module.exports = function(webpackEnv) {
|
||||
}
|
||||
: false,
|
||||
},
|
||||
cssProcessorPluginOptions: {
|
||||
preset: ['default', { minifyFontValues: { removeQuotes: false } }],
|
||||
},
|
||||
}),
|
||||
],
|
||||
// Automatically split vendor and commons
|
||||
// https://twitter.com/wSokra/status/969633336732905474
|
||||
// https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
|
||||
splitChunks: {
|
||||
//chunks: 'all',
|
||||
cacheGroups: {
|
||||
default: false,
|
||||
}
|
||||
cacheGroups: {
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
// Keep the runtime chunk separated to enable long term caching
|
||||
// https://twitter.com/wSokra/status/969679223278505985
|
||||
runtimeChunk: false,
|
||||
// https://github.com/facebook/create-react-app/issues/5358
|
||||
runtimeChunk: false,
|
||||
},
|
||||
resolve: {
|
||||
// This allows you to set a fallback for where Webpack should look for modules.
|
||||
// This allows you to set a fallback for where webpack should look for modules.
|
||||
// We placed these paths second because we want `node_modules` to "win"
|
||||
// if there are any conflicts. This matches Node resolution mechanism.
|
||||
// https://github.com/facebook/create-react-app/issues/253
|
||||
@@ -315,6 +320,12 @@ module.exports = function(webpackEnv) {
|
||||
// Support React Native Web
|
||||
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
|
||||
'react-native': 'react-native-web',
|
||||
// Allows for better profiling with ReactDevTools
|
||||
...(isEnvProductionProfile && {
|
||||
'react-dom$': 'react-dom/profiling',
|
||||
'scheduler/tracing': 'scheduler/tracing-profiling',
|
||||
}),
|
||||
...(modules.webpackAliases || {}),
|
||||
},
|
||||
plugins: [
|
||||
// Adds support for installing with Plug'n'Play, leading to faster installs and adding
|
||||
@@ -330,7 +341,7 @@ module.exports = function(webpackEnv) {
|
||||
},
|
||||
resolveLoader: {
|
||||
plugins: [
|
||||
// Also related to Plug'n'Play, but this time it tells Webpack to load its loaders
|
||||
// Also related to Plug'n'Play, but this time it tells webpack to load its loaders
|
||||
// from the current package.
|
||||
PnpWebpackPlugin.moduleLoader(module),
|
||||
],
|
||||
@@ -349,6 +360,7 @@ module.exports = function(webpackEnv) {
|
||||
use: [
|
||||
{
|
||||
options: {
|
||||
cache: true,
|
||||
formatter: require.resolve('react-dev-utils/eslintFormatter'),
|
||||
eslintPath: require.resolve('eslint'),
|
||||
resolvePluginsRelativeTo: __dirname,
|
||||
@@ -357,7 +369,7 @@ module.exports = function(webpackEnv) {
|
||||
loader: require.resolve('eslint-loader'),
|
||||
},
|
||||
],
|
||||
include: paths.appSrcLib,
|
||||
include: paths.appSrcLib,
|
||||
},
|
||||
{
|
||||
// "oneOf" will traverse all following loaders until one will
|
||||
@@ -392,7 +404,8 @@ module.exports = function(webpackEnv) {
|
||||
{
|
||||
loaderMap: {
|
||||
svg: {
|
||||
ReactComponent: '@svgr/webpack?-prettier,-svgo,+ref![path]',
|
||||
ReactComponent:
|
||||
'@svgr/webpack?-svgo,+titleProp,+ref![path]',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -402,7 +415,8 @@ module.exports = function(webpackEnv) {
|
||||
// It enables caching results in ./node_modules/.cache/babel-loader/
|
||||
// directory for faster rebuilds.
|
||||
cacheDirectory: true,
|
||||
cacheCompression: isEnvProduction,
|
||||
// See #6846 for context on why cacheCompression is disabled
|
||||
cacheCompression: false,
|
||||
compact: isEnvProduction,
|
||||
},
|
||||
},
|
||||
@@ -430,13 +444,14 @@ module.exports = function(webpackEnv) {
|
||||
]
|
||||
],
|
||||
cacheDirectory: true,
|
||||
cacheCompression: isEnvProduction,
|
||||
// See #6846 for context on why cacheCompression is disabled
|
||||
cacheCompression: false,
|
||||
|
||||
// If an error happens in a package, it's possible to be
|
||||
// because it was compiled. Thus, we don't want the browser
|
||||
// debugger to show the original code. Instead, the code
|
||||
// being evaluated would be much more helpful.
|
||||
sourceMaps: false,
|
||||
// Babel sourcemaps are needed for debugging into node_modules
|
||||
// code. Without the options below, debuggers like VSCode
|
||||
// show incorrect code and set breakpoints on the wrong lines.
|
||||
sourceMaps: shouldUseSourceMap,
|
||||
inputSourceMap: shouldUseSourceMap,
|
||||
},
|
||||
},
|
||||
// "postcss" loader applies autoprefixer to our CSS.
|
||||
@@ -466,8 +481,9 @@ module.exports = function(webpackEnv) {
|
||||
use: getStyleLoaders({
|
||||
importLoaders: 1,
|
||||
sourceMap: isEnvProduction && shouldUseSourceMap,
|
||||
modules: true,
|
||||
getLocalIdent: getCSSModuleLocalIdent,
|
||||
modules: {
|
||||
getLocalIdent: getCSSModuleLocalIdent,
|
||||
},
|
||||
}),
|
||||
},
|
||||
// Opt-in support for SASS (using .scss or .sass extensions).
|
||||
@@ -478,7 +494,7 @@ module.exports = function(webpackEnv) {
|
||||
exclude: sassModuleRegex,
|
||||
use: getStyleLoaders(
|
||||
{
|
||||
importLoaders: 2,
|
||||
importLoaders: 3,
|
||||
sourceMap: isEnvProduction && shouldUseSourceMap,
|
||||
},
|
||||
'sass-loader'
|
||||
@@ -495,10 +511,11 @@ module.exports = function(webpackEnv) {
|
||||
test: sassModuleRegex,
|
||||
use: getStyleLoaders(
|
||||
{
|
||||
importLoaders: 2,
|
||||
importLoaders: 3,
|
||||
sourceMap: isEnvProduction && shouldUseSourceMap,
|
||||
modules: true,
|
||||
getLocalIdent: getCSSModuleLocalIdent,
|
||||
modules: {
|
||||
getLocalIdent: getCSSModuleLocalIdent,
|
||||
},
|
||||
},
|
||||
'sass-loader'
|
||||
),
|
||||
@@ -555,15 +572,15 @@ module.exports = function(webpackEnv) {
|
||||
),
|
||||
// Inlines the webpack runtime script. This script is too small to warrant
|
||||
// a network request.
|
||||
// https://github.com/facebook/create-react-app/issues/5358
|
||||
isEnvProduction &&
|
||||
shouldInlineRuntimeChunk &&
|
||||
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime~.+[.]js/]),
|
||||
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime-.+[.]js/]),
|
||||
// Makes some environment variables available in index.html.
|
||||
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
|
||||
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
// In production, it will be an empty string unless you specify "homepage"
|
||||
// <link rel="icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
// It will be an empty string unless you specify "homepage"
|
||||
// in `package.json`, in which case it will be the pathname of that URL.
|
||||
// In development, this will be an empty string.
|
||||
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),
|
||||
// This gives some necessary context to module not found errors, such as
|
||||
// the requesting resource.
|
||||
@@ -581,7 +598,7 @@ module.exports = function(webpackEnv) {
|
||||
// See https://github.com/facebook/create-react-app/issues/240
|
||||
isEnvDevelopment && new CaseSensitivePathsPlugin(),
|
||||
// If you require a missing module and then `npm install` it, you still have
|
||||
// to restart the development server for Webpack to discover it. This plugin
|
||||
// to restart the development server for webpack to discover it. This plugin
|
||||
// makes the discovery automatic so you don't have to restart.
|
||||
// See https://github.com/facebook/create-react-app/issues/186
|
||||
isEnvDevelopment &&
|
||||
@@ -593,25 +610,32 @@ module.exports = function(webpackEnv) {
|
||||
filename: 'css/index.css',
|
||||
chunkFilename: 'css/index.[contenthash:8].chunk.css',
|
||||
}),
|
||||
// Generate a manifest file which contains a mapping of all asset filenames
|
||||
// to their corresponding output file so that tools can pick it up without
|
||||
// having to parse `index.html`.
|
||||
/*new ManifestPlugin({
|
||||
// Generate an asset manifest file with the following content:
|
||||
// - "files" key: Mapping of all asset filenames to their corresponding
|
||||
// output file so that tools can pick it up without having to parse
|
||||
// `index.html`
|
||||
// - "entrypoints" key: Array of files which are included in `index.html`,
|
||||
// can be used to reconstruct the HTML if necessary
|
||||
/*new ManifestPlugin({
|
||||
fileName: 'asset-manifest.json',
|
||||
publicPath: publicPath,
|
||||
generate: (seed, files) => {
|
||||
const manifestFiles = files.reduce(function(manifest, file) {
|
||||
publicPath: paths.publicUrlOrPath,
|
||||
generate: (seed, files, entrypoints) => {
|
||||
const manifestFiles = files.reduce((manifest, file) => {
|
||||
manifest[file.name] = file.path;
|
||||
return manifest;
|
||||
}, seed);
|
||||
const entrypointFiles = entrypoints.main.filter(
|
||||
fileName => !fileName.endsWith('.map')
|
||||
);
|
||||
|
||||
return {
|
||||
files: manifestFiles,
|
||||
entrypoints: entrypointFiles,
|
||||
};
|
||||
},
|
||||
}),*/
|
||||
// Moment.js is an extremely popular library that bundles large locale files
|
||||
// by default due to how Webpack interprets its code. This is a practical
|
||||
// by default due to how webpack interprets its code. This is a practical
|
||||
// solution that requires the user to opt into importing specific locales.
|
||||
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
|
||||
// You can remove this if you don't use Moment.js:
|
||||
@@ -624,19 +648,21 @@ module.exports = function(webpackEnv) {
|
||||
]),
|
||||
new PrettierPlugin(),
|
||||
// Generate a service worker script that will precache, and keep up to date,
|
||||
// the HTML & assets that are part of the Webpack build.
|
||||
// the HTML & assets that are part of the webpack build.
|
||||
/*isEnvProduction &&
|
||||
new WorkboxWebpackPlugin.GenerateSW({
|
||||
clientsClaim: true,
|
||||
exclude: [/\.map$/, /asset-manifest\.json$/],
|
||||
importWorkboxFrom: 'cdn',
|
||||
navigateFallback: publicUrl + '/index.html',
|
||||
navigateFallback: paths.publicUrlOrPath + 'index.html',
|
||||
navigateFallbackBlacklist: [
|
||||
// Exclude URLs starting with /_, as they're likely an API call
|
||||
new RegExp('^/_'),
|
||||
// Exclude URLs containing a dot, as they're likely a resource in
|
||||
// public/ and not a SPA route
|
||||
new RegExp('/[^/]+\\.[^/]+$'),
|
||||
// Exclude any URLs whose last part seems to be a file extension
|
||||
// as they're likely a resource and not a SPA route.
|
||||
// URLs containing a "?" character won't be blacklisted as they're likely
|
||||
// a route with query params (e.g. auth callbacks).
|
||||
new RegExp('/[^/?]+\\.[^/]+$'),
|
||||
],
|
||||
}),*/
|
||||
// TypeScript type checking
|
||||
@@ -662,14 +688,13 @@ module.exports = function(webpackEnv) {
|
||||
'!**/src/setupProxy.*',
|
||||
'!**/src/setupTests.*',
|
||||
],
|
||||
watch: paths.appSrcLib,
|
||||
silent: true,
|
||||
// The formatter is invoked directly in WebpackDevServerUtils during development
|
||||
formatter: isEnvProduction ? typescriptFormatter : undefined,
|
||||
}),
|
||||
].filter(Boolean),
|
||||
// Some libraries import Node modules but don't use them in the browser.
|
||||
// Tell Webpack to provide empty mocks for them so importing them works.
|
||||
// Tell webpack to provide empty mocks for them so importing them works.
|
||||
node: {
|
||||
module: 'empty',
|
||||
dgram: 'empty',
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware');
|
||||
const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware');
|
||||
const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware');
|
||||
const ignoredFiles = require('react-dev-utils/ignoredFiles');
|
||||
const redirectServedPath = require('react-dev-utils/redirectServedPathMiddleware');
|
||||
const paths = require('./paths');
|
||||
const fs = require('fs');
|
||||
const getHttpsConfig = require('./getHttpsConfig');
|
||||
|
||||
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
|
||||
const host = process.env.HOST || '0.0.0.0';
|
||||
const sockHost = process.env.WDS_SOCKET_HOST;
|
||||
const sockPath = process.env.WDS_SOCKET_PATH; // default: '/sockjs-node'
|
||||
const sockPort = process.env.WDS_SOCKET_PORT;
|
||||
|
||||
module.exports = function(proxy, allowedHost) {
|
||||
return {
|
||||
@@ -43,24 +47,39 @@ module.exports = function(proxy, allowedHost) {
|
||||
// Instead, we establish a convention that only files in `public` directory
|
||||
// get served. Our build script will copy `public` into the `build` folder.
|
||||
// In `index.html`, you can get URL of `public` folder with %PUBLIC_URL%:
|
||||
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
// <link rel="icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
// In JavaScript code, you can access it with `process.env.PUBLIC_URL`.
|
||||
// Note that we only recommend to use `public` folder as an escape hatch
|
||||
// for files like `favicon.ico`, `manifest.json`, and libraries that are
|
||||
// for some reason broken when imported through Webpack. If you just want to
|
||||
// for some reason broken when imported through webpack. If you just want to
|
||||
// use an image, put it in `src` and `import` it from JavaScript instead.
|
||||
contentBase: paths.appPublic,
|
||||
contentBasePublicPath: paths.publicUrlOrPath,
|
||||
// By default files from `contentBase` will not trigger a page reload.
|
||||
watchContentBase: true,
|
||||
// Enable hot reloading server. It will provide /sockjs-node/ endpoint
|
||||
// Enable hot reloading server. It will provide WDS_SOCKET_PATH endpoint
|
||||
// for the WebpackDevServer client so it can learn when the files were
|
||||
// updated. The WebpackDevServer client is included as an entry point
|
||||
// in the Webpack development configuration. Note that only changes
|
||||
// in the webpack development configuration. Note that only changes
|
||||
// to CSS are currently hot reloaded. JS changes will refresh the browser.
|
||||
hot: true,
|
||||
// It is important to tell WebpackDevServer to use the same "root" path
|
||||
// as we specified in the config. In development, we always serve from /.
|
||||
publicPath: '/',
|
||||
// Use 'ws' instead of 'sockjs-node' on server since we're using native
|
||||
// websockets in `webpackHotDevClient`.
|
||||
transportMode: 'ws',
|
||||
// Prevent a WS client from getting injected as we're already including
|
||||
// `webpackHotDevClient`.
|
||||
injectClient: false,
|
||||
// Enable custom sockjs pathname for websocket connection to hot reloading server.
|
||||
// Enable custom sockjs hostname, pathname and port for websocket connection
|
||||
// to hot reloading server.
|
||||
sockHost,
|
||||
sockPath,
|
||||
sockPort,
|
||||
// It is important to tell WebpackDevServer to use the same "publicPath" path as
|
||||
// we specified in the webpack config. When homepage is '.', default to serving
|
||||
// from the root.
|
||||
// remove last slash so user can land on `/test` instead of `/test/`
|
||||
publicPath: paths.publicUrlOrPath.slice(0, -1),
|
||||
// WebpackDevServer is noisy by default so we emit custom message instead
|
||||
// by listening to the compiler events with `compiler.hooks[...].tap` calls above.
|
||||
quiet: true,
|
||||
@@ -71,34 +90,41 @@ module.exports = function(proxy, allowedHost) {
|
||||
watchOptions: {
|
||||
ignored: ignoredFiles(paths.appSrc),
|
||||
},
|
||||
// Enable HTTPS if the HTTPS environment variable is set to 'true'
|
||||
https: protocol === 'https',
|
||||
https: getHttpsConfig(),
|
||||
host,
|
||||
overlay: false,
|
||||
historyApiFallback: {
|
||||
// Paths with dots should still use the history fallback.
|
||||
// See https://github.com/facebook/create-react-app/issues/387.
|
||||
disableDotRule: true,
|
||||
index: paths.publicUrlOrPath,
|
||||
},
|
||||
public: allowedHost,
|
||||
// `proxy` is run between `before` and `after` `webpack-dev-server` hooks
|
||||
proxy,
|
||||
before(app, server) {
|
||||
if (fs.existsSync(paths.proxySetup)) {
|
||||
// This registers user provided middleware for proxy reasons
|
||||
require(paths.proxySetup)(app);
|
||||
}
|
||||
|
||||
// Keep `evalSourceMapMiddleware` and `errorOverlayMiddleware`
|
||||
// middlewares before `redirectServedPath` otherwise will not have any effect
|
||||
// This lets us fetch source contents from webpack for the error overlay
|
||||
app.use(evalSourceMapMiddleware(server));
|
||||
// This lets us open files from the runtime error overlay.
|
||||
app.use(errorOverlayMiddleware());
|
||||
|
||||
if (fs.existsSync(paths.proxySetup)) {
|
||||
// This registers user provided middleware for proxy reasons
|
||||
require(paths.proxySetup)(app);
|
||||
}
|
||||
},
|
||||
after(app) {
|
||||
// Redirect to `PUBLIC_URL` or `homepage` from `package.json` if url not match
|
||||
app.use(redirectServedPath(paths.publicUrlOrPath));
|
||||
|
||||
// This service worker file is effectively a 'no-op' that will reset any
|
||||
// previous service worker registered for the same host:port combination.
|
||||
// We do this in development to avoid hitting the production cache if
|
||||
// it used the same host and port.
|
||||
// https://github.com/facebook/create-react-app/issues/2272#issuecomment-302832432
|
||||
app.use(noopServiceWorkerMiddleware());
|
||||
app.use(noopServiceWorkerMiddleware(paths.publicUrlOrPath));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
20774
package-lock.json
generated
20774
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
74
package.json
74
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "simple-keyboard",
|
||||
"version": "2.29.1",
|
||||
"version": "2.30.1",
|
||||
"description": "On-screen Javascript Virtual Keyboard",
|
||||
"main": "build/index.js",
|
||||
"types": "build/index.d.ts",
|
||||
@@ -41,44 +41,46 @@
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.9.0",
|
||||
"@babel/plugin-proposal-class-properties": "^7.8.3",
|
||||
"@babel/preset-env": "^7.9.5",
|
||||
"@babel/preset-react": "^7.9.4",
|
||||
"@svgr/webpack": "5.3.1",
|
||||
"@typescript-eslint/eslint-plugin": "1.13.0",
|
||||
"@typescript-eslint/parser": "1.13.0",
|
||||
"@babel/plugin-proposal-class-properties": "^7.10.4",
|
||||
"@babel/preset-env": "^7.11.5",
|
||||
"@babel/preset-react": "^7.10.4",
|
||||
"@svgr/webpack": "5.4.0",
|
||||
"@testing-library/jest-dom": "^4.2.4",
|
||||
"@testing-library/react": "^9.3.2",
|
||||
"@testing-library/user-event": "^7.1.2",
|
||||
"@typescript-eslint/eslint-plugin": "^2.10.0",
|
||||
"@typescript-eslint/parser": "^2.10.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-jest": "^25.4.0",
|
||||
"babel-jest": "^26.3.0",
|
||||
"babel-loader": "8.1.0",
|
||||
"babel-plugin-named-asset-import": "^0.3.6",
|
||||
"babel-preset-react-app": "^9.1.2",
|
||||
"camelcase": "^6.0.0",
|
||||
"case-sensitive-paths-webpack-plugin": "2.3.0",
|
||||
"copy-webpack-plugin": "^5.1.1",
|
||||
"css-loader": "3.5.2",
|
||||
"copy-webpack-plugin": "^5.1.2",
|
||||
"css-loader": "4.2.2",
|
||||
"dotenv": "8.2.0",
|
||||
"dotenv-expand": "5.1.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-react-app": "^5.0.1",
|
||||
"eslint-loader": "4.0.0",
|
||||
"eslint-plugin-flowtype": "3.13.0",
|
||||
"eslint-plugin-import": "2.20.2",
|
||||
"eslint-plugin-jsx-a11y": "6.2.3",
|
||||
"eslint-plugin-react": "7.19.0",
|
||||
"eslint-plugin-react-hooks": "^3.0.0",
|
||||
"file-loader": "6.0.0",
|
||||
"fs-extra": "9.0.0",
|
||||
"html-webpack-plugin": "4.2.0",
|
||||
"eslint-loader": "4.0.2",
|
||||
"eslint-plugin-flowtype": "4.7.0",
|
||||
"eslint-plugin-import": "2.22.0",
|
||||
"eslint-plugin-jsx-a11y": "6.3.1",
|
||||
"eslint-plugin-react": "7.20.6",
|
||||
"eslint-plugin-react-hooks": "^4.1.0",
|
||||
"file-loader": "6.1.0",
|
||||
"fs-extra": "9.0.1",
|
||||
"html-webpack-plugin": "4.4.1",
|
||||
"identity-obj-proxy": "3.0.0",
|
||||
"is-wsl": "^2.1.0",
|
||||
"jest": "25.4.0",
|
||||
"jest": "26.4.2",
|
||||
"jest-environment-jsdom-fourteen": "1.0.1",
|
||||
"jest-resolve": "25.4.0",
|
||||
"jest-watch-typeahead": "0.5.0",
|
||||
"mini-css-extract-plugin": "0.9.0",
|
||||
"optimize-css-assets-webpack-plugin": "5.0.3",
|
||||
"jest-resolve": "26.4.0",
|
||||
"jest-watch-typeahead": "0.6.0",
|
||||
"mini-css-extract-plugin": "0.11.0",
|
||||
"optimize-css-assets-webpack-plugin": "5.0.4",
|
||||
"pnp-webpack-plugin": "1.6.4",
|
||||
"postcss-flexbugs-fixes": "4.2.0",
|
||||
"postcss-flexbugs-fixes": "4.2.1",
|
||||
"postcss-loader": "3.0.0",
|
||||
"postcss-normalize": "9.0.0",
|
||||
"postcss-preset-env": "6.7.0",
|
||||
@@ -87,21 +89,21 @@
|
||||
"prettier-webpack-plugin": "^1.2.0",
|
||||
"react": "^16.13.1",
|
||||
"react-app-polyfill": "^1.0.6",
|
||||
"react-dev-utils": "10.1.0",
|
||||
"react-dev-utils": "^10.2.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"resolve": "1.16.1",
|
||||
"resolve": "1.17.0",
|
||||
"resolve-url-loader": "3.1.1",
|
||||
"sass-loader": "8.0.2",
|
||||
"sass-loader": "10.0.1",
|
||||
"semver": "7.3.2",
|
||||
"style-loader": "1.1.4",
|
||||
"terser-webpack-plugin": "2.3.5",
|
||||
"style-loader": "1.2.1",
|
||||
"terser-webpack-plugin": "4.1.0",
|
||||
"ts-pnp": "1.2.0",
|
||||
"uglifyjs-webpack-plugin": "^2.2.0",
|
||||
"url-loader": "4.1.0",
|
||||
"webpack": "4.43.0",
|
||||
"webpack-dev-server": "3.10.3",
|
||||
"webpack": "4.44.1",
|
||||
"webpack-dev-server": "3.11.0",
|
||||
"webpack-manifest-plugin": "2.2.0",
|
||||
"workbox-webpack-plugin": "5.1.2"
|
||||
"workbox-webpack-plugin": "5.1.3"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app"
|
||||
@@ -134,7 +136,9 @@
|
||||
"setupFiles": [
|
||||
"react-app-polyfill/jsdom"
|
||||
],
|
||||
"setupFilesAfterEnv": [],
|
||||
"setupFilesAfterEnv": [
|
||||
"<rootDir>/src/setupTests.js"
|
||||
],
|
||||
"testMatch": [
|
||||
"<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
|
||||
"<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}"
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 3.1 KiB |
@@ -1,5 +1,3 @@
|
||||
'use strict';
|
||||
|
||||
// Do this as the first thing so that any code reading it knows the right env.
|
||||
process.env.BABEL_ENV = 'production';
|
||||
process.env.NODE_ENV = 'production';
|
||||
@@ -94,7 +92,7 @@ checkBrowsers(paths.appPath, isInteractive)
|
||||
console.log();
|
||||
|
||||
const appPackage = require(paths.appPackageJson);
|
||||
const publicUrl = paths.publicUrl;
|
||||
const publicUrl = paths.publicUrlOrPath;
|
||||
const publicPath = config.output.publicPath;
|
||||
const buildFolder = path.relative(process.cwd(), paths.appBuild);
|
||||
printHostingInstructions(
|
||||
@@ -106,9 +104,19 @@ checkBrowsers(paths.appPath, isInteractive)
|
||||
);
|
||||
},
|
||||
err => {
|
||||
console.error('Failed to compile');
|
||||
printBuildError(err);
|
||||
process.exit(1);
|
||||
const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true';
|
||||
if (tscCompileOnError) {
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
'Compiled with the following type errors (you may want to check these before deploying your app):\n'
|
||||
)
|
||||
);
|
||||
printBuildError(err);
|
||||
} else {
|
||||
console.log(chalk.red('Failed to compile.\n'));
|
||||
printBuildError(err);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
)
|
||||
.catch(err => {
|
||||
@@ -142,8 +150,18 @@ function build(previousFileSizes) {
|
||||
if (!err.message) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
let errMessage = err.message;
|
||||
|
||||
// Add additional information for postcss errors
|
||||
if (Object.prototype.hasOwnProperty.call(err, 'postcssNode')) {
|
||||
errMessage +=
|
||||
'\nCompileError: Begins at CSS selector ' +
|
||||
err['postcssNode'].selector;
|
||||
}
|
||||
|
||||
messages = formatWebpackMessages({
|
||||
errors: [err.message],
|
||||
errors: [errMessage],
|
||||
warnings: [],
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
'use strict';
|
||||
|
||||
// Do this as the first thing so that any code reading it knows the right env.
|
||||
process.env.BABEL_ENV = 'production';
|
||||
process.env.NODE_ENV = 'production';
|
||||
@@ -94,7 +92,7 @@ checkBrowsers(paths.appPath, isInteractive)
|
||||
console.log();
|
||||
|
||||
const appPackage = require(paths.appPackageJson);
|
||||
const publicUrl = paths.publicUrl;
|
||||
const publicUrl = paths.publicUrlOrPath;
|
||||
const publicPath = config.output.publicPath;
|
||||
const buildFolder = path.relative(process.cwd(), paths.appDemo);
|
||||
printHostingInstructions(
|
||||
@@ -106,9 +104,19 @@ checkBrowsers(paths.appPath, isInteractive)
|
||||
);
|
||||
},
|
||||
err => {
|
||||
console.error('Failed to compile');
|
||||
printBuildError(err);
|
||||
process.exit(1);
|
||||
const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true';
|
||||
if (tscCompileOnError) {
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
'Compiled with the following type errors (you may want to check these before deploying your app):\n'
|
||||
)
|
||||
);
|
||||
printBuildError(err);
|
||||
} else {
|
||||
console.log(chalk.red('Failed to compile.\n'));
|
||||
printBuildError(err);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
)
|
||||
.catch(err => {
|
||||
@@ -142,8 +150,18 @@ function build(previousFileSizes) {
|
||||
if (!err.message) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
let errMessage = err.message;
|
||||
|
||||
// Add additional information for postcss errors
|
||||
if (Object.prototype.hasOwnProperty.call(err, 'postcssNode')) {
|
||||
errMessage +=
|
||||
'\nCompileError: Begins at CSS selector ' +
|
||||
err['postcssNode'].selector;
|
||||
}
|
||||
|
||||
messages = formatWebpackMessages({
|
||||
errors: [err.message],
|
||||
errors: [errMessage],
|
||||
warnings: [],
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'use strict';
|
||||
|
||||
|
||||
// Do this as the first thing so that any code reading it knows the right env.
|
||||
process.env.BABEL_ENV = 'development';
|
||||
@@ -81,7 +81,13 @@ checkBrowsers(paths.appPath, isInteractive)
|
||||
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
|
||||
const appName = require(paths.appPackageJson).name;
|
||||
const useTypeScript = fs.existsSync(paths.appTsConfig);
|
||||
const urls = prepareUrls(protocol, HOST, port);
|
||||
const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true';
|
||||
const urls = prepareUrls(
|
||||
protocol,
|
||||
HOST,
|
||||
port,
|
||||
paths.publicUrlOrPath.slice(0, -1)
|
||||
);
|
||||
const devSocket = {
|
||||
warnings: warnings =>
|
||||
devServer.sockWrite(devServer.sockets, 'warnings', warnings),
|
||||
@@ -96,11 +102,15 @@ checkBrowsers(paths.appPath, isInteractive)
|
||||
urls,
|
||||
useYarn,
|
||||
useTypeScript,
|
||||
tscCompileOnError,
|
||||
webpack,
|
||||
});
|
||||
// Load proxy config
|
||||
const proxySetting = require(paths.appPackageJson).proxy;
|
||||
const proxyConfig = prepareProxy(proxySetting, paths.appPublic);
|
||||
const proxyConfig = prepareProxy(
|
||||
proxySetting,
|
||||
paths.appPublic
|
||||
);
|
||||
// Serve webpack assets generated by the compiler over a web server.
|
||||
const serverConfig = createDevServerConfig(
|
||||
proxyConfig,
|
||||
@@ -141,11 +151,10 @@ checkBrowsers(paths.appPath, isInteractive)
|
||||
if (stats.errors && stats.errors.length > 0) {
|
||||
devServer.close();
|
||||
process.exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
console.warn("App started in test mode. Closing in 5 seconds.");
|
||||
let closeTimeout = setTimeout(() => {
|
||||
const closeTimeout = setTimeout(() => {
|
||||
clearTimeout(closeTimeout);
|
||||
devServer.close();
|
||||
process.exit();
|
||||
@@ -160,6 +169,15 @@ checkBrowsers(paths.appPath, isInteractive)
|
||||
process.exit();
|
||||
});
|
||||
});
|
||||
|
||||
if (isInteractive || process.env.CI !== 'true') {
|
||||
// Gracefully exit when stdin ends
|
||||
process.stdin.on('end', function() {
|
||||
devServer.close();
|
||||
process.exit();
|
||||
});
|
||||
process.stdin.resume();
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
if (err && err.message) {
|
||||
|
||||
@@ -32,7 +32,10 @@ class Demo {
|
||||
});
|
||||
|
||||
console.log(this.keyboard);
|
||||
setTimeout(this.keyboard.destroy, 10000);
|
||||
setTimeout(() => {
|
||||
this.keyboard.destroy();
|
||||
document.querySelector(".input").value = "";
|
||||
}, 10000);
|
||||
setTimeout(() => {
|
||||
this.keyboard = new Keyboard({
|
||||
theme: "hg-theme-default myTheme",
|
||||
|
||||
@@ -4,10 +4,10 @@ import "./css/index.css";
|
||||
* Demos
|
||||
*/
|
||||
import BasicDemo from "./BasicDemo";
|
||||
// import ButtonThemeDemo from "./ButtonThemeDemo";
|
||||
// import DOMElementDemo from "./DOMElementDemo";
|
||||
// import FullKeyboardDemo from "./FullKeyboardDemo";
|
||||
// import MultipleKeyboardsDemo from "./MultipleKeyboardsDestroyDemo";
|
||||
//import ButtonThemeDemo from "./ButtonThemeDemo";
|
||||
//import DOMElementDemo from "./DOMElementDemo";
|
||||
//import FullKeyboardDemo from "./FullKeyboardDemo";
|
||||
//import MultipleKeyboardsDemo from "./MultipleKeyboardsDestroyDemo";
|
||||
|
||||
/**
|
||||
* Selected demo
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import TestUtility from '../../utils/TestUtility';
|
||||
import { setDOM } from '../../utils/TestUtility';
|
||||
import BasicDemo from '../BasicDemo';
|
||||
|
||||
const testUtil = new TestUtility();
|
||||
|
||||
it('Demo will load', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
new BasicDemo();
|
||||
});
|
||||
|
||||
it('Demo onDOMLoaded will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new BasicDemo();
|
||||
|
||||
@@ -18,7 +16,7 @@ it('Demo onDOMLoaded will work', () => {
|
||||
});
|
||||
|
||||
it('Demo onChange will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new BasicDemo();
|
||||
|
||||
@@ -28,7 +26,7 @@ it('Demo onChange will work', () => {
|
||||
});
|
||||
|
||||
it('Demo onChange will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new BasicDemo();
|
||||
|
||||
@@ -38,7 +36,7 @@ it('Demo onChange will work', () => {
|
||||
});
|
||||
|
||||
it('Demo input change will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new BasicDemo();
|
||||
|
||||
@@ -49,7 +47,7 @@ it('Demo input change will work', () => {
|
||||
});
|
||||
|
||||
it('Demo handleShiftButton will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new BasicDemo();
|
||||
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import TestUtility from '../../utils/TestUtility';
|
||||
import { setDOM } from '../../utils/TestUtility';
|
||||
import ButtonThemeDemo from '../ButtonThemeDemo';
|
||||
|
||||
const testUtil = new TestUtility();
|
||||
|
||||
it('Demo will load', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
new ButtonThemeDemo();
|
||||
});
|
||||
|
||||
it('Demo onDOMLoaded will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new ButtonThemeDemo();
|
||||
|
||||
@@ -18,7 +16,7 @@ it('Demo onDOMLoaded will work', () => {
|
||||
});
|
||||
|
||||
it('Demo onChange will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new ButtonThemeDemo();
|
||||
|
||||
@@ -28,7 +26,7 @@ it('Demo onChange will work', () => {
|
||||
});
|
||||
|
||||
it('Demo onChange will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new ButtonThemeDemo();
|
||||
|
||||
@@ -38,7 +36,7 @@ it('Demo onChange will work', () => {
|
||||
});
|
||||
|
||||
it('Demo input change will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new ButtonThemeDemo();
|
||||
|
||||
@@ -49,7 +47,7 @@ it('Demo input change will work', () => {
|
||||
});
|
||||
|
||||
it('Demo handleShiftButton will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new ButtonThemeDemo();
|
||||
|
||||
@@ -61,7 +59,7 @@ it('Demo handleShiftButton will work', () => {
|
||||
});
|
||||
|
||||
it('Demo buttons will have proper attributes and classes', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new ButtonThemeDemo();
|
||||
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import TestUtility from '../../utils/TestUtility';
|
||||
import { setDOM } from '../../utils/TestUtility';
|
||||
import FullKeyboardDemo from '../FullKeyboardDemo';
|
||||
|
||||
const testUtil = new TestUtility();
|
||||
|
||||
it('Demo will load', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
new FullKeyboardDemo();
|
||||
});
|
||||
|
||||
it('Demo onDOMLoaded will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new FullKeyboardDemo();
|
||||
|
||||
@@ -17,7 +15,7 @@ it('Demo onDOMLoaded will work', () => {
|
||||
});
|
||||
|
||||
it('Demo onChange will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new FullKeyboardDemo();
|
||||
|
||||
@@ -27,7 +25,7 @@ it('Demo onChange will work', () => {
|
||||
});
|
||||
|
||||
it('Demo onChange will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new FullKeyboardDemo();
|
||||
|
||||
@@ -37,7 +35,7 @@ it('Demo onChange will work', () => {
|
||||
});
|
||||
|
||||
it('Demo input change will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new FullKeyboardDemo();
|
||||
|
||||
@@ -49,7 +47,7 @@ it('Demo input change will work', () => {
|
||||
});
|
||||
|
||||
it('Demo handleShiftButton will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new FullKeyboardDemo();
|
||||
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
import TestUtility from '../../utils/TestUtility';
|
||||
import { setDOM } from '../../utils/TestUtility';
|
||||
import MultipleKeyboardsDestroyDemo from '../MultipleKeyboardsDestroyDemo';
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
const testUtil = new TestUtility();
|
||||
|
||||
it('Demo will load', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
new MultipleKeyboardsDestroyDemo();
|
||||
});
|
||||
|
||||
it('Demo onDOMLoaded will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new MultipleKeyboardsDestroyDemo();
|
||||
|
||||
@@ -20,7 +18,7 @@ it('Demo onDOMLoaded will work', () => {
|
||||
});
|
||||
|
||||
it('Demo onChange will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new MultipleKeyboardsDestroyDemo();
|
||||
|
||||
@@ -32,7 +30,7 @@ it('Demo onChange will work', () => {
|
||||
});
|
||||
|
||||
it('Demo onChange will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new MultipleKeyboardsDestroyDemo();
|
||||
|
||||
@@ -42,7 +40,7 @@ it('Demo onChange will work', () => {
|
||||
});
|
||||
|
||||
it('Demo input change will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new MultipleKeyboardsDestroyDemo();
|
||||
|
||||
@@ -57,7 +55,7 @@ it('Demo input change will work', () => {
|
||||
});
|
||||
|
||||
it('Demo handleShiftButton will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new MultipleKeyboardsDestroyDemo();
|
||||
|
||||
@@ -69,7 +67,7 @@ it('Demo handleShiftButton will work', () => {
|
||||
});
|
||||
|
||||
it('MultipleKeyboardsDestroyDemo will run all timers', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const demo = new MultipleKeyboardsDestroyDemo();
|
||||
jest.runAllTimers();
|
||||
|
||||
30
src/lib/@types/index.d.ts
vendored
30
src/lib/@types/index.d.ts
vendored
@@ -1,7 +1,5 @@
|
||||
declare module 'simple-keyboard' {
|
||||
interface KeyboardLayoutObject {
|
||||
default: string[];
|
||||
shift?: any;
|
||||
[key: string]: string[];
|
||||
}
|
||||
|
||||
@@ -188,6 +186,11 @@ declare module 'simple-keyboard' {
|
||||
* Module classes to be loaded by simple-keyboard.
|
||||
*/
|
||||
modules?: any[];
|
||||
|
||||
/**
|
||||
* Module options can have any format
|
||||
*/
|
||||
[name: string]: any;
|
||||
}
|
||||
|
||||
class Keyboard {
|
||||
@@ -210,6 +213,29 @@ declare module 'simple-keyboard' {
|
||||
*/
|
||||
caretPosition?: number;
|
||||
|
||||
|
||||
/**
|
||||
* caretPositionEnd
|
||||
*/
|
||||
caretPositionEnd?: number;
|
||||
|
||||
/**
|
||||
* Changes the internal caret position
|
||||
* @param {number} position The caret's start position
|
||||
* @param {number} positionEnd The caret's end position
|
||||
*/
|
||||
setCaretPosition(position: number, positionEnd?: number): void;
|
||||
|
||||
/**
|
||||
* Retrieves the internal caret position
|
||||
*/
|
||||
getCaretPosition(): number;
|
||||
|
||||
/**
|
||||
* Retrieves the internal end caret position
|
||||
*/
|
||||
getCaretPositionEnd(): number;
|
||||
|
||||
/**
|
||||
* Adds/Modifies an entry to the `buttonTheme`. Basically a way to add a class to a button.
|
||||
* @param {string} buttons List of buttons to select (separated by a space).
|
||||
|
||||
@@ -28,6 +28,7 @@ class SimpleKeyboard {
|
||||
this.utilities = new Utilities({
|
||||
getOptions: this.getOptions,
|
||||
getCaretPosition: this.getCaretPosition,
|
||||
getCaretPositionEnd: this.getCaretPositionEnd,
|
||||
dispatch: this.dispatch
|
||||
});
|
||||
|
||||
@@ -36,6 +37,11 @@ class SimpleKeyboard {
|
||||
*/
|
||||
this.caretPosition = null;
|
||||
|
||||
/**
|
||||
* Caret position end
|
||||
*/
|
||||
this.caretPositionEnd = null;
|
||||
|
||||
/**
|
||||
* Processing options
|
||||
*/
|
||||
@@ -219,6 +225,15 @@ class SimpleKeyboard {
|
||||
*/
|
||||
getOptions = () => this.options;
|
||||
getCaretPosition = () => this.caretPosition;
|
||||
getCaretPositionEnd = () => this.caretPositionEnd;
|
||||
|
||||
/**
|
||||
* Setters
|
||||
*/
|
||||
setCaretPosition(position, endPosition) {
|
||||
this.caretPosition = position;
|
||||
this.caretPositionEnd = endPosition || position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles clicks made to keyboard buttons
|
||||
@@ -244,7 +259,8 @@ class SimpleKeyboard {
|
||||
const updatedInput = this.utilities.getUpdatedInput(
|
||||
button,
|
||||
this.input[this.options.inputName],
|
||||
this.caretPosition
|
||||
this.caretPosition,
|
||||
this.caretPositionEnd
|
||||
);
|
||||
|
||||
if (
|
||||
@@ -270,11 +286,21 @@ class SimpleKeyboard {
|
||||
button,
|
||||
this.input[this.options.inputName],
|
||||
this.caretPosition,
|
||||
this.caretPositionEnd,
|
||||
true
|
||||
);
|
||||
|
||||
if (debug) console.log("Input changed:", this.input);
|
||||
|
||||
if (this.options.debug) {
|
||||
console.log(
|
||||
"Caret at: ",
|
||||
this.getCaretPosition(),
|
||||
this.getCaretPositionEnd(),
|
||||
`(${this.keyboardDOMClass})`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforce syncInstanceInputs, if set
|
||||
*/
|
||||
@@ -314,28 +340,32 @@ class SimpleKeyboard {
|
||||
*/
|
||||
if (e) e.target.classList.add(this.activeButtonClass);
|
||||
|
||||
if (this.holdInteractionTimeout) clearTimeout(this.holdInteractionTimeout);
|
||||
if (this.holdTimeout) clearTimeout(this.holdTimeout);
|
||||
|
||||
/**
|
||||
* @type {boolean} Whether the mouse is being held onKeyPress
|
||||
*/
|
||||
this.isMouseHold = true;
|
||||
|
||||
if (this.holdInteractionTimeout) clearTimeout(this.holdInteractionTimeout);
|
||||
|
||||
if (this.holdTimeout) clearTimeout(this.holdTimeout);
|
||||
|
||||
/**
|
||||
* @type {object} Time to wait until a key hold is detected
|
||||
*/
|
||||
if (!this.options.disableButtonHold) {
|
||||
this.holdTimeout = setTimeout(() => {
|
||||
if (
|
||||
this.isMouseHold &&
|
||||
((!button.includes("{") && !button.includes("}")) ||
|
||||
button === "{delete}" ||
|
||||
button === "{backspace}" ||
|
||||
button === "{bksp}" ||
|
||||
button === "{space}" ||
|
||||
button === "{tab}")
|
||||
(this.isMouseHold &&
|
||||
// TODO: This needs to be configurable through options
|
||||
((!button.includes("{") && !button.includes("}")) ||
|
||||
button === "{delete}" ||
|
||||
button === "{backspace}" ||
|
||||
button === "{bksp}" ||
|
||||
button === "{space}" ||
|
||||
button === "{tab}")) ||
|
||||
button === "{arrowright}" ||
|
||||
button === "{arrowleft}" ||
|
||||
button === "{arrowup}" ||
|
||||
button === "{arrowdown}"
|
||||
) {
|
||||
if (this.options.debug) console.log("Button held:", button);
|
||||
|
||||
@@ -350,15 +380,18 @@ class SimpleKeyboard {
|
||||
* Handles button mouseup
|
||||
*/
|
||||
handleButtonMouseUp(button) {
|
||||
/**
|
||||
* Remove active class
|
||||
*/
|
||||
this.recurseButtons(buttonElement => {
|
||||
buttonElement.classList.remove(this.activeButtonClass);
|
||||
});
|
||||
this.dispatch(instance => {
|
||||
/**
|
||||
* Remove active class
|
||||
*/
|
||||
instance.recurseButtons(buttonElement => {
|
||||
buttonElement.classList.remove(this.activeButtonClass);
|
||||
});
|
||||
|
||||
this.isMouseHold = false;
|
||||
if (this.holdInteractionTimeout) clearTimeout(this.holdInteractionTimeout);
|
||||
instance.isMouseHold = false;
|
||||
if (instance.holdInteractionTimeout)
|
||||
clearTimeout(instance.holdInteractionTimeout);
|
||||
});
|
||||
|
||||
/**
|
||||
* Calling onKeyReleased
|
||||
@@ -403,7 +436,7 @@ class SimpleKeyboard {
|
||||
syncInstanceInputs() {
|
||||
this.dispatch(instance => {
|
||||
instance.replaceInput(this.input);
|
||||
instance.caretPosition = this.caretPosition;
|
||||
instance.setCaretPosition(this.caretPosition, this.caretPositionEnd);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -418,7 +451,7 @@ class SimpleKeyboard {
|
||||
/**
|
||||
* Reset caretPosition
|
||||
*/
|
||||
this.caretPosition = 0;
|
||||
this.setCaretPosition(0);
|
||||
|
||||
/**
|
||||
* Enforce syncInstanceInputs, if set
|
||||
@@ -510,11 +543,11 @@ class SimpleKeyboard {
|
||||
/**
|
||||
* inputName changed. This requires a caretPosition reset
|
||||
*/
|
||||
// TODO: Review side-effects
|
||||
if (this.options.debug) {
|
||||
console.log("inputName changed. caretPosition reset.");
|
||||
}
|
||||
|
||||
this.caretPosition = null;
|
||||
this.setCaretPosition(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -708,6 +741,8 @@ class SimpleKeyboard {
|
||||
* Handles simple-keyboard event listeners
|
||||
*/
|
||||
setEventListeners() {
|
||||
const { useTouchEvents, useMouseEvents } = this.options;
|
||||
|
||||
/**
|
||||
* Only first instance should set the event listeners
|
||||
*/
|
||||
@@ -719,10 +754,42 @@ class SimpleKeyboard {
|
||||
/**
|
||||
* Event Listeners
|
||||
*/
|
||||
document.addEventListener("keyup", this.handleKeyUp);
|
||||
document.addEventListener("keydown", this.handleKeyDown);
|
||||
document.addEventListener("mouseup", this.handleMouseUp);
|
||||
document.addEventListener("touchend", this.handleTouchEnd);
|
||||
document.onkeyup = this.handleKeyUp;
|
||||
document.onkeydown = this.handleKeyDown;
|
||||
|
||||
/**
|
||||
* Pointer events
|
||||
*/
|
||||
if (
|
||||
this.utilities.pointerEventsSupported() &&
|
||||
!useTouchEvents &&
|
||||
!useMouseEvents
|
||||
) {
|
||||
document.onpointerdown = this.handlePointerDown;
|
||||
document.onpointerup = this.handlePointerUp;
|
||||
document.onpointercancel = this.handlePointerUp;
|
||||
|
||||
this.keyboardDOM.onpointerdown = this.handleKeyboardContainerMouseDown;
|
||||
|
||||
/**
|
||||
* Touch events
|
||||
*/
|
||||
} else if (useTouchEvents) {
|
||||
document.ontouchstart = this.handlePointerDown;
|
||||
document.ontouchend = this.handlePointerUp;
|
||||
document.ontouchcancel = this.handlePointerUp;
|
||||
|
||||
this.keyboardDOM.ontouchstart = this.handleKeyboardContainerMouseDown;
|
||||
|
||||
/**
|
||||
* Mouse events
|
||||
*/
|
||||
} else if (!useTouchEvents) {
|
||||
document.onmousedown = this.handlePointerDown;
|
||||
document.onmouseup = this.handlePointerUp;
|
||||
|
||||
this.keyboardDOM.onmousedown = this.handleKeyboardContainerMouseDown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -747,16 +814,17 @@ class SimpleKeyboard {
|
||||
}
|
||||
|
||||
/**
|
||||
* Event Handler: MouseUp
|
||||
* Event Handler: PointerDown
|
||||
*/
|
||||
handleMouseUp(event) {
|
||||
handlePointerDown(event) {
|
||||
this.caretEventHandler(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Event Handler: TouchEnd
|
||||
* Event Handler: PointerUp
|
||||
*/
|
||||
handleTouchEnd(event) {
|
||||
handlePointerUp(event) {
|
||||
this.handleButtonMouseUp();
|
||||
this.caretEventHandler(event);
|
||||
}
|
||||
|
||||
@@ -764,39 +832,50 @@ class SimpleKeyboard {
|
||||
* Called by {@link setEventListeners} when an event that warrants a cursor position update is triggered
|
||||
*/
|
||||
caretEventHandler(event) {
|
||||
if (this.options.disableCaretPositioning) {
|
||||
this.setCaretPosition(null);
|
||||
return;
|
||||
}
|
||||
|
||||
let targetTagName;
|
||||
|
||||
if (event.target.tagName) {
|
||||
targetTagName = event.target.tagName.toLowerCase();
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
this.dispatch(instance => {
|
||||
if (instance.isMouseHold) {
|
||||
instance.isMouseHold = false;
|
||||
}
|
||||
const isKeyboard =
|
||||
event.target === instance.keyboardDOM ||
|
||||
(event.target && instance.keyboardDOM.contains(event.target));
|
||||
|
||||
if (
|
||||
(targetTagName === "textarea" || targetTagName === "input") &&
|
||||
!instance.options.disableCaretPositioning
|
||||
) {
|
||||
// if (!this.isMouseHold) {
|
||||
// instance.isMouseHold = false;
|
||||
// }
|
||||
|
||||
if (targetTagName === "textarea" || targetTagName === "input") {
|
||||
/**
|
||||
* Tracks current cursor position
|
||||
* As keys are pressed, text will be added/removed at that position within the input.
|
||||
*/
|
||||
instance.caretPosition = event.target.selectionStart;
|
||||
instance.setCaretPosition(
|
||||
event.target.selectionStart,
|
||||
event.target.selectionEnd
|
||||
);
|
||||
|
||||
if (instance.options.debug) {
|
||||
console.log(
|
||||
"Caret at: ",
|
||||
event.target.selectionStart,
|
||||
event.target.tagName.toLowerCase(),
|
||||
instance.getCaretPosition(),
|
||||
instance.getCaretPositionEnd(),
|
||||
event && event.target.tagName.toLowerCase(),
|
||||
`(${instance.keyboardDOMClass})`
|
||||
);
|
||||
}
|
||||
} else if (instance.options.disableCaretPositioning) {
|
||||
/**
|
||||
* If we toggled off disableCaretPositioning, we must ensure caretPosition doesn't persist once reactivated.
|
||||
*/
|
||||
instance.caretPosition = null;
|
||||
|
||||
// TODO: Review side-effects
|
||||
} else if (!isKeyboard) {
|
||||
instance.setCaretPosition(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -821,18 +900,6 @@ class SimpleKeyboard {
|
||||
`Destroying simple-keyboard instance: ${this.currentInstanceName}`
|
||||
);
|
||||
|
||||
/**
|
||||
* Remove document listeners
|
||||
*/
|
||||
document.removeEventListener("keyup", this.handleKeyUp);
|
||||
document.removeEventListener("keydown", this.handleKeyDown);
|
||||
document.removeEventListener("mouseup", this.handleMouseUp);
|
||||
document.removeEventListener("touchend", this.handleTouchEnd);
|
||||
document.onpointerup = null;
|
||||
document.ontouchend = null;
|
||||
document.ontouchcancel = null;
|
||||
document.onmouseup = null;
|
||||
|
||||
/**
|
||||
* Remove buttons
|
||||
*/
|
||||
@@ -852,8 +919,6 @@ class SimpleKeyboard {
|
||||
};
|
||||
|
||||
this.recurseButtons(deleteButton);
|
||||
|
||||
this.recurseButtons = null;
|
||||
deleteButton = null;
|
||||
|
||||
/**
|
||||
@@ -868,12 +933,55 @@ class SimpleKeyboard {
|
||||
*/
|
||||
this.clear();
|
||||
|
||||
/**
|
||||
* Remove timouts
|
||||
*/
|
||||
/* istanbul ignore next */
|
||||
if (this.holdInteractionTimeout) clearTimeout(this.holdInteractionTimeout);
|
||||
/* istanbul ignore next */
|
||||
if (this.holdTimeout) clearTimeout(this.holdTimeout);
|
||||
|
||||
/**
|
||||
* Remove instance
|
||||
*/
|
||||
window["SimpleKeyboardInstances"][this.currentInstanceName] = null;
|
||||
delete window["SimpleKeyboardInstances"][this.currentInstanceName];
|
||||
|
||||
/**
|
||||
* Removing document listeners if there are no more instances
|
||||
*/
|
||||
if (!Object.keys(window["SimpleKeyboardInstances"]).length) {
|
||||
/**
|
||||
* Remove document listeners
|
||||
*/
|
||||
document.onkeydown = null;
|
||||
document.onkeyup = null;
|
||||
|
||||
document.onpointerdown = null;
|
||||
document.onpointerup = null;
|
||||
|
||||
document.onmousedown = null;
|
||||
document.onmouseup = null;
|
||||
|
||||
document.ontouchstart = null;
|
||||
document.ontouchend = null;
|
||||
document.ontouchcancel = null;
|
||||
|
||||
if (this.options.debug) {
|
||||
console.log(
|
||||
"Destroy: No instances remaining. Document listeners removed",
|
||||
window["SimpleKeyboardInstances"]
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (this.options.debug) {
|
||||
console.log(
|
||||
"Destroy: Instances remaining! Document listeners not removed",
|
||||
window["SimpleKeyboardInstances"]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset initialized flag
|
||||
*/
|
||||
@@ -1061,7 +1169,7 @@ class SimpleKeyboard {
|
||||
*/
|
||||
onModulesLoaded() {
|
||||
if (typeof this.options.onModulesLoaded === "function")
|
||||
this.options.onModulesLoaded();
|
||||
this.options.onModulesLoaded(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1280,12 +1388,15 @@ class SimpleKeyboard {
|
||||
*/
|
||||
const buttonHasContainerStart =
|
||||
!disableRowButtonContainers &&
|
||||
button.includes("[") &&
|
||||
button.length > 1;
|
||||
typeof button === "string" &&
|
||||
button.length > 1 &&
|
||||
button.indexOf("[") === 0;
|
||||
|
||||
const buttonHasContainerEnd =
|
||||
!disableRowButtonContainers &&
|
||||
button.includes("]") &&
|
||||
button.length > 1;
|
||||
typeof button === "string" &&
|
||||
button.length > 1 &&
|
||||
button.indexOf("]") === button.length - 1;
|
||||
|
||||
/**
|
||||
* Save container start index, if applicable
|
||||
@@ -1384,7 +1495,6 @@ class SimpleKeyboard {
|
||||
* Handle mouse events
|
||||
*/
|
||||
buttonDOM.onclick = () => {
|
||||
this.isMouseHold = false;
|
||||
this.handleButtonClicked(button);
|
||||
};
|
||||
buttonDOM.onmousedown = e => {
|
||||
@@ -1455,36 +1565,6 @@ class SimpleKeyboard {
|
||||
*/
|
||||
this.initialized = true;
|
||||
|
||||
/**
|
||||
* Handling parent events
|
||||
*/
|
||||
/* istanbul ignore next */
|
||||
if (
|
||||
this.utilities.pointerEventsSupported() &&
|
||||
!useTouchEvents &&
|
||||
!useMouseEvents
|
||||
) {
|
||||
document.onpointerup = () => this.handleButtonMouseUp();
|
||||
this.keyboardDOM.onpointerdown = e =>
|
||||
this.handleKeyboardContainerMouseDown(e);
|
||||
} else if (useTouchEvents) {
|
||||
/**
|
||||
* Handling ontouchend, ontouchcancel
|
||||
*/
|
||||
document.ontouchend = () => this.handleButtonMouseUp();
|
||||
document.ontouchcancel = () => this.handleButtonMouseUp();
|
||||
|
||||
this.keyboardDOM.ontouchstart = e =>
|
||||
this.handleKeyboardContainerMouseDown(e);
|
||||
} else if (!useTouchEvents) {
|
||||
/**
|
||||
* Handling mouseup
|
||||
*/
|
||||
document.onmouseup = () => this.handleButtonMouseUp();
|
||||
this.keyboardDOM.onmousedown = e =>
|
||||
this.handleKeyboardContainerMouseDown(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calling onInit
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import Keyboard from '../Keyboard';
|
||||
import TestUtility from '../../../utils/TestUtility';
|
||||
|
||||
const testUtil = new TestUtility();
|
||||
import { setDOM, clearDOM, testLayoutStdButtons, iterateButtons, triggerDocumentPointerUp, triggerDocumentPointerDown } from '../../../utils/TestUtility';
|
||||
|
||||
it('Keyboard will not render without target element', () => {
|
||||
try {
|
||||
@@ -14,7 +12,7 @@ it('Keyboard will not render without target element', () => {
|
||||
|
||||
it('Keyboard will run without options', () => {
|
||||
// Prepare target DOM element
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
// No options
|
||||
new Keyboard();
|
||||
@@ -22,21 +20,21 @@ it('Keyboard will run without options', () => {
|
||||
|
||||
it('Keyboard will run with empty options', () => {
|
||||
// Prepare target DOM element
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
// No options
|
||||
new Keyboard({});
|
||||
});
|
||||
|
||||
it('Keyboard will run with custom DOM target', () => {
|
||||
testUtil.setDOM("myTestDiv");
|
||||
setDOM("myTestDiv");
|
||||
|
||||
new Keyboard(".myTestDiv");
|
||||
expect(document.body.querySelector(".myTestDiv")).toBeDefined();
|
||||
});
|
||||
|
||||
it('Keyboard will run with debug option set', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
debug: true
|
||||
@@ -48,7 +46,7 @@ it('Keyboard will run with debug option set', () => {
|
||||
it('Keyboard will use touch events', () => {
|
||||
let touched = false
|
||||
|
||||
testUtil.clear()
|
||||
clearDOM();
|
||||
|
||||
document.body.innerHTML = `
|
||||
<div class="keyboard"></div>
|
||||
@@ -72,19 +70,19 @@ it('Keyboard will use touch events', () => {
|
||||
})
|
||||
|
||||
it('Keyboard standard buttons will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
const keyboard = new Keyboard({
|
||||
maxLength: {
|
||||
"default": 10
|
||||
}
|
||||
});
|
||||
|
||||
testUtil.testLayoutStdButtons(keyboard);
|
||||
testLayoutStdButtons(keyboard);
|
||||
});
|
||||
|
||||
|
||||
it('Keyboard shift buttons will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
keyboard.setOptions({
|
||||
@@ -92,18 +90,18 @@ it('Keyboard shift buttons will work', () => {
|
||||
maxLength: 42
|
||||
});
|
||||
|
||||
testUtil.testLayoutStdButtons(keyboard);
|
||||
testLayoutStdButtons(keyboard);
|
||||
});
|
||||
|
||||
it('Keyboard setOptions will work without a param', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
keyboard.setOptions();
|
||||
});
|
||||
|
||||
it('Keyboard empty buttons wont do anything as expected', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
layout: {
|
||||
@@ -118,7 +116,7 @@ it('Keyboard empty buttons wont do anything as expected', () => {
|
||||
});
|
||||
|
||||
it('Keyboard onKeyPress will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
let pressed = false;
|
||||
|
||||
@@ -135,13 +133,13 @@ it('Keyboard onKeyPress will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard standard function buttons will not change input', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
useButtonTag: true
|
||||
});
|
||||
|
||||
testUtil.iterateButtons((button) => {
|
||||
iterateButtons((button) => {
|
||||
if(button.getAttribute("data-skbtn") === "{shift}"){
|
||||
button.onclick();
|
||||
}
|
||||
@@ -151,7 +149,7 @@ it('Keyboard standard function buttons will not change input', () => {
|
||||
});
|
||||
|
||||
it('Keyboard syncInstanceInputs will work', () => {
|
||||
testUtil.clear();
|
||||
clearDOM();
|
||||
|
||||
document.body.innerHTML = `
|
||||
<div class="keyboard1"></div>
|
||||
@@ -180,7 +178,7 @@ it('Keyboard syncInstanceInputs will work', () => {
|
||||
keyboard1.getButtonElement("5").onclick();
|
||||
keyboard1.getButtonElement("6").onclick();
|
||||
|
||||
keyboard1.caretPosition = 1;
|
||||
keyboard1.setCaretPosition(1);
|
||||
|
||||
keyboard1.getButtonElement("2").onclick();
|
||||
keyboard1.getButtonElement("3").onclick();
|
||||
@@ -191,7 +189,7 @@ it('Keyboard syncInstanceInputs will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard onChange will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
let output = false;
|
||||
|
||||
@@ -208,7 +206,7 @@ it('Keyboard onChange will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard onChangeAll will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
let output;
|
||||
|
||||
@@ -225,7 +223,7 @@ it('Keyboard onChangeAll will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard clearInput will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -242,7 +240,7 @@ it('Keyboard clearInput will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard clearInput will work with syncInstanceInputs', () => {
|
||||
testUtil.clear();
|
||||
clearDOM();
|
||||
|
||||
document.body.innerHTML = `
|
||||
<div class="keyboard1"></div>
|
||||
@@ -269,7 +267,7 @@ it('Keyboard clearInput will work with syncInstanceInputs', () => {
|
||||
});
|
||||
|
||||
it('Keyboard setInput will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -279,7 +277,7 @@ it('Keyboard setInput will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard setInput will work with syncInstanceInputs', () => {
|
||||
testUtil.clear();
|
||||
clearDOM();
|
||||
|
||||
document.body.innerHTML = `
|
||||
<div class="keyboard1"></div>
|
||||
@@ -299,7 +297,7 @@ it('Keyboard setInput will work with syncInstanceInputs', () => {
|
||||
});
|
||||
|
||||
it('Keyboard dispatch will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
document.body.innerHTML = `
|
||||
<div class="keyboard1"></div>
|
||||
@@ -324,7 +322,7 @@ it('Keyboard dispatch will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard dispatch will not work without SimpleKeyboardInstances', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
document.body.innerHTML = `
|
||||
<div class="keyboard1"></div>
|
||||
@@ -355,7 +353,7 @@ it('Keyboard dispatch will not work without SimpleKeyboardInstances', () => {
|
||||
});
|
||||
|
||||
it('Keyboard addButtonTheme will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
keyboard.addButtonTheme("q", "test");
|
||||
@@ -364,7 +362,7 @@ it('Keyboard addButtonTheme will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard addButtonTheme will not work without params', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
const returnVal = keyboard.addButtonTheme();
|
||||
@@ -373,7 +371,7 @@ it('Keyboard addButtonTheme will not work without params', () => {
|
||||
});
|
||||
|
||||
it('Keyboard addButtonTheme will amend a buttonTheme', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
buttonTheme: [
|
||||
@@ -390,7 +388,7 @@ it('Keyboard addButtonTheme will amend a buttonTheme', () => {
|
||||
});
|
||||
|
||||
it('Keyboard addButtonTheme will create a buttonTheme', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
buttonTheme: [
|
||||
@@ -407,7 +405,7 @@ it('Keyboard addButtonTheme will create a buttonTheme', () => {
|
||||
});
|
||||
|
||||
it('Keyboard addButtonTheme will ignore a repeated buttonTheme', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
buttonTheme: [
|
||||
@@ -424,7 +422,7 @@ it('Keyboard addButtonTheme will ignore a repeated buttonTheme', () => {
|
||||
});
|
||||
|
||||
it('Keyboard addButtonTheme will amend a buttonTheme', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
buttonTheme: [
|
||||
@@ -442,7 +440,7 @@ it('Keyboard addButtonTheme will amend a buttonTheme', () => {
|
||||
|
||||
|
||||
it('Keyboard removeButtonTheme without params will remove all button themes', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
buttonTheme: [
|
||||
@@ -460,7 +458,7 @@ it('Keyboard removeButtonTheme without params will remove all button themes', ()
|
||||
|
||||
|
||||
it('Keyboard removeButtonTheme will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
buttonTheme: [
|
||||
@@ -477,7 +475,7 @@ it('Keyboard removeButtonTheme will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard removeButtonTheme will work wihtout a class', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
buttonTheme: [
|
||||
@@ -494,7 +492,7 @@ it('Keyboard removeButtonTheme will work wihtout a class', () => {
|
||||
});
|
||||
|
||||
it('Keyboard removeButtonTheme will do nothing without a button param', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
buttonTheme: [
|
||||
@@ -511,7 +509,7 @@ it('Keyboard removeButtonTheme will do nothing without a button param', () => {
|
||||
});
|
||||
|
||||
it('Keyboard removeButtonTheme does nothing if req button doesnt have a buttonTheme', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
buttonTheme: [
|
||||
@@ -528,7 +526,7 @@ it('Keyboard removeButtonTheme does nothing if req button doesnt have a buttonTh
|
||||
});
|
||||
|
||||
it('Keyboard removeButtonTheme does nothing if buttonTheme class does not exist', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
buttonTheme: [
|
||||
@@ -545,7 +543,7 @@ it('Keyboard removeButtonTheme does nothing if buttonTheme class does not exist'
|
||||
});
|
||||
|
||||
it('Keyboard removeButtonTheme does nothing if buttonTheme doesnt have the requested buttons', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
buttonTheme: [
|
||||
@@ -562,7 +560,7 @@ it('Keyboard removeButtonTheme does nothing if buttonTheme doesnt have the reque
|
||||
});
|
||||
|
||||
it('Keyboard getButtonElement will not return anything if empty match', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
layout: {
|
||||
@@ -577,7 +575,7 @@ it('Keyboard getButtonElement will not return anything if empty match', () => {
|
||||
});
|
||||
|
||||
it('Keyboard getButtonElement will return multiple matched buttons', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -585,60 +583,54 @@ it('Keyboard getButtonElement will return multiple matched buttons', () => {
|
||||
});
|
||||
|
||||
it('Keyboard will receive physical keyboard events', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
new Keyboard({
|
||||
debug: true,
|
||||
physicalKeyboardHighlight: true
|
||||
});
|
||||
|
||||
document.dispatchEvent(new KeyboardEvent('keyup', {
|
||||
document.onkeyup({
|
||||
charCode: 0,
|
||||
code: "KeyF",
|
||||
key: "f",
|
||||
which: 70,
|
||||
target: {
|
||||
tagName: "input"
|
||||
}
|
||||
}));
|
||||
target: document.createElement('input')
|
||||
});
|
||||
});
|
||||
|
||||
it('Keyboard caretEventHandler will detect input, textarea focus', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
const myInput = document.createElement('input');
|
||||
|
||||
keyboard.caretEventHandler({
|
||||
charCode: 0,
|
||||
code: "KeyF",
|
||||
key: "f",
|
||||
which: 70,
|
||||
target: {
|
||||
tagName: "input",
|
||||
selectionStart: 3
|
||||
}
|
||||
target: myInput
|
||||
});
|
||||
|
||||
expect(keyboard.caretPosition).toBe(3);
|
||||
expect(keyboard.getCaretPosition()).toBe(0);
|
||||
});
|
||||
|
||||
it('Keyboard caretEventHandler will not set caretPosition on disableCaretPositioning', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
const myInput = document.createElement('input');
|
||||
|
||||
keyboard.caretEventHandler({
|
||||
charCode: 0,
|
||||
code: "KeyF",
|
||||
key: "f",
|
||||
which: 70,
|
||||
target: {
|
||||
tagName: "input",
|
||||
selectionStart: 3
|
||||
}
|
||||
target: myInput
|
||||
});
|
||||
|
||||
expect(keyboard.caretPosition).toBe(3);
|
||||
expect(keyboard.getCaretPosition()).toBe(0);
|
||||
|
||||
keyboard.setOptions({
|
||||
disableCaretPositioning: true
|
||||
@@ -649,17 +641,14 @@ it('Keyboard caretEventHandler will not set caretPosition on disableCaretPositio
|
||||
code: "KeyF",
|
||||
key: "f",
|
||||
which: 70,
|
||||
target: {
|
||||
tagName: "input",
|
||||
selectionStart: 3
|
||||
}
|
||||
target: myInput
|
||||
});
|
||||
|
||||
expect(keyboard.caretPosition).toBeFalsy();
|
||||
expect(keyboard.getCaretPosition()).toBe(null);
|
||||
});
|
||||
|
||||
it('Keyboard caretEventHandler ignore positioning if input, textarea is blur', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -670,38 +659,39 @@ it('Keyboard caretEventHandler ignore positioning if input, textarea is blur', (
|
||||
code: "KeyF",
|
||||
key: "f",
|
||||
which: 70,
|
||||
target: {
|
||||
tagName: "div",
|
||||
selectionStart: 4
|
||||
}
|
||||
target: document.createElement('div')
|
||||
});
|
||||
|
||||
expect(keyboard.caretPosition).toBeFalsy();
|
||||
expect(keyboard.getCaretPosition()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('Keyboard caretEventHandler will work with debug', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
debug: true
|
||||
});
|
||||
|
||||
keyboard.input.default = "hello";
|
||||
keyboard.setCaretPosition(2)
|
||||
|
||||
expect(keyboard.getCaretPosition()).toBe(2);
|
||||
|
||||
const myInput = document.createElement('input');
|
||||
|
||||
keyboard.caretEventHandler({
|
||||
charCode: 0,
|
||||
code: "KeyF",
|
||||
key: "f",
|
||||
which: 70,
|
||||
target: {
|
||||
tagName: "input",
|
||||
selectionStart: 3
|
||||
}
|
||||
target: myInput
|
||||
});
|
||||
|
||||
expect(keyboard.caretPosition).toBe(3);
|
||||
expect(keyboard.getCaretPosition()).toBe(0);
|
||||
});
|
||||
|
||||
it('Keyboard onInit will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
let passed = false;
|
||||
|
||||
@@ -715,7 +705,7 @@ it('Keyboard onInit will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard onRender will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
let passed = false;
|
||||
|
||||
@@ -729,7 +719,7 @@ it('Keyboard onRender will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard buttonTheme that is invalid will be ignored and not throw', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
new Keyboard({
|
||||
buttonTheme: [
|
||||
@@ -742,7 +732,7 @@ it('Keyboard buttonTheme that is invalid will be ignored and not throw', () => {
|
||||
});
|
||||
|
||||
it('Keyboard buttonTheme buttons that are invalid will be ignored and not throw', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
new Keyboard({
|
||||
buttonTheme: [
|
||||
@@ -755,7 +745,7 @@ it('Keyboard buttonTheme buttons that are invalid will be ignored and not throw'
|
||||
});
|
||||
|
||||
it('Keyboard buttonTheme will be ignored if buttons param not a string', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
new Keyboard({
|
||||
buttonTheme: [
|
||||
@@ -770,7 +760,7 @@ it('Keyboard buttonTheme will be ignored if buttons param not a string', () => {
|
||||
});
|
||||
|
||||
it('Keyboard buttonTheme will be ignored if already added', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
new Keyboard({
|
||||
buttonTheme: [
|
||||
@@ -799,7 +789,7 @@ it('Keyboard buttonTheme will be ignored if already added', () => {
|
||||
});
|
||||
|
||||
it('Keyboard can set a module', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -814,7 +804,7 @@ it('Keyboard can set a module', () => {
|
||||
});
|
||||
|
||||
it('Keyboard registerModule will return current module tree', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -834,7 +824,7 @@ it('Keyboard registerModule will return current module tree', () => {
|
||||
});
|
||||
|
||||
it('Keyboard can set a module by amending the modules tree', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -855,7 +845,7 @@ it('Keyboard can set a module by amending the modules tree', () => {
|
||||
});
|
||||
|
||||
it('Keyboard will not retrieve an option for an inexistent module', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -863,7 +853,7 @@ it('Keyboard will not retrieve an option for an inexistent module', () => {
|
||||
});
|
||||
|
||||
it('Keyboard will get a list of modules', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -878,7 +868,7 @@ it('Keyboard will get a list of modules', () => {
|
||||
});
|
||||
|
||||
it('Keyboard loadModules will load a simple module', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
class myClass {
|
||||
init = (module) => {
|
||||
@@ -894,48 +884,48 @@ it('Keyboard loadModules will load a simple module', () => {
|
||||
});
|
||||
|
||||
it('Keyboard handleButtonMouseUp will set isMouseHold to false', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
keyboard.isMouseHold = true;
|
||||
|
||||
document.onmouseup();
|
||||
document.onmouseup({
|
||||
target: document.body
|
||||
});
|
||||
|
||||
expect(keyboard.isMouseHold).toBeFalsy();
|
||||
});
|
||||
|
||||
it('Keyboard handleButtonMouseUp clear holdInteractionTimeout', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
keyboard.isMouseHold = true;
|
||||
keyboard.holdInteractionTimeout = setTimeout(() => {}, 10000);
|
||||
|
||||
document.onmouseup();
|
||||
document.onmouseup({
|
||||
target: document.body
|
||||
});
|
||||
});
|
||||
|
||||
it('Keyboard handleButtonMouseDown will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
const keyboard = new Keyboard({ useMouseEvents: true });
|
||||
|
||||
keyboard.handleButtonMouseDown("q", {
|
||||
target: keyboard.getButtonElement("q"),
|
||||
preventDefault: () => {},
|
||||
stopPropagation: () => {}
|
||||
console.log(keyboard.getButtonElement("q"))
|
||||
keyboard.getButtonElement("q").onclick();
|
||||
|
||||
document.onmouseup({
|
||||
target: document.body
|
||||
});
|
||||
|
||||
var clickEvent = document.createEvent('MouseEvents');
|
||||
clickEvent.initEvent('mousedown', true, true);
|
||||
keyboard.getButtonElement("q").dispatchEvent(clickEvent);
|
||||
document.onmouseup();
|
||||
|
||||
});
|
||||
|
||||
it('Keyboard handleButtonMouseDown will work with preventMouseDownDefault', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -947,15 +937,15 @@ it('Keyboard handleButtonMouseDown will work with preventMouseDownDefault', () =
|
||||
stopPropagation: () => {}
|
||||
});
|
||||
|
||||
var clickEvent = document.createEvent('MouseEvents');
|
||||
clickEvent.initEvent('mousedown', true, true);
|
||||
keyboard.getButtonElement("q").dispatchEvent(clickEvent);
|
||||
document.onmouseup();
|
||||
keyboard.getButtonElement("q").onclick();
|
||||
document.onmouseup({
|
||||
target: document.body
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('Keyboard onModulesLoaded will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
class myClass {
|
||||
init = (module) => {
|
||||
@@ -978,7 +968,7 @@ it('Keyboard onModulesLoaded will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard inputPattern will work globally', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
inputPattern: /^\d+$/,
|
||||
@@ -995,7 +985,7 @@ it('Keyboard inputPattern will work globally', () => {
|
||||
});
|
||||
|
||||
it('Keyboard inputPattern will work by input name', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
debug: true,
|
||||
@@ -1022,7 +1012,7 @@ it('Keyboard inputPattern will work by input name', () => {
|
||||
});
|
||||
|
||||
it('Keyboard processAutoTouchEvents will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
navigator.maxTouchPoints = true;
|
||||
|
||||
@@ -1034,7 +1024,7 @@ it('Keyboard processAutoTouchEvents will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard processAutoTouchEvents will work with debugging enabled', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
navigator.maxTouchPoints = true;
|
||||
|
||||
@@ -1047,7 +1037,7 @@ it('Keyboard processAutoTouchEvents will work with debugging enabled', () => {
|
||||
});
|
||||
|
||||
it('Keyboard beforeFirstRender method will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
let timesCalled = 0;
|
||||
|
||||
@@ -1068,7 +1058,7 @@ it('Keyboard beforeFirstRender method will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard beforeFirstRender will show PointerEvents warning', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
let timesCalled = 0;
|
||||
|
||||
@@ -1085,7 +1075,7 @@ it('Keyboard beforeFirstRender will show PointerEvents warning', () => {
|
||||
});
|
||||
|
||||
it('Keyboard beforeRender method will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
let timesCalled = 0;
|
||||
|
||||
@@ -1106,7 +1096,7 @@ it('Keyboard beforeRender method will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard parseRowDOMContainers will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
layout: {
|
||||
@@ -1139,7 +1129,7 @@ it('Keyboard parseRowDOMContainers will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard parseRowDOMContainers will ignore empty rows', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
let failed = false;
|
||||
|
||||
@@ -1157,7 +1147,7 @@ it('Keyboard parseRowDOMContainers will ignore empty rows', () => {
|
||||
|
||||
|
||||
it('Keyboard parseRowDOMContainers will ignore missing endIndex or endIndex before startIndex', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
new Keyboard({
|
||||
layout: {
|
||||
@@ -1174,7 +1164,7 @@ it('Keyboard parseRowDOMContainers will ignore missing endIndex or endIndex befo
|
||||
});
|
||||
|
||||
it('Keyboard disableRowButtonContainers will bypass parseRowDOMContainers', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
new Keyboard({
|
||||
disableRowButtonContainers: true,
|
||||
@@ -1202,16 +1192,16 @@ it('Keyboard disableRowButtonContainers will bypass parseRowDOMContainers', () =
|
||||
});
|
||||
|
||||
it('Keyboard inputName change will trigget caretPosition reset', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
keyboard.caretPosition = 0;
|
||||
keyboard.setCaretPosition(0);
|
||||
|
||||
keyboard.getButtonElement("q").onpointerdown();
|
||||
keyboard.getButtonElement("1").onpointerdown();
|
||||
|
||||
expect(keyboard.caretPosition).toBe(2);
|
||||
expect(keyboard.getCaretPosition()).toBe(2);
|
||||
|
||||
keyboard.setOptions({
|
||||
inputName: "myInput"
|
||||
@@ -1221,19 +1211,34 @@ it('Keyboard inputName change will trigget caretPosition reset', () => {
|
||||
keyboard.getButtonElement("1").onpointerdown();
|
||||
keyboard.getButtonElement("b").onpointerdown();
|
||||
|
||||
expect(keyboard.caretPosition).toBe(null);
|
||||
expect(keyboard.getCaretPosition()).toBe(null);
|
||||
});
|
||||
|
||||
it('Keyboard destroy will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
keyboard.destroy();
|
||||
expect(keyboard.keyboardDOM.innerHTML).toBe("");
|
||||
|
||||
expect(document.onkeydown).toBe(null);
|
||||
expect(document.onkeyup).toBe(null);
|
||||
|
||||
expect(document.onpointerdown).toBe(null);
|
||||
expect(document.onpointerup).toBe(null);
|
||||
|
||||
expect(document.onmousedown).toBe(null);
|
||||
expect(document.onmouseup).toBe(null);
|
||||
|
||||
expect(document.ontouchstart).toBe(null);
|
||||
expect(document.ontouchend).toBe(null);
|
||||
expect(document.ontouchcancel).toBe(null);
|
||||
|
||||
expect(keyboard.initialized).toBe(false);
|
||||
});
|
||||
|
||||
it('Keyboard destroy will work with debug option', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({ debug: true });
|
||||
keyboard.destroy();
|
||||
@@ -1241,7 +1246,7 @@ it('Keyboard destroy will work with debug option', () => {
|
||||
});
|
||||
|
||||
it('Keyboard disableButtonHold will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
disableButtonHold: true
|
||||
@@ -1251,39 +1256,33 @@ it('Keyboard disableButtonHold will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard caretEventHandler will be triggered on mouseup and ontouchend', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
disableCaretPositioning: true
|
||||
});
|
||||
|
||||
keyboard.caretPosition = 6;
|
||||
keyboard.setCaretPosition(6);
|
||||
|
||||
document.dispatchEvent(new MouseEvent('mouseup', {
|
||||
target: {
|
||||
tagName: "input"
|
||||
}
|
||||
}));
|
||||
expect(keyboard.getCaretPosition()).toBe(6);
|
||||
|
||||
expect(keyboard.caretPosition).toBe(null);
|
||||
const event = {
|
||||
target: document.body
|
||||
};
|
||||
|
||||
triggerDocumentPointerUp(event);
|
||||
|
||||
expect(keyboard.getCaretPosition()).toBe(null);
|
||||
|
||||
keyboard.setOptions({
|
||||
disableCaretPositioning: false
|
||||
})
|
||||
|
||||
keyboard.caretPosition = 10;
|
||||
|
||||
document.dispatchEvent(new TouchEvent('touchend', {
|
||||
target: {
|
||||
tagName: "input"
|
||||
}
|
||||
}));
|
||||
|
||||
expect(keyboard.caretPosition).toBe(10);
|
||||
keyboard.setCaretPosition(10);
|
||||
});
|
||||
|
||||
it('Keyboard onKeyReleased will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
let pressed = false;
|
||||
let firedTimes = 0;
|
||||
@@ -1307,7 +1306,7 @@ it('Keyboard onKeyReleased will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard buttonAttribute will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
new Keyboard({
|
||||
buttonAttributes: [
|
||||
@@ -1321,7 +1320,7 @@ it('Keyboard buttonAttribute will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard buttonAttribute will warn about invalid entries', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
new Keyboard({
|
||||
buttonAttributes: [
|
||||
@@ -1334,7 +1333,7 @@ it('Keyboard buttonAttribute will warn about invalid entries', () => {
|
||||
});
|
||||
|
||||
it('Keyboard recurseButtons will not work without a valid param', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
const keyboard = new Keyboard();
|
||||
expect(keyboard.recurseButtons()).toBe(false);
|
||||
});
|
||||
@@ -1360,4 +1359,38 @@ it('Keyboard will work with a DOM element param with class', () => {
|
||||
} catch (e) {
|
||||
expect(true).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it('Keyboard handleKeyboardContainerMouseDown will work', () => {
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
keyboard.keyboardDOM.onpointerdown();
|
||||
});
|
||||
|
||||
it('Keyboard handleKeyboardContainerMouseDown will respect preventMouseDownDefault', () => {
|
||||
setDOM();
|
||||
|
||||
let works = false;
|
||||
const keyboard = new Keyboard({ preventMouseDownDefault: true });
|
||||
keyboard.keyboardDOM.onpointerdown({ preventDefault: () => {
|
||||
works = true
|
||||
}});
|
||||
|
||||
expect(works).toBe(true);
|
||||
});
|
||||
|
||||
it('Keyboard handlePointerDown will work', () => {
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
keyboard.setCaretPosition(3);
|
||||
expect(keyboard.getCaretPosition()).toBe(3);
|
||||
|
||||
triggerDocumentPointerDown({
|
||||
target: document.body
|
||||
})
|
||||
|
||||
expect(keyboard.getCaretPosition()).toBe(null);
|
||||
});
|
||||
@@ -31,9 +31,9 @@ class PhysicalKeyboard {
|
||||
|
||||
if (buttonDOM) {
|
||||
buttonDOM.style.backgroundColor =
|
||||
options.physicalKeyboardHighlightBgColor || "#9ab4d0";
|
||||
options.physicalKeyboardHighlightBgColor || "#dadce4";
|
||||
buttonDOM.style.color =
|
||||
options.physicalKeyboardHighlightTextColor || "white";
|
||||
options.physicalKeyboardHighlightTextColor || "black";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,9 +5,10 @@ class Utilities {
|
||||
/**
|
||||
* Creates an instance of the Utility service
|
||||
*/
|
||||
constructor({ getOptions, getCaretPosition, dispatch }) {
|
||||
constructor({ getOptions, getCaretPosition, getCaretPositionEnd, dispatch }) {
|
||||
this.getOptions = getOptions;
|
||||
this.getCaretPosition = getCaretPosition;
|
||||
this.getCaretPositionEnd = getCaretPositionEnd;
|
||||
this.dispatch = dispatch;
|
||||
|
||||
/**
|
||||
@@ -125,19 +126,28 @@ class Utilities {
|
||||
* @param {string} button The button's layout name
|
||||
* @param {string} input The input string
|
||||
* @param {number} caretPos The cursor's current position
|
||||
* @param {number} caretPosEnd The cursor's current end position
|
||||
* @param {boolean} moveCaret Whether to update simple-keyboard's cursor
|
||||
*/
|
||||
getUpdatedInput(button, input, caretPos, moveCaret) {
|
||||
getUpdatedInput(
|
||||
button,
|
||||
input,
|
||||
caretPos,
|
||||
caretPosEnd = caretPos,
|
||||
moveCaret = false
|
||||
) {
|
||||
const options = this.getOptions();
|
||||
const commonParams = [caretPos, caretPosEnd, moveCaret];
|
||||
|
||||
let output = input;
|
||||
|
||||
if (
|
||||
(button === "{bksp}" || button === "{backspace}") &&
|
||||
output.length > 0
|
||||
) {
|
||||
output = this.removeAt(output, caretPos, moveCaret);
|
||||
output = this.removeAt(output, ...commonParams);
|
||||
} else if (button === "{space}")
|
||||
output = this.addStringAt(output, " ", caretPos, moveCaret);
|
||||
output = this.addStringAt(output, " ", ...commonParams);
|
||||
else if (
|
||||
button === "{tab}" &&
|
||||
!(
|
||||
@@ -145,12 +155,12 @@ class Utilities {
|
||||
options.tabCharOnTab === false
|
||||
)
|
||||
) {
|
||||
output = this.addStringAt(output, "\t", caretPos, moveCaret);
|
||||
output = this.addStringAt(output, "\t", ...commonParams);
|
||||
} else if (
|
||||
(button === "{enter}" || button === "{numpadenter}") &&
|
||||
options.newLineOnEnter
|
||||
)
|
||||
output = this.addStringAt(output, "\n", caretPos, moveCaret);
|
||||
output = this.addStringAt(output, "\n", ...commonParams);
|
||||
else if (
|
||||
button.includes("numpad") &&
|
||||
Number.isInteger(Number(button[button.length - 2]))
|
||||
@@ -158,23 +168,22 @@ class Utilities {
|
||||
output = this.addStringAt(
|
||||
output,
|
||||
button[button.length - 2],
|
||||
caretPos,
|
||||
moveCaret
|
||||
...commonParams
|
||||
);
|
||||
} else if (button === "{numpaddivide}")
|
||||
output = this.addStringAt(output, "/", caretPos, moveCaret);
|
||||
output = this.addStringAt(output, "/", ...commonParams);
|
||||
else if (button === "{numpadmultiply}")
|
||||
output = this.addStringAt(output, "*", caretPos, moveCaret);
|
||||
output = this.addStringAt(output, "*", ...commonParams);
|
||||
else if (button === "{numpadsubtract}")
|
||||
output = this.addStringAt(output, "-", caretPos, moveCaret);
|
||||
output = this.addStringAt(output, "-", ...commonParams);
|
||||
else if (button === "{numpadadd}")
|
||||
output = this.addStringAt(output, "+", caretPos, moveCaret);
|
||||
output = this.addStringAt(output, "+", ...commonParams);
|
||||
else if (button === "{numpaddecimal}")
|
||||
output = this.addStringAt(output, ".", caretPos, moveCaret);
|
||||
output = this.addStringAt(output, ".", ...commonParams);
|
||||
else if (button === "{" || button === "}")
|
||||
output = this.addStringAt(output, button, caretPos, moveCaret);
|
||||
output = this.addStringAt(output, button, ...commonParams);
|
||||
else if (!button.includes("{") && !button.includes("}"))
|
||||
output = this.addStringAt(output, button, caretPos, moveCaret);
|
||||
output = this.addStringAt(output, button, ...commonParams);
|
||||
|
||||
return output;
|
||||
}
|
||||
@@ -189,7 +198,7 @@ class Utilities {
|
||||
const newCaretPos = this.updateCaretPosAction(length, minus);
|
||||
|
||||
this.dispatch(instance => {
|
||||
instance.caretPosition = newCaretPos;
|
||||
instance.setCaretPosition(newCaretPos);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -220,17 +229,23 @@ class Utilities {
|
||||
* Adds a string to the input at a given position
|
||||
*
|
||||
* @param {string} source The source input
|
||||
* @param {string} string The string to add
|
||||
* @param {string} str The string to add
|
||||
* @param {number} position The (cursor) position where the string should be added
|
||||
* @param {boolean} moveCaret Whether to update simple-keyboard's cursor
|
||||
*/
|
||||
addStringAt(source, string, position, moveCaret) {
|
||||
addStringAt(
|
||||
source,
|
||||
str,
|
||||
position = source.length,
|
||||
positionEnd = source.length,
|
||||
moveCaret = false
|
||||
) {
|
||||
let output;
|
||||
|
||||
if (!position && position !== 0) {
|
||||
output = source + string;
|
||||
output = source + str;
|
||||
} else {
|
||||
output = [source.slice(0, position), string, source.slice(position)].join(
|
||||
output = [source.slice(0, position), str, source.slice(positionEnd)].join(
|
||||
""
|
||||
);
|
||||
|
||||
@@ -238,7 +253,7 @@ class Utilities {
|
||||
* Avoid caret position change when maxLength is set
|
||||
*/
|
||||
if (!this.isMaxLengthReached()) {
|
||||
if (moveCaret) this.updateCaretPos(string.length);
|
||||
if (moveCaret) this.updateCaretPos(str.length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,43 +267,56 @@ class Utilities {
|
||||
* @param {number} position The (cursor) position from where the characters should be removed
|
||||
* @param {boolean} moveCaret Whether to update simple-keyboard's cursor
|
||||
*/
|
||||
removeAt(source, position, moveCaret) {
|
||||
const caretPosition = this.getCaretPosition();
|
||||
|
||||
if (caretPosition === 0) {
|
||||
removeAt(
|
||||
source,
|
||||
position = source.length,
|
||||
positionEnd = source.length,
|
||||
moveCaret = false
|
||||
) {
|
||||
if (position === 0 && positionEnd === 0) {
|
||||
return source;
|
||||
}
|
||||
|
||||
let output;
|
||||
let prevTwoChars;
|
||||
let emojiMatched;
|
||||
const emojiMatchedReg = /([\uD800-\uDBFF][\uDC00-\uDFFF])/g;
|
||||
|
||||
/**
|
||||
* Emojis are made out of two characters, so we must take a custom approach to trim them.
|
||||
* For more info: https://mathiasbynens.be/notes/javascript-unicode
|
||||
*/
|
||||
if (position && position >= 0) {
|
||||
prevTwoChars = source.substring(position - 2, position);
|
||||
emojiMatched = prevTwoChars.match(emojiMatchedReg);
|
||||
if (position === positionEnd) {
|
||||
let prevTwoChars;
|
||||
let emojiMatched;
|
||||
const emojiMatchedReg = /([\uD800-\uDBFF][\uDC00-\uDFFF])/g;
|
||||
|
||||
if (emojiMatched) {
|
||||
output = source.substr(0, position - 2) + source.substr(position);
|
||||
if (moveCaret) this.updateCaretPos(2, true);
|
||||
/**
|
||||
* Emojis are made out of two characters, so we must take a custom approach to trim them.
|
||||
* For more info: https://mathiasbynens.be/notes/javascript-unicode
|
||||
*/
|
||||
if (position && position >= 0) {
|
||||
prevTwoChars = source.substring(position - 2, position);
|
||||
emojiMatched = prevTwoChars.match(emojiMatchedReg);
|
||||
|
||||
if (emojiMatched) {
|
||||
output = source.substr(0, position - 2) + source.substr(position);
|
||||
if (moveCaret) this.updateCaretPos(2, true);
|
||||
} else {
|
||||
output = source.substr(0, position - 1) + source.substr(position);
|
||||
if (moveCaret) this.updateCaretPos(1, true);
|
||||
}
|
||||
} else {
|
||||
output = source.substr(0, position - 1) + source.substr(position);
|
||||
if (moveCaret) this.updateCaretPos(1, true);
|
||||
prevTwoChars = source.slice(-2);
|
||||
emojiMatched = prevTwoChars.match(emojiMatchedReg);
|
||||
|
||||
if (emojiMatched) {
|
||||
output = source.slice(0, -2);
|
||||
if (moveCaret) this.updateCaretPos(2, true);
|
||||
} else {
|
||||
output = source.slice(0, -1);
|
||||
if (moveCaret) this.updateCaretPos(1, true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
prevTwoChars = source.slice(-2);
|
||||
emojiMatched = prevTwoChars.match(emojiMatchedReg);
|
||||
|
||||
if (emojiMatched) {
|
||||
output = source.slice(0, -2);
|
||||
if (moveCaret) this.updateCaretPos(2, true);
|
||||
} else {
|
||||
output = source.slice(0, -1);
|
||||
if (moveCaret) this.updateCaretPos(1, true);
|
||||
output = source.slice(0, position) + source.slice(positionEnd);
|
||||
if (moveCaret) {
|
||||
this.dispatch(instance => {
|
||||
instance.setCaretPosition(position);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,17 +417,17 @@ class Utilities {
|
||||
/**
|
||||
* Transforms an arbitrary string to camelCase
|
||||
*
|
||||
* @param {string} string The string to transform.
|
||||
* @param {string} str The string to transform.
|
||||
*/
|
||||
camelCase(string) {
|
||||
if (!string) return false;
|
||||
camelCase(str) {
|
||||
if (!str) return false;
|
||||
|
||||
return string
|
||||
return str
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
.split(/[.\-_\s]/g)
|
||||
.reduce((string, word) =>
|
||||
word.length ? string + word[0].toUpperCase() + word.slice(1) : string
|
||||
.reduce((str, word) =>
|
||||
word.length ? str + word[0].toUpperCase() + word.slice(1) : str
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import Keyboard from '../../components/Keyboard';
|
||||
import TestUtility from '../../../utils/TestUtility';
|
||||
|
||||
const testUtil = new TestUtility();
|
||||
import { setDOM } from '../../../utils/TestUtility';
|
||||
|
||||
it('PhysicalKeyboard keydown will be handled with physicalKeyboardHighlight', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
new Keyboard({
|
||||
physicalKeyboardHighlight: true
|
||||
@@ -20,7 +18,7 @@ it('PhysicalKeyboard keydown will be handled with physicalKeyboardHighlight', ()
|
||||
});
|
||||
|
||||
it('PhysicalKeyboard keydown will be handled without physicalKeyboardHighlight', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
new Keyboard({
|
||||
physicalKeyboardHighlight: false
|
||||
@@ -36,7 +34,7 @@ it('PhysicalKeyboard keydown will be handled without physicalKeyboardHighlight',
|
||||
});
|
||||
|
||||
it('PhysicalKeyboard keydown will not style non-existent buttons', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
new Keyboard({
|
||||
physicalKeyboardHighlight: true
|
||||
@@ -52,7 +50,7 @@ it('PhysicalKeyboard keydown will not style non-existent buttons', () => {
|
||||
});
|
||||
|
||||
it('PhysicalKeyboard keyup will be handled with physicalKeyboardHighlight', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
new Keyboard({
|
||||
physicalKeyboardHighlight: true
|
||||
@@ -68,7 +66,7 @@ it('PhysicalKeyboard keyup will be handled with physicalKeyboardHighlight', () =
|
||||
});
|
||||
|
||||
it('PhysicalKeyboard keyup will be handle special buttons', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
new Keyboard({
|
||||
physicalKeyboardHighlight: true
|
||||
@@ -84,7 +82,7 @@ it('PhysicalKeyboard keyup will be handle special buttons', () => {
|
||||
});
|
||||
|
||||
it('PhysicalKeyboard keyup will not style non-existent buttons', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
new Keyboard({
|
||||
physicalKeyboardHighlight: true,
|
||||
@@ -101,7 +99,7 @@ it('PhysicalKeyboard keyup will not style non-existent buttons', () => {
|
||||
});
|
||||
|
||||
it('PhysicalKeyboard will work with F1-F12 keys', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
new Keyboard({
|
||||
physicalKeyboardHighlight: true,
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import Keyboard from '../../components/Keyboard';
|
||||
import TestUtility from '../../../utils/TestUtility';
|
||||
|
||||
const testUtil = new TestUtility();
|
||||
import { setDOM, clearDOM, testLayoutFctButtons } from '../../../utils/TestUtility';
|
||||
|
||||
it('Keyboard mergeDisplay will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
mergeDisplay: true,
|
||||
@@ -17,17 +15,17 @@ it('Keyboard mergeDisplay will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard function buttons will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
new Keyboard();
|
||||
|
||||
testUtil.testLayoutFctButtons((fctBtnCount, fctBtnHasOnclickCount) => {
|
||||
testLayoutFctButtons((fctBtnCount, fctBtnHasOnclickCount) => {
|
||||
expect(fctBtnCount).toBe(fctBtnHasOnclickCount);
|
||||
});
|
||||
});
|
||||
|
||||
it('Keyboard {bksp} button will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -37,7 +35,7 @@ it('Keyboard {bksp} button will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard {space} button will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -47,7 +45,7 @@ it('Keyboard {space} button will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard {tab} button will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -57,7 +55,7 @@ it('Keyboard {tab} button will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard {tab} button will work with tabCharOnTab:false', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
tabCharOnTab: false
|
||||
@@ -69,7 +67,7 @@ it('Keyboard {tab} button will work with tabCharOnTab:false', () => {
|
||||
});
|
||||
|
||||
it('Keyboard {enter} button will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -79,7 +77,7 @@ it('Keyboard {enter} button will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard {enter} button will work with newLineOnEnter:true', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
newLineOnEnter: true
|
||||
@@ -91,7 +89,7 @@ it('Keyboard {enter} button will work with newLineOnEnter:true', () => {
|
||||
});
|
||||
|
||||
it('Keyboard {numpadX} buttons will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -102,7 +100,7 @@ it('Keyboard {numpadX} buttons will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard {numpaddivide} button will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -112,7 +110,7 @@ it('Keyboard {numpaddivide} button will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard {numpadmultiply} button will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -122,7 +120,7 @@ it('Keyboard {numpadmultiply} button will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard {numpadsubtract} button will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -132,7 +130,7 @@ it('Keyboard {numpadsubtract} button will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard {numpadadd} button will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -142,7 +140,7 @@ it('Keyboard {numpadadd} button will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard {numpadadd} button will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -152,7 +150,7 @@ it('Keyboard {numpadadd} button will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard {numpaddecimal} button will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -162,7 +160,7 @@ it('Keyboard {numpaddecimal} button will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard custom function buttons will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
layout: {
|
||||
@@ -179,7 +177,7 @@ it('Keyboard custom function buttons will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard "{" button will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -189,7 +187,7 @@ it('Keyboard "{" button will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard "}" button will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -199,7 +197,7 @@ it('Keyboard "}" button will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard standard button will affect input', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
@@ -211,42 +209,42 @@ it('Keyboard standard button will affect input', () => {
|
||||
});
|
||||
|
||||
it('Keyboard updateCaretPos will work with minus', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
syncInstanceInputs: true
|
||||
});
|
||||
|
||||
keyboard.caretPosition = 5;
|
||||
keyboard.setCaretPosition(5);
|
||||
keyboard.utilities.updateCaretPos(2, true);
|
||||
|
||||
expect(keyboard.caretPosition).toBe(3);
|
||||
});
|
||||
|
||||
it('Keyboard updateCaretPos will work with minus', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
keyboard.caretPosition = 5;
|
||||
keyboard.setCaretPosition(5);
|
||||
keyboard.utilities.updateCaretPos(2, true);
|
||||
|
||||
expect(keyboard.caretPosition).toBe(3);
|
||||
});
|
||||
|
||||
it('Keyboard updateCaretPos will work with plus', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
keyboard.caretPosition = 5;
|
||||
keyboard.setCaretPosition(5);
|
||||
keyboard.utilities.updateCaretPos(2);
|
||||
|
||||
expect(keyboard.caretPosition).toBe(7);
|
||||
});
|
||||
|
||||
it('Keyboard addStringAt will work with debug', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
debug: true
|
||||
@@ -258,14 +256,14 @@ it('Keyboard addStringAt will work with debug', () => {
|
||||
});
|
||||
|
||||
it('Keyboard addStringAt will work with position', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
debug: true
|
||||
});
|
||||
|
||||
keyboard.setInput("test");
|
||||
keyboard.caretPosition = 4;
|
||||
keyboard.setCaretPosition(5);
|
||||
|
||||
keyboard.getButtonElement("q").onclick();
|
||||
|
||||
@@ -273,7 +271,7 @@ it('Keyboard addStringAt will work with position', () => {
|
||||
});
|
||||
|
||||
it('Keyboard addStringAt will respect maxLength', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
debug: true,
|
||||
@@ -281,16 +279,17 @@ it('Keyboard addStringAt will respect maxLength', () => {
|
||||
});
|
||||
|
||||
keyboard.setInput("test");
|
||||
keyboard.caretPosition = 4;
|
||||
|
||||
keyboard.setCaretPosition(4);
|
||||
|
||||
keyboard.utilities.handleMaxLength(keyboard.input, "testq")
|
||||
keyboard.utilities.addStringAt("test", "q", 4);
|
||||
keyboard.utilities.addStringAt("test", "q", 4, 4);
|
||||
|
||||
expect(keyboard.caretPosition).toBe(4);
|
||||
});
|
||||
|
||||
it('Keyboard handleMaxLength will exit out on same updatedInput', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
debug: true
|
||||
@@ -304,7 +303,7 @@ it('Keyboard handleMaxLength will exit out on same updatedInput', () => {
|
||||
});
|
||||
|
||||
it('Keyboard handleMaxLength will work with object maxLength', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
maxLength: {
|
||||
@@ -320,7 +319,7 @@ it('Keyboard handleMaxLength will work with object maxLength', () => {
|
||||
});
|
||||
|
||||
it('Keyboard handleMaxLength will work with object maxLength and debug', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
maxLength: {
|
||||
@@ -337,7 +336,7 @@ it('Keyboard handleMaxLength will work with object maxLength and debug', () => {
|
||||
});
|
||||
|
||||
it('Keyboard handleMaxLength will return false if obj maxLength not reached', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
maxLength: {
|
||||
@@ -354,7 +353,7 @@ it('Keyboard handleMaxLength will return false if obj maxLength not reached', ()
|
||||
|
||||
|
||||
it('Keyboard handleMaxLength will work without debug', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
maxLength: 4
|
||||
@@ -369,7 +368,7 @@ it('Keyboard handleMaxLength will work without debug', () => {
|
||||
|
||||
|
||||
it('Keyboard handleMaxLength will work with numeric maxLength', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
maxLength: 3
|
||||
@@ -383,7 +382,7 @@ it('Keyboard handleMaxLength will work with numeric maxLength', () => {
|
||||
});
|
||||
|
||||
it('Keyboard handleMaxLength wont work with non numeric or object maxLength', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
maxLength: "wrong"
|
||||
@@ -397,7 +396,7 @@ it('Keyboard handleMaxLength wont work with non numeric or object maxLength', ()
|
||||
});
|
||||
|
||||
it('Keyboard handleMaxLength wont work with non numeric or object maxLength (with debug)', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
maxLength: "wrong",
|
||||
@@ -412,7 +411,7 @@ it('Keyboard handleMaxLength wont work with non numeric or object maxLength (wit
|
||||
});
|
||||
|
||||
it('Keyboard isMaxLengthReached will work', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
maxLength: 5
|
||||
@@ -424,70 +423,165 @@ it('Keyboard isMaxLengthReached will work', () => {
|
||||
});
|
||||
|
||||
it('Keyboard removeAt will exit out on caretPosition:0', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
keyboard.setInput("test");
|
||||
keyboard.caretPosition = 0;
|
||||
|
||||
keyboard.setCaretPosition(0);
|
||||
keyboard.utilities.removeAt(keyboard.getInput(), 0);
|
||||
expect(keyboard.getInput()).toBe("test");
|
||||
|
||||
keyboard.setInput("test");
|
||||
keyboard.caretPosition = 5;
|
||||
keyboard.utilities.removeAt(keyboard.getInput(), 0, true);
|
||||
expect(keyboard.caretPosition).toBe(4);
|
||||
|
||||
keyboard.setCaretPosition(5);
|
||||
keyboard.utilities.removeAt(keyboard.getInput(), 0, 0, true);
|
||||
expect(keyboard.caretPosition).toBe(5);
|
||||
});
|
||||
|
||||
it('Keyboard removeAt will remove multi-byte unicodes with caretPos>0', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
|
||||
keyboard.caretPosition = 6;
|
||||
let output = keyboard.utilities.removeAt("test\uD83D\uDE00", 6);
|
||||
keyboard.setCaretPosition(6);
|
||||
let output = keyboard.utilities.removeAt("test\uD83D\uDE00", 6, 6);
|
||||
expect(output).toBe("test");
|
||||
|
||||
keyboard.caretPosition = 6;
|
||||
output = keyboard.utilities.removeAt("test\uD83D\uDE00", 6, true);
|
||||
keyboard.setCaretPosition(6);
|
||||
output = keyboard.utilities.removeAt("test\uD83D\uDE00", 6, 6, true);
|
||||
expect(keyboard.caretPosition).toBe(4);
|
||||
});
|
||||
|
||||
it('Keyboard removeAt will not remove multi-byte unicodes with caretPos:0', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard();
|
||||
let output = keyboard.utilities.removeAt("\uD83D\uDE00");
|
||||
expect(output).toBeFalsy();
|
||||
|
||||
output = keyboard.utilities.removeAt("\uD83D\uDE00", 0, true);
|
||||
expect(output).toBeFalsy();
|
||||
output = keyboard.utilities.removeAt("\uD83D\uDE00", 0, 0, true);
|
||||
expect(output).toBe("\uD83D\uDE00");
|
||||
});
|
||||
|
||||
it('Keyboard removeAt will propagate caretPosition', () => {
|
||||
clearDOM();
|
||||
|
||||
document.body.innerHTML = `
|
||||
<div class="simple-keyboard"></div>
|
||||
<div class="keyboard2"></div>
|
||||
`;
|
||||
|
||||
const keyboard = new Keyboard({ useMouseEvents: true });
|
||||
const keyboard2 = new Keyboard('.keyboard2');
|
||||
|
||||
keyboard.input.default = "hello";
|
||||
keyboard2.input.default = "world"
|
||||
|
||||
keyboard.setCaretPosition(1);
|
||||
expect(keyboard.getCaretPosition()).toBe(1);
|
||||
expect(keyboard.getCaretPositionEnd()).toBe(1);
|
||||
|
||||
keyboard.setCaretPosition(1, 3);
|
||||
expect(keyboard.getCaretPosition()).toBe(1);
|
||||
expect(keyboard.getCaretPositionEnd()).toBe(3);
|
||||
|
||||
keyboard.getButtonElement('{bksp}').onclick();
|
||||
|
||||
expect(keyboard.getCaretPosition()).toBe(1);
|
||||
expect(keyboard2.getCaretPosition()).toBe(1);
|
||||
|
||||
expect(keyboard.getInput()).toBe('hlo');
|
||||
expect(keyboard.getCaretPositionEnd()).toBe(1);
|
||||
expect(keyboard2.getCaretPositionEnd()).toBe(1);
|
||||
});
|
||||
|
||||
it('Keyboard removeAt will propagate caretPosition in a syncInstanceInputs setting', () => {
|
||||
clearDOM();
|
||||
|
||||
document.body.innerHTML = `
|
||||
<div class="simple-keyboard"></div>
|
||||
<div class="keyboard2"></div>
|
||||
`;
|
||||
|
||||
const keyboard = new Keyboard({ useMouseEvents: true, syncInstanceInputs: true });
|
||||
const keyboard2 = new Keyboard('.keyboard2');
|
||||
|
||||
keyboard.input.default = "hello"
|
||||
|
||||
keyboard.setCaretPosition(1);
|
||||
expect(keyboard.getCaretPosition()).toBe(1);
|
||||
expect(keyboard.getCaretPositionEnd()).toBe(1);
|
||||
|
||||
keyboard.setCaretPosition(1, 3);
|
||||
expect(keyboard.getCaretPosition()).toBe(1);
|
||||
expect(keyboard.getCaretPositionEnd()).toBe(3);
|
||||
|
||||
keyboard.getButtonElement('{bksp}').onclick();
|
||||
|
||||
expect(keyboard.getCaretPosition()).toBe(1);
|
||||
expect(keyboard2.getCaretPosition()).toBe(1);
|
||||
|
||||
expect(keyboard.getInput()).toBe('hlo');
|
||||
expect(keyboard.getCaretPositionEnd()).toBe(1);
|
||||
expect(keyboard2.getCaretPositionEnd()).toBe(1);
|
||||
});
|
||||
|
||||
it('Keyboard removeAt will remove regular strings', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
debug: true
|
||||
});
|
||||
|
||||
keyboard.caretPosition = 6;
|
||||
let output = keyboard.utilities.removeAt("testie", 6);
|
||||
keyboard.setCaretPosition(6);
|
||||
let output = keyboard.utilities.removeAt("testie", 6, 6);
|
||||
expect(output).toBe("testi");
|
||||
|
||||
keyboard.caretPosition = 6;
|
||||
output = keyboard.utilities.removeAt("testie", 6, true);
|
||||
keyboard.setCaretPosition(6);
|
||||
output = keyboard.utilities.removeAt("testie", 6, 6, true);
|
||||
expect(keyboard.caretPosition).toBe(5);
|
||||
});
|
||||
|
||||
it('Keyboard removeAt will work with unset or start caretPosition', () => {
|
||||
setDOM();
|
||||
|
||||
const keyboard = new Keyboard({
|
||||
debug: true
|
||||
});
|
||||
|
||||
let output = keyboard.utilities.removeAt("test");
|
||||
expect(output).toBe("tes");
|
||||
|
||||
output = keyboard.utilities.removeAt("test", null, null);
|
||||
expect(output).toBe("tes");
|
||||
|
||||
output = keyboard.utilities.removeAt("😀", null, null);
|
||||
expect(output).toBe("");
|
||||
|
||||
/**
|
||||
* Will also work with moveCaret
|
||||
*/
|
||||
keyboard.setCaretPosition(3);
|
||||
output = keyboard.utilities.removeAt("test", null, null, true);
|
||||
expect(output).toBe("tes");
|
||||
expect(keyboard.getCaretPosition()).toBe(2);
|
||||
|
||||
keyboard.setCaretPosition(2);
|
||||
output = keyboard.utilities.removeAt("😀", null, null, true);
|
||||
expect(output).toBe("");
|
||||
expect(keyboard.getCaretPosition()).toBe(0);
|
||||
});
|
||||
|
||||
it('Keyboard will work with custom (and weird) class', () => {
|
||||
testUtil.setDOM("my--weird--class");
|
||||
setDOM("my--weird--class");
|
||||
const keyboard = new Keyboard(".my--weird--class");
|
||||
expect(keyboard.keyboardDOMClass).toBe("my--weird--class");
|
||||
});
|
||||
|
||||
it('Keyboard camelCase will work with empty strings', () => {
|
||||
testUtil.setDOM();
|
||||
setDOM();
|
||||
const keyboard = new Keyboard();
|
||||
expect(keyboard.utilities.camelCase()).toBeFalsy();
|
||||
});
|
||||
|
||||
5
src/setupTests.js
Normal file
5
src/setupTests.js
Normal file
@@ -0,0 +1,5 @@
|
||||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
@@ -1,12 +1,11 @@
|
||||
/**
|
||||
* Test Utility Functions
|
||||
*/
|
||||
export default class TestUtility {
|
||||
/**
|
||||
* Sets a basic DOM structure to test in
|
||||
*/
|
||||
setDOM = (divClass) => {
|
||||
this.clear();
|
||||
export const setDOM = (divClass) => {
|
||||
clearDOM();
|
||||
const wrapperDOM = document.createElement('div');
|
||||
wrapperDOM.setAttribute("id", "root");
|
||||
|
||||
@@ -20,19 +19,29 @@ export default class TestUtility {
|
||||
/**
|
||||
* Clears DOM structure
|
||||
*/
|
||||
clear = () => {
|
||||
export const clearDOM = () => {
|
||||
document.body.innerHTML = "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger pointerup
|
||||
*/
|
||||
export const triggerDocumentPointerUp = (e = {}) => (document.onpointerup || document.onmouseup || document.ontouchstart)(e);
|
||||
|
||||
/**
|
||||
* Trigger pointerdown
|
||||
*/
|
||||
export const triggerDocumentPointerDown = (e = {}) => (document.onpointerdown || document.onmousedown || document.ontouchend)(e);
|
||||
|
||||
/**
|
||||
* Test if standard buttons respect maxLength and do input a value
|
||||
*/
|
||||
testLayoutStdButtons = (keyboard) => {
|
||||
export const testLayoutStdButtons = (keyboard) => {
|
||||
let stdBtnCount = 0;
|
||||
let fullInput = '';
|
||||
|
||||
this.iterateButtons((button) => {
|
||||
let label = button.getAttribute("data-skbtn");
|
||||
iterateButtons((button) => {
|
||||
const label = button.getAttribute("data-skbtn");
|
||||
|
||||
if(label.includes("{"))
|
||||
return false;
|
||||
@@ -41,7 +50,7 @@ export default class TestUtility {
|
||||
button.onclick();
|
||||
|
||||
// Recording fullInput, bypasses maxLength
|
||||
fullInput = keyboard.utilities.getUpdatedInput(label, fullInput, keyboard.options, null);
|
||||
fullInput = keyboard.utilities.getUpdatedInput(label, fullInput);
|
||||
|
||||
stdBtnCount += label.length;
|
||||
});
|
||||
@@ -76,12 +85,12 @@ export default class TestUtility {
|
||||
/**
|
||||
* Test if function buttons are interactive (have an onclick)
|
||||
*/
|
||||
testLayoutFctButtons = (callback) => {
|
||||
export const testLayoutFctButtons = (callback) => {
|
||||
let fctBtnCount = 0;
|
||||
let fctBtnHasOnclickCount = 0;
|
||||
|
||||
this.iterateButtons((button) => {
|
||||
let label = button.getAttribute("data-skbtn");
|
||||
iterateButtons((button) => {
|
||||
const label = button.getAttribute("data-skbtn");
|
||||
|
||||
if(!label.includes("{") && !label.includes("}"))
|
||||
return false;
|
||||
@@ -100,8 +109,8 @@ export default class TestUtility {
|
||||
/**
|
||||
* Iterates on the keyboard buttons
|
||||
*/
|
||||
iterateButtons = (callback, selector) => {
|
||||
let rows = document.body.querySelector(selector || '.simple-keyboard').children;
|
||||
export const iterateButtons = (callback, selector) => {
|
||||
const rows = document.body.querySelector(selector || '.simple-keyboard').children;
|
||||
|
||||
Array.from(rows).forEach(row => {
|
||||
Array.from(row.children).forEach((button) => {
|
||||
@@ -109,4 +118,3 @@ export default class TestUtility {
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user