1/* 2 * Adds a virtual keyboard to a text input field. The virtual keyboard with these extenstions 3 * are known to work on Chrome, Firefox, and Safari running on Windows and iOS and on iOS and 4 * Android mobile devices. In mobile environments the native keyboard will be suppressed. 5 * 6 * Parameters: 7 * 8 * textBoxId - Id of the text input field to which the keyboard should be attached 9 * 10 * layout - Layout that the keyboard should use 11 * 12 * buttonId (optional) - Id of the DOM object to which a CLICK event handler will be attached 13 * for poping up the keyboard. This DOM object will be hidden when the keyboard is visible to 14 * reduce interactions with the keyboard and causing subtle bugs. If this parameter is missing 15 * or "falsy" then the keyboard will popup when the text input field receives focus. 16 * 17 * autocompleteUri (optional) - A URI that is compatible with the JQuery UI autocomplete widget. 18 * If this parameter is specified then a JQuery UI autocomplete widget will be attached to 19 * the text input field and will interact with the virtual keyboard. If the parameter is 20 * missing or "falsy" then a JQuery UI autocomplete widget will not be attached. 21 * 22 * selectionCallback (optional) - If a JQuery UI autocomplete widget was attached to the text input 23 * field then this callback, if specified, will be called when the user selects an item from 24 * the autocomplete dropdown list. 25 * 26 * changeCallback (optional) - If a JQuery UI autocomplete widget was attached to the text input 27 * field then this callback, if specified, will be called when the user changes selection in 28 * the autocomplete dropdown list. 29 * 30 * Examples: 31 * <link rel="stylesheet" href="./css/keyboard.css" type="text/css" media="all" /> 32 * <link rel="stylesheet" href="./css/keyboard-previewkeyset.css" type="text/css" media="all" /> 33 * 34 * <script src='./js/jquery.cookie.js'></script> 35 * <script src='./js/jquery.keyboard.js'></script> 36 * <script src='./js/jquery.keyboard.extension-mobile.js'></script> 37 * <script src='./js/jquery.keyboard.extension-navigation.js'></script> 38 * <script src='./js/jquery.keyboard.extension-autocomplete.js'></script> 39 * <script src='./js/jquery.keyboard.syriac.js'></script> 40 * <script src='./js/keyboardSupport.js'></script> 41 * 42 * // Add a keyboard with a button to popup the keyboard 43 * initializeKeyboard('#lexeme', getKeyboardLayout, '#lexeme-keyboard'); 44 * 45 * // Add a keyboard with a button to popup the keyboard with an autocomplete widget attached 46 * initializeKeyboard('#lexeme', getKeyboardLayout, '#lexeme-keyboard', Routing.generate('listlexemes'), onSelection); 47 * 48 * // Add a keyboard that will popup when the text input box gets focus 49 * initializeKeyboard('#lexeme', getKeyboardLayout); 50 * 51 * // Add a keyboard that will popup when the text input box gets focus with an autocomplete widget attached 52 * initializeKeyboard('#lexeme', getKeyboardLayout, null, Routing.generate('listlexemes'), onSelection); 53 */ 54function initializeKeyboard(textBoxId, layout, buttonId, autocompleteUri, selectionCallback, changeCallback) { 55 var mobile = (navigator.userAgent.toLowerCase().search(/ipad|iphone|android/i) > -1); 56 var popupButton = buttonId ? $(buttonId) : false; 57 58 function isFunction(functionToCheck) { 59 var getType = {}; 60 return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; 61 }; 62 63 var fixDirection = function() 64 { 65 var textBox = $(textBoxId); 66 var value = textBox.val(); 67 var matches = value.match(/[\u0700-\u074F]/g); 68 69 if (matches) 70 { 71 textBox.css('text-align', 'right'); 72 textBox.css('direction', 'rtl'); 73 } 74 else 75 { 76 textBox.css('text-align', 'left'); 77 textBox.css('direction', 'ltr'); 78 } 79 }; 80 81 var keyboardButtonPressed = function(e) 82 { 83 var textBox = $(textBoxId); 84 var text = textBox.val(); 85 86 fixDirection(); 87 88 if (text && text.length > 1) { 89 textBox.autocomplete("search"); 90 } 91 }; 92 93 var renderListItem = function(ul, item) { 94 return $('<li></li>') 95 .data('item.autocomplete', item) 96 .append('<a>' + item.label + '</a>') 97 .appendTo(ul); 98 }; 99 100 var attachAutoComplete = function () { 101 var textBox = $(textBoxId); 102 103 var options = { 104 source: autocompleteUri, 105 minLength: 2, 106 delay: 500, 107 autoFocus: true 108 }; 109 110 if (isFunction(selectionCallback)) options.select = selectionCallback;
111 if (isFunction(changeCallback)) options.change = changeCallback; 112 113 $(textBox).autocomplete(options).data("ui-autocomplete")._renderItem = renderListItem; 114 }; 115 116 var getKeyboard = function(close) { 117 var textBox = $(textBoxId); 118 return (isFunction(textBox.getkeyboard) ? textBox.getkeyboard() : false); 119 }; 120 121 var createKeyboard = function() { 122 var textBox = $(textBoxId); 123 var keyboardLayout = isFunction(layout) ? layout() : layout; 124 var options = { 125 stayOpen : false, 126 layout : keyboardLayout, 127 usePreview: false, 128 autoAccept: true, 129 autoAcceptOnEsc: true, 130 useWheel: false, 131 lockInput : mobile, 132 beforeVisible: function (e, keyboard, el) { 133 keyboard.el.blur(); 134 }, 135 position: { 136 // null = attach to input/textarea; 137 // use $(sel) to attach elsewhere 138 of: null, 139 my: 'center top', 140 at: 'center top', 141 // used when "usePreview" is false 142 at2: 'center bottom' 143 } 144 }; 145 146 if (popupButton) options.openOn = ""; 147 148 textBox.keyboard(options); 149 150 if (autocompleteUri) { 151 attachAutoComplete(); 152 153 textBox.addAutocomplete({ 154 position : { 155 of : textBox, 156 my : 'left top', 157 at : 'left bottom', 158 at2 : 'left bottom', 159 collision: 'none' 160 } 161 }); 162 } 163 164 var kb = getKeyboard(); 165 166 if (popupButton && kb) { 167 textBox.on('hidden', function(e){ 168 var kb = getKeyboard(); 169 if (kb) { 170 removeKeyboard(kb.options.autoAccept ? 'true' : false); 171 rebuildTextBox(); 172 if (autocompleteUri) { 173 attachAutoComplete(); 174 } 175 } 176 popupButton.prop('hidden', false); 177 }); 178 179 popupButton.prop('hidden', true); 180 kb.reveal(); 181 } 182 183 if (autocompleteUri) { 184 if (mobile) { 185 textBox.on('change', autocompleteUri ? keyboardButtonPressed : fixDirection); 186 $('button.ui-keyboard-button').on('touch', autocompleteUri ? keyboardButtonPressed : fixDirection); 187 } else { 188 textBox.on('change', autocompleteUri ? keyboardButtonPressed : fixDirection); 189 $('button.ui-keyboard-button').on('click', autocompleteUri ? keyboardButtonPressed : fixDirection); 190 } 191 } 192 }; 193 194 var removeKeyboard = function(close) { 195 var kb = getKeyboard(); 196 197 if (kb) { 198 kb.close(close); 199 kb.destroy(); 200 } 201 202 if (popupButton) popupButton.prop('hidden', false); 203 }; 204 205 var rebuildTextBox = function() { 206 var textBox = $(textBoxId); 207 var t = textBox.clone(false); 208 209 t.insertAfter(textBox); 210 textBox.remove(); 211 }; 212 213 $.keyboard.keyaction.enter = function() { 214 var kb = getKeyboard(); 215 216 if (kb) { 217 removeKeyboard(kb.options.autoAccept ? 'true' : false); 218 rebuildTextBox(); 219 if (autocompleteUri) { 220 attachAutoComplete(); 221 } 222 } 223 224 return false; 225 }; 226 227 var clickButton = function(e){ 228 var kb = getKeyboard(); 229 var isVisible = kb ? kb.isVisible() : false; 230 231 if (isVisible) { 232 removeKeyboard(); 233 } 234 235 rebuildTextBox(); 236 createKeyboard(); 237 }; 238 239 if (popupButton) { 240 popupButton.click(clickButton); 241 242 if (autocompleteUri) { 243 attachAutoComplete(); 244 } 245 } else { 246 createKeyboard(); 247 } 248}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.