From 27b4e3680df5c3883c2085648a5a5e7a822adc9c Mon Sep 17 00:00:00 2001 From: Agustin Moyano Date: Wed, 8 May 2019 23:41:43 -0300 Subject: [PATCH] Bug 17178: Add virtual keyboard to advanced cataloguing editor This patch adds Mottie keyboard (https://github.com/Mottie/Keyboard) to advanced editor. To test: 1) Apply patches 2) perl install/data/mysql/updatedatabase.pl 3) Enable EnableAdvancedCatalogingEditor system preference 4) Go to cataloguing and to Advanced editor 5) Click on Keyboard shortcuts SUCCESS => the keyboard shortcut "Ctrl-K" should be displayed, with "Toggle keyboard" as description 6) press Ctrl-K SUCCESS => a virtual keyboard should be displayed, and a new toolbar button labeled "Keyboard layout" should appear. => when you press a letter on both the physical and virtual keyboard, they should be added to the editor. 7) Click on "Keyboard layout" SUCCESS => a modal should appear, where you can filter and select keyboard layouts. => when you select a layout, it should be reflected on the keyboard. => when you close the modal without selecting a layout, it should keep using the previous layout. 8) Sign off Sponsored-by: Round Rock Public Library Signed-off-by: Josef Moravec --- .../lib/keyboard/css/keyboard-basic.min.css | 1 + .../lib/keyboard/css/keyboard-dark.min.css | 1 + .../keyboard/css/keyboard-previewkeyset.min.css | 1 + .../lib/keyboard/css/keyboard.min.css | 1 + .../js/jquery.keyboard.extension-all.min.js | 5 + .../jquery.keyboard.extension-altkeyspopup.min.js | 2 + .../jquery.keyboard.extension-autocomplete.min.js | 2 + .../js/jquery.keyboard.extension-caret.min.js | 2 + .../js/jquery.keyboard.extension-extender.min.js | 2 + .../js/jquery.keyboard.extension-mobile.min.js | 2 + .../js/jquery.keyboard.extension-navigation.min.js | 2 + .../jquery.keyboard.extension-previewkeyset.min.js | 2 + .../js/jquery.keyboard.extension-scramble.min.js | 2 + .../js/jquery.keyboard.extension-typing.min.js | 2 + .../lib/keyboard/js/jquery.keyboard.js | 3573 ++++++++++++++++++++ .../lib/keyboard/js/jquery.keyboard.min.js | 2 + .../lib/keyboard/js/jquery.mousewheel.min.js | 2 + .../lib/keyboard/languages/all.min.js | 1 + .../intranet-tmpl/lib/keyboard/layouts/all.min.js | 5 + .../lib/koha/cateditor/marc-editor.js | 78 + koha-tmpl/intranet-tmpl/prog/css/cateditor.css | 12 + .../prog/en/includes/cateditor-ui.inc | 4 + .../prog/en/includes/keyboard_shortcuts.inc | 1 + .../prog/en/modules/cataloguing/editor.tt | 20 + 24 files changed, 3725 insertions(+) create mode 100644 koha-tmpl/intranet-tmpl/lib/keyboard/css/keyboard-basic.min.css create mode 100644 koha-tmpl/intranet-tmpl/lib/keyboard/css/keyboard-dark.min.css create mode 100644 koha-tmpl/intranet-tmpl/lib/keyboard/css/keyboard-previewkeyset.min.css create mode 100644 koha-tmpl/intranet-tmpl/lib/keyboard/css/keyboard.min.css create mode 100644 koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-all.min.js create mode 100644 koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-altkeyspopup.min.js create mode 100644 koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-autocomplete.min.js create mode 100644 koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-caret.min.js create mode 100644 koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-extender.min.js create mode 100644 koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-mobile.min.js create mode 100644 koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-navigation.min.js create mode 100644 koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-previewkeyset.min.js create mode 100644 koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-scramble.min.js create mode 100644 koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-typing.min.js create mode 100644 koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.js create mode 100644 koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.min.js create mode 100644 koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.mousewheel.min.js create mode 100644 koha-tmpl/intranet-tmpl/lib/keyboard/languages/all.min.js create mode 100644 koha-tmpl/intranet-tmpl/lib/keyboard/layouts/all.min.js diff --git a/koha-tmpl/intranet-tmpl/lib/keyboard/css/keyboard-basic.min.css b/koha-tmpl/intranet-tmpl/lib/keyboard/css/keyboard-basic.min.css new file mode 100644 index 0000000000..20567ea16e --- /dev/null +++ b/koha-tmpl/intranet-tmpl/lib/keyboard/css/keyboard-basic.min.css @@ -0,0 +1 @@ +.ui-keyboard{font-size:14px;text-align:center;background:#fefefe;border:1px solid #aaa;padding:4px;width:100%;height:auto;left:0;top:auto;bottom:0;position:fixed;white-space:nowrap;overflow-x:auto;-ms-touch-action:manipulation;touch-action:manipulation}.ui-keyboard-has-focus{z-index:16001}.ui-keyboard-button{border:1px solid #aaa;padding: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,.5);box-shadow:1px 1px 3px 0 rgba(0,0,0,.5);background:#fff;background-image:-webkit-linear-gradient(-90deg,#fff 0,#e3e3e3 100%);background-image:linear-gradient(-90deg,#fff 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}.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:.8em;position:relative;top:-1em;left:-1.6em}.ui-keyboard-placeholder{color:#888}.ui-keyboard-nokeyboard{color:#888;border-color:#888}.ui-keyboard-spacer{display:inline-block;width:1px;height:0;cursor:default}.ui-keyboard-LRM span,.ui-keyboard-NBSP span,.ui-keyboard-RLM span,.ui-keyboard-ZWJ span,.ui-keyboard-ZWNJ span,.ui-keyboard-ZWSP span{font-size:.5em;line-height:1.5em;white-space:normal}.ui-keyboard-button.ui-keyboard-combo.ui-state-default{-webkit-box-shadow:1px 1px 3px 0 rgba(213,133,18,.5);box-shadow:1px 1px 3px 0 rgba(213,133,18,.5);border-color:#d58512}.ui-keyboard-button.ui-keyboard-combo.ui-state-active{-webkit-box-shadow:1px 1px 3px 0 rgba(38,154,188,.5);box-shadow:1px 1px 3px 0 rgba(38,154,188,.5);border-color:#269abc}button.ui-keyboard-accept.ui-keyboard-valid-input{-webkit-box-shadow:1px 1px 3px 0 rgba(57,132,57,.5);box-shadow:1px 1px 3px 0 rgba(57,132,57,.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,.5);box-shadow:1px 1px 3px 0 rgba(172,41,37,.5);border-color:#ac2925}button.ui-keyboard-accept.ui-keyboard-invalid-input:not([disabled]):hover{border-color:#d43f3a}button.ui-keyboard-toggle span{width:.9em;height:.9em;display:inline-block;background-repeat:no-repeat;background-position:center center;background-size:contain;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iIzExMSI+PHBhdGggZD0iTTguNyw0LjRINy41SDUuMHYtMS45YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40LDAtMi41LDEuMS0yLjUsMi41djEuOWgxLjIgdi0xLjljMC0wLjcsMC42LTEuMiwxLjItMS4yczEuMiwwLjYsMS4yLDEuMnYxLjljLTAuNywwLTEuMiwwLjYtMS4yLDEuMlY4LjggYzAsMC43LDAuNiwxLjIsMS4yLDEuMmg1LjBDOS40LDEwLDEwLDkuNCwxMCw4LjhWNS42QzEwLDUuMCw5LjQsNC40LDguOCw0LjR6IE02LjYsNy40djEuMCBjMCwwLjItMC4xLDAuMy0wLjMsMC4zUzYuMCw4LjYsNi4wLDguNFY3LjRjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zLDAuMy0wLjYsMC42LTAuNiBTNi45LDYuNiw2LjksNi45QzYuOSw3LjEsNi44LDcuMyw2LjYsNy40eiIvPjwvc3ZnPg==)}button.ui-keyboard-toggle.ui-keyboard-disabled span{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:.5}.ui-keyboard-overlay{position:absolute;top:0;left:0;bottom:0;right:0;background:rgba(238,238,238,.5)}.ui-keyboard-popup{display:inline-block;max-width:22em}.ui-keyboard.ui-keyboard-popup-open .ui-keyboard-keyset .ui-keyboard-button{pointer-events:none}.ui-keyboard-caret{background:#c00;width:1px;margin-top:3px}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;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgc3R5bGU9ImZpbGw6IzExMSI+PGc+PHBhdGggc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzExMSIgZD0iTSAwLjUsNC41IDE1LjUsNC41IDE1LjUsMTUuNSAwLjUsMTUuNSBaIj48L3BhdGg+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iMiIgeT0iNiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjYiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSI4IiB5PSI2Ij48L3JlY3Q+PHBhdGggZD0ibSAxMSw2IDMsMCAwLDUgLTIsMCAwLC0zIC0xLDAgeiI+PC9wYXRoPjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjEyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSI2IiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjEyIj48L3JlY3Q+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iOSIgeT0iOSI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjYiIHk9IjkiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSIyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIzIiBoZWlnaHQ9IjIiIHg9IjIiIHk9IjkiPjwvcmVjdD48L2c+PC9zdmc+)} \ No newline at end of file diff --git a/koha-tmpl/intranet-tmpl/lib/keyboard/css/keyboard-dark.min.css b/koha-tmpl/intranet-tmpl/lib/keyboard/css/keyboard-dark.min.css new file mode 100644 index 0000000000..b8b451e4de --- /dev/null +++ b/koha-tmpl/intranet-tmpl/lib/keyboard/css/keyboard-dark.min.css @@ -0,0 +1 @@ +.ui-keyboard{font-size:14px;text-align:center;background:#282828;border:1px solid #484848;padding:4px;width:100%;height:auto;left:0;top:auto;bottom:0;position:fixed;white-space:nowrap;overflow-x:auto;-ms-touch-action:manipulation;touch-action:manipulation}.ui-keyboard-has-focus{z-index:16001}.ui-keyboard-button{border:1px solid #404040;padding: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,.5);box-shadow:1px 1px 3px 0 rgba(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}.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:.8em;position:relative;top:-1em;left:-1.6em}.ui-keyboard-placeholder{color:#888}.ui-keyboard-nokeyboard{color:#888;border-color:#888}.ui-keyboard-spacer{display:inline-block;width:1px;height:0;cursor:default}.ui-keyboard-LRM span,.ui-keyboard-NBSP span,.ui-keyboard-RLM span,.ui-keyboard-ZWJ span,.ui-keyboard-ZWNJ span,.ui-keyboard-ZWSP span{font-size:.5em;line-height:1.5em;white-space:normal}.ui-keyboard-button.ui-keyboard-combo.ui-state-default{-webkit-box-shadow:1px 1px 3px 0 rgba(213,133,18,.5);box-shadow:1px 1px 3px 0 rgba(213,133,18,.5);border-color:#d58512}.ui-keyboard-button.ui-keyboard-combo.ui-state-active{-webkit-box-shadow:1px 1px 3px 0 rgba(38,154,188,.5);box-shadow:1px 1px 3px 0 rgba(38,154,188,.5);border-color:#269abc}button.ui-keyboard-accept.ui-keyboard-valid-input{-webkit-box-shadow:1px 1px 3px 0 rgba(57,132,57,.5);box-shadow:1px 1px 3px 0 rgba(57,132,57,.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,.5);box-shadow:1px 1px 3px 0 rgba(172,41,37,.5);border-color:#ac2925}button.ui-keyboard-accept.ui-keyboard-invalid-input:not([disabled]):hover{border-color:#d43f3a}button.ui-keyboard-toggle span{width:.9em;height:.9em;display:inline-block;background-repeat:no-repeat;background-position:center center;background-size:contain;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iI2VlZSI+PHBhdGggZD0iTTguNyw0LjRINy41SDUuMHYtMS45YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40LDAtMi41LDEuMS0yLjUsMi41djEuOWgxLjIgdi0xLjljMC0wLjcsMC42LTEuMiwxLjItMS4yczEuMiwwLjYsMS4yLDEuMnYxLjljLTAuNywwLTEuMiwwLjYtMS4yLDEuMlY4LjggYzAsMC43LDAuNiwxLjIsMS4yLDEuMmg1LjBDOS40LDEwLDEwLDkuNCwxMCw4LjhWNS42QzEwLDUuMCw5LjQsNC40LDguOCw0LjR6IE02LjYsNy40djEuMCBjMCwwLjItMC4xLDAuMy0wLjMsMC4zUzYuMCw4LjYsNi4wLDguNFY3LjRjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zLDAuMy0wLjYsMC42LTAuNiBTNi45LDYuNiw2LjksNi45QzYuOSw3LjEsNi44LDcuMyw2LjYsNy40eiIvPjwvc3ZnPg==)}button.ui-keyboard-toggle.ui-keyboard-disabled span{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:.5}.ui-keyboard-overlay{position:absolute;top:0;left:0;bottom:0;right:0;background:rgba(0,0,0,.5)}.ui-keyboard-popup{display:inline-block;max-width:22em}.ui-keyboard.ui-keyboard-popup-open .ui-keyboard-keyset .ui-keyboard-button{pointer-events:none}.ui-keyboard-caret{background:#c00;width:1px;margin-top:3px}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;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgc3R5bGU9ImZpbGw6I2VlZSI+PGc+PHBhdGggc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6I2VlZSIgZD0iTSAwLjUsNC41IDE1LjUsNC41IDE1LjUsMTUuNSAwLjUsMTUuNSBaIj48L3BhdGg+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iMiIgeT0iNiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjYiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSI4IiB5PSI2Ij48L3JlY3Q+PHBhdGggZD0ibSAxMSw2IDMsMCAwLDUgLTIsMCAwLC0zIC0xLDAgeiI+PC9wYXRoPjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjEyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSI2IiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjEyIj48L3JlY3Q+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iOSIgeT0iOSI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjYiIHk9IjkiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSIyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIzIiBoZWlnaHQ9IjIiIHg9IjIiIHk9IjkiPjwvcmVjdD48L2c+PC9zdmc+)} \ No newline at end of file diff --git a/koha-tmpl/intranet-tmpl/lib/keyboard/css/keyboard-previewkeyset.min.css b/koha-tmpl/intranet-tmpl/lib/keyboard/css/keyboard-previewkeyset.min.css new file mode 100644 index 0000000000..51b843fa95 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/lib/keyboard/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} \ No newline at end of file diff --git a/koha-tmpl/intranet-tmpl/lib/keyboard/css/keyboard.min.css b/koha-tmpl/intranet-tmpl/lib/keyboard/css/keyboard.min.css new file mode 100644 index 0000000000..74e9e951bc --- /dev/null +++ b/koha-tmpl/intranet-tmpl/lib/keyboard/css/keyboard.min.css @@ -0,0 +1 @@ +.ui-keyboard{text-align:center;padding:.3em;position:absolute;left:0;top:0;z-index:16000;-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}.ui-keyboard-empty span,.ui-keyboard-space span{font:0/0 a;text-shadow:none;color:transparent}.ui-keyboard-preview-wrapper{text-align:center;position:relative;overflow:hidden}.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}.ui-keyboard-nokeyboard{color:#888;border-color:#888}.ui-keyboard-spacer{display:inline-block;width:1px;height:0;cursor:default}.ui-keyboard-LRM span,.ui-keyboard-NBSP span,.ui-keyboard-RLM span,.ui-keyboard-ZWJ span,.ui-keyboard-ZWNJ span,.ui-keyboard-ZWSP span{font-size:.5em;line-height:1.5em;white-space:normal}.ui-keyboard-button.ui-keyboard-combo.ui-state-default{border-color:#ffaf0f}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:.5}button.ui-keyboard-accept.ui-keyboard-invalid-input:not([disabled]):hover{background:#a00}.ui-keyboard-caret{background:#c00;width:1px;margin-top:3px}div.ui-body.ui-keyboard button.ui-keyboard-button.ui-btn{padding:.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}.ui-body .ui-keyboard-keyset{line-height:.5em}.ui-body input.ui-input-text,.ui-body textarea.ui-input-text{width:95%}.ui-body .ui-btn-inner{height:2em;padding:.2em 0;margin:0}.ui-body .ui-btn{margin:0;font-size:13px}button.ui-keyboard-button.btn{padding:1px 6px}button.ui-keyboard-toggle span{width:.8em;height:.8em;display:inline-block;background-repeat:no-repeat;background-position:center center;background-size:contain}button.ui-keyboard-toggle span{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iIzExMSI+PHBhdGggZD0iTTguNyw0LjRINy41SDUuMHYtMS45YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40LDAtMi41LDEuMS0yLjUsMi41djEuOWgxLjIgdi0xLjljMC0wLjcsMC42LTEuMiwxLjItMS4yczEuMiwwLjYsMS4yLDEuMnYxLjljLTAuNywwLTEuMiwwLjYtMS4yLDEuMlY4LjggYzAsMC43LDAuNiwxLjIsMS4yLDEuMmg1LjBDOS40LDEwLDEwLDkuNCwxMCw4LjhWNS42QzEwLDUuMCw5LjQsNC40LDguOCw0LjR6IE02LjYsNy40djEuMCBjMCwwLjItMC4xLDAuMy0wLjMsMC4zUzYuMCw4LjYsNi4wLDguNFY3LjRjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zLDAuMy0wLjYsMC42LTAuNiBTNi45LDYuNiw2LjksNi45QzYuOSw3LjEsNi44LDcuMyw2LjYsNy40eiIvPjwvc3ZnPg==)}.ui-keyboard-dark-theme button.ui-keyboard-toggle span{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iI2VlZSI+PHBhdGggZD0iTTguNyw0LjRINy41SDUuMHYtMS45YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40LDAtMi41LDEuMS0yLjUsMi41djEuOWgxLjIgdi0xLjljMC0wLjcsMC42LTEuMiwxLjItMS4yczEuMiwwLjYsMS4yLDEuMnYxLjljLTAuNywwLTEuMiwwLjYtMS4yLDEuMlY4LjggYzAsMC43LDAuNiwxLjIsMS4yLDEuMmg1LjBDOS40LDEwLDEwLDkuNCwxMCw4LjhWNS42QzEwLDUuMCw5LjQsNC40LDguOCw0LjR6IE02LjYsNy40djEuMCBjMCwwLjItMC4xLDAuMy0wLjMsMC4zUzYuMCw4LjYsNi4wLDguNFY3LjRjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zLDAuMy0wLjYsMC42LTAuNiBTNi45LDYuNiw2LjksNi45QzYuOSw3LjEsNi44LDcuMyw2LjYsNy40eiIvPjwvc3ZnPg==)}button.ui-keyboard-toggle.ui-keyboard-disabled span{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iIzExMSI+PHBhdGggZD0iTTcuNCA0LjRWMi41YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40IDAtMi41IDEuMS0yLjUgMi41djEuOSBjLTAuNyAwLTEuMiAwLjUtMS4yIDEuMnYzLjFDMS4zIDkuNCAxLjggMTAgMi41IDEwaDQuOWMwLjcgMCAxLjItMC42IDEuMi0xLjJWNS42IEM4LjcgNC45IDguMSA0LjQgNy40IDQuNHogTTUuMyA3LjR2MS4wYzAgMC4yLTAuMSAwLjMtMC4zIDAuM2MtMC4yIDAtMC4zLTAuMS0wLjMtMC4zVjcuNCBjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zIDAuMy0wLjYgMC42LTAuNmMwLjMgMCAwLjYgMC4zIDAuNiAwLjYgQzUuNiA3LjEgNS41IDcuMyA1LjMgNy40eiBNNi4yIDQuNEgzLjdWMi41YzAtMC43IDAuNS0xLjIgMS4yLTEuMmMwLjcgMCAxLjIgMC42IDEuMiAxLjIgVjQuNHoiLz48L3N2Zz4=)}.ui-keyboard-dark-theme button.ui-keyboard-toggle.ui-keyboard-disabled span{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:.5}.ui-keyboard-overlay{position:absolute;top:0;left:0;bottom:0;right:0;background:rgba(0,0,0,.5)}.ui-keyboard-popup{display:inline-block;max-width:22em}.ui-keyboard.ui-keyboard-popup-open .ui-keyboard-keyset .ui-keyboard-button{pointer-events:none}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;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{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgc3R5bGU9ImZpbGw6I2VlZSI+PGc+PHBhdGggc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6I2VlZSIgZD0iTSAwLjUsNC41IDE1LjUsNC41IDE1LjUsMTUuNSAwLjUsMTUuNSBaIj48L3BhdGg+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iMiIgeT0iNiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjYiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSI4IiB5PSI2Ij48L3JlY3Q+PHBhdGggZD0ibSAxMSw2IDMsMCAwLDUgLTIsMCAwLC0zIC0xLDAgeiI+PC9wYXRoPjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjEyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSI2IiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjEyIj48L3JlY3Q+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iOSIgeT0iOSI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjYiIHk9IjkiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSIyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIzIiBoZWlnaHQ9IjIiIHg9IjIiIHk9IjkiPjwvcmVjdD48L2c+PC9zdmc+)}@media all and (max-width:319px){.ui-keyboard div{font-size:9px}.ui-keyboard .ui-keyboard-input{font-size:12px}.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:.3em 0}}@media all and (min-width:320px) and (max-width:479px){.ui-keyboard div{font-size:9px}.ui-keyboard .ui-keyboard-input{font-size:14px}.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:.7em 0}}@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:.5em 0}} \ No newline at end of file diff --git a/koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-all.min.js b/koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-all.min.js new file mode 100644 index 0000000000..68d8b0d07f --- /dev/null +++ b/koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-all.min.js @@ -0,0 +1,5 @@ +/*! jQuery UI Virtual Keyboard (1.29.1) - ALL Extensions + Mousewheel */ +/*! jQuery UI Virtual Keyboard Alt Key Popup v2.0.0 */ +!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(b){"use strict";var f=b.keyboard;b.extend(f.css,{altKeyPopup:"ui-keyboard-popup",altKeyOverlay:"ui-keyboard-overlay",altKeyPopupOpen:"ui-keyboard-popup-open"}),f.altKeys=b.extend({a:"å æ ā ă ą à á â ã ä",A:"Å Æ Ā Ă Ą À Á  à Ä",c:"ç ć ĉ ċ č",C:"Ç Ć Ĉ Ċ Č",d:"ď ð ď",D:"Ď Ð Ď",e:"ė ę ĕ ě ə è é ê ë ē",E:"Ė Ę Ĕ Ě Ǝ È É Ê Ë Ē",g:"ģ ğ ĝ ġ",G:"Ģ Ğ Ĝ Ġ",h:"ĥ ħ",H:"Ĥ Ħ",i:"ı į ī ï î í ì ĩ ĭ",I:"İ Į Ī Ï Î Í Ì Ĩ Ĭ",j:"ĵ",J:"Ĵ",k:"ķ",K:"Ķ",l:"Ł Ľ Ļ Ĺ Ŀ",L:"ł ľ ļ ĺ ŀ",n:"ʼn ň ņ ń ñ",N:"ʼn Ň Ņ Ń Ñ",o:"œ ő ø ö õ ô ó ò ō ŏ",O:"Œ Ő Ø Ö Õ Ô Ó Ò Ō Ŏ",r:"ŕ ř ŗ",R:"Ŕ Ř Ŗ",s:"ś š ş ß § ŝ",S:"Ś Š Ş ẞ § Ŝ",t:"þ ť ț ţ ŧ",T:"Þ Ť Ț Ţ Ŧ",u:"ų ű ů ū ü û ú ù ũ ŭ",U:"Ų Ű Ů Ū Ü Û Ú Ù Ũ Ŭ",w:"ŵ",W:"Ŵ",y:"ý",Y:"Ý",z:"ź ż ž",Z:"Ź Ż Ž","!":"¡",$:"€ £ ¤ ¥ ¢ ₡ ₱ ₩ ₹ ₪ ₭ ₮ ₦ ₤","?":"¿","'":"〈 「 『 “",'"':"〉 」 』 ”","(":"《 【 〔",")":"》 】 〕"},f.altKeys),b.fn.addAltKeyPopup=function(e){var t={holdTime:500,popupVisible:"popup-visible",popupHidden:"popup-hidden",popupPosition:null};return this.each(function(){var y=b(this).data("keyboard");if(y){if(y.altkeypopup_options=b.extend({},t,y.altkeypopup_options,e),y.altkeypopup_namespace)return y.altkeypopup_setup();y.altkeypopup_namespace=y.namespace+"AltKeyPopup",y.extensionNamespace.push(y.altkeypopup_namespace),y.altkeypopup_setup=function(){var a,e="mousedown touchstart ".split(" ").join(y.altkeypopup_namespace+" "),t="mouseup touchend touchcancel ".split(" ").join(y.altkeypopup_namespace+" ");y.options.repeatRate=0,y.unbindButton(y.altkeypopup_namespace).bindButton(e,function(){clearTimeout(a);var e=b(this),t=e.attr("data-value")||"",o=y.altkeypopup_options.holdTime;t in f.altKeys&&(o?a=setTimeout(function(){y.altKeyPopup_popup(t,e)},o):y.altKeyPopup_popup(t,e))}).bindButton(t,function(){clearTimeout(a)}),y.altkeypopup_blockingFlag=!1,y.$preview.unbind("keypress keydown keyup ".split(" ").join(y.altkeypopup_namespace+" ").trim()).bind("keypress keydown keyup ".split(" ").join(y.altkeypopup_namespace+" "),function(e){if("keyup"===e.type)return clearTimeout(a),y.altkeypopup_blockingFlag=!1,"Escape"!==e.key;var t=f.builtLayouts[y.layout],o=b(e.target),n=e.key,i=e.key;return"keydown"===e.type&&i in f.altKeys?y.altkeypopup_blockingFlag!==n&&(y.altkeypopup_blockingFlag=n,!0):y.altkeypopup_blockingFlag?(t.hasMappedKeys&&t.mappedKeys.hasOwnProperty(i)&&(i=t.mappedKeys[i]),i in f.altKeys&&(clearTimeout(a),a=setTimeout(function(){y.altkeypopup_blockingFlag===n&&y.altKeyPopup_popup(i,o)},y.altkeypopup_options.holdTime)),!0):void 0})},y.altKeyPopup_close=function(){y.altkeypopup_blockingFlag=!1,y.altKeyPopup_$overlay=null,setTimeout(function(){if(y.$keyboard.length){y.$keyboard.removeClass(f.css.altKeyPopupOpen);var e=y.$keyboard.find("."+f.css.altKeyOverlay);e&&e.remove()}},1),b(document).unbind(y.altkeypopup_namespace),y.$preview.focus(),y.options.ignoreEsc=y.altKeyPopup_savedIgnoreEsc,y.$el.trigger(y.altkeypopup_options.popupHidden,[y])},y.altKeyPopup_popup=function(e,t){if(!y.$keyboard.find("."+f.css.altKeyOverlay).length){var o,n,i,a,s,r,p,u,l,d=f.css,c={$kb:y.$keyboard,kbWidth:y.$keyboard.outerWidth(),kbHeight:y.$keyboard.outerHeight(),$key:t};y.altKeyPopup_$overlay=b('
').css({width:c.kbWidth,height:c.kbHeight}).appendTo(y.$keyboard).bind("click touchstart",function(){y.altKeyPopup_close()}),l="inactive hidden ".split(" ").join(y.altkeypopup_namespace+" "),y.$keyboard.addClass(f.css.altKeyPopupOpen),y.$el.unbind(l).bind(l,function(){y.altKeyPopup_close()}),"bksp"!==e&&f.keyaction.bksp(y),n=b('
'),o=f.altKeys[e].split(/\s+/),y.buildRow(n,0,o,[]),i=n.appendTo(y.altKeyPopup_$overlay).children().bind("mousedown touchstart",function(){y.altKeyPopup_close()}).bind("mouseover mouseleave",function(e){i.removeClass(y.options.css.buttonHover),"mouseleave"!==e.type&&b(this).addClass(y.options.css.buttonHover)}),y.altKeyPopup_navigate(!0),y.altKeyPopup_savedIgnoreEsc=y.options.ignoreEsc,y.options.ignoreEsc=!0,b(document).unbind(y.altkeypopup_namespace).bind("keydown"+y.altkeypopup_namespace,function(){return!1}).bind("keyup"+y.altkeypopup_namespace,function(e){return"Escape"===e.key?(e.which=0,y.altKeyPopup_close()):y.altKeyPopup_navigate(e),!1}),p=(c.$popup=n).outerWidth(),(a=t.position().left-p/2)+p>c.kbWidth&&(a=c.kbWidth-p)<0&&n.css({width:c.kbWidth,height:"auto"}),s=t.position().top-t.outerHeight()-5,u=n.outerHeight(),r=y.$keyboard.find("."+d.keySet).position().top,s+u>c.kbHeight&&(s=c.kbHeight-u)').appendTo(y.$keyboard),y.$caret&&y.$caret.remove(),y.$caret=b('
').insertAfter(y.$preview),y.$el.unbind(i.kbChange+n).bind(i.kbChange+n,function(){y.findCaretPos()}),y.$preview.unbind(t).bind(t,function(){y.findCaretPos()})},y.findCaretPos=function(){if(y.caret_$div){var t,o,e,n,i,a,s,r,p=y.preview,u=parseFloat(y.$preview.css("fontSize")),l="INPUT"===p.nodeName,d=y.caret_$div[0];t=d.style,o=window.getComputedStyle?getComputedStyle(p,null):p.currentStyle,n=f.caret(y.$preview),i=Math["ltr"===o.direction?"max":"min"](n.start,n.end),y.textareaCaretProperties.forEach(function(e){t[e]=o[e]}),f.firefox&&(t.width=parseInt(o.width,10)-2+"px",p.scrollHeight>parseInt(o.height,10)&&(t.overflowY="scroll")),t.width=parseInt(l?p.scrollWidth:o.width,10)+(l?2*u:0)+"px",d.textContent=p.value.substring(0,i),"INPUT"===p.nodeName&&(d.textContent=d.textContent.replace(/\x20/g," ")),(s=document.createElement("span")).textContent=p.value.substring(i)||"​",d.appendChild(s),r=b(s).position(),n="center"===t.textAlign?u:0,y.caretPos={top:r.top+parseInt(o.borderTopWidth,10)+c.offsetY,left:r.left+parseInt(o.borderLeftWidth,10)+c.offsetX-n},e=parseInt(y.$caret.css("margin-top"),10),t=Math.round(u+2*e)+c.adjustHt,r=y.$preview.position(),y.$caret.css({top:r.top-p.scrollTop+y.caretPos.top-e,left:r.left-p.scrollLeft+y.caretPos.left,height:t}),a=p.value.substring(i,i+c.charIndex).replace(/\s/," ")||" ",y.$caret.attr(c.charAttr,a)}},y.$el.unbind(n).bind(i.kbBeforeVisible+n,function(){y.caret_setup()}).bind(i.kbVisible+n,function(){y.findCaretPos()}).bind(i.kbHidden+n,function(){var e="keyup keypress mouseup mouseleave ".split(" ").join(n+" ");y.$preview.unbind(e),y.$caret.remove(),y.$caret=null,y.caret_$div=null}),y.options.alwaysOpen&&y.isVisible()&&(y.caret_setup(),y.findCaretPos()))})}}),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(n){"use strict";var i=n.keyboard;i.css.extender="ui-keyboard-extender",i.language.en.display.extender=" :toggle_numpad",i.layouts.numpad={normal:["{clear} / * -","7 8 9 +","4 5 6 %","1 2 3 =","0 {dec} {left} {right}"]},i.keyaction.extender=function(e){return e.extender_toggle(),!1},n.fn.addExtender=function(e){var t={layout:"numpad",showing:!1,reposition:!0};return this.each(function(){var o=n(this).data("keyboard");if(o){if(o.extender_options=n.extend({},t,o.extender_options,e),o.extender_namespace)return o.extender_layoutSwitcher();o.extender_namespace=o.namespace+"extender",o.extensionNamespace.push(o.extender_namespace),o.extender_layoutSwitcher=function(){o.extender_lastKeyset=o.last.keyset,o.extender_bindEvents(!1),o.$el.one(i.events.kbBeforeVisible,function(){o.shiftActive=o.extender_lastKeyset[0],o.altActive=o.extender_lastKeyset[1],o.metaActive=o.extender_lastKeyset[2],o.showKeySet(),o.extender_setup(),o.extender_bindEvents()}),o.redraw()},o.extender_bindEvents=function(e){var t=i.events.kbBeforeVisible+o.extender_namespace;o.$el.unbind(t),!1!==e&&o.$el.bind(t,function(){o.extender_setup()})},o.extender_setup=function(){var e,t=o.extender_options.layout;void 0===i.builtLayouts[t]&&o.buildKeyboard(t),(e=i.builtLayouts[t].$keyboard.find("."+i.css.keySet+"-normal").clone()).removeClass().removeAttr("name").addClass(i.css.extender).children("button").removeAttr("data-pos"),e[0].style.display=o.extender_options.showing?"inline-block":"none",o.$keyboard.find("div."+i.css.extender).remove(),o.$keyboard.append(e),o.extender_toggle(o.extender_options.showing),o.bindKeys()},o.extender_toggle=function(e){o.extender_options.showing=void 0===e?!o.extender_options.showing:e,o.$keyboard.find("button."+i.css.extender).toggleClass(o.options.css.buttonActive,o.extender_options.showing).end().find("div."+i.css.extender)[0].style.display=o.extender_options.showing?"inline-block":"none",o.extender_options.reposition&&n(window).trigger("resize")},o.options.alwaysOpen&&o.isVisible()&&o.extender_setup(),o.extender_bindEvents()}})}}),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(s){s.fn.addMobile=function(e){var a,t={container:{theme:"b",cssClass:"ui-body"},input:{theme:"b",cssClass:""},buttonMarkup:{theme:"b",cssClass:"ui-btn",shadow:"true",corners:"true"},buttonHover:{theme:"b",cssClass:"ui-btn-hover"},buttonAction:{theme:"b",cssClass:"ui-btn-active"},buttonActive:{theme:"b",cssClass:"ui-btn-active"},allThemes:"a b c"};return this.each(function(){var i=s(this).data("keyboard");i&&void 0!==s.fn.textinput&&(i.mobile_options=a=s.extend(!0,{},t,e),i.mobile_themes=s.trim((" "+a.allThemes).split(" ").join(" "+a.buttonMarkup.cssClass+"-")+(" "+a.allThemes).split(" ").join(" "+a.buttonAction.cssClass+"-")+(" "+a.allThemes).split(" ").join(" "+a.buttonActive.cssClass+"-")),void 0===i.options.mobile_savedActiveClass&&(i.options.mobile_savedActiveClass=""+i.options.css.buttonActive),i.mobile_init=function(){var e=i.namespace+"Mobile";s("."+s.keyboard.css.input).textinput(),i.options.alwaysOpen&&i.isVisible&&i.mobile_setup(),i.extensionNamespace.push(e),i.$el.unbind(e).bind(s.keyboard.events.kbBeforeVisible+e,function(){i&&i.el.active&&i.$keyboard.length&&i.$keyboard.css("visibility","hidden")}).bind(s.keyboard.events.kbVisible+e,function(){i&&i.el.active&&i.$keyboard.length&&(i.mobile_setup(),i.$keyboard.css("visibility","visible"),i.$preview.focus())})},i.mobile_setup=function(){var e,t=s.keyboard.css,o=i.options,n=i.mobile_themes;i.mobile_$actionKeys=i.$keyboard.find("."+i.options.css.buttonAction),o.css.buttonActive=o.mobile_savedActiveClass+" "+i.modOptions(a.buttonActive,a.buttonMarkup),i.$keyboard.addClass(i.modOptions(a.container,a.container)).find("."+t.preview).removeClass("ui-widget ui-widget-content").addClass(i.modOptions(a.input,a.input)).end().find("button").removeClass(s.trim("ui-corner-all ui-state-default "+n)).addClass(i.modOptions(a.buttonMarkup,a.buttonMarkup)).not(i.mobile_$actionKeys).hover(function(){s(this).removeClass(n).addClass(i.modOptions(a.buttonHover,a.buttonMarkup))},function(){s(this).removeClass(n+" "+a.buttonHover.cssClass).addClass(i.modOptions(a.buttonMarkup,a.buttonMarkup))}),i.mobile_$actionKeys.removeClass(n).addClass(i.modOptions(a.buttonAction,a.buttonMarkup)),i.msie&&i.$preview[0]!==i.el&&(i.$preview.hide(),i.$keyboard.css("width",""),i.width=i.$keyboard.outerWidth(),i.$keyboard.width(i.width+parseInt(i.$preview.css("fontSize"),10)),i.$preview.width(i.width),i.$preview.show()),s.ui&&s.ui.position&&((e=o.position).of=e.of||i.$el.data("keyboardPosition")||i.$el,e.collision=e.collision||"flipfit flipfit",i.$keyboard.position(e))},i.modOptions=function(e,t){return" "+(e.cssClass||"")+" "+(t&&t.cssClass?t.cssClass+"-"+(e.theme||""):"")+("true"==e.shadow?" ui-shadow":"")+("true"==e.corners?" ui-corner-all":"")},i.mobile_init())})}}),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(b){"use strict";b.keyboard=b.keyboard||{},b.keyboard.navigationKeys={toggle:112,enter:13,pageup:33,pagedown:34,end:35,home:36,left:37,up:38,right:39,down:40,caretrt:45,caretlt:46,caretright:function(e){b.keyboard.keyaction.right(e)},caretleft:function(e){b.keyboard.keyaction.left(e)}},b.fn.addNavigation=function(t){return this.each(function(){var l,e,d=b(this).data("keyboard"),c=d.options,n=b.keyboard.events,y=b.keyboard.css;d&&(d.navigation_options=l=b.extend({},{position:[0,0],toggleMode:!1,focusClass:"hasFocus",toggleKey:null,rowLooping:!1},t),d.navigation_keys=e=b.extend({},b.keyboard.navigationKeys),d.navigation_namespace=d.namespace+"Nav",d.extensionNamespace.push(d.navigation_namespace),d.saveNav=[d.options.tabNavigation,d.options.enterNavigation],d.allNavKeys=b.map(e,function(e){return e}),d.navigation_init=function(){d.$keyboard.toggleClass(l.focusClass,l.toggleMode).find("."+y.keySet+":visible").find("."+y.keyButton+'[data-pos="'+l.position[0]+","+l.position[1]+'"]').addClass(c.css.buttonHover),d.$preview.unbind(d.navigation_namespace).bind("keydown"+d.navigation_namespace,function(e){return d.checkKeys(e.which)})},d.checkKeys=function(e,t){if(void 0!==e&&d.isVisible()){var o=d.navigation_keys;return(e===(l.toggleKey||o.toggle)||t)&&(l.toggleMode=!t&&!l.toggleMode,d.options.tabNavigation=!l.toggleMode&&d.saveNav[0],d.options.enterNavigation=!l.toggleMode&&d.saveNav[1]),d.$keyboard.toggleClass(l.focusClass,l.toggleMode),l.toggleMode&&e===o.enter?(d.$keyboard.find("."+y.keySet+":visible").find("."+y.keyButton+'[data-pos="'+l.position[0]+","+l.position[1]+'"]').trigger(n.kbRepeater),!1):l.toggleMode&&0<=b.inArray(e,d.allNavKeys)?(d.navigateKeys(e),!1):void 0}},d.getMaxIndex=function(e,t){return e.find("."+y.keyButton+'[data-pos^="'+t+',"]').length-1},d.leftNavigateKey=function(e,t){var o=d.navigation_options.rowLooping,n=e-1;return 0<=n?n:o?t:0},d.rightNavigateKey=function(e,t){var o=d.navigation_options.rowLooping,n=e+1;return n<=t?n:o?0:t},d.navigateKeys=function(e,t,o){if(d.isVisible()){o="number"==typeof o?o:l.position[1],t="number"==typeof t?t:l.position[0];var n,i=d.$keyboard.find("."+y.keySet+":visible"),a=i.find("."+y.endRow).length-1,s=d.getMaxIndex(i,t),r=d.last,p=d.$preview.val().length,u=d.navigation_keys;switch(e){case u.pageup:t=0;break;case u.pagedown:t=a;break;case u.end:o=s;break;case u.home:o=0;break;case u.left:o=d.leftNavigateKey(o,s);break;case u.up:t+=0p?p:r.start,d.last.start=d.last.end=r.end=r.start,b.keyboard.caret(d.$preview,d.last)),(s=d.getMaxIndex(i,t))').css({width:c.kbWidth,height:c.kbHeight}).appendTo(d.$keyboard).bind("click touchstart",function(){d.altKeyPopup_close()}),y="inactive hidden ".split(" ").join(d.altkeypopup_namespace+" "),d.$keyboard.addClass(b.css.altKeyPopupOpen),d.$el.unbind(y).bind(y,function(){d.altKeyPopup_close()}),"bksp"!==e&&b.keyaction.bksp(d),t=k('
'),o=b.altKeys[e].split(/\s+/),d.buildRow(t,0,o,[]),a=t.appendTo(d.altKeyPopup_$overlay).children().bind("mousedown touchstart",function(){d.altKeyPopup_close()}).bind("mouseover mouseleave",function(e){a.removeClass(d.options.css.buttonHover),"mouseleave"!==e.type&&k(this).addClass(d.options.css.buttonHover)}),d.altKeyPopup_navigate(!0),d.altKeyPopup_savedIgnoreEsc=d.options.ignoreEsc,d.options.ignoreEsc=!0,k(document).unbind(d.altkeypopup_namespace).bind("keydown"+d.altkeypopup_namespace,function(){return!1}).bind("keyup"+d.altkeypopup_namespace,function(e){return"Escape"===e.key?(e.which=0,d.altKeyPopup_close()):d.altKeyPopup_navigate(e),!1}),s=(c.$popup=t).outerWidth(),(n=p.position().left-s/2)+s>c.kbWidth&&(n=c.kbWidth-s)<0&&t.css({width:c.kbWidth,height:"auto"}),i=p.position().top-p.outerHeight()-5,l=t.outerHeight(),u=d.$keyboard.find("."+r.keySet).position().top,i+l>c.kbHeight&&(i=c.kbHeight-l)').appendTo(u.$keyboard),u.$caret&&u.$caret.remove(),u.$caret=b('
').insertAfter(u.$preview),u.$el.unbind(o.kbChange+i).bind(o.kbChange+i,function(){u.findCaretPos()}),u.$preview.unbind(t).bind(t,function(){u.findCaretPos()})},u.findCaretPos=function(){if(u.caret_$div){var t,r,e,i,o,n,a,s,d=u.preview,c=parseFloat(u.$preview.css("fontSize")),p="INPUT"===d.nodeName,l=u.caret_$div[0];t=l.style,r=window.getComputedStyle?getComputedStyle(d,null):d.currentStyle,i=h.caret(u.$preview),o=Math["ltr"===r.direction?"max":"min"](i.start,i.end),u.textareaCaretProperties.forEach(function(e){t[e]=r[e]}),h.firefox&&(t.width=parseInt(r.width,10)-2+"px",d.scrollHeight>parseInt(r.height,10)&&(t.overflowY="scroll")),t.width=parseInt(p?d.scrollWidth:r.width,10)+(p?2*c:0)+"px",l.textContent=d.value.substring(0,o),"INPUT"===d.nodeName&&(l.textContent=l.textContent.replace(/\x20/g," ")),(a=document.createElement("span")).textContent=d.value.substring(o)||"​",l.appendChild(a),s=b(a).position(),i="center"===t.textAlign?c:0,u.caretPos={top:s.top+parseInt(r.borderTopWidth,10)+f.offsetY,left:s.left+parseInt(r.borderLeftWidth,10)+f.offsetX-i},e=parseInt(u.$caret.css("margin-top"),10),t=Math.round(c+2*e)+f.adjustHt,s=u.$preview.position(),u.$caret.css({top:s.top-d.scrollTop+u.caretPos.top-e,left:s.left-d.scrollLeft+u.caretPos.left,height:t}),n=d.value.substring(o,o+f.charIndex).replace(/\s/," ")||" ",u.$caret.attr(f.charAttr,n)}},u.$el.unbind(i).bind(o.kbBeforeVisible+i,function(){u.caret_setup()}).bind(o.kbVisible+i,function(){u.findCaretPos()}).bind(o.kbHidden+i,function(){var e="keyup keypress mouseup mouseleave ".split(" ").join(i+" ");u.$preview.unbind(e),u.$caret.remove(),u.$caret=null,u.caret_$div=null}),u.options.alwaysOpen&&u.isVisible()&&(u.caret_setup(),u.findCaretPos()))})}}); \ No newline at end of file diff --git a/koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-extender.min.js b/koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-extender.min.js new file mode 100644 index 0000000000..44549bf0f1 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-extender.min.js @@ -0,0 +1,2 @@ +/*! jQuery UI Virtual Keyboard Extender v1.0.3 */ +!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(o){"use strict";var s=o.keyboard;s.css.extender="ui-keyboard-extender",s.language.en.display.extender=" :toggle_numpad",s.layouts.numpad={normal:["{clear} / * -","7 8 9 +","4 5 6 %","1 2 3 =","0 {dec} {left} {right}"]},s.keyaction.extender=function(e){return e.extender_toggle(),!1},o.fn.addExtender=function(e){var n={layout:"numpad",showing:!1,reposition:!0};return this.each(function(){var t=o(this).data("keyboard");if(t){if(t.extender_options=o.extend({},n,t.extender_options,e),t.extender_namespace)return t.extender_layoutSwitcher();t.extender_namespace=t.namespace+"extender",t.extensionNamespace.push(t.extender_namespace),t.extender_layoutSwitcher=function(){t.extender_lastKeyset=t.last.keyset,t.extender_bindEvents(!1),t.$el.one(s.events.kbBeforeVisible,function(){t.shiftActive=t.extender_lastKeyset[0],t.altActive=t.extender_lastKeyset[1],t.metaActive=t.extender_lastKeyset[2],t.showKeySet(),t.extender_setup(),t.extender_bindEvents()}),t.redraw()},t.extender_bindEvents=function(e){var n=s.events.kbBeforeVisible+t.extender_namespace;t.$el.unbind(n),!1!==e&&t.$el.bind(n,function(){t.extender_setup()})},t.extender_setup=function(){var e,n=t.extender_options.layout;void 0===s.builtLayouts[n]&&t.buildKeyboard(n),(e=s.builtLayouts[n].$keyboard.find("."+s.css.keySet+"-normal").clone()).removeClass().removeAttr("name").addClass(s.css.extender).children("button").removeAttr("data-pos"),e[0].style.display=t.extender_options.showing?"inline-block":"none",t.$keyboard.find("div."+s.css.extender).remove(),t.$keyboard.append(e),t.extender_toggle(t.extender_options.showing),t.bindKeys()},t.extender_toggle=function(e){t.extender_options.showing=void 0===e?!t.extender_options.showing:e,t.$keyboard.find("button."+s.css.extender).toggleClass(t.options.css.buttonActive,t.extender_options.showing).end().find("div."+s.css.extender)[0].style.display=t.extender_options.showing?"inline-block":"none",t.extender_options.reposition&&o(window).trigger("resize")},t.options.alwaysOpen&&t.isVisible()&&t.extender_setup(),t.extender_bindEvents()}})}}); \ No newline at end of file diff --git a/koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-mobile.min.js b/koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-mobile.min.js new file mode 100644 index 0000000000..60ffd2daa1 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-mobile.min.js @@ -0,0 +1,2 @@ +/*! jQuery UI Virtual Keyboard for jQuery Mobile Themes v1.4.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(a){a.fn.addMobile=function(e){var n,t={container:{theme:"b",cssClass:"ui-body"},input:{theme:"b",cssClass:""},buttonMarkup:{theme:"b",cssClass:"ui-btn",shadow:"true",corners:"true"},buttonHover:{theme:"b",cssClass:"ui-btn-hover"},buttonAction:{theme:"b",cssClass:"ui-btn-active"},buttonActive:{theme:"b",cssClass:"ui-btn-active"},allThemes:"a b c"};return this.each(function(){var o=a(this).data("keyboard");o&&void 0!==a.fn.textinput&&(o.mobile_options=n=a.extend(!0,{},t,e),o.mobile_themes=a.trim((" "+n.allThemes).split(" ").join(" "+n.buttonMarkup.cssClass+"-")+(" "+n.allThemes).split(" ").join(" "+n.buttonAction.cssClass+"-")+(" "+n.allThemes).split(" ").join(" "+n.buttonActive.cssClass+"-")),void 0===o.options.mobile_savedActiveClass&&(o.options.mobile_savedActiveClass=""+o.options.css.buttonActive),o.mobile_init=function(){var e=o.namespace+"Mobile";a("."+a.keyboard.css.input).textinput(),o.options.alwaysOpen&&o.isVisible&&o.mobile_setup(),o.extensionNamespace.push(e),o.$el.unbind(e).bind(a.keyboard.events.kbBeforeVisible+e,function(){o&&o.el.active&&o.$keyboard.length&&o.$keyboard.css("visibility","hidden")}).bind(a.keyboard.events.kbVisible+e,function(){o&&o.el.active&&o.$keyboard.length&&(o.mobile_setup(),o.$keyboard.css("visibility","visible"),o.$preview.focus())})},o.mobile_setup=function(){var e,t=a.keyboard.css,s=o.options,i=o.mobile_themes;o.mobile_$actionKeys=o.$keyboard.find("."+o.options.css.buttonAction),s.css.buttonActive=s.mobile_savedActiveClass+" "+o.modOptions(n.buttonActive,n.buttonMarkup),o.$keyboard.addClass(o.modOptions(n.container,n.container)).find("."+t.preview).removeClass("ui-widget ui-widget-content").addClass(o.modOptions(n.input,n.input)).end().find("button").removeClass(a.trim("ui-corner-all ui-state-default "+i)).addClass(o.modOptions(n.buttonMarkup,n.buttonMarkup)).not(o.mobile_$actionKeys).hover(function(){a(this).removeClass(i).addClass(o.modOptions(n.buttonHover,n.buttonMarkup))},function(){a(this).removeClass(i+" "+n.buttonHover.cssClass).addClass(o.modOptions(n.buttonMarkup,n.buttonMarkup))}),o.mobile_$actionKeys.removeClass(i).addClass(o.modOptions(n.buttonAction,n.buttonMarkup)),o.msie&&o.$preview[0]!==o.el&&(o.$preview.hide(),o.$keyboard.css("width",""),o.width=o.$keyboard.outerWidth(),o.$keyboard.width(o.width+parseInt(o.$preview.css("fontSize"),10)),o.$preview.width(o.width),o.$preview.show()),a.ui&&a.ui.position&&((e=s.position).of=e.of||o.$el.data("keyboardPosition")||o.$el,e.collision=e.collision||"flipfit flipfit",o.$keyboard.position(e))},o.modOptions=function(e,t){return" "+(e.cssClass||"")+" "+(t&&t.cssClass?t.cssClass+"-"+(e.theme||""):"")+("true"==e.shadow?" ui-shadow":"")+("true"==e.corners?" ui-corner-all":"")},o.mobile_init())})}}); \ No newline at end of file diff --git a/koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-navigation.min.js b/koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-navigation.min.js new file mode 100644 index 0000000000..a424d1e230 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/lib/keyboard/js/jquery.keyboard.extension-navigation.min.js @@ -0,0 +1,2 @@ +/*! jQuery UI Virtual Keyboard Navigation v1.7.0 */ +!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(u){"use strict";u.keyboard=u.keyboard||{},u.keyboard.navigationKeys={toggle:112,enter:13,pageup:33,pagedown:34,end:35,home:36,left:37,up:38,right:39,down:40,caretrt:45,caretlt:46,caretright:function(e){u.keyboard.keyaction.right(e)},caretleft:function(e){u.keyboard.keyaction.left(e)}},u.fn.addNavigation=function(t){return this.each(function(){var c,e,v=u(this).data("keyboard"),y=v.options,n=u.keyboard.events,l=u.keyboard.css;v&&(v.navigation_options=c=u.extend({},{position:[0,0],toggleMode:!1,focusClass:"hasFocus",toggleKey:null,rowLooping:!1},t),v.navigation_keys=e=u.extend({},u.keyboard.navigationKeys),v.navigation_namespace=v.namespace+"Nav",v.extensionNamespace.push(v.navigation_namespace),v.saveNav=[v.options.tabNavigation,v.options.enterNavigation],v.allNavKeys=u.map(e,function(e){return e}),v.navigation_init=function(){v.$keyboard.toggleClass(c.focusClass,c.toggleMode).find("."+l.keySet+":visible").find("."+l.keyButton+'[data-pos="'+c.position[0]+","+c.position[1]+'"]').addClass(y.css.buttonHover),v.$preview.unbind(v.navigation_namespace).bind("keydown"+v.navigation_namespace,function(e){return v.checkKeys(e.which)})},v.checkKeys=function(e,t){if(void 0!==e&&v.isVisible()){var a=v.navigation_keys;return(e===(c.toggleKey||a.toggle)||t)&&(c.toggleMode=!t&&!c.toggleMode,v.options.tabNavigation=!c.toggleMode&&v.saveNav[0],v.options.enterNavigation=!c.toggleMode&&v.saveNav[1]),v.$keyboard.toggleClass(c.focusClass,c.toggleMode),c.toggleMode&&e===a.enter?(v.$keyboard.find("."+l.keySet+":visible").find("."+l.keyButton+'[data-pos="'+c.position[0]+","+c.position[1]+'"]').trigger(n.kbRepeater),!1):c.toggleMode&&0<=u.inArray(e,v.allNavKeys)?(v.navigateKeys(e),!1):void 0}},v.getMaxIndex=function(e,t){return e.find("."+l.keyButton+'[data-pos^="'+t+',"]').length-1},v.leftNavigateKey=function(e,t){var a=v.navigation_options.rowLooping,n=e-1;return 0<=n?n:a?t:0},v.rightNavigateKey=function(e,t){var a=v.navigation_options.rowLooping,n=e+1;return n<=t?n:a?0:t},v.navigateKeys=function(e,t,a){if(v.isVisible()){a="number"==typeof a?a:c.position[1],t="number"==typeof t?t:c.position[0];var n,o=v.$keyboard.find("."+l.keySet+":visible"),i=o.find("."+l.endRow).length-1,s=v.getMaxIndex(o,t),r=v.last,g=v.$preview.val().length,d=v.navigation_keys;switch(e){case d.pageup:t=0;break;case d.pagedown:t=i;break;case d.end:a=s;break;case d.home:a=0;break;case d.left:a=v.leftNavigateKey(a,s);break;case d.up:t+=0g?g:r.start,v.last.start=v.last.end=r.end=r.start,u.keyboard.caret(v.$preview,v.last)),(s=v.getMaxIndex(o,t)) 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 = (Object.prototype.toString.call(lang) === '[object Array]' ? 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) + if (kblang[lang] && kblang[lang].comboRegex) { + base.regex = kblang[lang].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 (typeof o.create === 'function') { + // 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.isTextArea) { + 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 + $('
') + .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, + 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 (!base.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 (base.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 (typeof o.change === 'function') { + event.type = $keyboard.events.inputChange; + o.change(event, base, base.el); + return false; + } + if (o.acceptValid && o.autoAcceptOnValid) { + if ( + typeof o.validate === 'function' && + 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 && typeof $keyboard.keyaction[action] === 'function') { + // 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 (typeof o.change === 'function') { + 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 ( + typeof o.validate === 'function' && + 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.isTextArea) { + // This makes sure the caret moves to the next line after clicking on enter (manual typing works fine) + if ($keyboard.msie && val.substring(pos.start, 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.substring(0, t - (bksp ? 1 : 0)) + txt + val.substring(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.substring(pos.start, 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 (typeof o.validate === 'function') { + 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 (typeof o.switchInput === 'function') { + 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 && typeof o.validate === 'function' && !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 = $('