virtual_keyboard 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +46 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/CODE_OF_CONDUCT.md +13 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +72 -0
  9. data/Rakefile +6 -0
  10. data/app/assets/javascripts/keyboard/jquery.keyboard.extension-all.min.js +4 -0
  11. data/app/assets/javascripts/keyboard/jquery.keyboard.extension-altkeyspopup.min.js +2 -0
  12. data/app/assets/javascripts/keyboard/jquery.keyboard.extension-autocomplete.min.js +2 -0
  13. data/app/assets/javascripts/keyboard/jquery.keyboard.extension-caret.min.js +2 -0
  14. data/app/assets/javascripts/keyboard/jquery.keyboard.extension-extender.min.js +2 -0
  15. data/app/assets/javascripts/keyboard/jquery.keyboard.extension-mobile.min.js +2 -0
  16. data/app/assets/javascripts/keyboard/jquery.keyboard.extension-navigation.min.js +2 -0
  17. data/app/assets/javascripts/keyboard/jquery.keyboard.extension-previewkeyset.min.js +2 -0
  18. data/app/assets/javascripts/keyboard/jquery.keyboard.extension-scramble.min.js +1 -0
  19. data/app/assets/javascripts/keyboard/jquery.keyboard.extension-typing.min.js +2 -0
  20. data/app/assets/javascripts/keyboard/jquery.keyboard.js +2924 -0
  21. data/app/assets/javascripts/keyboard/jquery.keyboard.min.js +3 -0
  22. data/app/assets/javascripts/keyboard/jquery.mousewheel.min.js +2 -0
  23. data/app/assets/javascripts/keyboard/languages/de.min.js +1 -0
  24. data/app/assets/javascripts/keyboard/languages/es.min.js +1 -0
  25. data/app/assets/javascripts/keyboard/languages/fa.min.js +1 -0
  26. data/app/assets/javascripts/keyboard/languages/fr.min.js +1 -0
  27. data/app/assets/javascripts/keyboard/languages/he.min.js +1 -0
  28. data/app/assets/javascripts/keyboard/languages/hu.min.js +1 -0
  29. data/app/assets/javascripts/keyboard/languages/it.min.js +1 -0
  30. data/app/assets/javascripts/keyboard/languages/lv.min.js +1 -0
  31. data/app/assets/javascripts/keyboard/languages/pl.min.js +1 -0
  32. data/app/assets/javascripts/keyboard/languages/pt.min.js +1 -0
  33. data/app/assets/javascripts/keyboard/languages/ro.min.js +1 -0
  34. data/app/assets/javascripts/keyboard/languages/ru.min.js +1 -0
  35. data/app/assets/javascripts/keyboard/languages/sq.min.js +1 -0
  36. data/app/assets/javascripts/keyboard/layouts/albanian.min.js +1 -0
  37. data/app/assets/javascripts/keyboard/layouts/arabic.min.js +1 -0
  38. data/app/assets/javascripts/keyboard/layouts/belarusian.min.js +1 -0
  39. data/app/assets/javascripts/keyboard/layouts/bengali.min.js +1 -0
  40. data/app/assets/javascripts/keyboard/layouts/bulgarian.min.js +1 -0
  41. data/app/assets/javascripts/keyboard/layouts/catalan.min.js +1 -0
  42. data/app/assets/javascripts/keyboard/layouts/chinese.min.js +1 -0
  43. data/app/assets/javascripts/keyboard/layouts/danish.min.js +1 -0
  44. data/app/assets/javascripts/keyboard/layouts/french.min.js +1 -0
  45. data/app/assets/javascripts/keyboard/layouts/german.min.js +1 -0
  46. data/app/assets/javascripts/keyboard/layouts/hebrew.min.js +1 -0
  47. data/app/assets/javascripts/keyboard/layouts/hindi.min.js +1 -0
  48. data/app/assets/javascripts/keyboard/layouts/hungarian.min.js +1 -0
  49. data/app/assets/javascripts/keyboard/layouts/hungarianansi.min.js +1 -0
  50. data/app/assets/javascripts/keyboard/layouts/japanese.min.js +1 -0
  51. data/app/assets/javascripts/keyboard/layouts/keyboard-layouts-combined.min.js +3 -0
  52. data/app/assets/javascripts/keyboard/layouts/keyboard-layouts-greywyvern.min.js +5 -0
  53. data/app/assets/javascripts/keyboard/layouts/keyboard-layouts-microsoft.min.js +6 -0
  54. data/app/assets/javascripts/keyboard/layouts/latvian.min.js +1 -0
  55. data/app/assets/javascripts/keyboard/layouts/mongolian.min.js +1 -0
  56. data/app/assets/javascripts/keyboard/layouts/ms-Albanian.min.js +1 -0
  57. data/app/assets/javascripts/keyboard/layouts/ms-Arabic.min.js +1 -0
  58. data/app/assets/javascripts/keyboard/layouts/ms-Armenian.min.js +1 -0
  59. data/app/assets/javascripts/keyboard/layouts/ms-Assamese.min.js +1 -0
  60. data/app/assets/javascripts/keyboard/layouts/ms-Azeri.min.js +1 -0
  61. data/app/assets/javascripts/keyboard/layouts/ms-Bashkir.min.js +1 -0
  62. data/app/assets/javascripts/keyboard/layouts/ms-Belarusian.min.js +1 -0
  63. data/app/assets/javascripts/keyboard/layouts/ms-Belgian.min.js +1 -0
  64. data/app/assets/javascripts/keyboard/layouts/ms-Bengali.min.js +1 -0
  65. data/app/assets/javascripts/keyboard/layouts/ms-Bulgarian.min.js +1 -0
  66. data/app/assets/javascripts/keyboard/layouts/ms-Canadian.min.js +1 -0
  67. data/app/assets/javascripts/keyboard/layouts/ms-Chinese.min.js +1 -0
  68. data/app/assets/javascripts/keyboard/layouts/ms-Czech.min.js +1 -0
  69. data/app/assets/javascripts/keyboard/layouts/ms-Danish.min.js +1 -0
  70. data/app/assets/javascripts/keyboard/layouts/ms-Devanagari.min.js +1 -0
  71. data/app/assets/javascripts/keyboard/layouts/ms-Divehi.min.js +1 -0
  72. data/app/assets/javascripts/keyboard/layouts/ms-Dutch.min.js +1 -0
  73. data/app/assets/javascripts/keyboard/layouts/ms-Estonian.min.js +1 -0
  74. data/app/assets/javascripts/keyboard/layouts/ms-Faeroese.min.js +1 -0
  75. data/app/assets/javascripts/keyboard/layouts/ms-Finnish.min.js +1 -0
  76. data/app/assets/javascripts/keyboard/layouts/ms-French.min.js +1 -0
  77. data/app/assets/javascripts/keyboard/layouts/ms-Gaelic.min.js +1 -0
  78. data/app/assets/javascripts/keyboard/layouts/ms-Georgian.min.js +1 -0
  79. data/app/assets/javascripts/keyboard/layouts/ms-German.min.js +1 -0
  80. data/app/assets/javascripts/keyboard/layouts/ms-Greek.min.js +1 -0
  81. data/app/assets/javascripts/keyboard/layouts/ms-Greenlandic.min.js +1 -0
  82. data/app/assets/javascripts/keyboard/layouts/ms-Gujarati.min.js +1 -0
  83. data/app/assets/javascripts/keyboard/layouts/ms-Hausa.min.js +1 -0
  84. data/app/assets/javascripts/keyboard/layouts/ms-Hebrew.min.js +1 -0
  85. data/app/assets/javascripts/keyboard/layouts/ms-Hindi.min.js +1 -0
  86. data/app/assets/javascripts/keyboard/layouts/ms-Hungarian.min.js +1 -0
  87. data/app/assets/javascripts/keyboard/layouts/ms-Icelandic.min.js +1 -0
  88. data/app/assets/javascripts/keyboard/layouts/ms-Igbo.min.js +1 -0
  89. data/app/assets/javascripts/keyboard/layouts/ms-Inuktitut.min.js +1 -0
  90. data/app/assets/javascripts/keyboard/layouts/ms-Irish.min.js +1 -0
  91. data/app/assets/javascripts/keyboard/layouts/ms-Italian.min.js +1 -0
  92. data/app/assets/javascripts/keyboard/layouts/ms-Japanese-Hiragana.min.js +1 -0
  93. data/app/assets/javascripts/keyboard/layouts/ms-Kannada.min.js +1 -0
  94. data/app/assets/javascripts/keyboard/layouts/ms-Kazakh.min.js +1 -0
  95. data/app/assets/javascripts/keyboard/layouts/ms-Korean.min.js +1 -0
  96. data/app/assets/javascripts/keyboard/layouts/ms-Kyrgyz-Cyrillic.min.js +1 -0
  97. data/app/assets/javascripts/keyboard/layouts/ms-Lao.min.js +1 -0
  98. data/app/assets/javascripts/keyboard/layouts/ms-Latin-American.min.js +1 -0
  99. data/app/assets/javascripts/keyboard/layouts/ms-Latvian.min.js +1 -0
  100. data/app/assets/javascripts/keyboard/layouts/ms-Lithuanian.min.js +1 -0
  101. data/app/assets/javascripts/keyboard/layouts/ms-Luxembourgish.min.js +1 -0
  102. data/app/assets/javascripts/keyboard/layouts/ms-Macedonian.min.js +1 -0
  103. data/app/assets/javascripts/keyboard/layouts/ms-Malayalam.min.js +1 -0
  104. data/app/assets/javascripts/keyboard/layouts/ms-Maltese.min.js +1 -0
  105. data/app/assets/javascripts/keyboard/layouts/ms-Maori.min.js +1 -0
  106. data/app/assets/javascripts/keyboard/layouts/ms-Marathi.min.js +1 -0
  107. data/app/assets/javascripts/keyboard/layouts/ms-Mongolian-Cyrillic.min.js +1 -0
  108. data/app/assets/javascripts/keyboard/layouts/ms-Nepali.min.js +1 -0
  109. data/app/assets/javascripts/keyboard/layouts/ms-Norwegian.min.js +1 -0
  110. data/app/assets/javascripts/keyboard/layouts/ms-Oriya.min.js +1 -0
  111. data/app/assets/javascripts/keyboard/layouts/ms-Pashto.min.js +1 -0
  112. data/app/assets/javascripts/keyboard/layouts/ms-Persian.min.js +1 -0
  113. data/app/assets/javascripts/keyboard/layouts/ms-Polish.min.js +1 -0
  114. data/app/assets/javascripts/keyboard/layouts/ms-Portuguese.min.js +1 -0
  115. data/app/assets/javascripts/keyboard/layouts/ms-Punjabi.min.js +1 -0
  116. data/app/assets/javascripts/keyboard/layouts/ms-Romanian.min.js +1 -0
  117. data/app/assets/javascripts/keyboard/layouts/ms-Russian.min.js +1 -0
  118. data/app/assets/javascripts/keyboard/layouts/ms-Sami.min.js +1 -0
  119. data/app/assets/javascripts/keyboard/layouts/ms-Serbian.min.js +1 -0
  120. data/app/assets/javascripts/keyboard/layouts/ms-Setswana.min.js +1 -0
  121. data/app/assets/javascripts/keyboard/layouts/ms-Sinhala.min.js +1 -0
  122. data/app/assets/javascripts/keyboard/layouts/ms-Slovak.min.js +1 -0
  123. data/app/assets/javascripts/keyboard/layouts/ms-Slovenian.min.js +1 -0
  124. data/app/assets/javascripts/keyboard/layouts/ms-Sorbian.min.js +1 -0
  125. data/app/assets/javascripts/keyboard/layouts/ms-Spanish.min.js +1 -0
  126. data/app/assets/javascripts/keyboard/layouts/ms-Swedish-Sami.min.js +1 -0
  127. data/app/assets/javascripts/keyboard/layouts/ms-Swedish.min.js +1 -0
  128. data/app/assets/javascripts/keyboard/layouts/ms-Swiss-German.min.js +1 -0
  129. data/app/assets/javascripts/keyboard/layouts/ms-Syriac.min.js +1 -0
  130. data/app/assets/javascripts/keyboard/layouts/ms-Tajik.min.js +1 -0
  131. data/app/assets/javascripts/keyboard/layouts/ms-Tamil.min.js +1 -0
  132. data/app/assets/javascripts/keyboard/layouts/ms-Tatar.min.js +1 -0
  133. data/app/assets/javascripts/keyboard/layouts/ms-Telugu.min.js +1 -0
  134. data/app/assets/javascripts/keyboard/layouts/ms-Thai.min.js +1 -0
  135. data/app/assets/javascripts/keyboard/layouts/ms-Tibetan.min.js +1 -0
  136. data/app/assets/javascripts/keyboard/layouts/ms-Turkish.min.js +1 -0
  137. data/app/assets/javascripts/keyboard/layouts/ms-Turkmen.min.js +1 -0
  138. data/app/assets/javascripts/keyboard/layouts/ms-US-Dvorak.min.js +1 -0
  139. data/app/assets/javascripts/keyboard/layouts/ms-US-English.min.js +1 -0
  140. data/app/assets/javascripts/keyboard/layouts/ms-Ukrainian.min.js +1 -0
  141. data/app/assets/javascripts/keyboard/layouts/ms-United-Kingdom.min.js +1 -0
  142. data/app/assets/javascripts/keyboard/layouts/ms-Urdu.min.js +1 -0
  143. data/app/assets/javascripts/keyboard/layouts/ms-Uyghur.min.js +1 -0
  144. data/app/assets/javascripts/keyboard/layouts/ms-Uzbek-Cyrillic.min.js +1 -0
  145. data/app/assets/javascripts/keyboard/layouts/ms-Vietnamese.min.js +1 -0
  146. data/app/assets/javascripts/keyboard/layouts/ms-Wolof.min.js +1 -0
  147. data/app/assets/javascripts/keyboard/layouts/ms-Yakut.min.js +1 -0
  148. data/app/assets/javascripts/keyboard/layouts/ms-Yoruba.min.js +1 -0
  149. data/app/assets/javascripts/keyboard/layouts/persian.min.js +1 -0
  150. data/app/assets/javascripts/keyboard/layouts/polish.min.js +1 -0
  151. data/app/assets/javascripts/keyboard/layouts/portuguese.min.js +1 -0
  152. data/app/assets/javascripts/keyboard/layouts/romanian.min.js +1 -0
  153. data/app/assets/javascripts/keyboard/layouts/russian.min.js +1 -0
  154. data/app/assets/javascripts/keyboard/layouts/serbian.min.js +1 -0
  155. data/app/assets/javascripts/keyboard/layouts/spanish.min.js +1 -0
  156. data/app/assets/javascripts/keyboard/layouts/swedish.min.js +1 -0
  157. data/app/assets/javascripts/keyboard/layouts/tamil.min.js +1 -0
  158. data/app/assets/javascripts/keyboard/layouts/thai.min.js +1 -0
  159. data/app/assets/javascripts/keyboard/layouts/turkish.min.js +1 -0
  160. data/app/assets/javascripts/keyboard/layouts/vietnamese.min.js +1 -0
  161. data/app/assets/stylesheets/keyboard/keyboard-basic.min.css +1 -0
  162. data/app/assets/stylesheets/keyboard/keyboard-dark.min.css +1 -0
  163. data/app/assets/stylesheets/keyboard/keyboard-previewkeyset.min.css +1 -0
  164. data/app/assets/stylesheets/keyboard/keyboard.min.css +1 -0
  165. data/bin/console +14 -0
  166. data/bin/setup +7 -0
  167. data/lib/virtual_keyboard.rb +6 -0
  168. data/lib/virtual_keyboard/engine.rb +4 -0
  169. data/lib/virtual_keyboard/version.rb +3 -0
  170. data/virtual_keyboard.gemspec +25 -0
  171. metadata +255 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 79c27ef698e19c282765b1f058c195d4107c0185
4
+ data.tar.gz: 741b6392124f6645f8a709cc0b959725c8150610
5
+ SHA512:
6
+ metadata.gz: 001bded8dbc0f10db009966e6ac6585d1245e5889baedfcf804946dcf417b99db163e3c871f02f766b91e461c8bc1fc462a9eb6ec08b50f8e5e2c1874b01495a
7
+ data.tar.gz: 864002ab8cd082a6c4bcefa4f6be1840bc4dffa58025ffbce57d2215ece0f714f449071ffc5d4546d41064cf2e15639b107e70837ebef79d007f4c67970a5fae
@@ -0,0 +1,46 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+
12
+
13
+ # Created by https://www.gitignore.io/api/rubymine
14
+
15
+ ### RubyMine ###
16
+ # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
17
+ # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
18
+
19
+ # User-specific stuff:
20
+ .idea/
21
+
22
+ ## File-based project format:
23
+ *.iws
24
+
25
+ ## Plugin-specific files:
26
+
27
+ # IntelliJ
28
+ /out/
29
+
30
+ # mpeltonen/sbt-idea plugin
31
+ .idea_modules/
32
+
33
+ # JIRA plugin
34
+ atlassian-ide-plugin.xml
35
+
36
+ # Crashlytics plugin (for Android Studio and IntelliJ)
37
+ com_crashlytics_export_strings.xml
38
+ crashlytics.properties
39
+ crashlytics-build.properties
40
+ fabric.properties
41
+
42
+ ### RubyMine Patch ###
43
+ # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
44
+
45
+ # *.iml
46
+ # modules.xml
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.3
4
+ before_install: gem install bundler -v 1.10.6
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in virtual_keyboard.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Cheikh Sidya CAMARA
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,72 @@
1
+ # VirtualKeyboard
2
+
3
+ An Ruby On Rails Virtual Keyboard Interface based on [Mottie/Keyboard.](https://mottie.github.io/Keyboard/)
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'virtual_keyboard'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install virtual_keyboard
20
+
21
+ ## Usage
22
+
23
+ Add this line to the application.css file :
24
+
25
+ ```
26
+ *= require keyboard/keyboard-basic.min
27
+ ```
28
+
29
+ And this line to the application.js file :
30
+
31
+ ```
32
+ //= require keyboard/jquery.keyboard.min
33
+ ```
34
+
35
+ Example of use :
36
+
37
+ ```javascript
38
+ $('#user_password').keyboard({
39
+ lockInput: true,
40
+ });
41
+ ```
42
+
43
+ Follow the official documentation of the [JQuery plugin](https://mottie.github.io/Keyboard/).
44
+
45
+ ## Contributing
46
+
47
+ Bug reports and pull requests are welcome on GitHub at https://github.com/scicasoft/virtual_keyboard. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
48
+
49
+
50
+ ## License
51
+
52
+ The MIT License (MIT)
53
+
54
+ Copyright (c) 2016 Cheikh Sidya CAMARA
55
+
56
+ Permission is hereby granted, free of charge, to any person obtaining a copy
57
+ of this software and associated documentation files (the "Software"), to deal
58
+ in the Software without restriction, including without limitation the rights
59
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
60
+ copies of the Software, and to permit persons to whom the Software is
61
+ furnished to do so, subject to the following conditions:
62
+
63
+ The above copyright notice and this permission notice shall be included in
64
+ all copies or substantial portions of the Software.
65
+
66
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
67
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
68
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
69
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
70
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
71
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
72
+ THE SOFTWARE.
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,4 @@
1
+ /*! jQuery UI Virtual Keyboard (1.25.27) - ALL Extensions + Mousewheel */
2
+ /*! jQuery UI Virtual Keyboard Alt Key Popup v1.1.1 */
3
+ !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){"use strict";var b=a.keyboard;a.extend(b.css,{altKeyPopup:"ui-keyboard-popup",altKeyOverlay:"ui-keyboard-overlay"}),b.altKeys=a.extend({a:"å æ ā ă ą à á â ã ä",A:"Å Æ Ā Ă Ą À Á  à Ä",c:"ç ć ĉ ċ č",C:"Ç Ć Ĉ Ċ Č",d:"ď ð ď",D:"Ď Ð Ď",e:"ė ę ĕ ě ə è é ê ë ē",E:"Ė Ę Ĕ Ě Ǝ È É Ê Ë Ē",g:"ģ ğ ĝ ġ",G:"Ģ Ğ Ĝ Ġ",h:"ĥ ħ",H:"Ĥ Ħ",i:"ı į ī ï î í ì ĩ ĭ",I:"İ Į Ī Ï Î Í Ì Ĩ Ĭ",j:"ĵ",J:"Ĵ",k:"ķ",K:"Ķ",l:"Ł Ľ Ļ Ĺ Ŀ",L:"ł ľ ļ ĺ ŀ",n:"ʼn ň ņ ń ñ",N:"ʼn Ň Ņ Ń Ñ",o:"œ ő ø ö õ ô ó ò ō ŏ",O:"Œ Ő Ø Ö Õ Ô Ó Ò Ō Ŏ",r:"ŕ ř ŗ",R:"Ŕ Ř Ŗ",s:"ś š ş ß § ŝ",S:"Ś Š Ş ẞ § Ŝ",t:"þ ť ț ţ ŧ",T:"Þ Ť Ț Ţ Ŧ",u:"ų ű ů ū ü û ú ù ũ ŭ",U:"Ų Ű Ů Ū Ü Û Ú Ù Ũ Ŭ",w:"ŵ",W:"Ŵ",y:"ý",Y:"Ý",z:"ź ż ž",Z:"Ź Ż Ž","!":"¡",$:"€ £ ¤ ¥ ¢ ₡ ₱ ₩ ₹ ₪ ₭ ₮ ₦ ₤","?":"¿","'":"〈 「 『 “",'"':"〉 」 』 ”","(":"《 【 〔",")":"》 】 〕"},b.altKeys),b.navigationKeys=a.extend({enter:13,escape:27,end:35,home:36,left:37,right:39},b.navigationKeys),a.fn.addAltKeyPopup=function(c){var d={holdTime:500,popupVisible:"popup-visible",popupHidden:"popup-hidden"};return this.each(function(){var e,f=a(this).data("keyboard");f&&(f.altkeypopup_options=a.extend({},d,c),e=f.altkeypopup_namespace=f.namespace+"AltKeyPopup",f.extensionNamespace.push(e),f.altkeypopup_setup=function(){var c,d="mousedown touchstart ".split(" ").join(e+" "),g="mouseup touchend touchcancel ".split(" ").join(e+" ");f.options.repeatRate=0,f.$allKeys.unbind(e).bind(d,function(){clearTimeout(c);var d=a(this),e=d.attr("data-value")||"";e in b.altKeys&&(c=setTimeout(function(){f.altKeyPopup_popup(e,d)},f.altkeypopup_options.holdTime))}).bind(g,function(){clearTimeout(c)}),f.altkeypopup_blockingFlag=!1,f.$preview.unbind(e).bind("keypress keydown keyup".split(" ").join(e+" "),function(d){if("keyup"===d.type)return clearTimeout(c),f.altkeypopup_blockingFlag=!1,!0;var e,g=b.builtLayouts[f.layout],h=b.keyCodes,i=a(d.target),j=d.charCode||d.which,k=String.fromCharCode(j);return"keydown"===d.type&&k in b.altKeys?(e=f.altkeypopup_blockingFlag,f.altkeypopup_blockingFlag=!0,!e):f.altkeypopup_blockingFlag?(j>=h.a&&j<=h.z&&!d.shiftKey&&(k=k.toLowerCase()),g.hasMappedKeys&&g.mappedKeys.hasOwnProperty(k)&&(k=g.mappedKeys[k]),k in b.altKeys&&(c=setTimeout(function(){f.altkeypopup_blockingFlag&&f.altKeyPopup_popup(k,i)},f.altkeypopup_options.holdTime)),!0):void 0})},f.altKeyPopup_close=function(){f.altkeypopup_blockingFlag=!1,f.altKeyPopup_$overlay=null,f.$keyboard.find("."+b.css.altKeyOverlay).remove(),a(document).unbind(e),f.$preview.focus(),f.options.ignoreEsc=f.altKeyPopup_savedIgnoreEsc,f.$el.trigger(f.altkeypopup_options.popupHidden,[f])},f.altKeyPopup_popup=function(c,d){if(!f.$keyboard.find("."+b.css.altKeyOverlay).length){var g,h,i,j,k,l,m=b.css,n=f.$keyboard.outerWidth(),o=f.$keyboard.outerHeight();f.altKeyPopup_$overlay=a('<div class="'+m.altKeyOverlay+'" />').css({width:n,height:o}).appendTo(f.$keyboard).bind("click touchstart",function(){f.altKeyPopup_close()}),"bksp"!==c&&b.keyaction.bksp(f),h=a('<div class="'+m.altKeyPopup+" "+f.options.css.container+'" />'),g=b.altKeys[c].split(/\s+/),f.buildRow(h,0,g,[]),i=h.appendTo(f.altKeyPopup_$overlay).children().bind("mousedown touchstart",function(c){var d=a(this).attr("data-action");d in b.keyaction&&a.isFunction(b.keyaction[d])?b.keyaction[d](f,this,c):f.insertText(d),f.altKeyPopup_close()}).bind("mouseover mouseleave",function(b){"mouseleave"===b.type?i.removeClass(f.options.css.buttonHover):a(this).addClass(f.options.css.buttonHover)}),f.altKeyPopup_navigate(!0),f.altKeyPopup_savedIgnoreEsc=f.options.ignoreEsc,f.options.ignoreEsc=!0,a(document).unbind(e).bind("keydown"+e,function(a){return!1}).bind("keyup"+e,function(a){return a.which===b.navigationKeys.escape?f.altKeyPopup_close():f.altKeyPopup_navigate(a),!1}),j=d.position().left-h.outerWidth()/2+h.outerWidth()/2,j+h.outerWidth()>n&&(j=n-h.outerWidth(),0>j&&h.css({width:n,height:"auto"})),k=d.position().top-d.outerHeight()-5,l=f.$keyboard.find("."+m.keySet).position().top,k+h.outerHeight()>o&&(k=o-h.outerHeight(),l>k&&h.css({height:o-l,width:"auto"})),h.css({position:"relative",top:l>k?l:k,left:0>j?0:j}),f.$preview.blur(),f.$el.trigger(f.altkeypopup_options.popupVisible,[f])}},f.altKeyPopup_navigate=function(a){var c,d=b.css,e=b.navigationKeys,g=f.options.css.buttonHover,h=f.$keyboard.find("."+d.altKeyPopup).find("."+d.keyButton),i=h.length-1;if(a===!0)return h.eq(0).addClass(g),void(f.altKeyPopup_currentIndex=0);if(c=f.altKeyPopup_currentIndex,a.which===e.enter)return f.insertText(h.eq(c).attr("data-value")),f.altKeyPopup_close(),!0;switch(a.which){case e.end:c=i;break;case e.home:c=0;break;case e.left:c-=1;break;case e.right:c+=1}0>c&&(c=0),c>i&&(c=i),f.altKeyPopup_currentIndex=c,h.removeClass(g).eq(c).addClass(g)},f.options.alwaysOpen&&f.isVisible()&&f.altkeypopup_setup(),f.$el.unbind(b.events.kbBeforeVisible+e).bind(b.events.kbBeforeVisible+e,function(){f.altkeypopup_setup()}))})}}),function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){"use strict";a.fn.addAutocomplete=function(b){var c={position:{of:null,my:"right top",at:"left top",collision:"flip"}};return this.each(function(){var d,e=a(this).data("keyboard");e&&(e.autocomplete_namespace=e.namespace+"Autocomplete",e.extensionNamespace.push(e.autocomplete_namespace),e.autocomplete_init=function(){d=e.autocomplete_options=a.extend(!0,{},c,b),e.options.alwaysOpen&&e.isVisible()&&e.autocomplete_setup(),e.$el.unbind(e.autocomplete_namespace).bind(a.keyboard.events.kbVisible+e.autocomplete_namespace,function(){e.autocomplete_setup()}).bind(a.keyboard.events.kbChange+e.autocomplete_namespace,function(){e.hasAutocomplete&&e.isVisible()&&e.$el.val(e.$preview.val()).trigger("keydown.autocomplete")}).bind(a.keyboard.events.kbHidden+e.autocomplete_namespace,function(){e.$el.autocomplete("close")}).bind("autocompleteopen"+e.autocomplete_namespace,function(){if(e.hasAutocomplete){var b=a.extend({},d.position);b.of=b.of||e.$keyboard,e.$autocomplete.menu.element.position(b)}}).bind("autocompleteselect"+e.autocomplete_namespace,function(a,b){var c=b.item&&b.item.value||"";e.hasAutocomplete&&""!==c&&(e.$preview.val(c).focus(),e.last.start=c.length,e.last.end=c.length)})},e.autocomplete_setup=function(){e.$autocomplete=e.$el.data("autocomplete")||e.$el.data("uiAutocomplete")||e.$el.data("ui-autocomplete"),e.hasAutocomplete="undefined"==typeof e.$autocomplete?!1:!e.$autocomplete.options.disabled,e.hasAutocomplete&&(e.$preview.bind("keydown"+e.autocomplete_namespace,function(a){e.$el.val(e.$preview.val()).triggerHandler(a)}),e.$allKeys.bind("mouseup mousedown mouseleave touchstart touchend touchcancel ".split(" ").join(e.autocomplete_namespace+" "),function(a){clearTimeout(e.$autocomplete.searching);var b=a;e.$autocomplete.searching=setTimeout(function(){e.$autocomplete.term!==e.$autocomplete.element.val()&&(e.$autocomplete.selectedItem=null,e.$autocomplete.search(null,b))},e.$autocomplete.options.delay)}))},e.origEscClose=e.escClose,e.escClose=function(b){e.hasAutocomplete&&("ui-active-menuitem"===b.target.id||a(b.target).closest("ul").hasClass("ui-autocomplete"))||e.origEscClose(b)},e.autocomplete_init())})}}),function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){"use strict";var b=a.keyboard;b.firefox="undefined"!=typeof window.mozInnerScreenX,a.extend(b.css,{caret:"ui-keyboard-caret",caretMirror:"ui-keyboard-mirror-div"}),a.fn.addCaret=function(c){var d={caretClass:"",charAttr:"data-character",charIndex:1,offsetX:0,offsetY:0,adjustHt:0};return this.each(function(){var e,f,g=b.events,h=a(this).data("keyboard");h&&(e=h.caret_options=a.extend({},d,c),f=h.caret_namespace=h.namespace+"caret",h.extensionNamespace.push(f),h.textareaCaretProperties=["direction","boxSizing","width","height","overflowX","overflowY","borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth","borderStyle","paddingTop","paddingRight","paddingBottom","paddingLeft","fontStyle","fontVariant","fontWeight","fontStretch","fontSize","fontSizeAdjust","lineHeight","fontFamily","textAlign","textTransform","textIndent","textDecoration","letterSpacing","wordSpacing","tabSize","MozTabSize"],h.caret_setup=function(){var c=b.css,d="keyup keypress mouseup mouseleave ".split(" ").join(f+" "),i="position:absolute;visibility:hidden;top:-9999em;left:-9999em;white-space:pre-wrap;z-index:-10;"+("INPUT"===h.preview.nodeName?"":"word-wrap:break-word;");h.$keyboard.find("."+c.caretMirror).remove(),h.caret_$div=a('<div class="'+c.caretMirror+'" style="'+i+'">').appendTo(h.$keyboard),h.$caret&&h.$caret.remove(),h.$caret=a('<div class="'+c.caret+" "+e.caretClass+'" style="position:absolute;">').insertAfter(h.$preview),h.$el.unbind(g.kbChange+f).bind(g.kbChange+f,function(){h.findCaretPos()}),h.$preview.unbind(d).bind(d,function(){h.findCaretPos()})},h.findCaretPos=function(){if(h.caret_$div){var c,d,f,g,i,j,k,l,m=h.preview,n=parseFloat(h.$preview.css("fontSize")),o="INPUT"===m.nodeName,p=h.caret_$div[0];c=p.style,d=window.getComputedStyle?getComputedStyle(m,null):m.currentStyle,g=b.caret(h.$preview),i=Math["ltr"===d.direction?"max":"min"](g.start,g.end),h.textareaCaretProperties.forEach(function(a){c[a]=d[a]}),b.firefox&&(c.width=parseInt(d.width,10)-2+"px",m.scrollHeight>parseInt(d.height,10)&&(c.overflowY="scroll")),c.width=parseInt(o?m.scrollWidth:d.width,10)+(o?2*n:0)+"px",p.textContent=m.value.substring(0,i),"INPUT"===m.nodeName&&(p.textContent=p.textContent.replace(/\x20/g," ")),k=document.createElement("span"),k.textContent=m.value.substring(i)||"​",p.appendChild(k),l=a(k).position(),g="center"===c.textAlign?n:0,h.caretPos={top:l.top+parseInt(d.borderTopWidth,10)+e.offsetY,left:l.left+parseInt(d.borderLeftWidth,10)+e.offsetX-g},f=parseInt(h.$caret.css("margin-top"),10),c=Math.round(n+2*f)+e.adjustHt,l=h.$preview.position(),h.$caret.css({top:l.top-m.scrollTop+h.caretPos.top-f,left:l.left-m.scrollLeft+h.caretPos.left,height:c}),j=m.value.substring(i,i+e.charIndex).replace(/\s/," ")||" ",h.$caret.attr(e.charAttr,j)}},h.$el.unbind(f).bind(g.kbBeforeVisible+f,function(){h.caret_setup()}).bind(g.kbVisible+f,function(){h.findCaretPos()}).bind(g.kbHidden+f,function(){var a="keyup keypress mouseup mouseleave ".split(" ").join(f+" ");h.$preview.unbind(a),h.$caret.remove(),h.$caret=null,h.caret_$div=null}),h.options.alwaysOpen&&h.isVisible()&&(h.caret_setup(),h.findCaretPos()))})}}),function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){"use strict";var b=a.keyboard;b.css.extender="ui-keyboard-extender",b.language.en.display.extender=" :toggle_numpad",b.layouts.numpad={normal:["{clear} / * -","7 8 9 +","4 5 6 %","1 2 3 =","0 {dec} {left} {right}"]},b.keyaction.extender=function(a,b){return a.extender_toggle(),!1},a.fn.addExtender=function(c){var d={layout:"numpad",showing:!1,reposition:!0};return this.each(function(){var e,f=a(this).data("keyboard");f&&(e=f.extender_options=a.extend({},d,c),f.extender_namespace=f.namespace+"extender",f.extensionNamespace.push(f.extender_namespace),f.extender_setup=function(){var a,c=e.layout;"undefined"==typeof b.builtLayouts[c]&&f.buildKeyboard(c),a=b.builtLayouts[c].$keyboard.find("."+b.css.keySet+"-normal").clone(),a.removeClass().removeAttr("name").addClass(b.css.extender).children("button").removeAttr("data-pos"),a[0].style.display=e.showing?"inline-block":"none",f.$keyboard.find("div."+b.css.extender).remove(),f.$keyboard.append(a),f.extender_toggle(e.showing),f.bindKeys()},f.extender_toggle=function(c){e.showing="undefined"==typeof c?!e.showing:c,f.$keyboard.find("button."+b.css.extender).toggleClass(f.options.css.buttonActive,e.showing).end().find("div."+b.css.extender)[0].style.display=e.showing?"inline-block":"none",e.reposition&&a(window).trigger("resize")},f.options.alwaysOpen&&f.isVisible()&&f.extender_setup(),f.$el.unbind(b.events.kbBeforeVisible+f.extender_namespace).bind(b.events.kbBeforeVisible+f.extender_namespace,function(){f.extender_setup()}))})}}),function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){a.fn.addMobile=function(b){var c,d={container:{theme:"b",cssClass:"ui-body"},input:{theme:"b",cssClass:""},buttonMarkup:{theme:"b",cssClass:"ui-btn",shadow:"true",corners:"true"},buttonHover:{theme:"b",cssClass:"ui-btn-hover"},buttonAction:{theme:"b",cssClass:"ui-btn-active"},buttonActive:{theme:"b",cssClass:"ui-btn-active"},allThemes:"a b c"};return this.each(function(){var e=a(this).data("keyboard");e&&"undefined"!=typeof a.fn.textinput&&(e.mobile_options=c=a.extend(!0,{},d,b),e.mobile_themes=a.trim((" "+c.allThemes).split(" ").join(" "+c.buttonMarkup.cssClass+"-")+(" "+c.allThemes).split(" ").join(" "+c.buttonAction.cssClass+"-")+(" "+c.allThemes).split(" ").join(" "+c.buttonActive.cssClass+"-")),"undefined"==typeof e.options.mobile_savedActiveClass&&(e.options.mobile_savedActiveClass=""+e.options.css.buttonActive),e.mobile_init=function(){var b=e.namespace+"Mobile";a("."+a.keyboard.css.input).textinput(),e.options.alwaysOpen&&e.isVisible&&e.mobile_setup(),e.extensionNamespace.push(b),e.$el.unbind(b).bind(a.keyboard.events.kbBeforeVisible+b,function(){e&&e.el.active&&e.$keyboard.length&&e.$keyboard.css("visibility","hidden")}).bind(a.keyboard.events.kbVisible+b,function(){e&&e.el.active&&e.$keyboard.length&&(e.mobile_setup(),e.$keyboard.css("visibility","visible"),e.$preview.focus())})},e.mobile_setup=function(){var b,d=a.keyboard.css,f=e.options,g=e.mobile_themes;e.mobile_$actionKeys=e.$keyboard.find("."+e.options.css.buttonAction),f.css.buttonActive=f.mobile_savedActiveClass+" "+e.modOptions(c.buttonActive,c.buttonMarkup),e.$keyboard.addClass(e.modOptions(c.container,c.container)).find("."+d.preview).removeClass("ui-widget ui-widget-content").addClass(e.modOptions(c.input,c.input)).end().find("button").removeClass(a.trim("ui-corner-all ui-state-default "+g)).addClass(e.modOptions(c.buttonMarkup,c.buttonMarkup)).not(e.mobile_$actionKeys).hover(function(){a(this).removeClass(g).addClass(e.modOptions(c.buttonHover,c.buttonMarkup))},function(){a(this).removeClass(g+" "+c.buttonHover.cssClass).addClass(e.modOptions(c.buttonMarkup,c.buttonMarkup))}),e.mobile_$actionKeys.removeClass(g).addClass(e.modOptions(c.buttonAction,c.buttonMarkup)),e.msie&&e.$preview[0]!==e.el&&(e.$preview.hide(),e.$keyboard.css("width",""),e.width=e.$keyboard.outerWidth(),e.$keyboard.width(e.width+parseInt(e.$preview.css("fontSize"),10)),e.$preview.width(e.width),e.$preview.show()),a.ui&&a.ui.position&&(b=f.position,b.of=b.of||e.$el.data("keyboardPosition")||e.$el,b.collision=b.collision||"flipfit flipfit",e.$keyboard.position(b))},e.modOptions=function(a,b){var c=" "+(a.cssClass||"");return c+" "+(b&&b.cssClass?b.cssClass+"-"+(a.theme||""):"")+("true"==a.shadow?" ui-shadow":"")+("true"==a.corners?" ui-corner-all":"")},e.mobile_init())})}}),function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){"use strict";a.keyboard=a.keyboard||{},a.keyboard.navigationKeys={toggle:112,enter:13,pageup:33,pagedown:34,end:35,home:36,left:37,up:38,right:39,down:40,caretrt:45,caretlt:46,caretright:function(b){a.keyboard.keyaction.right(b)},caretleft:function(b){a.keyboard.keyaction.left(b)}},a.fn.addNavigation=function(b){return this.each(function(){var c,d,e=a(this).data("keyboard"),f=e.options,g={position:[0,0],toggleMode:!1,focusClass:"hasFocus",toggleKey:null},h=a.keyboard.events;e&&(e.navigation_options=c=a.extend({},g,b),e.navigation_keys=d=a.extend({},a.keyboard.navigationKeys),e.navigation_namespace=e.namespace+"Nav",e.extensionNamespace.push(e.navigation_namespace),e.saveNav=[e.options.tabNavigation,e.options.enterNavigation],e.allNavKeys=a.map(d,function(a,b){return a}),e.navigation_init=function(){var b=a.keyboard.css;e.$keyboard.toggleClass(c.focusClass,c.toggleMode).find("."+b.keySet+":visible").find("."+b.keyButton+'[data-pos="'+c.position[0]+","+c.position[1]+'"]').addClass(f.css.buttonHover),e.$preview.unbind(e.navigation_namespace).bind("keydown"+e.navigation_namespace,function(a){return e.checkKeys(a.which)})},e.checkKeys=function(b,d){if("undefined"!=typeof b){var f=e.navigation_keys,g=a.keyboard.css;return(b===(c.toggleKey||f.toggle)||d)&&(c.toggleMode=d?!1:!c.toggleMode,e.options.tabNavigation=c.toggleMode?!1:e.saveNav[0],e.options.enterNavigation=c.toggleMode?!1:e.saveNav[1]),e.$keyboard.toggleClass(c.focusClass,c.toggleMode),c.toggleMode&&b===f.enter?(e.$keyboard.find("."+g.keySet+":visible").find("."+g.keyButton+'[data-pos="'+c.position[0]+","+c.position[1]+'"]').trigger(h.kbRepeater),!1):c.toggleMode&&a.inArray(b,e.allNavKeys)>=0?(e.navigateKeys(b),!1):void 0}},e.navigateKeys=function(b,d,g){g="number"==typeof g?g:c.position[1],d="number"==typeof d?d:c.position[0];var h=a.keyboard.css,i=e.$keyboard.find("."+h.keySet+":visible"),j=i.find("."+h.endRow).length-1,k=i.find("."+h.keyButton+'[data-pos^="'+d+',"]').length-1,l=e.last,m=e.$preview.val().length,n=e.navigation_keys;switch(b){case n.pageup:d=0;break;case n.pagedown:d=j;break;case n.end:g=k;break;case n.home:g=0;break;case n.left:g+=g>0?-1:0;break;case n.up:d+=d>0?-1:0;break;case n.right:g+=1;break;case n.down:d+=d+1>j?0:1;break;case n.caretrt:l.start++;break;case n.caretlt:l.start--}b!==n.caretrt&&b!==n.caretlt||(l.start=l.start<0?0:l.start>m?m:l.start,e.last.start=e.last.end=l.end=l.start,a.keyboard.caret(e.$preview,e.last)),k=i.find("."+h.keyButton+'[data-pos^="'+d+',"]').length-1,g>k&&(g=k),i.find("."+f.css.buttonHover).removeClass(f.css.buttonHover),i.find("."+h.keyButton+'[data-pos="'+d+","+g+'"]').addClass(f.css.buttonHover),c.position=[d,g]},e.options.alwaysOpen&&e.isVisible&&(e.$keyboard.find("."+f.css.buttonHover).removeClass(f.css.buttonHover),e.navigation_init()),e.$el.unbind(e.navigation_namespace).bind(h.kbVisible,function(){e.$keyboard.find("."+f.css.buttonHover).removeClass(f.css.buttonHover),e.navigation_init()}).bind(h.kbInactive+" "+h.kbHidden,function(a){e.checkKeys(a.which,!0)}).bind(h.kbKeysetChange,function(){e.navigateKeys(null)}).bind("navigate navigateTo",function(b,c,d){var f;c=isNaN(c)?c.toLowerCase():c,c in e.navigation_keys?(f=e.navigation_keys[c],isNaN(f)&&f in a.keyboard.keyaction?a.keyboard.keyaction[f](e,this,b):a.isFunction(f)?f(e):e.checkKeys(f)):"string"==typeof c&&c in a.keyboard.keyaction?a.keyboard.keyaction[c](e,this,b):e.navigateKeys(null,c,d)}))})}}),function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){"use strict";a.keyboard=a.keyboard||{},a.fn.previewKeyset=function(b){return this.each(function(){var c=a(this).data("keyboard"),d=c.namespace+"Preview",e={sets:["normal","shift","alt","alt-shift"]};c&&(c.previewKeyset_options=a.extend({},e,b),c.extensionNamespace.push(d),c.previewKeyset=function(){var b=a.keyboard.css,d=c.previewKeyset_options.sets,e=c.$keyboard.find("."+b.keySet).filter('[name="'+d.join('"],[name="')+'"]');e.length>1&&e.eq(0).find("."+b.keyButton).not("."+b.keyAction).each(function(){var c,f,g={},h=d.length,i=e.find('button[data-pos="'+a(this).attr("data-pos")+'"]');for(c=0;h>c;c++)f=i.eq(c).parent().attr("name"),a.inArray(f,d)>=0&&(g["data-"+f]=i.eq(c).find("."+b.keyText).text());i.attr(g)})},c.options.alwaysOpen&&c.isVisible()?c.previewKeyset():c.$el.unbind(a.keyboard.events.kbBeforeVisible+d).bind(a.keyboard.events.kbBeforeVisible+d,function(){c.previewKeyset()}))})}}),function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){"use strict";a.keyboard=a.keyboard||{},a.fn.addScramble=function(b){var c={targetKeys:/[a-z\d]/i,byRow:!0,byKeySet:!1,randomizeOnce:!0,sameForAll:!1,init:null};return this.each(function(){var d,e=a(this).data("keyboard"),f=e.namespace+"Scramble",g=e.options;e&&!e.scramble_options&&(d=e.scramble_options=a.extend({},c,b),e.extensionNamespace.push(f),d.orig_create=g.create,e.scramble_setup=function(b){var c,f,g,h,i,j,k,l,m,n,o;if(c=b.find("."+a.keyboard.css.keySet),b.length){for(d.byKeySet&&(c=c.eq(0)),f=0;f<c.length;f++)if(g=c.eq(f),k=0,o=[],m=[],l=[],n=[],g.children("button, span, br").each(function(){"BR"===this.tagName?d.byRow?(o.push(this),m.push(!1),n[k]=o,l[k]=m,o=[],m=[],k++):(n[k]=this,l[k]=!1,k++):(j=a(this).attr("data-value")||"",j=1===j.length&&d.targetKeys.test(j)?j:!1,d.byRow?(o.push(this),m.push(j)):(n[k]=this,l[k]=j,k++))}),g.find("."+a.keyboard.css.endRow).remove(),d.byRow)for(i=0;i<n.length;i++)for(o=e.shuffle(n[i],l[i]),h=0;h<o.length;h++)g.append(o[h]);else for(o=e.shuffle(n,l),h=0;h<o.length;h++)g.append(o[h]);return d.byKeySet&&(b=e.realign(b)),b}},e.shuffle=function(a,b){for(var c,d,e=a.length;e>0;)d=Math.floor(Math.random()*e),b[e-1]===!1&&e--,b[e-1]!==!1&&b[d]!==!1&&(e--,c=a[e],a[e]=a[d],a[d]=c);return a},e.realign=function(b){var c,d,e,f=b.find("."+a.keyboard.css.keySet),g=f.eq(0);return f=f.filter(":gt(0)"),g.children().each(function(b,g){d="BR"===g.tagName,e=a(g).attr("data-pos"),f.each(function(b,f){c=d?"br:first":'button[data-pos="'+e+'"]',a(f).find(c).appendTo(f)})}),b},e.setScrambleLayout=function(){if(!/^scrambled/.test(g.layout)){e.orig_layout=g.layout;var a=a||"scrambled"+Math.round(1e4*Math.random());g.layout=d.sameForAll?a:"scrambled"+Math.round(1e4*Math.random())}},g.create=function(){var b=g.layout;a.keyboard.builtLayouts[b]={mappedKeys:{},acceptedKeys:[],$keyboard:null},"undefined"==typeof a.keyboard.builtLayouts[e.orig_layout]&&(e.layout=g.layout=e.orig_layout,e.buildKeyboard(e.layout,!0),e.layout=g.layout=b),a.keyboard.builtLayouts[b]=a.extend(!0,{},a.keyboard.builtLayouts[e.orig_layout]),d.randomizeOnce&&(a.keyboard.builtLayouts[b].$keyboard=e.scramble_setup(a.keyboard.builtLayouts[e.orig_layout].$keyboard.clone())),e.$keyboard=a.keyboard.builtLayouts[b].$keyboard,d.randomizeOnce||e.$el.unbind(a.keyboard.events.kbBeforeVisible+f).bind(a.keyboard.events.kbBeforeVisible+f,function(a,b){b.$keyboard=b.scramble_setup(b.$keyboard)}),a.isFunction(d.orig_create)&&d.orig_create(e)},e.setScrambleLayout(),g.alwaysOpen&&e.$keyboard.length?setTimeout(function(){var b=a.keyboard.builtLayouts;e.$keyboard=e.scramble_setup(e.$keyboard),e.setScrambleLayout(),"undefined"==typeof b[g.layout]&&(b[g.layout]={mappedKeys:a.extend({},b[e.layout].mappedKeys),acceptedKeys:a.extend([],b[e.layout].acceptedKeys),$keyboard:e.$keyboard.clone()}),a.isFunction(d.init)&&d.init(e)},0):a.isFunction(d.init)&&d.init(e))})}}),function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){a.fn.addTyping=function(b){var c={showTyping:!0,lockTypeIn:!1,delay:250},d=a.keyboard;return this.each(function(){var e,f=a(this).data("keyboard");f&&(e=f.typing_options=a.extend({},c,b),f.typing_keymap={" ":"space",'"':"34","'":"39","&nbsp;":"space","\b":"bksp","{b}":"bksp","{d}":"del","{l}":"left","{r}":"right","\n":"enter","\r":"enter","{e}":"enter"," ":"tab","{t}":"tab"},f.typing_xref={8:"bksp",9:"tab",13:"enter",32:"space",37:"left",39:"right",46:"del"},f.typing_event=!1,f.typing_namespace=f.namespace+"typing",f.extensionNamespace.push(f.typing_namespace),e.savedLockInput=f.options.lockInput,f.typing_setup=function(){var a=d.events,b=f.typing_namespace;f.$el.unbind(b).bind([a.kbHidden,a.kbInactive,""].join(b+" "),function(a){f.typing_reset()}).bind(d.events.kbBeforeVisible+b,function(){f.typing_setup()}),f.$allKeys.unbind(b).bind("mousedown"+b,function(){f.typing_reset()}),f.$preview.unbind(b).bind("keyup"+b,function(a){if(e.init&&e.lockTypeIn)return!1;if(!(a.which>=37&&a.which<=40))return 16===a.which&&(f.shiftActive=!1),18===a.which&&(f.altActive=!1),16===a.which||18===a.which?(f.showSet(),void setTimeout(function(){f.$preview.focus()},200)):void 0}).bind("keydown"+b,function(a){return e.init&&e.lockTypeIn?!1:(a.temp=!1,16===a.which&&(a.temp=!f.shiftActive,f.shiftActive=!0),18===a.which&&(a.temp=!f.altActive,f.altActive=!0),a.temp&&(f.showSet(),f.$preview.focus()),f.typing_event=!0,void(f.typing_xref[a.which]&&f.typing_findKey("",a)))}).bind("keypress"+b,function(a){return e.init&&e.lockTypeIn?!1:void(f.typing_event&&!f.options.lockInput&&(f.typing_reset(),f.typing_event=!0,f.typing_findKey("",a)))})},f.typing_reset=function(){f.typing_event=e.init=!1,e.text="",e.len=e.current=0,f.options.lockInput=e.savedLockInput},f.typeIn=function(a,b,c,d){if(!f.isVisible())return clearTimeout(f.typing_timer),void f.typing_reset();if(f.typing_event){if("undefined"==typeof a)return f.typing_event=!1,void(f.options.lockInput=e.savedLockInput)}else e.init!==!0&&(e.init=!0,f.options.lockInput=e.lockTypeIn,e.text=a||e.text||"",e.len=e.text.length,e.delay=b||300,e.current=0,c&&(e.callback=c)),a=e.text.substring(e.current,++e.current),"{"===a&&"}"===e.text.substring(e.current+1,e.current+2)&&(a+=e.text.substring(e.current,e.current+=2)),f.typing_findKey(a,d)},f.typing_findKey=function(b,c){var g,h,i,j,k,l,m,n,o=d.css,p=d.builtLayouts[f.layout].mappedKeys;if(f.isOpen&&f.$keyboard.length)if(l=f.$keyboard.find("."+o.keySet),j=b in f.typing_keymap?f.typing_keymap[b]:b,g="."+o.keyButton+'[data-action="'+j+'"]',f.typing_event&&c&&("keypress"!==c.type&&f.typing_xref.hasOwnProperty(c.keyCode||c.which)?g="."+o.keyPrefix+f.processName(f.typing_xref[c.keyCode||c.which]):(h=String.fromCharCode(c.charCode||c.which),g=p.hasOwnProperty(h)?"."+o.keyButton+'[data-value="'+p[h].replace(/"/g,'\\"')+'"]':"."+o.keyPrefix+f.processName(h))),k=l.filter(":visible").find(g),k.length?f.typing_simulateKey(k,b,c):(f.typing_event?k=l.find(g):(i=b in f.typing_keymap?f.typing_keymap[b]:f.processName(b),k=l.find("."+o.keyPrefix+i)),n=k.closest("."+o.keySet),n.attr("name")?(m=n.attr("name"),f.shiftActive=/shift/.test(m),f.altActive=/alt/.test(m),f.metaActive=f.last.keyset[2]=m.match(/meta\d+/)||!1,f.showSet(f.metaActive),f.typing_simulateKey(k,b,c)):f.typing_event||(b in f.typing_keymap&&f.typing_keymap[b]in d.keyaction?d.keyaction[f.typing_keymap[b]](f,k,c):f.insertText(b),f.checkCombos(),f.$el.trigger(d.events.kbChange,[f,f.el]))),e.current<=e.len&&0!==e.len){if(!f.isVisible())return;setTimeout(function(){f.typeIn()},e.delay)}else{if(0!==e.len)return f.typing_reset(),void(a.isFunction(e.callback)&&setTimeout(function(){a.isFunction(e.callback)&&e.callback(f)},e.delay));f.typing_reset()}},f.typing_simulateKey=function(b,c,g){var h=b.length;h&&b.filter(":visible").trigger("mouseenter"+f.namespace),f.typing_timer=setTimeout(function(){var h=b.length;h&&setTimeout(function(){b.trigger("mouseleave"+f.namespace)},e.delay/3),f.isVisible()&&(f.typing_event||(c in f.typing_keymap&&f.typing_keymap[c]in d.keyaction?(g=g||a.Event("keypress"),g.target=b,d.keyaction[f.typing_keymap[c]](f,b,g)):f.insertText(c),f.checkCombos(),f.$el.trigger(d.events.kbChange,[f,f.el])))},e.delay/3)},e.showTyping&&(f.options.alwaysOpen&&f.isVisible()?f.typing_setup():f.$el.unbind(d.events.kbBeforeVisible+f.typing_namespace).bind(d.events.kbBeforeVisible+f.typing_namespace,function(){f.typing_setup()})))})}}),/*! Mousewheel version: 3.1.12 * (c) 2014 Brandon Aaron * MIT License */
4
+ function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?module.exports=a:a(jQuery)}(function(a){function b(b){var g=b||window.event,h=i.call(arguments,1),j=0,l=0,m=0,n=0,o=0,p=0;if(b=a.event.fix(g),b.type="mousewheel","detail"in g&&(m=-1*g.detail),"wheelDelta"in g&&(m=g.wheelDelta),"wheelDeltaY"in g&&(m=g.wheelDeltaY),"wheelDeltaX"in g&&(l=-1*g.wheelDeltaX),"axis"in g&&g.axis===g.HORIZONTAL_AXIS&&(l=-1*m,m=0),j=0===m?l:m,"deltaY"in g&&(m=-1*g.deltaY,j=m),"deltaX"in g&&(l=g.deltaX,0===m&&(j=-1*l)),0!==m||0!==l){if(1===g.deltaMode){var q=a.data(this,"mousewheel-line-height");j*=q,m*=q,l*=q}else if(2===g.deltaMode){var r=a.data(this,"mousewheel-page-height");j*=r,m*=r,l*=r}if(n=Math.max(Math.abs(m),Math.abs(l)),(!f||f>n)&&(f=n,d(g,n)&&(f/=40)),d(g,n)&&(j/=40,l/=40,m/=40),j=Math[j>=1?"floor":"ceil"](j/f),l=Math[l>=1?"floor":"ceil"](l/f),m=Math[m>=1?"floor":"ceil"](m/f),k.settings.normalizeOffset&&this.getBoundingClientRect){var s=this.getBoundingClientRect();o=b.clientX-s.left,p=b.clientY-s.top}return b.deltaX=l,b.deltaY=m,b.deltaFactor=f,b.offsetX=o,b.offsetY=p,b.deltaMode=0,h.unshift(b,j,l,m),e&&clearTimeout(e),e=setTimeout(c,200),(a.event.dispatch||a.event.handle).apply(this,h)}}function c(){f=null}function d(a,b){return k.settings.adjustOldDeltas&&"mousewheel"===a.type&&b%120===0}var e,f,g=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],h="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],i=Array.prototype.slice;if(a.event.fixHooks)for(var j=g.length;j;)a.event.fixHooks[g[--j]]=a.event.mouseHooks;var k=a.event.special.mousewheel={version:"3.1.12",setup:function(){if(this.addEventListener)for(var c=h.length;c;)this.addEventListener(h[--c],b,!1);else this.onmousewheel=b;a.data(this,"mousewheel-line-height",k.getLineHeight(this)),a.data(this,"mousewheel-page-height",k.getPageHeight(this))},teardown:function(){if(this.removeEventListener)for(var c=h.length;c;)this.removeEventListener(h[--c],b,!1);else this.onmousewheel=null;a.removeData(this,"mousewheel-line-height"),a.removeData(this,"mousewheel-page-height")},getLineHeight:function(b){var c=a(b),d=c["offsetParent"in a.fn?"offsetParent":"parent"]();return d.length||(d=a("body")),parseInt(d.css("fontSize"),10)||parseInt(c.css("fontSize"),10)||16},getPageHeight:function(b){return a(b).height()},settings:{adjustOldDeltas:!0,normalizeOffset:!0}};a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})});
@@ -0,0 +1,2 @@
1
+ /*! jQuery UI Virtual Keyboard Alt Key Popup v1.1.1 */
2
+ !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){"use strict";var b=a.keyboard;a.extend(b.css,{altKeyPopup:"ui-keyboard-popup",altKeyOverlay:"ui-keyboard-overlay"}),b.altKeys=a.extend({a:"å æ ā ă ą à á â ã ä",A:"Å Æ Ā Ă Ą À Á  à Ä",c:"ç ć ĉ ċ č",C:"Ç Ć Ĉ Ċ Č",d:"ď ð ď",D:"Ď Ð Ď",e:"ė ę ĕ ě ə è é ê ë ē",E:"Ė Ę Ĕ Ě Ǝ È É Ê Ë Ē",g:"ģ ğ ĝ ġ",G:"Ģ Ğ Ĝ Ġ",h:"ĥ ħ",H:"Ĥ Ħ",i:"ı į ī ï î í ì ĩ ĭ",I:"İ Į Ī Ï Î Í Ì Ĩ Ĭ",j:"ĵ",J:"Ĵ",k:"ķ",K:"Ķ",l:"Ł Ľ Ļ Ĺ Ŀ",L:"ł ľ ļ ĺ ŀ",n:"ʼn ň ņ ń ñ",N:"ʼn Ň Ņ Ń Ñ",o:"œ ő ø ö õ ô ó ò ō ŏ",O:"Œ Ő Ø Ö Õ Ô Ó Ò Ō Ŏ",r:"ŕ ř ŗ",R:"Ŕ Ř Ŗ",s:"ś š ş ß § ŝ",S:"Ś Š Ş ẞ § Ŝ",t:"þ ť ț ţ ŧ",T:"Þ Ť Ț Ţ Ŧ",u:"ų ű ů ū ü û ú ù ũ ŭ",U:"Ų Ű Ů Ū Ü Û Ú Ù Ũ Ŭ",w:"ŵ",W:"Ŵ",y:"ý",Y:"Ý",z:"ź ż ž",Z:"Ź Ż Ž","!":"¡",$:"€ £ ¤ ¥ ¢ ₡ ₱ ₩ ₹ ₪ ₭ ₮ ₦ ₤","?":"¿","'":"〈 「 『 “",'"':"〉 」 』 ”","(":"《 【 〔",")":"》 】 〕"},b.altKeys),b.navigationKeys=a.extend({enter:13,escape:27,end:35,home:36,left:37,right:39},b.navigationKeys),a.fn.addAltKeyPopup=function(c){var d={holdTime:500,popupVisible:"popup-visible",popupHidden:"popup-hidden"};return this.each(function(){var e,f=a(this).data("keyboard");f&&(f.altkeypopup_options=a.extend({},d,c),e=f.altkeypopup_namespace=f.namespace+"AltKeyPopup",f.extensionNamespace.push(e),f.altkeypopup_setup=function(){var c,d="mousedown touchstart ".split(" ").join(e+" "),g="mouseup touchend touchcancel ".split(" ").join(e+" ");f.options.repeatRate=0,f.$allKeys.unbind(e).bind(d,function(){clearTimeout(c);var d=a(this),e=d.attr("data-value")||"";e in b.altKeys&&(c=setTimeout(function(){f.altKeyPopup_popup(e,d)},f.altkeypopup_options.holdTime))}).bind(g,function(){clearTimeout(c)}),f.altkeypopup_blockingFlag=!1,f.$preview.unbind(e).bind("keypress keydown keyup".split(" ").join(e+" "),function(d){if("keyup"===d.type)return clearTimeout(c),f.altkeypopup_blockingFlag=!1,!0;var e,g=b.builtLayouts[f.layout],h=b.keyCodes,i=a(d.target),j=d.charCode||d.which,k=String.fromCharCode(j);return"keydown"===d.type&&k in b.altKeys?(e=f.altkeypopup_blockingFlag,f.altkeypopup_blockingFlag=!0,!e):f.altkeypopup_blockingFlag?(j>=h.a&&j<=h.z&&!d.shiftKey&&(k=k.toLowerCase()),g.hasMappedKeys&&g.mappedKeys.hasOwnProperty(k)&&(k=g.mappedKeys[k]),k in b.altKeys&&(c=setTimeout(function(){f.altkeypopup_blockingFlag&&f.altKeyPopup_popup(k,i)},f.altkeypopup_options.holdTime)),!0):void 0})},f.altKeyPopup_close=function(){f.altkeypopup_blockingFlag=!1,f.altKeyPopup_$overlay=null,f.$keyboard.find("."+b.css.altKeyOverlay).remove(),a(document).unbind(e),f.$preview.focus(),f.options.ignoreEsc=f.altKeyPopup_savedIgnoreEsc,f.$el.trigger(f.altkeypopup_options.popupHidden,[f])},f.altKeyPopup_popup=function(c,d){if(!f.$keyboard.find("."+b.css.altKeyOverlay).length){var g,h,i,j,k,l,m=b.css,n=f.$keyboard.outerWidth(),o=f.$keyboard.outerHeight();f.altKeyPopup_$overlay=a('<div class="'+m.altKeyOverlay+'" />').css({width:n,height:o}).appendTo(f.$keyboard).bind("click touchstart",function(){f.altKeyPopup_close()}),"bksp"!==c&&b.keyaction.bksp(f),h=a('<div class="'+m.altKeyPopup+" "+f.options.css.container+'" />'),g=b.altKeys[c].split(/\s+/),f.buildRow(h,0,g,[]),i=h.appendTo(f.altKeyPopup_$overlay).children().bind("mousedown touchstart",function(c){var d=a(this).attr("data-action");d in b.keyaction&&a.isFunction(b.keyaction[d])?b.keyaction[d](f,this,c):f.insertText(d),f.altKeyPopup_close()}).bind("mouseover mouseleave",function(b){"mouseleave"===b.type?i.removeClass(f.options.css.buttonHover):a(this).addClass(f.options.css.buttonHover)}),f.altKeyPopup_navigate(!0),f.altKeyPopup_savedIgnoreEsc=f.options.ignoreEsc,f.options.ignoreEsc=!0,a(document).unbind(e).bind("keydown"+e,function(a){return!1}).bind("keyup"+e,function(a){return a.which===b.navigationKeys.escape?f.altKeyPopup_close():f.altKeyPopup_navigate(a),!1}),j=d.position().left-h.outerWidth()/2+h.outerWidth()/2,j+h.outerWidth()>n&&(j=n-h.outerWidth(),0>j&&h.css({width:n,height:"auto"})),k=d.position().top-d.outerHeight()-5,l=f.$keyboard.find("."+m.keySet).position().top,k+h.outerHeight()>o&&(k=o-h.outerHeight(),l>k&&h.css({height:o-l,width:"auto"})),h.css({position:"relative",top:l>k?l:k,left:0>j?0:j}),f.$preview.blur(),f.$el.trigger(f.altkeypopup_options.popupVisible,[f])}},f.altKeyPopup_navigate=function(a){var c,d=b.css,e=b.navigationKeys,g=f.options.css.buttonHover,h=f.$keyboard.find("."+d.altKeyPopup).find("."+d.keyButton),i=h.length-1;if(a===!0)return h.eq(0).addClass(g),void(f.altKeyPopup_currentIndex=0);if(c=f.altKeyPopup_currentIndex,a.which===e.enter)return f.insertText(h.eq(c).attr("data-value")),f.altKeyPopup_close(),!0;switch(a.which){case e.end:c=i;break;case e.home:c=0;break;case e.left:c-=1;break;case e.right:c+=1}0>c&&(c=0),c>i&&(c=i),f.altKeyPopup_currentIndex=c,h.removeClass(g).eq(c).addClass(g)},f.options.alwaysOpen&&f.isVisible()&&f.altkeypopup_setup(),f.$el.unbind(b.events.kbBeforeVisible+e).bind(b.events.kbBeforeVisible+e,function(){f.altkeypopup_setup()}))})}});
@@ -0,0 +1,2 @@
1
+ /*! jQuery UI Virtual Keyboard Autocomplete v1.9.2 */
2
+ !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){"use strict";a.fn.addAutocomplete=function(b){var c={position:{of:null,my:"right top",at:"left top",collision:"flip"}};return this.each(function(){var d,e=a(this).data("keyboard");e&&(e.autocomplete_namespace=e.namespace+"Autocomplete",e.extensionNamespace.push(e.autocomplete_namespace),e.autocomplete_init=function(){d=e.autocomplete_options=a.extend(!0,{},c,b),e.options.alwaysOpen&&e.isVisible()&&e.autocomplete_setup(),e.$el.unbind(e.autocomplete_namespace).bind(a.keyboard.events.kbVisible+e.autocomplete_namespace,function(){e.autocomplete_setup()}).bind(a.keyboard.events.kbChange+e.autocomplete_namespace,function(){e.hasAutocomplete&&e.isVisible()&&e.$el.val(e.$preview.val()).trigger("keydown.autocomplete")}).bind(a.keyboard.events.kbHidden+e.autocomplete_namespace,function(){e.$el.autocomplete("close")}).bind("autocompleteopen"+e.autocomplete_namespace,function(){if(e.hasAutocomplete){var b=a.extend({},d.position);b.of=b.of||e.$keyboard,e.$autocomplete.menu.element.position(b)}}).bind("autocompleteselect"+e.autocomplete_namespace,function(a,b){var c=b.item&&b.item.value||"";e.hasAutocomplete&&""!==c&&(e.$preview.val(c).focus(),e.last.start=c.length,e.last.end=c.length)})},e.autocomplete_setup=function(){e.$autocomplete=e.$el.data("autocomplete")||e.$el.data("uiAutocomplete")||e.$el.data("ui-autocomplete"),e.hasAutocomplete="undefined"==typeof e.$autocomplete?!1:!e.$autocomplete.options.disabled,e.hasAutocomplete&&(e.$preview.bind("keydown"+e.autocomplete_namespace,function(a){e.$el.val(e.$preview.val()).triggerHandler(a)}),e.$allKeys.bind("mouseup mousedown mouseleave touchstart touchend touchcancel ".split(" ").join(e.autocomplete_namespace+" "),function(a){clearTimeout(e.$autocomplete.searching);var b=a;e.$autocomplete.searching=setTimeout(function(){e.$autocomplete.term!==e.$autocomplete.element.val()&&(e.$autocomplete.selectedItem=null,e.$autocomplete.search(null,b))},e.$autocomplete.options.delay)}))},e.origEscClose=e.escClose,e.escClose=function(b){e.hasAutocomplete&&("ui-active-menuitem"===b.target.id||a(b.target).closest("ul").hasClass("ui-autocomplete"))||e.origEscClose(b)},e.autocomplete_init())})}});
@@ -0,0 +1,2 @@
1
+ /*! jQuery UI Virtual Keyboard Virtual Caret v1.1.5 (beta) */
2
+ !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){"use strict";var b=a.keyboard;b.firefox="undefined"!=typeof window.mozInnerScreenX,a.extend(b.css,{caret:"ui-keyboard-caret",caretMirror:"ui-keyboard-mirror-div"}),a.fn.addCaret=function(c){var d={caretClass:"",charAttr:"data-character",charIndex:1,offsetX:0,offsetY:0,adjustHt:0};return this.each(function(){var e,f,g=b.events,h=a(this).data("keyboard");h&&(e=h.caret_options=a.extend({},d,c),f=h.caret_namespace=h.namespace+"caret",h.extensionNamespace.push(f),h.textareaCaretProperties=["direction","boxSizing","width","height","overflowX","overflowY","borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth","borderStyle","paddingTop","paddingRight","paddingBottom","paddingLeft","fontStyle","fontVariant","fontWeight","fontStretch","fontSize","fontSizeAdjust","lineHeight","fontFamily","textAlign","textTransform","textIndent","textDecoration","letterSpacing","wordSpacing","tabSize","MozTabSize"],h.caret_setup=function(){var c=b.css,d="keyup keypress mouseup mouseleave ".split(" ").join(f+" "),i="position:absolute;visibility:hidden;top:-9999em;left:-9999em;white-space:pre-wrap;z-index:-10;"+("INPUT"===h.preview.nodeName?"":"word-wrap:break-word;");h.$keyboard.find("."+c.caretMirror).remove(),h.caret_$div=a('<div class="'+c.caretMirror+'" style="'+i+'">').appendTo(h.$keyboard),h.$caret&&h.$caret.remove(),h.$caret=a('<div class="'+c.caret+" "+e.caretClass+'" style="position:absolute;">').insertAfter(h.$preview),h.$el.unbind(g.kbChange+f).bind(g.kbChange+f,function(){h.findCaretPos()}),h.$preview.unbind(d).bind(d,function(){h.findCaretPos()})},h.findCaretPos=function(){if(h.caret_$div){var c,d,f,g,i,j,k,l,m=h.preview,n=parseFloat(h.$preview.css("fontSize")),o="INPUT"===m.nodeName,p=h.caret_$div[0];c=p.style,d=window.getComputedStyle?getComputedStyle(m,null):m.currentStyle,g=b.caret(h.$preview),i=Math["ltr"===d.direction?"max":"min"](g.start,g.end),h.textareaCaretProperties.forEach(function(a){c[a]=d[a]}),b.firefox&&(c.width=parseInt(d.width,10)-2+"px",m.scrollHeight>parseInt(d.height,10)&&(c.overflowY="scroll")),c.width=parseInt(o?m.scrollWidth:d.width,10)+(o?2*n:0)+"px",p.textContent=m.value.substring(0,i),"INPUT"===m.nodeName&&(p.textContent=p.textContent.replace(/\x20/g," ")),k=document.createElement("span"),k.textContent=m.value.substring(i)||"​",p.appendChild(k),l=a(k).position(),g="center"===c.textAlign?n:0,h.caretPos={top:l.top+parseInt(d.borderTopWidth,10)+e.offsetY,left:l.left+parseInt(d.borderLeftWidth,10)+e.offsetX-g},f=parseInt(h.$caret.css("margin-top"),10),c=Math.round(n+2*f)+e.adjustHt,l=h.$preview.position(),h.$caret.css({top:l.top-m.scrollTop+h.caretPos.top-f,left:l.left-m.scrollLeft+h.caretPos.left,height:c}),j=m.value.substring(i,i+e.charIndex).replace(/\s/," ")||" ",h.$caret.attr(e.charAttr,j)}},h.$el.unbind(f).bind(g.kbBeforeVisible+f,function(){h.caret_setup()}).bind(g.kbVisible+f,function(){h.findCaretPos()}).bind(g.kbHidden+f,function(){var a="keyup keypress mouseup mouseleave ".split(" ").join(f+" ");h.$preview.unbind(a),h.$caret.remove(),h.$caret=null,h.caret_$div=null}),h.options.alwaysOpen&&h.isVisible()&&(h.caret_setup(),h.findCaretPos()))})}});
@@ -0,0 +1,2 @@
1
+ /*! jQuery UI Virtual Keyboard Extender v1.0.3 */
2
+ !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){"use strict";var b=a.keyboard;b.css.extender="ui-keyboard-extender",b.language.en.display.extender=" :toggle_numpad",b.layouts.numpad={normal:["{clear} / * -","7 8 9 +","4 5 6 %","1 2 3 =","0 {dec} {left} {right}"]},b.keyaction.extender=function(a,b){return a.extender_toggle(),!1},a.fn.addExtender=function(c){var d={layout:"numpad",showing:!1,reposition:!0};return this.each(function(){var e,f=a(this).data("keyboard");f&&(e=f.extender_options=a.extend({},d,c),f.extender_namespace=f.namespace+"extender",f.extensionNamespace.push(f.extender_namespace),f.extender_setup=function(){var a,c=e.layout;"undefined"==typeof b.builtLayouts[c]&&f.buildKeyboard(c),a=b.builtLayouts[c].$keyboard.find("."+b.css.keySet+"-normal").clone(),a.removeClass().removeAttr("name").addClass(b.css.extender).children("button").removeAttr("data-pos"),a[0].style.display=e.showing?"inline-block":"none",f.$keyboard.find("div."+b.css.extender).remove(),f.$keyboard.append(a),f.extender_toggle(e.showing),f.bindKeys()},f.extender_toggle=function(c){e.showing="undefined"==typeof c?!e.showing:c,f.$keyboard.find("button."+b.css.extender).toggleClass(f.options.css.buttonActive,e.showing).end().find("div."+b.css.extender)[0].style.display=e.showing?"inline-block":"none",e.reposition&&a(window).trigger("resize")},f.options.alwaysOpen&&f.isVisible()&&f.extender_setup(),f.$el.unbind(b.events.kbBeforeVisible+f.extender_namespace).bind(b.events.kbBeforeVisible+f.extender_namespace,function(){f.extender_setup()}))})}});
@@ -0,0 +1,2 @@
1
+ /*! jQuery UI Virtual Keyboard for jQuery Mobile Themes v1.4.1 */
2
+ !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){a.fn.addMobile=function(b){var c,d={container:{theme:"b",cssClass:"ui-body"},input:{theme:"b",cssClass:""},buttonMarkup:{theme:"b",cssClass:"ui-btn",shadow:"true",corners:"true"},buttonHover:{theme:"b",cssClass:"ui-btn-hover"},buttonAction:{theme:"b",cssClass:"ui-btn-active"},buttonActive:{theme:"b",cssClass:"ui-btn-active"},allThemes:"a b c"};return this.each(function(){var e=a(this).data("keyboard");e&&"undefined"!=typeof a.fn.textinput&&(e.mobile_options=c=a.extend(!0,{},d,b),e.mobile_themes=a.trim((" "+c.allThemes).split(" ").join(" "+c.buttonMarkup.cssClass+"-")+(" "+c.allThemes).split(" ").join(" "+c.buttonAction.cssClass+"-")+(" "+c.allThemes).split(" ").join(" "+c.buttonActive.cssClass+"-")),"undefined"==typeof e.options.mobile_savedActiveClass&&(e.options.mobile_savedActiveClass=""+e.options.css.buttonActive),e.mobile_init=function(){var b=e.namespace+"Mobile";a("."+a.keyboard.css.input).textinput(),e.options.alwaysOpen&&e.isVisible&&e.mobile_setup(),e.extensionNamespace.push(b),e.$el.unbind(b).bind(a.keyboard.events.kbBeforeVisible+b,function(){e&&e.el.active&&e.$keyboard.length&&e.$keyboard.css("visibility","hidden")}).bind(a.keyboard.events.kbVisible+b,function(){e&&e.el.active&&e.$keyboard.length&&(e.mobile_setup(),e.$keyboard.css("visibility","visible"),e.$preview.focus())})},e.mobile_setup=function(){var b,d=a.keyboard.css,f=e.options,g=e.mobile_themes;e.mobile_$actionKeys=e.$keyboard.find("."+e.options.css.buttonAction),f.css.buttonActive=f.mobile_savedActiveClass+" "+e.modOptions(c.buttonActive,c.buttonMarkup),e.$keyboard.addClass(e.modOptions(c.container,c.container)).find("."+d.preview).removeClass("ui-widget ui-widget-content").addClass(e.modOptions(c.input,c.input)).end().find("button").removeClass(a.trim("ui-corner-all ui-state-default "+g)).addClass(e.modOptions(c.buttonMarkup,c.buttonMarkup)).not(e.mobile_$actionKeys).hover(function(){a(this).removeClass(g).addClass(e.modOptions(c.buttonHover,c.buttonMarkup))},function(){a(this).removeClass(g+" "+c.buttonHover.cssClass).addClass(e.modOptions(c.buttonMarkup,c.buttonMarkup))}),e.mobile_$actionKeys.removeClass(g).addClass(e.modOptions(c.buttonAction,c.buttonMarkup)),e.msie&&e.$preview[0]!==e.el&&(e.$preview.hide(),e.$keyboard.css("width",""),e.width=e.$keyboard.outerWidth(),e.$keyboard.width(e.width+parseInt(e.$preview.css("fontSize"),10)),e.$preview.width(e.width),e.$preview.show()),a.ui&&a.ui.position&&(b=f.position,b.of=b.of||e.$el.data("keyboardPosition")||e.$el,b.collision=b.collision||"flipfit flipfit",e.$keyboard.position(b))},e.modOptions=function(a,b){var c=" "+(a.cssClass||"");return c+" "+(b&&b.cssClass?b.cssClass+"-"+(a.theme||""):"")+("true"==a.shadow?" ui-shadow":"")+("true"==a.corners?" ui-corner-all":"")},e.mobile_init())})}});
@@ -0,0 +1,2 @@
1
+ /*! jQuery UI Virtual Keyboard Navigation v1.6.1 */
2
+ !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){"use strict";a.keyboard=a.keyboard||{},a.keyboard.navigationKeys={toggle:112,enter:13,pageup:33,pagedown:34,end:35,home:36,left:37,up:38,right:39,down:40,caretrt:45,caretlt:46,caretright:function(b){a.keyboard.keyaction.right(b)},caretleft:function(b){a.keyboard.keyaction.left(b)}},a.fn.addNavigation=function(b){return this.each(function(){var c,d,e=a(this).data("keyboard"),f=e.options,g={position:[0,0],toggleMode:!1,focusClass:"hasFocus",toggleKey:null},h=a.keyboard.events;e&&(e.navigation_options=c=a.extend({},g,b),e.navigation_keys=d=a.extend({},a.keyboard.navigationKeys),e.navigation_namespace=e.namespace+"Nav",e.extensionNamespace.push(e.navigation_namespace),e.saveNav=[e.options.tabNavigation,e.options.enterNavigation],e.allNavKeys=a.map(d,function(a,b){return a}),e.navigation_init=function(){var b=a.keyboard.css;e.$keyboard.toggleClass(c.focusClass,c.toggleMode).find("."+b.keySet+":visible").find("."+b.keyButton+'[data-pos="'+c.position[0]+","+c.position[1]+'"]').addClass(f.css.buttonHover),e.$preview.unbind(e.navigation_namespace).bind("keydown"+e.navigation_namespace,function(a){return e.checkKeys(a.which)})},e.checkKeys=function(b,d){if("undefined"!=typeof b){var f=e.navigation_keys,g=a.keyboard.css;return(b===(c.toggleKey||f.toggle)||d)&&(c.toggleMode=d?!1:!c.toggleMode,e.options.tabNavigation=c.toggleMode?!1:e.saveNav[0],e.options.enterNavigation=c.toggleMode?!1:e.saveNav[1]),e.$keyboard.toggleClass(c.focusClass,c.toggleMode),c.toggleMode&&b===f.enter?(e.$keyboard.find("."+g.keySet+":visible").find("."+g.keyButton+'[data-pos="'+c.position[0]+","+c.position[1]+'"]').trigger(h.kbRepeater),!1):c.toggleMode&&a.inArray(b,e.allNavKeys)>=0?(e.navigateKeys(b),!1):void 0}},e.navigateKeys=function(b,d,g){g="number"==typeof g?g:c.position[1],d="number"==typeof d?d:c.position[0];var h=a.keyboard.css,i=e.$keyboard.find("."+h.keySet+":visible"),j=i.find("."+h.endRow).length-1,k=i.find("."+h.keyButton+'[data-pos^="'+d+',"]').length-1,l=e.last,m=e.$preview.val().length,n=e.navigation_keys;switch(b){case n.pageup:d=0;break;case n.pagedown:d=j;break;case n.end:g=k;break;case n.home:g=0;break;case n.left:g+=g>0?-1:0;break;case n.up:d+=d>0?-1:0;break;case n.right:g+=1;break;case n.down:d+=d+1>j?0:1;break;case n.caretrt:l.start++;break;case n.caretlt:l.start--}b!==n.caretrt&&b!==n.caretlt||(l.start=l.start<0?0:l.start>m?m:l.start,e.last.start=e.last.end=l.end=l.start,a.keyboard.caret(e.$preview,e.last)),k=i.find("."+h.keyButton+'[data-pos^="'+d+',"]').length-1,g>k&&(g=k),i.find("."+f.css.buttonHover).removeClass(f.css.buttonHover),i.find("."+h.keyButton+'[data-pos="'+d+","+g+'"]').addClass(f.css.buttonHover),c.position=[d,g]},e.options.alwaysOpen&&e.isVisible&&(e.$keyboard.find("."+f.css.buttonHover).removeClass(f.css.buttonHover),e.navigation_init()),e.$el.unbind(e.navigation_namespace).bind(h.kbVisible,function(){e.$keyboard.find("."+f.css.buttonHover).removeClass(f.css.buttonHover),e.navigation_init()}).bind(h.kbInactive+" "+h.kbHidden,function(a){e.checkKeys(a.which,!0)}).bind(h.kbKeysetChange,function(){e.navigateKeys(null)}).bind("navigate navigateTo",function(b,c,d){var f;c=isNaN(c)?c.toLowerCase():c,c in e.navigation_keys?(f=e.navigation_keys[c],isNaN(f)&&f in a.keyboard.keyaction?a.keyboard.keyaction[f](e,this,b):a.isFunction(f)?f(e):e.checkKeys(f)):"string"==typeof c&&c in a.keyboard.keyaction?a.keyboard.keyaction[c](e,this,b):e.navigateKeys(null,c,d)}))})}});
@@ -0,0 +1,2 @@
1
+ /*! jQuery UI Virtual Keyboard previewKeyset v1.1.1 */
2
+ !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){"use strict";a.keyboard=a.keyboard||{},a.fn.previewKeyset=function(b){return this.each(function(){var c=a(this).data("keyboard"),d=c.namespace+"Preview",e={sets:["normal","shift","alt","alt-shift"]};c&&(c.previewKeyset_options=a.extend({},e,b),c.extensionNamespace.push(d),c.previewKeyset=function(){var b=a.keyboard.css,d=c.previewKeyset_options.sets,e=c.$keyboard.find("."+b.keySet).filter('[name="'+d.join('"],[name="')+'"]');e.length>1&&e.eq(0).find("."+b.keyButton).not("."+b.keyAction).each(function(){var c,f,g={},h=d.length,i=e.find('button[data-pos="'+a(this).attr("data-pos")+'"]');for(c=0;h>c;c++)f=i.eq(c).parent().attr("name"),a.inArray(f,d)>=0&&(g["data-"+f]=i.eq(c).find("."+b.keyText).text());i.attr(g)})},c.options.alwaysOpen&&c.isVisible()?c.previewKeyset():c.$el.unbind(a.keyboard.events.kbBeforeVisible+d).bind(a.keyboard.events.kbBeforeVisible+d,function(){c.previewKeyset()}))})}});
@@ -0,0 +1 @@
1
+ !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){"use strict";a.keyboard=a.keyboard||{},a.fn.addScramble=function(b){var c={targetKeys:/[a-z\d]/i,byRow:!0,byKeySet:!1,randomizeOnce:!0,sameForAll:!1,init:null};return this.each(function(){var d,e=a(this).data("keyboard"),f=e.namespace+"Scramble",g=e.options;e&&!e.scramble_options&&(d=e.scramble_options=a.extend({},c,b),e.extensionNamespace.push(f),d.orig_create=g.create,e.scramble_setup=function(b){var c,f,g,h,i,j,k,l,m,n,o;if(c=b.find("."+a.keyboard.css.keySet),b.length){for(d.byKeySet&&(c=c.eq(0)),f=0;f<c.length;f++)if(g=c.eq(f),k=0,o=[],m=[],l=[],n=[],g.children("button, span, br").each(function(){"BR"===this.tagName?d.byRow?(o.push(this),m.push(!1),n[k]=o,l[k]=m,o=[],m=[],k++):(n[k]=this,l[k]=!1,k++):(j=a(this).attr("data-value")||"",j=1===j.length&&d.targetKeys.test(j)?j:!1,d.byRow?(o.push(this),m.push(j)):(n[k]=this,l[k]=j,k++))}),g.find("."+a.keyboard.css.endRow).remove(),d.byRow)for(i=0;i<n.length;i++)for(o=e.shuffle(n[i],l[i]),h=0;h<o.length;h++)g.append(o[h]);else for(o=e.shuffle(n,l),h=0;h<o.length;h++)g.append(o[h]);return d.byKeySet&&(b=e.realign(b)),b}},e.shuffle=function(a,b){for(var c,d,e=a.length;e>0;)d=Math.floor(Math.random()*e),b[e-1]===!1&&e--,b[e-1]!==!1&&b[d]!==!1&&(e--,c=a[e],a[e]=a[d],a[d]=c);return a},e.realign=function(b){var c,d,e,f=b.find("."+a.keyboard.css.keySet),g=f.eq(0);return f=f.filter(":gt(0)"),g.children().each(function(b,g){d="BR"===g.tagName,e=a(g).attr("data-pos"),f.each(function(b,f){c=d?"br:first":'button[data-pos="'+e+'"]',a(f).find(c).appendTo(f)})}),b},e.setScrambleLayout=function(){if(!/^scrambled/.test(g.layout)){e.orig_layout=g.layout;var a=a||"scrambled"+Math.round(1e4*Math.random());g.layout=d.sameForAll?a:"scrambled"+Math.round(1e4*Math.random())}},g.create=function(){var b=g.layout;a.keyboard.builtLayouts[b]={mappedKeys:{},acceptedKeys:[],$keyboard:null},"undefined"==typeof a.keyboard.builtLayouts[e.orig_layout]&&(e.layout=g.layout=e.orig_layout,e.buildKeyboard(e.layout,!0),e.layout=g.layout=b),a.keyboard.builtLayouts[b]=a.extend(!0,{},a.keyboard.builtLayouts[e.orig_layout]),d.randomizeOnce&&(a.keyboard.builtLayouts[b].$keyboard=e.scramble_setup(a.keyboard.builtLayouts[e.orig_layout].$keyboard.clone())),e.$keyboard=a.keyboard.builtLayouts[b].$keyboard,d.randomizeOnce||e.$el.unbind(a.keyboard.events.kbBeforeVisible+f).bind(a.keyboard.events.kbBeforeVisible+f,function(a,b){b.$keyboard=b.scramble_setup(b.$keyboard)}),a.isFunction(d.orig_create)&&d.orig_create(e)},e.setScrambleLayout(),g.alwaysOpen&&e.$keyboard.length?setTimeout(function(){var b=a.keyboard.builtLayouts;e.$keyboard=e.scramble_setup(e.$keyboard),e.setScrambleLayout(),"undefined"==typeof b[g.layout]&&(b[g.layout]={mappedKeys:a.extend({},b[e.layout].mappedKeys),acceptedKeys:a.extend([],b[e.layout].acceptedKeys),$keyboard:e.$keyboard.clone()}),a.isFunction(d.init)&&d.init(e)},0):a.isFunction(d.init)&&d.init(e))})}});
@@ -0,0 +1,2 @@
1
+ /*! jQuery UI Virtual Keyboard Typing Simulator v1.10.2 */
2
+ !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){a.fn.addTyping=function(b){var c={showTyping:!0,lockTypeIn:!1,delay:250},d=a.keyboard;return this.each(function(){var e,f=a(this).data("keyboard");f&&(e=f.typing_options=a.extend({},c,b),f.typing_keymap={" ":"space",'"':"34","'":"39","&nbsp;":"space","\b":"bksp","{b}":"bksp","{d}":"del","{l}":"left","{r}":"right","\n":"enter","\r":"enter","{e}":"enter"," ":"tab","{t}":"tab"},f.typing_xref={8:"bksp",9:"tab",13:"enter",32:"space",37:"left",39:"right",46:"del"},f.typing_event=!1,f.typing_namespace=f.namespace+"typing",f.extensionNamespace.push(f.typing_namespace),e.savedLockInput=f.options.lockInput,f.typing_setup=function(){var a=d.events,b=f.typing_namespace;f.$el.unbind(b).bind([a.kbHidden,a.kbInactive,""].join(b+" "),function(a){f.typing_reset()}).bind(d.events.kbBeforeVisible+b,function(){f.typing_setup()}),f.$allKeys.unbind(b).bind("mousedown"+b,function(){f.typing_reset()}),f.$preview.unbind(b).bind("keyup"+b,function(a){if(e.init&&e.lockTypeIn)return!1;if(!(a.which>=37&&a.which<=40))return 16===a.which&&(f.shiftActive=!1),18===a.which&&(f.altActive=!1),16===a.which||18===a.which?(f.showSet(),void setTimeout(function(){f.$preview.focus()},200)):void 0}).bind("keydown"+b,function(a){return e.init&&e.lockTypeIn?!1:(a.temp=!1,16===a.which&&(a.temp=!f.shiftActive,f.shiftActive=!0),18===a.which&&(a.temp=!f.altActive,f.altActive=!0),a.temp&&(f.showSet(),f.$preview.focus()),f.typing_event=!0,void(f.typing_xref[a.which]&&f.typing_findKey("",a)))}).bind("keypress"+b,function(a){return e.init&&e.lockTypeIn?!1:void(f.typing_event&&!f.options.lockInput&&(f.typing_reset(),f.typing_event=!0,f.typing_findKey("",a)))})},f.typing_reset=function(){f.typing_event=e.init=!1,e.text="",e.len=e.current=0,f.options.lockInput=e.savedLockInput},f.typeIn=function(a,b,c,d){if(!f.isVisible())return clearTimeout(f.typing_timer),void f.typing_reset();if(f.typing_event){if("undefined"==typeof a)return f.typing_event=!1,void(f.options.lockInput=e.savedLockInput)}else e.init!==!0&&(e.init=!0,f.options.lockInput=e.lockTypeIn,e.text=a||e.text||"",e.len=e.text.length,e.delay=b||300,e.current=0,c&&(e.callback=c)),a=e.text.substring(e.current,++e.current),"{"===a&&"}"===e.text.substring(e.current+1,e.current+2)&&(a+=e.text.substring(e.current,e.current+=2)),f.typing_findKey(a,d)},f.typing_findKey=function(b,c){var g,h,i,j,k,l,m,n,o=d.css,p=d.builtLayouts[f.layout].mappedKeys;if(f.isOpen&&f.$keyboard.length)if(l=f.$keyboard.find("."+o.keySet),j=b in f.typing_keymap?f.typing_keymap[b]:b,g="."+o.keyButton+'[data-action="'+j+'"]',f.typing_event&&c&&("keypress"!==c.type&&f.typing_xref.hasOwnProperty(c.keyCode||c.which)?g="."+o.keyPrefix+f.processName(f.typing_xref[c.keyCode||c.which]):(h=String.fromCharCode(c.charCode||c.which),g=p.hasOwnProperty(h)?"."+o.keyButton+'[data-value="'+p[h].replace(/"/g,'\\"')+'"]':"."+o.keyPrefix+f.processName(h))),k=l.filter(":visible").find(g),k.length?f.typing_simulateKey(k,b,c):(f.typing_event?k=l.find(g):(i=b in f.typing_keymap?f.typing_keymap[b]:f.processName(b),k=l.find("."+o.keyPrefix+i)),n=k.closest("."+o.keySet),n.attr("name")?(m=n.attr("name"),f.shiftActive=/shift/.test(m),f.altActive=/alt/.test(m),f.metaActive=f.last.keyset[2]=m.match(/meta\d+/)||!1,f.showSet(f.metaActive),f.typing_simulateKey(k,b,c)):f.typing_event||(b in f.typing_keymap&&f.typing_keymap[b]in d.keyaction?d.keyaction[f.typing_keymap[b]](f,k,c):f.insertText(b),f.checkCombos(),f.$el.trigger(d.events.kbChange,[f,f.el]))),e.current<=e.len&&0!==e.len){if(!f.isVisible())return;setTimeout(function(){f.typeIn()},e.delay)}else{if(0!==e.len)return f.typing_reset(),void(a.isFunction(e.callback)&&setTimeout(function(){a.isFunction(e.callback)&&e.callback(f)},e.delay));f.typing_reset()}},f.typing_simulateKey=function(b,c,g){var h=b.length;h&&b.filter(":visible").trigger("mouseenter"+f.namespace),f.typing_timer=setTimeout(function(){var h=b.length;h&&setTimeout(function(){b.trigger("mouseleave"+f.namespace)},e.delay/3),f.isVisible()&&(f.typing_event||(c in f.typing_keymap&&f.typing_keymap[c]in d.keyaction?(g=g||a.Event("keypress"),g.target=b,d.keyaction[f.typing_keymap[c]](f,b,g)):f.insertText(c),f.checkCombos(),f.$el.trigger(d.events.kbChange,[f,f.el])))},e.delay/3)},e.showTyping&&(f.options.alwaysOpen&&f.isVisible()?f.typing_setup():f.$el.unbind(d.events.kbBeforeVisible+f.typing_namespace).bind(d.events.kbBeforeVisible+f.typing_namespace,function(){f.typing_setup()})))})}});
@@ -0,0 +1,2924 @@
1
+ /*! jQuery UI Virtual Keyboard v1.25.27 *//*
2
+ Author: Jeremy Satterfield
3
+ Maintained: Rob Garrison (Mottie on github)
4
+ Licensed under the MIT License
5
+
6
+ An on-screen virtual keyboard embedded within the browser window which
7
+ will popup when a specified entry field is focused. The user can then
8
+ type and preview their input before Accepting or Canceling.
9
+
10
+ This plugin adds default class names to match jQuery UI theme styling.
11
+ Bootstrap & custom themes may also be applied - See
12
+ https://github.com/Mottie/Keyboard#themes
13
+
14
+ Requires:
15
+ jQuery v1.4.3+
16
+ Caret plugin (included)
17
+ Optional:
18
+ jQuery UI (position utility only) & CSS theme
19
+ jQuery mousewheel
20
+
21
+ Setup/Usage:
22
+ Please refer to https://github.com/Mottie/Keyboard/wiki
23
+
24
+ -----------------------------------------
25
+ Caret code modified from jquery.caret.1.02.js
26
+ Licensed under the MIT License:
27
+ http://www.opensource.org/licenses/mit-license.php
28
+ -----------------------------------------
29
+ */
30
+ /*jshint browser:true, jquery:true, unused:false */
31
+ /*global require:false, define:false, module:false */
32
+ ;(function (factory) {
33
+ if (typeof define === 'function' && define.amd) {
34
+ define(['jquery'], factory);
35
+ } else if (typeof module === 'object' && typeof module.exports === 'object') {
36
+ module.exports = factory(require('jquery'));
37
+ } else {
38
+ factory(jQuery);
39
+ }
40
+ }(function ($) {
41
+ 'use strict';
42
+ var $keyboard = $.keyboard = function (el, options) {
43
+ var o, base = this;
44
+
45
+ base.version = '1.25.27';
46
+
47
+ // Access to jQuery and DOM versions of element
48
+ base.$el = $(el);
49
+ base.el = el;
50
+
51
+ // Add a reverse reference to the DOM object
52
+ base.$el.data('keyboard', base);
53
+
54
+ base.init = function () {
55
+ var k, position, tmp,
56
+ kbcss = $keyboard.css,
57
+ kbevents = $keyboard.events;
58
+ base.settings = options || {};
59
+ // shallow copy position to prevent performance issues; see #357
60
+ if (options && options.position) {
61
+ position = $.extend({}, options.position);
62
+ options.position = null;
63
+ }
64
+ base.options = o = $.extend(true, {}, $keyboard.defaultOptions, options);
65
+ if (position) {
66
+ o.position = position;
67
+ options.position = position;
68
+ }
69
+
70
+ // keyboard is active (not destroyed);
71
+ base.el.active = true;
72
+ // unique keyboard namespace
73
+ base.namespace = '.keyboard' + Math.random().toString(16).slice(2);
74
+ // extension namespaces added here (to unbind listeners on base.$el upon destroy)
75
+ base.extensionNamespace = [];
76
+ // Shift and Alt key toggles, sets is true if a layout has more than one keyset
77
+ // used for mousewheel message
78
+ base.shiftActive = base.altActive = base.metaActive = base.sets = base.capsLock = false;
79
+ // Class names of the basic key set - meta keysets are handled by the keyname
80
+ base.rows = ['', '-shift', '-alt', '-alt-shift'];
81
+
82
+ base.inPlaceholder = base.$el.attr('placeholder') || '';
83
+ // html 5 placeholder/watermark
84
+ base.watermark = $keyboard.watermark && base.inPlaceholder !== '';
85
+ // convert mouse repeater rate (characters per second) into a time in milliseconds.
86
+ base.repeatTime = 1000 / (o.repeatRate || 20);
87
+ // delay in ms to prevent mousedown & touchstart from both firing events at the same time
88
+ o.preventDoubleEventTime = o.preventDoubleEventTime || 100;
89
+ // flag indication that a keyboard is open
90
+ base.isOpen = false;
91
+ // is mousewheel plugin loaded?
92
+ base.wheel = $.isFunction($.fn.mousewheel);
93
+ // special character in regex that need to be escaped
94
+ base.escapeRegex = /[-\/\\^$*+?.()|[\]{}]/g;
95
+
96
+ // keyCode of keys always allowed to be typed
97
+ k = $keyboard.keyCodes;
98
+ // base.alwaysAllowed = [20,33,34,35,36,37,38,39,40,45,46];
99
+ base.alwaysAllowed = [
100
+ k.capsLock,
101
+ k.pageUp,
102
+ k.pageDown,
103
+ k.end,
104
+ k.home,
105
+ k.left,
106
+ k.up,
107
+ k.right,
108
+ k.down,
109
+ k.insert,
110
+ k.delete
111
+ ];
112
+ base.$keyboard = [];
113
+ // keyboard enabled; set to false on destroy
114
+ base.enabled = true;
115
+ // make a copy of the original keyboard position
116
+ if (!$.isEmptyObject(o.position)) {
117
+ o.position.orig_at = o.position.at;
118
+ }
119
+
120
+ base.checkCaret = (o.lockInput || $keyboard.checkCaretSupport());
121
+
122
+ base.last = {
123
+ start: 0,
124
+ end: 0,
125
+ key: '',
126
+ val: '',
127
+ preVal: '',
128
+ layout: '',
129
+ virtual: true,
130
+ keyset: [false, false, false], // [shift, alt, meta]
131
+ wheel_$Keys: null,
132
+ wheelIndex: 0,
133
+ wheelLayers: []
134
+ };
135
+ // used when building the keyboard - [keyset element, row, index]
136
+ base.temp = ['', 0, 0];
137
+
138
+ // Callbacks
139
+ $.each([
140
+ kbevents.kbInit,
141
+ kbevents.kbBeforeVisible,
142
+ kbevents.kbVisible,
143
+ kbevents.kbHidden,
144
+ kbevents.inputCanceled,
145
+ kbevents.inputAccepted,
146
+ kbevents.kbBeforeClose
147
+ ], function (i, callback) {
148
+ if ($.isFunction(o[callback])) {
149
+ // bind callback functions within options to triggered events
150
+ base.$el.bind(callback + base.namespace + 'callbacks', o[callback]);
151
+ }
152
+ });
153
+
154
+ // Close with esc key & clicking outside
155
+ if (o.alwaysOpen) {
156
+ o.stayOpen = true;
157
+ }
158
+
159
+ tmp = $(document);
160
+ if (base.el.ownerDocument !== document) {
161
+ tmp = tmp.add(base.el.ownerDocument);
162
+ }
163
+ tmp.bind('mousedown keyup touchstart checkkeyboard '.split(' ')
164
+ .join(base.namespace + ' '), base.checkClose);
165
+
166
+ // Display keyboard on focus
167
+ base.$el
168
+ .addClass(kbcss.input + ' ' + o.css.input)
169
+ .attr({
170
+ 'aria-haspopup': 'true',
171
+ 'role': 'textbox'
172
+ });
173
+
174
+ // set lockInput if the element is readonly; or make the element readonly if lockInput is set
175
+ if (o.lockInput || base.el.readOnly) {
176
+ o.lockInput = true;
177
+ base.$el
178
+ .addClass(kbcss.locked)
179
+ .attr({
180
+ 'readonly': 'readonly'
181
+ });
182
+ }
183
+ // add disabled/readonly class - dynamically updated on reveal
184
+ if (base.$el.is(':disabled') || (base.$el.attr('readonly') &&
185
+ !base.$el.hasClass(kbcss.locked))) {
186
+ base.$el.addClass(kbcss.noKeyboard);
187
+ }
188
+
189
+ if (o.openOn) {
190
+ base.bindFocus();
191
+ }
192
+
193
+ // Add placeholder if not supported by the browser
194
+ if (!base.watermark && base.$el.val() === '' && base.inPlaceholder !== '' &&
195
+ base.$el.attr('placeholder') !== '') {
196
+ base.$el
197
+ .addClass(kbcss.placeholder) // css watermark style (darker text)
198
+ .val(base.inPlaceholder);
199
+ }
200
+
201
+ base.$el.trigger(kbevents.kbInit, [base, base.el]);
202
+
203
+ // initialized with keyboard open
204
+ if (o.alwaysOpen) {
205
+ base.reveal();
206
+ }
207
+
208
+ };
209
+
210
+ base.toggle = function () {
211
+ var $toggle = base.$keyboard.find('.' + $keyboard.css.keyToggle),
212
+ locked = !base.enabled;
213
+ // prevent physical keyboard from working
214
+ base.$preview.prop('readonly', locked || base.options.lockInput);
215
+ // disable all buttons
216
+ base.$keyboard
217
+ .toggleClass($keyboard.css.keyDisabled, locked)
218
+ .find('.' + $keyboard.css.keyButton)
219
+ .not($toggle)
220
+ .prop('disabled', locked)
221
+ .attr('aria-disabled', locked);
222
+ $toggle.toggleClass($keyboard.css.keyDisabled, locked);
223
+ // stop auto typing
224
+ if (locked && base.typing_options) {
225
+ base.typing_options.text = '';
226
+ }
227
+ };
228
+
229
+ base.setCurrent = function () {
230
+ var kbcss = $keyboard.css,
231
+ // close any "isCurrent" keyboard (just in case they are always open)
232
+ $current = $('.' + kbcss.isCurrent),
233
+ kb = $current.data('keyboard');
234
+ // close keyboard, if not self
235
+ if (!$.isEmptyObject(kb) && kb.el !== base.el) {
236
+ kb.close(kb.options.autoAccept ? 'true' : false);
237
+ }
238
+ $current.removeClass(kbcss.isCurrent);
239
+ // ui-keyboard-has-focus is applied in case multiple keyboards have
240
+ // alwaysOpen = true and are stacked
241
+ $('.' + kbcss.hasFocus).removeClass(kbcss.hasFocus);
242
+
243
+ base.$el.addClass(kbcss.isCurrent);
244
+ base.$keyboard.addClass(kbcss.hasFocus);
245
+ base.isCurrent(true);
246
+ base.isOpen = true;
247
+ };
248
+
249
+ base.isCurrent = function (set) {
250
+ var cur = $keyboard.currentKeyboard || false;
251
+ if (set) {
252
+ cur = $keyboard.currentKeyboard = base.el;
253
+ } else if (set === false && cur === base.el) {
254
+ cur = $keyboard.currentKeyboard = '';
255
+ }
256
+ return cur === base.el;
257
+ };
258
+
259
+ base.isVisible = function () {
260
+ return base.$keyboard && base.$keyboard.length ? base.$keyboard.is(':visible') : false;
261
+ };
262
+
263
+ base.focusOn = function () {
264
+ if (!base && base.el.active) {
265
+ // keyboard was destroyed
266
+ return;
267
+ }
268
+ if (!base.isVisible()) {
269
+ clearTimeout(base.timer);
270
+ base.reveal();
271
+ }
272
+ };
273
+
274
+ // add redraw method to make API more clear
275
+ base.redraw = function () {
276
+ // update keyboard after a layout change
277
+ if (base.$keyboard.length) {
278
+
279
+ base.last.preVal = '' + base.last.val;
280
+ base.last.val = base.$preview && base.$preview.val() || base.$el.val();
281
+ base.$el.val( base.last.val );
282
+
283
+ base.removeKeyboard();
284
+ base.shiftActive = base.altActive = base.metaActive = false;
285
+ }
286
+ base.isOpen = o.alwaysOpen;
287
+ base.reveal(true);
288
+ };
289
+
290
+ base.reveal = function (redraw) {
291
+ var alreadyOpen = base.isOpen,
292
+ kbcss = $keyboard.css;
293
+ base.opening = !alreadyOpen;
294
+ // remove all 'extra' keyboards by calling close function
295
+ $('.' + kbcss.keyboard).not('.' + kbcss.alwaysOpen).each(function(){
296
+ var kb = $(this).data('keyboard');
297
+ if (!$.isEmptyObject(kb)) {
298
+ kb.close(kb.options.autoAccept && kb.options.autoAcceptOnEsc ? 'true' : false);
299
+ }
300
+ });
301
+
302
+ // Don't open if disabled
303
+ if (base.$el.is(':disabled') || (base.$el.attr('readonly') && !base.$el.hasClass(kbcss.locked))) {
304
+ base.$el.addClass(kbcss.noKeyboard);
305
+ return;
306
+ } else {
307
+ base.$el.removeClass(kbcss.noKeyboard);
308
+ }
309
+
310
+ // Unbind focus to prevent recursion - openOn may be empty if keyboard is opened externally
311
+ if (o.openOn) {
312
+ base.$el.unbind($.trim((o.openOn + ' ').split(/\s+/).join(base.namespace + ' ')));
313
+ }
314
+
315
+ // build keyboard if it doesn't exist; or attach keyboard if it was removed, but not cleared
316
+ if (!base.$keyboard || base.$keyboard &&
317
+ (!base.$keyboard.length || $.contains(document.body, base.$keyboard[0]))) {
318
+ base.startup();
319
+ }
320
+
321
+ // clear watermark
322
+ if (!base.watermark && base.el.value === base.inPlaceholder) {
323
+ base.$el
324
+ .removeClass(kbcss.placeholder)
325
+ .val('');
326
+ }
327
+ // save starting content, in case we cancel
328
+ base.originalContent = base.$el.val();
329
+ base.$preview.val(base.originalContent);
330
+
331
+ // disable/enable accept button
332
+ if (o.acceptValid) {
333
+ base.checkValid();
334
+ }
335
+
336
+ if (o.resetDefault) {
337
+ base.shiftActive = base.altActive = base.metaActive = false;
338
+ }
339
+ base.showSet();
340
+
341
+ // beforeVisible event
342
+ if (!base.isVisible()) {
343
+ base.$el.trigger($keyboard.events.kbBeforeVisible, [base, base.el]);
344
+ }
345
+ base.setCurrent();
346
+ // update keyboard - enabled or disabled?
347
+ base.toggle();
348
+
349
+ // show keyboard
350
+ base.$keyboard.show();
351
+
352
+ // adjust keyboard preview window width - save width so IE won't keep expanding (fix issue #6)
353
+ if (o.usePreview && $keyboard.msie) {
354
+ if (typeof base.width === 'undefined') {
355
+ base.$preview.hide(); // preview is 100% browser width in IE7, so hide the damn thing
356
+ base.width = Math.ceil(base.$keyboard.width()); // set input width to match the widest keyboard row
357
+ base.$preview.show();
358
+ }
359
+ base.$preview.width(base.width);
360
+ }
361
+
362
+ base.position = $.isEmptyObject(o.position) ? false : o.position;
363
+
364
+ // position after keyboard is visible (required for UI position utility) and appropriately sized
365
+ if ($.ui && $.ui.position && base.position) {
366
+ // get single target position || target stored in element data (multiple targets) || default @ element
367
+ base.position.of = base.position.of || base.$el.data('keyboardPosition') || base.$el;
368
+ base.position.collision = base.position.collision || 'flipfit flipfit';
369
+ o.position.at = o.usePreview ? o.position.orig_at : o.position.at2;
370
+ base.$keyboard.position(base.position);
371
+ }
372
+
373
+ base.checkDecimal();
374
+
375
+ // get preview area line height
376
+ // add roughly 4px to get line height from font height, works well for font-sizes from 14-36px
377
+ // needed for textareas
378
+ base.lineHeight = parseInt(base.$preview.css('lineHeight'), 10) ||
379
+ parseInt(base.$preview.css('font-size'), 10) + 4;
380
+
381
+ if (o.caretToEnd) {
382
+ base.saveCaret(base.originalContent.length, base.originalContent.length);
383
+ }
384
+
385
+ // IE caret haxx0rs
386
+ if ($keyboard.allie) {
387
+ // sometimes end = 0 while start is > 0
388
+ if (base.last.end === 0 && base.last.start > 0) {
389
+ base.last.end = base.last.start;
390
+ }
391
+ // IE will have start -1, end of 0 when not focused (see demo: http://jsfiddle.net/Mottie/fgryQ/3/)
392
+ if (base.last.start < 0) {
393
+ // ensure caret is at the end of the text (needed for IE)
394
+ base.last.start = base.last.end = base.originalContent.length;
395
+ }
396
+ }
397
+
398
+ if (alreadyOpen || redraw) {
399
+ // restore caret position (userClosed)
400
+ $keyboard.caret(base.$preview, base.last);
401
+ return base;
402
+ }
403
+
404
+ // opening keyboard flag; delay allows switching between keyboards without immediately closing
405
+ // the keyboard
406
+ base.timer2 = setTimeout(function () {
407
+ var undef;
408
+ base.opening = false;
409
+ // Number inputs don't support selectionStart and selectionEnd
410
+ // Number/email inputs don't support selectionStart and selectionEnd
411
+ if (!/(number|email)/i.test(base.el.type) && !o.caretToEnd) {
412
+ // caret position is always 0,0 in webkit; and nothing is focused at this point... odd
413
+ // save caret position in the input to transfer it to the preview
414
+ // inside delay to get correct caret position
415
+ base.saveCaret(undef, undef, base.$el);
416
+ }
417
+ if (o.initialFocus) {
418
+ $keyboard.caret(base.$preview, base.last);
419
+ }
420
+ // save event time for keyboards with stayOpen: true
421
+ base.last.eventTime = new Date().getTime();
422
+ base.$el.trigger($keyboard.events.kbVisible, [base, base.el]);
423
+ base.timer = setTimeout(function () {
424
+ // get updated caret information after visible event - fixes #331
425
+ if (base) { // Check if base exists, this is a case when destroy is called, before timers fire
426
+ base.saveCaret();
427
+ }
428
+ }, 200);
429
+ }, 10);
430
+ // return base to allow chaining in typing extension
431
+ return base;
432
+ };
433
+
434
+ base.updateLanguage = function () {
435
+ // change language if layout is named something like 'french-azerty-1'
436
+ var layouts = $keyboard.layouts,
437
+ lang = o.language || layouts[o.layout] && layouts[o.layout].lang &&
438
+ layouts[o.layout].lang || [o.language || 'en'],
439
+ kblang = $keyboard.language;
440
+
441
+ // some languages include a dash, e.g. 'en-gb' or 'fr-ca'
442
+ // allow o.language to be a string or array...
443
+ // array is for future expansion where a layout can be set for multiple languages
444
+ lang = ($.isArray(lang) ? lang[0] : lang).split('-')[0];
445
+
446
+ // set keyboard language
447
+ o.display = $.extend(true, {},
448
+ kblang.en.display,
449
+ kblang[lang] && kblang[lang].display || {},
450
+ base.settings.display
451
+ );
452
+ o.combos = $.extend(true, {},
453
+ kblang.en.combos,
454
+ kblang[lang] && kblang[lang].combos || {},
455
+ base.settings.combos
456
+ );
457
+ o.wheelMessage = kblang[lang] && kblang[lang].wheelMessage || kblang.en.wheelMessage;
458
+ // rtl can be in the layout or in the language definition; defaults to false
459
+ o.rtl = layouts[o.layout] && layouts[o.layout].rtl || kblang[lang] && kblang[lang].rtl || false;
460
+
461
+ // save default regex (in case loading another layout changes it)
462
+ base.regex = kblang[lang] && kblang[lang].comboRegex || $keyboard.comboRegex;
463
+ // determine if US '.' or European ',' system being used
464
+ base.decimal = /^\./.test(o.display.dec);
465
+ base.$el
466
+ .toggleClass('rtl', o.rtl)
467
+ .css('direction', o.rtl ? 'rtl' : '');
468
+ };
469
+
470
+ base.startup = function () {
471
+ var kbcss = $keyboard.css;
472
+ // ensure base.$preview is defined; but don't overwrite it if keyboard is always visible
473
+ if (!((o.alwaysOpen || o.userClosed) && base.$preview)) {
474
+ base.makePreview();
475
+ }
476
+ if (!(base.$keyboard && base.$keyboard.length)) {
477
+ // custom layout - create a unique layout name based on the hash
478
+ if (o.layout === 'custom') {
479
+ o.layoutHash = 'custom' + base.customHash();
480
+ }
481
+ base.layout = o.layout === 'custom' ? o.layoutHash : o.layout;
482
+ base.last.layout = base.layout;
483
+
484
+ base.updateLanguage();
485
+ if (typeof $keyboard.builtLayouts[base.layout] === 'undefined') {
486
+ if ($.isFunction(o.create)) {
487
+ // create must call buildKeyboard() function; or create it's own keyboard
488
+ base.$keyboard = o.create(base);
489
+ } else if (!base.$keyboard.length) {
490
+ base.buildKeyboard(base.layout, true);
491
+ }
492
+ }
493
+ base.$keyboard = $keyboard.builtLayouts[base.layout].$keyboard.clone();
494
+ base.$keyboard.data('keyboard', base);
495
+ if ((base.el.id || '') !== '') {
496
+ // add ID to keyboard for styling purposes
497
+ base.$keyboard.attr('id', base.el.id + $keyboard.css.idSuffix);
498
+ }
499
+
500
+ base.makePreview();
501
+ // build preview display
502
+ if (o.usePreview) {
503
+ // restore original positioning (in case usePreview option is altered)
504
+ if (!$.isEmptyObject(o.position)) {
505
+ o.position.at = o.position.orig_at;
506
+ }
507
+ } else {
508
+ // No preview display, use element and reposition the keyboard under it.
509
+ if (!$.isEmptyObject(o.position)) {
510
+ o.position.at = o.position.at2;
511
+ }
512
+ }
513
+
514
+ }
515
+
516
+ base.$decBtn = base.$keyboard.find('.' + kbcss.keyPrefix + 'dec');
517
+ // add enter to allowed keys; fixes #190
518
+ if (o.enterNavigation || base.el.nodeName === 'TEXTAREA') {
519
+ base.alwaysAllowed.push(13);
520
+ }
521
+
522
+ base.bindKeyboard();
523
+
524
+ base.$keyboard.appendTo(o.appendLocally ? base.$el.parent() : o.appendTo || 'body');
525
+
526
+ base.bindKeys();
527
+
528
+ // adjust with window resize; don't check base.position
529
+ // here in case it is changed dynamically
530
+ if (o.reposition && $.ui && $.ui.position && o.appendTo == 'body') {
531
+ $(window).bind('resize' + base.namespace, function () {
532
+ if (base.position && base.isVisible()) {
533
+ base.$keyboard.position(base.position);
534
+ }
535
+ });
536
+ }
537
+
538
+ };
539
+
540
+ base.makePreview = function () {
541
+ if (o.usePreview) {
542
+ var indx, attrs, attr, removedAttr,
543
+ kbcss = $keyboard.css;
544
+ base.$preview = base.$el.clone(false)
545
+ .data('keyboard', base)
546
+ .removeClass(kbcss.placeholder + ' ' + kbcss.input)
547
+ .addClass(kbcss.preview + ' ' + o.css.input)
548
+ .attr('tabindex', '-1')
549
+ .show(); // for hidden inputs
550
+ base.preview = base.$preview[0];
551
+
552
+ // Switch the number input field to text so the caret positioning will work again
553
+ if (base.preview.type === 'number') {
554
+ base.preview.type = 'text';
555
+ }
556
+
557
+ // remove extraneous attributes.
558
+ removedAttr = /^(data-|id|aria-haspopup)/i;
559
+ attrs = base.$preview.get(0).attributes;
560
+ for (indx = attrs.length - 1; indx >= 0; indx--) {
561
+ attr = attrs[indx] && attrs[indx].name;
562
+ if (removedAttr.test(attr)) {
563
+ // remove data-attributes - see #351
564
+ base.preview.removeAttribute(attr);
565
+ }
566
+ }
567
+ // build preview container and append preview display
568
+ $('<div />')
569
+ .addClass(kbcss.wrapper)
570
+ .append(base.$preview)
571
+ .prependTo(base.$keyboard);
572
+ } else {
573
+ base.$preview = base.$el;
574
+ base.preview = base.el;
575
+ }
576
+ };
577
+
578
+ base.saveCaret = function (start, end, $el) {
579
+ var p = $keyboard.caret($el || base.$preview, start, end);
580
+ base.last.start = typeof start === 'undefined' ? p.start : start;
581
+ base.last.end = typeof end === 'undefined' ? p.end : end;
582
+ };
583
+
584
+ base.setScroll = function () {
585
+ // Set scroll so caret & current text is in view
586
+ // needed for virtual keyboard typing, NOT manual typing - fixes #23
587
+ if (base.last.virtual) {
588
+
589
+ var scrollWidth, clientWidth, adjustment, direction,
590
+ isTextarea = base.preview.nodeName === 'TEXTAREA',
591
+ value = base.last.val.substring(0, Math.max(base.last.start, base.last.end));
592
+
593
+ if (!base.$previewCopy) {
594
+ // clone preview
595
+ base.$previewCopy = base.$preview.clone()
596
+ .removeAttr('id') // fixes #334
597
+ .css({
598
+ position: 'absolute',
599
+ left: 0,
600
+ zIndex: -10,
601
+ visibility: 'hidden'
602
+ })
603
+ .addClass($keyboard.css.inputClone);
604
+ if (!isTextarea) {
605
+ // make input zero-width because we need an accurate scrollWidth
606
+ base.$previewCopy.css({
607
+ 'white-space': 'pre',
608
+ 'width': 0
609
+ });
610
+ }
611
+ if (o.usePreview) {
612
+ // add clone inside of preview wrapper
613
+ base.$preview.after(base.$previewCopy);
614
+ } else {
615
+ // just slap that thing in there somewhere
616
+ base.$keyboard.prepend(base.$previewCopy);
617
+ }
618
+ }
619
+
620
+ if (isTextarea) {
621
+ // need the textarea scrollHeight, so set the clone textarea height to be the line height
622
+ base.$previewCopy
623
+ .height(base.lineHeight)
624
+ .val(value);
625
+ // set scrollTop for Textarea
626
+ base.preview.scrollTop = base.lineHeight *
627
+ (Math.floor(base.$previewCopy[0].scrollHeight / base.lineHeight) - 1);
628
+ } else {
629
+ // add non-breaking spaces
630
+ base.$previewCopy.val(value.replace(/\s/g, '\xa0'));
631
+
632
+ // if scrollAdjustment option is set to "c" or "center" then center the caret
633
+ adjustment = /c/i.test(o.scrollAdjustment) ? base.preview.clientWidth / 2 : o.scrollAdjustment;
634
+ scrollWidth = base.$previewCopy[0].scrollWidth - 1;
635
+
636
+ // set initial state as moving right
637
+ if (typeof base.last.scrollWidth === 'undefined') {
638
+ base.last.scrollWidth = scrollWidth;
639
+ base.last.direction = true;
640
+ }
641
+ // if direction = true; we're scrolling to the right
642
+ direction = base.last.scrollWidth === scrollWidth ?
643
+ base.last.direction :
644
+ base.last.scrollWidth < scrollWidth;
645
+ clientWidth = base.preview.clientWidth - adjustment;
646
+
647
+ // set scrollLeft for inputs; try to mimic the inherit caret positioning + scrolling:
648
+ // hug right while scrolling right...
649
+ if (direction) {
650
+ if (scrollWidth < clientWidth) {
651
+ base.preview.scrollLeft = 0;
652
+ } else {
653
+ base.preview.scrollLeft = scrollWidth - clientWidth;
654
+ }
655
+ } else {
656
+ // hug left while scrolling left...
657
+ if (scrollWidth >= base.preview.scrollWidth - clientWidth) {
658
+ base.preview.scrollLeft = base.preview.scrollWidth - adjustment;
659
+ } else if (scrollWidth - adjustment > 0) {
660
+ base.preview.scrollLeft = scrollWidth - adjustment;
661
+ } else {
662
+ base.preview.scrollLeft = 0;
663
+ }
664
+ }
665
+
666
+ base.last.scrollWidth = scrollWidth;
667
+ base.last.direction = direction;
668
+ }
669
+ }
670
+ };
671
+
672
+ base.bindFocus = function () {
673
+ if (o.openOn) {
674
+ // make sure keyboard isn't destroyed
675
+ // Check if base exists, this is a case when destroy is called, before timers have fired
676
+ if (base && base.el.active) {
677
+ base.$el.bind(o.openOn + base.namespace, function () {
678
+ base.focusOn();
679
+ });
680
+ // remove focus from element (needed for IE since blur doesn't seem to work)
681
+ if ($(':focus')[0] === base.el) {
682
+ base.$el.blur();
683
+ }
684
+ }
685
+ }
686
+ };
687
+
688
+ base.bindKeyboard = function () {
689
+ var evt,
690
+ keyCodes = $keyboard.keyCodes,
691
+ layout = $keyboard.builtLayouts[base.layout];
692
+ base.$preview
693
+ .unbind(base.namespace)
694
+ .bind('click' + base.namespace + ' touchstart' + base.namespace, function () {
695
+ if (o.alwaysOpen && !base.isCurrent()) {
696
+ base.reveal();
697
+ }
698
+ // update last caret position after user click, use at least 150ms or it doesn't work in IE
699
+ base.timer2 = setTimeout(function () {
700
+ if (base){
701
+ base.saveCaret();
702
+ }
703
+ }, 150);
704
+
705
+ })
706
+ .bind('keypress' + base.namespace, function (e) {
707
+ if (o.lockInput) {
708
+ return false;
709
+ }
710
+ var k = e.charCode || e.which,
711
+ // capsLock can only be checked while typing a-z
712
+ k1 = k >= keyCodes.A && k <= keyCodes.Z,
713
+ k2 = k >= keyCodes.a && k <= keyCodes.z,
714
+ str = base.last.key = String.fromCharCode(k);
715
+ base.last.virtual = false;
716
+ base.last.event = e;
717
+ base.last.$key = []; // not a virtual keyboard key
718
+ if (base.checkCaret) {
719
+ base.saveCaret();
720
+ }
721
+
722
+ // update capsLock
723
+ if (k !== keyCodes.capsLock && (k1 || k2)) {
724
+ base.capsLock = (k1 && !e.shiftKey) || (k2 && e.shiftKey);
725
+ // if shifted keyset not visible, then show it
726
+ if (base.capsLock && !base.shiftActive) {
727
+ base.shiftActive = true;
728
+ base.showSet();
729
+ }
730
+ }
731
+
732
+ // restrict input - keyCode in keypress special keys:
733
+ // see http://www.asquare.net/javascript/tests/KeyCode.html
734
+ if (o.restrictInput) {
735
+ // allow navigation keys to work - Chrome doesn't fire a keypress event (8 = bksp)
736
+ if ((e.which === keyCodes.backSpace || e.which === 0) &&
737
+ $.inArray(e.keyCode, base.alwaysAllowed)) {
738
+ return;
739
+ }
740
+ // quick key check
741
+ if ($.inArray(str, layout.acceptedKeys) === -1) {
742
+ e.preventDefault();
743
+ // copy event object in case e.preventDefault() breaks when changing the type
744
+ evt = $.extend({}, e);
745
+ evt.type = $keyboard.events.inputRestricted;
746
+ base.$el.trigger(evt, [base, base.el]);
747
+ if ($.isFunction(o.restricted)) {
748
+ o.restricted(evt, base, base.el);
749
+ }
750
+ }
751
+ } else if ((e.ctrlKey || e.metaKey) &&
752
+ (e.which === keyCodes.A || e.which === keyCodes.C || e.which === keyCodes.V ||
753
+ (e.which >= keyCodes.X && e.which <= keyCodes.Z))) {
754
+ // Allow select all (ctrl-a), copy (ctrl-c), paste (ctrl-v) & cut (ctrl-x) &
755
+ // redo (ctrl-y)& undo (ctrl-z); meta key for mac
756
+ return;
757
+ }
758
+ // Mapped Keys - allows typing on a regular keyboard and the mapped key is entered
759
+ // Set up a key in the layout as follows: 'm(a):label'; m = key to map, (a) = actual keyboard key
760
+ // to map to (optional), ':label' = title/tooltip (optional)
761
+ // example: \u0391 or \u0391(A) or \u0391:alpha or \u0391(A):alpha
762
+ if (layout.hasMappedKeys && layout.mappedKeys.hasOwnProperty(str)) {
763
+ base.last.key = layout.mappedKeys[str];
764
+ base.insertText(base.last.key);
765
+ e.preventDefault();
766
+ }
767
+ base.checkMaxLength();
768
+
769
+ })
770
+ .bind('keyup' + base.namespace, function (e) {
771
+ base.last.virtual = false;
772
+ switch (e.which) {
773
+ // Insert tab key
774
+ case keyCodes.tab:
775
+ // Added a flag to prevent from tabbing into an input, keyboard opening, then adding the tab
776
+ // to the keyboard preview area on keyup. Sadly it still happens if you don't release the tab
777
+ // key immediately because keydown event auto-repeats
778
+ if (base.tab && o.tabNavigation && !o.lockInput) {
779
+ base.shiftActive = e.shiftKey;
780
+ // when switching inputs, the tab keyaction returns false
781
+ var notSwitching = $keyboard.keyaction.tab(base);
782
+ base.tab = false;
783
+ if (!notSwitching) {
784
+ return false;
785
+ }
786
+ } else {
787
+ e.preventDefault();
788
+ }
789
+ break;
790
+
791
+ // Escape will hide the keyboard
792
+ case keyCodes.escape:
793
+ if (!o.ignoreEsc) {
794
+ base.close(o.autoAccept && o.autoAcceptOnEsc ? 'true' : false);
795
+ }
796
+ return false;
797
+ }
798
+
799
+ // throttle the check combo function because fast typers will have an incorrectly positioned caret
800
+ clearTimeout(base.throttled);
801
+ base.throttled = setTimeout(function () {
802
+ // fix error in OSX? see issue #102
803
+ if (base && base.isVisible()) {
804
+ base.checkCombos();
805
+ }
806
+ }, 100);
807
+
808
+ base.checkMaxLength();
809
+
810
+ base.last.preVal = '' + base.last.val;
811
+ base.last.val = base.$preview.val();
812
+ e.type = $keyboard.events.kbChange;
813
+ // base.last.key may be empty string (shift, enter, tab, etc) when keyboard is first visible
814
+ // use e.key instead, if browser supports it
815
+ e.action = base.last.key;
816
+ base.$el.trigger(e, [base, base.el]);
817
+
818
+ // change callback is no longer bound to the input element as the callback could be
819
+ // called during an external change event with all the necessary parameters (issue #157)
820
+ if ($.isFunction(o.change)) {
821
+ e.type = $keyboard.events.inputChange;
822
+ o.change(e, base, base.el);
823
+ return false;
824
+ }
825
+ })
826
+ .bind('keydown' + base.namespace, function (e) {
827
+ // ensure alwaysOpen keyboards are made active
828
+ if (o.alwaysOpen && !base.isCurrent()) {
829
+ base.reveal();
830
+ }
831
+ // prevent tab key from leaving the preview window
832
+ if (e.which === keyCodes.tab) {
833
+ // allow tab to pass through - tab to next input/shift-tab for prev
834
+ base.tab = true;
835
+ return false;
836
+ }
837
+
838
+ if (o.lockInput) {
839
+ return false;
840
+ }
841
+
842
+ base.last.virtual = false;
843
+ switch (e.which) {
844
+
845
+ case keyCodes.backSpace:
846
+ $keyboard.keyaction.bksp(base, null, e);
847
+ e.preventDefault();
848
+ break;
849
+
850
+ case keyCodes.enter:
851
+ $keyboard.keyaction.enter(base, null, e);
852
+ break;
853
+
854
+ // Show capsLock
855
+ case keyCodes.capsLock:
856
+ base.shiftActive = base.capsLock = !base.capsLock;
857
+ base.showSet();
858
+ break;
859
+
860
+ case keyCodes.V:
861
+ // prevent ctrl-v/cmd-v
862
+ if (e.ctrlKey || e.metaKey) {
863
+ if (o.preventPaste) {
864
+ e.preventDefault();
865
+ return;
866
+ }
867
+ base.checkCombos(); // check pasted content
868
+ }
869
+ break;
870
+ }
871
+ })
872
+ .bind('mouseup touchend '.split(' ').join(base.namespace + ' '), function () {
873
+ base.last.virtual = true;
874
+ base.saveCaret();
875
+ });
876
+
877
+ // prevent keyboard event bubbling
878
+ base.$keyboard.bind('mousedown click touchstart '.split(' ').join(base.namespace + ' '), function (e) {
879
+ e.stopPropagation();
880
+ if (!base.isCurrent()) {
881
+ base.reveal();
882
+ $(document).trigger('checkkeyboard' + base.namespace);
883
+ }
884
+ if (!o.noFocus) {
885
+ base.$preview.focus();
886
+ }
887
+ });
888
+
889
+ // If preventing paste, block context menu (right click)
890
+ if (o.preventPaste) {
891
+ base.$preview.bind('contextmenu' + base.namespace, function (e) {
892
+ e.preventDefault();
893
+ });
894
+ base.$el.bind('contextmenu' + base.namespace, function (e) {
895
+ e.preventDefault();
896
+ });
897
+ }
898
+
899
+ };
900
+
901
+ base.bindKeys = function () {
902
+ var kbcss = $keyboard.css;
903
+ base.$allKeys = base.$keyboard.find('button.' + kbcss.keyButton)
904
+ .unbind(base.namespace + ' ' + base.namespace + 'kb')
905
+ // Change hover class and tooltip - moved this touchstart before option.keyBinding touchstart
906
+ // to prevent mousewheel lag/duplication - Fixes #379 & #411
907
+ .bind('mouseenter mouseleave touchstart '.split(' ').join(base.namespace + ' '), function (e) {
908
+ if ((o.alwaysOpen || o.userClosed) && e.type !== 'mouseleave' && !base.isCurrent()) {
909
+ base.reveal();
910
+ base.$preview.focus();
911
+ $keyboard.caret(base.$preview, base.last);
912
+ }
913
+ if (!base.isCurrent()) {
914
+ return;
915
+ }
916
+ var $keys, txt,
917
+ last = base.last,
918
+ $this = $(this),
919
+ type = e.type;
920
+
921
+ if (o.useWheel && base.wheel) {
922
+ $keys = base.getLayers($this);
923
+ txt = ($keys.length ? $keys.map(function () {
924
+ return $(this).attr('data-value') || '';
925
+ })
926
+ .get() : '') || [$this.text()];
927
+ last.wheel_$Keys = $keys;
928
+ last.wheelLayers = txt;
929
+ last.wheelIndex = $.inArray($this.attr('data-value'), txt);
930
+ }
931
+
932
+ if ((type === 'mouseenter' || type === 'touchstart') && base.el.type !== 'password' &&
933
+ !$this.hasClass(o.css.buttonDisabled)) {
934
+ $this.addClass(o.css.buttonHover);
935
+ if (o.useWheel && base.wheel) {
936
+ $this.attr('title', function (i, t) {
937
+ // show mouse wheel message
938
+ return (base.wheel && t === '' && base.sets && txt.length > 1 && type !== 'touchstart') ?
939
+ o.wheelMessage : t;
940
+ });
941
+ }
942
+ }
943
+ if (type === 'mouseleave') {
944
+ // needed or IE flickers really bad
945
+ $this.removeClass((base.el.type === 'password') ? '' : o.css.buttonHover);
946
+ if (o.useWheel && base.wheel) {
947
+ last.wheelIndex = 0;
948
+ last.wheelLayers = [];
949
+ last.wheel_$Keys = null;
950
+ $this
951
+ .attr('title', function (i, t) {
952
+ return (t === o.wheelMessage) ? '' : t;
953
+ })
954
+ .html($this.attr('data-html')); // restore original button text
955
+ }
956
+ }
957
+ })
958
+ // keyBinding = 'mousedown touchstart' by default
959
+ .bind(o.keyBinding.split(' ').join(base.namespace + ' ') + base.namespace + ' ' +
960
+ $keyboard.events.kbRepeater, function (e) {
961
+ e.preventDefault();
962
+ // prevent errors when external triggers attempt to 'type' - see issue #158
963
+ if (!base.$keyboard.is(':visible')) {
964
+ return false;
965
+ }
966
+ var action, $keys,
967
+ last = base.last,
968
+ key = this,
969
+ $key = $(key),
970
+ // prevent mousedown & touchstart from both firing events at the same time - see #184
971
+ timer = new Date().getTime();
972
+
973
+ if (o.useWheel && base.wheel) {
974
+ // get keys from other layers/keysets (shift, alt, meta, etc) that line up by data-position
975
+ $keys = last.wheel_$Keys;
976
+ // target mousewheel selected key
977
+ $key = $keys && last.wheelIndex > -1 ? $keys.eq(last.wheelIndex) : $key;
978
+ }
979
+ action = $key.attr('data-action');
980
+ if (timer - (last.eventTime || 0) < o.preventDoubleEventTime) {
981
+ return;
982
+ }
983
+ last.eventTime = timer;
984
+ last.event = e;
985
+ last.virtual = true;
986
+ if (!o.noFocus) {
987
+ base.$preview.focus();
988
+ }
989
+ last.$key = $key;
990
+ last.key = $key.attr('data-value');
991
+ // Start caret in IE when not focused (happens with each virtual keyboard button click
992
+ if (base.checkCaret) {
993
+ $keyboard.caret(base.$preview, last);
994
+ }
995
+ if (action.match('meta')) {
996
+ action = 'meta';
997
+ }
998
+ // keyaction is added as a string, override original action & text
999
+ if (action === last.key && typeof $keyboard.keyaction[action] === 'string') {
1000
+ last.key = action = $keyboard.keyaction[action];
1001
+ } else if (action in $keyboard.keyaction && $.isFunction($keyboard.keyaction[action])) {
1002
+ // stop processing if action returns false (close & cancel)
1003
+ if ($keyboard.keyaction[action](base, this, e) === false) {
1004
+ return false;
1005
+ }
1006
+ action = null; // prevent inserting action name
1007
+ }
1008
+ if (typeof action !== 'undefined' && action !== null) {
1009
+ last.key = $(this).hasClass(kbcss.keyAction) ? action : last.key;
1010
+ base.insertText(last.key);
1011
+ if (!base.capsLock && !o.stickyShift && !e.shiftKey) {
1012
+ base.shiftActive = false;
1013
+ base.showSet($key.attr('data-name'));
1014
+ }
1015
+ }
1016
+ // set caret if caret moved by action function; also, attempt to fix issue #131
1017
+ $keyboard.caret(base.$preview, last);
1018
+ base.checkCombos();
1019
+ e.type = $keyboard.events.kbChange;
1020
+ e.action = last.key;
1021
+ base.$el.trigger(e, [base, base.el]);
1022
+ last.preVal = '' + last.val;
1023
+ last.val = base.$preview.val();
1024
+
1025
+ if ($.isFunction(o.change)) {
1026
+ e.type = $keyboard.events.inputChange;
1027
+ o.change(e, base, base.el);
1028
+ // return false to prevent reopening keyboard if base.accept() was called
1029
+ return false;
1030
+ }
1031
+
1032
+ })
1033
+ // using 'kb' namespace for mouse repeat functionality to keep it separate
1034
+ // I need to trigger a 'repeater.keyboard' to make it work
1035
+ .bind('mouseup' + base.namespace + ' ' + 'mouseleave touchend touchmove touchcancel '.split(' ')
1036
+ .join(base.namespace + 'kb '), function (e) {
1037
+ base.last.virtual = true;
1038
+ var offset,
1039
+ $this = $(this);
1040
+ if (e.type === 'touchmove') {
1041
+ // if moving within the same key, don't stop repeating
1042
+ offset = $this.offset();
1043
+ offset.right = offset.left + $this.outerWidth();
1044
+ offset.bottom = offset.top + $this.outerHeight();
1045
+ if (e.originalEvent.touches[0].pageX >= offset.left &&
1046
+ e.originalEvent.touches[0].pageX < offset.right &&
1047
+ e.originalEvent.touches[0].pageY >= offset.top &&
1048
+ e.originalEvent.touches[0].pageY < offset.bottom) {
1049
+ return true;
1050
+ }
1051
+ } else if (/(mouseleave|touchend|touchcancel)/i.test(e.type)) {
1052
+ $this.removeClass(o.css.buttonHover); // needed for touch devices
1053
+ } else {
1054
+ if (!o.noFocus && base.isVisible() && base.isCurrent()) {
1055
+ base.$preview.focus();
1056
+ }
1057
+ if (base.checkCaret) {
1058
+ $keyboard.caret(base.$preview, base.last);
1059
+ }
1060
+ }
1061
+ base.mouseRepeat = [false, ''];
1062
+ clearTimeout(base.repeater); // make sure key repeat stops!
1063
+ return false;
1064
+ })
1065
+ // prevent form submits when keyboard is bound locally - issue #64
1066
+ .bind('click' + base.namespace, function () {
1067
+ return false;
1068
+ })
1069
+ // no mouse repeat for action keys (shift, ctrl, alt, meta, etc)
1070
+ .not('.' + kbcss.keyAction)
1071
+ // Allow mousewheel to scroll through other keysets of the same (non-action) key
1072
+ .bind('mousewheel' + base.namespace, function (e, delta) {
1073
+ if (o.useWheel && base.wheel) {
1074
+ // deltaY used by newer versions of mousewheel plugin
1075
+ delta = delta || e.deltaY;
1076
+ var n,
1077
+ txt = base.last.wheelLayers || [];
1078
+ if (txt.length > 1) {
1079
+ n = base.last.wheelIndex + (delta > 0 ? -1 : 1);
1080
+ if (n > txt.length - 1) {
1081
+ n = 0;
1082
+ }
1083
+ if (n < 0) {
1084
+ n = txt.length - 1;
1085
+ }
1086
+ } else {
1087
+ n = 0;
1088
+ }
1089
+ base.last.wheelIndex = n;
1090
+ $(this).html(txt[n]);
1091
+ return false;
1092
+ }
1093
+ })
1094
+ // mouse repeated action key exceptions
1095
+ .add('.' + kbcss.keyPrefix + ('tab bksp space enter'.split(' ')
1096
+ .join(',.' + kbcss.keyPrefix)), base.$keyboard)
1097
+ .bind('mousedown touchstart '.split(' ').join(base.namespace + 'kb '), function () {
1098
+ if (o.repeatRate !== 0) {
1099
+ var key = $(this);
1100
+ // save the key, make sure we are repeating the right one (fast typers)
1101
+ base.mouseRepeat = [true, key];
1102
+ setTimeout(function () {
1103
+ // don't repeat keys if it is disabled - see #431
1104
+ if (base && base.mouseRepeat[0] && base.mouseRepeat[1] === key && !key[0].disabled) {
1105
+ base.repeatKey(key);
1106
+ }
1107
+ }, o.repeatDelay);
1108
+ }
1109
+ return false;
1110
+ });
1111
+ };
1112
+
1113
+ // Insert text at caret/selection - thanks to Derek Wickwire for fixing this up!
1114
+ base.insertText = function (txt) {
1115
+ if (typeof txt === 'undefined') {
1116
+ return;
1117
+ }
1118
+ var bksp, t,
1119
+ isBksp = txt === '\b',
1120
+ // use base.$preview.val() instead of base.preview.value (val.length includes carriage returns in IE).
1121
+ val = base.$preview.val(),
1122
+ pos = $keyboard.caret(base.$preview),
1123
+ len = val.length; // save original content length
1124
+
1125
+ // silly IE caret hacks... it should work correctly, but navigating using arrow keys in a textarea
1126
+ // is still difficult
1127
+ // in IE, pos.end can be zero after input loses focus
1128
+ if (pos.end < pos.start) {
1129
+ pos.end = pos.start;
1130
+ }
1131
+ if (pos.start > len) {
1132
+ pos.end = pos.start = len;
1133
+ }
1134
+
1135
+ if (base.preview.nodeName === 'TEXTAREA') {
1136
+ // This makes sure the caret moves to the next line after clicking on enter (manual typing works fine)
1137
+ if ($keyboard.msie && val.substr(pos.start, 1) === '\n') {
1138
+ pos.start += 1;
1139
+ pos.end += 1;
1140
+ }
1141
+ }
1142
+
1143
+ if (txt === '{d}') {
1144
+ txt = '';
1145
+ t = pos.start;
1146
+ pos.end += 1;
1147
+ }
1148
+
1149
+ bksp = isBksp && pos.start === pos.end;
1150
+ txt = isBksp ? '' : txt;
1151
+ val = val.substr(0, pos.start - (bksp ? 1 : 0)) + txt + val.substr(pos.end);
1152
+ t = pos.start + (bksp ? -1 : txt.length);
1153
+
1154
+ base.$preview.val(val);
1155
+ base.saveCaret(t, t); // save caret in case of bksp
1156
+ base.setScroll();
1157
+ };
1158
+
1159
+ // check max length
1160
+ base.checkMaxLength = function () {
1161
+ var start, caret,
1162
+ val = base.$preview.val();
1163
+ if (o.maxLength !== false && val.length > o.maxLength) {
1164
+ start = $keyboard.caret(base.$preview).start;
1165
+ caret = Math.min(start, o.maxLength);
1166
+
1167
+ // prevent inserting new characters when maxed #289
1168
+ if (!o.maxInsert) {
1169
+ val = base.last.val;
1170
+ caret = start - 1; // move caret back one
1171
+ }
1172
+
1173
+ base.$preview.val(val.substring(0, o.maxLength));
1174
+ // restore caret on change, otherwise it ends up at the end.
1175
+ base.saveCaret(caret, caret);
1176
+ }
1177
+ if (base.$decBtn.length) {
1178
+ base.checkDecimal();
1179
+ }
1180
+ };
1181
+
1182
+ // mousedown repeater
1183
+ base.repeatKey = function (key) {
1184
+ key.trigger($keyboard.events.kbRepeater);
1185
+ if (base.mouseRepeat[0]) {
1186
+ base.repeater = setTimeout(function () {
1187
+ if (base){
1188
+ base.repeatKey(key);
1189
+ }
1190
+ }, base.repeatTime);
1191
+ }
1192
+ };
1193
+
1194
+ // make it easier to switch keysets via API
1195
+ // showKeySet('shift+alt+meta1')
1196
+ base.showKeySet = function (str) {
1197
+ if (typeof str === 'string') {
1198
+ base.last.keyset = [base.shiftActive, base.altActive, base.metaActive];
1199
+ base.shiftActive = /shift/i.test(str);
1200
+ base.altActive = /alt/i.test(str);
1201
+ if (/meta/.test(str)) {
1202
+ base.metaActive = true;
1203
+ base.showSet(str.match(/meta\d+/i)[0]);
1204
+ } else {
1205
+ base.metaActive = false;
1206
+ base.showSet();
1207
+ }
1208
+ } else {
1209
+ base.showSet(str);
1210
+ }
1211
+ };
1212
+
1213
+ base.showSet = function (name) {
1214
+ o = base.options; // refresh options
1215
+ var kbcss = $keyboard.css,
1216
+ prefix = '.' + kbcss.keyPrefix,
1217
+ active = o.css.buttonActive,
1218
+ key = '',
1219
+ toShow = (base.shiftActive ? 1 : 0) + (base.altActive ? 2 : 0);
1220
+ if (!base.shiftActive) {
1221
+ base.capsLock = false;
1222
+ }
1223
+ // check meta key set
1224
+ if (base.metaActive) {
1225
+ // the name attribute contains the meta set # 'meta99'
1226
+ key = (/meta/i.test(name)) ? name : '';
1227
+ // save active meta keyset name
1228
+ if (key === '') {
1229
+ key = (base.metaActive === true) ? '' : base.metaActive;
1230
+ } else {
1231
+ base.metaActive = key;
1232
+ }
1233
+ // if meta keyset doesn't have a shift or alt keyset, then show just the meta key set
1234
+ if ((!o.stickyShift && base.last.keyset[2] !== base.metaActive) ||
1235
+ ((base.shiftActive || base.altActive) &&
1236
+ !base.$keyboard.find('.' + kbcss.keySet + '-' + key + base.rows[toShow]).length)) {
1237
+ base.shiftActive = base.altActive = false;
1238
+ }
1239
+ } else if (!o.stickyShift && base.last.keyset[2] !== base.metaActive && base.shiftActive) {
1240
+ // switching from meta key set back to default, reset shift & alt if using stickyShift
1241
+ base.shiftActive = base.altActive = false;
1242
+ }
1243
+ toShow = (base.shiftActive ? 1 : 0) + (base.altActive ? 2 : 0);
1244
+ key = (toShow === 0 && !base.metaActive) ? '-normal' : (key === '') ? '' : '-' + key;
1245
+ if (!base.$keyboard.find('.' + kbcss.keySet + key + base.rows[toShow]).length) {
1246
+ // keyset doesn't exist, so restore last keyset settings
1247
+ base.shiftActive = base.last.keyset[0];
1248
+ base.altActive = base.last.keyset[1];
1249
+ base.metaActive = base.last.keyset[2];
1250
+ return;
1251
+ }
1252
+ base.$keyboard
1253
+ .find(prefix + 'alt,' + prefix + 'shift,.' + kbcss.keyAction + '[class*=meta]')
1254
+ .removeClass(active)
1255
+ .end()
1256
+ .find(prefix + 'alt')
1257
+ .toggleClass(active, base.altActive)
1258
+ .end()
1259
+ .find(prefix + 'shift')
1260
+ .toggleClass(active, base.shiftActive)
1261
+ .end()
1262
+ .find(prefix + 'lock')
1263
+ .toggleClass(active, base.capsLock)
1264
+ .end()
1265
+ .find('.' + kbcss.keySet)
1266
+ .hide()
1267
+ .end()
1268
+ .find('.' + kbcss.keyAction + prefix + key)
1269
+ .addClass(active);
1270
+
1271
+ // show keyset using inline-block ( extender layout will then line up )
1272
+ base.$keyboard.find('.' + kbcss.keySet + key + base.rows[toShow])[0].style.display = 'inline-block';
1273
+
1274
+ if (base.metaActive) {
1275
+ base.$keyboard.find(prefix + base.metaActive)
1276
+ // base.metaActive contains the string "meta#" or false
1277
+ // without the !== false, jQuery UI tries to transition the classes
1278
+ .toggleClass(active, base.metaActive !== false);
1279
+ }
1280
+ base.last.keyset = [base.shiftActive, base.altActive, base.metaActive];
1281
+ base.$el.trigger($keyboard.events.kbKeysetChange, [base, base.el]);
1282
+ };
1283
+
1284
+ // check for key combos (dead keys)
1285
+ base.checkCombos = function () {
1286
+ // return val for close function
1287
+ if (!(base.isVisible() || base.$keyboard.hasClass($keyboard.css.hasFocus))) {
1288
+ return base.$preview.val();
1289
+ }
1290
+ var r, t, t2,
1291
+ // use base.$preview.val() instead of base.preview.value (val.length includes carriage returns in IE).
1292
+ val = base.$preview.val(),
1293
+ pos = $keyboard.caret(base.$preview),
1294
+ layout = $keyboard.builtLayouts[base.layout],
1295
+ len = val.length; // save original content length
1296
+ // return if val is empty; fixes #352
1297
+ if (val === '') {
1298
+ // check valid on empty string - see #429
1299
+ if (o.acceptValid) {
1300
+ base.checkValid();
1301
+ }
1302
+ return val;
1303
+ }
1304
+
1305
+ // silly IE caret hacks... it should work correctly, but navigating using arrow keys in a textarea
1306
+ // is still difficult
1307
+ // in IE, pos.end can be zero after input loses focus
1308
+ if (pos.end < pos.start) {
1309
+ pos.end = pos.start;
1310
+ }
1311
+ if (pos.start > len) {
1312
+ pos.end = pos.start = len;
1313
+ }
1314
+ // This makes sure the caret moves to the next line after clicking on enter (manual typing works fine)
1315
+ if ($keyboard.msie && val.substr(pos.start, 1) === '\n') {
1316
+ pos.start += 1;
1317
+ pos.end += 1;
1318
+ }
1319
+
1320
+ if (o.useCombos) {
1321
+ // keep 'a' and 'o' in the regex for ae and oe ligature (æ,œ)
1322
+ // thanks to KennyTM: http://stackoverflow.com/q/4275077
1323
+ // original regex /([`\'~\^\"ao])([a-z])/mig moved to $.keyboard.comboRegex
1324
+ if ($keyboard.msie) {
1325
+ // old IE may not have the caret positioned correctly, so just check the whole thing
1326
+ val = val.replace(base.regex, function (s, accent, letter) {
1327
+ return (o.combos.hasOwnProperty(accent)) ? o.combos[accent][letter] || s : s;
1328
+ });
1329
+ // prevent combo replace error, in case the keyboard closes - see issue #116
1330
+ } else if (base.$preview.length) {
1331
+ // Modern browsers - check for combos from last two characters left of the caret
1332
+ t = pos.start - (pos.start - 2 >= 0 ? 2 : 0);
1333
+ // target last two characters
1334
+ $keyboard.caret(base.$preview, t, pos.end);
1335
+ // do combo replace
1336
+ t2 = ($keyboard.caret(base.$preview).text || '').replace(base.regex, function (s, accent, letter) {
1337
+ return (o.combos.hasOwnProperty(accent)) ? o.combos[accent][letter] || s : s;
1338
+ });
1339
+ // add combo back
1340
+ base.$preview.val($keyboard.caret(base.$preview).replaceStr(t2));
1341
+ val = base.$preview.val();
1342
+ }
1343
+ }
1344
+
1345
+ // check input restrictions - in case content was pasted
1346
+ if (o.restrictInput && val !== '') {
1347
+ t = layout.acceptedKeys.length;
1348
+
1349
+ r = layout.acceptedKeysRegex;
1350
+ if (!r) {
1351
+ t2 = $.map(layout.acceptedKeys, function (v) {
1352
+ // escape any special characters
1353
+ return v.replace(base.escapeRegex, '\\$&');
1354
+ });
1355
+ r = layout.acceptedKeysRegex = new RegExp('(' + t2.join('|') + ')', 'g');
1356
+ }
1357
+
1358
+ // only save matching keys
1359
+ t2 = val.match(r);
1360
+ if (t2) {
1361
+ val = t2.join('');
1362
+ } else {
1363
+ // no valid characters
1364
+ val = '';
1365
+ len = 0;
1366
+ }
1367
+ }
1368
+
1369
+ // save changes, then reposition caret
1370
+ pos.start += val.length - len;
1371
+ pos.end += val.length - len;
1372
+ base.$preview.val(val);
1373
+ base.saveCaret(pos.start, pos.end);
1374
+ // set scroll to keep caret in view
1375
+ base.setScroll();
1376
+
1377
+ base.checkMaxLength();
1378
+
1379
+ if (o.acceptValid) {
1380
+ base.checkValid();
1381
+ }
1382
+
1383
+ return val; // return text, used for keyboard closing section
1384
+ };
1385
+
1386
+ // Toggle accept button classes, if validating
1387
+ base.checkValid = function () {
1388
+ var kbcss = $keyboard.css,
1389
+ $accept = base.$keyboard.find('.' + kbcss.keyPrefix + 'accept'),
1390
+ valid = true;
1391
+ if ($.isFunction(o.validate)) {
1392
+ valid = o.validate(base, base.$preview.val(), false);
1393
+ }
1394
+ // toggle accept button classes; defined in the css
1395
+ $accept
1396
+ .toggleClass(kbcss.inputInvalid, !valid)
1397
+ .toggleClass(kbcss.inputValid, valid)
1398
+ // update title to indicate that the entry is valid or invalid
1399
+ .attr('title', $accept.attr('data-title') + ' (' + o.display[valid ? 'valid' : 'invalid'] + ')');
1400
+ };
1401
+
1402
+ // Decimal button for num pad - only allow one (not used by default)
1403
+ base.checkDecimal = function () {
1404
+ // Check US '.' or European ',' format
1405
+ if ((base.decimal && /\./g.test(base.preview.value)) ||
1406
+ (!base.decimal && /\,/g.test(base.preview.value))) {
1407
+ base.$decBtn
1408
+ .attr({
1409
+ 'disabled': 'disabled',
1410
+ 'aria-disabled': 'true'
1411
+ })
1412
+ .removeClass(o.css.buttonHover)
1413
+ .addClass(o.css.buttonDisabled);
1414
+ } else {
1415
+ base.$decBtn
1416
+ .removeAttr('disabled')
1417
+ .attr({
1418
+ 'aria-disabled': 'false'
1419
+ })
1420
+ .addClass(o.css.buttonDefault)
1421
+ .removeClass(o.css.buttonDisabled);
1422
+ }
1423
+ };
1424
+
1425
+ // get other layer values for a specific key
1426
+ base.getLayers = function ($el) {
1427
+ var kbcss = $keyboard.css,
1428
+ key = $el.attr('data-pos'),
1429
+ $keys = $el.closest('.' + kbcss.keyboard)
1430
+ .find('button[data-pos="' + key + '"]');
1431
+ return $keys.filter(function () {
1432
+ return $(this)
1433
+ .find('.' + kbcss.keyText)
1434
+ .text() !== '';
1435
+ })
1436
+ .add($el);
1437
+ };
1438
+
1439
+ // Go to next or prev inputs
1440
+ // goToNext = true, then go to next input; if false go to prev
1441
+ // isAccepted is from autoAccept option or true if user presses shift+enter
1442
+ base.switchInput = function (goToNext, isAccepted) {
1443
+ if ($.isFunction(o.switchInput)) {
1444
+ o.switchInput(base, goToNext, isAccepted);
1445
+ } else {
1446
+ // base.$keyboard may be an empty array - see #275 (apod42)
1447
+ if (base.$keyboard.length) {
1448
+ base.$keyboard.hide();
1449
+ }
1450
+ var kb,
1451
+ stopped = false,
1452
+ all = $('button, input, textarea, a')
1453
+ .filter(':visible')
1454
+ .not(':disabled'),
1455
+ indx = all.index(base.$el) + (goToNext ? 1 : -1);
1456
+ if (base.$keyboard.length) {
1457
+ base.$keyboard.show();
1458
+ }
1459
+ if (indx > all.length - 1) {
1460
+ stopped = o.stopAtEnd;
1461
+ indx = 0; // go to first input
1462
+ }
1463
+ if (indx < 0) {
1464
+ stopped = o.stopAtEnd;
1465
+ indx = all.length - 1; // stop or go to last
1466
+ }
1467
+ if (!stopped) {
1468
+ isAccepted = base.close(isAccepted);
1469
+ if (!isAccepted) {
1470
+ return;
1471
+ }
1472
+ kb = all.eq(indx).data('keyboard');
1473
+ if (kb && kb.options.openOn.length) {
1474
+ kb.focusOn();
1475
+ } else {
1476
+ all.eq(indx).focus();
1477
+ }
1478
+ }
1479
+ }
1480
+ return false;
1481
+ };
1482
+
1483
+ // Close the keyboard, if visible. Pass a status of true, if the content was accepted
1484
+ // (for the event trigger).
1485
+ base.close = function (accepted) {
1486
+ if (base.isOpen && base.$keyboard.length) {
1487
+ clearTimeout(base.throttled);
1488
+ var kbcss = $keyboard.css,
1489
+ kbevents = $keyboard.events,
1490
+ val = (accepted) ? base.checkCombos() : base.originalContent;
1491
+ // validate input if accepted
1492
+ if (accepted && $.isFunction(o.validate) && !o.validate(base, val, true)) {
1493
+ val = base.originalContent;
1494
+ accepted = false;
1495
+ if (o.cancelClose) {
1496
+ return;
1497
+ }
1498
+ }
1499
+ base.isCurrent(false);
1500
+ base.isOpen = o.alwaysOpen || o.userClosed;
1501
+ // update value for always open keyboards
1502
+ base.$preview.val(val);
1503
+ base.$el
1504
+ .removeClass(kbcss.isCurrent + ' ' + kbcss.inputAutoAccepted)
1505
+ // add 'ui-keyboard-autoaccepted' to inputs - see issue #66
1506
+ .addClass((accepted || false) ? accepted === true ? '' : kbcss.inputAutoAccepted : '')
1507
+ .val(val)
1508
+ // trigger default change event - see issue #146
1509
+ .trigger(kbevents.inputChange)
1510
+ // don't trigger beforeClose if keyboard is always open
1511
+ .trigger((o.alwaysOpen) ? '' : kbevents.kbBeforeClose, [base, base.el, (accepted || false)])
1512
+
1513
+ .trigger(((accepted || false) ? kbevents.inputAccepted : kbevents.inputCanceled), [base, base.el])
1514
+ .trigger((o.alwaysOpen) ? kbevents.kbInactive : kbevents.kbHidden, [base, base.el])
1515
+ .blur();
1516
+
1517
+ // save caret after updating value (fixes userClosed issue with changing focus)
1518
+ $keyboard.caret(base.$preview, base.last);
1519
+ // base is undefined if keyboard was destroyed - fixes #358
1520
+ if (base) {
1521
+ // add close event time
1522
+ base.last.eventTime = new Date().getTime();
1523
+ if (!(o.alwaysOpen || o.userClosed && accepted === 'true') && base.$keyboard.length) {
1524
+ // free up memory
1525
+ base.removeKeyboard();
1526
+ // rebind input focus - delayed to fix IE issue #72
1527
+ base.timer = setTimeout(function () {
1528
+ if(base){
1529
+ base.bindFocus();
1530
+ }
1531
+ }, 500);
1532
+ }
1533
+ if (!base.watermark && base.el.value === '' && base.inPlaceholder !== '') {
1534
+ base.$el
1535
+ .addClass(kbcss.placeholder)
1536
+ .val(base.inPlaceholder);
1537
+ }
1538
+ }
1539
+ }
1540
+ return !!accepted;
1541
+ };
1542
+
1543
+ base.accept = function () {
1544
+ return base.close(true);
1545
+ };
1546
+
1547
+ base.checkClose = function (e) {
1548
+ if (base.opening) {
1549
+ return;
1550
+ }
1551
+ base.escClose(e);
1552
+ var kbcss = $.keyboard.css,
1553
+ $target = $(e.target);
1554
+ // needed for IE to allow switching between keyboards smoothly
1555
+ if ($target.hasClass(kbcss.input)) {
1556
+ var kb = $target.data('keyboard');
1557
+ // only trigger on self
1558
+ if (kb === base && !kb.$el.hasClass(kbcss.isCurrent) && e.type === kb.options.openOn) {
1559
+ kb.focusOn();
1560
+ }
1561
+ }
1562
+ };
1563
+
1564
+ base.escClose = function (e) {
1565
+ if (e && e.type === 'keyup') {
1566
+ return (e.which === $keyboard.keyCodes.escape && !o.ignoreEsc) ?
1567
+ base.close(o.autoAccept && o.autoAcceptOnEsc ? 'true' : false) :
1568
+ '';
1569
+ }
1570
+ // keep keyboard open if alwaysOpen or stayOpen is true - fixes mutliple always open keyboards or
1571
+ // single stay open keyboard
1572
+ if (!base.isOpen) {
1573
+ return;
1574
+ }
1575
+ // ignore autoaccept if using escape - good idea?
1576
+ if (!base.isCurrent() && base.isOpen || base.isOpen && e.target !== base.el) {
1577
+ // don't close if stayOpen is set; but close if a different keyboard is being opened
1578
+ if ((o.stayOpen || o.userClosed) && !$(e.target).hasClass($keyboard.css.input)) {
1579
+ return;
1580
+ }
1581
+ // stop propogation in IE - an input getting focus doesn't open a keyboard if one is already open
1582
+ if ($keyboard.allie) {
1583
+ e.preventDefault();
1584
+ }
1585
+ // send 'true' instead of a true (boolean), the input won't get a 'ui-keyboard-autoaccepted'
1586
+ // class name - see issue #66
1587
+ base.close(o.autoAccept ? 'true' : false);
1588
+ }
1589
+ };
1590
+
1591
+ // Build default button
1592
+ base.keyBtn = $('<button />')
1593
+ .attr({
1594
+ 'role': 'button',
1595
+ 'type': 'button',
1596
+ 'aria-disabled': 'false',
1597
+ 'tabindex': '-1'
1598
+ })
1599
+ .addClass($keyboard.css.keyButton);
1600
+
1601
+ // convert key names into a class name
1602
+ base.processName = function (name) {
1603
+ var index, n,
1604
+ process = (name || '').replace(/[^a-z0-9-_]/gi, ''),
1605
+ len = process.length,
1606
+ newName = [];
1607
+ if (len > 1 && name === process) {
1608
+ // return name if basic text
1609
+ return name;
1610
+ }
1611
+ // return character code sequence
1612
+ len = name.length;
1613
+ if (len) {
1614
+ for (index = 0; index < len; index++) {
1615
+ n = name[index];
1616
+ // keep '-' and '_'... so for dash, we get two dashes in a row
1617
+ newName.push(/[a-z0-9-_]/i.test(n) ?
1618
+ (/[-_]/.test(n) && index !== 0 ? '' : n) :
1619
+ (index === 0 ? '' : '-') + n.charCodeAt(0)
1620
+ );
1621
+ }
1622
+ return newName.join('');
1623
+ } else {
1624
+ return name;
1625
+ }
1626
+ };
1627
+
1628
+ base.processKeys = function (name) {
1629
+ var tmp,
1630
+ parts = name.split(':'),
1631
+ data = {
1632
+ name: null,
1633
+ map: '',
1634
+ title: ''
1635
+ };
1636
+ /* map defined keys
1637
+ format 'key(A):Label_for_key_(ignore_parentheses_here)'
1638
+ 'key' = key that is seen (can any character(s); but it might need to be escaped using '\'
1639
+ or entered as unicode '\u####'
1640
+ '(A)' = the actual key on the real keyboard to remap
1641
+ ':Label_for_key' ends up in the title/tooltip
1642
+ Examples:
1643
+ '\u0391(A):alpha', 'x(y):this_(might)_cause_problems
1644
+ or edge cases of ':(x)', 'x(:)', 'x(()' or 'x())'
1645
+ Enhancement (if I can get alt keys to work):
1646
+ A mapped key will include the mod key, e.g. 'x(alt-x)' or 'x(alt-shift-x)'
1647
+ */
1648
+ if (/\(.+\)/.test(parts[0]) || /^:\(.+\)/.test(name) || /\([(:)]\)/.test(name)) {
1649
+ // edge cases 'x(:)', 'x(()' or 'x())'
1650
+ if (/\([(:)]\)/.test(name)) {
1651
+ tmp = parts[0].match(/([^(]+)\((.+)\)/);
1652
+ if (tmp && tmp.length) {
1653
+ data.name = tmp[1];
1654
+ data.map = tmp[2];
1655
+ data.title = parts.length > 1 ? parts.slice(1).join(':') : '';
1656
+ } else {
1657
+ // edge cases 'x(:)', ':(x)' or ':(:)'
1658
+ data.name = name.match(/([^(]+)/)[0];
1659
+ if (data.name === ':') {
1660
+ // ':(:):test' => parts = [ '', '(', ')', 'title' ] need to slice 1
1661
+ parts = parts.slice(1);
1662
+ }
1663
+ if (tmp === null) {
1664
+ // 'x(:):test' => parts = [ 'x(', ')', 'title' ] need to slice 2
1665
+ data.map = ':';
1666
+ parts = parts.slice(2);
1667
+ }
1668
+ data.title = parts.length ? parts.join(':') : '';
1669
+ }
1670
+ } else {
1671
+ // example: \u0391(A):alpha; extract 'A' from '(A)'
1672
+ data.map = name.match(/\(([^()]+?)\)/)[1];
1673
+ // remove '(A)', left with '\u0391:alpha'
1674
+ name = name.replace(/\(([^()]+)\)/, '');
1675
+ tmp = name.split(':');
1676
+ // get '\u0391' from '\u0391:alpha'
1677
+ if (tmp[0] === '') {
1678
+ data.name = ':';
1679
+ parts = parts.slice(1);
1680
+ } else {
1681
+ data.name = tmp[0];
1682
+ }
1683
+ data.title = parts.length > 1 ? parts.slice(1).join(':') : '';
1684
+ }
1685
+ } else {
1686
+ // find key label
1687
+ // corner case of '::;' reduced to ':;', split as ['', ';']
1688
+ if (parts[0] === '') {
1689
+ data.name = ':';
1690
+ parts = parts.slice(1);
1691
+ } else {
1692
+ data.name = parts[0];
1693
+ }
1694
+ data.title = parts.length > 1 ? parts.slice(1).join(':') : '';
1695
+ }
1696
+ data.title = $.trim(data.title).replace(/_/g, ' ');
1697
+ return data;
1698
+ };
1699
+
1700
+ // Add key function
1701
+ // keyName = the name of the function called in $.keyboard.keyaction when the button is clicked
1702
+ // name = name added to key, or cross-referenced in the display options
1703
+ // base.temp[0] = keyset to attach the new button
1704
+ // regKey = true when it is not an action key
1705
+ base.addKey = function (keyName, action, regKey) {
1706
+ var keyClass, tmp, keys,
1707
+ data = {},
1708
+ txt = base.processKeys(regKey ? keyName : action),
1709
+ kbcss = $keyboard.css;
1710
+
1711
+ if (!regKey && o.display[txt.name]) {
1712
+ keys = base.processKeys(o.display[txt.name]);
1713
+ // action contained in "keyName" (e.g. keyName = "accept",
1714
+ // action = "a" (use checkmark instead of text))
1715
+ keys.action = base.processKeys(keyName).name;
1716
+ } else {
1717
+ // when regKey is true, keyName is the same as action
1718
+ keys = txt;
1719
+ keys.action = txt.name;
1720
+ }
1721
+
1722
+ data.name = base.processName(txt.name);
1723
+
1724
+ if (keys.map !== '') {
1725
+ $keyboard.builtLayouts[base.layout].mappedKeys[keys.map] = keys.name;
1726
+ $keyboard.builtLayouts[base.layout].acceptedKeys.push(keys.name);
1727
+ } else if (regKey) {
1728
+ $keyboard.builtLayouts[base.layout].acceptedKeys.push(keys.name);
1729
+ }
1730
+
1731
+ if (regKey) {
1732
+ keyClass = data.name === '' ? '' : kbcss.keyPrefix + data.name;
1733
+ } else {
1734
+ // Action keys will have the 'ui-keyboard-actionkey' class
1735
+ keyClass = kbcss.keyAction + ' ' + kbcss.keyPrefix + keys.action;
1736
+ }
1737
+ // '\u2190'.length = 1 because the unicode is converted, so if more than one character,
1738
+ // add the wide class
1739
+ keyClass += (keys.name.length > 2 ? ' ' + kbcss.keyWide : '') + ' ' + o.css.buttonDefault;
1740
+
1741
+ data.html = '<span class="' + kbcss.keyText + '">' +
1742
+ // this prevents HTML from being added to the key
1743
+ keys.name.replace(/[\u00A0-\u9999]/gim, function (i) {
1744
+ return '&#' + i.charCodeAt(0) + ';';
1745
+ }) +
1746
+ '</span>';
1747
+
1748
+ data.$key = base.keyBtn
1749
+ .clone()
1750
+ .attr({
1751
+ 'data-value': regKey ? keys.name : keys.action, // value
1752
+ 'data-name': keys.action,
1753
+ 'data-pos': base.temp[1] + ',' + base.temp[2],
1754
+ 'data-action': keys.action,
1755
+ 'data-html': data.html
1756
+ })
1757
+ // add 'ui-keyboard-' + data.name for all keys
1758
+ // (e.g. 'Bksp' will have 'ui-keyboard-bskp' class)
1759
+ // any non-alphanumeric characters will be replaced with
1760
+ // their decimal unicode value
1761
+ // (e.g. '~' is a regular key, class = 'ui-keyboard-126'
1762
+ // (126 is the unicode decimal value - same as &#126;)
1763
+ // See https://en.wikipedia.org/wiki/List_of_Unicode_characters#Control_codes
1764
+ .addClass(keyClass)
1765
+ .html(data.html)
1766
+ .appendTo(base.temp[0]);
1767
+
1768
+ if (keys.map) {
1769
+ data.$key.attr('data-mapped', keys.map);
1770
+ }
1771
+ if (keys.title || txt.title) {
1772
+ data.$key.attr({
1773
+ 'data-title': txt.title || keys.title, // used to allow adding content to title
1774
+ 'title': txt.title || keys.title
1775
+ });
1776
+ }
1777
+
1778
+ if (typeof o.buildKey === 'function') {
1779
+ data = o.buildKey(base, data);
1780
+ // copy html back to attributes
1781
+ tmp = data.$key.html();
1782
+ data.$key.attr('data-html', tmp);
1783
+ }
1784
+ return data.$key;
1785
+ };
1786
+
1787
+ base.customHash = function (layout) {
1788
+ /*jshint bitwise:false */
1789
+ var i, array, hash, character, len,
1790
+ arrays = [],
1791
+ merged = [];
1792
+ // pass layout to allow for testing
1793
+ layout = typeof layout === 'undefined' ? o.customLayout : layout;
1794
+ // get all layout arrays
1795
+ for (array in layout) {
1796
+ if (layout.hasOwnProperty(array)) {
1797
+ arrays.push(layout[array]);
1798
+ }
1799
+ }
1800
+ // flatten array
1801
+ merged = merged.concat.apply(merged, arrays).join(' ');
1802
+ // produce hash name - http://stackoverflow.com/a/7616484/145346
1803
+ hash = 0;
1804
+ len = merged.length;
1805
+ if (len === 0) {
1806
+ return hash;
1807
+ }
1808
+ for (i = 0; i < len; i++) {
1809
+ character = merged.charCodeAt(i);
1810
+ hash = ((hash << 5) - hash) + character;
1811
+ hash = hash & hash; // Convert to 32bit integer
1812
+ }
1813
+ return hash;
1814
+ };
1815
+
1816
+ base.buildKeyboard = function (name, internal) {
1817
+ // o.display is empty when this is called from the scramble extension (when alwaysOpen:true)
1818
+ if ($.isEmptyObject(o.display)) {
1819
+ // set keyboard language
1820
+ base.updateLanguage();
1821
+ }
1822
+ var row, $row, currentSet,
1823
+ kbcss = $keyboard.css,
1824
+ sets = 0,
1825
+ layout = $keyboard.builtLayouts[name || base.layout || o.layout] = {
1826
+ mappedKeys: {},
1827
+ acceptedKeys: []
1828
+ },
1829
+ acceptedKeys = layout.acceptedKeys = o.restrictInclude ?
1830
+ ('' + o.restrictInclude).split(/\s+/) || [] :
1831
+ [],
1832
+ // using $layout temporarily to hold keyboard popup classnames
1833
+ $layout = kbcss.keyboard + ' ' + o.css.popup + ' ' + o.css.container +
1834
+ (o.alwaysOpen || o.userClosed ? ' ' + kbcss.alwaysOpen : ''),
1835
+
1836
+ container = $('<div />')
1837
+ .addClass($layout)
1838
+ .attr({
1839
+ 'role': 'textbox'
1840
+ })
1841
+ .hide();
1842
+ // verify layout or setup custom keyboard
1843
+ if ((internal && o.layout === 'custom') || !$keyboard.layouts.hasOwnProperty(o.layout)) {
1844
+ o.layout = 'custom';
1845
+ $layout = $keyboard.layouts.custom = o.customLayout || {
1846
+ 'normal': ['{cancel}']
1847
+ };
1848
+ } else {
1849
+ $layout = $keyboard.layouts[internal ? o.layout : name || base.layout || o.layout];
1850
+ }
1851
+
1852
+ // Main keyboard building loop
1853
+ $.each($layout, function (set, keySet) {
1854
+ // skip layout name & lang settings
1855
+ if (set !== '' && !/^(name|lang|rtl)$/i.test(set)) {
1856
+ // keep backwards compatibility for change from default to normal naming
1857
+ if (set === 'default') {
1858
+ set = 'normal';
1859
+ }
1860
+ sets++;
1861
+ $row = $('<div />')
1862
+ .attr('name', set) // added for typing extension
1863
+ .addClass(kbcss.keySet + ' ' + kbcss.keySet + '-' + set)
1864
+ .appendTo(container)
1865
+ .toggle(set === 'normal');
1866
+
1867
+ for (row = 0; row < keySet.length; row++) {
1868
+ // remove extra spaces before spliting (regex probably could be improved)
1869
+ currentSet = $.trim(keySet[row]).replace(/\{(\.?)[\s+]?:[\s+]?(\.?)\}/g, '{$1:$2}');
1870
+ base.buildRow($row, row, currentSet.split(/\s+/), acceptedKeys);
1871
+ $row.find('.' + kbcss.keyButton + ',.' + kbcss.keySpacer)
1872
+ .filter(':last')
1873
+ .after('<br class="' + kbcss.endRow + '"/>');
1874
+ }
1875
+ }
1876
+ });
1877
+
1878
+ if (sets > 1) {
1879
+ base.sets = true;
1880
+ }
1881
+ layout.hasMappedKeys = !($.isEmptyObject(layout.mappedKeys));
1882
+ layout.$keyboard = container;
1883
+ return container;
1884
+ };
1885
+
1886
+ base.buildRow = function ($row, row, keys, acceptedKeys) {
1887
+ var t, txt, key, isAction, action, margin,
1888
+ kbcss = $keyboard.css;
1889
+ for (key = 0; key < keys.length; key++) {
1890
+ // used by addKey function
1891
+ base.temp = [$row, row, key];
1892
+ isAction = false;
1893
+
1894
+ // ignore empty keys
1895
+ if (keys[key].length === 0) {
1896
+ continue;
1897
+ }
1898
+
1899
+ // process here if it's an action key
1900
+ if (/^\{\S+\}$/.test(keys[key])) {
1901
+ action = keys[key].match(/^\{(\S+)\}$/)[1];
1902
+ // add active class if there are double exclamation points in the name
1903
+ if (/\!\!/.test(action)) {
1904
+ action = action.replace('!!', '');
1905
+ isAction = true;
1906
+ }
1907
+
1908
+ // add empty space
1909
+ if (/^sp:((\d+)?([\.|,]\d+)?)(em|px)?$/i.test(action)) {
1910
+ // not perfect globalization, but allows you to use {sp:1,1em}, {sp:1.2em} or {sp:15px}
1911
+ margin = parseFloat(action
1912
+ .replace(/,/, '.')
1913
+ .match(/^sp:((\d+)?([\.|,]\d+)?)(em|px)?$/i)[1] || 0
1914
+ );
1915
+ $('<span class="' + kbcss.keyText + '"></span>')
1916
+ // previously {sp:1} would add 1em margin to each side of a 0 width span
1917
+ // now Firefox doesn't seem to render 0px dimensions, so now we set the
1918
+ // 1em margin x 2 for the width
1919
+ .width((action.match(/px/i) ? margin + 'px' : (margin * 2) + 'em'))
1920
+ .addClass(kbcss.keySpacer)
1921
+ .appendTo($row);
1922
+ }
1923
+
1924
+ // add empty button
1925
+ if (/^empty(:((\d+)?([\.|,]\d+)?)(em|px)?)?$/i.test(action)) {
1926
+ margin = (/:/.test(action)) ? parseFloat(action
1927
+ .replace(/,/, '.')
1928
+ .match(/^empty:((\d+)?([\.|,]\d+)?)(em|px)?$/i)[1] || 0
1929
+ ) : '';
1930
+ base
1931
+ .addKey('', ' ')
1932
+ .addClass(o.css.buttonDisabled + ' ' + o.css.buttonEmpty)
1933
+ .attr('aria-disabled', true)
1934
+ .width(margin ? (action.match('px') ? margin + 'px' : (margin * 2) + 'em') : '');
1935
+ }
1936
+
1937
+ // meta keys
1938
+ if (/^meta\d+\:?(\w+)?/i.test(action)) {
1939
+ base
1940
+ .addKey(action.split(':')[0], action)
1941
+ .addClass(kbcss.keyHasActive);
1942
+ continue;
1943
+ }
1944
+
1945
+ // switch needed for action keys with multiple names/shortcuts or
1946
+ // default will catch all others
1947
+ txt = action.split(':');
1948
+ switch (txt[0].toLowerCase()) {
1949
+
1950
+ case 'a':
1951
+ case 'accept':
1952
+ base
1953
+ .addKey('accept', action)
1954
+ .addClass(o.css.buttonAction + ' ' + kbcss.keyAction);
1955
+ break;
1956
+
1957
+ case 'alt':
1958
+ case 'altgr':
1959
+ base
1960
+ .addKey('alt', action)
1961
+ .addClass(kbcss.keyHasActive);
1962
+ break;
1963
+
1964
+ case 'b':
1965
+ case 'bksp':
1966
+ base.addKey('bksp', action);
1967
+ break;
1968
+
1969
+ case 'c':
1970
+ case 'cancel':
1971
+ base
1972
+ .addKey('cancel', action)
1973
+ .addClass(o.css.buttonAction + ' ' + kbcss.keyAction);
1974
+ break;
1975
+
1976
+ // toggle combo/diacritic key
1977
+ /*jshint -W083 */
1978
+ case 'combo':
1979
+ base
1980
+ .addKey('combo', action)
1981
+ .addClass(kbcss.keyHasActive)
1982
+ .attr('title', function (indx, title) {
1983
+ // add combo key state to title
1984
+ return title + ' ' + o.display[o.useCombos ? 'active' : 'disabled'];
1985
+ })
1986
+ .toggleClass(o.css.buttonActive, o.useCombos);
1987
+ break;
1988
+
1989
+ // Decimal - unique decimal point (num pad layout)
1990
+ case 'dec':
1991
+ acceptedKeys.push((base.decimal) ? '.' : ',');
1992
+ base.addKey('dec', action);
1993
+ break;
1994
+
1995
+ case 'e':
1996
+ case 'enter':
1997
+ base
1998
+ .addKey('enter', action)
1999
+ .addClass(o.css.buttonAction + ' ' + kbcss.keyAction);
2000
+ break;
2001
+
2002
+ case 'lock':
2003
+ base
2004
+ .addKey('lock', action)
2005
+ .addClass(kbcss.keyHasActive);
2006
+ break;
2007
+
2008
+ case 's':
2009
+ case 'shift':
2010
+ base
2011
+ .addKey('shift', action)
2012
+ .addClass(kbcss.keyHasActive);
2013
+ break;
2014
+
2015
+ // Change sign (for num pad layout)
2016
+ case 'sign':
2017
+ acceptedKeys.push('-');
2018
+ base.addKey('sign', action);
2019
+ break;
2020
+
2021
+ case 'space':
2022
+ acceptedKeys.push(' ');
2023
+ base.addKey('space', action);
2024
+ break;
2025
+
2026
+ case 't':
2027
+ case 'tab':
2028
+ base.addKey('tab', action);
2029
+ break;
2030
+
2031
+ default:
2032
+ if ($keyboard.keyaction.hasOwnProperty(txt[0])) {
2033
+ base
2034
+ .addKey(txt[0], action)
2035
+ .toggleClass(o.css.buttonAction + ' ' + kbcss.keyAction, isAction);
2036
+ }
2037
+
2038
+ }
2039
+
2040
+ } else {
2041
+
2042
+ // regular button (not an action key)
2043
+ t = keys[key];
2044
+ base.addKey(t, t, true);
2045
+ }
2046
+ }
2047
+ };
2048
+
2049
+ base.removeBindings = function (namespace) {
2050
+ $(document).unbind(namespace);
2051
+ if (base.el.ownerDocument !== document) {
2052
+ $(base.el.ownerDocument).unbind(namespace);
2053
+ }
2054
+ $(window).unbind(namespace);
2055
+ base.$el.unbind(namespace);
2056
+ };
2057
+
2058
+ base.removeKeyboard = function () {
2059
+ base.$allKeys = null;
2060
+ base.$decBtn = null;
2061
+ // base.$preview === base.$el when o.usePreview is false - fixes #442
2062
+ if (o.usePreview) {
2063
+ base.$preview.removeData('keyboard');
2064
+ }
2065
+ base.preview = null;
2066
+ base.$preview = null;
2067
+ base.$previewCopy = null;
2068
+ base.$keyboard.removeData('keyboard');
2069
+ base.$keyboard.remove();
2070
+ base.$keyboard = [];
2071
+ base.isOpen = false;
2072
+ base.isCurrent(false);
2073
+ };
2074
+
2075
+ base.destroy = function (callback) {
2076
+ var index,
2077
+ kbcss = $keyboard.css,
2078
+ len = base.extensionNamespace.length,
2079
+ tmp = [
2080
+ kbcss.input,
2081
+ kbcss.locked,
2082
+ kbcss.placeholder,
2083
+ kbcss.noKeyboard,
2084
+ kbcss.alwaysOpen,
2085
+ o.css.input,
2086
+ kbcss.isCurrent
2087
+ ].join(' ');
2088
+ clearTimeout(base.timer);
2089
+ clearTimeout(base.timer2);
2090
+ if (base.$keyboard.length) {
2091
+ base.removeKeyboard();
2092
+ }
2093
+ base.removeBindings(base.namespace);
2094
+ base.removeBindings(base.namespace + 'callbacks');
2095
+ for (index = 0; index < len; index++) {
2096
+ base.removeBindings(base.extensionNamespace[index]);
2097
+ }
2098
+ base.el.active = false;
2099
+
2100
+ base.$el
2101
+ .removeClass(tmp)
2102
+ .removeAttr('aria-haspopup')
2103
+ .removeAttr('role')
2104
+ .removeData('keyboard');
2105
+ base = null;
2106
+
2107
+ if (typeof callback === 'function') {
2108
+ callback();
2109
+ }
2110
+ };
2111
+
2112
+ // Run initializer
2113
+ base.init();
2114
+
2115
+ }; // end $.keyboard definition
2116
+
2117
+ // event.which & ASCII values
2118
+ $keyboard.keyCodes = {
2119
+ backSpace: 8,
2120
+ tab: 9,
2121
+ enter: 13,
2122
+ capsLock: 20,
2123
+ escape: 27,
2124
+ space: 32,
2125
+ pageUp: 33,
2126
+ pageDown: 34,
2127
+ end: 35,
2128
+ home: 36,
2129
+ left: 37,
2130
+ up: 38,
2131
+ right: 39,
2132
+ down: 40,
2133
+ insert: 45,
2134
+ delete: 46,
2135
+ // event.which keyCodes (uppercase letters)
2136
+ A: 65,
2137
+ Z: 90,
2138
+ V: 86,
2139
+ C: 67,
2140
+ X: 88,
2141
+
2142
+ // ASCII lowercase a & z
2143
+ a: 97,
2144
+ z: 122
2145
+ };
2146
+
2147
+ $keyboard.css = {
2148
+ // keyboard id suffix
2149
+ idSuffix: '_keyboard',
2150
+ // element class names
2151
+ input: 'ui-keyboard-input',
2152
+ inputClone: 'ui-keyboard-preview-clone',
2153
+ wrapper: 'ui-keyboard-preview-wrapper',
2154
+ preview: 'ui-keyboard-preview',
2155
+ keyboard: 'ui-keyboard',
2156
+ keySet: 'ui-keyboard-keyset',
2157
+ keyButton: 'ui-keyboard-button',
2158
+ keyWide: 'ui-keyboard-widekey',
2159
+ keyPrefix: 'ui-keyboard-',
2160
+ keyText: 'ui-keyboard-text', // span with button text
2161
+ keyHasActive: 'ui-keyboard-hasactivestate',
2162
+ keyAction: 'ui-keyboard-actionkey',
2163
+ keySpacer: 'ui-keyboard-spacer', // empty keys
2164
+ keyToggle: 'ui-keyboard-toggle',
2165
+ keyDisabled: 'ui-keyboard-disabled',
2166
+ // states
2167
+ locked: 'ui-keyboard-lockedinput',
2168
+ alwaysOpen: 'ui-keyboard-always-open',
2169
+ noKeyboard: 'ui-keyboard-nokeyboard',
2170
+ placeholder: 'ui-keyboard-placeholder',
2171
+ hasFocus: 'ui-keyboard-has-focus',
2172
+ isCurrent: 'ui-keyboard-input-current',
2173
+ // validation & autoaccept
2174
+ inputValid: 'ui-keyboard-valid-input',
2175
+ inputInvalid: 'ui-keyboard-invalid-input',
2176
+ inputAutoAccepted: 'ui-keyboard-autoaccepted',
2177
+ endRow: 'ui-keyboard-button-endrow' // class added to <br>
2178
+ };
2179
+
2180
+ $keyboard.events = {
2181
+ // keyboard events
2182
+ kbChange: 'keyboardChange',
2183
+ kbBeforeClose: 'beforeClose',
2184
+ kbBeforeVisible: 'beforeVisible',
2185
+ kbVisible: 'visible',
2186
+ kbInit: 'initialized',
2187
+ kbInactive: 'inactive',
2188
+ kbHidden: 'hidden',
2189
+ kbRepeater: 'repeater',
2190
+ kbKeysetChange: 'keysetChange',
2191
+ // input events
2192
+ inputAccepted: 'accepted',
2193
+ inputCanceled: 'canceled',
2194
+ inputChange: 'change',
2195
+ inputRestricted: 'restricted'
2196
+ };
2197
+
2198
+ // Action key function list
2199
+ $keyboard.keyaction = {
2200
+ accept: function (base) {
2201
+ base.close(true); // same as base.accept();
2202
+ return false; // return false prevents further processing
2203
+ },
2204
+ alt: function (base) {
2205
+ base.altActive = !base.altActive;
2206
+ base.showSet();
2207
+ },
2208
+ bksp: function (base) {
2209
+ // the script looks for the '\b' string and initiates a backspace
2210
+ base.insertText('\b');
2211
+ },
2212
+ cancel: function (base) {
2213
+ base.close();
2214
+ return false; // return false prevents further processing
2215
+ },
2216
+ clear: function (base) {
2217
+ base.$preview.val('');
2218
+ if (base.$decBtn.length) {
2219
+ base.checkDecimal();
2220
+ }
2221
+ },
2222
+ combo: function (base) {
2223
+ var o = base.options,
2224
+ c = !o.useCombos,
2225
+ $combo = base.$keyboard.find('.' + $keyboard.css.keyPrefix + 'combo');
2226
+ o.useCombos = c;
2227
+ $combo
2228
+ .toggleClass(o.css.buttonActive, c)
2229
+ // update combo key state
2230
+ .attr('title', $combo.attr('data-title') + ' (' + o.display[c ? 'active' : 'disabled'] + ')');
2231
+ if (c) {
2232
+ base.checkCombos();
2233
+ }
2234
+ return false;
2235
+ },
2236
+ dec: function (base) {
2237
+ base.insertText((base.decimal) ? '.' : ',');
2238
+ },
2239
+ del: function (base) {
2240
+ // the script looks for the '{d}' string and initiates a delete
2241
+ base.insertText('{d}');
2242
+ },
2243
+ // resets to base keyset (deprecated because "default" is a reserved word)
2244
+ 'default': function (base) {
2245
+ base.shiftActive = base.altActive = base.metaActive = false;
2246
+ base.showSet();
2247
+ },
2248
+ // el is the pressed key (button) object; it is null when the real keyboard enter is pressed
2249
+ enter: function (base, el, e) {
2250
+ var tag = base.el.nodeName,
2251
+ o = base.options;
2252
+ // shift+enter in textareas
2253
+ if (e.shiftKey) {
2254
+ // textarea & input - enterMod + shift + enter = accept, then go to prev;
2255
+ // base.switchInput(goToNext, autoAccept)
2256
+ // textarea & input - shift + enter = accept (no navigation)
2257
+ return (o.enterNavigation) ? base.switchInput(!e[o.enterMod], true) : base.close(true);
2258
+ }
2259
+ // input only - enterMod + enter to navigate
2260
+ if (o.enterNavigation && (tag !== 'TEXTAREA' || e[o.enterMod])) {
2261
+ return base.switchInput(!e[o.enterMod], o.autoAccept ? 'true' : false);
2262
+ }
2263
+ // pressing virtual enter button inside of a textarea - add a carriage return
2264
+ // e.target is span when clicking on text and button at other times
2265
+ if (tag === 'TEXTAREA' && $(e.target).closest('button').length) {
2266
+ // IE8 fix (space + \n) - fixes #71 thanks Blookie!
2267
+ base.insertText(($keyboard.msie ? ' ' : '') + '\n');
2268
+ }
2269
+ },
2270
+ // caps lock key
2271
+ lock: function (base) {
2272
+ base.last.keyset[0] = base.shiftActive = base.capsLock = !base.capsLock;
2273
+ base.showSet();
2274
+ },
2275
+ left: function (base) {
2276
+ var p = $keyboard.caret(base.$preview);
2277
+ if (p.start - 1 >= 0) {
2278
+ // move both start and end of caret (prevents text selection) & save caret position
2279
+ base.last.start = base.last.end = p.start - 1;
2280
+ $keyboard.caret(base.$preview, base.last);
2281
+ base.setScroll();
2282
+ }
2283
+ },
2284
+ meta: function (base, el) {
2285
+ var $el = $(el);
2286
+ base.metaActive = !$el.hasClass(base.options.css.buttonActive);
2287
+ base.showSet($el.attr('data-name'));
2288
+ },
2289
+ next: function (base) {
2290
+ base.switchInput(true, base.options.autoAccept);
2291
+ return false;
2292
+ },
2293
+ // same as 'default' - resets to base keyset
2294
+ normal: function (base) {
2295
+ base.shiftActive = base.altActive = base.metaActive = false;
2296
+ base.showSet();
2297
+ },
2298
+ prev: function (base) {
2299
+ base.switchInput(false, base.options.autoAccept);
2300
+ return false;
2301
+ },
2302
+ right: function (base) {
2303
+ var p = $keyboard.caret(base.$preview);
2304
+ if (p.start + 1 <= base.$preview.val().length) {
2305
+ // move both start and end of caret (prevents text selection) && save caret position
2306
+ base.last.start = base.last.end = p.start + 1;
2307
+ $keyboard.caret(base.$preview, base.last);
2308
+ base.setScroll();
2309
+ }
2310
+ },
2311
+ shift: function (base) {
2312
+ base.last.keyset[0] = base.shiftActive = !base.shiftActive;
2313
+ base.showSet();
2314
+ },
2315
+ sign: function (base) {
2316
+ if (/^\-?\d*\.?\d*$/.test(base.$preview.val())) {
2317
+ base.$preview.val((base.$preview.val() * -1));
2318
+ }
2319
+ },
2320
+ space: function (base) {
2321
+ base.insertText(' ');
2322
+ },
2323
+ tab: function (base) {
2324
+ var tag = base.el.nodeName,
2325
+ o = base.options;
2326
+ if (tag === 'INPUT') {
2327
+ if (o.tabNavigation) {
2328
+ return base.switchInput(!base.shiftActive, true);
2329
+ } else {
2330
+ // ignore tab key in input
2331
+ return false;
2332
+ }
2333
+ }
2334
+ base.insertText('\t');
2335
+ },
2336
+ toggle: function (base) {
2337
+ base.enabled = !base.enabled;
2338
+ base.toggle();
2339
+ },
2340
+ // *** Special action keys: NBSP & zero-width characters ***
2341
+ // Non-breaking space
2342
+ NBSP: '\u00a0',
2343
+ // zero width space
2344
+ ZWSP: '\u200b',
2345
+ // Zero width non-joiner
2346
+ ZWNJ: '\u200c',
2347
+ // Zero width joiner
2348
+ ZWJ: '\u200d',
2349
+ // Left-to-right Mark
2350
+ LRM: '\u200e',
2351
+ // Right-to-left Mark
2352
+ RLM: '\u200f'
2353
+ };
2354
+
2355
+ // Default keyboard layouts
2356
+ $keyboard.builtLayouts = {};
2357
+ $keyboard.layouts = {
2358
+ 'alpha': {
2359
+ 'normal': [
2360
+ '` 1 2 3 4 5 6 7 8 9 0 - = {bksp}',
2361
+ '{tab} a b c d e f g h i j [ ] \\',
2362
+ 'k l m n o p q r s ; \' {enter}',
2363
+ '{shift} t u v w x y z , . / {shift}',
2364
+ '{accept} {space} {cancel}'
2365
+ ],
2366
+ 'shift': [
2367
+ '~ ! @ # $ % ^ & * ( ) _ + {bksp}',
2368
+ '{tab} A B C D E F G H I J { } |',
2369
+ 'K L M N O P Q R S : " {enter}',
2370
+ '{shift} T U V W X Y Z < > ? {shift}',
2371
+ '{accept} {space} {cancel}'
2372
+ ]
2373
+ },
2374
+ 'qwerty': {
2375
+ 'normal': [
2376
+ '` 1 2 3 4 5 6 7 8 9 0 - = {bksp}',
2377
+ '{tab} q w e r t y u i o p [ ] \\',
2378
+ 'a s d f g h j k l ; \' {enter}',
2379
+ '{shift} z x c v b n m , . / {shift}',
2380
+ '{accept} {space} {cancel}'
2381
+ ],
2382
+ 'shift': [
2383
+ '~ ! @ # $ % ^ & * ( ) _ + {bksp}',
2384
+ '{tab} Q W E R T Y U I O P { } |',
2385
+ 'A S D F G H J K L : " {enter}',
2386
+ '{shift} Z X C V B N M < > ? {shift}',
2387
+ '{accept} {space} {cancel}'
2388
+ ]
2389
+ },
2390
+ 'international': {
2391
+ 'normal': [
2392
+ '` 1 2 3 4 5 6 7 8 9 0 - = {bksp}',
2393
+ '{tab} q w e r t y u i o p [ ] \\',
2394
+ 'a s d f g h j k l ; \' {enter}',
2395
+ '{shift} z x c v b n m , . / {shift}',
2396
+ '{accept} {alt} {space} {alt} {cancel}'
2397
+ ],
2398
+ 'shift': [
2399
+ '~ ! @ # $ % ^ & * ( ) _ + {bksp}',
2400
+ '{tab} Q W E R T Y U I O P { } |',
2401
+ 'A S D F G H J K L : " {enter}',
2402
+ '{shift} Z X C V B N M < > ? {shift}',
2403
+ '{accept} {alt} {space} {alt} {cancel}'
2404
+ ],
2405
+ 'alt': [
2406
+ '~ \u00a1 \u00b2 \u00b3 \u00a4 \u20ac \u00bc \u00bd \u00be \u2018 \u2019 \u00a5 \u00d7 {bksp}',
2407
+ '{tab} \u00e4 \u00e5 \u00e9 \u00ae \u00fe \u00fc \u00fa \u00ed \u00f3 \u00f6 \u00ab \u00bb \u00ac',
2408
+ '\u00e1 \u00df \u00f0 f g h j k \u00f8 \u00b6 \u00b4 {enter}',
2409
+ '{shift} \u00e6 x \u00a9 v b \u00f1 \u00b5 \u00e7 > \u00bf {shift}',
2410
+ '{accept} {alt} {space} {alt} {cancel}'
2411
+ ],
2412
+ 'alt-shift': [
2413
+ '~ \u00b9 \u00b2 \u00b3 \u00a3 \u20ac \u00bc \u00bd \u00be \u2018 \u2019 \u00a5 \u00f7 {bksp}',
2414
+ '{tab} \u00c4 \u00c5 \u00c9 \u00ae \u00de \u00dc \u00da \u00cd \u00d3 \u00d6 \u00ab \u00bb \u00a6',
2415
+ '\u00c4 \u00a7 \u00d0 F G H J K \u00d8 \u00b0 \u00a8 {enter}',
2416
+ '{shift} \u00c6 X \u00a2 V B \u00d1 \u00b5 \u00c7 . \u00bf {shift}',
2417
+ '{accept} {alt} {space} {alt} {cancel}'
2418
+ ]
2419
+ },
2420
+ 'colemak': {
2421
+ 'normal': [
2422
+ '` 1 2 3 4 5 6 7 8 9 0 - = {bksp}',
2423
+ '{tab} q w f p g j l u y ; [ ] \\',
2424
+ '{bksp} a r s t d h n e i o \' {enter}',
2425
+ '{shift} z x c v b k m , . / {shift}',
2426
+ '{accept} {space} {cancel}'
2427
+ ],
2428
+ 'shift': [
2429
+ '~ ! @ # $ % ^ & * ( ) _ + {bksp}',
2430
+ '{tab} Q W F P G J L U Y : { } |',
2431
+ '{bksp} A R S T D H N E I O " {enter}',
2432
+ '{shift} Z X C V B K M < > ? {shift}',
2433
+ '{accept} {space} {cancel}'
2434
+ ]
2435
+ },
2436
+ 'dvorak': {
2437
+ 'normal': [
2438
+ '` 1 2 3 4 5 6 7 8 9 0 [ ] {bksp}',
2439
+ '{tab} \' , . p y f g c r l / = \\',
2440
+ 'a o e u i d h t n s - {enter}',
2441
+ '{shift} ; q j k x b m w v z {shift}',
2442
+ '{accept} {space} {cancel}'
2443
+ ],
2444
+ 'shift': [
2445
+ '~ ! @ # $ % ^ & * ( ) { } {bksp}',
2446
+ '{tab} " < > P Y F G C R L ? + |',
2447
+ 'A O E U I D H T N S _ {enter}',
2448
+ '{shift} : Q J K X B M W V Z {shift}',
2449
+ '{accept} {space} {cancel}'
2450
+ ]
2451
+ },
2452
+ 'num': {
2453
+ 'normal': [
2454
+ '= ( ) {b}',
2455
+ '{clear} / * -',
2456
+ '7 8 9 +',
2457
+ '4 5 6 {sign}',
2458
+ '1 2 3 %',
2459
+ '0 {dec} {a} {c}'
2460
+ ]
2461
+ }
2462
+ };
2463
+
2464
+ $keyboard.language = {
2465
+ en: {
2466
+ display: {
2467
+ // check mark - same action as accept
2468
+ 'a': '\u2714:Accept (Shift+Enter)',
2469
+ 'accept': 'Accept:Accept (Shift+Enter)',
2470
+ // other alternatives \u2311
2471
+ 'alt': 'Alt:\u2325 AltGr',
2472
+ // Left arrow (same as &larr;)
2473
+ 'b': '\u232b:Backspace',
2474
+ 'bksp': 'Bksp:Backspace',
2475
+ // big X, close - same action as cancel
2476
+ 'c': '\u2716:Cancel (Esc)',
2477
+ 'cancel': 'Cancel:Cancel (Esc)',
2478
+ // clear num pad
2479
+ 'clear': 'C:Clear',
2480
+ 'combo': '\u00f6:Toggle Combo Keys',
2481
+ // decimal point for num pad (optional), change '.' to ',' for European format
2482
+ 'dec': '.:Decimal',
2483
+ // down, then left arrow - enter symbol
2484
+ 'e': '\u23ce:Enter',
2485
+ 'empty': '\u00a0',
2486
+ 'enter': 'Enter:Enter \u23ce',
2487
+ // left arrow (move caret)
2488
+ 'left': '\u2190',
2489
+ // caps lock
2490
+ 'lock': 'Lock:\u21ea Caps Lock',
2491
+ 'next': 'Next \u21e8',
2492
+ 'prev': '\u21e6 Prev',
2493
+ // right arrow (move caret)
2494
+ 'right': '\u2192',
2495
+ // thick hollow up arrow
2496
+ 's': '\u21e7:Shift',
2497
+ 'shift': 'Shift:Shift',
2498
+ // +/- sign for num pad
2499
+ 'sign': '\u00b1:Change Sign',
2500
+ 'space': '\u00a0:Space',
2501
+ // right arrow to bar (used since this virtual keyboard works with one directional tabs)
2502
+ 't': '\u21e5:Tab',
2503
+ // \u21b9 is the true tab symbol (left & right arrows)
2504
+ 'tab': '\u21e5 Tab:Tab',
2505
+ // replaced by an image
2506
+ 'toggle': ' ',
2507
+
2508
+ // added to titles of keys
2509
+ // accept key status when acceptValid:true
2510
+ 'valid': 'valid',
2511
+ 'invalid': 'invalid',
2512
+ // combo key states
2513
+ 'active': 'active',
2514
+ 'disabled': 'disabled'
2515
+ },
2516
+
2517
+ // Message added to the key title while hovering, if the mousewheel plugin exists
2518
+ wheelMessage: 'Use mousewheel to see other keys',
2519
+
2520
+ comboRegex: /([`\'~\^\"ao])([a-z])/mig,
2521
+ combos: {
2522
+ // grave
2523
+ '`': { a: '\u00e0', A: '\u00c0', e: '\u00e8', E: '\u00c8', i: '\u00ec', I: '\u00cc', o: '\u00f2',
2524
+ O: '\u00d2', u: '\u00f9', U: '\u00d9', y: '\u1ef3', Y: '\u1ef2' },
2525
+ // acute & cedilla
2526
+ "'": { a: '\u00e1', A: '\u00c1', e: '\u00e9', E: '\u00c9', i: '\u00ed', I: '\u00cd', o: '\u00f3',
2527
+ O: '\u00d3', u: '\u00fa', U: '\u00da', y: '\u00fd', Y: '\u00dd' },
2528
+ // umlaut/trema
2529
+ '"': { a: '\u00e4', A: '\u00c4', e: '\u00eb', E: '\u00cb', i: '\u00ef', I: '\u00cf', o: '\u00f6',
2530
+ O: '\u00d6', u: '\u00fc', U: '\u00dc', y: '\u00ff', Y: '\u0178' },
2531
+ // circumflex
2532
+ '^': { a: '\u00e2', A: '\u00c2', e: '\u00ea', E: '\u00ca', i: '\u00ee', I: '\u00ce', o: '\u00f4',
2533
+ O: '\u00d4', u: '\u00fb', U: '\u00db', y: '\u0177', Y: '\u0176' },
2534
+ // tilde
2535
+ '~': { a: '\u00e3', A: '\u00c3', e: '\u1ebd', E: '\u1ebc', i: '\u0129', I: '\u0128', o: '\u00f5',
2536
+ O: '\u00d5', u: '\u0169', U: '\u0168', y: '\u1ef9', Y: '\u1ef8', n: '\u00f1', N: '\u00d1' }
2537
+ }
2538
+ }
2539
+ };
2540
+
2541
+ $keyboard.defaultOptions = {
2542
+ // set this to ISO 639-1 language code to override language set by the layout
2543
+ // http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
2544
+ // language defaults to 'en' if not found
2545
+ language: null,
2546
+ rtl: false,
2547
+
2548
+ // *** choose layout & positioning ***
2549
+ layout: 'qwerty',
2550
+ customLayout: null,
2551
+
2552
+ position: {
2553
+ // optional - null (attach to input/textarea) or a jQuery object (attach elsewhere)
2554
+ of: null,
2555
+ my: 'center top',
2556
+ at: 'center top',
2557
+ // used when 'usePreview' is false (centers the keyboard at the bottom of the input/textarea)
2558
+ at2: 'center bottom'
2559
+ },
2560
+
2561
+ // allow jQuery position utility to reposition the keyboard on window resize
2562
+ reposition: true,
2563
+
2564
+ // preview added above keyboard if true, original input/textarea used if false
2565
+ usePreview: true,
2566
+
2567
+ // if true, the keyboard will always be visible
2568
+ alwaysOpen: false,
2569
+
2570
+ // give the preview initial focus when the keyboard becomes visible
2571
+ initialFocus: true,
2572
+
2573
+ // avoid changing the focus (hardware keyboard probably won't work)
2574
+ noFocus: false,
2575
+
2576
+ // if true, keyboard will remain open even if the input loses focus, but closes on escape
2577
+ // or when another keyboard opens.
2578
+ stayOpen: false,
2579
+
2580
+ // if true, keyboard will not close if you press escape.
2581
+ ignoreEsc: false,
2582
+
2583
+ css: {
2584
+ // input & preview
2585
+ input: 'ui-widget-content ui-corner-all',
2586
+ // keyboard container
2587
+ container: 'ui-widget-content ui-widget ui-corner-all ui-helper-clearfix',
2588
+ // keyboard container extra class (same as container, but separate)
2589
+ popup: '',
2590
+ // default state
2591
+ buttonDefault: 'ui-state-default ui-corner-all',
2592
+ // hovered button
2593
+ buttonHover: 'ui-state-hover',
2594
+ // Action keys (e.g. Accept, Cancel, Tab, etc); this replaces 'actionClass' option
2595
+ buttonAction: 'ui-state-active',
2596
+ // Active keys (e.g. shift down, meta keyset active, combo keys active)
2597
+ buttonActive: 'ui-state-active',
2598
+ // used when disabling the decimal button {dec} when a decimal exists in the input area
2599
+ buttonDisabled: 'ui-state-disabled',
2600
+ buttonEmpty: 'ui-keyboard-empty'
2601
+ },
2602
+
2603
+ // *** Useability ***
2604
+ // Auto-accept content when clicking outside the keyboard (popup will close)
2605
+ autoAccept: false,
2606
+ // Auto-accept content even if the user presses escape (only works if `autoAccept` is `true`)
2607
+ autoAcceptOnEsc: false,
2608
+
2609
+ // Prevents direct input in the preview window when true
2610
+ lockInput: false,
2611
+
2612
+ // Prevent keys not in the displayed keyboard from being typed in
2613
+ restrictInput: false,
2614
+ // Additional allowed characters while restrictInput is true
2615
+ restrictInclude: '', // e.g. 'a b foo \ud83d\ude38'
2616
+
2617
+ // Check input against validate function, if valid the accept button gets a class name of
2618
+ // 'ui-keyboard-valid-input'. If invalid, the accept button gets a class name of
2619
+ // 'ui-keyboard-invalid-input'
2620
+ acceptValid: false,
2621
+
2622
+ // if acceptValid is true & the validate function returns a false, this option will cancel
2623
+ // a keyboard close only after the accept button is pressed
2624
+ cancelClose: true,
2625
+
2626
+ // tab to go to next, shift-tab for previous (default behavior)
2627
+ tabNavigation: false,
2628
+
2629
+ // enter for next input; shift+enter accepts content & goes to next
2630
+ // shift + 'enterMod' + enter ('enterMod' is the alt as set below) will accept content and go
2631
+ // to previous in a textarea
2632
+ enterNavigation: false,
2633
+ // mod key options: 'ctrlKey', 'shiftKey', 'altKey', 'metaKey' (MAC only)
2634
+ enterMod: 'altKey', // alt-enter to go to previous; shift-alt-enter to accept & go to previous
2635
+
2636
+ // if true, the next button will stop on the last keyboard input/textarea; prev button stops at first
2637
+ // if false, the next button will wrap to target the first input/textarea; prev will go to the last
2638
+ stopAtEnd: true,
2639
+
2640
+ // Set this to append the keyboard after the input/textarea (appended to the input/textarea parent).
2641
+ // This option works best when the input container doesn't have a set width & when the 'tabNavigation'
2642
+ // option is true.
2643
+ appendLocally: false,
2644
+ // When appendLocally is false, the keyboard will be appended to this object
2645
+ appendTo: 'body',
2646
+
2647
+ // If false, the shift key will remain active until the next key is (mouse) clicked on; if true it will
2648
+ // stay active until pressed again
2649
+ stickyShift: true,
2650
+
2651
+ // Prevent pasting content into the area
2652
+ preventPaste: false,
2653
+
2654
+ // caret placed at the end of any text when keyboard becomes visible
2655
+ caretToEnd: false,
2656
+
2657
+ // caret stays this many pixels from the edge of the input while scrolling left/right;
2658
+ // use "c" or "center" to center the caret while scrolling
2659
+ scrollAdjustment: 10,
2660
+
2661
+ // Set the max number of characters allowed in the input, setting it to false disables this option
2662
+ maxLength: false,
2663
+ // allow inserting characters @ caret when maxLength is set
2664
+ maxInsert: true,
2665
+
2666
+ // Mouse repeat delay - when clicking/touching a virtual keyboard key, after this delay the key will
2667
+ // start repeating
2668
+ repeatDelay: 500,
2669
+
2670
+ // Mouse repeat rate - after the repeatDelay, this is the rate (characters per second) at which the
2671
+ // key is repeated Added to simulate holding down a real keyboard key and having it repeat. I haven't
2672
+ // calculated the upper limit of this rate, but it is limited to how fast the javascript can process
2673
+ // the keys. And for me, in Firefox, it's around 20.
2674
+ repeatRate: 20,
2675
+
2676
+ // resets the keyboard to the default keyset when visible
2677
+ resetDefault: true,
2678
+
2679
+ // Event (namespaced) on the input to reveal the keyboard. To disable it, just set it to ''.
2680
+ openOn: 'focus',
2681
+
2682
+ // Event (namepaced) for when the character is added to the input (clicking on the keyboard)
2683
+ keyBinding: 'mousedown touchstart',
2684
+
2685
+ // enable/disable mousewheel functionality
2686
+ // enabling still depends on the mousewheel plugin
2687
+ useWheel: true,
2688
+
2689
+ // combos (emulate dead keys : http://en.wikipedia.org/wiki/Keyboard_layout#US-International)
2690
+ // if user inputs `a the script converts it to à, ^o becomes ô, etc.
2691
+ useCombos: true,
2692
+
2693
+ /*
2694
+ // *** Methods ***
2695
+ // commenting these out to reduce the size of the minified version
2696
+ // Callbacks - attach a function to any of these callbacks as desired
2697
+ initialized : function(e, keyboard, el) {},
2698
+ beforeVisible : function(e, keyboard, el) {},
2699
+ visible : function(e, keyboard, el) {},
2700
+ change : function(e, keyboard, el) {},
2701
+ beforeClose : function(e, keyboard, el, accepted) {},
2702
+ accepted : function(e, keyboard, el) {},
2703
+ canceled : function(e, keyboard, el) {},
2704
+ restricted : function(e, keyboard, el) {},
2705
+ hidden : function(e, keyboard, el) {},
2706
+ // called instead of base.switchInput
2707
+ switchInput : function(keyboard, goToNext, isAccepted) {},
2708
+ // used if you want to create a custom layout or modify the built-in keyboard
2709
+ create : function(keyboard) { return keyboard.buildKeyboard(); },
2710
+
2711
+ // build key callback
2712
+ buildKey : function( keyboard, data ) {
2713
+ / *
2714
+ data = {
2715
+ // READ ONLY
2716
+ isAction : [boolean] true if key is an action key
2717
+ name : [string] key class name suffix ( prefix = 'ui-keyboard-' );
2718
+ may include decimal ascii value of character
2719
+ value : [string] text inserted (non-action keys)
2720
+ title : [string] title attribute of key
2721
+ action : [string] keyaction name
2722
+ html : [string] HTML of the key; it includes a <span> wrapping the text
2723
+ // use to modify key HTML
2724
+ $key : [object] jQuery selector of key which is already appended to keyboard
2725
+ }
2726
+ * /
2727
+ return data;
2728
+ },
2729
+ */
2730
+
2731
+ // this callback is called, if the acceptValid is true, and just before the 'beforeClose' to check
2732
+ // the value if the value is valid, return true and the keyboard will continue as it should
2733
+ // (close if not always open, etc). If the value is not valid, return false and clear the keyboard
2734
+ // value ( like this "keyboard.$preview.val('');" ), if desired. The validate function is called after
2735
+ // each input, the 'isClosing' value will be false; when the accept button is clicked,
2736
+ // 'isClosing' is true
2737
+ validate: function (keyboard, value, isClosing) {
2738
+ return true;
2739
+ }
2740
+
2741
+ };
2742
+
2743
+ // for checking combos
2744
+ $keyboard.comboRegex = /([`\'~\^\"ao])([a-z])/mig;
2745
+
2746
+ // store current keyboard element; used by base.isCurrent()
2747
+ $keyboard.currentKeyboard = '';
2748
+
2749
+ $('<!--[if lte IE 8]><script>jQuery("body").addClass("oldie");</script><![endif]--><!--[if IE]>' +
2750
+ '<script>jQuery("body").addClass("ie");</script><![endif]-->')
2751
+ .appendTo('body')
2752
+ .remove();
2753
+ $keyboard.msie = $('body').hasClass('oldie'); // Old IE flag, used for caret positioning
2754
+ $keyboard.allie = $('body').hasClass('ie');
2755
+
2756
+ $keyboard.watermark = (typeof (document.createElement('input').placeholder) !== 'undefined');
2757
+
2758
+ $keyboard.checkCaretSupport = function () {
2759
+ if (typeof $keyboard.checkCaret !== 'boolean') {
2760
+ // Check if caret position is saved when input is hidden or loses focus
2761
+ // (*cough* all versions of IE and I think Opera has/had an issue as well
2762
+ var $temp = $('<div style="height:0px;width:0px;overflow:hidden;position:fixed;top:0;left:-100px;">' +
2763
+ '<input type="text" value="testing"/></div>').prependTo('body'); // stop page scrolling
2764
+ $keyboard.caret($temp.find('input'), 3, 3);
2765
+ // Also save caret position of the input if it is locked
2766
+ $keyboard.checkCaret = $keyboard.caret($temp.find('input').hide().show()).start !== 3;
2767
+ $temp.remove();
2768
+ }
2769
+ return $keyboard.checkCaret;
2770
+ };
2771
+
2772
+ $keyboard.caret = function ($el, param1, param2) {
2773
+ if (!$el || !$el.length || $el.is(':hidden') || $el.css('visibility') === 'hidden') {
2774
+ return {};
2775
+ }
2776
+ var start, end, txt, pos,
2777
+ kb = $el.data('keyboard'),
2778
+ noFocus = kb && kb.options.noFocus;
2779
+ if (!noFocus) {
2780
+ $el.focus();
2781
+ }
2782
+ // set caret position
2783
+ if (typeof param1 !== 'undefined') {
2784
+ // allow setting caret using ( $el, { start: x, end: y } )
2785
+ if (typeof param1 === 'object' && 'start' in param1 && 'end' in param1) {
2786
+ start = param1.start;
2787
+ end = param1.end;
2788
+ } else if (typeof param2 === 'undefined') {
2789
+ param2 = param1; // set caret using start position
2790
+ }
2791
+ // set caret using ( $el, start, end );
2792
+ if (typeof param1 === 'number' && typeof param2 === 'number') {
2793
+ start = param1;
2794
+ end = param2;
2795
+ } else if (param1 === 'start') {
2796
+ start = end = 0;
2797
+ } else if (typeof param1 === 'string') {
2798
+ // unknown string setting, move caret to end
2799
+ start = end = $el.val().length;
2800
+ }
2801
+
2802
+ // *** SET CARET POSITION ***
2803
+ // modify the line below to adapt to other caret plugins
2804
+ return $el.caret(start, end, noFocus);
2805
+ }
2806
+ // *** GET CARET POSITION ***
2807
+ // modify the line below to adapt to other caret plugins
2808
+ pos = $el.caret();
2809
+ start = pos.start;
2810
+ end = pos.end;
2811
+
2812
+ // *** utilities ***
2813
+ txt = ($el[0].value || $el.text() || '');
2814
+ return {
2815
+ start: start,
2816
+ end: end,
2817
+ // return selected text
2818
+ text: txt.substring(start, end),
2819
+ // return a replace selected string method
2820
+ replaceStr: function (str) {
2821
+ return txt.substring(0, start) + str + txt.substring(end, txt.length);
2822
+ }
2823
+ };
2824
+ };
2825
+
2826
+ $.fn.keyboard = function (options) {
2827
+ return this.each(function () {
2828
+ if (!$(this).data('keyboard')) {
2829
+ /*jshint nonew:false */
2830
+ (new $.keyboard(this, options));
2831
+ }
2832
+ });
2833
+ };
2834
+
2835
+ $.fn.getkeyboard = function () {
2836
+ return this.data('keyboard');
2837
+ };
2838
+
2839
+ /* Copyright (c) 2010 C. F., Wong (<a href="http://cloudgen.w0ng.hk">Cloudgen Examplet Store</a>)
2840
+ * Licensed under the MIT License:
2841
+ * http://www.opensource.org/licenses/mit-license.php
2842
+ * Highly modified from the original
2843
+ */
2844
+
2845
+ $.fn.caret = function (start, end, noFocus) {
2846
+ if (typeof this[0] === 'undefined' || this.is(':hidden') || this.css('visibility') === 'hidden') {
2847
+ return this;
2848
+ }
2849
+ var selRange, range, stored_range, txt, val,
2850
+ selection = document.selection,
2851
+ $el = this,
2852
+ el = $el[0],
2853
+ sTop = el.scrollTop,
2854
+ ss = false,
2855
+ supportCaret = true;
2856
+ try {
2857
+ ss = 'selectionStart' in el;
2858
+ } catch (err) {
2859
+ supportCaret = false;
2860
+ }
2861
+ if (supportCaret && typeof start !== 'undefined') {
2862
+ if (!/(email|number)/i.test(el.type)) {
2863
+ if (ss) {
2864
+ el.selectionStart = start;
2865
+ el.selectionEnd = end;
2866
+ } else {
2867
+ selRange = el.createTextRange();
2868
+ selRange.collapse(true);
2869
+ selRange.moveStart('character', start);
2870
+ selRange.moveEnd('character', end - start);
2871
+ selRange.select();
2872
+ }
2873
+ }
2874
+ // must be visible or IE8 crashes; IE9 in compatibility mode works fine - issue #56
2875
+ if (!noFocus && ($el.is(':visible') || $el.css('visibility') !== 'hidden')) {
2876
+ el.focus();
2877
+ }
2878
+ el.scrollTop = sTop;
2879
+ return this;
2880
+ } else {
2881
+ if (/(email|number)/i.test(el.type)) {
2882
+ // fix suggested by raduanastase (https://github.com/Mottie/Keyboard/issues/105#issuecomment-40456535)
2883
+ start = end = $el.val().length;
2884
+ } else if (ss) {
2885
+ start = el.selectionStart;
2886
+ end = el.selectionEnd;
2887
+ } else if (selection) {
2888
+ if (el.nodeName === 'TEXTAREA') {
2889
+ val = $el.val();
2890
+ range = selection.createRange();
2891
+ stored_range = range.duplicate();
2892
+ stored_range.moveToElementText(el);
2893
+ stored_range.setEndPoint('EndToEnd', range);
2894
+ // thanks to the awesome comments in the rangy plugin
2895
+ start = stored_range.text.replace(/\r/g, '\n').length;
2896
+ end = start + range.text.replace(/\r/g, '\n').length;
2897
+ } else {
2898
+ val = $el.val().replace(/\r/g, '\n');
2899
+ range = selection.createRange().duplicate();
2900
+ range.moveEnd('character', val.length);
2901
+ start = (range.text === '' ? val.length : val.lastIndexOf(range.text));
2902
+ range = selection.createRange().duplicate();
2903
+ range.moveStart('character', -val.length);
2904
+ end = range.text.length;
2905
+ }
2906
+ } else {
2907
+ // caret positioning not supported
2908
+ start = end = (el.value || '').length;
2909
+ }
2910
+ txt = (el.value || '');
2911
+ return {
2912
+ start: start,
2913
+ end: end,
2914
+ text: txt.substring(start, end),
2915
+ replace: function (str) {
2916
+ return txt.substring(0, start) + str + txt.substring(end, txt.length);
2917
+ }
2918
+ };
2919
+ }
2920
+ };
2921
+
2922
+ return $keyboard;
2923
+
2924
+ }));