├── .gitignore
├── LICENSE-MIT
├── demo.html
├── jquery.onScreenKeyboard.js
├── jquery.onScreenKeyboard.min.js
├── onScreenKeyboard.css
├── package.json
└── readme.md
/.gitignore:
--------------------------------------------------------------------------------
1 | jquery.ui.draggable.js
2 |
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015 Chris Cook
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | On Screen Keyboard demo
8 |
9 |
33 |
34 |
35 |
36 |
37 |
43 |
44 |
45 |
46 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/jquery.onScreenKeyboard.js:
--------------------------------------------------------------------------------
1 | /**
2 | * On-Screen Keyboard jQuery Plugin
3 | *
4 | * Provides users with a fluid-width on-screen keyboard.
5 | *
6 | * @author Chris Cook
7 | * @license MIT
8 | * @version 1.0.2
9 | */
10 |
11 | (function ($) {
12 |
13 | 'use strict';
14 |
15 | $.fn.onScreenKeyboard = function (options) {
16 |
17 | var settings = $.extend({
18 | draggable: false,
19 | rewireReturn: false,
20 | rewireTab: false,
21 | topPosition: '20%',
22 | leftPosition: '30%'
23 | }, options);
24 | var $keyboardTriggers = this;
25 | var $input = $();
26 | var $keyboard = renderKeyboard('osk-container');
27 | var $keys = $keyboard.children('li');
28 | var $letterKeys = $keyboard.children('li.osk-letter');
29 | var $symbolKeys = $keyboard.children('li.osk-symbol');
30 | var $numberKeys = $keyboard.children('li.osk-number');
31 | var $returnKey = $keyboard.children('li.osk-return');
32 | var $tabKey = $keyboard.children('li.osk-tab');
33 | var shift = false;
34 | var capslock = false;
35 | var inputOptions = [];
36 | var browserInPercent = $tabKey.css('marginRight').indexOf('%') > -1;
37 |
38 | /**
39 | * Focuses and customises the keyboard for the current input object.
40 | *
41 | * @param {jQueryObject} The input object to focus on.
42 | */
43 | function activateInput($input) {
44 | var inputOptionsString = $input.attr('data-osk-options');
45 | $keys.removeClass('osk-disabled');
46 | $keyboardTriggers.removeClass('osk-focused');
47 | if (inputOptionsString !== undefined) {
48 | inputOptions = inputOptionsString.split(' ');
49 | if ($.inArray('disableSymbols', inputOptions) > -1) {
50 | $symbolKeys.addClass('osk-disabled');
51 | }
52 | if ($.inArray('disableTab', inputOptions) > -1) {
53 | $tabKey.addClass('osk-disabled');
54 | }
55 | if ($.inArray('disableReturn', inputOptions) > -1) {
56 | $returnKey.addClass('osk-disabled');
57 | }
58 |
59 | }
60 | $input.addClass('osk-focused').focus();
61 | }
62 |
63 | /**
64 | * Fixes the width of the keyboard in browsers which round down part-pixel
65 | * values (all except Firefox). Most browsers which do this return CSS
66 | * margins in pixels rather than percent, so this is used to determine
67 | * whether or not to use this function. Opera does not however, so for now
68 | * this function does not work in that browser.
69 | */
70 | function fixWidths() {
71 | var $key = $(),
72 | keyboardWidth = $keyboard.width(),
73 | totalKeysWidth = 0,
74 | difference;
75 | if (browserInPercent) {
76 | $keys.each(function () {
77 | $key = $(this);
78 | if (!$key.hasClass('osk-dragger') && !$key.hasClass('osk-space')) {
79 | totalKeysWidth += $key.width() + Math.floor((parseFloat($key.css('marginRight')) / 100) * keyboardWidth);
80 | if ($key.hasClass('osk-last-item')) {
81 | difference = keyboardWidth - totalKeysWidth;
82 | if (difference > 0) {
83 | $key.width($key.width() + difference);
84 | }
85 | difference = 0;
86 | totalKeysWidth = 0;
87 | }
88 | }
89 | });
90 | }
91 | }
92 |
93 | if (settings.draggable && jQuery.ui) {
94 | $keyboard.children('li.osk-dragger').show();
95 | $keyboard.css('paddingTop', '0').draggable({
96 | containment : 'document',
97 | handle : 'li.osk-dragger'
98 | });
99 | }
100 |
101 | if (settings.rewireReturn) {
102 | $returnKey.html(settings.rewireReturn);
103 | }
104 |
105 | $keyboard.css('top', settings.topPosition).css('left', settings.leftPosition);
106 |
107 | fixWidths();
108 |
109 | $keyboard.hide().css('visibility', 'visible');
110 |
111 | $(window).resize(function () {
112 | fixWidths();
113 | });
114 |
115 | $keyboardTriggers.click(function () {
116 | $input = $(this);
117 | activateInput($input);
118 | $keyboard.fadeIn('fast');
119 | });
120 |
121 | $keyboard.on('click', 'li', function () {
122 | var $key = $(this),
123 | character = $key.html(),
124 | inputValue,
125 | indexOfNextInput;
126 |
127 | // Disabled keys/dragger
128 | if ($key.hasClass('osk-dragger') || $key.hasClass('osk-disabled')) {
129 | $input.focus();
130 | return false;
131 | }
132 |
133 | // 'Hide Keyboard' key
134 | if ($key.hasClass('osk-hide')) {
135 | $keyboard.fadeOut('fast');
136 | $input.blur();
137 | $keyboardTriggers.removeClass('osk-focused');
138 | return false;
139 | }
140 |
141 | // 'Shift' key
142 | if ($key.hasClass('osk-shift')) {
143 | $letterKeys.toggleClass('osk-uppercase');
144 | $.merge($symbolKeys.children('span'), $numberKeys.children('span')).toggle();
145 | if ($symbolKeys.hasClass('osk-disabled')) {
146 | $numberKeys.toggleClass('osk-disabled');
147 | }
148 | shift = !shift;
149 | capslock = false;
150 | return false;
151 | }
152 |
153 | // 'Caps Lock' key
154 | if ($key.hasClass('osk-capslock')) {
155 | $letterKeys.toggleClass('osk-uppercase');
156 | capslock = true;
157 | return false;
158 | }
159 |
160 | // 'Backspace' key
161 | if ($key.hasClass('osk-backspace')) {
162 | inputValue = $input.val();
163 | $input.val(inputValue.substr(0, inputValue.length - 1));
164 | $input.trigger('keyup');
165 | return false;
166 | }
167 |
168 | // Symbol/number keys
169 | if ($key.hasClass('osk-symbol') || $key.hasClass('osk-number')) {
170 | character = $('span:visible', $key).html();
171 | }
172 |
173 | // Spacebar
174 | if ($key.hasClass('osk-space')) {
175 | character = ' ';
176 | }
177 |
178 | // 'Tab' key - either enter an indent (default) or switch to next form element
179 | if ($key.hasClass('osk-tab')) {
180 | if (settings.rewireTab) {
181 | $input.trigger('onchange');
182 | indexOfNextInput = $keyboardTriggers.index($input) + 1;
183 | if (indexOfNextInput < $keyboardTriggers.length) {
184 | $input = $($keyboardTriggers[indexOfNextInput]);
185 | } else {
186 | $input = $($keyboardTriggers[0]);
187 | }
188 | activateInput($input);
189 | return false;
190 | } else {
191 | character = '\t';
192 | }
193 | }
194 |
195 | // 'Return' key - either linebreak (default) or submit form
196 | if ($key.hasClass('osk-return')) {
197 | if (settings.rewireReturn) {
198 | $keyboardTriggers.parent('form').submit();
199 | return false;
200 | } else {
201 | character = '\n';
202 | }
203 | }
204 |
205 | // Uppercase keys
206 | if ($key.hasClass('osk-uppercase')) {
207 | character = character.toUpperCase();
208 | }
209 |
210 | // Handler for when shift is enabled
211 | if (shift) {
212 | $.merge($symbolKeys.children('span'), $numberKeys.children('span')).toggle();
213 | if (!capslock) {
214 | $letterKeys.toggleClass('osk-uppercase');
215 | }
216 | if (settings.disableSymbols) {
217 | $numberKeys.toggleClass('osk-disabled');
218 | }
219 | shift = false;
220 | }
221 |
222 | $input.focus().val($input.val() + character);
223 | $input.trigger('keyup');
224 | });
225 |
226 | return this;
227 |
228 | };
229 |
230 | /**
231 | * Renders the keyboard.
232 | *
233 | * @param {String} id of the keyboard
234 | * @return {jQuery} the keyboard jQuery instance
235 | */
236 | function renderKeyboard(keyboardId) {
237 | var $keyboard = $('#' + keyboardId);
238 |
239 | if ($keyboard.length) {
240 | return $keyboard;
241 | }
242 |
243 | $keyboard = $(
244 | '
'),s("body").append(a),a)}s.fn.onScreenKeyboard=function(a){function o(l){var a=l.attr("data-osk-options");k.removeClass("osk-disabled"),n.removeClass("osk-focused"),void 0!==a&&(m=a.split(" "),s.inArray("disableSymbols",m)>-1&&p.addClass("osk-disabled"),s.inArray("disableTab",m)>-1&&u.addClass("osk-disabled"),s.inArray("disableReturn",m)>-1&&d.addClass("osk-disabled")),l.addClass("osk-focused").focus()}function i(){var l,a=s(),o=c.width(),i=0;g&&k.each(function(){a=s(this),a.hasClass("osk-dragger")||a.hasClass("osk-space")||(i+=a.width()+Math.floor(parseFloat(a.css("marginRight"))/100*o),a.hasClass("osk-last-item")&&(l=o-i,l>0&&a.width(a.width()+l),l=0,i=0))})}var e=s.extend({draggable:!1,rewireReturn:!1,rewireTab:!1,topPosition:"20%",leftPosition:"30%"},a),n=this,t=s(),c=l("osk-container"),k=c.children("li"),r=c.children("li.osk-letter"),p=c.children("li.osk-symbol"),f=c.children("li.osk-number"),d=c.children("li.osk-return"),u=c.children("li.osk-tab"),b=!1,h=!1,m=[],g=u.css("marginRight").indexOf("%")>-1;return e.draggable&&jQuery.ui&&(c.children("li.osk-dragger").show(),c.css("paddingTop","0").draggable({containment:"document",handle:"li.osk-dragger"})),e.rewireReturn&&d.html(e.rewireReturn),c.css("top",e.topPosition).css("left",e.leftPosition),i(),c.hide().css("visibility","visible"),s(window).resize(function(){i()}),n.click(function(){t=s(this),o(t),c.fadeIn("fast")}),c.on("click","li",function(){var l,a,i=s(this),k=i.html();if(i.hasClass("osk-dragger")||i.hasClass("osk-disabled"))return t.focus(),!1;if(i.hasClass("osk-hide"))return c.fadeOut("fast"),t.blur(),n.removeClass("osk-focused"),!1;if(i.hasClass("osk-shift"))return r.toggleClass("osk-uppercase"),s.merge(p.children("span"),f.children("span")).toggle(),p.hasClass("osk-disabled")&&f.toggleClass("osk-disabled"),b=!b,h=!1,!1;if(i.hasClass("osk-capslock"))return r.toggleClass("osk-uppercase"),h=!0,!1;if(i.hasClass("osk-backspace"))return l=t.val(),t.val(l.substr(0,l.length-1)),t.trigger("keyup"),!1;if((i.hasClass("osk-symbol")||i.hasClass("osk-number"))&&(k=s("span:visible",i).html()),i.hasClass("osk-space")&&(k=" "),i.hasClass("osk-tab")){if(e.rewireTab)return t.trigger("onchange"),a=n.index(t)+1,t=s(a li {
13 | float: left;
14 | width: 5.81395349%;
15 | height: 3em;
16 | margin: 0 0.726744186% 5px 0;
17 | line-height: 3em;
18 | text-align: center;
19 | list-style-type: none;
20 | cursor: pointer;
21 | -webkit-user-select: none;
22 | -khtml-user-select: none;
23 | -moz-user-select: -moz-none;
24 | -ms-user-select: none;
25 | user-select: none;
26 | }
27 |
28 | #osk-container > .osk-capslock,
29 | #osk-container > .osk-tab,
30 | #osk-container > .osk-shift {
31 | clear: left;
32 | }
33 |
34 | #osk-container > .osk-dragger {
35 | display: none;
36 | width: 100%;
37 | cursor: move;
38 | }
39 |
40 | #osk-container > .osk-dragger:hover {
41 | position: static;
42 | }
43 |
44 | #osk-container > .osk-tab,
45 | #osk-container > .osk-backspace {
46 | width: 14.9709302%;
47 | }
48 |
49 | #osk-container > .osk-capslock {
50 | width: 13.6337209%;
51 | }
52 |
53 | #osk-container > .osk-return {
54 | width: 13.6918605%;
55 | }
56 |
57 | #osk-container > .osk-shift {
58 | width: 16.2381395%;
59 | }
60 |
61 | #osk-container > .osk-hide {
62 | width: 17.5581396%;
63 | }
64 |
65 | #osk-container > .osk-space {
66 | clear: left;
67 | width: 100%;
68 | margin: 0;
69 | }
70 |
71 | #osk-container > .osk-last-item {
72 | margin-right: 0 !important;
73 | }
74 |
75 | #osk-container .osk-on {
76 | display: none;
77 | }
78 |
79 | #osk-container > .osk-uppercase {
80 | text-transform: uppercase;
81 | }
82 |
83 | #osk-container > .osk-disabled {
84 | cursor: default;
85 | }
86 |
87 | #osk-container > .osk-disabled:hover {
88 | position: static;
89 | }
90 |
91 | #osk-container > li:hover {
92 | position: relative;
93 | top: 1px;
94 | }
95 |
96 | /*-----[Customisable styles]--------------------------------------------------*/
97 |
98 | #osk-container {
99 | width: 47%; /* Account for 2% padding and a vertical scroll bar */
100 | min-width: 500px;
101 | max-width: 1200px;
102 | background: #EEE;
103 | border-radius: 5%;
104 | box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
105 | }
106 |
107 | #osk-container > li {
108 | background: #DDD;
109 | border-radius: 10%;
110 | -moz-transition: 0.5s;
111 | }
112 |
113 | #osk-container > .osk-dragger {
114 | background: transparent;
115 | color: #AAA;
116 | }
117 |
118 | #osk-container > .osk-disabled {
119 | background: #E5E5E5;
120 | color: #CCC;
121 | }
122 |
123 | .osk-focused {
124 | background: #FAFAFA !important;
125 | }
126 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "onScreenKeyboard",
3 | "version": "1.0.2",
4 | "title": "On-Screen Keyboard jQuery plug-in",
5 | "description": "Provides users with a fluid-width on-screen keyboard.",
6 | "homepage": "https://github.com/chriscook/on-screen-keyboard",
7 | "author": {
8 | "name": "Chris Cook",
9 | "email": "chris@chris-cook.co.uk",
10 | "url": "http://chris-cook.co.uk"
11 | },
12 | "license": "MIT",
13 | "keywords": [
14 | "ecosystem:jquery",
15 | "jquery-plugin",
16 | "keyboard",
17 | "security",
18 | "accessibility",
19 | "touchscreen",
20 | "touch"
21 | ],
22 | "repository": {
23 | "type": "git",
24 | "url": "https://github.com/chriscook/on-screen-keyboard.git"
25 | },
26 | "bugs": {
27 | "email": "chris@chris-cook.co.uk",
28 | "url": "https://github.com/chriscook/on-screen-keyboard/issues"
29 | },
30 | "dependencies": {
31 | "jquery": ">=1.5"
32 | },
33 | "optionalDependencies": {
34 | "jquery-ui": ">=1.0"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # On Screen Keyboard
2 |
3 | ## Version 1.0.2
4 |
5 | ### Introduction
6 |
7 | __On-Screen Keyboard__ is a _jQuery_ plug-in which allows a fluid-width keyboard to be launched when the user clicks on an element.
8 |
9 | ### Demo
10 |
11 | A demo is available [here](http://chriscook.github.com/on-screen-keyboard/).
12 |
13 | ### How to use it
14 |
15 | 1. Add `jquery.onScreenKeyboard.js` and `onScreenKeyboard.css` to your project, along with _jQuery_. Optionally also add _jQuery UI_ with the _Draggables_ widget if you would like your users to be able to move the keyboard around the screen.
16 | 2. Create your form or input elements.
17 | 3. Add the following JavaScript to your page, to be executed on load:
18 |
19 | ```javascript
20 | $('.osk-trigger').onScreenKeyboard();
21 | ```
22 |
23 | ...where `.osk-trigger` is a selector for the input elements you would like to trigger the keyboard.
24 |
25 | A demo is available in demo.html.
26 |
27 | ### Additional settings
28 |
29 | Additional settings can be used to customise the keyboard, and should be added as a parameter within curly braces:
30 |
31 | + `draggable`: __Requres jQuery UI with Draggables__ Whether or not the keyboard is movable (default `false`; must be boolean).
32 | + `rewireReturn`: Make the return key submit the form instead of inserting a linebreak (default `false`; must be either boolean false or a string to replace `'return'` with on the key).
33 | + `rewireTab`: Make the tab key cycle through input elements in the order they appear in the DOM instead of inserting a tab (default `false`; must be boolean).
34 | + `topPosition`: The `top` CSS property of the keyboard (default `20%`; must be a string suitable for CSS, i.e. one ending in a measurement unit).
35 | + `leftPosition`: The `left` CSS property of the keyboard (default `30%`; must be a string suitable for CSS, i.e. one ending in a measurement unit).
36 |
37 | An example of these in practice:
38 |
39 | ```javascript
40 | $('.osk-trigger').onScreenKeyboard({
41 | 'draggable': true,
42 | 'rewireReturn': 'search',
43 | 'rewireTab': true
44 | });
45 | ```
46 |
47 | In addition to these universal settings, you can change the keyboard on an input-by-input basis using the following parameters added to your input elements under the attribute `data-osk-options`, separated by spaces:
48 |
49 | + `disableSymbols` allows you to disable the symbol keys.
50 | + `disableTab` allows you to disable the tab key.
51 | + `disableReturn` allows you to disable the return key.
52 |
53 | An example of these in practice:
54 |
55 | ```html
56 |
57 | ```
58 |
59 | `jquery.onscreenkeyboard.js` contains the HTML for the keyboard at the bottom. As long as class names remain the same, this can be changed however much you like. The keyboard can only be written manually (e.g. custom non-us keyboard layouts) - the plugin is able to pick it up. Keep in mind that the character entered into the input box is taken directly from the contents of the `li` element for the pressed key (with exceptions for special keys such as return and tab, when not overridden, and backspace).
60 |
61 | `onscreenkeyboard.css` can also be edited to customise the keyboard's design. The first section, "Keyboard Structure" should be mostly left alone. The second section contains definitions for colour and keyboard position.
62 |
63 | ### Compatibility
64 |
65 | + Internet Explorer 7+
66 | + Firefox 3+
67 | + Chrome
68 | + Opera (see note below)
69 | + Safari
70 |
71 | ### Issues
72 |
73 | + In Opera, the widths of keys on the upper three rows will not match that of the space bar. This is due to the way Opera deals with sub-pixel values.
74 |
75 | ### Author and Acknowledgements
76 |
77 | + Written by [Chris Cook](http://chris-cook.co.uk)
78 | + Based upon [this tutorial from nettuts+](http://net.tutsplus.com/tutorials/javascript-ajax/creating-a-keyboard-with-css-and-jquery/)
79 |
--------------------------------------------------------------------------------