[WIP] point_of_sale: split screens / popups / gui into own files

This commit is contained in:
Frédéric van der Essen
2014-12-31 15:34:31 +01:00
parent 1ac9c4957a
commit 5e3600224b
6 changed files with 592 additions and 548 deletions
+2 -22
View File
@@ -949,7 +949,7 @@ openerp.point_of_sale.load_chrome = function load_chrome(instance, module){ //mo
}));
popup.find('.button').click(function(){
self.close();
self.gui.close();
});
popup.css({ zindex: 9001 });
@@ -1040,7 +1040,7 @@ openerp.point_of_sale.load_chrome = function load_chrome(instance, module){ //mo
},2000);
} else {
clearTimeout(this.confirmed);
this.chrome.close();
this.gui.close();
}
},
}
@@ -1137,26 +1137,6 @@ openerp.point_of_sale.load_chrome = function load_chrome(instance, module){ //mo
}
}
},
close: function() {
var self = this;
self.loading_show();
self.loading_message(_t('Closing ...'));
self.pos.push_order().then(function(){
return new instance.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_client_pos_menu']], ['res_id'])
.pipe(function(res) {
window.location = '/web#action=' + res[0]['res_id'];
},function(err,event) {
event.preventDefault();
self.gui.show_popup('error',{
'title': _t('Could not close the point of sale.'),
'body': _t('Your internet connection is probably down.'),
});
self.close_button.renderElement();
});
});
},
destroy: function() {
this.pos.destroy();
instance.webclient.set_content_full_screen(false);
+326
View File
@@ -0,0 +1,326 @@
// this file contains the Gui, which is the pos 'controller'.
// It contains high level methods to manipulate the interface
// such as changing between screens, creating popups, etc.
//
// it is available to all pos objects trough the '.gui' field.
openerp.point_of_sale.load_gui = function load_gui(instance, module) {
"use strict";
var QWeb = instance.web.qweb;
var _t = instance.web._t;
module.Gui = instance.web.Class.extend({
init: function(options){
var self = this;
this.pos = options.pos;
this.chrome = options.chrome;
this.screen_set = {};
this.popup_set = {};
this.default_screen = null;
this.startup_screen = null;
this.current_popup = null;
this.current_screen = null;
this.chrome.ready.then(function(){
var order = self.pos.get_order();
if (order) {
self.show_saved_screen(order);
} else {
self.show_screen(self.startup_screen);
}
self.pos.bind('change:selectedOrder', function(){
self.show_saved_screen(self.pos.get_order());
});
});
},
/* ---- Gui: SCREEN MANIPULATION ---- */
// register a screen widget to the gui,
// it must have been inserted into the dom.
add_screen: function(name, screen){
screen.hide();
this.screen_set[name] = screen;
},
// sets the screen that will be displayed
// for new orders
set_default_screen: function(name){
this.default_screen = name;
},
// sets the screen that will be displayed
// when no orders are present
set_startup_screen: function(name) {
this.startup_screen = name;
},
// display the screen saved in an order,
// called when the user changes the current order
// no screen saved ? -> display default_screen
// no order ? -> display startup_screen
show_saved_screen: function(order,options) {
options = options || {};
this.close_popup();
if (order) {
this.show_screen(order.get_screen_data('screen') ||
options.default_screen ||
this.default_screen,
null,'refresh');
} else {
this.show_screen(this.startup_screen);
}
},
// display a screen.
// If there is an order, the screen will be saved in the order
// - params: used to load a screen with parameters, for
// example loading a 'product_details' screen for a specific product.
// - refresh: if you want the screen to cycle trough show / hide even
// if you are already on the same screen.
show_screen: function(screen_name,params,refresh) {
var screen = this.screen_set[screen_name];
if (!screen) {
console.error("ERROR: show_screen("+screen_name+") : screen not found");
}
this.close_popup();
var order = this.pos.get_order();
if (order) {
var old_screen_name = order.get_screen_data('screen');
order.set_screen_data('screen',screen_name);
if(params){
order.set_screen_data('params',params);
}
if( screen_name !== old_screen_name ){
order.set_screen_data('previous-screen',old_screen_name);
}
}
if (refresh || screen !== this.current_screen) {
if (this.current_screen) {
this.current_screen.close();
this.current_screen.hide();
}
this.current_screen = screen;
this.current_screen.show();
}
},
// returns the current screen.
get_current_screen: function() {
return this.pos.get_order().get_screen_data('screen') || this.default_screen;
},
// goes to the previous screen (as specified in the order). The history only
// goes 1 deep ...
back: function() {
var previous = this.pos.get_order().get_screen_data('previous-screen');
if (previous) {
this.show_screen(previous);
}
},
// returns the parameter specified when this screen was displayed
get_current_screen_param: function(param) {
var params = this.pos.get_order().get_screen_data('params');
return params ? params[param] : undefined;
},
/* ---- Gui: POPUP MANIPULATION ---- */
// registers a new popup in the GUI.
// the popup must have been previously inserted
// into the dom.
add_popup: function(name, popup) {
popup.hide();
this.popup_set[name] = popup;
},
// displays a popup. Popup do not stack,
// are not remembered by the order, and are
// closed by screen changes or new popups.
show_popup: function(name,options) {
if (this.current_popup) {
this.close_popup();
}
this.current_popup = this.popup_set[name];
this.current_popup.show(options);
},
// close the current popup.
close_popup: function() {
if (this.current_popup) {
this.current_popup.close();
this.current_popup.hide();
this.current_popup = null;
}
},
/* ---- Gui: ACCESS CONTROL ---- */
// A Generic UI that allow to select a user from a list.
// It returns a deferred that resolves with the selected user
// upon success. Several options are available :
// - security: passwords will be asked
// - only_managers: restricts the list to managers
// - current_user: password will not be asked if this
// user is selected.
// - title: The title of the user selection list.
select_user: function(options){
options = options || {};
var self = this;
var def = new $.Deferred();
var list = [];
for (var i = 0; i < this.pos.users.length; i++) {
var user = this.pos.users[i];
if (!options.only_managers || user.role === 'manager') {
list.push({
'label': user.name,
'item': user,
});
}
}
this.show_popup('selection',{
'title': options.title || _t('Select User'),
list: list,
confirm: function(user){ def.resolve(user); },
cancel: function(){ def.reject(); },
});
return def.then(function(user){
if (options.security && user !== options.current_user && user.pos_security_pin) {
return self.ask_password(user.pos_security_pin).then(function(){
return user;
});
} else {
return user;
}
});
},
// Ask for a password, and checks if it this
// the same as specified by the function call.
// returns a deferred that resolves on success,
// fails on failure.
ask_password: function(password) {
var self = this;
var ret = new $.Deferred();
if (password) {
this.gui.show_popup('password',{
'title': _t('Password ?'),
confirm: function(pw) {
if (pw !== password) {
self.show_popup('error',_t('Incorrect Password'));
ret.reject();
} else {
ret.resolve();
}
},
});
} else {
ret.resolve();
}
return ret;
},
// checks if the current user (or the user provided) has manager
// access rights. If not, a popup is shown allowing the user to
// temporarily login as an administrator.
// This method returns a deferred, that succeeds with the
// manager user when the login is successfull.
sudo: function(user){
var def = new $.Deferred();
user = user || this.pos.get_cashier();
if (user.role === 'manager') {
return new $.Deferred().resolve(user);
} else {
return this.select_user({
security: true,
only_managers: true,
title: _t('Login as a Manager'),
})
}
},
/* ---- Gui: CLOSING THE POINT OF SALE ---- */
close: function() {
var self = this;
this.chrome.loading_show();
this.chrome.loading_message(_t('Closing ...'));
this.pos.push_order().then(function(){
return new instance.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_client_pos_menu']], ['res_id'])
.pipe(function(res) {
window.location = '/web#action=' + res[0]['res_id'];
},function(err,event) {
event.preventDefault();
self.show_popup('error',{
'title': _t('Could not close the point of sale.'),
'body': _t('Your internet connection is probably down.'),
});
self.chrome.widget.close_button.renderElement();
});
});
},
/* ---- Gui: KEYBOARD INPUT ---- */
// This is a helper to handle numpad keyboard input.
// - buffer: an empty or number string
// - input: '[0-9],'+','-','.','CLEAR','BACKSPACE'
// - options: 'firstinput' -> will clear buffer if
// input is '[0-9]' or '.'
// returns the new buffer containing the modifications
// (the original is not touched)
numpad_input: function(buffer, input, options) {
var options = options || {};
var newbuf = buffer.slice(0);
if (input === '.') {
if (options.firstinput) {
newbuf = "0.";
}else if (!newbuf.length || newbuf === '-') {
newbuf += "0.";
} else if (newbuf.indexOf('.') < 0){
newbuf = newbuf + '.';
}
} else if (input === 'CLEAR') {
newbuf = "";
} else if (input === 'BACKSPACE') {
newbuf = newbuf.substring(0,newbuf.length - 1);
} else if (input === '+') {
if ( newbuf[0] === '-' ) {
newbuf = newbuf.substring(1,newbuf.length);
}
} else if (input === '-') {
if ( newbuf[0] === '-' ) {
newbuf = newbuf.substring(1,newbuf.length);
} else {
newbuf = '-' + newbuf;
}
} else if (input[0] === '+' && !isNaN(parseFloat(input))) {
newbuf = '' + ((parseFloat(newbuf) || 0) + parseFloat(input));
} else if (!isNaN(parseInt(input))) {
if (options.firstinput) {
newbuf = '' + input;
} else {
newbuf += input;
}
}
return newbuf;
},
});
};
@@ -12,6 +12,10 @@ openerp.point_of_sale = function(openerp) {
openerp.point_of_sale.load_keyboard(openerp,module);
openerp.point_of_sale.load_gui(openerp,module);
openerp.point_of_sale.load_popups(openerp,module);
openerp.point_of_sale.load_screens(openerp,module);
openerp.point_of_sale.load_devices(openerp,module);
@@ -0,0 +1,236 @@
// This file contains the Popups.
// Popups must be loaded and named in chrome.js.
// They are instanciated / destroyed with the .gui.show_popup()
// and .gui.close_popup() methods.
openerp.point_of_sale.load_popups = function load_popups(instance, module) {
"use strict";
module.PopupWidget = module.PosBaseWidget.extend({
init: function(parent, args) {
this._super(parent, args);
this.options = {};
},
events: {
'click .button.cancel': 'click_cancel',
'click .button.confirm': 'click_confirm',
'click .selection-item': 'click_item',
'click .input-button': 'click_numpad',
'click .mode-button': 'click_numpad',
},
// show the popup !
show: function(options){
if(this.$el){
this.$el.removeClass('oe_hidden');
}
if (typeof options === 'string') {
this.options = {title: options};
} else {
this.options = options || {};
}
this.renderElement();
// popups block the barcode reader ...
if (this.pos.barcode_reader) {
this.pos.barcode_reader.save_callbacks();
this.pos.barcode_reader.reset_action_callbacks();
}
},
// called before hide, when a popup is closed.
// extend this if you want a custom action when the
// popup is closed.
close: function(){
if (this.pos.barcode_reader) {
this.pos.barcode_reader.restore_callbacks();
}
},
// hides the popup. keep in mind that this is called in
// the initialization pass of the pos instantiation,
// so you don't want to do anything fancy in here
hide: function(){
if (this.$el) {
this.$el.addClass('oe_hidden');
}
},
// what happens when we click cancel
// ( it should close the popup and do nothing )
click_cancel: function(){
this.gui.close_popup();
if (this.options.cancel) {
this.options.cancel.call(this);
}
},
// what happens when we confirm the action
click_confirm: function(){
this.gui.close_popup();
if (this.options.confirm) {
this.options.confirm.call(this);
}
},
// Since Widget does not support extending the events declaration
// we declared them all in the top class.
click_item: function(){},
click_numad: function(){},
});
module.ErrorPopupWidget = module.PopupWidget.extend({
template:'ErrorPopupWidget',
show: function(options){
this._super(options);
$('body').append('<audio src="/point_of_sale/static/src/sounds/error.wav" autoplay="true"></audio>');
},
});
module.ErrorTracebackPopupWidget = module.ErrorPopupWidget.extend({
template:'ErrorTracebackPopupWidget',
});
module.ErrorBarcodePopupWidget = module.ErrorPopupWidget.extend({
template:'ErrorBarcodePopupWidget',
show: function(barcode){
this._super({barcode: barcode});
},
});
module.ConfirmPopupWidget = module.PopupWidget.extend({
template: 'ConfirmPopupWidget',
});
/**
* A popup that allows the user to select one item from a list.
*
* show_popup('selection',{
* title: "Popup Title",
* list: [
* { label: 'foobar', item: 45 },
* { label: 'bar foo', item: 'stuff' },
* ],
* confirm: function(item) {
* // get the item selected by the user.
* },
* cancel: function(){
* // user chose nothing
* }
* });
*/
module.SelectionPopupWidget = module.PopupWidget.extend({
template: 'SelectionPopupWidget',
show: function(options){
options = options || {};
var self = this;
this._super();
this.list = options.list || [];
this.renderElement();
this.$('.selection-item').click(function(){
if (options.confirm) {
var item = self.list[parseInt($(this).data('item-index'))];
item = item ? item.item : item;
options.confirm.call(self,item);
}
});
},
click_item : function(event) {
this.gui.close_popup();
if (this.options.confirm) {
var item = self.list[parseInt($(event.target).data('item-index'))];
item = item ? item.item : item;
}
}
});
module.TextInputPopupWidget = module.PopupWidget.extend({
template: 'TextInputPopupWidget',
show: function(options){
options = options || {};
var self = this;
this._super();
this.renderElement();
this.$('input,textarea').focus();
this.$('.button.confirm').click(function(){
});
},
click_confirm: function(){
var value = self.$('input,textarea').val();
self.gui.close_popup();
if( this.options.confirm ){
this.options.confirm.call(self,value);
}
},
});
module.TextAreaPopupWidget = module.TextInputPopupWidget.extend({
template: 'TextAreaPopupWidget',
});
module.NumberPopupWidget = module.PopupWidget.extend({
template: 'NumberPopupWidget',
show: function(options){
options = options || {};
var self = this;
this._super();
this.inputbuffer = options.value || '';
this.renderElement();
this.firstinput = true;
},
click_numpad: function(event){
var newbuf = this.gui.numpad_input(
this.inputbuffer,
$(event.target).data('action'),
{'firstinput': this.firstinput});
this.firstinput = (newbuf.length === 0);
if (newbuf !== this.inputbuffer) {
this.inputbuffer = newbuf;
this.$('.value').text(this.inputbuffer);
}
},
click_confirm: function(event){
this.gui.close_popup();
if( this.options.confirm ){
this.options.confirm.call(this,this.inputbuffer);
}
},
});
module.PasswordPopupWidget = module.NumberPopupWidget.extend({
renderElement: function(){
this._super();
this.$('.popup').addClass('popup-password'); // WHY NOT ?!
},
});
module.ErrorNoClientPopupWidget = module.ErrorPopupWidget.extend({
template: 'ErrorNoClientPopupWidget',
});
module.ErrorInvoiceTransferPopupWidget = module.ErrorPopupWidget.extend({
template: 'ErrorInvoiceTransferPopupWidget',
});
module.UnsentOrdersPopupWidget = module.ConfirmPopupWidget.extend({
template: 'UnsentOrdersPopupWidget',
});
module.UnpaidOrdersPopupWidget = module.ConfirmPopupWidget.extend({
template: 'UnpaidOrdersPopupWidget',
});
};
+22 -526
View File
@@ -1,318 +1,39 @@
// this file contains the screens definitions. Screens are the
// This file contains the Screens definitions. Screens are the
// content of the right pane of the pos, containing the main functionalities.
// screens are contained in the PosWidget, in chrome.js
// all screens are present in the dom at all time, but only one is shown at the
// same time.
//
// transition between screens is made possible by the use of the gui,
// which is responsible of hiding and showing the screens, as well as maintaining
// the state of the screens between different orders.
// Screens must be defined and named in chrome.js before use.
//
// all screens inherit from ScreenWidget. the only addition from the base widgets
// Screens transitions are controlled by the Gui.
// gui.set_startup_screen() sets the screen displayed at startup
// gui.set_default_screen() sets the screen displayed for new orders
// gui.show_screen() shows a screen
// gui.back() goes to the previous screen
//
// Screen state is saved in the order. When a new order is selected,
// a screen is displayed based on the state previously saved in the order.
// this is also done in the Gui with:
// gui.show_saved_screen()
//
// All screens inherit from ScreenWidget. The only addition from the base widgets
// are show() and hide() which shows and hides the screen but are also used to
// bind and unbind actions on widgets and devices. The gui guarantees
// that only one screen is shown at the same time and that show() is called after all
// hide()s
//
// Each Screens must be independant from each other, and should have no
// persistent state outside the models. Screen state variables are reset at
// each screen display. A screen can be called with parameters, which are
// to be used for the duration of the screen only.
openerp.point_of_sale.load_screens = function load_screens(instance, module){ //module is instance.point_of_sale
"use strict";
var QWeb = instance.web.qweb,
_t = instance.web._t;
var QWeb = instance.web.qweb;
var _t = instance.web._t;
var round_pr = instance.web.round_precision
module.Gui = instance.web.Class.extend({
init: function(options){
var self = this;
this.pos = options.pos;
this.chrome = options.chrome;
this.screen_set = {};
this.popup_set = {};
this.default_screen = null;
this.startup_screen = null;
this.current_popup = null;
this.current_screen = null;
this.chrome.ready.then(function(){
var order = self.pos.get_order();
if (order) {
self.show_saved_screen(order);
} else {
self.show_screen(self.startup_screen);
}
self.pos.bind('change:selectedOrder', function(){
self.show_saved_screen(self.pos.get_order());
});
});
},
/* ---- Gui: SCREEN MANIPULATION ---- */
// register a screen widget to the gui,
// it must have been inserted into the dom.
add_screen: function(name, screen){
screen.hide();
this.screen_set[name] = screen;
},
// sets the screen that will be displayed
// for new orders
set_default_screen: function(name){
this.default_screen = name;
},
// sets the screen that will be displayed
// when no orders are present
set_startup_screen: function(name) {
this.startup_screen = name;
},
// display the screen saved in an order,
// called when the user changes the current order
// no screen saved ? -> display default_screen
// no order ? -> display startup_screen
show_saved_screen: function(order,options) {
options = options || {};
this.close_popup();
if (order) {
this.show_screen(order.get_screen_data('screen') ||
options.default_screen ||
this.default_screen,
null,'refresh');
} else {
this.show_screen(this.startup_screen);
}
},
// display a screen.
// If there is an order, the screen will be saved in the order
// - params: used to load a screen with parameters, for
// example loading a 'product_details' screen for a specific product.
// - refresh: if you want the screen to cycle trough show / hide even
// if you are already on the same screen.
show_screen: function(screen_name,params,refresh) {
var screen = this.screen_set[screen_name];
if (!screen) {
console.error("ERROR: show_screen("+screen_name+") : screen not found");
}
this.close_popup();
var order = this.pos.get_order();
if (order) {
var old_screen_name = order.get_screen_data('screen');
order.set_screen_data('screen',screen_name);
if(params){
order.set_screen_data('params',params);
}
if( screen_name !== old_screen_name ){
order.set_screen_data('previous-screen',old_screen_name);
}
}
if (refresh || screen !== this.current_screen) {
if (this.current_screen) {
this.current_screen.close();
this.current_screen.hide();
}
this.current_screen = screen;
this.current_screen.show();
}
},
// returns the current screen.
get_current_screen: function() {
return this.pos.get_order().get_screen_data('screen') || this.default_screen;
},
// goes to the previous screen (as specified in the order). The history only
// goes 1 deep ...
back: function() {
var previous = this.pos.get_order().get_screen_data('previous-screen');
if (previous) {
this.show_screen(previous);
}
},
// returns the parameter specified when this screen was displayed
get_current_screen_param: function(param) {
var params = this.pos.get_order().get_screen_data('params');
return params ? params[param] : undefined;
},
/* ---- Gui: POPUP MANIPULATION ---- */
// registers a new popup in the GUI.
// the popup must have been previously inserted
// into the dom.
add_popup: function(name, popup) {
popup.hide();
this.popup_set[name] = popup;
},
// displays a popup. Popup do not stack,
// are not remembered by the order, and are
// closed by screen changes or new popups.
show_popup: function(name,options) {
if (this.current_popup) {
this.close_popup();
}
this.current_popup = this.popup_set[name];
this.current_popup.show(options);
},
// close the current popup.
close_popup: function() {
if (this.current_popup) {
this.current_popup.close();
this.current_popup.hide();
this.current_popup = null;
}
},
/* ---- Gui: ACCESS CONTROL ---- */
// A Generic UI that allow to select a user from a list.
// It returns a deferred that resolves with the selected user
// upon success. Several options are available :
// - security: passwords will be asked
// - only_managers: restricts the list to managers
// - current_user: password will not be asked if this
// user is selected.
// - title: The title of the user selection list.
select_user: function(options){
options = options || {};
var self = this;
var def = new $.Deferred();
var list = [];
for (var i = 0; i < this.pos.users.length; i++) {
var user = this.pos.users[i];
if (!options.only_managers || user.role === 'manager') {
list.push({
'label': user.name,
'item': user,
});
}
}
this.show_popup('selection',{
'title': options.title || _t('Select User'),
list: list,
confirm: function(user){ def.resolve(user); },
cancel: function(){ def.reject(); },
});
return def.then(function(user){
if (options.security && user !== options.current_user && user.pos_security_pin) {
return self.ask_password(user.pos_security_pin).then(function(){
return user;
});
} else {
return user;
}
});
},
// Ask for a password, and checks if it this
// the same as specified by the function call.
// returns a deferred that resolves on success,
// fails on failure.
ask_password: function(password) {
var self = this;
var ret = new $.Deferred();
if (password) {
this.gui.show_popup('password',{
'title': _t('Password ?'),
confirm: function(pw) {
if (pw !== password) {
self.show_popup('error',_t('Incorrect Password'));
ret.reject();
} else {
ret.resolve();
}
},
});
} else {
ret.resolve();
}
return ret;
},
// checks if the current user (or the user provided) has manager
// access rights. If not, a popup is shown allowing the user to
// temporarily login as an administrator.
// This method returns a deferred, that succeeds with the
// manager user when the login is successfull.
sudo: function(user){
var def = new $.Deferred();
user = user || this.pos.get_cashier();
if (user.role === 'manager') {
return new $.Deferred().resolve(user);
} else {
return this.select_user({
security: true,
only_managers: true,
title: _t('Login as a Manager'),
})
}
},
/* ---- Gui: KEYBOARD INPUT ---- */
// This is a helper to handle numpad keyboard input.
// - buffer: an empty or number string
// - input: '[0-9],'+','-','.','CLEAR','BACKSPACE'
// - options: 'firstinput' -> will clear buffer if
// input is '[0-9]' or '.'
// returns the new buffer containing the modifications
// (the original is not touched)
numpad_input: function(buffer, input, options) {
var options = options || {};
var newbuf = buffer.slice(0);
if (input === '.') {
if (options.firstinput) {
newbuf = "0.";
}else if (!newbuf.length || newbuf === '-') {
newbuf += "0.";
} else if (newbuf.indexOf('.') < 0){
newbuf = newbuf + '.';
}
} else if (input === 'CLEAR') {
newbuf = "";
} else if (input === 'BACKSPACE') {
newbuf = newbuf.substring(0,newbuf.length - 1);
} else if (input === '+') {
if ( newbuf[0] === '-' ) {
newbuf = newbuf.substring(1,newbuf.length);
}
} else if (input === '-') {
if ( newbuf[0] === '-' ) {
newbuf = newbuf.substring(1,newbuf.length);
} else {
newbuf = '-' + newbuf;
}
} else if (input[0] === '+' && !isNaN(parseFloat(input))) {
newbuf = '' + ((parseFloat(newbuf) || 0) + parseFloat(input));
} else if (!isNaN(parseInt(input))) {
if (options.firstinput) {
newbuf = '' + input;
} else {
newbuf += input;
}
}
return newbuf;
},
});
module.ScreenWidget = module.PosBaseWidget.extend({
show_numpad: true,
@@ -437,231 +158,6 @@ openerp.point_of_sale.load_screens = function load_screens(instance, module){ //
},
});
module.PopUpWidget = module.PosBaseWidget.extend({
init: function(parent, args) {
this._super(parent, args);
this.options = {};
},
events: {
'click .button.cancel': 'click_cancel',
'click .button.confirm': 'click_confirm',
'click .selection-item': 'click_item',
'click .input-button': 'click_numpad',
'click .mode-button': 'click_numpad',
},
// show the popup !
show: function(options){
if(this.$el){
this.$el.removeClass('oe_hidden');
}
if (typeof options === 'string') {
this.options = {title: options};
} else {
this.options = options || {};
}
this.renderElement();
// popups block the barcode reader ...
if (this.pos.barcode_reader) {
this.pos.barcode_reader.save_callbacks();
this.pos.barcode_reader.reset_action_callbacks();
}
},
// called before hide, when a popup is closed.
// extend this if you want a custom action when the
// popup is closed.
close: function(){
if (this.pos.barcode_reader) {
this.pos.barcode_reader.restore_callbacks();
}
},
// hides the popup. keep in mind that this is called in
// the initialization pass of the pos instantiation,
// so you don't want to do anything fancy in here
hide: function(){
if (this.$el) {
this.$el.addClass('oe_hidden');
}
},
// what happens when we click cancel
// ( it should close the popup and do nothing )
click_cancel: function(){
this.gui.close_popup();
if (this.options.cancel) {
this.options.cancel.call(this);
}
},
// what happens when we confirm the action
click_confirm: function(){
this.gui.close_popup();
if (this.options.confirm) {
this.options.confirm.call(this);
}
},
// Since Widget does not support extending the events declaration
// we declared them all in the top class.
click_item: function(){},
click_numad: function(){},
});
module.ErrorPopupWidget = module.PopUpWidget.extend({
template:'ErrorPopupWidget',
show: function(options){
this._super(options);
$('body').append('<audio src="/point_of_sale/static/src/sounds/error.wav" autoplay="true"></audio>');
},
});
module.ErrorTracebackPopupWidget = module.ErrorPopupWidget.extend({
template:'ErrorTracebackPopupWidget',
});
module.ErrorBarcodePopupWidget = module.ErrorPopupWidget.extend({
template:'ErrorBarcodePopupWidget',
show: function(barcode){
this._super({barcode: barcode});
},
});
module.ConfirmPopupWidget = module.PopUpWidget.extend({
template: 'ConfirmPopupWidget',
});
/**
* A popup that allows the user to select one item from a list.
*
* show_popup('selection',{
* title: "Popup Title",
* list: [
* { label: 'foobar', item: 45 },
* { label: 'bar foo', item: 'stuff' },
* ],
* confirm: function(item) {
* // get the item selected by the user.
* },
* cancel: function(){
* // user chose nothing
* }
* });
*/
module.SelectionPopupWidget = module.PopUpWidget.extend({
template: 'SelectionPopupWidget',
show: function(options){
options = options || {};
var self = this;
this._super();
this.list = options.list || [];
this.renderElement();
this.$('.selection-item').click(function(){
if (options.confirm) {
var item = self.list[parseInt($(this).data('item-index'))];
item = item ? item.item : item;
options.confirm.call(self,item);
}
});
},
click_item : function(event) {
this.gui.close_popup();
if (this.options.confirm) {
var item = self.list[parseInt($(event.target).data('item-index'))];
item = item ? item.item : item;
}
}
});
module.TextInputPopupWidget = module.PopUpWidget.extend({
template: 'TextInputPopupWidget',
show: function(options){
options = options || {};
var self = this;
this._super();
this.renderElement();
this.$('input,textarea').focus();
this.$('.button.confirm').click(function(){
});
},
click_confirm: function(){
var value = self.$('input,textarea').val();
self.gui.close_popup();
if( this.options.confirm ){
this.options.confirm.call(self,value);
}
},
});
module.TextAreaPopupWidget = module.TextInputPopupWidget.extend({
template: 'TextAreaPopupWidget',
});
module.NumberPopupWidget = module.PopUpWidget.extend({
template: 'NumberPopupWidget',
show: function(options){
options = options || {};
var self = this;
this._super();
this.inputbuffer = options.value || '';
this.renderElement();
this.firstinput = true;
},
click_numpad: function(event){
var newbuf = this.gui.numpad_input(
this.inputbuffer,
$(event.target).data('action'),
{'firstinput': this.firstinput});
this.firstinput = (newbuf.length === 0);
if (newbuf !== this.inputbuffer) {
this.inputbuffer = newbuf;
this.$('.value').text(this.inputbuffer);
}
},
click_confirm: function(event){
this.gui.close_popup();
if( this.options.confirm ){
this.options.confirm.call(this,this.inputbuffer);
}
},
});
module.PasswordPopupWidget = module.NumberPopupWidget.extend({
renderElement: function(){
this._super();
this.$('.popup').addClass('popup-password'); // WHY NOT ?!
},
});
module.ErrorNoClientPopupWidget = module.ErrorPopupWidget.extend({
template: 'ErrorNoClientPopupWidget',
});
module.ErrorInvoiceTransferPopupWidget = module.ErrorPopupWidget.extend({
template: 'ErrorInvoiceTransferPopupWidget',
});
module.UnsentOrdersPopupWidget = module.ConfirmPopupWidget.extend({
template: 'UnsentOrdersPopupWidget',
});
module.UnpaidOrdersPopupWidget = module.ConfirmPopupWidget.extend({
template: 'UnpaidOrdersPopupWidget',
});
module.ScaleScreenWidget = module.ScreenWidget.extend({
template:'ScaleScreenWidget',
@@ -1572,5 +1068,5 @@ openerp.point_of_sale.load_screens = function load_screens(instance, module){ //
},
});
}
};
@@ -14,6 +14,8 @@
<script type="text/javascript" src="/point_of_sale/static/src/js/keyboard.js"></script>
<script type="text/javascript" src="/point_of_sale/static/src/js/chrome.js"></script>
<script type="text/javascript" src="/point_of_sale/static/src/js/devices.js"></script>
<script type="text/javascript" src="/point_of_sale/static/src/js/gui.js"></script>
<script type="text/javascript" src="/point_of_sale/static/src/js/popups.js"></script>
<script type="text/javascript" src="/point_of_sale/static/src/js/screens.js"></script>
<script type="text/javascript" src="/point_of_sale/static/src/js/tests.js"></script>
</xpath>