Ver Fonte

Bower: add Keyboard

Angel Fernando Quiroz Campos há 6 anos atrás
pai
commit
eb46f47b6b
100 ficheiros alterados com 5251 adições e 0 exclusões
  1. 69 0
      app/Resources/public/assets/keyboard/.bower.json
  2. 10 0
      app/Resources/public/assets/keyboard/.editorconfig
  3. 29 0
      app/Resources/public/assets/keyboard/.eslintrc
  4. 22 0
      app/Resources/public/assets/keyboard/.gitattributes
  5. 23 0
      app/Resources/public/assets/keyboard/.gitignore
  6. 4 0
      app/Resources/public/assets/keyboard/.mailmap
  7. 52 0
      app/Resources/public/assets/keyboard/AUTHORS
  8. 1 0
      app/Resources/public/assets/keyboard/CHANGELOG.md
  9. 11 0
      app/Resources/public/assets/keyboard/CONTRIBUTING.md
  10. 275 0
      app/Resources/public/assets/keyboard/Gruntfile.js
  11. 45 0
      app/Resources/public/assets/keyboard/LICENSE
  12. 178 0
      app/Resources/public/assets/keyboard/README.md
  13. 58 0
      app/Resources/public/assets/keyboard/bower.json
  14. 52 0
      app/Resources/public/assets/keyboard/composer.json
  15. 3 0
      app/Resources/public/assets/keyboard/css/images/disabled.svg
  16. 3 0
      app/Resources/public/assets/keyboard/css/images/enabled.svg
  17. 15 0
      app/Resources/public/assets/keyboard/css/images/keyboard.svg
  18. 196 0
      app/Resources/public/assets/keyboard/css/keyboard-basic.css
  19. 196 0
      app/Resources/public/assets/keyboard/css/keyboard-dark.css
  20. 44 0
      app/Resources/public/assets/keyboard/css/keyboard-previewkeyset.css
  21. 337 0
      app/Resources/public/assets/keyboard/css/keyboard.css
  22. 0 0
      app/Resources/public/assets/keyboard/dist/css/keyboard-basic.min.css
  23. 0 0
      app/Resources/public/assets/keyboard/dist/css/keyboard-dark.min.css
  24. 1 0
      app/Resources/public/assets/keyboard/dist/css/keyboard-previewkeyset.min.css
  25. 0 0
      app/Resources/public/assets/keyboard/dist/css/keyboard.min.css
  26. 2 0
      app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.extension-all.min.js
  27. 1 0
      app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.extension-altkeyspopup.min.js
  28. 1 0
      app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.extension-autocomplete.min.js
  29. 1 0
      app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.extension-caret.min.js
  30. 1 0
      app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.extension-extender.min.js
  31. 1 0
      app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.extension-mobile.min.js
  32. 1 0
      app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.extension-navigation.min.js
  33. 2 0
      app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.extension-previewkeyset.min.js
  34. 1 0
      app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.extension-scramble.min.js
  35. 1 0
      app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.extension-typing.min.js
  36. 3561 0
      app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.js
  37. 1 0
      app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.min.js
  38. 1 0
      app/Resources/public/assets/keyboard/dist/js/jquery.mousewheel.min.js
  39. 0 0
      app/Resources/public/assets/keyboard/dist/languages/amh.min.js
  40. 1 0
      app/Resources/public/assets/keyboard/dist/languages/de.min.js
  41. 1 0
      app/Resources/public/assets/keyboard/dist/languages/es.min.js
  42. 1 0
      app/Resources/public/assets/keyboard/dist/languages/fa.min.js
  43. 1 0
      app/Resources/public/assets/keyboard/dist/languages/fr.min.js
  44. 1 0
      app/Resources/public/assets/keyboard/dist/languages/he.min.js
  45. 1 0
      app/Resources/public/assets/keyboard/dist/languages/hu.min.js
  46. 1 0
      app/Resources/public/assets/keyboard/dist/languages/it.min.js
  47. 1 0
      app/Resources/public/assets/keyboard/dist/languages/lv.min.js
  48. 1 0
      app/Resources/public/assets/keyboard/dist/languages/my.min.js
  49. 1 0
      app/Resources/public/assets/keyboard/dist/languages/pl.min.js
  50. 1 0
      app/Resources/public/assets/keyboard/dist/languages/pt.min.js
  51. 1 0
      app/Resources/public/assets/keyboard/dist/languages/ro.min.js
  52. 1 0
      app/Resources/public/assets/keyboard/dist/languages/ru.min.js
  53. 1 0
      app/Resources/public/assets/keyboard/dist/languages/sq.min.js
  54. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/albanian.min.js
  55. 0 0
      app/Resources/public/assets/keyboard/dist/layouts/arabic.min.js
  56. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/belarusian.min.js
  57. 0 0
      app/Resources/public/assets/keyboard/dist/layouts/bengali.min.js
  58. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/bulgarian.min.js
  59. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/burmese.min.js
  60. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/catalan.min.js
  61. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/chinese.min.js
  62. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/danish.min.js
  63. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/ethiopic.min.js
  64. 0 0
      app/Resources/public/assets/keyboard/dist/layouts/french.min.js
  65. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/german.min.js
  66. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/hebrew.min.js
  67. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/hindi.min.js
  68. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/hungarian.min.js
  69. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/hungarianansi.min.js
  70. 0 0
      app/Resources/public/assets/keyboard/dist/layouts/japanese.min.js
  71. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/keyboard-layouts-combined.min.js
  72. 2 0
      app/Resources/public/assets/keyboard/dist/layouts/keyboard-layouts-greywyvern.min.js
  73. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/keyboard-layouts-microsoft.min.js
  74. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/latvian.min.js
  75. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/mongolian.min.js
  76. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Albanian.min.js
  77. 0 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Arabic.min.js
  78. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Armenian.min.js
  79. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Assamese.min.js
  80. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Azeri.min.js
  81. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Bashkir.min.js
  82. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Belarusian.min.js
  83. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Belgian.min.js
  84. 0 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Bengali.min.js
  85. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Bulgarian.min.js
  86. 0 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Canadian.min.js
  87. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Chinese.min.js
  88. 0 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Czech.min.js
  89. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Danish.min.js
  90. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Devanagari.min.js
  91. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Divehi.min.js
  92. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Dutch.min.js
  93. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Estonian.min.js
  94. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Faeroese.min.js
  95. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Finnish.min.js
  96. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-French.min.js
  97. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Gaelic.min.js
  98. 0 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Georgian.min.js
  99. 1 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-German.min.js
  100. 0 0
      app/Resources/public/assets/keyboard/dist/layouts/ms-Greek.min.js

+ 69 - 0
app/Resources/public/assets/keyboard/.bower.json

@@ -0,0 +1,69 @@
+{
+  "name": "keyboard",
+  "description": "Virtual Keyboard using jQuery UI",
+  "keywords": [
+    "customizable",
+    "keyboard",
+    "ui",
+    "accessibility",
+    "osk",
+    "jquery-plugin"
+  ],
+  "authors": [
+    {
+      "name": "Jeremy Satterfield",
+      "homepage": "https://github.com/jsatt"
+    },
+    {
+      "name": "Rob Garrison",
+      "homepage": "https://mottie.github.io/Keyboard/",
+      "email": "wowmotty@gmail.com"
+    }
+  ],
+  "homepage": "https://github.com/Mottie/Keyboard",
+  "main": [
+    "dist/js/jquery.keyboard.js",
+    "css/keyboard.css"
+  ],
+  "ignore": [
+    "js/*.js",
+    "docs/*"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/Mottie/keyboard.git"
+  },
+  "license": "MIT",
+  "moduleType": [
+    "amd",
+    "globals",
+    "node"
+  ],
+  "dependencies": {
+    "jquery": ">=1.4.3",
+    "jquery-ui": ">=1.9.2"
+  },
+  "devDependencies": {
+    "grunt": "^1.0.3",
+    "grunt-cli": "^1.3.1",
+    "grunt-contrib-clean": "^2.0.0",
+    "grunt-contrib-concat": "^1.0.1",
+    "grunt-contrib-copy": "^1.0.0",
+    "grunt-contrib-cssmin": "^3.0.0",
+    "grunt-contrib-jshint": "^2.0.0",
+    "grunt-contrib-qunit": "^3.0.1",
+    "grunt-contrib-uglify": "^4.0.0",
+    "grunt-contrib-watch": "^1.1.0"
+  },
+  "version": "1.28.7",
+  "_release": "1.28.7",
+  "_resolution": {
+    "type": "version",
+    "tag": "v1.28.7",
+    "commit": "7d115e954c5ca674e527306d1e81548a7076915e"
+  },
+  "_source": "https://github.com/Mottie/Keyboard.git",
+  "_target": "^1.28.7",
+  "_originalSource": "keyboard",
+  "_direct": true
+}

+ 10 - 0
app/Resources/public/assets/keyboard/.editorconfig

@@ -0,0 +1,10 @@
+# https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties
+root = true
+
+[*]
+indent_style = tab
+trim_trailing_whitespace = true
+end_of_line = lf
+charset = utf-8
+insert_final_newline = true
+max_line_length = 100

+ 29 - 0
app/Resources/public/assets/keyboard/.eslintrc

@@ -0,0 +1,29 @@
+{
+  "env": {
+    "browser": true,
+    "jquery": true
+  },
+  "rules": {
+    "curly": 1,
+    "dot-location": [2, "property"],
+    "eqeqeq": 1,
+    "linebreak-style": [2, "unix"],
+    "no-else-return": 1,
+    "no-eval": 2,
+    "no-octal": 2,
+    "no-with": 2,
+    "radix": 2,
+    "brace-style": 0,
+    "camelcase": 0,
+    "indent": 0,
+    "no-array-constructor": 2,
+    "quotes": [2, "single", {
+      "allowTemplateLiterals": true,
+      "avoidEscape": true
+    }],
+    "spaced-comment": 0,
+    "arrow-spacing": 2,
+    "no-var": 0,
+    "no-unused-vars": 1
+  }
+}

+ 22 - 0
app/Resources/public/assets/keyboard/.gitattributes

@@ -0,0 +1,22 @@
+# Auto detect text files and perform LF normalization
+* text=auto
+
+# Custom for Visual Studio
+*.cs     diff=csharp
+*.sln    merge=union
+*.csproj merge=union
+*.vbproj merge=union
+*.fsproj merge=union
+*.dbproj merge=union
+
+# Standard to msysgit
+*.doc	 diff=astextplain
+*.DOC	 diff=astextplain
+*.docx diff=astextplain
+*.DOCX diff=astextplain
+*.dot  diff=astextplain
+*.DOT  diff=astextplain
+*.pdf  diff=astextplain
+*.PDF	 diff=astextplain
+*.rtf	 diff=astextplain
+*.RTF	 diff=astextplain

+ 23 - 0
app/Resources/public/assets/keyboard/.gitignore

@@ -0,0 +1,23 @@
+# lockfiles
+package-lock.json
+yarn.lock
+
+# temp stuff
+tmp/
+*.tmp
+*.bak
+_test*
+
+# logs
+*.stackdump
+*.log
+
+# Build
+node_modules/
+
+# Windows crap
+Thumbs.db
+Desktop.ini
+
+# Mac crap
+.DS_Store

+ 4 - 0
app/Resources/public/assets/keyboard/.mailmap

@@ -0,0 +1,4 @@
+Rob Garrison <wowmotty@gmail.com> Mottie <wowmotty@gmail.com>
+Rob Garrison <wowmotty@gmail.com> Rob G <wowmotty@gmail.com>
+Muthiah Annamalai <ezhillang@gmail.com> Muthiah Annamalai <muthuspost@gmail.com>
+Bogdan <bs08@ukr.net> bsurai <bs08@ukr.net>

+ 52 - 0
app/Resources/public/assets/keyboard/AUTHORS

@@ -0,0 +1,52 @@
+# Authors ordered by first contribution.
+
+Rob Garrison <wowmotty@gmail.com>
+Yury Kotlyarov <yura@brainhouse.ru>
+Baris Aydinoglu <baydinoglu@gmail.com>
+David Hollifield <david@loadoncall.com>
+Francisco Alcantara <alcantaranet@gmail.com>
+tbvinh <tbvinh@gmail.com>
+utilisezlinux <utilisezlinux@gmail.com>
+José Miguel Sanz <jmsanzg@gmail.com>
+Peter Rekdal <peters@users.noreply.github.com>
+Muthiah Annamalai <ezhillang@gmail.com>
+Lorenzo Stoakes <lstoakes@gmail.com>
+BrandonLWhite <brandonlwhite@gmail.com>
+shin <shin@fucinaludica.it>
+ags131 <ashumann13@gmail.com>
+Marian Pollzien <marian.pollzien@netresearch.de>
+Alex Florea <alecz.fia@gmail.com>
+Eugene Beschastnov <eugene.beschastnov@gmail.com>
+Leonardo Gatica <lgaticastyle@gmail.com>
+Quentin Delcourt <kant312@gmail.com>
+Raido Kuli <raido.kuli@erply.com>
+Joe <jmathews@xumo.com>
+Peter Turczak <peter@turczak.de>
+ihsoft <igor.zavoychinskiy@gmail.com>
+Greg Kubisa <gkubisa@digisoft.tv>
+Adrian Fish <adrian.r.fish@gmail.com>
+Ben Schmidt <none@none>
+isfs <sightless_schmidt@yahoo.com.au>
+The Gitter Badger <badger@gitter.im>
+Akira Speirs <akiraspeirs@gmail.com>
+Chosko <ruben.caliandro@gmail.com>
+Stefan Riedinger <stefan.riedinger@kardex.com>
+ohohyeah <ohohyeah0515@gmail.com>
+uNmAnNeR <ubivaza@gmail.com>
+Sebastian Hillig <bastih@users.noreply.github.com>
+= <=>
+La Min Ko <lminko.lmk@gmail.com>
+Pietro Liuzzo <pietro.liuzzo@gmail.com>
+Simon Legner <Simon.Legner@gmail.com>
+Viktor.Mironov <vicktor.mironov@gmail.com>
+Martin Vavra <martin.vavra.cz@gmail.com>
+Bogdan <bs08@ukr.net>
+Lu, Tom <Tom_Lu@cable.comcast.com>
+fossabot <badges@fossa.io>
+vkurlyan <vkurlyan@users.noreply.github.com>
+BastienVerschaete <32361274+BastienVerschaete@users.noreply.github.com>
+Josh Gum <revgum@gmail.com>
+lsching17 <lsching17@users.noreply.github.com>
+0xflotus <0xflotus@gmail.com>
+
+# Generated by tools/authors.sh

+ 1 - 0
app/Resources/public/assets/keyboard/CHANGELOG.md

@@ -0,0 +1 @@
+Please refer to the wiki pages for the [change log](https://github.com/Mottie/Keyboard/wiki/Log).

+ 11 - 0
app/Resources/public/assets/keyboard/CONTRIBUTING.md

@@ -0,0 +1,11 @@
+# Contributing to the Keyboard Project
+
+Please refer to the [contributing wiki page](https://github.com/Mottie/Keyboard/wiki/Contributing) for more details on how to set up Language & layout files:
+
+* [Layout file](https://github.com/Mottie/Keyboard/wiki/Contributing#layout-file).
+* [Keyboard layot object map](https://github.com/Mottie/Keyboard/wiki/Contributing#map).
+* [Language](https://github.com/Mottie/Keyboard/wiki/Contributing#language).
+* [Set a license](#set-a-license).
+* [Saving &amp; Using your file](https://github.com/Mottie/Keyboard/wiki/Contributing#saving--using-your-file).
+
+# [License](https://github.com/Mottie/Keyboard/blob/master/LICENSE)

+ 275 - 0
app/Resources/public/assets/keyboard/Gruntfile.js

@@ -0,0 +1,275 @@
+/*global module:false */
+module.exports = function(grunt) {
+	'use strict';
+
+	var pkg = grunt.file.readJSON( 'package.json' ),
+	nomod = '/*** This file is dynamically generated ***\n' +
+		'█████▄ ▄████▄   █████▄ ▄████▄ ██████   ███████▄ ▄████▄ █████▄ ██ ██████ ██  ██\n' +
+		'██  ██ ██  ██   ██  ██ ██  ██   ██     ██ ██ ██ ██  ██ ██  ██ ██ ██     ██  ██\n' +
+		'██  ██ ██  ██   ██  ██ ██  ██   ██     ██ ██ ██ ██  ██ ██  ██ ██ ██▀▀   ▀▀▀▀██\n' +
+		'█████▀ ▀████▀   ██  ██ ▀████▀   ██     ██ ██ ██ ▀████▀ █████▀ ██ ██     █████▀\n*/\n',
+
+	hintOpts = {
+		'jquery': true,
+		'browser': true,
+		'sub': true, // used by layouts
+		'-W100': true // ignore "This character may get silently deleted by one or more browsers."
+	};
+
+	// Project configuration.
+	grunt.initConfig({
+
+		pkg: pkg,
+
+		clean: {
+			core: {
+				src: [
+					'dist/css/*',
+					'dist/js/*',
+					'js/jquery.keyboard.extension-all.js'
+				]
+			},
+			layouts: {
+				src: [
+					'dist/*',
+					'js/jquery.keyboard.extension-all.js',
+					'layouts/keyboard-layouts-combined.js',
+					'layouts/keyboard-layouts-microsoft.js'
+				]
+			},
+			languages: {
+				src: [ 'dist/languages/*' ]
+			}
+		},
+
+		copy: {
+			js: {
+				files : [{
+					expand: true,
+					dot: true,
+					flatten: true,
+					src: [ 'js/jquery.keyboard.js' ],
+					dest: 'dist/js/'
+				}]
+			}
+		},
+
+		concat: {
+			exts: {
+				options: {
+					banner: nomod + '/*! jQuery UI Virtual Keyboard (<%= pkg.version %>) - ALL Extensions + Mousewheel */\n'
+				},
+				files: {
+					'js/jquery.keyboard.extension-all.js': [ 'js/jquery.keyboard.extension-*.js', 'js/jquery.mousewheel.js' ]
+				}
+			},
+			origLayouts: {
+				options: {
+					banner: nomod + '/*! jQuery UI Virtual Keyboard - Original Layouts */\n'
+				},
+				files: {
+					'layouts/keyboard-layouts-combined.js': [
+						'layouts/*',
+						'!layouts/_layout_template.js',
+						'!layouts/ms-*.js',
+						'!layouts/keyboard-layouts-greywyvern.js',
+						'languages/*.js',
+						'!languages/_language_template.js',
+						'!languages/*.untranslated.js'
+					]
+				}
+			},
+			msLayouts: {
+				options: {
+					banner: nomod + '/*! jQuery UI Virtual Keyboard - Microsoft Generated Layouts */\n'
+				},
+				files: {
+					'layouts/keyboard-layouts-microsoft.js': [
+						'layouts/ms-*.js',
+						'!layouts/_layout_template.js',
+						'languages/*.js',
+						'!languages/_language_template.js',
+						'!languages/*.untranslated.js'
+					]
+				}
+			},
+			greyLayouts: {
+				options: {
+					banner: nomod + '/*! jQuery UI Virtual Keyboard - Microsoft Generated Layouts */\n'
+				},
+				files: {
+					'dist/layouts/keyboard-layouts-greywyvern.min.js': [
+						'layouts/keyboard-layouts-greywyvern.js',
+						'languages/*.js',
+						'!languages/_language_template.js',
+						'!languages/*.untranslated.js'
+					]
+				}
+			}
+		},
+
+		jshint: {
+			core: {
+				options: hintOpts,
+				src: [ 'js/jquery.*.js' ]
+			},
+			layouts: {
+				options: hintOpts,
+				src: [ 'js/jquery.*.js', 'layouts/*' ]
+			},
+			languages: {
+				option: hintOpts,
+				src: [ 'languages/*' ]
+			}
+		},
+
+		cssmin: {
+			target: {
+				files: [{
+					expand: true,
+					flatten: true,
+					src: ['css/*.css'],
+					dest: 'dist/css/',
+					ext: '.min.css'
+				}]
+			}
+		},
+
+		uglify: {
+			options: {
+				output: {
+					comments: /^!/,
+					beautify: false
+				},
+				report: 'gzip'
+			},
+			core: {
+				files: [{
+					expand: true,
+					cwd: '',
+					src: [ 'js/jquery*.js' ],
+					dest: 'dist/js/',
+					ext: '.min.js',
+					extDot: 'last',
+					flatten: true
+				}]
+			},
+			splitLayouts: {
+				files: [{
+					expand: true,
+					cwd: '',
+					src: [ 'layouts/*.js', '!layouts/_layout_template.js', '!layouts/keyboard-layouts-greywyvern.js' ],
+					dest: 'dist/layouts/',
+					ext: '.min.js',
+					extDot: 'last',
+					flatten: true
+				}]
+			},
+			greyLayout: {
+				files: [{
+					expand: true,
+					cwd: '',
+					src: [ 'dist/layouts/keyboard-layouts-greywyvern.min.js' ],
+					dest: 'dist/layouts/',
+					ext: '.js',
+					extDot: 'last',
+					flatten: true
+				}]
+			},
+			languages: {
+				files: [{
+					expand: true,
+					cwd: '',
+					src: [ 'languages/*.js', '!languages/_language_template.js', '!languages/*.untranslated.js' ],
+					dest: 'dist/languages/',
+					ext: '.min.js',
+					extDot: 'last',
+					flatten: true
+				}]
+			}
+		},
+
+		qunit: {
+			files: ['testing/test.html']
+		},
+
+		watch: {
+			scripts: {
+				files: ['js/*.js'],
+				tasks: ['build']
+			}
+		}
+
+	});
+
+	grunt.loadNpmTasks('grunt-contrib-clean');
+	grunt.loadNpmTasks('grunt-contrib-jshint');
+	grunt.loadNpmTasks('grunt-contrib-qunit');
+	grunt.loadNpmTasks('grunt-contrib-concat');
+	grunt.loadNpmTasks('grunt-contrib-uglify');
+	grunt.loadNpmTasks('grunt-contrib-cssmin');
+	grunt.loadNpmTasks('grunt-contrib-watch');
+	grunt.loadNpmTasks('grunt-contrib-copy');
+
+	// Default task.
+	grunt.registerTask('default', [
+		'clean:core',
+		'jshint:core',
+		'qunit',
+		'copy',
+		'concat:exts',
+		'cssmin',
+		'uglify:core',
+		'updateManifest'
+	]);
+	// layout build takes a lot longer to uglify
+	grunt.registerTask('layouts', [
+		'clean:layouts',
+		'jshint:layouts',
+		'concat',
+		'cssmin',
+		'uglify'
+	]);
+
+	function escapeRegExp(str) {
+		return str.replace(/[$()*+\-.\/?[\\\]^{|}]/g, '\\$&');
+	}
+
+	// update keyboard.jquery.json file version numbers to match the package.json version
+	grunt.registerTask( 'updateManifest', function() {
+		var i, project,
+			projectFile = [ 'keyboard.jquery.json', 'bower.json' ],
+			len = projectFile.length;
+		for ( i = 0; i < len; i++ ) {
+			if ( !grunt.file.exists( projectFile[ i ] ) ) {
+				grunt.log.error( 'file ' + projectFile[ i ] + ' not found' );
+				return true; // return false to abort the execution
+			}
+			project = grunt.file.readJSON( projectFile[ i ] ); // get file as json object
+			if (i === 0 ) {
+				// only update version in keyboard.jquery.json
+				project.version = pkg.version;
+			} else if (i === 1) {
+				// update devDependencies in bower
+				project.devDependencies = pkg.devDependencies;
+			}
+			grunt.file.write( projectFile[i], JSON.stringify( project, null, 2 ) ); // serialize it back to file
+		}
+		// check internal version number
+		project = grunt.file.read('js/jquery.keyboard.js');
+		if (
+			new RegExp(escapeRegExp('/*! jQuery UI Virtual Keyboard v' + pkg.version)).test(project) &&
+			new RegExp(escapeRegExp('base.version = \'' + pkg.version)).test(project)
+		) {
+			console.info('versions all match!');
+		} else {
+			grunt.log.writeln('\n**** version mismatch! ****'['red'].bold);
+		}
+		// check internal version number
+		project = grunt.file.read('README.md');
+		if (!new RegExp(escapeRegExp('### Version ' + pkg.version)).test(project)) {
+			grunt.log.writeln('\n**** Missing Readme entry! ****'['red'].bold);
+		}
+	});
+
+};

+ 45 - 0
app/Resources/public/assets/keyboard/LICENSE

@@ -0,0 +1,45 @@
+==========================
+Keyboard code & Caret code
+==========================
+
+MIT License
+
+Keyboard code: Copyright Rob Garrison & Jeremy Satterfield
+Caret code: Copyright C. F., Wong (Cloudgen)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+==========================
+Language & Layout
+==========================
+
+WTFPL
+
+        DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+                    Version 2, December 2004
+
+ Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
+
+ Everyone is permitted to copy and distribute verbatim or modified
+ copies of this license document, and changing it is allowed as long
+ as the name is changed.
+
+            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. You just DO WHAT THE FUCK YOU WANT TO.

+ 178 - 0
app/Resources/public/assets/keyboard/README.md

@@ -0,0 +1,178 @@
+<img alt="keyboard logo" align="right" src="./docs/css/images/keyboard-logo.png">A jQuery on-screen keyboard (OSK) plugin that works in the browser.<br>
+
+Originally posted by Jeremy Satterfield in his [blog](http://jsatt.blogspot.com/2010/01/on-screen-keyboard-widget-using-jquery.html), [jQuery plugins](http://plugins.jquery.com/project/virtual_keyboard) and on [Snipplr](http://snipplr.com/view/21577/virtual-keyboard-widget/). Currently maintained by [Mottie](https://github.com/Mottie/Keyboard).
+
+[![Bower Version][bower-image]][bower-url] [![NPM Version][npm-image]][npm-url] [![devDependency Status][david-dev-image]][david-dev-url] [![Join the chat at https://gitter.im/Mottie/Keyboard][gitter-image]][gitter]
+[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FMottie%2FKeyboard.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2FMottie%2FKeyboard?ref=badge_shield)
+
+## Features ([Demo](https://mottie.github.io/Keyboard/))
+
+### Ease of use
+
+* An on-screen virtual keyboard embedded within the browser window which will popup when a specified entry field is focused.
+* The user can then type and preview their input before Accepting or Canceling.
+* It can be set to always remain open, and to not use a preview.
+
+### Ease of installation
+
+* Grab the files as a zip, or from npm or bower - see the [installation](#installation) section below.
+* In a minimal setup, the keyboard works by including:
+  * jQuery
+  * jQuery UI theme
+  * (optional) jQuery UI position utility to position the keyboard at the input/textarea element
+  * Initialize keyboard - no options needed for qwerty keyboard.
+
+### Ease of setup
+
+* Attach a keyboard to inputs, textareas or contenteditable elements.
+* Add custom keyboard layouts easily.
+* Multiple region specific keyboard layouts included in a separate directory. This is a work in progress and slowly growing.
+* Add up to four standard key sets to each layout that use the shift and alt keys (default, shift, alt and alt-shift).
+* Add any number of optional modifier keys (meta keys) to add more key sets.
+* Each meta key set can also include the shift, alt and alt-shift keysets.
+* Position the keyboard in any location around the element, or target another element on the page (using jQuery UI position utility).
+* Easily modify the key text to any language or symbol.
+* Allow direct input or lock the preview window.
+* Set a maximum length to the inputted content.
+* Scroll through the other key sets using the mouse wheel while hovering over a key to bypass the need to use alt, shift or meta keys.
+* Easily type in characters with diacritics. Here are some default combination examples:
+    * `'` + vowel ( vowel with acute accent, e.g. `'` + `e` = `é` )
+    * `` ` `` + vowel ( vowel with grave accent, e.g., `` ` `` + `e` = `è` )
+    * `"` + vowel ( vowel with diaresis, e.g., `"` + `e` = `ë` )
+    * `^` + vowel ( vowel with circumflex accent, e.g., `^` + `e` = `ê` )
+    * `~` + certain letters ( letter with tilde, e.g. `~` + `n` = `ñ`, `~` + `o` = `õ` )
+* Enable, disable or add more diacritic functionality as desired.
+* Use callbacks and event triggers that occur when the keyboard is open or closed and when the content has changed, been accepted or canceled.
+* Includes ARIA support (may not be fully implemented).
+* Built in watermarking. It emulates HTML5's placeholder, if the browser doesn't support it.
+* Include validation using a callback function so third-party validation methods can be used.
+
+### Themes
+
+* jQuery UI themes are used by default.
+* Bootstrap themes ([original](https://jsfiddle.net/Mottie/gfgkb4o1/) or [dark](https://jsfiddle.net/Mottie/emLfqchq/)) can also be applied.
+* Or add a completely custom theme (without using jQuery UI position utility):
+  * [Light](https://jsfiddle.net/Mottie/jsh0377k/) using [keyboard-basic.css](https://github.com/Mottie/Keyboard/blob/master/css/keyboard-basic.css).
+  * [Dark](https://jsfiddle.net/Mottie/6dmqhLvh/) using [keyboard-dark.css](https://github.com/Mottie/Keyboard/blob/master/css/keyboard-dark.css).
+
+### Extensions
+
+* [Alt-keys](https://mottie.github.io/Keyboard/docs/altkeys-popup.html): Show alternate keys in a popup after long-clicking on a key.
+* [Autocomplete](https://mottie.github.io/Keyboard/index.html#autocomplete): Integrate with jQuery UI's autocomplete widget.
+* [Caret](https://mottie.github.io/Keyboard/index.html#caret): Add a caret with custom styling.
+* [Extender](https://mottie.github.io/Keyboard/docs/extender.html): Add a togglable layout (e.g. toggle number pad)
+* [Keyset](https://mottie.github.io/Keyboard/docs/preview-keyset.html): Show shift, alt or meta keyset within the virtual keyboard - custom styling.
+* [Mobile](https://mottie.github.io/Keyboard/docs/mobile.html): Use with jQuery Mobile &amp; jQuery [Mobile v1.4](https://mottie.github.io/Keyboard/docs/jquery-mobile-1.4.html).
+* [Navigate](https://mottie.github.io/Keyboard/docs/navigate.html): Use arrow, home, end &amp; page up/down to navigate inside of the keyboard.
+* [Scramble](https://mottie.github.io/Keyboard/docs/scramble.html): Scramble the entire keyset or by row, once or every time the keyboard is opened for added security.
+* [Typing](https://mottie.github.io/Keyboard/index.html#typing): Allows you to simulate typing into the keyboard for demo purposes or to assist user input.
+
+## Dependencies
+
+* Required
+    * jQuery 1.4.3+
+    * jQuery caret (included with source)
+* Optional
+    * jQuery UI Positioning Utility (optional, if you position the keyboard yourself)
+    * jQuery UI CSS (can be customized) / Bootstrap CSS
+    * jQuery mousewheel plugin - allows using mousewheel to scroll through other key sets
+    * jQuery UI Autocomplete widget - use with jQuery keyboard autocomplete extension
+
+## Installation
+
+* Download a [zip](https://github.com/Mottie/Keyboard/archive/master.zip) or [tar.gz](https://github.com/Mottie/Keyboard/archive/master.tar.gz) with all files, for use in the browser.
+* Use the files from [CDNJS](https://cdnjs.com/libraries/virtual-keyboard).
+* Install using [bower](https://github.com/bower/bower) via `bower install keyboard`.
+* Install using [npm](https://www.npmjs.com/) via `npm install virtual-keyboard`.
+* Use with:
+  * [AngularJs](https://github.com/antonio-spinelli/ng-virtual-keyboard) by [antonio-spinelli](https://github.com/antonio-spinelli) via `bower install ng-virtual-keyboard`.
+  * [Ember](https://github.com/SleepyWerewolf/ember-virtual-keyboard) by [SleepyWerewolf](https://github.com/SleepyWerewolf).
+  * [React.js](https://github.com/Utzel-Butzel/react-virtual-keyboard) by [Utzel-Butzel](https://github.com/Utzel-Butzel).
+  * [Ruby On Rails](https://github.com/scicasoft/virtual_keyboard) by [scicasoft](https://github.com/scicasoft) via `gem install virtual_keyboard`.
+  * [VR Toolbox](https://steamcommunity.com/games/488040/announcements/detail/1431432753528769455).
+
+## TypeScript
+
+You can use it with TypeScript. Install [TypeScript](https://www.typescriptlang.org/) and [@types/virtual-keyboard](https://www.npmjs.com/package/@types/virtual-keyboard) into dev dependencies for that.
+
+## Documentation
+
+Wiki: [Home](https://github.com/Mottie/Keyboard/wiki/Home) | [FAQ](https://github.com/Mottie/Keyboard/wiki/FAQ) | [Setup](https://github.com/Mottie/Keyboard/wiki/Setup) | [Usage](https://github.com/Mottie/Keyboard/wiki/Usage) | [Options](https://github.com/Mottie/Keyboard/wiki/Options) ( [Layout](https://github.com/Mottie/Keyboard/wiki/Layout), [Language](https://github.com/Mottie/Keyboard/wiki/Language), [Usability](https://github.com/Mottie/Keyboard/wiki/Usability), [Actions](https://github.com/Mottie/Keyboard/wiki/Actions) ) | [Methods](https://github.com/Mottie/Keyboard/wiki/Methods) | [Theme](https://github.com/Mottie/Keyboard/wiki/Theme) | [Log](https://github.com/Mottie/Keyboard/wiki/Log)
+
+## To Do
+
+* Add an input mask extension. I think I'll try to make it compatible with [this plugin](https://github.com/RobinHerbots/jquery.inputmask).
+* <del>Allow attaching a keyboard to a contenteditable element</del>. Added v1.27.0.
+
+## Known Problems
+
+* *ALL*: Only inputs of type "text", "search", "url", "telephone" and "password" <strong>support caret positioning</strong> ([ref](https://html.spec.whatwg.org/#do-not-apply)). Using this keyboard with any other input type will break  the caret left/right, backspace and delete keys (see [issue #241](https://github.com/Mottie/Keyboard/issues/241) for details).
+* *Mobile*: If the key press lags behind by one character, it is likely due to the mousewheel plugin. Disable it. See issues [#379](https://github.com/Mottie/Keyboard/issues/379) &amp; [#411](https://github.com/Mottie/Keyboard/issues/411).
+* *IE* and *Opera*:
+    * In a text area with multiple carriage returns, the caret positioning will be off when repositioning it with the mouse.
+    * Using the right and left arrow keys to navigate through a text area with multiple carriage returns is problematic. The caret doesn't behave like in other browsers when moving from one line to the next. You can always reposition the caret using the mouse.
+* *Opera*: When pressing the tab key while inside a textarea, all browsers but Opera add the tab to the virtual keyboard textarea.
+* *Safari*: See the QWERTY Text Area demo with a locked input. While using the virtual keyboard to type, it enters the text in backwards! This is because textareas with a "readonly" attribute always returns zero for the caret position.
+* *Typing Extension*:
+    * When pressing "Alt", the key set will change to the alt key set, but the focus will be moved to the browser menu. Pressing it quickly a second time will return the focus. This is built into the browser and it isn't possible (as far as I know) to automatically restore the window focus the first time alt is pressed.
+    * Holding down the Alt key and trying to type is also not possible since the Windows OS is assuming you are trying to type a shortcut key to access the browser menu. You can still click the keys in the alt key set with the mouse.
+    * Simulated typing on the keyboard breaks when the CapsLock is on. Still looking for a cross-browser solution.
+
+## Contributing
+
+* Install [node.js](http://nodejs.org/) - this includes `npm` (node package manager).
+* Run `npm install` in the root directory.
+* Run `npm install -g grunt-cli` to install the grunt command-line interface.
+* Make any changes to the code.
+* Unit tests will be added later.
+* Run `grunt` to perform a new build in the `/dist` folder.
+* Submit a pull request from a branch other than the `master`.
+
+## Licensing
+
+* Keyboard code: [MIT License](http://www.opensource.org/licenses/mit-license.php) for all versions.
+* Caret code by C. F., Wong (Cloudgen): [MIT License](http://www.opensource.org/licenses/mit-license.php)
+* Layouts files: Most are under [WTFPL](http://sam.zoy.org/wtfpl/), unless the file itself specifies otherwise.
+
+[npm-url]: https://npmjs.org/package/virtual-keyboard
+[npm-image]: https://img.shields.io/npm/v/virtual-keyboard.svg
+[david-dev-url]: https://david-dm.org/Mottie/keyboard?type=dev
+[david-dev-image]: https://david-dm.org/Mottie/keyboard/dev-status.svg
+[bower-url]: http://bower.io/search/?q=keyboard
+[bower-image]: https://img.shields.io/bower/v/keyboard.svg
+[gitter-image]: https://badges.gitter.im/Join%20Chat.svg
+[gitter]: https://gitter.im/Mottie/Keyboard?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
+
+
+[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FMottie%2FKeyboard.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2FMottie%2FKeyboard?ref=badge_large)
+
+## Change Log
+
+Only the latest changes will be shown below, see the [wiki log](https://github.com/Mottie/Keyboard/wiki/Log) to view older versions.
+
+### Version 1.28.7 (2018-10-09)
+
+* Core:
+  * Fix JS Error. Closes [issue #699](https://github.com/Mottie/Keyboard/issues/699).
+* Readme:
+  * Fix Usability (spelling error). See [PR #694](https://github.com/Mottie/Keyboard/pull/694); thanks [@0xflotus](https://github.com/0xflotus)!
+  * Fix comboRegex (spelling error). See [PR #695](https://github.com/Mottie/Keyboard/pull/695); thanks [@0xflotus](https://github.com/0xflotus)!
+
+### Version 1.28.6 (2018-09-15)
+
+* Core:
+  * Fix tab key insertion in textarea.
+* Typing:
+  * Prevent occasional focus error.
+* Meta:
+  * Update dependencies.
+
+### Version 1.28.5 (2018-07-28)
+
+* Core:
+  * Add mousewheel throttle & key check. See [issue #665](https://github.com/Mottie/Keyboard/issues/665).
+  * Include enter when restrictInput true; fixes [issue #686](https://github.com/Mottie/Keyboard/issues/686).
+  * Reduce rebinding focus delay. See [issue #677](https://github.com/Mottie/Keyboard/issues/677).
+* Meta:
+  * Add `CHANGELOG.md` file pointing to the wiki pages. See [issue #685](https://github.com/Mottie/Keyboard/issues/685).
+  * Update dependencies.

+ 58 - 0
app/Resources/public/assets/keyboard/bower.json

@@ -0,0 +1,58 @@
+{
+  "name": "keyboard",
+  "description": "Virtual Keyboard using jQuery UI",
+  "keywords": [
+    "customizable",
+    "keyboard",
+    "ui",
+    "accessibility",
+    "osk",
+    "jquery-plugin"
+  ],
+  "authors": [
+    {
+      "name": "Jeremy Satterfield",
+      "homepage": "https://github.com/jsatt"
+    },
+    {
+      "name": "Rob Garrison",
+      "homepage": "https://mottie.github.io/Keyboard/",
+      "email": "wowmotty@gmail.com"
+    }
+  ],
+  "homepage": "https://github.com/Mottie/Keyboard",
+  "main": [
+    "dist/js/jquery.keyboard.js",
+    "css/keyboard.css"
+  ],
+  "ignore": [
+    "js/*.js",
+    "docs/*"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/Mottie/keyboard.git"
+  },
+  "license": "MIT",
+  "moduleType": [
+    "amd",
+    "globals",
+    "node"
+  ],
+  "dependencies": {
+    "jquery": ">=1.4.3",
+    "jquery-ui": ">=1.9.2"
+  },
+  "devDependencies": {
+    "grunt": "^1.0.3",
+    "grunt-cli": "^1.3.1",
+    "grunt-contrib-clean": "^2.0.0",
+    "grunt-contrib-concat": "^1.0.1",
+    "grunt-contrib-copy": "^1.0.0",
+    "grunt-contrib-cssmin": "^3.0.0",
+    "grunt-contrib-jshint": "^2.0.0",
+    "grunt-contrib-qunit": "^3.0.1",
+    "grunt-contrib-uglify": "^4.0.0",
+    "grunt-contrib-watch": "^1.1.0"
+  }
+}

+ 52 - 0
app/Resources/public/assets/keyboard/composer.json

@@ -0,0 +1,52 @@
+{
+  "name": "mottie/keyboard",
+  "description": "A jQuery on-screen keyboard (OSK) plugin that works in the browser.",
+  "homepage": "https://github.com/Mottie/Keyboard",
+  "type": "component",
+  "license": "MIT",
+  "require": {
+    "jquery": "^1.6.0"
+  },
+  "authors": [{
+    "name": "Jeremy Satterfield",
+    "url": "https://github.com/jsatt"
+  },{
+    "name": "Rob Garrison",
+    "url": "https://github.com/Mottie",
+    "email": "wowmotty@gmail.com"
+  }],
+  "keywords": [
+    "customizable",
+    "keyboard",
+    "ui",
+    "accessibility",
+    "osk",
+    "jquery-plugin"
+  ],
+  "extra": {
+    "component": {
+      "scripts": [
+        "dist/js/jquery.keyboard.js"
+      ],
+      "files": [
+        "dist/css/keyboard.min.css",
+        "dist/css/keyboard-basic.min.css",
+        "dist/css/keyboard-dark.min.css",
+        "dist/css/keyboard-previewkeyset.min.css",
+        "dist/js/jquery.keyboard.js",
+        "dist/js/jquery.keyboard.min.js",
+        "dist/js/jquery.keyboard.extension-all.min.js",
+        "dist/js/jquery.keyboard.extension-altkeyspopup.min.js",
+        "dist/js/jquery.keyboard.extension-autocomplete.min.js",
+        "dist/js/jquery.keyboard.extension-caret.min.js",
+        "dist/js/jquery.keyboard.extension-extender.min.js",
+        "dist/js/jquery.keyboard.extension-mobile.min.js",
+        "dist/js/jquery.keyboard.extension-navigation.min.js",
+        "dist/js/jquery.keyboard.extension-previewkeyset.min.js",
+        "dist/js/jquery.keyboard.extension-scramble.min.js",
+        "dist/js/jquery.keyboard.extension-typing.min.js",
+        "dist/js/jquery.mousewheel.min.js"
+      ]
+    }
+  }
+}

+ 3 - 0
app/Resources/public/assets/keyboard/css/images/disabled.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" fill="#111">
+  <path d="M7.4 4.4V2.5c0-1.4-1.1-2.5-2.5-2.5c-1.4 0-2.5 1.1-2.5 2.5v1.9 c-0.7 0-1.2 0.5-1.2 1.2v3.1C1.3 9.4 1.8 10 2.5 10h4.9c0.7 0 1.2-0.6 1.2-1.2V5.6 C8.7 4.9 8.1 4.4 7.4 4.4z M5.3 7.4v1.0c0 0.2-0.1 0.3-0.3 0.3c-0.2 0-0.3-0.1-0.3-0.3V7.4 c-0.2-0.1-0.3-0.3-0.3-0.5c0-0.3 0.3-0.6 0.6-0.6c0.3 0 0.6 0.3 0.6 0.6 C5.6 7.1 5.5 7.3 5.3 7.4z M6.2 4.4H3.7V2.5c0-0.7 0.5-1.2 1.2-1.2c0.7 0 1.2 0.6 1.2 1.2 V4.4z"/>
+</svg>

+ 3 - 0
app/Resources/public/assets/keyboard/css/images/enabled.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" fill="#111">
+  <path d="M8.7,4.4H7.5H5.0v-1.9c0-1.4-1.1-2.5-2.5-2.5c-1.4,0-2.5,1.1-2.5,2.5v1.9h1.2 v-1.9c0-0.7,0.6-1.2,1.2-1.2s1.2,0.6,1.2,1.2v1.9c-0.7,0-1.2,0.6-1.2,1.2V8.8 c0,0.7,0.6,1.2,1.2,1.2h5.0C9.4,10,10,9.4,10,8.8V5.6C10,5.0,9.4,4.4,8.8,4.4z M6.6,7.4v1.0 c0,0.2-0.1,0.3-0.3,0.3S6.0,8.6,6.0,8.4V7.4c-0.2-0.1-0.3-0.3-0.3-0.5c0-0.3,0.3-0.6,0.6-0.6 S6.9,6.6,6.9,6.9C6.9,7.1,6.8,7.3,6.6,7.4z"/>
+</svg>

+ 15 - 0
app/Resources/public/assets/keyboard/css/images/keyboard.svg

@@ -0,0 +1,15 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" style="fill:#888">
+ <g>
+  <path style="fill:none;stroke:#888" d="M 0.5,4.5 15.5,4.5 15.5,15.5 0.5,15.5 Z"></path>
+  <rect width="2" height="2" x="2" y="6"></rect>
+  <rect width="2" height="2" x="5" y="6"></rect>
+  <rect width="2" height="2" x="8" y="6"></rect>
+  <path d="m 11,6 3,0 0,5 -2,0 0,-3 -1,0 z"></path>
+  <rect width="2" height="2" x="12" y="12"></rect>
+  <rect width="6" height="2" x="5" y="12"></rect>
+  <rect width="2" height="2" x="9" y="9"></rect>
+  <rect width="2" height="2" x="6" y="9"></rect>
+  <rect width="2" height="2" x="2" y="12"></rect>
+  <rect width="3" height="2" x="2" y="9"></rect>
+ </g>
+</svg>

+ 196 - 0
app/Resources/public/assets/keyboard/css/keyboard-basic.css

@@ -0,0 +1,196 @@
+/* *** keyboard light theme ***
+  for when jQuery UI themes are not being used
+  See https://jsfiddle.net/Mottie/jsh0377k/
+ */
+.ui-keyboard {
+	/* adjust overall keyboard size using "font-size" */
+	font-size: 14px;
+	text-align: center;
+	background: #fefefe;
+	border: 1px solid #aaa;
+	padding: 4px;
+
+	/* include the following setting to place the
+	keyboard at the bottom of the browser window */
+	width: 100%;
+	height: auto;
+	left: 0px;
+	top: auto;
+	bottom: 0px;
+	position: fixed;
+	white-space: nowrap;
+	overflow-x: auto;
+	/* see issue #484 */
+	-ms-touch-action: manipulation;
+	touch-action: manipulation;
+}
+.ui-keyboard-has-focus {
+	z-index: 16001;
+}
+.ui-keyboard-button {
+	border: 1px solid #aaa;
+	padding: 0 0.5em;
+	margin: 1px;
+	min-width: 3em;
+	height: 3em;
+	line-height: 3em;
+	vertical-align: top;
+	font-family: Helvetica, Arial, sans-serif;
+	color: #333;
+	text-align: center;
+	border-radius: 5px;
+	-webkit-box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, 0.5);
+	box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, 0.5);
+	background: white;
+	background-image: -webkit-linear-gradient(-90deg, white 0%, #e3e3e3 100%);
+	background-image:         linear-gradient(-90deg, white 0%, #e3e3e3 100%);
+	cursor: pointer;
+	overflow: hidden;
+	-moz-user-focus: ignore;
+}
+.ui-keyboard-button:not([disabled]):hover {
+	background: #eee;
+	background-image: -webkit-linear-gradient(-90deg, #f2f2f2 0%, #d3d3d3 100%);
+	background-image:         linear-gradient(-90deg, #f2f2f2 0%, #d3d3d3 100%);
+}
+.ui-keyboard-button:not([disabled]):active {
+	background: #ddd;
+	background-image: -webkit-linear-gradient(-90deg, #e5e5e5 0%, #d3d3d3 100%);
+	background-image:         linear-gradient(-90deg, #e5e5e5 0%, #d3d3d3 100%);
+}
+.ui-keyboard-button span {
+	display: block;
+	width: 100%;
+	font-size: 1.2em;
+	text-align: center;
+}
+/* make action keys extra-wide */
+.ui-keyboard-actionkey:not(.ui-keyboard-dec):not(.ui-keyboard-combo) {
+	min-width: 6em;
+}
+.ui-keyboard-space {
+	width: 15em;
+}
+.ui-keyboard-actionkey:not(.ui-keyboard-dec):not(.ui-keyboard-combo) span {
+	font-size: 0.8em;
+	position: relative;
+	top: -1em;
+	left: -1.6em;
+}
+.ui-keyboard-placeholder {
+	color: #888;
+}
+/* disabled or readonly inputs, or use input[disabled='disabled'] { color: #f00; } */
+.ui-keyboard-nokeyboard {
+	color: #888;
+	border-color: #888;
+}
+.ui-keyboard-spacer {
+	display: inline-block;
+	width: 1px;
+	height: 0;
+	cursor: default;
+}
+.ui-keyboard-NBSP span, .ui-keyboard-ZWSP span, .ui-keyboard-ZWNJ span, .ui-keyboard-ZWJ span,
+.ui-keyboard-LRM span, .ui-keyboard-RLM span {
+	font-size: 0.5em;
+	line-height: 1.5em;
+	white-space: normal;
+}
+
+/* combo key styling - toggles diacritics on/off */
+.ui-keyboard-button.ui-keyboard-combo.ui-state-default {
+	-webkit-box-shadow: 1px 1px 3px 0 rgba(213, 133, 18, 0.5);
+	        box-shadow: 1px 1px 3px 0 rgba(213, 133, 18, 0.5);
+	border-color: #d58512;
+}
+.ui-keyboard-button.ui-keyboard-combo.ui-state-active {
+	-webkit-box-shadow: 1px 1px 3px 0 rgba(38, 154, 188, 0.5);
+	        box-shadow: 1px 1px 3px 0 rgba(38, 154, 188, 0.5);
+	border-color: #269abc;
+}
+/* (in)valid inputs */
+button.ui-keyboard-accept.ui-keyboard-valid-input {
+	-webkit-box-shadow: 1px 1px 3px 0 rgba(57, 132, 57, 0.5);
+	        box-shadow: 1px 1px 3px 0 rgba(57, 132, 57, 0.5);
+	border-color: #398439;
+}
+button.ui-keyboard-accept.ui-keyboard-valid-input:not([disabled]):hover {
+	border-color: #4cae4c;
+}
+button.ui-keyboard-accept.ui-keyboard-invalid-input {
+	-webkit-box-shadow: 1px 1px 3px 0 rgba(172, 41, 37, 0.5);
+	        box-shadow: 1px 1px 3px 0 rgba(172, 41, 37, 0.5);
+	border-color: #ac2925;
+}
+button.ui-keyboard-accept.ui-keyboard-invalid-input:not([disabled]):hover {
+	border-color: #d43f3a;
+}
+/* unlocked icon (keyboard enabled) */
+button.ui-keyboard-toggle span {
+	width: .9em;
+	height: .9em;
+	display: inline-block;
+	background-repeat: no-repeat;
+	background-position: center center;
+	background-size: contain;
+	/* light theme unlocked icon - fill: #111 */
+	background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iIzExMSI+PHBhdGggZD0iTTguNyw0LjRINy41SDUuMHYtMS45YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40LDAtMi41LDEuMS0yLjUsMi41djEuOWgxLjIgdi0xLjljMC0wLjcsMC42LTEuMiwxLjItMS4yczEuMiwwLjYsMS4yLDEuMnYxLjljLTAuNywwLTEuMiwwLjYtMS4yLDEuMlY4LjggYzAsMC43LDAuNiwxLjIsMS4yLDEuMmg1LjBDOS40LDEwLDEwLDkuNCwxMCw4LjhWNS42QzEwLDUuMCw5LjQsNC40LDguOCw0LjR6IE02LjYsNy40djEuMCBjMCwwLjItMC4xLDAuMy0wLjMsMC4zUzYuMCw4LjYsNi4wLDguNFY3LjRjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zLDAuMy0wLjYsMC42LTAuNiBTNi45LDYuNiw2LjksNi45QzYuOSw3LjEsNi44LDcuMyw2LjYsNy40eiIvPjwvc3ZnPg==');
+}
+/* locked icon (keyboard disabled) */
+button.ui-keyboard-toggle.ui-keyboard-disabled span {
+	/* light theme locked icon - fill: #111 */
+	background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iIzExMSI+PHBhdGggZD0iTTcuNCA0LjRWMi41YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40IDAtMi41IDEuMS0yLjUgMi41djEuOSBjLTAuNyAwLTEuMiAwLjUtMS4yIDEuMnYzLjFDMS4zIDkuNCAxLjggMTAgMi41IDEwaDQuOWMwLjcgMCAxLjItMC42IDEuMi0xLjJWNS42IEM4LjcgNC45IDguMSA0LjQgNy40IDQuNHogTTUuMyA3LjR2MS4wYzAgMC4yLTAuMSAwLjMtMC4zIDAuM2MtMC4yIDAtMC4zLTAuMS0wLjMtMC4zVjcuNCBjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zIDAuMy0wLjYgMC42LTAuNmMwLjMgMCAwLjYgMC4zIDAuNiAwLjYgQzUuNiA3LjEgNS41IDcuMyA1LjMgNy40eiBNNi4yIDQuNEgzLjdWMi41YzAtMC43IDAuNS0xLjIgMS4yLTEuMmMwLjcgMCAxLjIgMC42IDEuMiAxLjIgVjQuNHoiLz48L3N2Zz4=');
+}
+.ui-keyboard.ui-keyboard-disabled button:not(.ui-keyboard-toggle), .ui-keyboard.ui-keyboard-disabled input {
+	opacity: 0.5;
+}
+
+/*** Alt-Keys Popup extension ***/
+/* clickable overlay on top of keyboard to hide the popup */
+.ui-keyboard-overlay {
+	position: absolute;
+	top: 0;
+	left: 0;
+	bottom: 0;
+	right: 0;
+	background: rgba(238, 238, 238, 0.5);
+}
+/* the actual popup styling, class names from the css.container option are also added */
+.ui-keyboard-popup {
+	display: inline-block;
+	/* default buttons are 2em wide + .1em margin on either side (set in .ui-keyboard-button definition);
+	so use multiples of 2.2em	for a max-width if you don't want any extra white space on the sides,
+	e.g. 5 buttons * 2.2em = 11em, 6 buttons * 2.2em = 13.2em, etc */
+	max-width: 22em;
+	/* 10 buttons */
+}
+.ui-keyboard.ui-keyboard-popup-open .ui-keyboard-keyset .ui-keyboard-button {
+	/* Disable keys under overlay while popup is open - see #654 */
+	pointer-events: none;
+}
+
+/*** Caret extension definition ***/
+/* margin-top => is added to the caret height (top & bottom) */
+.ui-keyboard-caret {
+	background: #c00;
+	width: 1px;
+	margin-top: 3px;
+}
+
+/*** Extender keyboard extension ***/
+div.ui-keyboard-extender {
+	margin-left: 5px;
+	margin-right: 10px;
+}
+button.ui-keyboard-extender span {
+	width: .9em;
+	height: .9em;
+	display: inline-block;
+	margin-bottom: 3px;
+	background-repeat: no-repeat;
+	background-position: center center;
+	background-size: contain;
+	/* light theme extender icon - fill: #111 */
+	background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgc3R5bGU9ImZpbGw6IzExMSI+PGc+PHBhdGggc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzExMSIgZD0iTSAwLjUsNC41IDE1LjUsNC41IDE1LjUsMTUuNSAwLjUsMTUuNSBaIj48L3BhdGg+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iMiIgeT0iNiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjYiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSI4IiB5PSI2Ij48L3JlY3Q+PHBhdGggZD0ibSAxMSw2IDMsMCAwLDUgLTIsMCAwLC0zIC0xLDAgeiI+PC9wYXRoPjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjEyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSI2IiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjEyIj48L3JlY3Q+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iOSIgeT0iOSI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjYiIHk9IjkiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSIyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIzIiBoZWlnaHQ9IjIiIHg9IjIiIHk9IjkiPjwvcmVjdD48L2c+PC9zdmc+');
+}

+ 196 - 0
app/Resources/public/assets/keyboard/css/keyboard-dark.css

@@ -0,0 +1,196 @@
+/* *** keyboard dark theme ***
+  for when jQuery UI themes are not being used
+  See https://jsfiddle.net/Mottie/6dmqhLvh/
+ */
+.ui-keyboard {
+	/* adjust overall keyboard size using "font-size" */
+	font-size: 14px;
+	text-align: center;
+	background: #282828;
+	border: 1px solid #484848;
+	padding: 4px;
+
+	/* include the following setting to place the
+	keyboard at the bottom of the browser window */
+	width: 100%;
+	height: auto;
+	left: 0px;
+	top: auto;
+	bottom: 0px;
+	position: fixed;
+	white-space: nowrap;
+	overflow-x: auto;
+	/* see issue #484 */
+	-ms-touch-action: manipulation;
+	touch-action: manipulation;
+}
+.ui-keyboard-has-focus {
+	z-index: 16001;
+}
+.ui-keyboard-button {
+	border: 1px solid #404040;
+	padding: 0 0.5em;
+	margin: 1px;
+	min-width: 3em;
+	height: 3em;
+	line-height: 3em;
+	vertical-align: top;
+	font-family: Helvetica, Arial, sans-serif;
+	color: #eee;
+	text-align: center;
+	border-radius: 5px;
+	-webkit-box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, 0.5);
+	box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, 0.5);
+	background: #444;
+	background-image: -webkit-linear-gradient(-90deg, #444 0%, #333 100%);
+	background-image:         linear-gradient(-90deg, #444 0%, #333 100%);
+	cursor: pointer;
+	overflow: hidden;
+	-moz-user-focus: ignore;
+}
+.ui-keyboard-button:not([disabled]):hover {
+	background: #eee;
+	background-image: -webkit-linear-gradient(-90deg, #4f4f4f 0%, #444 100%);
+	background-image:         linear-gradient(-90deg, #4f4f4f 0%, #444 100%);
+}
+.ui-keyboard-button:not([disabled]):active {
+	background: #ddd;
+	background-image: -webkit-linear-gradient(-90deg, #555 0%, #5f5f5f 100%);
+	background-image:         linear-gradient(-90deg, #555 0%, #5f5f5f 100%);
+}
+.ui-keyboard-button span {
+	display: block;
+	width: 100%;
+	font-size: 1.2em;
+	text-align: center;
+}
+/* make action keys extra-wide */
+.ui-keyboard-actionkey:not(.ui-keyboard-dec):not(.ui-keyboard-combo) {
+	min-width: 6em;
+}
+.ui-keyboard-space {
+	width: 15em;
+}
+.ui-keyboard-actionkey:not(.ui-keyboard-dec):not(.ui-keyboard-combo) span {
+	font-size: 0.8em;
+	position: relative;
+	top: -1em;
+	left: -1.6em;
+}
+.ui-keyboard-placeholder {
+	color: #888;
+}
+/* disabled or readonly inputs, or use input[disabled='disabled'] { color: #f00; } */
+.ui-keyboard-nokeyboard {
+	color: #888;
+	border-color: #888;
+}
+.ui-keyboard-spacer {
+	display: inline-block;
+	width: 1px;
+	height: 0;
+	cursor: default;
+}
+.ui-keyboard-NBSP span, .ui-keyboard-ZWSP span, .ui-keyboard-ZWNJ span, .ui-keyboard-ZWJ span,
+.ui-keyboard-LRM span, .ui-keyboard-RLM span {
+	font-size: 0.5em;
+	line-height: 1.5em;
+	white-space: normal;
+}
+
+/* combo key styling - toggles diacritics on/off */
+.ui-keyboard-button.ui-keyboard-combo.ui-state-default {
+	-webkit-box-shadow: 1px 1px 3px 0 rgba(213, 133, 18, 0.5);
+	        box-shadow: 1px 1px 3px 0 rgba(213, 133, 18, 0.5);
+	border-color: #d58512;
+}
+.ui-keyboard-button.ui-keyboard-combo.ui-state-active {
+	-webkit-box-shadow: 1px 1px 3px 0 rgba(38, 154, 188, 0.5);
+	        box-shadow: 1px 1px 3px 0 rgba(38, 154, 188, 0.5);
+	border-color: #269abc;
+}
+/* (in)valid inputs */
+button.ui-keyboard-accept.ui-keyboard-valid-input {
+	-webkit-box-shadow: 1px 1px 3px 0 rgba(57, 132, 57, 0.5);
+	        box-shadow: 1px 1px 3px 0 rgba(57, 132, 57, 0.5);
+	border-color: #398439;
+}
+button.ui-keyboard-accept.ui-keyboard-valid-input:not([disabled]):hover {
+	border-color: #4cae4c;
+}
+button.ui-keyboard-accept.ui-keyboard-invalid-input {
+	-webkit-box-shadow: 1px 1px 3px 0 rgba(172, 41, 37, 0.5);
+	        box-shadow: 1px 1px 3px 0 rgba(172, 41, 37, 0.5);
+	border-color: #ac2925;
+}
+button.ui-keyboard-accept.ui-keyboard-invalid-input:not([disabled]):hover {
+	border-color: #d43f3a;
+}
+/* unlocked icon (keyboard enabled) */
+button.ui-keyboard-toggle span {
+	width: .9em;
+	height: .9em;
+	display: inline-block;
+	background-repeat: no-repeat;
+	background-position: center center;
+	background-size: contain;
+	/* dark theme unlocked icon - fill: #eee */
+	background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iI2VlZSI+PHBhdGggZD0iTTguNyw0LjRINy41SDUuMHYtMS45YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40LDAtMi41LDEuMS0yLjUsMi41djEuOWgxLjIgdi0xLjljMC0wLjcsMC42LTEuMiwxLjItMS4yczEuMiwwLjYsMS4yLDEuMnYxLjljLTAuNywwLTEuMiwwLjYtMS4yLDEuMlY4LjggYzAsMC43LDAuNiwxLjIsMS4yLDEuMmg1LjBDOS40LDEwLDEwLDkuNCwxMCw4LjhWNS42QzEwLDUuMCw5LjQsNC40LDguOCw0LjR6IE02LjYsNy40djEuMCBjMCwwLjItMC4xLDAuMy0wLjMsMC4zUzYuMCw4LjYsNi4wLDguNFY3LjRjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zLDAuMy0wLjYsMC42LTAuNiBTNi45LDYuNiw2LjksNi45QzYuOSw3LjEsNi44LDcuMyw2LjYsNy40eiIvPjwvc3ZnPg==');
+}
+/* locked icon (keyboard disabled) */
+button.ui-keyboard-toggle.ui-keyboard-disabled span {
+	/* dark theme locked icon - fill: #eee */
+	background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iI2VlZSI+PHBhdGggZD0iTTcuNCA0LjRWMi41YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40IDAtMi41IDEuMS0yLjUgMi41djEuOSBjLTAuNyAwLTEuMiAwLjUtMS4yIDEuMnYzLjFDMS4zIDkuNCAxLjggMTAgMi41IDEwaDQuOWMwLjcgMCAxLjItMC42IDEuMi0xLjJWNS42IEM4LjcgNC45IDguMSA0LjQgNy40IDQuNHogTTUuMyA3LjR2MS4wYzAgMC4yLTAuMSAwLjMtMC4zIDAuM2MtMC4yIDAtMC4zLTAuMS0wLjMtMC4zVjcuNCBjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zIDAuMy0wLjYgMC42LTAuNmMwLjMgMCAwLjYgMC4zIDAuNiAwLjYgQzUuNiA3LjEgNS41IDcuMyA1LjMgNy40eiBNNi4yIDQuNEgzLjdWMi41YzAtMC43IDAuNS0xLjIgMS4yLTEuMmMwLjcgMCAxLjIgMC42IDEuMiAxLjIgVjQuNHoiLz48L3N2Zz4=');
+}
+.ui-keyboard.ui-keyboard-disabled button:not(.ui-keyboard-toggle), .ui-keyboard.ui-keyboard-disabled input {
+	opacity: 0.5;
+}
+
+/*** Alt-Keys Popup extension ***/
+/* clickable overlay on top of keyboard to hide the popup */
+.ui-keyboard-overlay {
+	position: absolute;
+	top: 0;
+	left: 0;
+	bottom: 0;
+	right: 0;
+	background: rgba(0, 0, 0, 0.5);
+}
+/* the actual popup styling, class names from the css.container option are also added */
+.ui-keyboard-popup {
+	display: inline-block;
+	/* default buttons are 2em wide + .1em margin on either side (set in .ui-keyboard-button definition);
+	so use multiples of 2.2em	for a max-width if you don't want any extra white space on the sides,
+	e.g. 5 buttons * 2.2em = 11em, 6 buttons * 2.2em = 13.2em, etc */
+	max-width: 22em;
+	/* 10 buttons */
+}
+.ui-keyboard.ui-keyboard-popup-open .ui-keyboard-keyset .ui-keyboard-button {
+	/* Disable keys under overlay while popup is open - see #654 */
+	pointer-events: none;
+}
+
+/*** Caret extension definition ***/
+/* margin-top => is added to the caret height (top & bottom) */
+.ui-keyboard-caret {
+	background: #c00;
+	width: 1px;
+	margin-top: 3px;
+}
+
+/*** Extender keyboard extension ***/
+div.ui-keyboard-extender {
+	margin-left: 5px;
+	margin-right: 10px;
+}
+button.ui-keyboard-extender span {
+	width: .9em;
+	height: .9em;
+	display: inline-block;
+	margin-bottom: 3px;
+	background-repeat: no-repeat;
+	background-position: center center;
+	background-size: contain;
+	/* dark theme extender icon - fill: #eee */
+	background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgc3R5bGU9ImZpbGw6I2VlZSI+PGc+PHBhdGggc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6I2VlZSIgZD0iTSAwLjUsNC41IDE1LjUsNC41IDE1LjUsMTUuNSAwLjUsMTUuNSBaIj48L3BhdGg+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iMiIgeT0iNiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjYiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSI4IiB5PSI2Ij48L3JlY3Q+PHBhdGggZD0ibSAxMSw2IDMsMCAwLDUgLTIsMCAwLC0zIC0xLDAgeiI+PC9wYXRoPjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjEyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSI2IiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjEyIj48L3JlY3Q+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iOSIgeT0iOSI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjYiIHk9IjkiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSIyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIzIiBoZWlnaHQ9IjIiIHg9IjIiIHk9IjkiPjwvcmVjdD48L2c+PC9zdmc+');
+}

+ 44 - 0
app/Resources/public/assets/keyboard/css/keyboard-previewkeyset.css

@@ -0,0 +1,44 @@
+/* basic previewKeyset setup - modify as desired */
+.ui-keyboard-keyset .ui-keyboard-button {
+	position: relative;
+}
+/* show mini-shift keyset with normal keyset */
+.ui-keyboard-keyset-normal .ui-keyboard-button::after {
+	content: attr(data-shift);
+	font-size: 0.6em;
+	color: #999;
+	position: absolute;
+	top: -1em;
+	left: 2px;
+	z-index: 200;
+}
+/* show mini-normal keyset with shift keyset */
+.ui-keyboard-keyset-shift .ui-keyboard-button::after {
+	content: attr(data-normal);
+	font-size: 0.6em;
+	color: #999;
+	position: absolute;
+	top: -1em;
+	left: 2px;
+	z-index: 200;
+}
+/* show mini-normal keyset with alt keyset */
+.ui-keyboard-keyset-alt .ui-keyboard-button::after {
+	content: attr(data-alt-shift);
+	font-size: 0.6em;
+	color: #999;
+	position: absolute;
+	top: -1em;
+	left: 2px;
+	z-index: 200;
+}
+/* show mini-alt-shift keyset with alt-shift keyset */
+.ui-keyboard-keyset-alt-shift .ui-keyboard-button::after {
+	content: attr(data-alt);
+	font-size: 0.6em;
+	color: #999;
+	position: absolute;
+	top: -1em;
+	left: 2px;
+	z-index: 200;
+}

+ 337 - 0
app/Resources/public/assets/keyboard/css/keyboard.css

@@ -0,0 +1,337 @@
+/* keyboard - jQuery UI Widget */
+.ui-keyboard {
+	text-align: center;
+	padding: .3em;
+	position: absolute;
+	left: 0;
+	top: 0;
+	z-index: 16000;
+	/* see issue #484 */
+	-ms-touch-action: manipulation;
+	touch-action: manipulation;
+}
+.ui-keyboard-has-focus {
+	z-index: 16001;
+}
+.ui-keyboard div {
+	font-size: 1.1em;
+}
+.ui-keyboard[contenteditable] {
+	white-space: pre;
+}
+
+.ui-keyboard-button {
+	height: 2em;
+	min-width: 2em;
+	margin: .1em;
+	cursor: pointer;
+	overflow: hidden;
+	line-height: 2em;
+	-moz-user-focus: ignore;
+}
+.ui-keyboard-button span {
+	padding: 0;
+	margin: 0;
+	white-space: nowrap;
+	display: inline-block;
+}
+.ui-keyboard-button-endrow {
+	clear: left;
+}
+.ui-keyboard-space {
+	width: 15em;
+}
+/* see http://nicolasgallagher.com/another-css-image-replacement-technique/ */
+.ui-keyboard-space span, .ui-keyboard-empty span {
+	font: 0/0 a;
+	text-shadow: none;
+	color: transparent;
+}
+.ui-keyboard-preview-wrapper {
+	text-align: center;
+	position: relative;
+	overflow: hidden;
+}
+/* width is calculated in IE, since 99% = 99% full browser width =( */
+.ui-keyboard-preview {
+	text-align: left;
+	margin: 0 0 3px 0;
+	display: inline;
+	width: 99%;
+}
+.ui-keyboard-keyset {
+	text-align: center;
+	white-space: nowrap;
+}
+.ui-keyboard-input {
+	text-align: left;
+}
+.ui-keyboard-input-current {
+	-moz-box-shadow: 0 0 5px #4d90fe;
+	-webkit-box-shadow: 0 0 5px #4d90fe;
+	box-shadow: 0 0 5px #4d90fe;
+}
+.ui-keyboard-placeholder {
+	color: #888;
+}
+/* disabled or readonly inputs, or use
+ input[disabled='disabled'] { color: #f00; } */
+.ui-keyboard-nokeyboard {
+	color: #888;
+	border-color: #888;
+}
+.ui-keyboard-spacer {
+	display: inline-block;
+	width: 1px;
+	height: 0;
+	cursor: default;
+}
+
+.ui-keyboard-NBSP span, .ui-keyboard-ZWSP span, .ui-keyboard-ZWNJ span,
+.ui-keyboard-ZWJ span, .ui-keyboard-LRM span, .ui-keyboard-RLM span {
+	font-size: 0.5em;
+	line-height: 1.5em;
+	white-space: normal;
+}
+
+/* combo key styling - toggles diacritics on/off */
+.ui-keyboard-button.ui-keyboard-combo.ui-state-default {
+	border-color: #ffaf0f;
+}
+
+/* (in)valid inputs */
+button.ui-keyboard-accept.ui-keyboard-valid-input {
+	border-color: #0c0;
+	background: #080;
+	color: #fff;
+}
+button.ui-keyboard-accept.ui-keyboard-valid-input:not([disabled]):hover {
+	background: #0a0;
+}
+button.ui-keyboard-accept.ui-keyboard-invalid-input {
+	border-color: #c00;
+	background: #800;
+	color: #fff;
+	opacity: 0.5;
+	filter: alpha(opacity=50);
+}
+button.ui-keyboard-accept.ui-keyboard-invalid-input:not([disabled]):hover {
+	background: #a00;
+}
+
+/*** Caret extension definition ***/
+/* margin-top => is added to the caret height (top & bottom) */
+.ui-keyboard-caret {
+	background: #c00;
+	width: 1px;
+	margin-top: 3px;
+}
+
+/*** jQuery Mobile definitions ***/
+/* jQuery Mobile styles - need wider buttons because of font size and
+ text-overflow:ellipsis */
+div.ui-body.ui-keyboard button.ui-keyboard-button.ui-btn {
+	padding: 0.5em 1em;
+	border-color: transparent;
+}
+.ui-body .ui-keyboard-button {
+	width: 3em;
+	height: 3em;
+	display: inline-block;
+}
+.ui-body .ui-keyboard-widekey {
+	width: 5.5em;
+}
+.ui-body .ui-keyboard-space {
+	width: 15em;
+}
+.ui-body .ui-keyboard-space span {
+	visibility: hidden; /* hides the ellipsis */
+}
+.ui-body .ui-keyboard-keyset {
+	line-height: 0.5em;
+}
+.ui-body input.ui-input-text, .ui-body textarea.ui-input-text {
+	width: 95%;
+}
+
+/* over-ride padding set by mobile ui theme - needed because the mobile script
+ wraps button text with several more spans */
+.ui-body .ui-btn-inner {
+	height: 2em;
+	padding: 0.2em 0;
+	margin: 0;
+}
+.ui-body .ui-btn {
+	margin: 0;
+	font-size: 13px; /* mobile default size is 13px */
+}
+
+/* override Bootstrap excessive button padding */
+button.ui-keyboard-button.btn {
+	padding: 1px 6px;
+}
+
+/* enable/disable icons */
+button.ui-keyboard-toggle span {
+	width: .8em;
+	height: .8em;
+	display: inline-block;
+	background-repeat: no-repeat;
+	background-position: center center;
+	background-size: contain;
+}
+/* unlocked icon (keyboard enabled) */
+button.ui-keyboard-toggle span {
+	/* light theme unlocked icon - fill: #111 */
+	background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iIzExMSI+PHBhdGggZD0iTTguNyw0LjRINy41SDUuMHYtMS45YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40LDAtMi41LDEuMS0yLjUsMi41djEuOWgxLjIgdi0xLjljMC0wLjcsMC42LTEuMiwxLjItMS4yczEuMiwwLjYsMS4yLDEuMnYxLjljLTAuNywwLTEuMiwwLjYtMS4yLDEuMlY4LjggYzAsMC43LDAuNiwxLjIsMS4yLDEuMmg1LjBDOS40LDEwLDEwLDkuNCwxMCw4LjhWNS42QzEwLDUuMCw5LjQsNC40LDguOCw0LjR6IE02LjYsNy40djEuMCBjMCwwLjItMC4xLDAuMy0wLjMsMC4zUzYuMCw4LjYsNi4wLDguNFY3LjRjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zLDAuMy0wLjYsMC42LTAuNiBTNi45LDYuNiw2LjksNi45QzYuOSw3LjEsNi44LDcuMyw2LjYsNy40eiIvPjwvc3ZnPg==);
+}
+.ui-keyboard-dark-theme button.ui-keyboard-toggle span {
+	/* dark theme unlocked icon - fill: #eee */
+	background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iI2VlZSI+PHBhdGggZD0iTTguNyw0LjRINy41SDUuMHYtMS45YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40LDAtMi41LDEuMS0yLjUsMi41djEuOWgxLjIgdi0xLjljMC0wLjcsMC42LTEuMiwxLjItMS4yczEuMiwwLjYsMS4yLDEuMnYxLjljLTAuNywwLTEuMiwwLjYtMS4yLDEuMlY4LjggYzAsMC43LDAuNiwxLjIsMS4yLDEuMmg1LjBDOS40LDEwLDEwLDkuNCwxMCw4LjhWNS42QzEwLDUuMCw5LjQsNC40LDguOCw0LjR6IE02LjYsNy40djEuMCBjMCwwLjItMC4xLDAuMy0wLjMsMC4zUzYuMCw4LjYsNi4wLDguNFY3LjRjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zLDAuMy0wLjYsMC42LTAuNiBTNi45LDYuNiw2LjksNi45QzYuOSw3LjEsNi44LDcuMyw2LjYsNy40eiIvPjwvc3ZnPg==);
+}
+
+/* locked icon (keyboard disabled) */
+button.ui-keyboard-toggle.ui-keyboard-disabled span {
+	/* light theme locked icon - fill: #111 */
+	background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iIzExMSI+PHBhdGggZD0iTTcuNCA0LjRWMi41YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40IDAtMi41IDEuMS0yLjUgMi41djEuOSBjLTAuNyAwLTEuMiAwLjUtMS4yIDEuMnYzLjFDMS4zIDkuNCAxLjggMTAgMi41IDEwaDQuOWMwLjcgMCAxLjItMC42IDEuMi0xLjJWNS42IEM4LjcgNC45IDguMSA0LjQgNy40IDQuNHogTTUuMyA3LjR2MS4wYzAgMC4yLTAuMSAwLjMtMC4zIDAuM2MtMC4yIDAtMC4zLTAuMS0wLjMtMC4zVjcuNCBjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zIDAuMy0wLjYgMC42LTAuNmMwLjMgMCAwLjYgMC4zIDAuNiAwLjYgQzUuNiA3LjEgNS41IDcuMyA1LjMgNy40eiBNNi4yIDQuNEgzLjdWMi41YzAtMC43IDAuNS0xLjIgMS4yLTEuMmMwLjcgMCAxLjIgMC42IDEuMiAxLjIgVjQuNHoiLz48L3N2Zz4=);
+}
+.ui-keyboard-dark-theme button.ui-keyboard-toggle.ui-keyboard-disabled span {
+	/* dark theme locked icon - fill: #eee */
+	background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iI2VlZSI+PHBhdGggZD0iTTcuNCA0LjRWMi41YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40IDAtMi41IDEuMS0yLjUgMi41djEuOSBjLTAuNyAwLTEuMiAwLjUtMS4yIDEuMnYzLjFDMS4zIDkuNCAxLjggMTAgMi41IDEwaDQuOWMwLjcgMCAxLjItMC42IDEuMi0xLjJWNS42IEM4LjcgNC45IDguMSA0LjQgNy40IDQuNHogTTUuMyA3LjR2MS4wYzAgMC4yLTAuMSAwLjMtMC4zIDAuM2MtMC4yIDAtMC4zLTAuMS0wLjMtMC4zVjcuNCBjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zIDAuMy0wLjYgMC42LTAuNmMwLjMgMCAwLjYgMC4zIDAuNiAwLjYgQzUuNiA3LjEgNS41IDcuMyA1LjMgNy40eiBNNi4yIDQuNEgzLjdWMi41YzAtMC43IDAuNS0xLjIgMS4yLTEuMmMwLjcgMCAxLjIgMC42IDEuMiAxLjIgVjQuNHoiLz48L3N2Zz4=);
+}
+
+.ui-keyboard.ui-keyboard-disabled button:not(.ui-keyboard-toggle),
+.ui-keyboard.ui-keyboard-disabled input {
+	opacity: 0.5;
+}
+
+/*** Alt-Keys Popup extension ***/
+/* clickable overlay on top of keyboard to hide the popup */
+.ui-keyboard-overlay {
+	position: absolute;
+	top: 0;
+	left: 0;
+	bottom: 0;
+	right: 0;
+	background: rgba(0, 0, 0, 0.5);
+}
+/* the actual popup styling, class names from the css.container option are also
+ added */
+.ui-keyboard-popup {
+	display: inline-block;
+	/* default buttons are 2em wide + .1em margin on either side (set in
+	.ui-keyboard-button definition); so use multiples of 2.2em for a max-width
+	if you don't want any extra white space on the sides, e.g.
+	5 buttons * 2.2em = 11em,
+	6 buttons * 2.2em = 13.2em, etc
+	*/
+	max-width: 22em; /* 10 buttons */
+}
+.ui-keyboard.ui-keyboard-popup-open .ui-keyboard-keyset .ui-keyboard-button {
+	/* Disable keys under overlay while popup is open - see #654 */
+	pointer-events: none;
+}
+
+/*** Extender keyboard extension ***/
+div.ui-keyboard-extender {
+	margin-left: 5px;
+}
+button.ui-keyboard-extender span {
+	width: .9em;
+	height: .9em;
+	display: inline-block;
+	margin-bottom: 3px;
+	background-repeat: no-repeat;
+	background-position: center center;
+	background-size: contain;
+	/* light theme extender icon - fill: #111 */
+	background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgc3R5bGU9ImZpbGw6IzExMSI+PGc+PHBhdGggc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzExMSIgZD0iTSAwLjUsNC41IDE1LjUsNC41IDE1LjUsMTUuNSAwLjUsMTUuNSBaIj48L3BhdGg+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iMiIgeT0iNiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjYiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSI4IiB5PSI2Ij48L3JlY3Q+PHBhdGggZD0ibSAxMSw2IDMsMCAwLDUgLTIsMCAwLC0zIC0xLDAgeiI+PC9wYXRoPjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjEyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSI2IiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjEyIj48L3JlY3Q+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iOSIgeT0iOSI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjYiIHk9IjkiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSIyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIzIiBoZWlnaHQ9IjIiIHg9IjIiIHk9IjkiPjwvcmVjdD48L2c+PC9zdmc+);
+}
+.ui-keyboard-dark-theme button.ui-keyboard-extender span {
+	/* dark theme extender icon - fill: #eee */
+	background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgc3R5bGU9ImZpbGw6I2VlZSI+PGc+PHBhdGggc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6I2VlZSIgZD0iTSAwLjUsNC41IDE1LjUsNC41IDE1LjUsMTUuNSAwLjUsMTUuNSBaIj48L3BhdGg+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iMiIgeT0iNiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjYiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSI4IiB5PSI2Ij48L3JlY3Q+PHBhdGggZD0ibSAxMSw2IDMsMCAwLDUgLTIsMCAwLC0zIC0xLDAgeiI+PC9wYXRoPjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjEyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSI2IiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjEyIj48L3JlY3Q+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iOSIgeT0iOSI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjYiIHk9IjkiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSIyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIzIiBoZWlnaHQ9IjIiIHg9IjIiIHk9IjkiPjwvcmVjdD48L2c+PC9zdmc+);
+}
+
+/* Media Queries (optimized for jQuery UI themes;
+ may be slightly off in jQuery Mobile themes) */
+/* 240 x 320 (small phone)  */
+@media all and (max-width: 319px) {
+	.ui-keyboard div {
+		font-size: 9px;
+	}
+	.ui-keyboard .ui-keyboard-input {
+		font-size: 12px;
+	}
+	/* I don't own an iPhone so I have no idea how small this really is... is it
+	even clickable with your finger? */
+	.ui-body .ui-btn {
+		margin: 0;
+		font-size: 9px;
+	}
+	.ui-body .ui-keyboard-button {
+		width: 1.8em;
+		height: 2.5em;
+	}
+	.ui-body .ui-keyboard-widekey {
+		width: 4em;
+	}
+	.ui-body .ui-keyboard-space {
+		width: 8em;
+	}
+	.ui-body .ui-btn-inner {
+		height: 2.5em;
+		padding: 0.3em 0;
+	}
+}
+
+/* 320 x 480 (iPhone)  */
+@media all and (min-width: 320px) and (max-width: 479px) {
+	.ui-keyboard div {
+		font-size: 9px;
+	}
+	.ui-keyboard .ui-keyboard-input {
+		font-size: 14px;
+	}
+	/* I don't own an iPhone so I have no idea how small this really is... is it
+	even clickable with your finger? */
+	.ui-body .ui-btn {
+		margin: 0;
+		font-size: 11px;
+	}
+	.ui-body .ui-keyboard-button {
+		width: 1.8em;
+		height: 3em;
+	}
+	.ui-body .ui-keyboard-widekey {
+		width: 4.5em;
+	}
+	.ui-body .ui-keyboard-space {
+		width: 10em;
+	}
+	.ui-body .ui-btn-inner {
+		height: 3em;
+		padding: 0.7em 0;
+	}
+}
+
+/* 480 x 640 (small tablet) */
+@media all and (min-width: 480px) and (max-width: 767px) {
+	.ui-keyboard div {
+		font-size: 13px;
+	}
+	.ui-keyboard .ui-keyboard-input {
+		font-size: 14px;
+	}
+	.ui-body .ui-btn {
+		margin: 0;
+		font-size: 10px;
+	}
+	.ui-body .ui-keyboard-button {
+		height: 2.5em;
+	}
+	.ui-body .ui-btn-inner {
+		height: 2.5em;
+		padding: 0.5em 0;
+	}
+}

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
app/Resources/public/assets/keyboard/dist/css/keyboard-basic.min.css


Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
app/Resources/public/assets/keyboard/dist/css/keyboard-dark.min.css


+ 1 - 0
app/Resources/public/assets/keyboard/dist/css/keyboard-previewkeyset.min.css

@@ -0,0 +1 @@
+.ui-keyboard-keyset .ui-keyboard-button{position:relative}.ui-keyboard-keyset-normal .ui-keyboard-button::after{content:attr(data-shift);font-size:.6em;color:#999;position:absolute;top:-1em;left:2px;z-index:200}.ui-keyboard-keyset-shift .ui-keyboard-button::after{content:attr(data-normal);font-size:.6em;color:#999;position:absolute;top:-1em;left:2px;z-index:200}.ui-keyboard-keyset-alt .ui-keyboard-button::after{content:attr(data-alt-shift);font-size:.6em;color:#999;position:absolute;top:-1em;left:2px;z-index:200}.ui-keyboard-keyset-alt-shift .ui-keyboard-button::after{content:attr(data-alt);font-size:.6em;color:#999;position:absolute;top:-1em;left:2px;z-index:200}

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
app/Resources/public/assets/keyboard/dist/css/keyboard.min.css


Diff do ficheiro suprimidas por serem muito extensas
+ 2 - 0
app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.extension-all.min.js


Diff do ficheiro suprimidas por serem muito extensas
+ 1 - 0
app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.extension-altkeyspopup.min.js


Diff do ficheiro suprimidas por serem muito extensas
+ 1 - 0
app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.extension-autocomplete.min.js


Diff do ficheiro suprimidas por serem muito extensas
+ 1 - 0
app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.extension-caret.min.js


Diff do ficheiro suprimidas por serem muito extensas
+ 1 - 0
app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.extension-extender.min.js


Diff do ficheiro suprimidas por serem muito extensas
+ 1 - 0
app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.extension-mobile.min.js


Diff do ficheiro suprimidas por serem muito extensas
+ 1 - 0
app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.extension-navigation.min.js


+ 2 - 0
app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.extension-previewkeyset.min.js

@@ -0,0 +1,2 @@
+/*! jQuery UI Virtual Keyboard previewKeyset v1.1.1 */
+!function(e){"function"==typeof define&&define.amd?define(["jquery"],e):"object"==typeof module&&"object"==typeof module.exports?module.exports=e(require("jquery")):e(jQuery)}(function(d){"use strict";d.keyboard=d.keyboard||{},d.fn.previewKeyset=function(n){return this.each(function(){var e=d(this).data("keyboard"),t=e.namespace+"Preview";e&&(e.previewKeyset_options=d.extend({},{sets:["normal","shift","alt","alt-shift"]},n),e.extensionNamespace.push(t),e.previewKeyset=function(){var a=d.keyboard.css,r=e.previewKeyset_options.sets,s=e.$keyboard.find("."+a.keySet).filter('[name="'+r.join('"],[name="')+'"]');1<s.length&&s.eq(0).find("."+a.keyButton).not("."+a.keyAction).each(function(){var e,t,n={},i=r.length,o=s.find('button[data-pos="'+d(this).attr("data-pos")+'"]');for(e=0;e<i;e++)t=o.eq(e).parent().attr("name"),0<=d.inArray(t,r)&&(n["data-"+t]=o.eq(e).find("."+a.keyText).text());o.attr(n)})},e.options.alwaysOpen&&e.isVisible()?e.previewKeyset():e.$el.unbind(d.keyboard.events.kbBeforeVisible+t).bind(d.keyboard.events.kbBeforeVisible+t,function(){e.previewKeyset()}))})}});

Diff do ficheiro suprimidas por serem muito extensas
+ 1 - 0
app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.extension-scramble.min.js


Diff do ficheiro suprimidas por serem muito extensas
+ 1 - 0
app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.extension-typing.min.js


+ 3561 - 0
app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.js

@@ -0,0 +1,3561 @@
+/*! jQuery UI Virtual Keyboard v1.28.7 *//*
+Author: Jeremy Satterfield
+Maintained: Rob Garrison (Mottie on github)
+Licensed under the MIT License
+
+An on-screen virtual keyboard embedded within the browser window which
+will popup when a specified entry field is focused. The user can then
+type and preview their input before Accepting or Canceling.
+
+This plugin adds default class names to match jQuery UI theme styling.
+Bootstrap & custom themes may also be applied - See
+https://github.com/Mottie/Keyboard#themes
+
+Requires:
+	jQuery v1.4.3+
+	Caret plugin (included)
+Optional:
+	jQuery UI (position utility only) & CSS theme
+	jQuery mousewheel
+
+Setup/Usage:
+	Please refer to https://github.com/Mottie/Keyboard/wiki
+
+-----------------------------------------
+Caret code modified from jquery.caret.1.02.js
+Licensed under the MIT License:
+http://www.opensource.org/licenses/mit-license.php
+-----------------------------------------
+*/
+/*jshint browser:true, jquery:true, unused:false */
+/*global require:false, define:false, module:false */
+;(function (factory) {
+	if (typeof define === 'function' && define.amd) {
+		define(['jquery'], factory);
+	} else if (typeof module === 'object' && typeof module.exports === 'object') {
+		module.exports = factory(require('jquery'));
+	} else {
+		factory(jQuery);
+	}
+}(function ($) {
+	'use strict';
+	var $keyboard = $.keyboard = function (el, options) {
+	var o, base = this;
+
+	base.version = '1.28.7';
+
+	// Access to jQuery and DOM versions of element
+	base.$el = $(el);
+	base.el = el;
+
+	// Add a reverse reference to the DOM object
+	base.$el.data('keyboard', base);
+
+	base.init = function () {
+		base.initialized = false;
+		var k, position, tmp,
+			kbcss = $keyboard.css,
+			kbevents = $keyboard.events;
+		base.settings = options || {};
+		// shallow copy position to prevent performance issues; see #357
+		if (options && options.position) {
+			position = $.extend({}, options.position);
+			options.position = null;
+		}
+		base.options = o = $.extend(true, {}, $keyboard.defaultOptions, options);
+		if (position) {
+			o.position = position;
+			options.position = position;
+		}
+
+		// keyboard is active (not destroyed);
+		base.el.active = true;
+		// unique keyboard namespace
+		base.namespace = '.keyboard' + Math.random().toString(16).slice(2);
+		// extension namespaces added here (to unbind listeners on base.$el upon destroy)
+		base.extensionNamespace = [];
+		// Shift and Alt key toggles, sets is true if a layout has more than one keyset
+		// used for mousewheel message
+		base.shiftActive = base.altActive = base.metaActive = base.sets = base.capsLock = false;
+		// Class names of the basic key set - meta keysets are handled by the keyname
+		base.rows = ['', '-shift', '-alt', '-alt-shift'];
+
+		base.inPlaceholder = base.$el.attr('placeholder') || '';
+		// html 5 placeholder/watermark
+		base.watermark = $keyboard.watermark && base.inPlaceholder !== '';
+		// convert mouse repeater rate (characters per second) into a time in milliseconds.
+		base.repeatTime = 1000 / (o.repeatRate || 20);
+		// delay in ms to prevent mousedown & touchstart from both firing events at the same time
+		o.preventDoubleEventTime = o.preventDoubleEventTime || 100;
+		// flag indication that a keyboard is open
+		base.isOpen = false;
+		// is mousewheel plugin loaded?
+		base.wheel = $.isFunction($.fn.mousewheel);
+		// special character in regex that need to be escaped
+		base.escapeRegex = /[-\/\\^$*+?.()|[\]{}]/g;
+		// detect contenteditable
+		base.isContentEditable = !/(input|textarea)/i.test(base.el.nodeName) &&
+			base.el.isContentEditable;
+
+		// keyCode of keys always allowed to be typed
+		k = $keyboard.keyCodes;
+		// base.alwaysAllowed = [20,33,34,35,36,37,38,39,40,45,46];
+		base.alwaysAllowed = [
+			k.capsLock,
+			k.pageUp,
+			k.pageDown,
+			k.end,
+			k.home,
+			k.left,
+			k.up,
+			k.right,
+			k.down,
+			k.insert,
+			k.delete
+		];
+		base.$keyboard = [];
+		// keyboard enabled; set to false on destroy
+		base.enabled = true;
+
+		base.checkCaret = (o.lockInput || $keyboard.checkCaretSupport());
+
+		// disable problematic usePreview for contenteditable
+		if (base.isContentEditable) {
+			o.usePreview = false;
+		}
+
+		base.last = {
+			start: 0,
+			end: 0,
+			key: '',
+			val: '',
+			preVal: '',
+			layout: '',
+			virtual: true,
+			keyset: [false, false, false], // [shift, alt, meta]
+			wheel_$Keys: [],
+			wheelIndex: 0,
+			wheelLayers: []
+		};
+		// used when building the keyboard - [keyset element, row, index]
+		base.temp = ['', 0, 0];
+
+		// Callbacks
+		$.each([
+			kbevents.kbInit,
+			kbevents.kbBeforeVisible,
+			kbevents.kbVisible,
+			kbevents.kbHidden,
+			kbevents.inputCanceled,
+			kbevents.inputAccepted,
+			kbevents.kbBeforeClose,
+			kbevents.inputRestricted
+		], function (i, callback) {
+			if ($.isFunction(o[callback])) {
+				// bind callback functions within options to triggered events
+				base.$el.bind(callback + base.namespace + 'callbacks', o[callback]);
+			}
+		});
+
+		// Close with esc key & clicking outside
+		if (o.alwaysOpen) {
+			o.stayOpen = true;
+		}
+
+		tmp = $(document);
+		if (base.el.ownerDocument !== document) {
+			tmp = tmp.add(base.el.ownerDocument);
+		}
+
+		var bindings = 'keyup checkkeyboard mousedown touchstart ';
+		if (o.closeByClickEvent) {
+			bindings += 'click ';
+		}
+		// debounce bindings... see #542
+		tmp.bind(bindings.split(' ').join(base.namespace + ' '), function(e) {
+			clearTimeout(base.timer3);
+			base.timer3 = setTimeout(function() {
+				base.checkClose(e);
+			}, 1);
+		});
+
+		// Display keyboard on focus
+		base.$el
+			.addClass(kbcss.input + ' ' + o.css.input)
+			.attr({
+				'aria-haspopup': 'true',
+				'role': 'textbox'
+			});
+
+		// set lockInput if the element is readonly; or make the element readonly if lockInput is set
+		if (o.lockInput || base.el.readOnly) {
+			o.lockInput = true;
+			base.$el
+				.addClass(kbcss.locked)
+				.attr({
+					'readonly': 'readonly'
+				});
+		}
+		// add disabled/readonly class - dynamically updated on reveal
+		if (base.isUnavailable()) {
+			base.$el.addClass(kbcss.noKeyboard);
+		}
+		if (o.openOn) {
+			base.bindFocus();
+		}
+
+		// Add placeholder if not supported by the browser
+		if (
+			!base.watermark &&
+			base.getValue(base.$el) === '' &&
+			base.inPlaceholder !== '' &&
+			base.$el.attr('placeholder') !== ''
+		) {
+			// css watermark style (darker text)
+			base.$el.addClass(kbcss.placeholder);
+			base.setValue(base.inPlaceholder, base.$el);
+		}
+
+		base.$el.trigger(kbevents.kbInit, [base, base.el]);
+
+		// initialized with keyboard open
+		if (o.alwaysOpen) {
+			base.reveal();
+		}
+		base.initialized = true;
+	};
+
+	base.toggle = function () {
+		if (!base.hasKeyboard()) { return; }
+		var $toggle = base.$keyboard.find('.' + $keyboard.css.keyToggle),
+			locked = !base.enabled;
+		// prevent physical keyboard from working
+		base.preview.readonly = locked || base.options.lockInput;
+		// disable all buttons
+		base.$keyboard
+			.toggleClass($keyboard.css.keyDisabled, locked)
+			.find('.' + $keyboard.css.keyButton)
+			.not($toggle)
+			.attr('aria-disabled', locked)
+			.each(function() {
+				this.disabled = locked;
+			});
+		$toggle.toggleClass($keyboard.css.keyDisabled, locked);
+		// stop auto typing
+		if (locked && base.typing_options) {
+			base.typing_options.text = '';
+		}
+		// allow chaining
+		return base;
+	};
+
+	base.setCurrent = function () {
+		var kbcss = $keyboard.css,
+			// close any "isCurrent" keyboard (just in case they are always open)
+			$current = $('.' + kbcss.isCurrent),
+			kb = $current.data('keyboard');
+		// close keyboard, if not self
+		if (!$.isEmptyObject(kb) && kb.el !== base.el) {
+			kb.close(kb.options.autoAccept ? 'true' : false);
+		}
+		$current.removeClass(kbcss.isCurrent);
+		// ui-keyboard-has-focus is applied in case multiple keyboards have
+		// alwaysOpen = true and are stacked
+		$('.' + kbcss.hasFocus).removeClass(kbcss.hasFocus);
+
+		base.$el.addClass(kbcss.isCurrent);
+		base.$keyboard.addClass(kbcss.hasFocus);
+		base.isCurrent(true);
+		base.isOpen = true;
+	};
+
+	base.isUnavailable = function() {
+		return (
+			base.$el.is(':disabled') || (
+				!base.options.activeOnReadonly &&
+				base.$el.attr('readonly') &&
+				!base.$el.hasClass($keyboard.css.locked)
+			)
+		);
+	};
+
+	base.isCurrent = function (set) {
+		var cur = $keyboard.currentKeyboard || false;
+		if (set) {
+			cur = $keyboard.currentKeyboard = base.el;
+		} else if (set === false && cur === base.el) {
+			cur = $keyboard.currentKeyboard = '';
+		}
+		return cur === base.el;
+	};
+
+	base.hasKeyboard = function () {
+		return base.$keyboard && base.$keyboard.length > 0;
+	};
+
+	base.isVisible = function () {
+		return base.hasKeyboard() ? base.$keyboard.is(':visible') : false;
+	};
+
+	base.setFocus = function () {
+		var $el = base.$preview || base.$el;
+		if (!o.noFocus) {
+			$el.focus();
+		}
+		if (base.isContentEditable) {
+			$keyboard.setEditableCaret($el, base.last.start, base.last.end);
+		} else {
+			$keyboard.caret($el, base.last);
+		}
+	};
+
+	base.focusOn = function () {
+		if (!base && base.el.active) {
+			// keyboard was destroyed
+			return;
+		}
+		if (!base.isVisible()) {
+			clearTimeout(base.timer);
+			base.reveal();
+		} else {
+			// keyboard already open, make it the current keyboard
+			base.setCurrent();
+		}
+	};
+
+	// add redraw method to make API more clear
+	base.redraw = function (layout) {
+		if (layout) {
+			// allow updating the layout by calling redraw
+			base.options.layout = layout;
+		}
+		// update keyboard after a layout change
+		if (base.$keyboard.length) {
+
+			base.last.preVal = '' + base.last.val;
+			base.saveLastChange();
+			base.setValue(base.last.val, base.$el);
+
+			base.removeKeyboard();
+			base.shiftActive = base.altActive = base.metaActive = false;
+		}
+		base.isOpen = o.alwaysOpen;
+		base.reveal(true);
+		return base;
+	};
+
+	base.reveal = function (redraw) {
+		var temp,
+			alreadyOpen = base.isOpen,
+			kbcss = $keyboard.css;
+		base.opening = !alreadyOpen;
+		// remove all 'extra' keyboards by calling close function
+		$('.' + kbcss.keyboard).not('.' + kbcss.alwaysOpen).each(function(){
+			var kb = $(this).data('keyboard');
+			if (!$.isEmptyObject(kb)) {
+				// this closes previous keyboard when clicking another input - see #515
+				kb.close(kb.options.autoAccept ? 'true' : false);
+			}
+		});
+
+		// Don't open if disabled
+		if (base.isUnavailable()) {
+			return;
+		}
+		base.$el.removeClass(kbcss.noKeyboard);
+
+		// Unbind focus to prevent recursion - openOn may be empty if keyboard is opened externally
+		if (o.openOn) {
+			base.$el.unbind($.trim((o.openOn + ' ').split(/\s+/).join(base.namespace + ' ')));
+		}
+
+		// build keyboard if it doesn't exist; or attach keyboard if it was removed, but not cleared
+		if (!base.$keyboard || base.$keyboard &&
+			(!base.$keyboard.length || $.contains(base.el.ownerDocument.body, base.$keyboard[0]))) {
+			base.startup();
+		}
+
+		// clear watermark
+		if (!base.watermark && base.getValue() === base.inPlaceholder) {
+			base.$el.removeClass(kbcss.placeholder);
+			base.setValue('', base.$el);
+		}
+		// save starting content, in case we cancel
+		base.originalContent = base.isContentEditable ?
+			base.$el.html() :
+			base.getValue(base.$el);
+		if (base.el !== base.preview && !base.isContentEditable) {
+			base.setValue(base.originalContent);
+		}
+
+		// disable/enable accept button
+		if (o.acceptValid && o.checkValidOnInit) {
+			base.checkValid();
+		}
+
+		if (o.resetDefault) {
+			base.shiftActive = base.altActive = base.metaActive = false;
+		}
+		base.showSet();
+
+		// beforeVisible event
+		if (!base.isVisible()) {
+			base.$el.trigger($keyboard.events.kbBeforeVisible, [base, base.el]);
+		}
+		if (
+			base.initialized ||
+			o.initialFocus ||
+			( !o.initialFocus && base.$el.hasClass($keyboard.css.initialFocus) )
+		) {
+			base.setCurrent();
+		}
+		// update keyboard - enabled or disabled?
+		base.toggle();
+
+		// show keyboard
+		base.$keyboard.show();
+
+		// adjust keyboard preview window width - save width so IE won't keep expanding (fix issue #6)
+		if (o.usePreview && $keyboard.msie) {
+			if (typeof base.width === 'undefined') {
+				base.$preview.hide(); // preview is 100% browser width in IE7, so hide the damn thing
+				base.width = Math.ceil(base.$keyboard.width()); // set input width to match the widest keyboard row
+				base.$preview.show();
+			}
+			base.$preview.width(base.width);
+		}
+
+		base.reposition();
+
+		base.checkDecimal();
+
+		// get preview area line height
+		// add roughly 4px to get line height from font height, works well for font-sizes from 14-36px
+		// needed for textareas
+		base.lineHeight = parseInt(base.$preview.css('lineHeight'), 10) ||
+			parseInt(base.$preview.css('font-size'), 10) + 4;
+
+		if (o.caretToEnd) {
+			temp = base.isContentEditable ? $keyboard.getEditableLength(base.el) : base.originalContent.length;
+			base.saveCaret(temp, temp);
+		}
+
+		// IE caret haxx0rs
+		if ($keyboard.allie) {
+			// sometimes end = 0 while start is > 0
+			if (base.last.end === 0 && base.last.start > 0) {
+				base.last.end = base.last.start;
+			}
+			// IE will have start -1, end of 0 when not focused (see demo: https://jsfiddle.net/Mottie/fgryQ/3/)
+			if (base.last.start < 0) {
+				// ensure caret is at the end of the text (needed for IE)
+				base.last.start = base.last.end = base.originalContent.length;
+			}
+		}
+
+		if (alreadyOpen || redraw) {
+			// restore caret position (userClosed)
+			$keyboard.caret(base.$preview, base.last);
+			base.opening = false;
+			return base;
+		}
+
+		// opening keyboard flag; delay allows switching between keyboards without immediately closing
+		// the keyboard
+		base.timer2 = setTimeout(function () {
+			var undef;
+			base.opening = false;
+			// Number inputs don't support selectionStart and selectionEnd
+			// Number/email inputs don't support selectionStart and selectionEnd
+			if (!/(number|email)/i.test(base.el.type) && !o.caretToEnd) {
+				// caret position is always 0,0 in webkit; and nothing is focused at this point... odd
+				// save caret position in the input to transfer it to the preview
+				// inside delay to get correct caret position
+				base.saveCaret(undef, undef, base.$el);
+			}
+			if (o.initialFocus || base.$el.hasClass($keyboard.css.initialFocus)) {
+				$keyboard.caret(base.$preview, base.last);
+			}
+			// save event time for keyboards with stayOpen: true
+			base.last.eventTime = new Date().getTime();
+			base.$el.trigger($keyboard.events.kbVisible, [base, base.el]);
+			base.timer = setTimeout(function () {
+				// get updated caret information after visible event - fixes #331
+				if (base) { // Check if base exists, this is a case when destroy is called, before timers fire
+					base.saveCaret();
+				}
+			}, 200);
+		}, 10);
+		// return base to allow chaining in typing extension
+		return base;
+	};
+
+	base.updateLanguage = function () {
+		// change language if layout is named something like 'french-azerty-1'
+		var layouts = $keyboard.layouts,
+			lang = o.language || layouts[o.layout] && layouts[o.layout].lang &&
+				layouts[o.layout].lang || [o.language || 'en'],
+			kblang = $keyboard.language;
+
+		// some languages include a dash, e.g. 'en-gb' or 'fr-ca'
+		// allow o.language to be a string or array...
+		// array is for future expansion where a layout can be set for multiple languages
+		lang = ($.isArray(lang) ? lang[0] : lang);
+		base.language = lang;
+		lang = lang.split('-')[0];
+
+		// set keyboard language
+		o.display = $.extend(true, {},
+			kblang.en.display,
+			kblang[lang] && kblang[lang].display || {},
+			base.settings.display
+		);
+		o.combos = $.extend(true, {},
+			kblang.en.combos,
+			kblang[lang] && kblang[lang].combos || {},
+			base.settings.combos
+		);
+		o.wheelMessage = kblang[lang] && kblang[lang].wheelMessage || kblang.en.wheelMessage;
+		// rtl can be in the layout or in the language definition; defaults to false
+		o.rtl = layouts[o.layout] && layouts[o.layout].rtl || kblang[lang] && kblang[lang].rtl || false;
+
+		// save default regex (in case loading another layout changes it)
+		base.regex = kblang[lang] && kblang[lang].comboRegex || $keyboard.comboRegex;
+		// determine if US '.' or European ',' system being used
+		base.decimal = /^\./.test(o.display.dec);
+		base.$el
+			.toggleClass('rtl', o.rtl)
+			.css('direction', o.rtl ? 'rtl' : '');
+	};
+
+	base.startup = function () {
+		var kbcss = $keyboard.css;
+		// ensure base.$preview is defined; but don't overwrite it if keyboard is always visible
+		if (!((o.alwaysOpen || o.userClosed) && base.$preview)) {
+			base.makePreview();
+		}
+		if (!base.hasKeyboard()) {
+			// custom layout - create a unique layout name based on the hash
+			if (o.layout === 'custom') {
+				o.layoutHash = 'custom' + base.customHash();
+			}
+			base.layout = o.layout === 'custom' ? o.layoutHash : o.layout;
+			base.last.layout = base.layout;
+
+			base.updateLanguage();
+			if (typeof $keyboard.builtLayouts[base.layout] === 'undefined') {
+				if ($.isFunction(o.create)) {
+					// create must call buildKeyboard() function; or create it's own keyboard
+					base.$keyboard = o.create(base);
+				} else if (!base.$keyboard.length) {
+					base.buildKeyboard(base.layout, true);
+				}
+			}
+			base.$keyboard = $keyboard.builtLayouts[base.layout].$keyboard.clone();
+			base.$keyboard.data('keyboard', base);
+			if ((base.el.id || '') !== '') {
+				// add ID to keyboard for styling purposes
+				base.$keyboard.attr('id', base.el.id + $keyboard.css.idSuffix);
+			}
+
+			base.makePreview();
+		}
+
+		// Add layout and laguage data-attibutes
+		base.$keyboard
+			.attr('data-' + kbcss.keyboard + '-layout', o.layout)
+			.attr('data-' + kbcss.keyboard + '-language', base.language);
+
+		base.$decBtn = base.$keyboard.find('.' + kbcss.keyPrefix + 'dec');
+		// add enter to allowed keys; fixes #190
+		if (o.enterNavigation || base.el.nodeName === 'TEXTAREA') {
+			base.alwaysAllowed.push($keyboard.keyCodes.enter);
+		}
+
+		base.bindKeyboard();
+
+		base.$keyboard.appendTo(o.appendLocally ? base.$el.parent() : o.appendTo || 'body');
+
+		base.bindKeys();
+
+		// reposition keyboard on window resize
+		if (o.reposition && $.ui && $.ui.position && o.appendTo === 'body') {
+			$(window).bind('resize' + base.namespace, function () {
+				base.reposition();
+			});
+		}
+
+	};
+
+	base.reposition = function () {
+		base.position = $.isEmptyObject(o.position) ? false : o.position;
+		// position after keyboard is visible (required for UI position utility)
+		// and appropriately sized
+		if ($.ui && $.ui.position && base.position) {
+			base.position.of =
+				// get single target position
+				base.position.of ||
+				// OR target stored in element data (multiple targets)
+				base.$el.data('keyboardPosition') ||
+				// OR default @ element
+				base.$el;
+			base.position.collision = base.position.collision || 'flipfit flipfit';
+			base.position.at = o.usePreview ? o.position.at : o.position.at2;
+			if (base.isVisible()) {
+				base.$keyboard.position(base.position);
+			}
+		}
+		// make chainable
+		return base;
+	};
+
+	base.makePreview = function () {
+		if (o.usePreview) {
+			var indx, attrs, attr, removedAttr,
+				kbcss = $keyboard.css;
+			base.$preview = base.$el.clone(false)
+				.data('keyboard', base)
+				.removeClass(kbcss.placeholder + ' ' + kbcss.input)
+				.addClass(kbcss.preview + ' ' + o.css.input)
+				.attr('tabindex', '-1')
+				.show(); // for hidden inputs
+			base.preview = base.$preview[0];
+
+			// Switch the number input field to text so the caret positioning will work again
+			if (base.preview.type === 'number') {
+				base.preview.type = 'text';
+			}
+
+			// remove extraneous attributes.
+			removedAttr = /^(data-|id|aria-haspopup)/i;
+			attrs = base.$preview.get(0).attributes;
+			for (indx = attrs.length - 1; indx >= 0; indx--) {
+				attr = attrs[indx] && attrs[indx].name;
+				if (removedAttr.test(attr)) {
+					// remove data-attributes - see #351
+					base.preview.removeAttribute(attr);
+				}
+			}
+			// build preview container and append preview display
+			$('<div />')
+				.addClass(kbcss.wrapper)
+				.append(base.$preview)
+				.prependTo(base.$keyboard);
+		} else {
+			base.$preview = base.$el;
+			base.preview = base.el;
+		}
+	};
+
+	// Added in v1.26.8 to allow chaining of the caret function, e.g.
+	// keyboard.reveal().caret(4,5).insertText('test').caret('end');
+	base.caret = function(param1, param2) {
+		var result = $keyboard.caret(base.$preview, param1, param2),
+			wasSetCaret = result instanceof $;
+		// Caret was set, save last position & make chainable
+		if (wasSetCaret) {
+			base.saveCaret(result.start, result.end);
+			return base;
+		}
+		// return caret position if using .caret()
+		return result;
+	};
+
+	base.saveCaret = function (start, end, $el) {
+		if (base.isCurrent()) {
+			var p;
+			if (typeof start === 'undefined') {
+				// grab & save current caret position
+				p = $keyboard.caret($el || base.$preview);
+			} else {
+				p = $keyboard.caret($el || base.$preview, start, end);
+			}
+			base.last.start = typeof start === 'undefined' ? p.start : start;
+			base.last.end = typeof end === 'undefined' ? p.end : end;
+		}
+	};
+
+	base.saveLastChange = function (val) {
+		base.last.val = val || base.getValue(base.$preview || base.$el);
+		if (base.isContentEditable) {
+			base.last.elms = base.el.cloneNode(true);
+		}
+	};
+
+	base.setScroll = function () {
+		// Set scroll so caret & current text is in view
+		// needed for virtual keyboard typing, NOT manual typing - fixes #23
+		if (!base.isContentEditable && base.last.virtual) {
+
+			var scrollWidth, clientWidth, adjustment, direction,
+				isTextarea = base.preview.nodeName === 'TEXTAREA',
+				value = base.last.val.substring(0, Math.max(base.last.start, base.last.end));
+
+			if (!base.$previewCopy) {
+				// clone preview
+				base.$previewCopy = base.$preview.clone()
+					.removeAttr('id') // fixes #334
+					.css({
+						position: 'absolute',
+						left: 0,
+						zIndex: -10,
+						visibility: 'hidden'
+					})
+					.addClass($keyboard.css.inputClone);
+				// prevent submitting content on form submission
+				base.$previewCopy[0].disabled = true;
+				if (!isTextarea) {
+					// make input zero-width because we need an accurate scrollWidth
+					base.$previewCopy.css({
+						'white-space': 'pre',
+						'width': 0
+					});
+				}
+				if (o.usePreview) {
+					// add clone inside of preview wrapper
+					base.$preview.after(base.$previewCopy);
+				} else {
+					// just slap that thing in there somewhere
+					base.$keyboard.prepend(base.$previewCopy);
+				}
+			}
+
+			if (isTextarea) {
+				// need the textarea scrollHeight, so set the clone textarea height to be the line height
+				base.$previewCopy
+					.height(base.lineHeight)
+					.val(value);
+				// set scrollTop for Textarea
+				base.preview.scrollTop = base.lineHeight *
+					(Math.floor(base.$previewCopy[0].scrollHeight / base.lineHeight) - 1);
+			} else {
+				// add non-breaking spaces
+				base.$previewCopy.val(value.replace(/\s/g, '\xa0'));
+
+				// if scrollAdjustment option is set to "c" or "center" then center the caret
+				adjustment = /c/i.test(o.scrollAdjustment) ? base.preview.clientWidth / 2 : o.scrollAdjustment;
+				scrollWidth = base.$previewCopy[0].scrollWidth - 1;
+
+				// set initial state as moving right
+				if (typeof base.last.scrollWidth === 'undefined') {
+					base.last.scrollWidth = scrollWidth;
+					base.last.direction = true;
+				}
+				// if direction = true; we're scrolling to the right
+				direction = base.last.scrollWidth === scrollWidth ?
+					base.last.direction :
+					base.last.scrollWidth < scrollWidth;
+				clientWidth = base.preview.clientWidth - adjustment;
+
+				// set scrollLeft for inputs; try to mimic the inherit caret positioning + scrolling:
+				// hug right while scrolling right...
+				if (direction) {
+					if (scrollWidth < clientWidth) {
+						base.preview.scrollLeft = 0;
+					} else {
+						base.preview.scrollLeft = scrollWidth - clientWidth;
+					}
+				} else {
+					// hug left while scrolling left...
+					if (scrollWidth >= base.preview.scrollWidth - clientWidth) {
+						base.preview.scrollLeft = base.preview.scrollWidth - adjustment;
+					} else if (scrollWidth - adjustment > 0) {
+						base.preview.scrollLeft = scrollWidth - adjustment;
+					} else {
+						base.preview.scrollLeft = 0;
+					}
+				}
+
+				base.last.scrollWidth = scrollWidth;
+				base.last.direction = direction;
+			}
+		}
+	};
+
+	base.bindFocus = function () {
+		if (o.openOn) {
+			// make sure keyboard isn't destroyed
+			// Check if base exists, this is a case when destroy is called, before timers have fired
+			if (base && base.el.active) {
+				base.$el.bind(o.openOn + base.namespace, function () {
+					base.focusOn();
+				});
+				// remove focus from element (needed for IE since blur doesn't seem to work)
+				if ($(':focus')[0] === base.el) {
+					base.$el.blur();
+				}
+			}
+		}
+	};
+
+	base.bindKeyboard = function () {
+		var evt,
+			keyCodes = $keyboard.keyCodes,
+			layout = $keyboard.builtLayouts[base.layout],
+			namespace = base.namespace + 'keybindings';
+		base.$preview
+			.unbind(base.namespace)
+			.bind('click' + namespace + ' touchstart' + namespace, function () {
+				if (o.alwaysOpen && !base.isCurrent()) {
+					base.reveal();
+				}
+				// update last caret position after user click, use at least 150ms or it doesn't work in IE
+				base.timer2 = setTimeout(function () {
+					if (base){
+						base.saveCaret();
+					}
+				}, 150);
+
+			})
+			.bind('keypress' + namespace, function (e) {
+				if (o.lockInput) {
+					return false;
+				}
+				if (!base.isCurrent()) {
+					return;
+				}
+
+				var k = e.charCode || e.which,
+					// capsLock can only be checked while typing a-z
+					k1 = k >= keyCodes.A && k <= keyCodes.Z,
+					k2 = k >= keyCodes.a && k <= keyCodes.z,
+					str = base.last.key = String.fromCharCode(k);
+				// check, that keypress wasn't rise by functional key
+				// space is first typing symbol in UTF8 table
+				if (k < keyCodes.space) { //see #549
+					return;
+				}
+				base.last.virtual = false;
+				base.last.event = e;
+				base.last.$key = []; // not a virtual keyboard key
+				if (base.checkCaret) {
+					base.saveCaret();
+				}
+
+				// update capsLock
+				if (k !== keyCodes.capsLock && (k1 || k2)) {
+					base.capsLock = (k1 && !e.shiftKey) || (k2 && e.shiftKey);
+					// if shifted keyset not visible, then show it
+					if (base.capsLock && !base.shiftActive) {
+						base.shiftActive = true;
+						base.showSet();
+					}
+				}
+
+				// restrict input - keyCode in keypress special keys:
+				// see http://www.asquare.net/javascript/tests/KeyCode.html
+				if (o.restrictInput) {
+					// allow navigation keys to work - Chrome doesn't fire a keypress event (8 = bksp)
+					if ((e.which === keyCodes.backSpace || e.which === 0) &&
+						$.inArray(e.keyCode, base.alwaysAllowed)) {
+						return;
+					}
+					// quick key check
+					if ($.inArray(str, layout.acceptedKeys) === -1) {
+						e.preventDefault();
+						// copy event object in case e.preventDefault() breaks when changing the type
+						evt = $.extend({}, e);
+						evt.type = $keyboard.events.inputRestricted;
+						base.$el.trigger(evt, [base, base.el]);
+					}
+				} else if ((e.ctrlKey || e.metaKey) &&
+					(e.which === keyCodes.A || e.which === keyCodes.C || e.which === keyCodes.V ||
+						(e.which >= keyCodes.X && e.which <= keyCodes.Z))) {
+					// Allow select all (ctrl-a), copy (ctrl-c), paste (ctrl-v) & cut (ctrl-x) &
+					// redo (ctrl-y)& undo (ctrl-z); meta key for mac
+					return;
+				}
+				// Mapped Keys - allows typing on a regular keyboard and the mapped key is entered
+				// Set up a key in the layout as follows: 'm(a):label'; m = key to map, (a) = actual keyboard key
+				// to map to (optional), ':label' = title/tooltip (optional)
+				// example: \u0391 or \u0391(A) or \u0391:alpha or \u0391(A):alpha
+				if (layout.hasMappedKeys && layout.mappedKeys.hasOwnProperty(str)) {
+					base.last.key = layout.mappedKeys[str];
+					base.insertText(base.last.key);
+					e.preventDefault();
+				}
+				if (typeof o.beforeInsert === 'function') {
+					base.insertText(base.last.key);
+					e.preventDefault();
+				}
+				base.checkMaxLength();
+
+			})
+			.bind('keyup' + namespace, function (e) {
+				if (!base.isCurrent()) { return; }
+				base.last.virtual = false;
+				switch (e.which) {
+					// Insert tab key
+				case keyCodes.tab:
+					// Added a flag to prevent from tabbing into an input, keyboard opening, then adding the tab
+					// to the keyboard preview area on keyup. Sadly it still happens if you don't release the tab
+					// key immediately because keydown event auto-repeats
+					if (base.tab && !o.lockInput) {
+						base.shiftActive = e.shiftKey;
+						// when switching inputs, the tab keyaction returns false
+						var notSwitching = $keyboard.keyaction.tab(base);
+						base.tab = false;
+						if (!notSwitching) {
+							return false;
+						}
+					} else {
+						e.preventDefault();
+					}
+					break;
+
+					// Escape will hide the keyboard
+				case keyCodes.escape:
+					if (!o.ignoreEsc) {
+						base.close(o.autoAccept && o.autoAcceptOnEsc ? 'true' : false);
+					}
+					return false;
+				}
+
+				// throttle the check combo function because fast typers will have an incorrectly positioned caret
+				clearTimeout(base.throttled);
+				base.throttled = setTimeout(function () {
+					// fix error in OSX? see issue #102
+					if (base && base.isVisible()) {
+						base.checkCombos();
+					}
+				}, 100);
+
+				base.checkMaxLength();
+
+				base.last.preVal = '' + base.last.val;
+				base.saveLastChange();
+
+				// don't alter "e" or the "keyup" event never finishes processing; fixes #552
+				var event = $.Event( $keyboard.events.kbChange );
+				// base.last.key may be empty string (shift, enter, tab, etc) when keyboard is first visible
+				// use e.key instead, if browser supports it
+				event.action = base.last.key;
+				base.$el.trigger(event, [base, base.el]);
+
+				// change callback is no longer bound to the input element as the callback could be
+				// called during an external change event with all the necessary parameters (issue #157)
+				if ($.isFunction(o.change)) {
+					event.type = $keyboard.events.inputChange;
+					o.change(event, base, base.el);
+					return false;
+				}
+				if (o.acceptValid && o.autoAcceptOnValid) {
+					if (
+						$.isFunction(o.validate) &&
+						o.validate(base, base.getValue(base.$preview))
+					) {
+						base.$preview.blur();
+						base.accept();
+					}
+				}
+			})
+			.bind('keydown' + namespace, function (e) {
+				base.last.keyPress = e.which;
+				// ensure alwaysOpen keyboards are made active
+				if (o.alwaysOpen && !base.isCurrent()) {
+					base.reveal();
+				}
+				// prevent tab key from leaving the preview window
+				if (e.which === keyCodes.tab) {
+					// allow tab to pass through - tab to next input/shift-tab for prev
+					base.tab = true;
+					return false;
+				}
+				if (o.lockInput || e.timeStamp === base.last.timeStamp) {
+					return !o.lockInput;
+				}
+
+				base.last.timeStamp = e.timeStamp; // fixes #659
+				base.last.virtual = false;
+				switch (e.which) {
+
+				case keyCodes.backSpace:
+					$keyboard.keyaction.bksp(base, null, e);
+					e.preventDefault();
+					break;
+
+				case keyCodes.enter:
+					$keyboard.keyaction.enter(base, null, e);
+					break;
+
+					// Show capsLock
+				case keyCodes.capsLock:
+					base.shiftActive = base.capsLock = !base.capsLock;
+					base.showSet();
+					break;
+
+				case keyCodes.V:
+					// prevent ctrl-v/cmd-v
+					if (e.ctrlKey || e.metaKey) {
+						if (o.preventPaste) {
+							e.preventDefault();
+							return;
+						}
+						base.checkCombos(); // check pasted content
+					}
+					break;
+				}
+			})
+			.bind('mouseup touchend '.split(' ').join(namespace + ' '), function () {
+				base.last.virtual = true;
+				base.saveCaret();
+			});
+
+		// prevent keyboard event bubbling
+		base.$keyboard.bind('mousedown click touchstart '.split(' ').join(base.namespace + ' '), function (e) {
+			e.stopPropagation();
+			if (!base.isCurrent()) {
+				base.reveal();
+				$(base.el.ownerDocument).trigger('checkkeyboard' + base.namespace);
+			}
+			base.setFocus();
+		});
+
+		// If preventing paste, block context menu (right click)
+		if (o.preventPaste) {
+			base.$preview.bind('contextmenu' + base.namespace, function (e) {
+				e.preventDefault();
+			});
+			base.$el.bind('contextmenu' + base.namespace, function (e) {
+				e.preventDefault();
+			});
+		}
+
+	};
+
+	base.bindButton = function(events, handler) {
+		var button = '.' + $keyboard.css.keyButton,
+			callback = function(e) {
+				e.stopPropagation();
+				// save closest keyboard wrapper/input to check in checkClose function
+				e.$target = $(this).closest('.' + $keyboard.css.keyboard + ', .' + $keyboard.css.input);
+				handler.call(this, e);
+			};
+		if ($.fn.on) {
+			// jQuery v1.7+
+			base.$keyboard.on(events, button, callback);
+		} else if ($.fn.delegate) {
+			// jQuery v1.4.2 - 3.0.0
+			base.$keyboard.delegate(button, events, callback);
+		}
+		return base;
+	};
+
+	base.unbindButton = function(namespace) {
+		if ($.fn.off) {
+			// jQuery v1.7+
+			base.$keyboard.off(namespace);
+		} else if ($.fn.undelegate) {
+			// jQuery v1.4.2 - 3.0.0 (namespace only added in v1.6)
+			base.$keyboard.undelegate('.' + $keyboard.css.keyButton, namespace);
+		}
+		return base;
+	};
+
+	base.bindKeys = function () {
+		var kbcss = $keyboard.css;
+		base
+			.unbindButton(base.namespace + ' ' + base.namespace + 'kb')
+			// Change hover class and tooltip - moved this touchstart before option.keyBinding touchstart
+			// to prevent mousewheel lag/duplication - Fixes #379 & #411
+			.bindButton('mouseenter mouseleave touchstart '.split(' ').join(base.namespace + ' '), function (e) {
+				if ((o.alwaysOpen || o.userClosed) && e.type !== 'mouseleave' && !base.isCurrent()) {
+					base.reveal();
+					base.setFocus();
+				}
+				if (!base.isCurrent() || this.disabled) {
+					return;
+				}
+				var $keys, txt,
+					last = base.last,
+					$this = $(this),
+					type = e.type;
+
+				if (o.useWheel && base.wheel) {
+					$keys = base.getLayers($this);
+					txt = ($keys.length ? $keys.map(function () {
+							return $(this).attr('data-value') || '';
+						})
+						.get() : '') || [$this.text()];
+					last.wheel_$Keys = $keys;
+					last.wheelLayers = txt;
+					last.wheelIndex = $.inArray($this.attr('data-value'), txt);
+				}
+
+				if ((type === 'mouseenter' || type === 'touchstart') && base.el.type !== 'password' &&
+					!$this.hasClass(o.css.buttonDisabled)) {
+					$this.addClass(o.css.buttonHover);
+					if (o.useWheel && base.wheel) {
+						$this.attr('title', function (i, t) {
+							// show mouse wheel message
+							return (base.wheel && t === '' && base.sets && txt.length > 1 && type !== 'touchstart') ?
+								o.wheelMessage : t;
+						});
+					}
+				}
+				if (type === 'mouseleave') {
+					// needed or IE flickers really bad
+					$this.removeClass((base.el.type === 'password') ? '' : o.css.buttonHover);
+					if (o.useWheel && base.wheel) {
+						last.wheelIndex = 0;
+						last.wheelLayers = [];
+						last.wheel_$Keys = [];
+						$this
+							.attr('title', function (i, t) {
+								return (t === o.wheelMessage) ? '' : t;
+							})
+							.html($this.attr('data-html')); // restore original button text
+					}
+				}
+			})
+			// keyBinding = 'mousedown touchstart' by default
+			.bindButton(o.keyBinding.split(' ').join(base.namespace + ' ') + base.namespace + ' ' +
+				$keyboard.events.kbRepeater, function (e) {
+				e.preventDefault();
+				// prevent errors when external triggers attempt to 'type' - see issue #158
+				if (!base.$keyboard.is(':visible') || this.disabled) {
+					return false;
+				}
+				var action,
+					last = base.last,
+					$key = $(this),
+					// prevent mousedown & touchstart from both firing events at the same time - see #184
+					timer = new Date().getTime();
+
+				if (o.useWheel && base.wheel) {
+					// get keys from other layers/keysets (shift, alt, meta, etc) that line up by data-position
+					// target mousewheel selected key
+					$key = last.wheel_$Keys.length && last.wheelIndex > -1 ? last.wheel_$Keys.eq(last.wheelIndex) : $key;
+				}
+				action = $key.attr('data-action');
+				if (timer - (last.eventTime || 0) < o.preventDoubleEventTime) {
+					return;
+				}
+				last.eventTime = timer;
+				last.event = e;
+				last.virtual = true;
+				last.$key = $key;
+				last.key = $key.attr('data-value');
+				last.keyPress = '';
+				// Start caret in IE when not focused (happens with each virtual keyboard button click
+				base.setFocus();
+				if (/^meta/.test(action)) {
+					action = 'meta';
+				}
+				// keyaction is added as a string, override original action & text
+				if (action === last.key && typeof $keyboard.keyaction[action] === 'string') {
+					last.key = action = $keyboard.keyaction[action];
+				} else if (action in $keyboard.keyaction && $.isFunction($keyboard.keyaction[action])) {
+					// stop processing if action returns false (close & cancel)
+					if ($keyboard.keyaction[action](base, this, e) === false) {
+						return false;
+					}
+					action = null; // prevent inserting action name
+				}
+				// stop processing if keyboard closed and keyaction did not return false - see #536
+				if (!base.hasKeyboard()) {
+					return false;
+				}
+				if (typeof action !== 'undefined' && action !== null) {
+					last.key = $(this).hasClass(kbcss.keyAction) ? action : last.key;
+					base.insertText(last.key);
+					if (!base.capsLock && !o.stickyShift && !e.shiftKey) {
+						base.shiftActive = false;
+						base.showSet($key.attr('data-name'));
+					}
+				}
+				// set caret if caret moved by action function; also, attempt to fix issue #131
+				$keyboard.caret(base.$preview, last);
+				base.checkCombos();
+				e = $.extend({}, e, $.Event($keyboard.events.kbChange));
+				e.target = base.el;
+				e.action = last.key;
+				base.$el.trigger(e, [base, base.el]);
+				last.preVal = '' + last.val;
+				base.saveLastChange();
+
+				if ($.isFunction(o.change)) {
+					e.type = $keyboard.events.inputChange;
+					o.change(e, base, base.el);
+					// return false to prevent reopening keyboard if base.accept() was called
+					return false;
+				}
+
+			})
+			// using 'kb' namespace for mouse repeat functionality to keep it separate
+			// I need to trigger a 'repeater.keyboard' to make it work
+			.bindButton('mouseup' + base.namespace + ' ' + 'mouseleave touchend touchmove touchcancel '.split(' ')
+				.join(base.namespace + 'kb '), function (e) {
+				base.last.virtual = true;
+				var offset,
+					$this = $(this);
+				if (e.type === 'touchmove') {
+					// if moving within the same key, don't stop repeating
+					offset = $this.offset();
+					offset.right = offset.left + $this.outerWidth();
+					offset.bottom = offset.top + $this.outerHeight();
+					if (e.originalEvent.touches[0].pageX >= offset.left &&
+						e.originalEvent.touches[0].pageX < offset.right &&
+						e.originalEvent.touches[0].pageY >= offset.top &&
+						e.originalEvent.touches[0].pageY < offset.bottom) {
+						return true;
+					}
+				} else if (/(mouseleave|touchend|touchcancel)/i.test(e.type)) {
+					$this.removeClass(o.css.buttonHover); // needed for touch devices
+				} else {
+					if (!o.noFocus && base.isCurrent() && base.isVisible()) {
+						base.$preview.focus();
+					}
+					if (base.checkCaret) {
+						$keyboard.caret(base.$preview, base.last);
+					}
+				}
+				base.mouseRepeat = [false, ''];
+				clearTimeout(base.repeater); // make sure key repeat stops!
+				if (o.acceptValid && o.autoAcceptOnValid) {
+					if (
+						$.isFunction(o.validate) &&
+						o.validate(base, base.getValue())
+					) {
+						base.$preview.blur();
+						base.accept();
+					}
+				}
+				return false;
+			})
+			// prevent form submits when keyboard is bound locally - issue #64
+			.bindButton('click' + base.namespace, function () {
+				return false;
+			})
+			// Allow mousewheel to scroll through other keysets of the same (non-action) key
+			.bindButton('mousewheel' + base.namespace, base.throttleEvent(function (e, delta) {
+				var $btn = $(this);
+				// no mouse repeat for action keys (shift, ctrl, alt, meta, etc)
+				if (!$btn || $btn.hasClass(kbcss.keyAction) || base.last.wheel_$Keys[0] !== this) {
+					return;
+				}
+				if (o.useWheel && base.wheel) {
+					// deltaY used by newer versions of mousewheel plugin
+					delta = delta || e.deltaY;
+					var n,
+						txt = base.last.wheelLayers || [];
+					if (txt.length > 1) {
+						n = base.last.wheelIndex + (delta > 0 ? -1 : 1);
+						if (n > txt.length - 1) {
+							n = 0;
+						}
+						if (n < 0) {
+							n = txt.length - 1;
+						}
+					} else {
+						n = 0;
+					}
+					base.last.wheelIndex = n;
+					$btn.html(txt[n]);
+					return false;
+				}
+			}, 30))
+			.bindButton('mousedown touchstart '.split(' ').join(base.namespace + 'kb '), function () {
+				var $btn = $(this);
+				// no mouse repeat for action keys (shift, ctrl, alt, meta, etc)
+				if (
+					!$btn || (
+						$btn.hasClass(kbcss.keyAction) &&
+						// mouse repeated action key exceptions
+						!$btn.is('.' + kbcss.keyPrefix + ('tab bksp space enter'.split(' ').join(',.' + kbcss.keyPrefix)))
+					)
+				) {
+					return;
+				}
+				if (o.repeatRate !== 0) {
+					// save the key, make sure we are repeating the right one (fast typers)
+					base.mouseRepeat = [true, $btn];
+					setTimeout(function () {
+						// don't repeat keys if it is disabled - see #431
+						if (base && base.mouseRepeat[0] && base.mouseRepeat[1] === $btn && !$btn[0].disabled) {
+							base.repeatKey($btn);
+						}
+					}, o.repeatDelay);
+				}
+				return false;
+			});
+	};
+
+	// No call on tailing event
+	base.throttleEvent = function(cb, time) {
+		var interm;
+		return function() {
+			if (!interm) {
+				cb.apply(this, arguments);
+				interm = true;
+				setTimeout(function() {
+					interm = false;
+				}, time);
+			}
+		};
+	};
+
+	base.execCommand = function(cmd, str) {
+		base.el.ownerDocument.execCommand(cmd, false, str);
+		base.el.normalize();
+		if (o.reposition) {
+			base.reposition();
+		}
+	};
+
+	base.getValue = function ($el) {
+		$el = $el || base.$preview;
+		return $el[base.isContentEditable ? 'text' : 'val']();
+	};
+
+	base.setValue = function (txt, $el) {
+		$el = $el || base.$preview;
+		if (base.isContentEditable) {
+			if (txt !== $el.text()) {
+				$keyboard.replaceContent($el, txt);
+				base.saveCaret();
+			}
+		} else {
+			$el.val(txt);
+		}
+		return base;
+	};
+
+	// Insert text at caret/selection - thanks to Derek Wickwire for fixing this up!
+	base.insertText = function (txt) {
+		if (!base.$preview) { return base; }
+		if (typeof o.beforeInsert === 'function') {
+			txt = o.beforeInsert(base.last.event, base, base.el, txt);
+		}
+		if (typeof txt === 'undefined' || txt === false) {
+			base.last.key = '';
+			return base;
+		}
+		if (base.isContentEditable) {
+			return base.insertContentEditable(txt);
+		}
+		var t,
+			bksp = false,
+			isBksp = txt === '\b',
+			// use base.$preview.val() instead of base.preview.value (val.length includes carriage returns in IE).
+			val = base.getValue(),
+			pos = $keyboard.caret(base.$preview),
+			len = val.length; // save original content length
+
+		// silly IE caret hacks... it should work correctly, but navigating using arrow keys in a textarea
+		// is still difficult
+		// in IE, pos.end can be zero after input loses focus
+		if (pos.end < pos.start) {
+			pos.end = pos.start;
+		}
+		if (pos.start > len) {
+			pos.end = pos.start = len;
+		}
+
+		if (base.preview.nodeName === 'TEXTAREA') {
+			// This makes sure the caret moves to the next line after clicking on enter (manual typing works fine)
+			if ($keyboard.msie && val.substr(pos.start, 1) === '\n') {
+				pos.start += 1;
+				pos.end += 1;
+			}
+		}
+
+		t = pos.start;
+		if (txt === '{d}') {
+			txt = '';
+			pos.end += 1;
+		}
+
+		if (isBksp) {
+			txt = '';
+			bksp = isBksp && t === pos.end && t > 0;
+		}
+		val = val.substr(0, t - (bksp ? 1 : 0)) + txt + val.substr(pos.end);
+		t += bksp ? -1 : txt.length;
+
+		base.setValue(val);
+		base.saveCaret(t, t); // save caret in case of bksp
+		base.setScroll();
+		// see #506.. allow chaining of insertText
+		return base;
+	};
+
+	base.insertContentEditable = function (txt) {
+		base.$preview.focus();
+		base.execCommand('insertText', txt);
+		base.saveCaret();
+		return base;
+	};
+
+	// check max length
+	base.checkMaxLength = function () {
+		if (!base.$preview) { return; }
+		var start, caret,
+			val = base.getValue(),
+			len = base.isContentEditable ? $keyboard.getEditableLength(base.el) : val.length;
+		if (o.maxLength !== false && len > o.maxLength) {
+			start = $keyboard.caret(base.$preview).start;
+			caret = Math.min(start, o.maxLength);
+
+			// prevent inserting new characters when maxed #289
+			if (!o.maxInsert) {
+				val = base.last.val;
+				caret = start - 1; // move caret back one
+			}
+			base.setValue(val.substring(0, o.maxLength));
+			// restore caret on change, otherwise it ends up at the end.
+			base.saveCaret(caret, caret);
+		}
+		if (base.$decBtn.length) {
+			base.checkDecimal();
+		}
+		// allow chaining
+		return base;
+	};
+
+	// mousedown repeater
+	base.repeatKey = function (key) {
+		key.trigger($keyboard.events.kbRepeater);
+		if (base.mouseRepeat[0]) {
+			base.repeater = setTimeout(function () {
+				if (base){
+					base.repeatKey(key);
+				}
+			}, base.repeatTime);
+		}
+	};
+
+	base.getKeySet = function () {
+		var sets = [];
+		if (base.altActive) {
+			sets.push('alt');
+		}
+		if (base.shiftActive) {
+			sets.push('shift');
+		}
+		if (base.metaActive) {
+			// base.metaActive contains the string name of the
+			// current meta keyset
+			sets.push(base.metaActive);
+		}
+		return sets.length ? sets.join('+') : 'normal';
+	};
+
+	// make it easier to switch keysets via API
+	// showKeySet('shift+alt+meta1')
+	base.showKeySet = function (str) {
+		if (typeof str === 'string') {
+			base.last.keyset = [base.shiftActive, base.altActive, base.metaActive];
+			base.shiftActive = /shift/i.test(str);
+			base.altActive = /alt/i.test(str);
+			if (/\bmeta/.test(str)) {
+				base.metaActive = true;
+				base.showSet(str.match(/\bmeta[\w-]+/i)[0]);
+			} else {
+				base.metaActive = false;
+				base.showSet();
+			}
+		} else {
+			base.showSet(str);
+		}
+		// allow chaining
+		return base;
+	};
+
+	base.showSet = function (name) {
+		if (!base.hasKeyboard()) { return; }
+		o = base.options; // refresh options
+		var kbcss = $keyboard.css,
+			prefix = '.' + kbcss.keyPrefix,
+			active = o.css.buttonActive,
+			key = '',
+			toShow = (base.shiftActive ? 1 : 0) + (base.altActive ? 2 : 0);
+		if (!base.shiftActive) {
+			base.capsLock = false;
+		}
+		// check meta key set
+		if (base.metaActive) {
+			// remove "-shift" and "-alt" from meta name if it exists
+			if (base.shiftActive) {
+				name = (name || '').replace('-shift', '');
+			}
+			if (base.altActive) {
+				name = (name || '').replace('-alt', '');
+			}
+			// the name attribute contains the meta set name 'meta99'
+			key = (/^meta/i.test(name)) ? name : '';
+			// save active meta keyset name
+			if (key === '') {
+				key = (base.metaActive === true) ? '' : base.metaActive;
+			} else {
+				base.metaActive = key;
+			}
+			// if meta keyset doesn't have a shift or alt keyset, then show just the meta key set
+			if ((!o.stickyShift && base.last.keyset[2] !== base.metaActive) ||
+				((base.shiftActive || base.altActive) &&
+				!base.$keyboard.find('.' + kbcss.keySet + '-' + key + base.rows[toShow]).length)) {
+				base.shiftActive = base.altActive = false;
+			}
+		} else if (!o.stickyShift && base.last.keyset[2] !== base.metaActive && base.shiftActive) {
+			// switching from meta key set back to default, reset shift & alt if using stickyShift
+			base.shiftActive = base.altActive = false;
+		}
+		toShow = (base.shiftActive ? 1 : 0) + (base.altActive ? 2 : 0);
+		key = (toShow === 0 && !base.metaActive) ? '-normal' : (key === '') ? '' : '-' + key;
+		if (!base.$keyboard.find('.' + kbcss.keySet + key + base.rows[toShow]).length) {
+			// keyset doesn't exist, so restore last keyset settings
+			base.shiftActive = base.last.keyset[0];
+			base.altActive = base.last.keyset[1];
+			base.metaActive = base.last.keyset[2];
+			return;
+		}
+		base.$keyboard
+			.find(prefix + 'alt,' + prefix + 'shift,.' + kbcss.keyAction + '[class*=meta]')
+			.removeClass(active)
+			.end()
+			.find(prefix + 'alt')
+			.toggleClass(active, base.altActive)
+			.end()
+			.find(prefix + 'shift')
+			.toggleClass(active, base.shiftActive)
+			.end()
+			.find(prefix + 'lock')
+			.toggleClass(active, base.capsLock)
+			.end()
+			.find('.' + kbcss.keySet)
+			.hide()
+			.end()
+			.find('.' + (kbcss.keyAction + prefix + key).replace('--', '-'))
+			.addClass(active);
+
+		// show keyset using inline-block ( extender layout will then line up )
+		base.$keyboard.find('.' + kbcss.keySet + key + base.rows[toShow])[0].style.display = 'inline-block';
+		if (base.metaActive) {
+			base.$keyboard.find(prefix + base.metaActive)
+				// base.metaActive contains the string "meta#" or false
+				// without the !== false, jQuery UI tries to transition the classes
+				.toggleClass(active, base.metaActive !== false);
+		}
+		base.last.keyset = [base.shiftActive, base.altActive, base.metaActive];
+		base.$el.trigger($keyboard.events.kbKeysetChange, [base, base.el]);
+		if (o.reposition) {
+			base.reposition();
+		}
+	};
+
+	// check for key combos (dead keys)
+	base.checkCombos = function () {
+		// return val for close function
+		if ( !(
+			base.isVisible() || (
+				base.hasKeyboard() &&
+				base.$keyboard.hasClass( $keyboard.css.hasFocus )
+			)
+		) ) {
+			return base.getValue(base.$preview || base.$el);
+		}
+		var r, t, t2, repl,
+			// use base.$preview.val() instead of base.preview.value
+			// (val.length includes carriage returns in IE).
+			val = base.getValue(),
+			pos = $keyboard.caret(base.$preview),
+			layout = $keyboard.builtLayouts[base.layout],
+			max = base.isContentEditable ? $keyboard.getEditableLength(base.el) : val.length,
+			// save original content length
+			len = max;
+		// return if val is empty; fixes #352
+		if (val === '') {
+			// check valid on empty string - see #429
+			if (o.acceptValid) {
+				base.checkValid();
+			}
+			return val;
+		}
+
+		// silly IE caret hacks... it should work correctly, but navigating using arrow keys in a textarea
+		// is still difficult
+		// in IE, pos.end can be zero after input loses focus
+		if (pos.end < pos.start) {
+			pos.end = pos.start;
+		}
+		if (pos.start > len) {
+			pos.end = pos.start = len;
+		}
+		// This makes sure the caret moves to the next line after clicking on enter (manual typing works fine)
+		if ($keyboard.msie && val.substr(pos.start, 1) === '\n') {
+			pos.start += 1;
+			pos.end += 1;
+		}
+
+		if (o.useCombos) {
+			// keep 'a' and 'o' in the regex for ae and oe ligature (æ,œ)
+			// thanks to KennyTM: http://stackoverflow.com/q/4275077
+			// original regex /([`\'~\^\"ao])([a-z])/mig moved to $.keyboard.comboRegex
+			if ($keyboard.msie) {
+				// old IE may not have the caret positioned correctly, so just check the whole thing
+				val = val.replace(base.regex, function (s, accent, letter) {
+					return (o.combos.hasOwnProperty(accent)) ? o.combos[accent][letter] || s : s;
+				});
+				// prevent combo replace error, in case the keyboard closes - see issue #116
+			} else if (base.$preview.length) {
+				// Modern browsers - check for combos from last two characters left of the caret
+				t = pos.start - (pos.start - 2 >= 0 ? 2 : 0);
+				// target last two characters
+				$keyboard.caret(base.$preview, t, pos.end);
+				// do combo replace
+				t = $keyboard.caret(base.$preview);
+				repl = function (txt) {
+					return (txt || '').replace(base.regex, function (s, accent, letter) {
+						return (o.combos.hasOwnProperty(accent)) ? o.combos[accent][letter] || s : s;
+					});
+				};
+				t2 = repl(t.text);
+				// add combo back
+				// prevent error if caret doesn't return a function
+				if (t && t.replaceStr && t2 !== t.text) {
+					if (base.isContentEditable) {
+						$keyboard.replaceContent(el, repl);
+					} else {
+						base.setValue(t.replaceStr(t2));
+					}
+				}
+				val = base.getValue();
+			}
+		}
+
+		// check input restrictions - in case content was pasted
+		if (o.restrictInput && val !== '') {
+			t = layout.acceptedKeys.length;
+
+			r = layout.acceptedKeysRegex;
+			if (!r) {
+				t2 = $.map(layout.acceptedKeys, function (v) {
+					// escape any special characters
+					return v.replace(base.escapeRegex, '\\$&');
+				});
+				if (base.alwaysAllowed.indexOf($keyboard.keyCodes.enter) > -1) {
+					t2.push('\\n'); // Fixes #686
+				}
+				r = layout.acceptedKeysRegex = new RegExp('(' + t2.join('|') + ')', 'g');
+			}
+			// only save matching keys
+			t2 = val.match(r);
+			if (t2) {
+				val = t2.join('');
+			} else {
+				// no valid characters
+				val = '';
+				len = 0;
+			}
+		}
+
+		// save changes, then reposition caret
+		pos.start += max - len;
+		pos.end += max - len;
+
+		base.setValue(val);
+		base.saveCaret(pos.start, pos.end);
+		// set scroll to keep caret in view
+		base.setScroll();
+		base.checkMaxLength();
+
+		if (o.acceptValid) {
+			base.checkValid();
+		}
+		return val; // return text, used for keyboard closing section
+	};
+
+	// Toggle accept button classes, if validating
+	base.checkValid = function () {
+		var kbcss = $keyboard.css,
+			$accept = base.$keyboard.find('.' + kbcss.keyPrefix + 'accept'),
+			valid = true;
+		if ($.isFunction(o.validate)) {
+			valid = o.validate(base, base.getValue(), false);
+		}
+		// toggle accept button classes; defined in the css
+		$accept
+			.toggleClass(kbcss.inputInvalid, !valid)
+			.toggleClass(kbcss.inputValid, valid)
+			// update title to indicate that the entry is valid or invalid
+			.attr('title', $accept.attr('data-title') + ' (' + o.display[valid ? 'valid' : 'invalid'] + ')');
+	};
+
+	// Decimal button for num pad - only allow one (not used by default)
+	base.checkDecimal = function () {
+		// Check US '.' or European ',' format
+		if ((base.decimal && /\./g.test(base.preview.value)) ||
+			(!base.decimal && /\,/g.test(base.preview.value))) {
+			base.$decBtn
+				.attr({
+					'disabled': 'disabled',
+					'aria-disabled': 'true'
+				})
+				.removeClass(o.css.buttonHover)
+				.addClass(o.css.buttonDisabled);
+		} else {
+			base.$decBtn
+				.removeAttr('disabled')
+				.attr({
+					'aria-disabled': 'false'
+				})
+				.addClass(o.css.buttonDefault)
+				.removeClass(o.css.buttonDisabled);
+		}
+	};
+
+	// get other layer values for a specific key
+	base.getLayers = function ($el) {
+		var kbcss = $keyboard.css,
+			key = $el.attr('data-pos'),
+			$keys = $el.closest('.' + kbcss.keyboard)
+			.find('button[data-pos="' + key + '"]');
+		return $keys.filter(function () {
+			return $(this)
+				.find('.' + kbcss.keyText)
+				.text() !== '';
+		})
+		.add($el);
+	};
+
+	// Go to next or prev inputs
+	// goToNext = true, then go to next input; if false go to prev
+	// isAccepted is from autoAccept option or true if user presses shift+enter
+	base.switchInput = function (goToNext, isAccepted) {
+		if ($.isFunction(o.switchInput)) {
+			o.switchInput(base, goToNext, isAccepted);
+		} else {
+			// base.$keyboard may be an empty array - see #275 (apod42)
+			if (base.$keyboard.length) {
+				base.$keyboard.hide();
+			}
+			var kb,
+				stopped = false,
+				all = $('button, input, select, textarea, a, [contenteditable]')
+					.filter(':visible')
+					.not(':disabled'),
+				indx = all.index(base.$el) + (goToNext ? 1 : -1);
+			if (base.$keyboard.length) {
+				base.$keyboard.show();
+			}
+			if (indx > all.length - 1) {
+				stopped = o.stopAtEnd;
+				indx = 0; // go to first input
+			}
+			if (indx < 0) {
+				stopped = o.stopAtEnd;
+				indx = all.length - 1; // stop or go to last
+			}
+			if (!stopped) {
+				isAccepted = base.close(isAccepted);
+				if (!isAccepted) {
+					return;
+				}
+				kb = all.eq(indx).data('keyboard');
+				if (kb && kb.options.openOn.length) {
+					kb.focusOn();
+				} else {
+					all.eq(indx).focus();
+				}
+			}
+		}
+		return false;
+	};
+
+	// Close the keyboard, if visible. Pass a status of true, if the content was accepted
+	// (for the event trigger).
+	base.close = function (accepted) {
+		if (base.isOpen && base.$keyboard.length) {
+			clearTimeout(base.throttled);
+			var kbcss = $keyboard.css,
+				kbevents = $keyboard.events,
+				val = accepted ? base.checkCombos() : base.originalContent;
+			// validate input if accepted
+			if (accepted && $.isFunction(o.validate) && !o.validate(base, val, true)) {
+				val = base.originalContent;
+				accepted = false;
+				if (o.cancelClose) {
+					return;
+				}
+			}
+			base.isCurrent(false);
+			base.isOpen = o.alwaysOpen || o.userClosed;
+			if (base.isContentEditable && !accepted) {
+				// base.originalContent stores the HTML
+				base.$el.html(val);
+			} else {
+				base.setValue(val, base.$el);
+			}
+			base.$el
+				.removeClass(kbcss.isCurrent + ' ' + kbcss.inputAutoAccepted)
+				// add 'ui-keyboard-autoaccepted' to inputs - see issue #66
+				.addClass((accepted || false) ? accepted === true ? '' : kbcss.inputAutoAccepted : '')
+				// trigger default change event - see issue #146
+				.trigger(kbevents.inputChange);
+			// don't trigger an empty event - see issue #463
+			if (!o.alwaysOpen) {
+				// don't trigger beforeClose if keyboard is always open
+				base.$el.trigger(kbevents.kbBeforeClose, [base, base.el, (accepted || false)]);
+			}
+			// save caret after updating value (fixes userClosed issue with changing focus)
+			$keyboard.caret(base.$preview, base.last);
+
+			base.$el
+				.trigger(((accepted || false) ? kbevents.inputAccepted : kbevents.inputCanceled), [base, base.el])
+				.trigger((o.alwaysOpen) ? kbevents.kbInactive : kbevents.kbHidden, [base, base.el])
+				.blur();
+
+			// base is undefined if keyboard was destroyed - fixes #358
+			if (base) {
+				// add close event time
+				base.last.eventTime = new Date().getTime();
+				if (!(o.alwaysOpen || o.userClosed && accepted === 'true') && base.$keyboard.length) {
+					// free up memory
+					base.removeKeyboard();
+					// rebind input focus - delayed to fix IE issue #72
+					base.timer = setTimeout(function () {
+						if (base) {
+							base.bindFocus();
+						}
+					}, 200);
+				}
+				if (!base.watermark && base.el.value === '' && base.inPlaceholder !== '') {
+					base.$el.addClass(kbcss.placeholder);
+					base.setValue(base.inPlaceholder, base.$el);
+				}
+			}
+		}
+		return !!accepted;
+	};
+
+	base.accept = function () {
+		return base.close(true);
+	};
+
+	base.checkClose = function (e) {
+		if (base.opening) {
+			return;
+		}
+		var kbcss = $.keyboard.css,
+			$target = e.$target || $(e.target).closest('.' + $keyboard.css.keyboard + ', .' + $keyboard.css.input);
+		if (!$target.length) {
+			$target = $(e.target);
+		}
+		// needed for IE to allow switching between keyboards smoothly
+		if ($target.length && $target.hasClass(kbcss.keyboard)) {
+			var kb = $target.data('keyboard');
+			// only trigger on self
+			if (
+				kb !== base &&
+				!kb.$el.hasClass(kbcss.isCurrent) &&
+				kb.options.openOn &&
+				e.type === o.openOn
+			) {
+				kb.focusOn();
+			}
+		} else {
+			base.escClose(e, $target);
+		}
+	};
+
+	// callback functions called to check if the keyboard needs to be closed
+	// e.g. on escape or clicking outside the keyboard
+	base.escCloseCallback = {
+		// keep keyboard open if alwaysOpen or stayOpen is true - fixes mutliple
+		// always open keyboards or single stay open keyboard
+		keepOpen: function() {
+			return !base.isOpen;
+		}
+	};
+
+	base.escClose = function (e, $el) {
+		if (!base.isOpen) {
+			return;
+		}
+		if (e && e.type === 'keyup') {
+			return (e.which === $keyboard.keyCodes.escape && !o.ignoreEsc) ?
+				base.close(o.autoAccept && o.autoAcceptOnEsc ? 'true' : false) :
+				'';
+		}
+		var shouldStayOpen = false,
+			$target = $el.length && $el || $(e.target);
+		$.each(base.escCloseCallback, function(i, callback) {
+			if (typeof callback === 'function') {
+				shouldStayOpen = shouldStayOpen || callback($target);
+			}
+		});
+		if (shouldStayOpen) {
+			return;
+		}
+		// ignore autoaccept if using escape - good idea?
+		if (!base.isCurrent() && base.isOpen || base.isOpen && $target[0] !== base.el) {
+			// don't close if stayOpen is set; but close if a different keyboard is being opened
+			if ((o.stayOpen || o.userClosed) && !$target.hasClass($keyboard.css.input)) {
+				return;
+			}
+			// stop propogation in IE - an input getting focus doesn't open a keyboard if one is already open
+			if ($keyboard.allie) {
+				e.preventDefault();
+			}
+			if (o.closeByClickEvent) {
+				// only close the keyboard if the user is clicking on an input or if they cause a click
+				// event (touchstart/mousedown will not force the close with this setting)
+				var name = $target[0] && $target[0].nodeName.toLowerCase();
+				if (name === 'input' || name === 'textarea' || e.type === 'click') {
+					base.close(o.autoAccept ? 'true' : false);
+				}
+			} else {
+				// send 'true' instead of a true (boolean), the input won't get a 'ui-keyboard-autoaccepted'
+				// class name - see issue #66
+				base.close(o.autoAccept ? 'true' : false);
+			}
+		}
+	};
+
+	// Build default button
+	base.keyBtn = $('<button />')
+		.attr({
+			'role': 'button',
+			'type': 'button',
+			'aria-disabled': 'false',
+			'tabindex': '-1'
+		})
+		.addClass($keyboard.css.keyButton);
+
+	// convert key names into a class name
+	base.processName = function (name) {
+		var index, n,
+			process = (name || '').replace(/[^a-z0-9-_]/gi, ''),
+			len = process.length,
+			newName = [];
+		if (len > 1 && name === process) {
+			// return name if basic text
+			return name;
+		}
+		// return character code sequence
+		len = name.length;
+		if (len) {
+			for (index = 0; index < len; index++) {
+				n = name[index];
+				// keep '-' and '_'... so for dash, we get two dashes in a row
+				newName.push(/[a-z0-9-_]/i.test(n) ?
+					(/[-_]/.test(n) && index !== 0 ? '' : n) :
+					(index === 0 ? '' : '-') + n.charCodeAt(0)
+				);
+			}
+			return newName.join('');
+		}
+		return name;
+	};
+
+	base.processKeys = function (name) {
+		var tmp,
+			// Don't split colons followed by //, e.g. https://; Fixes #555
+			parts = name.split(/:(?!\/\/)/),
+			data = {
+				name: null,
+				map: '',
+				title: ''
+			};
+		/* map defined keys
+		format 'key(A):Label_for_key_(ignore_parentheses_here)'
+			'key' = key that is seen (can any character(s); but it might need to be escaped using '\'
+			or entered as unicode '\u####'
+			'(A)' = the actual key on the real keyboard to remap
+			':Label_for_key' ends up in the title/tooltip
+		Examples:
+			'\u0391(A):alpha', 'x(y):this_(might)_cause_problems
+			or edge cases of ':(x)', 'x(:)', 'x(()' or 'x())'
+		Enhancement (if I can get alt keys to work):
+			A mapped key will include the mod key, e.g. 'x(alt-x)' or 'x(alt-shift-x)'
+		*/
+		if (/\(.+\)/.test(parts[0]) || /^:\(.+\)/.test(name) || /\([(:)]\)/.test(name)) {
+			// edge cases 'x(:)', 'x(()' or 'x())'
+			if (/\([(:)]\)/.test(name)) {
+				tmp = parts[0].match(/([^(]+)\((.+)\)/);
+				if (tmp && tmp.length) {
+					data.name = tmp[1];
+					data.map = tmp[2];
+					data.title = parts.length > 1 ? parts.slice(1).join(':') : '';
+				} else {
+					// edge cases 'x(:)', ':(x)' or ':(:)'
+					data.name = name.match(/([^(]+)/)[0];
+					if (data.name === ':') {
+						// ':(:):test' => parts = [ '', '(', ')', 'title' ] need to slice 1
+						parts = parts.slice(1);
+					}
+					if (tmp === null) {
+						// 'x(:):test' => parts = [ 'x(', ')', 'title' ] need to slice 2
+						data.map = ':';
+						parts = parts.slice(2);
+					}
+					data.title = parts.length ? parts.join(':') : '';
+				}
+			} else {
+				// example: \u0391(A):alpha; extract 'A' from '(A)'
+				data.map = name.match(/\(([^()]+?)\)/)[1];
+				// remove '(A)', left with '\u0391:alpha'
+				name = name.replace(/\(([^()]+)\)/, '');
+				tmp = name.split(':');
+				// get '\u0391' from '\u0391:alpha'
+				if (tmp[0] === '') {
+					data.name = ':';
+					parts = parts.slice(1);
+				} else {
+					data.name = tmp[0];
+				}
+				data.title = parts.length > 1 ? parts.slice(1).join(':') : '';
+			}
+		} else {
+			// find key label
+			// corner case of '::;' reduced to ':;', split as ['', ';']
+			if (name !== '' && parts[0] === '') {
+				data.name = ':';
+				parts = parts.slice(1);
+			} else {
+				data.name = parts[0];
+			}
+			data.title = parts.length > 1 ? parts.slice(1).join(':') : '';
+		}
+		data.title = $.trim(data.title).replace(/_/g, ' ');
+		return data;
+	};
+
+	// Add key function
+	// keyName = the name of the function called in $.keyboard.keyaction when the button is clicked
+	// name = name added to key, or cross-referenced in the display options
+	// base.temp[0] = keyset to attach the new button
+	// regKey = true when it is not an action key
+	base.addKey = function (keyName, action, regKey) {
+		var keyClass, tmp, keys,
+			data = {},
+			txt = base.processKeys(regKey ? keyName : action),
+			kbcss = $keyboard.css;
+
+		if (!regKey && o.display[txt.name]) {
+			keys = base.processKeys(o.display[txt.name]);
+			// action contained in "keyName" (e.g. keyName = "accept",
+			// action = "a" (use checkmark instead of text))
+			keys.action = base.processKeys(keyName).name;
+		} else {
+			// when regKey is true, keyName is the same as action
+			keys = txt;
+			keys.action = txt.name;
+		}
+
+		data.name = base.processName(txt.name);
+		if (keys.name !== '') {
+			if (keys.map !== '') {
+				$keyboard.builtLayouts[base.layout].mappedKeys[keys.map] = keys.name;
+				$keyboard.builtLayouts[base.layout].acceptedKeys.push(keys.name);
+			} else if (regKey) {
+				$keyboard.builtLayouts[base.layout].acceptedKeys.push(keys.name);
+			}
+		}
+
+		if (regKey) {
+			keyClass = data.name === '' ? '' : kbcss.keyPrefix + data.name;
+		} else {
+			// Action keys will have the 'ui-keyboard-actionkey' class
+			keyClass = kbcss.keyAction + ' ' + kbcss.keyPrefix + keys.action;
+		}
+		// '\u2190'.length = 1 because the unicode is converted, so if more than one character,
+		// add the wide class
+		keyClass += (keys.name.length > 2 ? ' ' + kbcss.keyWide : '') + ' ' + o.css.buttonDefault;
+
+		data.html = '<span class="' + kbcss.keyText + '">' +
+			// this prevents HTML from being added to the key
+			keys.name.replace(/[\u00A0-\u9999]/gim, function (i) {
+				return '&#' + i.charCodeAt(0) + ';';
+			}) +
+			'</span>';
+
+		data.$key = base.keyBtn
+			.clone()
+			.attr({
+				'data-value': regKey ? keys.name : keys.action, // value
+				'data-name': keys.action,
+				'data-pos': base.temp[1] + ',' + base.temp[2],
+				'data-action': keys.action,
+				'data-html': data.html
+			})
+			// add 'ui-keyboard-' + data.name for all keys
+			//  (e.g. 'Bksp' will have 'ui-keyboard-bskp' class)
+			// any non-alphanumeric characters will be replaced with
+			//  their decimal unicode value
+			//  (e.g. '~' is a regular key, class = 'ui-keyboard-126'
+			//  (126 is the unicode decimal value - same as &#126;)
+			//  See https://en.wikipedia.org/wiki/List_of_Unicode_characters#Control_codes
+			.addClass(keyClass)
+			.html(data.html)
+			.appendTo(base.temp[0]);
+
+		if (keys.map) {
+			data.$key.attr('data-mapped', keys.map);
+		}
+		if (keys.title || txt.title) {
+			data.$key.attr({
+				'data-title': txt.title || keys.title, // used to allow adding content to title
+				'title': txt.title || keys.title
+			});
+		}
+
+		if (typeof o.buildKey === 'function') {
+			data = o.buildKey(base, data);
+			// copy html back to attributes
+			tmp = data.$key.html();
+			data.$key.attr('data-html', tmp);
+		}
+		return data.$key;
+	};
+
+	base.customHash = function (layout) {
+		/*jshint bitwise:false */
+		var i, array, hash, character, len,
+			arrays = [],
+			merged = [];
+		// pass layout to allow for testing
+		layout = typeof layout === 'undefined' ? o.customLayout : layout;
+		// get all layout arrays
+		for (array in layout) {
+			if (layout.hasOwnProperty(array)) {
+				arrays.push(layout[array]);
+			}
+		}
+		// flatten array
+		merged = merged.concat.apply(merged, arrays).join(' ');
+		// produce hash name - http://stackoverflow.com/a/7616484/145346
+		hash = 0;
+		len = merged.length;
+		if (len === 0) {
+			return hash;
+		}
+		for (i = 0; i < len; i++) {
+			character = merged.charCodeAt(i);
+			hash = ((hash << 5) - hash) + character;
+			hash = hash & hash; // Convert to 32bit integer
+		}
+		return hash;
+	};
+
+	base.buildKeyboard = function (name, internal) {
+		// o.display is empty when this is called from the scramble extension (when alwaysOpen:true)
+		if ($.isEmptyObject(o.display)) {
+			// set keyboard language
+			base.updateLanguage();
+		}
+		var index, row, $row, currentSet,
+			kbcss = $keyboard.css,
+			sets = 0,
+			layout = $keyboard.builtLayouts[name || base.layout || o.layout] = {
+				mappedKeys: {},
+				acceptedKeys: []
+			},
+			acceptedKeys = layout.acceptedKeys = o.restrictInclude ?
+				('' + o.restrictInclude).split(/\s+/) || [] :
+				[],
+			// using $layout temporarily to hold keyboard popup classnames
+			$layout = kbcss.keyboard + ' ' + o.css.popup + ' ' + o.css.container +
+				(o.alwaysOpen || o.userClosed ? ' ' + kbcss.alwaysOpen : ''),
+
+			container = $('<div />')
+				.addClass($layout)
+				.attr({
+					'role': 'textbox'
+				})
+				.hide();
+
+		// allow adding "{space}" as an accepted key - Fixes #627
+		index = $.inArray('{space}', acceptedKeys);
+		if (index > -1) {
+			acceptedKeys[index] = ' ';
+		}
+
+		// verify layout or setup custom keyboard
+		if ((internal && o.layout === 'custom') || !$keyboard.layouts.hasOwnProperty(o.layout)) {
+			o.layout = 'custom';
+			$layout = $keyboard.layouts.custom = o.customLayout || {
+				'normal': ['{cancel}']
+			};
+		} else {
+			$layout = $keyboard.layouts[internal ? o.layout : name || base.layout || o.layout];
+		}
+
+		// Main keyboard building loop
+		$.each($layout, function (set, keySet) {
+			// skip layout name & lang settings
+			if (set !== '' && !/^(name|lang|rtl)$/i.test(set)) {
+				// keep backwards compatibility for change from default to normal naming
+				if (set === 'default') {
+					set = 'normal';
+				}
+				sets++;
+				$row = $('<div />')
+					.attr('name', set) // added for typing extension
+					.addClass(kbcss.keySet + ' ' + kbcss.keySet + '-' + set)
+					.appendTo(container)
+					.toggle(set === 'normal');
+
+				for (row = 0; row < keySet.length; row++) {
+					// remove extra spaces before spliting (regex probably could be improved)
+					currentSet = $.trim(keySet[row]).replace(/\{(\.?)[\s+]?:[\s+]?(\.?)\}/g, '{$1:$2}');
+					base.buildRow($row, row, currentSet.split(/\s+/), acceptedKeys);
+					$row.find('.' + kbcss.keyButton + ',.' + kbcss.keySpacer)
+						.filter(':last')
+						.after('<br class="' + kbcss.endRow + '"/>');
+				}
+			}
+		});
+
+		if (sets > 1) {
+			base.sets = true;
+		}
+		layout.hasMappedKeys = !($.isEmptyObject(layout.mappedKeys));
+		layout.$keyboard = container;
+		return container;
+	};
+
+	base.buildRow = function ($row, row, keys, acceptedKeys) {
+		var t, txt, key, isAction, action, margin,
+			kbcss = $keyboard.css;
+		for (key = 0; key < keys.length; key++) {
+			// used by addKey function
+			base.temp = [$row, row, key];
+			isAction = false;
+
+			// ignore empty keys
+			if (keys[key].length === 0) {
+				continue;
+			}
+
+			// process here if it's an action key
+			if (/^\{\S+\}$/.test(keys[key])) {
+				action = keys[key].match(/^\{(\S+)\}$/)[1];
+				// add active class if there are double exclamation points in the name
+				if (/\!\!/.test(action)) {
+					action = action.replace('!!', '');
+					isAction = true;
+				}
+
+				// add empty space
+				if (/^sp:((\d+)?([\.|,]\d+)?)(em|px)?$/i.test(action)) {
+					// not perfect globalization, but allows you to use {sp:1,1em}, {sp:1.2em} or {sp:15px}
+					margin = parseFloat(action
+						.replace(/,/, '.')
+						.match(/^sp:((\d+)?([\.|,]\d+)?)(em|px)?$/i)[1] || 0
+					);
+					$('<span class="' + kbcss.keyText + '"></span>')
+						// previously {sp:1} would add 1em margin to each side of a 0 width span
+						// now Firefox doesn't seem to render 0px dimensions, so now we set the
+						// 1em margin x 2 for the width
+						.width((action.match(/px/i) ? margin + 'px' : (margin * 2) + 'em'))
+						.addClass(kbcss.keySpacer)
+						.appendTo($row);
+				}
+
+				// add empty button
+				if (/^empty(:((\d+)?([\.|,]\d+)?)(em|px)?)?$/i.test(action)) {
+					margin = (/:/.test(action)) ? parseFloat(action
+						.replace(/,/, '.')
+						.match(/^empty:((\d+)?([\.|,]\d+)?)(em|px)?$/i)[1] || 0
+					) : '';
+					base
+						.addKey('', ' ', true)
+						.addClass(o.css.buttonDisabled + ' ' + o.css.buttonEmpty)
+						.attr('aria-disabled', true)
+						.width(margin ? (action.match('px') ? margin + 'px' : (margin * 2) + 'em') : '');
+					continue;
+				}
+
+				// meta keys
+				if (/^meta[\w-]+\:?(\w+)?/i.test(action)) {
+					base
+						.addKey(action.split(':')[0], action)
+						.addClass(kbcss.keyHasActive);
+					continue;
+				}
+
+				// switch needed for action keys with multiple names/shortcuts or
+				// default will catch all others
+				txt = action.split(':');
+				switch (txt[0].toLowerCase()) {
+
+				case 'a':
+				case 'accept':
+					base
+						.addKey('accept', action)
+						.addClass(o.css.buttonAction + ' ' + kbcss.keyAction);
+					break;
+
+				case 'alt':
+				case 'altgr':
+					base
+						.addKey('alt', action)
+						.addClass(kbcss.keyHasActive);
+					break;
+
+				case 'b':
+				case 'bksp':
+					base.addKey('bksp', action);
+					break;
+
+				case 'c':
+				case 'cancel':
+					base
+						.addKey('cancel', action)
+						.addClass(o.css.buttonAction + ' ' + kbcss.keyAction);
+					break;
+
+					// toggle combo/diacritic key
+					/*jshint -W083 */
+				case 'combo':
+					base
+						.addKey('combo', action)
+						.addClass(kbcss.keyHasActive)
+						.attr('title', function (indx, title) {
+							// add combo key state to title
+							return title + ' ' + o.display[o.useCombos ? 'active' : 'disabled'];
+						})
+						.toggleClass(o.css.buttonActive, o.useCombos);
+					break;
+
+					// Decimal - unique decimal point (num pad layout)
+				case 'dec':
+					acceptedKeys.push((base.decimal) ? '.' : ',');
+					base.addKey('dec', action);
+					break;
+
+				case 'e':
+				case 'enter':
+					base
+						.addKey('enter', action)
+						.addClass(o.css.buttonAction + ' ' + kbcss.keyAction);
+					break;
+
+				case 'lock':
+					base
+						.addKey('lock', action)
+						.addClass(kbcss.keyHasActive);
+					break;
+
+				case 's':
+				case 'shift':
+					base
+						.addKey('shift', action)
+						.addClass(kbcss.keyHasActive);
+					break;
+
+					// Change sign (for num pad layout)
+				case 'sign':
+					acceptedKeys.push('-');
+					base.addKey('sign', action);
+					break;
+
+				case 'space':
+					acceptedKeys.push(' ');
+					base.addKey('space', action);
+					break;
+
+				case 't':
+				case 'tab':
+					base.addKey('tab', action);
+					break;
+
+				default:
+					if ($keyboard.keyaction.hasOwnProperty(txt[0])) {
+						base
+							.addKey(txt[0], action)
+							.toggleClass(o.css.buttonAction + ' ' + kbcss.keyAction, isAction);
+					}
+
+				}
+
+			} else {
+
+				// regular button (not an action key)
+				t = keys[key];
+				base.addKey(t, t, true);
+			}
+		}
+	};
+
+	base.removeBindings = function (namespace) {
+		$(document).unbind(namespace);
+		if (base.el.ownerDocument !== document) {
+			$(base.el.ownerDocument).unbind(namespace);
+		}
+		$(window).unbind(namespace);
+		base.$el.unbind(namespace);
+	};
+
+	base.removeKeyboard = function () {
+		base.$decBtn = [];
+		// base.$preview === base.$el when o.usePreview is false - fixes #442
+		if (o.usePreview) {
+			base.$preview.removeData('keyboard');
+		}
+		base.$preview.unbind(base.namespace + 'keybindings');
+		base.preview = null;
+		base.$preview = null;
+		base.$previewCopy = null;
+		base.$keyboard.removeData('keyboard');
+		base.$keyboard.remove();
+		base.$keyboard = [];
+		base.isOpen = false;
+		base.isCurrent(false);
+	};
+
+	base.destroy = function (callback) {
+		var index,
+			kbcss = $keyboard.css,
+			len = base.extensionNamespace.length,
+			tmp = [
+				kbcss.input,
+				kbcss.locked,
+				kbcss.placeholder,
+				kbcss.noKeyboard,
+				kbcss.alwaysOpen,
+				o.css.input,
+				kbcss.isCurrent
+			].join(' ');
+		clearTimeout(base.timer);
+		clearTimeout(base.timer2);
+		clearTimeout(base.timer3);
+		if (base.$keyboard.length) {
+			base.removeKeyboard();
+		}
+		base.removeBindings(base.namespace);
+		base.removeBindings(base.namespace + 'callbacks');
+		for (index = 0; index < len; index++) {
+			base.removeBindings(base.extensionNamespace[index]);
+		}
+		base.el.active = false;
+
+		base.$el
+			.removeClass(tmp)
+			.removeAttr('aria-haspopup')
+			.removeAttr('role')
+			.removeData('keyboard');
+		base = null;
+
+		if (typeof callback === 'function') {
+			callback();
+		}
+	};
+
+	// Run initializer
+	base.init();
+
+	}; // end $.keyboard definition
+
+	// event.which & ASCII values
+	$keyboard.keyCodes = {
+		backSpace: 8,
+		tab: 9,
+		enter: 13,
+		capsLock: 20,
+		escape: 27,
+		space: 32,
+		pageUp: 33,
+		pageDown: 34,
+		end: 35,
+		home: 36,
+		left: 37,
+		up: 38,
+		right: 39,
+		down: 40,
+		insert: 45,
+		delete: 46,
+		// event.which keyCodes (uppercase letters)
+		A: 65,
+		Z: 90,
+		V: 86,
+		C: 67,
+		X: 88,
+
+		// ASCII lowercase a & z
+		a: 97,
+		z: 122
+	};
+
+	$keyboard.css = {
+		// keyboard id suffix
+		idSuffix: '_keyboard',
+		// class name to set initial focus
+		initialFocus: 'keyboard-init-focus',
+		// element class names
+		input: 'ui-keyboard-input',
+		inputClone: 'ui-keyboard-preview-clone',
+		wrapper: 'ui-keyboard-preview-wrapper',
+		preview: 'ui-keyboard-preview',
+		keyboard: 'ui-keyboard',
+		keySet: 'ui-keyboard-keyset',
+		keyButton: 'ui-keyboard-button',
+		keyWide: 'ui-keyboard-widekey',
+		keyPrefix: 'ui-keyboard-',
+		keyText: 'ui-keyboard-text', // span with button text
+		keyHasActive: 'ui-keyboard-hasactivestate',
+		keyAction: 'ui-keyboard-actionkey',
+		keySpacer: 'ui-keyboard-spacer', // empty keys
+		keyToggle: 'ui-keyboard-toggle',
+		keyDisabled: 'ui-keyboard-disabled',
+		// Class for BRs with a div wrapper inside of contenteditable
+		divWrapperCE: 'ui-keyboard-div-wrapper',
+		// states
+		locked: 'ui-keyboard-lockedinput',
+		alwaysOpen: 'ui-keyboard-always-open',
+		noKeyboard: 'ui-keyboard-nokeyboard',
+		placeholder: 'ui-keyboard-placeholder',
+		hasFocus: 'ui-keyboard-has-focus',
+		isCurrent: 'ui-keyboard-input-current',
+		// validation & autoaccept
+		inputValid: 'ui-keyboard-valid-input',
+		inputInvalid: 'ui-keyboard-invalid-input',
+		inputAutoAccepted: 'ui-keyboard-autoaccepted',
+		endRow: 'ui-keyboard-button-endrow' // class added to <br>
+	};
+
+	$keyboard.events = {
+		// keyboard events
+		kbChange: 'keyboardChange',
+		kbBeforeClose: 'beforeClose',
+		kbBeforeVisible: 'beforeVisible',
+		kbVisible: 'visible',
+		kbInit: 'initialized',
+		kbInactive: 'inactive',
+		kbHidden: 'hidden',
+		kbRepeater: 'repeater',
+		kbKeysetChange: 'keysetChange',
+		// input events
+		inputAccepted: 'accepted',
+		inputCanceled: 'canceled',
+		inputChange: 'change',
+		inputRestricted: 'restricted'
+	};
+
+	// Action key function list
+	$keyboard.keyaction = {
+		accept: function (base) {
+			base.close(true); // same as base.accept();
+			return false; // return false prevents further processing
+		},
+		alt: function (base) {
+			base.altActive = !base.altActive;
+			base.showSet();
+		},
+		bksp: function (base) {
+			if (base.isContentEditable) {
+				base.execCommand('delete');
+				// save new caret position
+				base.saveCaret();
+			} else {
+				// the script looks for the '\b' string and initiates a backspace
+				base.insertText('\b');
+			}
+		},
+		cancel: function (base) {
+			base.close();
+			return false; // return false prevents further processing
+		},
+		clear: function (base) {
+			base.$preview[base.isContentEditable ? 'text' : 'val']('');
+			if (base.$decBtn.length) {
+				base.checkDecimal();
+			}
+		},
+		combo: function (base) {
+			var o = base.options,
+				c = !o.useCombos,
+				$combo = base.$keyboard.find('.' + $keyboard.css.keyPrefix + 'combo');
+			o.useCombos = c;
+			$combo
+				.toggleClass(o.css.buttonActive, c)
+				// update combo key state
+				.attr('title', $combo.attr('data-title') + ' (' + o.display[c ? 'active' : 'disabled'] + ')');
+			if (c) {
+				base.checkCombos();
+			}
+			return false;
+		},
+		dec: function (base) {
+			base.insertText((base.decimal) ? '.' : ',');
+		},
+		del: function (base) {
+			if (base.isContentEditable) {
+				base.execCommand('forwardDelete');
+			} else {
+				// the script looks for the '{d}' string and initiates a delete
+				base.insertText('{d}');
+			}
+		},
+		// resets to base keyset (deprecated because "default" is a reserved word)
+		'default': function (base) {
+			base.shiftActive = base.altActive = base.metaActive = false;
+			base.showSet();
+		},
+		// el is the pressed key (button) object; it is null when the real keyboard enter is pressed
+		enter: function (base, el, e) {
+			var tag = base.el.nodeName,
+				o = base.options;
+			// shift+enter in textareas
+			if (e.shiftKey) {
+				// textarea, input & contenteditable - enterMod + shift + enter = accept,
+				//  then go to prev; base.switchInput(goToNext, autoAccept)
+				// textarea & input - shift + enter = accept (no navigation)
+				return (o.enterNavigation) ? base.switchInput(!e[o.enterMod], true) : base.close(true);
+			}
+			// input only - enterMod + enter to navigate
+			if (o.enterNavigation && (tag !== 'TEXTAREA' || e[o.enterMod])) {
+				return base.switchInput(!e[o.enterMod], o.autoAccept ? 'true' : false);
+			}
+			// pressing virtual enter button inside of a textarea - add a carriage return
+			// e.target is span when clicking on text and button at other times
+			if (tag === 'TEXTAREA' && $(e.target).closest('button').length) {
+				// IE8 fix (space + \n) - fixes #71 thanks Blookie!
+				base.insertText(($keyboard.msie ? ' ' : '') + '\n');
+			}
+			if (base.isContentEditable && !o.enterNavigation) {
+				base.execCommand('insertHTML', '<div><br class="' + $keyboard.css.divWrapperCE + '"></div>');
+				// Using backspace on wrapped BRs will now shift the textnode inside of the wrapped BR
+				// Although not ideal, the caret is moved after the block - see the wiki page for
+				// more details: https://github.com/Mottie/Keyboard/wiki/Contenteditable#limitations
+				// move caret after a delay to allow rendering of HTML
+				setTimeout(function() {
+					$keyboard.keyaction.right(base);
+					base.saveCaret();
+				}, 0);
+			}
+		},
+		// caps lock key
+		lock: function (base) {
+			base.last.keyset[0] = base.shiftActive = base.capsLock = !base.capsLock;
+			base.showSet();
+		},
+		left: function (base) {
+			var p = $keyboard.caret(base.$preview);
+			if (p.start - 1 >= 0) {
+				// move both start and end of caret (prevents text selection) & save caret position
+				base.last.start = base.last.end = p.start - 1;
+				$keyboard.caret(base.$preview, base.last);
+				base.setScroll();
+			}
+		},
+		meta: function (base, el) {
+			var $el = $(el);
+			base.metaActive = !$el.hasClass(base.options.css.buttonActive);
+			base.showSet($el.attr('data-name'));
+		},
+		next: function (base) {
+			base.switchInput(true, base.options.autoAccept);
+			return false;
+		},
+		// same as 'default' - resets to base keyset
+		normal: function (base) {
+			base.shiftActive = base.altActive = base.metaActive = false;
+			base.showSet();
+		},
+		prev: function (base) {
+			base.switchInput(false, base.options.autoAccept);
+			return false;
+		},
+		right: function (base) {
+			var p = $keyboard.caret(base.$preview),
+				len = base.isContentEditable ? $keyboard.getEditableLength(base.el) : base.getValue().length;
+			if (p.end + 1 <= len) {
+				// move both start and end of caret to end position
+				// (prevents text selection) && save caret position
+				base.last.start = base.last.end = p.end + 1;
+				$keyboard.caret(base.$preview, base.last);
+				base.setScroll();
+			}
+		},
+		shift: function (base) {
+			base.last.keyset[0] = base.shiftActive = !base.shiftActive;
+			base.showSet();
+		},
+		sign: function (base) {
+			if (/^[+-]?\d*\.?\d*$/.test(base.getValue())) {
+				var caret,
+					p = $keyboard.caret(base.$preview),
+					val = base.getValue(),
+					len = base.isContentEditable ? $keyboard.getEditableLength(base.el) : val.length;
+				base.setValue(val * -1);
+				caret = len - val.length;
+				base.last.start = p.start + caret;
+				base.last.end = p.end + caret;
+				$keyboard.caret(base.$preview, base.last);
+				base.setScroll();
+			}
+		},
+		space: function (base) {
+			base.insertText(' ');
+		},
+		tab: function (base) {
+			var tag = base.el.nodeName,
+				o = base.options;
+			if (tag !== 'TEXTAREA') {
+				if (o.tabNavigation) {
+					return base.switchInput(!base.shiftActive, true);
+				} else if (tag === 'INPUT') {
+					// ignore tab key in input
+					return false;
+				}
+			}
+			base.insertText('\t');
+		},
+		toggle: function (base) {
+			base.enabled = !base.enabled;
+			base.toggle();
+		},
+		// *** Special action keys: NBSP & zero-width characters ***
+		// Non-breaking space
+		NBSP: '\u00a0',
+		// zero width space
+		ZWSP: '\u200b',
+		// Zero width non-joiner
+		ZWNJ: '\u200c',
+		// Zero width joiner
+		ZWJ: '\u200d',
+		// Left-to-right Mark
+		LRM: '\u200e',
+		// Right-to-left Mark
+		RLM: '\u200f'
+	};
+
+	// Default keyboard layouts
+	$keyboard.builtLayouts = {};
+	$keyboard.layouts = {
+		'alpha': {
+			'normal': [
+				'` 1 2 3 4 5 6 7 8 9 0 - = {bksp}',
+				'{tab} a b c d e f g h i j [ ] \\',
+				'k l m n o p q r s ; \' {enter}',
+				'{shift} t u v w x y z , . / {shift}',
+				'{accept} {space} {cancel}'
+			],
+			'shift': [
+				'~ ! @ # $ % ^ & * ( ) _ + {bksp}',
+				'{tab} A B C D E F G H I J { } |',
+				'K L M N O P Q R S : " {enter}',
+				'{shift} T U V W X Y Z < > ? {shift}',
+				'{accept} {space} {cancel}'
+			]
+		},
+		'qwerty': {
+			'normal': [
+				'` 1 2 3 4 5 6 7 8 9 0 - = {bksp}',
+				'{tab} q w e r t y u i o p [ ] \\',
+				'a s d f g h j k l ; \' {enter}',
+				'{shift} z x c v b n m , . / {shift}',
+				'{accept} {space} {cancel}'
+			],
+			'shift': [
+				'~ ! @ # $ % ^ & * ( ) _ + {bksp}',
+				'{tab} Q W E R T Y U I O P { } |',
+				'A S D F G H J K L : " {enter}',
+				'{shift} Z X C V B N M < > ? {shift}',
+				'{accept} {space} {cancel}'
+			]
+		},
+		'international': {
+			'normal': [
+				'` 1 2 3 4 5 6 7 8 9 0 - = {bksp}',
+				'{tab} q w e r t y u i o p [ ] \\',
+				'a s d f g h j k l ; \' {enter}',
+				'{shift} z x c v b n m , . / {shift}',
+				'{accept} {alt} {space} {alt} {cancel}'
+			],
+			'shift': [
+				'~ ! @ # $ % ^ & * ( ) _ + {bksp}',
+				'{tab} Q W E R T Y U I O P { } |',
+				'A S D F G H J K L : " {enter}',
+				'{shift} Z X C V B N M < > ? {shift}',
+				'{accept} {alt} {space} {alt} {cancel}'
+			],
+			'alt': [
+				'~ \u00a1 \u00b2 \u00b3 \u00a4 \u20ac \u00bc \u00bd \u00be \u2018 \u2019 \u00a5 \u00d7 {bksp}',
+				'{tab} \u00e4 \u00e5 \u00e9 \u00ae \u00fe \u00fc \u00fa \u00ed \u00f3 \u00f6 \u00ab \u00bb \u00ac',
+				'\u00e1 \u00df \u00f0 f g h j k \u00f8 \u00b6 \u00b4 {enter}',
+				'{shift} \u00e6 x \u00a9 v b \u00f1 \u00b5 \u00e7 > \u00bf {shift}',
+				'{accept} {alt} {space} {alt} {cancel}'
+			],
+			'alt-shift': [
+				'~ \u00b9 \u00b2 \u00b3 \u00a3 \u20ac \u00bc \u00bd \u00be \u2018 \u2019 \u00a5 \u00f7 {bksp}',
+				'{tab} \u00c4 \u00c5 \u00c9 \u00ae \u00de \u00dc \u00da \u00cd \u00d3 \u00d6 \u00ab \u00bb \u00a6',
+				'\u00c4 \u00a7 \u00d0 F G H J K \u00d8 \u00b0 \u00a8 {enter}',
+				'{shift} \u00c6 X \u00a2 V B \u00d1 \u00b5 \u00c7 . \u00bf {shift}',
+				'{accept} {alt} {space} {alt} {cancel}'
+			]
+		},
+		'colemak': {
+			'normal': [
+				'` 1 2 3 4 5 6 7 8 9 0 - = {bksp}',
+				'{tab} q w f p g j l u y ; [ ] \\',
+				'{bksp} a r s t d h n e i o \' {enter}',
+				'{shift} z x c v b k m , . / {shift}',
+				'{accept} {space} {cancel}'
+			],
+			'shift': [
+				'~ ! @ # $ % ^ & * ( ) _ + {bksp}',
+				'{tab} Q W F P G J L U Y : { } |',
+				'{bksp} A R S T D H N E I O " {enter}',
+				'{shift} Z X C V B K M < > ? {shift}',
+				'{accept} {space} {cancel}'
+			]
+		},
+		'dvorak': {
+			'normal': [
+				'` 1 2 3 4 5 6 7 8 9 0 [ ] {bksp}',
+				'{tab} \' , . p y f g c r l / = \\',
+				'a o e u i d h t n s - {enter}',
+				'{shift} ; q j k x b m w v z {shift}',
+				'{accept} {space} {cancel}'
+			],
+			'shift': [
+				'~ ! @ # $ % ^ & * ( ) { } {bksp}',
+				'{tab} " < > P Y F G C R L ? + |',
+				'A O E U I D H T N S _ {enter}',
+				'{shift} : Q J K X B M W V Z {shift}',
+				'{accept} {space} {cancel}'
+			]
+		},
+		'num': {
+			'normal': [
+				'= ( ) {b}',
+				'{clear} / * -',
+				'7 8 9 +',
+				'4 5 6 {sign}',
+				'1 2 3 %',
+				'0 {dec} {a} {c}'
+			]
+		}
+	};
+
+	$keyboard.language = {
+		en: {
+			display: {
+				// check mark - same action as accept
+				'a': '\u2714:Accept (Shift+Enter)',
+				'accept': 'Accept:Accept (Shift+Enter)',
+				// other alternatives \u2311
+				'alt': 'Alt:\u2325 AltGr',
+				// Left arrow (same as &larr;)
+				'b': '\u232b:Backspace',
+				'bksp': 'Bksp:Backspace',
+				// big X, close - same action as cancel
+				'c': '\u2716:Cancel (Esc)',
+				'cancel': 'Cancel:Cancel (Esc)',
+				// clear num pad
+				'clear': 'C:Clear',
+				'combo': '\u00f6:Toggle Combo Keys',
+				// decimal point for num pad (optional), change '.' to ',' for European format
+				'dec': '.:Decimal',
+				// down, then left arrow - enter symbol
+				'e': '\u23ce:Enter',
+				'empty': '\u00a0',
+				'enter': 'Enter:Enter \u23ce',
+				// left arrow (move caret)
+				'left': '\u2190',
+				// caps lock
+				'lock': 'Lock:\u21ea Caps Lock',
+				'next': 'Next \u21e8',
+				'prev': '\u21e6 Prev',
+				// right arrow (move caret)
+				'right': '\u2192',
+				// thick hollow up arrow
+				's': '\u21e7:Shift',
+				'shift': 'Shift:Shift',
+				// +/- sign for num pad
+				'sign': '\u00b1:Change Sign',
+				'space': '\u00a0:Space',
+				// right arrow to bar (used since this virtual keyboard works with one directional tabs)
+				't': '\u21e5:Tab',
+				// \u21b9 is the true tab symbol (left & right arrows)
+				'tab': '\u21e5 Tab:Tab',
+				// replaced by an image
+				'toggle': ' ',
+
+				// added to titles of keys
+				// accept key status when acceptValid:true
+				'valid': 'valid',
+				'invalid': 'invalid',
+				// combo key states
+				'active': 'active',
+				'disabled': 'disabled'
+			},
+
+			// Message added to the key title while hovering, if the mousewheel plugin exists
+			wheelMessage: 'Use mousewheel to see other keys',
+
+			comboRegex: /([`\'~\^\"ao])([a-z])/mig,
+			combos: {
+				// grave
+				'`': { a: '\u00e0', A: '\u00c0', e: '\u00e8', E: '\u00c8', i: '\u00ec', I: '\u00cc', o: '\u00f2',
+						O: '\u00d2', u: '\u00f9', U: '\u00d9', y: '\u1ef3', Y: '\u1ef2' },
+				// acute & cedilla
+				"'": { a: '\u00e1', A: '\u00c1', e: '\u00e9', E: '\u00c9', i: '\u00ed', I: '\u00cd', o: '\u00f3',
+						O: '\u00d3', u: '\u00fa', U: '\u00da', y: '\u00fd', Y: '\u00dd' },
+				// umlaut/trema
+				'"': { a: '\u00e4', A: '\u00c4', e: '\u00eb', E: '\u00cb', i: '\u00ef', I: '\u00cf', o: '\u00f6',
+						O: '\u00d6', u: '\u00fc', U: '\u00dc', y: '\u00ff', Y: '\u0178' },
+				// circumflex
+				'^': { a: '\u00e2', A: '\u00c2', e: '\u00ea', E: '\u00ca', i: '\u00ee', I: '\u00ce', o: '\u00f4',
+						O: '\u00d4', u: '\u00fb', U: '\u00db', y: '\u0177', Y: '\u0176' },
+				// tilde
+				'~': { a: '\u00e3', A: '\u00c3', e: '\u1ebd', E: '\u1ebc', i: '\u0129', I: '\u0128', o: '\u00f5',
+						O: '\u00d5', u: '\u0169', U: '\u0168', y: '\u1ef9', Y: '\u1ef8', n: '\u00f1', N: '\u00d1' }
+			}
+		}
+	};
+
+	$keyboard.defaultOptions = {
+		// set this to ISO 639-1 language code to override language set by the layout
+		// http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
+		// language defaults to 'en' if not found
+		language: null,
+		rtl: false,
+
+		// *** choose layout & positioning ***
+		layout: 'qwerty',
+		customLayout: null,
+
+		position: {
+			// optional - null (attach to input/textarea) or a jQuery object (attach elsewhere)
+			of: null,
+			my: 'center top',
+			at: 'center top',
+			// used when 'usePreview' is false (centers the keyboard at the bottom of the input/textarea)
+			at2: 'center bottom'
+		},
+
+		// allow jQuery position utility to reposition the keyboard on window resize
+		reposition: true,
+
+		// preview added above keyboard if true, original input/textarea used if false
+		usePreview: true,
+
+		// if true, the keyboard will always be visible
+		alwaysOpen: false,
+
+		// give the preview initial focus when the keyboard becomes visible
+		initialFocus: true,
+
+		// avoid changing the focus (hardware keyboard probably won't work)
+		noFocus: false,
+
+		// if true, keyboard will remain open even if the input loses focus, but closes on escape
+		// or when another keyboard opens.
+		stayOpen: false,
+
+		// Prevents the keyboard from closing when the user clicks or presses outside the keyboard
+		// the `autoAccept` option must also be set to true when this option is true or changes are lost
+		userClosed: false,
+
+		// if true, keyboard will not close if you press escape.
+		ignoreEsc: false,
+
+		// if true, keyboard will only closed on click event instead of mousedown and touchstart
+		closeByClickEvent: false,
+
+		css: {
+			// input & preview
+			input: 'ui-widget-content ui-corner-all',
+			// keyboard container
+			container: 'ui-widget-content ui-widget ui-corner-all ui-helper-clearfix',
+			// keyboard container extra class (same as container, but separate)
+			popup: '',
+			// default state
+			buttonDefault: 'ui-state-default ui-corner-all',
+			// hovered button
+			buttonHover: 'ui-state-hover',
+			// Action keys (e.g. Accept, Cancel, Tab, etc); this replaces 'actionClass' option
+			buttonAction: 'ui-state-active',
+			// Active keys (e.g. shift down, meta keyset active, combo keys active)
+			buttonActive: 'ui-state-active',
+			// used when disabling the decimal button {dec} when a decimal exists in the input area
+			buttonDisabled: 'ui-state-disabled',
+			buttonEmpty: 'ui-keyboard-empty'
+		},
+
+		// *** Useability ***
+		// Auto-accept content when clicking outside the keyboard (popup will close)
+		autoAccept: false,
+		// Auto-accept content even if the user presses escape (only works if `autoAccept` is `true`)
+		autoAcceptOnEsc: false,
+
+		// Prevents direct input in the preview window when true
+		lockInput: false,
+
+		// Prevent keys not in the displayed keyboard from being typed in
+		restrictInput: false,
+		// Additional allowed characters while restrictInput is true
+		restrictInclude: '', // e.g. 'a b foo \ud83d\ude38'
+
+		// Check input against validate function, if valid the accept button gets a class name of
+		// 'ui-keyboard-valid-input'. If invalid, the accept button gets a class name of
+		// 'ui-keyboard-invalid-input'
+		acceptValid: false,
+		// Auto-accept when input is valid; requires `acceptValid` set `true` & validate callback
+		autoAcceptOnValid: false,
+		// Check validation on keyboard initialization. If false, the "Accept" key state (color)
+		// will not change to show if the content is valid, or not
+		checkValidOnInit: true,
+
+		// if acceptValid is true & the validate function returns a false, this option will cancel
+		// a keyboard close only after the accept button is pressed
+		cancelClose: true,
+
+		// tab to go to next, shift-tab for previous (default behavior)
+		tabNavigation: false,
+
+		// enter for next input; shift+enter accepts content & goes to next
+		// shift + 'enterMod' + enter ('enterMod' is the alt as set below) will accept content and go
+		// to previous in a textarea
+		enterNavigation: false,
+		// mod key options: 'ctrlKey', 'shiftKey', 'altKey', 'metaKey' (MAC only)
+		enterMod: 'altKey', // alt-enter to go to previous; shift-alt-enter to accept & go to previous
+
+		// if true, the next button will stop on the last keyboard input/textarea; prev button stops at first
+		// if false, the next button will wrap to target the first input/textarea; prev will go to the last
+		stopAtEnd: true,
+
+		// Set this to append the keyboard after the input/textarea (appended to the input/textarea parent).
+		// This option works best when the input container doesn't have a set width & when the 'tabNavigation'
+		// option is true.
+		appendLocally: false,
+		// When appendLocally is false, the keyboard will be appended to this object
+		appendTo: 'body',
+
+		// Wrap all <br>s inside of a contenteditable in a div; without wrapping, the caret
+		// position will not be accurate
+		wrapBRs: true,
+
+		// If false, the shift key will remain active until the next key is (mouse) clicked on; if true it will
+		// stay active until pressed again
+		stickyShift: true,
+
+		// Prevent pasting content into the area
+		preventPaste: false,
+
+		// caret placed at the end of any text when keyboard becomes visible
+		caretToEnd: false,
+
+		// caret stays this many pixels from the edge of the input while scrolling left/right;
+		// use "c" or "center" to center the caret while scrolling
+		scrollAdjustment: 10,
+
+		// Set the max number of characters allowed in the input, setting it to false disables this option
+		maxLength: false,
+		// allow inserting characters @ caret when maxLength is set
+		maxInsert: true,
+
+		// Mouse repeat delay - when clicking/touching a virtual keyboard key, after this delay the key will
+		// start repeating
+		repeatDelay: 500,
+
+		// Mouse repeat rate - after the repeatDelay, this is the rate (characters per second) at which the
+		// key is repeated Added to simulate holding down a real keyboard key and having it repeat. I haven't
+		// calculated the upper limit of this rate, but it is limited to how fast the javascript can process
+		// the keys. And for me, in Firefox, it's around 20.
+		repeatRate: 20,
+
+		// resets the keyboard to the default keyset when visible
+		resetDefault: true,
+
+		// Event (namespaced) on the input to reveal the keyboard. To disable it, just set it to ''.
+		openOn: 'focus',
+
+		// enable the keyboard on readonly inputs
+		activeOnReadonly: false,
+
+		// Event (namepaced) for when the character is added to the input (clicking on the keyboard)
+		keyBinding: 'mousedown touchstart',
+
+		// enable/disable mousewheel functionality
+		// enabling still depends on the mousewheel plugin
+		useWheel: true,
+
+		// combos (emulate dead keys : http://en.wikipedia.org/wiki/Keyboard_layout#US-International)
+		// if user inputs `a the script converts it to à, ^o becomes ô, etc.
+		useCombos: true,
+
+		/*
+			// *** Methods ***
+			// commenting these out to reduce the size of the minified version
+			// Callbacks - attach a function to any of these callbacks as desired
+			initialized   : function(e, keyboard, el) {},
+			beforeVisible : function(e, keyboard, el) {},
+			visible       : function(e, keyboard, el) {},
+			beforeInsert  : function(e, keyboard, el, textToAdd) { return textToAdd; },
+			change        : function(e, keyboard, el) {},
+			beforeClose   : function(e, keyboard, el, accepted) {},
+			accepted      : function(e, keyboard, el) {},
+			canceled      : function(e, keyboard, el) {},
+			restricted    : function(e, keyboard, el) {},
+			hidden        : function(e, keyboard, el) {},
+			// called instead of base.switchInput
+			switchInput   : function(keyboard, goToNext, isAccepted) {},
+			// used if you want to create a custom layout or modify the built-in keyboard
+			create        : function(keyboard) { return keyboard.buildKeyboard(); },
+
+			// build key callback
+			buildKey : function( keyboard, data ) {
+				/ *
+				data = {
+				// READ ONLY
+				isAction : [boolean] true if key is an action key
+				name     : [string]  key class name suffix ( prefix = 'ui-keyboard-' );
+														 may include decimal ascii value of character
+				value    : [string]  text inserted (non-action keys)
+				title    : [string]  title attribute of key
+				action   : [string]  keyaction name
+				html     : [string]  HTML of the key; it includes a <span> wrapping the text
+				// use to modify key HTML
+				$key     : [object]  jQuery selector of key which is already appended to keyboard
+				}
+				* /
+				return data;
+			},
+		*/
+
+		// this callback is called, if the acceptValid is true, and just before the 'beforeClose' to check
+		// the value if the value is valid, return true and the keyboard will continue as it should
+		// (close if not always open, etc). If the value is not valid, return false and clear the keyboard
+		// value ( like this "keyboard.$preview.val('');" ), if desired. The validate function is called after
+		// each input, the 'isClosing' value will be false; when the accept button is clicked,
+		// 'isClosing' is true
+		validate: function (/* keyboard, value, isClosing */) {
+			return true;
+		}
+
+	};
+
+	// for checking combos
+	$keyboard.comboRegex = /([`\'~\^\"ao])([a-z])/mig;
+
+	// store current keyboard element; used by base.isCurrent()
+	$keyboard.currentKeyboard = '';
+
+	$('<!--[if lte IE 8]><script>jQuery("body").addClass("oldie");</script><![endif]--><!--[if IE]>' +
+			'<script>jQuery("body").addClass("ie");</script><![endif]-->')
+		.appendTo('body')
+		.remove();
+	$keyboard.msie = $('body').hasClass('oldie'); // Old IE flag, used for caret positioning
+	$keyboard.allie = $('body').hasClass('ie');
+
+	$keyboard.watermark = (typeof (document.createElement('input').placeholder) !== 'undefined');
+
+	$keyboard.checkCaretSupport = function () {
+		if (typeof $keyboard.checkCaret !== 'boolean') {
+			// Check if caret position is saved when input is hidden or loses focus
+			// (*cough* all versions of IE and I think Opera has/had an issue as well
+			var $temp = $('<div style="height:0px;width:0px;overflow:hidden;position:fixed;top:0;left:-100px;">' +
+				'<input type="text" value="testing"/></div>').prependTo('body'); // stop page scrolling
+			$keyboard.caret($temp.find('input'), 3, 3);
+			// Also save caret position of the input if it is locked
+			$keyboard.checkCaret = $keyboard.caret($temp.find('input').hide().show()).start !== 3;
+			$temp.remove();
+		}
+		return $keyboard.checkCaret;
+	};
+
+	$keyboard.caret = function($el, param1, param2) {
+		if (!$el || !$el.length || $el.is(':hidden') || $el.css('visibility') === 'hidden') {
+			return {};
+		}
+		var start, end, txt, pos,
+			kb = $el.data( 'keyboard' ),
+			noFocus = kb && kb.options.noFocus,
+			formEl = /(textarea|input)/i.test($el[0].nodeName);
+		if (!noFocus) { $el.focus(); }
+		// set caret position
+		if (typeof param1 !== 'undefined') {
+			// allow setting caret using ( $el, { start: x, end: y } )
+			if (typeof param1 === 'object' && 'start' in param1 && 'end' in param1) {
+				start = param1.start;
+				end = param1.end;
+			} else if (typeof param2 === 'undefined') {
+				param2 = param1; // set caret using start position
+			}
+			// set caret using ( $el, start, end );
+			if (typeof param1 === 'number' && typeof param2 === 'number') {
+				start = param1;
+				end = param2;
+			} else if ( param1 === 'start' ) {
+				start = end = 0;
+			} else if ( typeof param1 === 'string' ) {
+				// unknown string setting, move caret to end
+				start = end = 'end';
+			}
+
+			// *** SET CARET POSITION ***
+			// modify the line below to adapt to other caret plugins
+			return formEl ?
+				$el.caret( start, end, noFocus ) :
+				$keyboard.setEditableCaret( $el, start, end );
+		}
+		// *** GET CARET POSITION ***
+		// modify the line below to adapt to other caret plugins
+		if (formEl) {
+			// modify the line below to adapt to other caret plugins
+			pos = $el.caret();
+		} else {
+			// contenteditable
+			pos = $keyboard.getEditableCaret($el[0]);
+		}
+		start = pos.start;
+		end = pos.end;
+
+		// *** utilities ***
+		txt = formEl && $el[0].value || $el.text() || '';
+		return {
+			start : start,
+			end : end,
+			// return selected text
+			text : txt.substring( start, end ),
+			// return a replace selected string method
+			replaceStr : function( str ) {
+				return txt.substring( 0, start ) + str + txt.substring( end, txt.length );
+			}
+		};
+	};
+
+	$keyboard.isTextNode = function(el) {
+		return el && el.nodeType === 3;
+	};
+
+	$keyboard.isBlock = function(el, node) {
+		var win = el.ownerDocument.defaultView;
+		if (
+			node && node.nodeType === 1 && node !== el &&
+			win.getComputedStyle(node).display === 'block'
+		) {
+			return 1;
+		}
+		return 0;
+	};
+
+	// Wrap all BR's inside of contenteditable
+	$keyboard.wrapBRs = function(container) {
+		var $el = $(container).find('br:not(.' + $keyboard.css.divWrapperCE + ')');
+		if ($el.length) {
+			$.each($el, function(i, el) {
+				var len = el.parentNode.childNodes.length;
+				if (
+					// wrap BRs if not solo child
+					len !== 1 ||
+					// Or if BR is wrapped by a span
+					len === 1 && !$keyboard.isBlock(container, el.parentNode)
+				) {
+					$(el).addClass($keyboard.css.divWrapperCE).wrap('<div>');
+				}
+			});
+		}
+	};
+
+	$keyboard.getEditableCaret = function(container) {
+		container = $(container)[0];
+		if (!container.isContentEditable) { return {}; }
+		var end, text,
+			options = ($(container).data('keyboard') || {}).options,
+			doc = container.ownerDocument,
+			range = doc.getSelection().getRangeAt(0),
+			result = pathToNode(range.startContainer, range.startOffset),
+			start = result.position;
+		if (options.wrapBRs !== false) {
+			$keyboard.wrapBRs(container);
+		}
+		function pathToNode(endNode, offset) {
+			var node, adjust,
+				txt = '',
+				done = false,
+				position = 0,
+				nodes = $.makeArray(container.childNodes);
+
+			function checkBlock(val) {
+				if (val) {
+					position += val;
+					txt += options && options.replaceCR || '\n';
+				}
+			}
+
+			while (!done && nodes.length) {
+				node = nodes.shift();
+				if (node === endNode) {
+					done = true;
+				}
+
+				// Add one if previous sibling was a block node (div, p, etc)
+				adjust = $keyboard.isBlock(container, node.previousSibling);
+				checkBlock(adjust);
+
+				if ($keyboard.isTextNode(node)) {
+					position += done ? offset : node.length;
+					txt += node.textContent;
+					if (done) {
+						return {position: position, text: txt};
+					}
+				} else if (!done && node.childNodes) {
+					nodes = $.makeArray(node.childNodes).concat(nodes);
+				}
+				// Add one if we're inside a block node (div, p, etc)
+				// and previous sibling was a text node
+				adjust = $keyboard.isTextNode(node.previousSibling) && $keyboard.isBlock(container, node);
+				checkBlock(adjust);
+			}
+			return {position: position, text: txt};
+		}
+		// check of start and end are the same
+		if (range.endContainer === range.startContainer && range.endOffset === range.startOffset) {
+			end = start;
+			text = '';
+		} else {
+			result = pathToNode(range.endContainer, range.endOffset);
+			end = result.position;
+			text = result.text.substring(start, end);
+		}
+		return {
+			start: start,
+			end: end,
+			text: text
+		};
+	};
+
+	$keyboard.getEditableLength = function(container) {
+		var result = $keyboard.setEditableCaret(container, 'getMax');
+		// if not a number, the container is not a contenteditable element
+		return typeof result === 'number' ? result : null;
+	};
+
+	$keyboard.setEditableCaret = function(container, start, end) {
+		container = $(container)[0];
+		if (!container.isContentEditable) { return {}; }
+		var doc = container.ownerDocument,
+			range = doc.createRange(),
+			sel = doc.getSelection(),
+			options = ($(container).data('keyboard') || {}).options,
+			s = start,
+			e = end,
+			text = '',
+			result = findNode(start === 'getMax' ? 'end' : start);
+		function findNode(offset) {
+			if (offset === 'end') {
+				// Set some value > content length; but return max
+				offset = container.innerHTML.length;
+			} else if (offset < 0) {
+				offset = 0;
+			}
+			var node, check,
+				txt = '',
+				done = false,
+				position = 0,
+				last = 0,
+				max = 0,
+				nodes = $.makeArray(container.childNodes);
+			function updateText(val) {
+				txt += val ? options && options.replaceCR || '\n' : '';
+				return val > 0;
+			}
+			function checkDone(adj) {
+				var val = position + adj;
+				last = max;
+				max += adj;
+				if (offset - val >= 0) {
+					position = val;
+					return offset - position <= 0;
+				}
+				return offset - val <= 0;
+			}
+			while (!done && nodes.length) {
+				node = nodes.shift();
+				// Add one if the previous sibling was a block node (div, p, etc)
+				check = $keyboard.isBlock(container, node.previousSibling);
+				if (updateText(check) && checkDone(check)) {
+					done = true;
+				}
+				// Add one if we're inside a block node (div, p, etc)
+				check = $keyboard.isTextNode(node.previousSibling) && $keyboard.isBlock(container, node);
+				if (updateText(check) && checkDone(check)) {
+					done = true;
+				}
+				if ($keyboard.isTextNode(node)) {
+					txt += node.textContent;
+					if (checkDone(node.length)) {
+						check = offset - position === 0 && position - last >= 1 ? node.length : offset - position;
+						return {
+							node: node,
+							offset: check,
+							position: offset,
+							text: txt
+						};
+					}
+				} else if (!done && node.childNodes) {
+					nodes = $.makeArray(node.childNodes).concat(nodes);
+				}
+			}
+			return nodes.length ?
+				{node: node, offset: offset - position, position: offset, text: txt} :
+				// Offset is larger than content, return max
+				{node: node, offset: node && node.length || 0, position: max, text: txt};
+		}
+		if (result.node) {
+			s = result.position; // Adjust if start > content length
+			if (start === 'getMax') {
+				return s;
+			}
+			range.setStart(result.node, result.offset);
+			// Only find end if > start and is defined... this allows passing
+			// setEditableCaret(el, 'end') or setEditableCaret(el, 10, 'end');
+			if (typeof end !== 'undefined' && end !== start) {
+				result = findNode(end);
+			}
+			if (result.node) {
+				e = result.position; // Adjust if end > content length
+				range.setEnd(result.node, result.offset);
+				text = s === e ? '' : result.text.substring(s, e);
+			}
+			sel.removeAllRanges();
+			sel.addRange(range);
+		}
+		return {
+			start: s,
+			end: e,
+			text: text
+		};
+	};
+
+	$keyboard.replaceContent = function (el, param) {
+		el = $(el)[0];
+		var node, i, str,
+			type = typeof param,
+			caret = $keyboard.getEditableCaret(el).start,
+			charIndex = 0,
+			nodeStack = [el];
+		while ((node = nodeStack.pop())) {
+			if ($keyboard.isTextNode(node)) {
+				if (type === 'function') {
+					if (caret >= charIndex && caret <= charIndex + node.length) {
+						node.textContent = param(node.textContent);
+					}
+				} else if (type === 'string') {
+					// maybe not the best method, but it works for simple changes
+					str = param.substring(charIndex, charIndex + node.length);
+					if (str !== node.textContent) {
+						node.textContent = str;
+					}
+				}
+				charIndex += node.length;
+			} else if (node && node.childNodes) {
+				i = node.childNodes.length;
+				while (i--) {
+					nodeStack.push(node.childNodes[i]);
+				}
+			}
+		}
+		i = $keyboard.getEditableCaret(el);
+		$keyboard.setEditableCaret(el, i.start, i.start);
+	};
+
+	$.fn.keyboard = function (options) {
+		return this.each(function () {
+			if (!$(this).data('keyboard')) {
+				/*jshint nonew:false */
+				(new $.keyboard(this, options));
+			}
+		});
+	};
+
+	$.fn.getkeyboard = function () {
+		return this.data('keyboard');
+	};
+
+	/* Copyright (c) 2010 C. F., Wong (<a href="http://cloudgen.w0ng.hk">Cloudgen Examplet Store</a>)
+	 * Licensed under the MIT License:
+	 * http://www.opensource.org/licenses/mit-license.php
+	 * Highly modified from the original
+	 */
+
+	$.fn.caret = function (start, end, noFocus) {
+		if (
+			typeof this[0] === 'undefined' ||
+			this.is(':hidden') ||
+			this.css('visibility') === 'hidden' ||
+			!/(INPUT|TEXTAREA)/.test(this[0].nodeName)
+		) {
+			return this;
+		}
+		var selRange, range, stored_range, txt, val,
+			$el = this,
+			el = $el[0],
+			selection = el.ownerDocument.selection,
+			sTop = el.scrollTop,
+			ss = false,
+			supportCaret = true;
+		try {
+			ss = 'selectionStart' in el;
+		} catch (err) {
+			supportCaret = false;
+		}
+		if (supportCaret && typeof start !== 'undefined') {
+			if (!/(email|number)/i.test(el.type)) {
+				if (ss) {
+					el.selectionStart = start;
+					el.selectionEnd = end;
+				} else {
+					selRange = el.createTextRange();
+					selRange.collapse(true);
+					selRange.moveStart('character', start);
+					selRange.moveEnd('character', end - start);
+					selRange.select();
+				}
+			}
+			// must be visible or IE8 crashes; IE9 in compatibility mode works fine - issue #56
+			if (!noFocus && ($el.is(':visible') || $el.css('visibility') !== 'hidden')) {
+				el.focus();
+			}
+			el.scrollTop = sTop;
+			return this;
+		}
+		if (/(email|number)/i.test(el.type)) {
+			// fix suggested by raduanastase (https://github.com/Mottie/Keyboard/issues/105#issuecomment-40456535)
+			start = end = $el.val().length;
+		} else if (ss) {
+			start = el.selectionStart;
+			end = el.selectionEnd;
+		} else if (selection) {
+			if (el.nodeName === 'TEXTAREA') {
+				val = $el.val();
+				range = selection.createRange();
+				stored_range = range.duplicate();
+				stored_range.moveToElementText(el);
+				stored_range.setEndPoint('EndToEnd', range);
+				// thanks to the awesome comments in the rangy plugin
+				start = stored_range.text.replace(/\r/g, '\n').length;
+				end = start + range.text.replace(/\r/g, '\n').length;
+			} else {
+				val = $el.val().replace(/\r/g, '\n');
+				range = selection.createRange().duplicate();
+				range.moveEnd('character', val.length);
+				start = (range.text === '' ? val.length : val.lastIndexOf(range.text));
+				range = selection.createRange().duplicate();
+				range.moveStart('character', -val.length);
+				end = range.text.length;
+			}
+		} else {
+			// caret positioning not supported
+			start = end = (el.value || '').length;
+		}
+		txt = (el.value || '');
+		return {
+			start: start,
+			end: end,
+			text: txt.substring(start, end),
+			replace: function (str) {
+				return txt.substring(0, start) + str + txt.substring(end, txt.length);
+			}
+		};
+	};
+
+	return $keyboard;
+
+}));

Diff do ficheiro suprimidas por serem muito extensas
+ 1 - 0
app/Resources/public/assets/keyboard/dist/js/jquery.keyboard.min.js


Diff do ficheiro suprimidas por serem muito extensas
+ 1 - 0
app/Resources/public/assets/keyboard/dist/js/jquery.mousewheel.min.js


Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
app/Resources/public/assets/keyboard/dist/languages/amh.min.js


+ 1 - 0
app/Resources/public/assets/keyboard/dist/languages/de.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.language.de={language:"Deutsch (German)",display:{a:"✔:Übernehmen (Umschalt+Enter)",accept:"Übernehmen:Übernehmen (Umschalt+Enter)",alt:"AltGr:Alt Graph",b:"←:Rücktaste",bksp:"Rück:Rücktaste",c:"✖:Abbrechen (Esc)",cancel:"Abbrechen:Abbrechen (Esc)",clear:"C:Löschen",combo:"ö:Tottasten umschalten",dec:",:Dezimal",e:"↵:Eingabe",enter:"Enter:Eingabe",lock:"⇩:Feststelltaste",s:"⇧:Umschalttaste",shift:"Umschalt:Umschalttaste",sign:"±:Vorzeichen wechseln",space:"&nbsp;:Leertaste",t:"⇥:Tabulatortaste",tab:"⇥ Tab:Tabulatortaste"},wheelMessage:"Mausrad benutzen, um weitere Tasten zu sehen"};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/languages/es.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.language.es={language:"Español (Spanish)",display:{a:"✔:Acceptar (Cambio+Inscribir)",accept:"Acceptar:Acceptar (Cambio+Inscribir)",alt:"AltGr:Grafemas Alternativos",b:"←:Retroceso",bksp:"Bksp:Retroceso",c:"✖:Cancelar (Esc)",cancel:"Cancelar:Cancelar (Esc)",clear:"C:Vaciar",combo:"ö:Alternar las Teclas Combinados",dec:",:Decimal",e:"↵:Inscribir",enter:"Inscribir:Inscribir",lock:"⇪ Bloq:Mayús",s:"⇧:Cambio",shift:"Cambio:Cambio",sign:"±:Cambiar Signo",space:"&nbsp;:Espacio",t:"⇥:Tab",tab:"⇥ Tab:Tab"},wheelMessage:"Utilice la rueda del mouse para ver otras teclas"};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/languages/fa.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.language.fa={language:"فارسی (Farsi)",display:{a:"✔:تأیید (Shift+Enter)",accept:"تأیید:تأیید (Shift+Enter)",alt:"Lng:Alternate Graphemes",b:"←:⬅ Backspace",bksp:"⬅ Bksp:⬅ Backspace",c:"✖:انصراف (Esc)",cancel:"انصراف:انصراف (Esc)",clear:"C:Clear",combo:"ö:Toggle Combo Keys",dec:".:Decimal",e:"↵:Enter",enter:"Enter:Enter",lock:"⇪ Lock:Caps Lock",s:"⇧:Shift",shift:"Shift:Shift",sign:"±:Change Sign",space:"&nbsp;:Space",t:"⇥:Tab",tab:"⇥ Tab:Tab"},wheelMessage:"Use mousewheel to see other keys",rtl:!0};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/languages/fr.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.language.fr={language:"Français (French)",display:{a:"✔:Valider (Shift+Enter)",accept:"Valider:Valider (Shift+Enter)",alt:"AltGr:Charactère alternatif",b:"←:Suppr arrière",bksp:"←Suppr:Suppr arrière",c:"✖:Annuler",cancel:"Annuler:Annuler (Échap)",clear:"C:Effacer",combo:"ö:Bacsuler les touches combo",dec:".:Decimal",e:"↵:Entrée",enter:"Entrée:Entrée",lock:"⇪ Verr Mag:Verouillage majuscule",s:"⇧:Majuscule",shift:"Maj:Majuscule",sign:"±:Change de signe",space:"&nbsp;:Espace",t:"⇥:Tabulation",tab:"⇥ Tab:Tabulation"},wheelMessage:"Utiliser la molette de la souris pour voir les autres lettres"};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/languages/he.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.language.he={language:"עברית (Hebrew)",display:{a:"✔:אישור (Shift+Enter)",accept:"אישור:אישור (Shift+Enter)",alt:"Alt:תווים נוספים",b:"←:Backspace",bksp:"Bksp:Backspace",c:"✖:ביטול (Esc)",cancel:"ביטול:ביטול (Esc)",clear:"C:ניקוי",combo:"ö:Toggle Combo Keys",dec:".:נקודה עשרונית",e:"↵:Enter",enter:"Enter:Enter",lock:"⇪ Lock:Caps Lock",s:"⇧:Shift",shift:"Shift:Shift",sign:"±:שינוי סימן",space:"&nbsp;:רווח",t:"⇥:Tab",tab:"⇥ Tab:Tab"},wheelMessage:"ניתן להשתמש בגלגלת העכבר כדי לראות מקשים נוספים",rtl:!0};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/languages/hu.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.language.hu={language:"Magyar (Hungarian)",display:{a:"✔:Rendben (Shift+Enter)",accept:"Rendben:Rendben (Shift+Enter)",alt:"AltGr:Alternate Graphemes",b:"←:Backspace",bksp:"Töröl:Backspace",c:"✖:Cancel (Esc)",cancel:"Mégsem:Cancel (Esc)",clear:"C:Clear",combo:"ö:Toggle Combo Keys",dec:".:Decimal",e:"↵:Enter",enter:"Enter:Enter",lock:"⇪ Lock:Caps Lock",s:"⇧:Shift",shift:"Shift:Shift",sign:"±:Change Sign",space:"&nbsp;:Space",t:"⇥:Tab",tab:"⇥ Tab:Tab"},wheelMessage:"Használd az egér görgetőt a többi billentyű átváltáshoz"};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/languages/it.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.language.it={language:"Italiano (Italian)",display:{a:"✔:Accetta (Shift+Enter)",accept:"Accetta:Accetta (Shift+Enter)",alt:"AltGr:Grafemi Alternativi",b:"←:Cancella",bksp:"Canc:Cancella",c:"✖:Annulla (Esc)",cancel:"Annulla:Annulla (Esc)",clear:"C:Pulisci",combo:"ö:Tasti Combinati",dec:",:Decimale",e:"↵:Invio",enter:"Invio:Invio",lock:"⇪ Bloc:Bloc Maiusc",s:"⇧:Maiusc",shift:"Maiusc:Maiusc",sign:"±:Cambia Segno",space:"&nbsp;:Spazio",t:"⇥:Tab",tab:"⇥ Tab:Tab"},wheelMessage:"Usa la rotella del mouse per vedere altri tasti"};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/languages/lv.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.language.lv={language:"Latviešu (Latvian)",display:{a:"✔:Pieņemt (Shift+Enter)",accept:"Pieņemt:Pieņemt (Shift+Enter)",alt:"AltGr:Alternēšanas taustiņš",b:"←:Atpakaļatkāpe",bksp:"Bksp:Atpakaļatkāpe",c:"✖:Atcelt (Esc)",cancel:"Atcelt:Atcelt (Esc)",clear:"C:Clear",combo:"ö:Toggle Combo Keys",dec:".:Decimal",e:"↵:Enter",enter:"Enter:Enter",lock:"⇪ Lock:Caps Lock",s:"⇧:Shift",shift:"Shift:Shift",sign:"±:Change Sign",space:"&nbsp;:Space",t:"⇥:Tab",tab:"⇥ Tab:Tab"},wheelMessage:"Izmanto peles ritenīti, lai apskatītu citus taustiņus",combos:{"'":{c:"ć",C:"Ć",e:"é",E:"É",n:"ń",N:"Ń",o:"ó",O:"Ó",s:"ś",S:"Ś",z:"ź",Z:"Ź"},"¨":{a:"ä",A:"Ä",o:"ö",O:"Ö",u:"ü",U:"Ü"},"°":{a:"å",A:"Å",e:"ė",E:"Ė",g:"ġ",z:"ż",Z:"Ż"}},comboRegex:/([`\'~\^\"ao\u00a8\u00b0])([a-z])/gim};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/languages/my.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.language.my={language:"ဗမာ (Burmese)",display:{a:"✔:Accept (Shift+Enter)",accept:"Accept:Accept (Shift+Enter)",alt:"AltGr:Alternate Graphemes",b:"←:Backspace",bksp:"Bksp:Backspace",c:"✖:Cancel (Esc)",cancel:"Cancel:Cancel (Esc)",clear:"C:ရှင်းလင်းရန်",combo:"ö:Toggle Combo Keys",dec:".:ဒသမ",e:"↵:Enter",enter:"Enter:Enter",lock:"⇪ Lock:Caps Lock",s:"⇧:Shift",shift:"Shift:Shift",sign:"±:Change Sign",space:"&nbsp;:Space",t:"⇥:Tab",tab:"⇥ Tab:Tab"},wheelMessage:"အခြားခလုတ်များကို မြင်ရစေရန် မောက်စ်ဝှီးလ်ကို အသုံးပြုပါ"};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/languages/pl.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.language.pl={language:"Polski (Polish)",display:{a:"✔:Akceptuj (Shift+Enter)",accept:"Accept:Akceptuj (Shift+Enter)",alt:"AltGr:Polskie znaki",b:"←:Cofnij",bksp:"Bksp:Cofnij",c:"✖:Anuluj (Esc)",cancel:"Cancel:Anuluj (Esc)",clear:"C:Czyść",combo:"ö:Klawisze kombo",dec:".:Dziesiętny",e:"↵:Enter",enter:"Enter:Enter",lock:"⇪ Lock:Caps Lock",s:"⇧:Shift",shift:"Shift:Shift",sign:"±:Zmień znak",space:"&nbsp;:Spacja",t:"⇥:Tab",tab:"⇥ Tab:Tab"},wheelMessage:"Użyj rolki aby zobaczyć pozozstałe klawisze"};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/languages/pt.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.language.pt={language:"Português (Portuguese)",display:{a:"✔:Aceitar (Shift+Enter)",accept:"Aceitar:Concluir (Shift+Enter)",alt:"AltGr:Carateres Adicionais/CTRL+ALT",b:"←:Retroceder",bksp:"← Bksp:Retroceder",c:"✖:Cancelar/Escape (Esc)",cancel:"Cancel:Cancelar/Escape(Esc)",clear:"C:Limpar",combo:"ö:Acentuação Automática",dec:".:Decimal",e:"↵:Introduzir/Mudar de Linha",enter:"Enter↵:Introduzir/Mudar de Linha",lock:"⇪ Lock:CapsLock/Maiúsculas",s:"⇧:Shift/Maiúsculas",shift:"⇪ Shift:Maiúsculas-Minúsculas",sign:"±:Mudar Sinal",space:"&nbsp;:Espaço",t:"⇥:Tab/Tabela/Avançar",tab:"⇥ Tab:Tabela/Avançar"},wheelMessage:"Use a roda do rato/navegador para ver mais teclas",comboRegex:/([`\'~\^\"ao\u00b4])([a-z])/gim,combos:{"´":{a:"á",A:"Á",e:"é",E:"É",i:"í",I:"Í",o:"ó",O:"Ó",u:"ú",U:"Ú",y:"ý",Y:"Ý"},"'":{}}};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/languages/ro.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.language.ro={language:"Română (Romanian)",display:{a:"✔:Accept (Shift+Enter)",accept:"Accept:Accept (Shift+Enter)",alt:"AltGr:Alternate Graphemes",b:"←:Backspace",bksp:"Bksp:Backspace",c:"✖:Cancel (Esc)",cancel:"Cancel:Cancel (Esc)",clear:"C:Clear",combo:"ö:Toggle Combo Keys",dec:",:Decimal",e:"↵:Enter",enter:"Enter:Enter",lock:"⇪ Lock:Caps Lock",s:"⇧:Shift",shift:"Shift:Shift",sign:"±:Schimba semnul",space:"&nbsp;:Spatiu",t:"⇥:Tab",tab:"⇥ Tab:Tab"},wheelMessage:"Foloseste rotita mouse-ului pentru a vedea si celelalte caractere"};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/languages/ru.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.language.ru={language:"Русский (Russian)",display:{a:"✔:Сохранить (Shift+Enter)",accept:"Сохранить:Сохранить (Shift+Enter)",alt:"РУС:Русская клавиатура",b:"←:Удалить символ слева",bksp:"⇦:Удалить символ слева",c:"✖:Отменить (Esc)",cancel:"Отменить:Отменить (Esc)",clear:"C:Очистить",combo:"ö:Toggle Combo Keys",dec:",:Decimal",e:"↵:Ввод",enter:"Ввод:Перевод строки",lock:"⇪ Lock:Caps Lock",s:"⇧:Верхний регистр",shift:"⇧:Верхний регистр",sign:"±:Сменить знак",space:"Пробел:",t:"⇥:Tab",tab:"⇥ Tab:Tab"},wheelMessage:"Use mousewheel to see other keys"};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/languages/sq.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.language.sq={language:"Shqip (Albanian)",display:{a:"✔:Prano (Shift+Enter)",accept:"Prano:Prano (Shift+Enter)",alt:"Alt:Alternativ",b:"←:Hapësirën Mbrapa",bksp:"Bksp:Hapësirën Mbrapa",c:"✖:Anuloj (Arratisjes)",cancel:"Anuloj:Anuloj (Arratisjes)",clear:"C:Qartë",combo:"ö:Kombinimi",dec:".:Decimal",e:"↵:Shkruani",enter:"Shkruani:Shkruani",lock:"⇪ Bllokoj:Caps Lock",next:"Next ⇨",prev:"⇦ Prev",s:"⇧:Ndryshim",shift:"Ndryshim:Ndryshim",sign:"±:Ndryshimi Regjistrohu",space:"&nbsp;:Hapësirë",t:"⇥:Tab",tab:"⇥ Tab:Tab"},wheelMessage:"Përdorimi mousewheel për të parë çelësat e tjera",comboRegex:/([`\'~\^\"ao\/])([a-z])/gim,combos:{"/":{d:"đ",D:"Đ",l:"ł",L:"Ł"}}};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/albanian.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["albanian-qwertz"]={name:"Albanian-qwertz",lang:["sq"],normal:["\\ 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} q w e r t z u i o p ç '","a s d f g h j k l ë [ ] {enter}","{shift} < y x c v b n m , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:['| ! " # $ % ^ & * ( ) _ + {bksp}',"{tab} Q W E R T Z U I O P Ç @","A S D F G H J K L Ë { } {enter}","{shift} > Y X C V B N M ; : ? {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["\\ ~ ˇ ^ ˘ ° ˛ ` ˙ ´ ˝ ¨ ¸ {bksp}","{tab} q w € r t z u i o p ÷ ×","ä đ:Shortcut_(/d) Đ:Shortcut_(/D) f g h j ł:Shortcut_(/l) Ł:Shortcut_(/L) $ ß ¤ {enter}","{shift} < y x c @ { } § < > / {shift}","{accept} {alt} {space} {alt} {cancel}"]},jQuery.keyboard.layouts["albanian-qwerty"]={name:"Albanian-qwerty",lang:["sq"],normal:["` 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} q w e r t y u i o p ë '","a s d f g h j k l ; ç # {enter}","{shift} \\ z x c v b n m , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:['¬ ! " § $ % ^ & * ( ) _ + {bksp}',"{tab} Q W E R T Y U I O P Ë @","A S D F G H J K L : Ç ~ {enter}","{shift} ¦ Z X C V B N M < > ? {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["| 1 2 3 4 5 6 { } [ ] - = {bksp}","{tab} q w € r t y u i o p ÷ ×","a s d f g h j k l ; ç # {enter}","{shift} \\ z x c v b n m , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],"alt-shift":['| ! " § $ % ^ & * ( ) _ + {bksp}',"{tab} Q W € R T Y U I O P Ë @","A S D F G H J K L : Ç ~ {enter}","{shift} ¦ Z X C V B N M < > ? {shift}","{accept} {alt} {space} {alt} {cancel}"]};

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
app/Resources/public/assets/keyboard/dist/layouts/arabic.min.js


+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/belarusian.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["belarusian-qwerty"]={name:"belarusian-qwerty",lang:["be"],normal:["` 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} q w e r t y u i o p [ ] \\","a s d f g h j k l ; ' {enter}","{shift} z x c v b n m , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:["~ ! @ # $ % ^ & * ( ) _ + {bksp}","{tab} Q W E R T Y U I O P { } |",'A S D F G H J K L : " {enter}',"{shift} Z X C V B N M < > ? {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["ё 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} й ц у к е н г ш ў з х ' \\","ф ы в а п р о л д ж э {enter}","{shift} я ч с м і т ь б ю . {shift}","{accept} {alt} {space} {alt} {cancel}"],"alt-shift":['Ё ! " № ; € : ? * ( ) _ + {bksp}',"{tab} Й Ц У К Е Н Г Ш Ў З Х ' /","Ф Ы В А П Р О Л Д Ж Э {enter}","{shift} Я Ч С М І Т Ь Б Ю , {shift}","{accept} {alt} {space} {alt} {cancel}"]};

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
app/Resources/public/assets/keyboard/dist/layouts/bengali.min.js


+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/bulgarian.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["bulgarian-qwerty"]={name:"bulgarian-qwerty",lang:["bg"],normal:["` 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} q w e r t y u i o p [ ] \\","a s d f g h j k l ; ' {enter}","{shift} z x c v b n m , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:["~ ! @ # $ % ^ & * ( ) _ + {bksp}","{tab} Q W E R T Y U I O P { } |",'A S D F G H J K L : " {enter}',"{shift} Z X C V B N M < > ? {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["` 1 2 3 4 5 6 7 8 9 0 - . {bksp}","{tab} , у е и ш щ к с д з ц ; (","ь я а о ж г т н в м ч {enter}","{shift} ю й ъ э ф х п р л б {shift}","{accept} {alt} {space} {alt} {cancel}"],"alt-shift":['~ ! ? + " % = : / _ № I V {bksp}',"{tab} ы У Е И Ш Щ К С Д З Ц § )","Ь Я А О Ж Г Т Н В М Ч {enter}","{shift} Ю Й Ъ Э Ф Х П Р Л Б {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/burmese.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts.burmese={name:"burmese",lang:["my"],normal:["ၐ ၁ ၂ ၃ ၄ ၅ ၆ ၇ ၈ ၉ ၀ - = {bksp}","{tab} ဆ တ န မ အ ပ က င သ စ ဟ ဩ ၏","ေ ျ ိ ် ါ ့ ြ ု ူ း ' {enter}","{shift} ဖ ထ ခ လ ဘ ည ာ , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:["ဎ ဍ ၒ ဋ ၓ ၔ ၕ ရ * ( ) _ + {bksp}","{tab} ဈ ဝ ဣ ၎ ဤ ၌ ဥ ၍ ဿ ဏ ဧ ဪ ၑ",'ဗ ှ ီ ္ ွ ံ ဲ ဒ ဓ ဂ " {enter}',"{shift} ဇ ဌ ဃ ဠ ယ ဉ ဦ ၊ ။ ? {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["~ ¡ ² ³ ¤ € ¼ ½ ¾ ‘ ’ ¥ × {bksp}","{tab} ä å é ® þ ü ú í ó ö « » ¬","á ß ð f g h j k ø ¶ ´ {enter}","{shift} æ x © v b ñ µ ç > ¿ {shift}","{accept} {alt} {space} {alt} {cancel}"],"alt-shift":["~ ¹ ² ³ £ € ¼ ½ ¾ ‘ ’ ¥ ÷ {bksp}","{tab} Ä Å É ® Þ Ü Ú Í Ó Ö « » ¦","Ä § Ð F G H J K Ø ° ¨ {enter}","{shift} Æ X ¢ V B Ñ µ Ç . ¿ {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/catalan.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["catalan-qwerty"]={name:"catalan-qwerty",lang:["ca"],normal:["º 1 2 3 4 5 6 7 8 9 0 ' ¡ {bksp}","{tab} q w e r t y u i o p ̀ +","a s d f g h j k l ñ ́ ç {enter}","{shift} < z x c v b n m , . - {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:['ª ! " · $ % & / ( ) = ? ¿ {bksp}',"{tab} Q W E R T Y U I O P ̂ *","A S D F G H J K L Ñ ̈ Ç {enter}","{shift} > Z X C V B N M ; : _ {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["\\ | @ # ̃ 5 ¬ 7 8 9 0 ' ¡ {bksp}","{tab} q w € r t y u i o p [ ]","a s d f g h j k l ñ { } {enter}","{shift} | z x c v b n m , . - {shift}","{accept} {alt} {space} {alt} {cancel}"],"alt-shift":['ª ! " · $ % & / ( ) = ? ¿ {bksp}',"{tab} Q W E R T Y U I O P [ ]","A S D F G H J K L Ñ { } {enter}","{shift} > Z X C V B N M ; : _ {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/chinese.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts.chinese={name:"chinese",lang:["zh"],normal:["€ 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} 手 田 水 口 廿 卜 山 戈 人 心 [ ] \\","日 尸 木 火 土 竹 十 大 中 ; ' {enter}","{shift} Z 難 金 女 月 弓 一 . - / {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:["~ ! @ # $ % ^ & * ) ( _ + {bksp}","{tab} q w e r t y u i o p { } |",'a s d f g h j k l : " {enter}',"{shift} z x c v b n m , < > ? {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["` 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} q w e r t y u i o p [ ] \\","a s d f g h j k l ; ' {enter}","{shift} z x c v b n m , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],"alt-shift":["~ ! @ # $ % ^ & * ( ) _ + {bksp}","{tab} Q W E R T Y U I O P { } |",'A S D F G H J K L : " {enter}',"{shift} Z X C V B N M < > ? {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/danish.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["danish-qwerty"]={name:"danish-qwerty",lang:["da"],normal:["§ 1 2 3 4 5 6 7 8 9 0 + ́ {b}","{tab} q w e r t y u i o p å ¨","a s d f g h j k l æ ø ' {enter}","{shift} < z x c v b n m , . - {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:['½ ! " # ¤ % & / ( ) = ? ̀ {b}',"{tab} Q W E R T Y U I O P Å ^","A S D F G H J K L Æ Ø * {enter}","{shift} > Z X C V B N M ; : _ {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["§ 1 @ £ $ 5 6 { [ ] } + | {b}","{tab} q w € r t y u i o p å ~","a s d f g h j k l æ ø ' {enter}","{shift} \\ z x c v b n µ , . - {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/ethiopic.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts.ethiopic={name:"Amharic",lang:["amh"],normal:["` ፩ ፪ ፫ ፬ ፭ ፮ ፯ ፰ ፱ 0 ፥ = {bksp}","{tab} ቀ ወ ǝ ረ ተ የ u i o ጰ ቈ ኈ \\","a ሰ ደ ፈ ገ ሀ ጸ ከ ለ:Shortcut_(l_+_e_=_ል) ; አ {enter}","{shift} ዘ ኀ ቸ ሸ በ ነ መ ፡ ። / {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:["~ ፲ ፳ ፴ ፵ ፶ ፷ ፸ ፹ ፺ ፻ ፼ + {bksp}","{tab} ቐ ዐ Ǝ ሯ ጠ Y U I O ፐ ጐ ኰ ᎄ",'ā ሠ ጀ ፘ ጘ ሐ ፀ ኸ ዸ እግዚአብሔር፡ " {enter}',"{shift} ዠ ፙ ጨ ፚ ቨ ኘ ᎀ ᎈ ᎌ ለግዚአብሔር፡ {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["` 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} q ʷ e r t y u i o ṗ [ ] \\","a š d f ǧ ḫ j k l ; ʾ {enter}","{shift} ž x č̣ č b ñ m , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],"alt-shift":["~ ! @ # $ % ^ & * ( ) _ + {bksp}","{tab} Q W E R T Y U I O Ṗ { } |","A Š D F Ǧ Ḫ J K L : ʿ {enter}","{shift} Ž X Č̣ Č B Ñ M < > ? {shift}","{accept} {alt} {space} {alt} {cancel}"]};

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
app/Resources/public/assets/keyboard/dist/layouts/french.min.js


+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/german.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["german-qwertz-1"]={name:"german-qwertz-1",lang:["de"],normal:["̂ 1 2 3 4 5 6 7 8 9 0 ß ́ {bksp}","{tab} q w e r t z u i o p ü +","a s d f g h j k l ö ä # {enter}","{shift} < y x c v b n m , . - {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:['° ! " § $ % & / ( ) = ? ̀ {bksp}',"{tab} Q W E R T Z U I O P Ü *","A S D F G H J K L Ö Ä ' {enter}","{shift} > Y X C V B N M ; : _ {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["̂ 1 ² ³ 4 5 6 { [ ] } \\ ́ {bksp}","{tab} @ w € r t z u i o p ü ̃","a s d f g h j k l ö ä # {enter}","{shift} | y x c v b n µ , . - {shift}","{accept} {alt} {space} {alt} {cancel}"]},jQuery.keyboard.layouts["german-qwertz-2"]={name:"german-qwertz-2",lang:["de"],normal:["§ 1 2 3 4 5 6 7 8 9 0 ' ̂ {bksp}","{tab} q w e r t z u i o p ü ̈","a s d f g h j k l ö ä $ {enter}","{shift} < y x c v b n m , . - {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:['° + " * ç % & / ( ) = ? ̀ {bksp}',"{tab} Q W E R T Z U I O P è !","A S D F G H J K L é à £ {enter}","{shift} > Y X C V B N M ; : _ {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["§ | @ # 4 5 ¬ ¦ ¢ 9 0 ́ ̃ {bksp}","{tab} q w € r t z u i o p [ ]","a s d f g h j k l ö { } {enter}","{shift} \\ y x c v b n m , . - {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/hebrew.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["hebrew-qwerty"]={name:"hebrew-qwerty",lang:["he"],normal:["; 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} / ' ק ר א ט ו ן ם פ [ ] \\","ש ד ג כ ע י ח ל ך ף , {enter}","{shift} ז ס ב ה נ מ צ ת ץ . {shift}","{accept} {alt} {space} {alt} {cancel}"],"alt-shift":["~ ! @ # $ % ^ & * ( ) _ + {bksp}","{tab} Q W E R T Y U I O P { } |",'A S D F G H J K L : " {enter}',"{shift} Z X C V B N M < > ? {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["` 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} q w e r t y u i o p [ ] \\","a s d f g h j k l ; ' {enter}","{shift} z x c v b n m , . / {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/hindi.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts.hindi={name:"hindi",lang:["hi"],normal:["` ऍ ॅ ्र र् ज्ञ त्र क्ष श्र ९ ० - ृ {bksp}","{tab} ौ ै ा ी ू ब ह ग द ज ड ़ ॉ \\","ो े ् ि ु प र क त च ट {enter}","{shift} ं म न व ल स , . य {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:["~ १ २ ३ ४ ५ ६ ७ ८ ९ ० ः ऋ {bksp}","{tab} औ ऐ आ ई ऊ भ ङ घ ध झ ढ ञ ऑ","ओ ए अ इ उ फ ऱ ख थ छ ठ {enter}",'{shift} "" ँ ण न व ळ श ष । य़ {shift}',"{accept} {alt} {space} {alt} {cancel}"],alt:["` 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} q w e r t y u i o p [ ] \\","a s d f g h j k l ; ' {enter}","{shift} z x c v b n m , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],"alt-shift":["~ ! @ # $ % ^ & * ( ) _ + {bksp}","{tab} Q W E R T Y U I O P { } |",'A S D F G H J K L : " {enter}',"{shift} Z X C V B N M < > ? {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/hungarian.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["hungarian-qwertz-1"]={name:"hungarian-qwertz-1",lang:["hu"],default:["0 1 2 3 4 5 6 7 8 9 ö ü ó ű {bksp}","{tab} q w e r t z u i o p ő ú","a s d f g h j k l é á {enter}","{shift} í y x c v b n m , . - {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:["§ ' \" + ! % / = ( ) Ö Ü Ó Ű {bksp}","{tab} Q W E R T Z U I O P Ő Ú","A S D F G H J K L É Á {enter}","{shift} Í Y X C V B N M ; : _ {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["{sp:1} ~ ˇ ^ ˘ ° ˛ ` ˙ ´ ˝ ¨ ¸ ¤ {bksp}","{tab} \\ | Ä {sp:1} {sp:1} {sp:1} € Í {sp:1} {sp:1} ÷ ×","ä đ Đ [ ] {sp:1} í ł Ł $ ß {enter}","{shift} < > # & @ { } < ; > * {shift}","{accept} {alt} {space} {alt} {cancel}"]},jQuery.keyboard.layouts["hungarian-qwertz-2"]={name:"hungarian-qwertz-2",lang:["hu"],default:["0 1 2 3 4 5 6 7 8 9 ö ü ó {bksp}","{tab} q w e r t z u i o p ő ú","a s d f g h j k l é á ű {enter}","{shift} í y x c v b n m , . - {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:["§ ' \" + ! % / = ( ) Ö Ü Ó {bksp}","{tab} Q W E R T Z U I O P Ő Ú","A S D F G H J K L É Á Ű {enter}","{shift} Í Y X C V B N M ; : _ {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["{sp:1} ~ ˇ ^ ˘ ° ˛ ` ˙ ´ ˝ ¨ ¸ {bksp}","{tab} \\ | Ä {sp:1} {sp:1} {sp:1} € Í {sp:1} {sp:1} ÷ ×","ä đ Đ [ ] {sp:1} í ł Ł $ ß ¤ {enter}","{shift} < > # & @ { } < ; > * {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/hungarianansi.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["hungarianansi-qwertz-1"]={name:"hungarianansi-qwertz-1",lang:["hu"],normal:["0 1 2 3 4 5 6 7 8 9 ö ü ó ű {bksp}","{tab} q w e r t z u i o p ő ú","a s d f g h j k l é á {enter}","{shift} í y x c v b n m , . - {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:["§ ' \" + ! % / = ( ) Ö Ü Ó Ű {bksp}","{tab} Q W E R T Z U I O P Ő Ú","A S D F G H J K L É Á {enter}","{shift} Í Y X C V B N M ; : _ {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["{sp:1} ~ ˇ ^ ˘ ° ˛ ` ˙ ´ ˝ ¨ ¸ ¤ {bksp}","{tab} \\ | Ä {sp:1} {sp:1} {sp:1} € Í {sp:1} {sp:1} ÷ ×","ä đ Đ [ ] {sp:1} í ł Ł $ ß {enter}","{shift} < > # & @ { } < ; > * {shift}","{accept} {alt} {space} {alt} {cancel}"]},jQuery.keyboard.layouts["hungarianansi-qwertz-2"]={name:"hungarianansi-qwertz-2",lang:["hu"],normal:["0 1 2 3 4 5 6 7 8 9 ö ü ó {bksp}","{tab} q w e r t z u i o p ő ú","a s d f g h j k l é á ű {enter}","{shift} í y x c v b n m , . - {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:["§ ' \" + ! % / = ( ) Ö Ü Ó {bksp}","{tab} Q W E R T Z U I O P Ő Ú","A S D F G H J K L É Á Ű {enter}","{shift} Í Y X C V B N M ; : _ {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["{sp:1} ~ ˇ ^ ˘ ° ˛ ` ˙ ´ ˝ ¨ ¸ {bksp}","{tab} \\ | Ä {sp:1} {sp:1} {sp:1} € Í {sp:1} {sp:1} ÷ ×","ä đ Đ [ ] {sp:1} í ł Ł $ ß ¤ {enter}","{shift} < > # & @ { } < ; > * {shift}","{accept} {alt} {space} {alt} {cancel}"]};

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
app/Resources/public/assets/keyboard/dist/layouts/japanese.min.js


Diff do ficheiro suprimidas por serem muito extensas
+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/keyboard-layouts-combined.min.js


Diff do ficheiro suprimidas por serem muito extensas
+ 2 - 0
app/Resources/public/assets/keyboard/dist/layouts/keyboard-layouts-greywyvern.min.js


Diff do ficheiro suprimidas por serem muito extensas
+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/keyboard-layouts-microsoft.min.js


+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/latvian.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["latvian-qwerty"]={name:"latvian-qwerty",lang:["lv"],normal:["` 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} q w e r t y u i o p [ ] °","a s d f g h j k l ; ' {enter}","{shift} z x c v b n m , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:["~ ! @ # $ % ^ & * ( ) _ + {bksp}","{tab} Q W E R T Y U I O P { } |",'A S D F G H J K L : " {enter}',"{shift} Z X C V B N M < > ? {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["¬ 1 « » € 5 ’ 7 8 9 0 – = {bksp}","{tab} q w ē ŗ t y ū ī ō p [ ] °","ā š d f ģ h j ķ ļ ; ´ {enter}","{shift} ž x č v b ņ m , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],"alt-shift":["~ 1 2 3 4 § « 7 ± × 0 — = {bksp}","{tab} Q W Ē Ŗ T Y Ū Ī Ō P { } |","Ā Š D F Ģ H J Ķ Ļ : ¨ {enter}","{shift} Ž X Č V B Ņ M < > ? {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/mongolian.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts.mongolian={name:"mongolian",lang:["mn"],normal:['= № - " ₮ : . _ , % ? е щ {bksp}',"{tab} ф ц у ж э н г ш ү з к ъ \\","й ы б ө а х р о л д п {enter}","{shift} я ч ё с м и т ь в ю {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:["+ 1 2 3 4 5 6 7 8 9 0 Е Щ {bksp}","{tab} Ф Ц У Ж Э Н Г Ш Ү З К Ъ |","Й Ы Б Ө А Х Р О Л Д П {enter}","{shift} Я Ч Ё С М И Т Ь В Ю {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["` 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} q w e r t y u i o p [ ] \\","a s d f g h j k l ; ' {enter}","{shift} z x c v b n m , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],"alt-shift":["~ ! @ # $ % ^ & * ( ) _ + {bksp}","{tab} Q W E R T Y U I O P { } |",'A S D F G H J K L : " {enter}',"{shift} Z X C V B N M < > ? {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Albanian.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["ms-Albanian"]={name:"ms-Albanian",lang:["sq"],normal:["\\ 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} q w e r t z u i o p ç @","a s d f g h j k l ë [ ] {enter}","{shift} < y x c v b n m , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:['| ! " # $ % ^ & * ( ) _ + {bksp}',"{tab} Q W E R T Z U I O P Ç '","A S D F G H J K L Ë { } {enter}","{shift} > Y X C V B N M ; : ? {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["{empty} ~ ˇ ^ ˘ ° ˛ ` ˙ ´ ˝ ¨ ¸ {bksp}","{tab} \\ | {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} ÷ ×","{empty} đ Đ [ ] {empty} {empty} ł Ł $ ß ¤ {enter}","{shift} {empty} {empty} {empty} {empty} @ { } § < > {empty} {shift}","{accept} {alt} {space} {alt} {cancel}"]};

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Arabic.min.js


+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Armenian.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["ms-Armenian Eastern"]={name:"ms-Armenian Eastern",lang:["hy-e"],normal:["՝ : ձ յ ՛ , - . « » օ ռ ժ {bksp}","{tab} խ ւ է ր տ ե ը ի ո պ չ ջ '","ա ս դ ֆ ք հ ճ կ լ թ փ {enter}","{shift} ' զ ց գ վ բ ն մ շ ղ / {shift}","{accept} {space} {cancel}"],shift:["՜ 1 Ձ Յ 3 4 9 և ( ) Օ Ռ Ժ {bksp}","{tab} Խ Ւ Է Ր Տ Ե Ը Ի Ո Պ Չ Ջ ՞","Ա Ս Դ Ֆ Ք Հ Ճ Կ Լ Թ Փ {enter}","{shift} ՞ Զ Ց Գ Վ Բ Ն Մ Շ Ղ / {shift}","{accept} {space} {cancel}"]},jQuery.keyboard.layouts["ms-Armenian Western"]={name:"ms-Armenian Western",lang:["hy-w"],normal:["՝ : ձ յ ՛ , - . « » օ ռ ժ {bksp}","{tab} խ վ է ր դ ե ը ի ո բ չ ջ '","ա ս տ ֆ կ հ ճ ք լ թ փ {enter}","{shift} ' զ ց գ ւ պ ն մ շ ղ / {shift}","{accept} {space} {cancel}"],shift:["՜ 1 Ձ Յ 3 4 9 և ( ) Օ Ռ Ժ {bksp}","{tab} Խ Վ Է Ր Դ Ե Ը Ի Ո Բ Չ Ջ ՞","Ա Ս Տ Ֆ Կ Հ Ճ Ք Լ Թ Փ {enter}","{shift} ՞ Զ Ց Գ Ւ Պ Ն Մ Շ Ղ / {shift}","{accept} {space} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Assamese.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["ms-Assamese-INSCRIPT"]={name:"ms-Assamese-INSCRIPT",lang:["as"],normal:["॥ ১ ২ ৩ ৪ ৫ ৬ ৭ ৮ ৯ ০ - ৃ {bksp}","{tab} ৌ ৈ া ী ূ ব হ গ দ জ ড ় {empty}","ো ে ্ ি ু প ৰ ক ত চ ট {enter}","{shift} {empty} {empty} ং ম ন ৱ ল স , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:["{empty} ! @ ্ৰ ৰ্ জ্ঞ ত্ৰ ক্ষ শ্ৰ ( ) ঃ ঋ {bksp}","{tab} ঔ ঐ আ ঈ ঊ ভ ঙ ঘ ধ ঝ ঢ ঞ {empty}","ও এ অ ই উ ফ {empty} খ থ ছ ঠ {enter}","{shift} {empty} {empty} ঁ ণ {empty} {empty} {empty} শ ষ । / {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["` 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} q w e r t y u i o p [ ] \\","a s d f g h j k l ; ' {enter}","{shift} z x c v b n m , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],"alt-shift":["~ ! @ # $ % ^ & * ( ) _ + {bksp}","{tab} Q W E R T Y U I O P { } |",'A S D F G H J K L : " {enter}',"{shift} Z X C V B N M < > ? {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Azeri.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["ms-Azeri Cyrillic"]={name:"ms-Azeri Cyrillic",lang:["az"],normal:["` 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} ј ү у к е н г ш һ з х ҹ \\","ф ы в а п р о л д ж ҝ {enter}","{shift} \\ ә ч с м и т ғ б ө / {shift}","{accept} {space} {cancel}"],shift:['~ ! " № ; % : ? * ( ) _ + {bksp}',"{tab} Ј Ү У К Е Н Г Ш Һ З Х Ҹ /","Ф Ы В А П Р О Л Д Ж Ҝ {enter}","{shift} | Ә Ч С М И Т Ғ Б Ө / {shift}","{accept} {space} {cancel}"]},jQuery.keyboard.layouts["ms-Azeri Latin"]={name:"ms-Azeri Latin",lang:["az"],normal:["` 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} q ü e r t y u i o p ö ğ \\","a s d f g h j k l ı ə {enter}","{shift} \\ z x c v b n m ç ş / {shift}","{accept} {space} {cancel}"],shift:['~ ! " Ⅶ ; % : ? * ( ) _ + {bksp}',"{tab} Q Ü E R T Y U İ O P Ö Ğ /","A S D F G H J K L I Ə {enter}","{shift} / Z X C V B N M Ç Ş / {shift}","{accept} {space} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Bashkir.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["ms-Bashkir"]={name:"ms-Bashkir",lang:["ba"],normal:["ә ! ө ҡ ғ ҫ : ҙ һ ? № - ү {bksp}","{tab} й ц у к е н г ш щ з х ъ ң","ф ы в а п р о л д ж э {enter}","{shift} я ч с м и т ь б ю / {shift}","{accept} {space} {cancel}"],shift:['Ә " Ө Ҡ Ғ Ҫ ; Ҙ Һ ( ) % Ү {bksp}',"{tab} Й Ц У К Е Н Г Ш Щ З Х Ъ Ң","Ф Ы В А П Р О Л Д Ж Э {enter}","{shift} Я Ч С М И Т Ь Б Ю / {shift}","{accept} {space} {cancel}"]},jQuery.keyboard.layouts["ms-Bosnian (Cyrillic)"]={name:"ms-Bosnian (Cyrillic)",lang:["bs"],normal:["` 1 2 3 4 5 6 7 8 9 0 ' + {bksp}","{tab} љ њ е р т з у и о п ш ђ ж","а с д ф г х ј к л ч ћ {enter}","{shift} < ѕ џ ц в б н м , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:['~ ! " # $ % & / ( ) = ? * {bksp}',"{tab} Љ Њ Е Р Т З У И О П Ш Ђ Ж","А С Д Ф Г Х Ј К Л Ч Ћ {enter}","{shift} > Ѕ Џ Ц В Б Н М ; : / {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["{empty} {empty} {empty} ^ {empty} ° {empty} {empty} {empty} {empty} {empty} {empty} {empty} {bksp}","{tab} \\ | € {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty}","{empty} {empty} {empty} [ ] {empty} {empty} {empty} {empty} {empty} {empty} {enter}","{shift} {empty} {empty} {empty} {empty} @ { } § < > {empty} {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Belarusian.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["ms-Belarusian"]={name:"ms-Belarusian",lang:["be"],normal:["ё 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} й ц у к е н г ш ў з х ' \\","ф ы в а п р о л д ж э {enter}","{shift} \\ я ч с м і т ь б ю / {shift}","{accept} {space} {cancel}"],shift:['Ё ! " № ; % : ? * ( ) _ + {bksp}',"{tab} Й Ц У К Е Н Г Ш Ў З Х ' /","Ф Ы В А П Р О Л Д Ж Э {enter}","{shift} / Я Ч С М І Т Ь Б Ю / {shift}","{accept} {space} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Belgian.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["ms-Belgian (Comma)"]={name:"ms-Belgian (Comma)",lang:["nl","fr","de"],normal:["² & é \" ' ( § è ! ç à ) - {bksp}","{tab} a z e r t y u i o p ^ $ µ","q s d f g h j k l m ù {enter}","{shift} < w x c v b n , ; : / {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:["³ 1 2 3 4 5 6 7 8 9 0 ° _ {bksp}","{tab} A Z E R T Y U I O P ¨ * £","Q S D F G H J K L M % {enter}","{shift} > W X C V B N ? . / / {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["{empty} | @ # { [ ^ {empty} {empty} { } {empty} {empty} {bksp}","{tab} {empty} {empty} € {empty} {empty} {empty} {empty} {empty} {empty} {empty} [ ] {empty}","{empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} ´ {enter}","{shift} \\ {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {shift}","{accept} {alt} {space} {alt} {cancel}"]},jQuery.keyboard.layouts["ms-Belgian French"]={name:"ms-Belgian French",lang:["nl-fr","fr"],normal:["² & é \" ' ( § è ! ç à ) - {bksp}","{tab} a z e r t y u i o p ^ $ µ","q s d f g h j k l m ù {enter}","{shift} < w x c v b n , ; : / {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:["³ 1 2 3 4 5 6 7 8 9 0 ° _ {bksp}","{tab} A Z E R T Y U I O P ¨ * £","Q S D F G H J K L M % {enter}","{shift} > W X C V B N ? . / / {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["{empty} | @ # { [ ^ {empty} {empty} { } {empty} {empty} {bksp}","{tab} {empty} {empty} € {empty} {empty} {empty} {empty} {empty} {empty} {empty} [ ] {empty}","{empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} ´ {enter}","{shift} \\ {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {shift}","{accept} {alt} {space} {alt} {cancel}"]};

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Bengali.min.js


+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Bulgarian.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["ms-Bulgarian (Phonetic Traditional)"]={name:"ms-Bulgarian (Phonetic Traditional)",lang:["bg"],normal:["ч 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} я в е р т ъ у и о п ш щ ю","а с д ф г х й к л ; ' {enter}","{shift} ю з ь ц ж б н м , . / {shift}","{accept} {space} {cancel}"],shift:["Ч ! @ № $ % € § * ( ) _ + {bksp}","{tab} Я В Е Р Т Ъ У И О П Ш Щ Ю",'А С Д Ф Г Х Й К Л : " {enter}',"{shift} Ю З ѝ Ц Ж Б Н М < > / {shift}","{accept} {space} {cancel}"]},jQuery.keyboard.layouts["ms-Bulgarian (Phonetic)"]={name:"ms-Bulgarian (Phonetic)",lang:["bg"],normal:["ю 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} ч ш е р т ъ у и о п я щ ь","а с д ф г х й к л ; ' {enter}","{shift} ѝ з ж ц в б н м , . / {shift}","{accept} {space} {cancel}"],shift:["Ю ! @ № $ % € § * ( ) – + {bksp}","{tab} Ч Ш Е Р Т Ъ У И О П Я Щ ѝ",'А С Д Ф Г Х Й К Л : " {enter}',"{shift} Ѝ З Ж Ц В Б Н М „ “ / {shift}","{accept} {space} {cancel}"]},jQuery.keyboard.layouts["ms-Bulgarian (Typewriter)"]={name:"ms-Bulgarian (Typewriter)",lang:["bg"],normal:["` 1 2 3 4 5 6 7 8 9 0 - . {bksp}","{tab} , у е и ш щ к с д з ц ; (","ь я а о ж г т н в м ч {enter}","{shift} \\ ю й ъ э ф х п р л / {shift}","{accept} {space} {cancel}"],shift:['~ ! ? + " % = : / _ № І V {bksp}',"{tab} ы У Е И Ш Щ К С Д З Ц § )","Ь Я А О Ж Г Т Н В М Ч {enter}","{shift} | Ю Й Ъ Э Ф Х П Р Л / {shift}","{accept} {space} {cancel}"]};

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Canadian.min.js


+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Chinese.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["ms-Chinese Bopomofo IME"]={name:"ms-Chinese Bopomofo IME",lang:["zh"],normal:["€ ㄅ ㄉ ˇ ˋ ㄓ ˊ ˙ ㄚ ㄞ ㄢ ㄦ = {bksp}","{tab} ㄆ ㄊ ㄍ ㄐ ㄔ ㄗ ㄧ ㄛ ㄟ ㄣ [ ] \\","ㄇ ㄋ ㄎ ㄑ ㄕ ㄘ ㄨ ㄜ ㄠ ㄤ ' {enter}","ㄈ ㄌ ㄏ ㄒ ㄖ ㄙ ㄩ ㄝ ㄡ ㄥ","{accept} {alt} {space} {alt} {cancel}"],alt:["` 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} q w e r t y u i o p [ ] \\","a s d f g h j k l ; ' {enter}","{shift} z x c v b n m , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],"alt-shift":["~ ! @ # $ % ^ & * ( ) _ + {bksp}","{tab} Q W E R T Y U I O P { } |",'A S D F G H J K L : " {enter}',"{shift} Z X C V B N M < > ? {shift}","{accept} {alt} {space} {alt} {cancel}"]},jQuery.keyboard.layouts["ms-Chinese ChaJei IME"]={name:"ms-Chinese ChaJei IME",lang:["zh"],normal:["€ 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} 手 田 水 口 廿 卜 山 戈 人 心 [ ] \\","日 尸 木 火 土 竹 十 大 中 ; ' {enter}","Z 難 金 女 月 弓 一 , . /","{accept} {alt} {space} {alt} {cancel}"],alt:["` 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} q w e r t y u i o p [ ] \\","a s d f g h j k l ; ' {enter}","{shift} z x c v b n m , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],"alt-shift":["~ ! @ # $ % ^ & * ( ) _ + {bksp}","{tab} Q W E R T Y U I O P { } |",'A S D F G H J K L : " {enter}',"{shift} Z X C V B N M < > ? {shift}","{accept} {alt} {space} {alt} {cancel}"]};

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Czech.min.js


+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Danish.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["ms-Danish"]={name:"ms-Danish",lang:["da"],normal:["½ 1 2 3 4 5 6 7 8 9 0 + ´ {bksp}","{tab} q w e r t y u i o p å ¨","a s d f g h j k l æ ø '  {enter}","{shift} < z x c v b n m , . - {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:['§ ! " # ¤ % & / ( ) = ? ` {bksp}',"{tab} Q W E R T Y U I O P Å ^","A S D F G H J K L Æ Ø *  {enter}","{shift} > Z X C V B N M ; : _ {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["{empty} {empty} @ £ $ € {empty} { [ ] } {empty} | {bksp}","{tab} {empty} {empty} € {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} ~","{empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {enter}","{shift} \\ {empty} {empty} {empty} {empty} {empty} {empty} µ {empty} {empty} {empty} {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Devanagari.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["ms-Devanagari - INSCRIPT"]={name:"ms-Devanagari - INSCRIPT",lang:["hi","ne","mr","kok","bodo","mai"],normal:["ॊ 1 2 3 4 5 6 7 8 9 0 - ृ {bksp}","{tab} ौ ै ा ी ू ब ह ग द ज ड ़ ॉ","ो े ् ि ु प र क त च ट {enter}","{shift} ॉ ॆ ं म न व ल स , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:["ऒ ऍ ॅ ्र र् ज्ञ त्र क्ष श्र ( ) ः ऋ {bksp}","{tab} औ ऐ आ ई ऊ भ ङ घ ध झ ढ ञ ऑ","ओ ए अ इ उ फ ऱ ख थ छ ठ {enter}","{shift} ऑ ऎ ँ ण ऩ ऴ ळ श ष । / {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["{empty} १ २ ३ ४ ५ ६ ७ ८ ९ ० {empty} ॄ {bksp}","{tab} {empty} {empty} {empty} ॣ {empty} {empty} {empty} ग़ {empty} ज़ ड़ {empty} {empty}","{empty} {empty} {empty} ॢ {empty} {empty} {empty} क़ {empty} ॒ {empty} {enter}","{shift} {empty} ॓ {empty} ॔ {empty} {empty} {empty} {empty} ॰ ॥ {empty} {shift}","{accept} {alt} {space} {alt} {cancel}"],"alt-shift":["{empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} ॠ {bksp}","{tab} {empty} {empty} {empty} ॡ {empty} {empty} {empty} {empty} {empty} {empty} ढ़ {empty} {empty}","{empty} {empty} {empty} ऌ {empty} फ़ {empty} ख़ {empty} {empty} ॑ {enter}","{shift} {empty} {empty} ॐ {empty} {empty} {empty} {empty} {empty} {empty} ऽ {empty} {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Divehi.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["ms-Divehi Phonetic"]={name:"ms-Divehi Phonetic",lang:["dv"],normal:["` 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} ް އ ެ ރ ތ ޔ ު ި ޮ ޕ ] [ \\","ަ ސ ދ ފ ގ ހ ޖ ކ ލ ؛ ' {enter}","{shift} \\ ޒ × ޗ ވ ބ ނ މ ، . / {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:["~ ! @ # $ % ^ & * ) ( _ + {bksp}","{tab} ޤ ޢ ޭ ޜ ޓ ޠ ޫ ީ ޯ ÷ } { |",'ާ ށ ޑ ﷲ ޣ ޙ ޛ ޚ ޅ : " {enter}',"{shift} | ޡ ޘ ޝ ޥ ޞ ޏ ޟ > < / {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["{empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {bksp}","{tab} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty}","{empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} ; {empty} {enter}","{shift} {empty} {empty} {empty} {empty} {ZWJ} {ZWNJ} {LRM} {RLM} , {empty} {empty} {shift}","{accept} {alt} {space} {alt} {cancel}"]},jQuery.keyboard.layouts["ms-Divehi Typewriter"]={name:"ms-Divehi Typewriter",lang:["dv"],normal:["` 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} ޫ ޮ ާ ީ ޭ ގ ރ މ ތ ހ ލ [ ]","ި ު ް ަ ެ ވ އ ނ ކ ފ ﷲ {enter}","{shift} \\ ޒ ޑ ސ ޔ ޅ ދ ބ ށ ޓ / {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:["~ ! @ # $ % ^ & * ) ( _ + {bksp}","{tab} × ’ “ / : ޤ ޜ ޣ ޠ ޙ ÷ { }",'< > . ، " ޥ ޢ ޘ ޚ ޡ ؛ {enter}',"{shift} | ޖ ޕ ޏ ޗ ޟ ޛ ޝ \\ ޞ / {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["{empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {bksp}","{tab} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty}","{empty} {empty} {empty} , {empty} {empty} {empty} {empty} {empty} {empty} ; {enter}","{shift} {empty} {empty} {empty} {empty} {ZWJ} {ZWNJ} {LRM} {RLM} {empty} {empty} {empty} {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Dutch.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["ms-Dutch"]={name:"ms-Dutch",lang:["nl"],normal:["@ 1 2 3 4 5 6 7 8 9 0 / ° {bksp}","{tab} q w e r t y u i o p ¨ * {enter}","a s d f g h j k l + ´ < ","{shift} ] z x c v b n m , . - {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:["§ ! \" # $ % & _ ( ) ' ? ~ {bksp}","{tab} Q W E R T Y U I O P ^ | {enter}","A S D F G H J K L ± ` > ","{shift} [ Z X C V B N M ; : = {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["¬ ¹ ² ³ ¼ ½ ¾ £ { } {empty} \\ ¸ {bksp}","{tab} {empty} {empty} € ¶ {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {enter}","{empty} ß {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} ","{shift} ¦ « » ¢ {empty} {empty} {empty} µ {empty} · {empty} {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Estonian.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["ms-Estonian"]={name:"ms-Estonian",lang:["et"],normal:["ˇ 1 2 3 4 5 6 7 8 9 0 + ´ {bksp}","{tab} q w e r t y u i o p ü õ '","a s d f g h j k l ö ä {enter}","{shift} < z x c v b n m , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:['~ ! " # ¤ % & / ( ) = ? ` {bksp}',"{tab} Q W E R T Y U I O P Ü Õ *","A S D F G H J K L Ö Ä {enter}","{shift} > Z X C V B N M ; : / {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["{empty} {empty} @ £ $ € {empty} { [ ] } \\ {empty} {bksp}","{tab} {empty} {empty} € {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} § ½","{empty} š {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} ^ {enter}","{shift} | ž {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {shift}","{accept} {alt} {space} {alt} {cancel}"],"alt-shift":["{empty} {empty} @ £ $ {empty} {empty} { [ ] } \\ {empty} {bksp}","{tab} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} § ½","{empty} Š {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} ^ {enter}","{shift} | Ž {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Faeroese.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["ms-Faroese"]={name:"ms-Faroese",lang:["fo"],normal:["½ 1 2 3 4 5 6 7 8 9 0 + ´ {bksp}","{tab} q w e r t y u i o p å ð {enter}","a s d f g h j k l æ ø ' ","{shift} < z x c v b n m , . - {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:['§ ! " # ¤ % & / ( ) = ? ` {bksp}',"{tab} Q W E R T Y U I O P Å Ð {enter}","A S D F G H J K L Æ Ø * ","{shift} > Z X C V B N M ; : _ {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["{empty} {empty} @ £ $ € {empty} { [ ] } {empty} | {bksp}","{tab} {empty} {empty} € {empty} {empty} {empty} {empty} {empty} {empty} {empty} ¨ ~ {enter}","{empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} ^ {empty} ","{shift} \\ {empty} {empty} {empty} {empty} {empty} {empty} µ {empty} {empty} {empty} {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Finnish.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["ms-Finnish"]={name:"ms-Finnish",lang:["fi"],normal:["§ 1 2 3 4 5 6 7 8 9 0 + ´ {bksp}","{tab} q w e r t y u i o p å ¨ {enter}","a s d f g h j k l ö ä ' ","{shift} < z x c v b n m , . - {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:['½ ! " # ¤ % & / ( ) = ? ` {bksp}',"{tab} Q W E R T Y U I O P Å ^ {enter}","A S D F G H J K L Ö Ä * ","{shift} > Z X C V B N M ; : _ {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["{empty} {empty} @ £ $ € {empty} { [ ] } \\ {empty} {bksp}","{tab} {empty} {empty} € {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} ~ {enter}","{empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} ","{shift} | {empty} {empty} {empty} {empty} {empty} {empty} µ {empty} {empty} {empty} {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-French.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["ms-French"]={name:"ms-French",lang:["fr"],normal:["² & é \" ' ( - è _ ç à ) = {bksp}","{tab} a z e r t y u i o p ^ $","q s d f g h j k l m ù * {enter}","{shift} < w x c v b n , ; : ! {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:["{empty} 1 2 3 4 5 6 7 8 9 0 ° + {bksp}","{tab} A Z E R T Y U I O P ¨ £","Q S D F G H J K L M % µ {enter}","{shift} > W X C V B N ? . / § {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["{empty} {empty} ~ # { [ | ` \\ ^ @ ] } {bksp}","{tab} {empty} {empty} € {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} ¤","{empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {enter}","{shift} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {shift}","{accept} {alt} {space} {alt} {cancel}"]};

+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Gaelic.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["ms-Gaelic"]={name:"ms-Gaelic",lang:["gd"],normal:["` 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} q w e r t y u i o p [ ]","a s d f g h j k l ; ' # {enter}","{shift} \\ z x c v b n m , . / {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:['` ! " £ $ % ^ & * ( ) _ + {bksp}',"{tab} Q W E R T Y U I O P { }","A S D F G H J K L : @ ~ {enter}","{shift} | Z X C V B N M < > ? {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["¦ {empty} {empty} {empty} € {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {bksp}","{tab} {empty} {empty} é {empty} {empty} ý ú í ó {empty} {empty} {empty}","á {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} ' {empty} {enter}","{shift} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {shift}","{accept} {alt} {space} {alt} {cancel}"],"alt-shift":["¬ {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {bksp}","{tab} {empty} {empty} É {empty} {empty} Ý Ú Í Ó {empty} {empty} {empty}","Á {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {enter}","{shift} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {shift}","{accept} {alt} {space} {alt} {cancel}"]};

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Georgian.min.js


+ 1 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-German.min.js

@@ -0,0 +1 @@
+jQuery.keyboard.layouts["ms-German"]={name:"ms-German",lang:["de"],normal:["^ 1 2 3 4 5 6 7 8 9 0 ß ´ {bksp}","{tab} q w e r t z u i o p ü +","a s d f g h j k l ö ä # {enter}","{shift} < y x c v b n m , . - {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:['° ! " § $ % & / ( ) = ? ` {bksp}',"{tab} Q W E R T Z U I O P Ü *","A S D F G H J K L Ö Ä ' {enter}","{shift} > Y X C V B N M ; : _ {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["{empty} {empty} ² ³ {empty} {empty} {empty} { [ ] } \\ {empty} {bksp}","{tab} @ {empty} € {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} ~","{empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {enter}","{shift} | {empty} {empty} {empty} {empty} {empty} {empty} µ {empty} {empty} {empty} {shift}","{accept} {alt} {space} {alt} {cancel}"]},jQuery.keyboard.layouts["ms-German (IBM)"]={name:"ms-German (IBM)",lang:["de"],normal:["^ 1 2 3 4 5 6 7 8 9 0 ß ´ {bksp}","{tab} q w e r t z u i o p ü +","a s d f g h j k l ö ä # {enter}","{shift} < y x c v b n m , . - {shift}","{accept} {alt} {space} {alt} {cancel}"],shift:['° ! " § $ % & / ( ) = ? ` {bksp}',"{tab} Q W E R T Z U I O P Ü *","A S D F G H J K L Ö Ä ' {enter}","{shift} > Y X C V B N M ; : _ {shift}","{accept} {alt} {space} {alt} {cancel}"],alt:["{empty} {empty} ² ³ {empty} {empty} {empty} { [ ] } \\ {empty} {bksp}","{tab} @ {empty} € {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} ~","{empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {empty} {enter}","{shift} | {empty} {empty} {empty} {empty} {empty} {empty} µ {empty} {empty} {empty} {shift}","{accept} {alt} {space} {alt} {cancel}"]};

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
app/Resources/public/assets/keyboard/dist/layouts/ms-Greek.min.js


Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff