[IMP + FIX] point_of_sale: plugged the memory leaks

- correctly call destroy on widgets
 - unbind backbone events on destroy
 - jquery show() hide() flooded jQuery.cache
 - introduced automated ui tests

bzr revid: fva@openerp.com-20130917101420-g76gos2qjjaii3zf
This commit is contained in:
Frédéric van der Essen 2013-09-17 12:14:20 +02:00
parent ffe677a736
commit 65c70b85a7
10 changed files with 170 additions and 65 deletions

View File

@ -98,6 +98,7 @@ Main Features
'static/src/js/widgets.js',
'static/src/js/devices.js',
'static/src/js/screens.js',
'static/src/js/tests.js',
'static/src/js/main.js',
],
'css': [

View File

@ -21,6 +21,10 @@
user-select: none;
}
.point-of-sale .oe_hidden{
display: none !important;
}
.point-of-sale ul, .point-of-sale li {
margin: 0;
padding: 0;

View File

@ -40,6 +40,7 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
});
}else{
running = false;
scheduled_end_time = 0;
end_of_queue.resolve();
}
};
@ -100,15 +101,13 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
};
this.custom_payment_status = this.default_payment_status;
this.notifications = {};
this.bypass_proxy = false;
this.connection = new instance.web.Session(undefined,url);
this.connection.session_id = _.uniqueId('posproxy');
this.connected = true;
this.bypass_proxy = false;
this.notifications = {};
this.message('test_connection').fail(function(){
self.connected = false;
console.error('Could not connect to the OpenERP Device Proxy Server');
});
this.test_connection();
window.proxy = this;
},
close: function(){
@ -125,6 +124,14 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
return (new $.Deferred()).reject();
}
},
test_connection: function(){
var self = this;
this.connected = true;
return this.message('test_connection').fail(function(){
self.connected = false;
console.error('Could not connect to the Proxy');
});
},
// this allows the client to be notified when a proxy call is made. The notification
// callback will be executed with the same arguments as the proxy call

View File

@ -16,10 +16,12 @@ openerp.point_of_sale = function(instance) {
openerp_pos_scrollbar(instance,module); // import pos_scrollbar_widget.js
openerp_pos_screens(instance,module); // import pos_screens.js
openerp_pos_devices(instance,module); // import pos_devices.js
openerp_pos_widgets(instance,module); // import pos_widgets.js
openerp_pos_devices(instance,module); // import pos_devices.js
openerp_pos_tests(instance,module); // import pos_tests.js
instance.web.client_actions.add('pos.ui', 'instance.point_of_sale.PosWidget');
};

View File

@ -263,7 +263,6 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
//removes the current order
delete_current_order: function(){
this.get('selectedOrder').destroy({'reason':'abandon'});
console.log('coucou!');
},
// saves the order locally and try to send it to the backend.

View File

@ -253,7 +253,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
this.hidden = false;
if(this.$el){
this.$el.show();
this.$el.removeClass('oe_hidden');
}
if(this.pos_widget.action_bar.get_button_count() > 0){
@ -314,7 +314,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
hide: function(){
this.hidden = true;
if(this.$el){
this.$el.hide();
this.$el.addClass('oe_hidden');
}
},
@ -326,7 +326,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
this._super();
if(this.hidden){
if(this.$el){
this.$el.hide();
this.$el.addClass('oe_hidden');
}
}
},
@ -335,7 +335,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
module.PopUpWidget = module.PosBaseWidget.extend({
show: function(){
if(this.$el){
this.$el.show();
this.$el.removeClass('oe_hidden');
}
},
/* called before hide, when a popup is closed */
@ -345,7 +345,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
* pos instantiation, so you don't want to do anything fancy in here */
hide: function(){
if(this.$el){
this.$el.hide();
this.$el.addClass('oe_hidden');
}
},
});
@ -692,7 +692,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
barcode_client_action: function(ean){
this.pos.proxy.transaction_start();
this._super(ean);
$('.goodbye-message').hide();
$('.goodbye-message').addClass('oe_hidden');
this.pos_widget.screen_selector.show_popup('choose-receipt');
},
@ -704,14 +704,14 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
label: _t('Help'),
icon: '/point_of_sale/static/src/img/icons/png48/help.png',
click: function(){
$('.goodbye-message').css({opacity:1}).hide();
$('.goodbye-message').css({opacity:1}).addClass('oe_hidden');
self.help_button_action();
},
});
$('.goodbye-message').css({opacity:1}).show();
$('.goodbye-message').css({opacity:1}).removeClass('oe_hidden');
setTimeout(function(){
$('.goodbye-message').animate({opacity:0},500,'swing',function(){$('.goodbye-message').hide();});
$('.goodbye-message').animate({opacity:0},500,'swing',function(){$('.goodbye-message').addClass('oe_hidden');});
},5000);
},
});

View File

@ -0,0 +1,92 @@
function openerp_pos_tests(instance, module){ //module is instance.point_of_sale
// Various UI Tests to measure performance and memory leaks.
module.UiTester = function(){
var running = false;
var queue = new module.JobQueue();
// stop the currently running test
this.stop = function(){
queue.clear();
};
// randomly switch product categories
this.category_switch = function(interval){
queue.schedule(function(){
var breadcrumbs = $('.breadcrumb a');
var categories = $('li.category-button');
if(categories.length > 0){
var rnd = Math.floor(Math.random()*categories.length);
categories.eq(rnd).click();
}else{
var rnd = Math.floor(Math.random()*breadcrumbs.length);
breadcrumbs.eq(rnd).click();
}
},{repeat:true, duration:interval});
};
// randomly order products then resets the order
this.order_products = function(interval){
queue.schedule(function(){
var def = new $.Deferred();
var order_queue = new module.JobQueue();
var order_size = 1 + Math.floor(Math.random()*10);
while(order_size--){
order_queue.schedule(function(){
var products = $('.product a');
if(products.length > 0){
var rnd = Math.floor(Math.random()*products.length);
products.eq(rnd).click();
}
},{duration:250});
}
order_queue.finished().then(function(){
$('.deleteorder-button').click();
def.resolve();
});
return def;
},{repeat:true, duration: interval});
};
// makes a complete product order cycle ( print via proxy must be activated, and scale deactivated )
this.full_order_cycle = function(interval){
queue.schedule(function(){
var def = new $.Deferred();
var order_queue = new module.JobQueue();
var order_size = 1 + Math.floor(Math.random()*50);
while(order_size--){
order_queue.schedule(function(){
var products = $('.product a');
if(products.length > 0){
var rnd = Math.floor(Math.random()*products.length);
products.eq(rnd).click();
}
},{duration:250});
}
order_queue.schedule(function(){
$('.paypad-button:first').click();
},{duration:250});
order_queue.schedule(function(){
$('.paymentline-amount input:first').val(10000);
$('.paymentline-amount input:first').keyup();
},{duration:250});
order_queue.schedule(function(){
$('.pos-actionbar-button-list .button:eq(2)').click();
},{duration:250});
order_queue.schedule(function(){
def.resolve();
});
return def;
},{repeat: true, duration: interval});
};
};
if(jQuery.deparam(jQuery.param.querystring()).debug !== undefined){
window.pos_test_ui = new module.UiTester();
}
}

View File

@ -41,10 +41,10 @@ function openerp_pos_basewidget(instance, module){ //module is instance.point_of
},
show: function(){
this.$el.show();
this.$el.removeClass('oe_hidden');
},
hide: function(){
this.$el.hide();
this.$el.addClass('oe_hidden');
},
});

View File

@ -81,7 +81,7 @@ function openerp_pos_scrollbar(instance, module){ //module is instance.point_of_
$(window).unbind('resize',this.resize_handler);
$(window).bind('resize',this.resize_handler);
this.target().unbind('mousewheel',this.target_mousweheel_handler);
this.target().unbind('mousewheel',this.target_mousewheel_handler);
this.target().bind('mousewheel',this.target_mousewheel_handler);
// because the rendering is asynchronous we must wait for the next javascript update
@ -93,22 +93,18 @@ function openerp_pos_scrollbar(instance, module){ //module is instance.point_of_
},0);
},
// binds the window resize and the target scrolling events.
// it is good advice not to bind these multiple_times
bind_events:function(){
$(window).resize(function(){
});
this.target().bind('mousewheel',function(event,delta){
self.scroll(delta*self.wheel_step);
});
destroy: function(){
$(window).unbind('resize',this.resize_handler);
this.target().unbind('mousewheel',this.target_mousewheel_handler);
this._super();
},
// shows the scrollbar. if animated is true, it will do it in an animated fashion
show: function(animated){ //FIXME: animated show and hide don't work ... ?
if(animated){
this.$el.show().animate({'width':'48px'}, 500, 'swing');
this.$el.removeClass('oe_hidden').animate({'width':'48px'}, 500, 'swing');
}else{
this.$el.show().css('width','48px');
this.$el.removeClass('oe_hidden').css('width','48px');
}
this.on_show(this);
},
@ -117,9 +113,9 @@ function openerp_pos_scrollbar(instance, module){ //module is instance.point_of_
hide: function(animated){
var self = this;
if(animated){
this.$el.animate({'width':'0px'}, 500, 'swing', function(){ self.$el.hide();});
this.$el.animate({'width':'0px'}, 500, 'swing', function(){ self.$el.addClass('oe_hidden');});
}else{
this.$el.hide().css('width','0px');
this.$el.addClass('oe_hidden').css('width','0px');
}
this.on_hide(this);
},

View File

@ -137,17 +137,15 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
this.model = options.model;
this.order = options.order;
this.model.bind('change', _.bind( function() {
this.refresh();
}, this));
},
click_handler: function() {
this.order.selectLine(this.model);
this.trigger('order_line_selected');
this.model.bind('change', this.refresh, this);
},
renderElement: function() {
var self = this;
this._super();
this.$el.click(_.bind(this.click_handler, this));
this.$el.click(function(){
self.order.selectLine(this.model);
self.trigger('order_line_selected');
});
if(this.model.is_selected()){
this.$el.addClass('selected');
}
@ -156,6 +154,10 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
this.renderElement();
this.trigger('order_line_refreshed');
},
destroy: function(){
this.model.unbind('change',this.refresh,this);
this._super();
},
});
module.OrderWidget = module.PosBaseWidget.extend({
@ -358,16 +360,16 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
var self = this;
this.order = options.order;
this.order.bind('destroy',function(){ self.destroy(); });
this.order.bind('change', function(){ self.renderElement(); });
this.pos.bind('change:selectedOrder', function() {
self.renderElement();
}, this);
this.order.bind('destroy',this.destroy, this );
this.order.bind('change', this.renderElement, this );
this.pos.bind('change:selectedOrder', this.renderElement,this );
},
renderElement:function(){
this._super();
this.$('button.select-order').off('click').click(_.bind(this.selectOrder, this));
this.$('button.close-order').off('click').click(_.bind(this.closeOrder, this));
var self = this;
this.$el.click(function(){
self.selectOrder();
});
if( this.order === this.pos.get('selectedOrder') ){
this.$el.addClass('selected-order');
}
@ -377,8 +379,11 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
selectedOrder: this.order
});
},
closeOrder: function(event) {
this.order.destroy();
destroy: function(){
this.order.unbind('destroy', this.destroy, this);
this.order.unbind('change', this.renderElement, this);
this.pos.unbind('change:selectedOrder', this.renderElement, this);
this._super();
},
});
@ -422,9 +427,9 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
if(visible != this.visibility[element]){
this.visibility[element] = !!visible;
if(visible){
this.$('.'+element).show();
this.$('.'+element).removeClass('oe_hidden');
}else{
this.$('.'+element).hide();
this.$('.'+element).addClass('oe_hidden');
}
}
if(visible && action){
@ -459,10 +464,10 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
return button;
},
show:function(){
this.$el.show();
this.$el.removeClass('oe_hidden');
},
hide:function(){
this.$el.hide();
this.$el.addClass('oe_hidden');
},
});
@ -690,8 +695,8 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
this.$el.click(function(){ self.action(); });
}
},
show: function(){ this.$el.show(); },
hide: function(){ this.$el.hide(); },
show: function(){ this.$el.removeClass('oe_hidden'); },
hide: function(){ this.$el.addClass('oe_hidden'); },
});
// The debug widget lets the user control and monitor the hardware and software status
@ -870,13 +875,12 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
new_order_button.selectOrder();
}, self);
self.pos.get('orders').add(new module.Order({ pos: self.pos }));
self.pos.add_new_order();
self.build_widgets();
self.screen_selector.set_default_screen();
window.screen_selector = self.screen_selector;
self.pos.barcode_reader.connect();
@ -889,7 +893,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
}
instance.web.unblockUI();
self.$('.loader').animate({opacity:0},1500,'swing',function(){self.$('.loader').hide();});
self.$('.loader').animate({opacity:0},1500,'swing',function(){self.$('.loader').addClass('oe_hidden');});
self.pos.flush();
@ -1078,11 +1082,11 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
if(visible !== this.leftpane_visible){
this.leftpane_visible = visible;
if(visible){
$('#leftpane').show().animate({'width':this.leftpane_width},500,'swing');
$('#leftpane').removeClass('oe_hidden').animate({'width':this.leftpane_width},500,'swing');
$('#rightpane').animate({'left':this.leftpane_width},500,'swing');
}else{
var leftpane = $('#leftpane');
$('#leftpane').animate({'width':'0px'},500,'swing', function(){ leftpane.hide(); });
$('#leftpane').animate({'width':'0px'},500,'swing', function(){ leftpane.addClass('oe_hidden'); });
$('#rightpane').animate({'left':'0px'},500,'swing');
}
}
@ -1092,11 +1096,11 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
if(visible !== this.cashier_controls_visible){
this.cashier_controls_visible = visible;
if(visible){
$('#loggedas').show();
$('#rightheader').show();
$('#loggedas').removeClass('oe_hidden');
$('#rightheader').removeClass('oe_hidden');
}else{
$('#loggedas').hide();
$('#rightheader').hide();
$('#loggedas').addClass('oe_hidden');
$('#rightheader').addClass('oe_hidden');
}
}
},