diff --git a/addons/point_of_sale/static/src/css/pos.css b/addons/point_of_sale/static/src/css/pos.css
index 09fbe3818f2..47ea23f202b 100644
--- a/addons/point_of_sale/static/src/css/pos.css
+++ b/addons/point_of_sale/static/src/css/pos.css
@@ -487,3 +487,149 @@
}
}
+/* Onscreen Keyboard http://net.tutsplus.com/tutorials/javascript-ajax/creating-a-keyboard-with-css-and-jquery/ */
+
+.point-of-sale .keyboard_frame{
+ display: none;
+ position:absolute;
+ left: 0;
+ bottom: 0px;
+ margin: 0;
+ padding: 0;
+ padding-top: 15px;
+ width: 100%;
+ height: 0px; /* 235px, animated via jquery */
+ background-color: #BBB;
+ overflow:hidden;
+ -webkit-box-shadow: 0px 0px 10px rgba(0,0,0, 0.3);
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+
+}
+.point-of-sale .keyboard_frame .close_button{
+ height:40px;
+ width:60px;
+ text-align:center;
+ background-color: #DDD;
+ font-size: 12px;
+ line-height:40px;
+ border: 1px solid #CCC;
+ -webkit-border-radius: 5px;
+ -webkit-box-shadow: 0px 2px 5px rgba(0,0,0, 0.2);
+ position:absolute;
+ top:0;
+ right:15px;
+ cursor: pointer;
+}
+.point-of-sale .keyboard li {
+ float: left;
+ text-align: center;
+ background-color: #fff;
+ border: 1px solid #f0f0f0;
+ top:0;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ -webkit-box-shadow: 0px 2px 5px rgba(0,0,0, 0.2);
+ -webkit-transition-property: top, background-color;
+ -webkit-transition-duration: 0.2s;
+ -webkit-transition-timing-function: linear;
+}
+.point-of-sale .keyboard li:hover {
+ position: relative;
+ top: 2px;
+ left: 0px;
+ border-color: #ddd;
+ background-color:#e5e5e5;
+ cursor: pointer;
+ -webkit-transition-property: top, background-color;
+ -webkit-transition-duration: 0.1s;
+ -webkit-transition-timing-function: ease-out;
+}
+.point-of-sale .uppercase {
+ text-transform: uppercase;
+}
+.point-of-sale .on {
+ display: none;
+}
+.point-of-sale .firstitem{
+ clear: left;
+}
+.point-of-sale .keyboard .lastitem {
+ margin-right: 0;
+}
+
+/* ---- full sized keyboard ---- */
+
+.point-of-sale .full_keyboard {
+ list-style: none;
+ font-size: 14px;
+ width: 680px;
+ height: 100%;
+ margin-left: auto;
+ margin-right: auto;
+}
+.point-of-sale .full_keyboard li{
+ margin: 0 5px 5px 0;
+ width: 40px;
+ height: 40px;
+ line-height: 40px;
+}
+.point-of-sale .full_keyboard .tab, .point-of-sale .full_keyboard .delete {
+ width: 70px;
+}
+.point-of-sale .full_keyboard .capslock {
+ width: 80px;
+}
+.point-of-sale .full_keyboard .return {
+ width: 77px;
+}
+.point-of-sale .full_keyboard .left-shift {
+ width: 95px;
+}
+.point-of-sale .full_keyboard .right-shift {
+ width: 109px;
+}
+.point-of-sale .full_keyboard .space {
+ clear: left;
+ width: 673px;
+}
+
+/* ---- simplified keyboard ---- */
+
+.point-of-sale .simple_keyboard {
+ list-style: none;
+ font-size: 16px;
+ width: 545px;
+ height: 220px;
+ margin-left: auto;
+ margin-right: auto;
+}
+.point-of-sale .simple_keyboard li{
+ margin: 0 5px 5px 0;
+ width: 49px;
+ height: 49px;
+ line-height: 49px;
+}
+.point-of-sale .simple_keyboard .firstitem.row_asdf{
+ margin-left:25px;
+}
+.point-of-sale .simple_keyboard .firstitem.row_zxcv{
+ margin-left:55px;
+}
+.point-of-sale .simple_keyboard .delete{
+ width: 103px;
+}
+.point-of-sale .simple_keyboard .return{
+ width: 103px;
+}
+.point-of-sale .simple_keyboard .space{
+ width:268px;
+}
+.point-of-sale .simple_keyboard .numlock{
+ width:103px;
+}
+
diff --git a/addons/point_of_sale/static/src/js/pos.js b/addons/point_of_sale/static/src/js/pos.js
index a03e34a3e53..7d37ae5dd8c 100644
--- a/addons/point_of_sale/static/src/js/pos.js
+++ b/addons/point_of_sale/static/src/js/pos.js
@@ -1082,6 +1082,198 @@ openerp.point_of_sale = function(db) {
}
});
+ // A Widget that displays an onscreen keyboard.
+ // There are two options when creating the widget :
+ //
+ // * 'keyboard_model' : 'simple' | 'full' (default)
+ // The 'full' emulates a PC keyboard, while 'simple' emulates an 'android' one.
+ //
+ // * 'input_selector : (default: '.searchbox input')
+ // defines the dom element that the keyboard will write to.
+ //
+ // The widget is initally hidden. It can be shown with this.show(), and is
+ // automatically shown when the input_selector gets focused.
+ var OnscreenKeyboardWidget = db.web.Widget.extend({
+ tagName: 'div',
+
+ init: function(parent, options){
+ var self = this;
+
+ function get_option(opt,default_value){
+ if(options){
+ return options[opt] || default_value;
+ }else{
+ return default_value;
+ }
+ }
+
+ this.keyboard_model = get_option('keyboard_model','full');
+ this.template_simple = qweb_template('pos-onscreen-keyboard-simple-template');
+ this.template_full = qweb_template('pos-onscreen-keyboard-full-template');
+
+ this.template_fct = function(){
+ if( this.keyboard_model == 'full' ){
+ return this.template_full.apply(this,arguments);
+ }else{
+ return this.template_simple.apply(this,arguments);
+ }
+ };
+
+ this.input_selector = get_option('input_selector','.searchbox input');
+
+ //show the keyboard when the input zone is clicked.
+ $(this.input_selector).focus(function(){self.show();});
+
+ //Keyboard state
+ this.capslock = false;
+ this.shift = false;
+ this.numlock = false;
+ },
+
+ // Write a character to the input zone
+ writeCharacter: function(character){
+ var $input = $(this.input_selector);
+ $input[0].value += character;
+ $input.keydown();
+ $input.keyup();
+ },
+
+ // Sends a 'return' character to the input zone. TODO
+ sendReturn: function(){
+ },
+
+ // Removes the last character from the input zone.
+ deleteCharacter: function(){
+ var $input = $(this.input_selector);
+ var input_value = $input[0].value;
+ $input[0].value = input_value.substr(0, input_value.length - 1);
+ $input.keydown();
+ $input.keyup();
+ },
+
+ // Clears the content of the input zone.
+ deleteAllCharacters: function(){
+ var $input = $(this.input_selector);
+ $input[0].value = "";
+ $input.keydown();
+ $input.keyup();
+ },
+ renderElement: function(){
+ this.$element.html(this.template_fct());
+ },
+
+ // Makes the keyboard show and slide from the bottom of the screen.
+ show: function(){
+ $('.keyboard_frame').show().animate({'height':'235px'}, 500, 'swing');
+ },
+
+ // Makes the keyboard hide by sliding to the bottom of the screen.
+ hide: function(){
+ var self = this;
+ var frame = $('.keyboard_frame');
+ frame.animate({'height':'0'}, 500, 'swing', function(){ frame.hide(); self.reset(); });
+ },
+
+ //What happens when the shift key is pressed : toggle case, remove capslock
+ toggleShift: function(){
+ $('.letter').toggleClass('uppercase');
+ $('.symbol span').toggle();
+
+ self.shift = (self.shift === true) ? false : true;
+ self.capslock = false;
+ },
+
+ //what happens when capslock is pressed : toggle case, set capslock
+ toggleCapsLock: function(){
+ $('.letter').toggleClass('uppercase');
+ self.capslock = true;
+ },
+
+ //What happens when numlock is pressed : toggle symbols and numlock label
+ toggleNumLock: function(){
+ $('.symbol span').toggle();
+ $('.numlock span').toggle();
+ self.numlock = (self.numlock === true ) ? false : true;
+ },
+
+ //After a key is pressed, shift is disabled.
+ removeShift: function(){
+ if (self.shift === true) {
+ $('.symbol span').toggle();
+ if (this.capslock === false) $('.letter').toggleClass('uppercase');
+
+ self.shift = false;
+ }
+ },
+
+ // Resets the keyboard to its original state; capslock: false, shift: false, numlock: false
+ reset: function(){
+ if(this.shift){
+ this.toggleShift();
+ }
+ if(this.capslock){
+ this.toggleCapsLock();
+ }
+ if(this.numlock){
+ this.toggleNumLock();
+ }
+ },
+
+ //called after the keyboard is in the DOM, sets up the key bindings.
+ start: function(){
+ var self = this;
+
+ //this.show();
+
+
+ $('.close_button').click(function(){
+ self.deleteAllCharacters();
+ self.hide();
+ });
+
+ // Keyboard key click handling
+ $('.keyboard li').click(function(){
+
+ var $this = $(this),
+ character = $this.html(); // If it's a lowercase letter, nothing happens to this variable
+
+ if ($this.hasClass('left-shift') || $this.hasClass('right-shift')) {
+ self.toggleShift();
+ return false;
+ }
+
+ if ($this.hasClass('capslock')) {
+ self.toggleCapsLock();
+ return false;
+ }
+
+ if ($this.hasClass('delete')) {
+ self.deleteCharacter();
+ return false;
+ }
+
+ if ($this.hasClass('numlock')){
+ self.toggleNumLock();
+ return false;
+ }
+
+ // Special characters
+ if ($this.hasClass('symbol')) character = $('span:visible', $this).html();
+ if ($this.hasClass('space')) character = ' ';
+ if ($this.hasClass('tab')) character = "\t";
+ if ($this.hasClass('return')) character = "\n";
+
+ // Uppercase letter
+ if ($this.hasClass('uppercase')) character = character.toUpperCase();
+
+ // Remove shift once a key is clicked.
+ self.removeShift();
+
+ self.writeCharacter(character);
+ });
+ },
+ });
+
var ShopWidget = db.web.OldWidget.extend({
init: function(parent, options) {
this._super(parent);
@@ -1179,6 +1371,9 @@ openerp.point_of_sale = function(db) {
this.categoryView = new CategoryWidget(null, 'products-screen-categories');
this.categoryView.on_change_category.add_last(_.bind(this.category, this));
this.category();
+
+ this.onscreenKeyboard = new OnscreenKeyboardWidget(null,{keyboard_model:'simple'});
+ this.onscreenKeyboard.appendTo($(".point-of-sale #content"));
};
App.prototype.category = function(id) {
diff --git a/addons/point_of_sale/static/src/xml/pos.xml b/addons/point_of_sale/static/src/xml/pos.xml
index 16192f208c8..b772b9ca2e5 100644
--- a/addons/point_of_sale/static/src/xml/pos.xml
+++ b/addons/point_of_sale/static/src/xml/pos.xml
@@ -294,4 +294,108 @@
+
+
+
+
+ - `~
+ - 1!
+ - 2@
+ - 3#
+ - 4$
+ - 5%
+ - 6^
+ - 7&
+ - 8*
+ - 9(
+ - 0)
+ - -_
+ - =+
+ - delete
+ - tab
+ - q
+ - w
+ - e
+ - r
+ - t
+ - y
+ - u
+ - i
+ - o
+ - p
+ - [{
+ - ]}
+ - \|
+ - caps lock
+ - a
+ - s
+ - d
+ - f
+ - g
+ - h
+ - j
+ - k
+ - l
+ - ;:
+ - '"
+ - return
+ - shift
+ - z
+ - x
+ - c
+ - v
+ - b
+ - n
+ - m
+ - ,<
+ - .>
+ - /?
+ - shift
+ -
+
+
close
+
+
+
+
+
+ - q1
+ - w2
+ - e3
+ - r4
+ - t5
+ - y6
+ - u7
+ - i8
+ - o9
+ - p0
+
+ - a@
+ - s#
+ - d%
+ - f*
+ - g/
+ - h-
+ - j+
+ - k(
+ - l)
+
+ - z?
+ - x!
+ - c"
+ - v'
+ - b:
+ - n;
+ - m,
+ - delete
+
+ - 123ABC
+ -
+ - ..
+ - return
+
+
close
+
+