diff --git a/addons/stock_dropshipping/__init__.py b/addons/stock_dropshipping/__init__.py
index d7156f09070..67dee8c60db 100644
--- a/addons/stock_dropshipping/__init__.py
+++ b/addons/stock_dropshipping/__init__.py
@@ -1,3 +1,2 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-import models # noqa
diff --git a/addons/stock_dropshipping/models/__init__.py b/addons/stock_dropshipping/models/__init__.py
deleted file mode 100644
index 16c708eba5a..00000000000
--- a/addons/stock_dropshipping/models/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# -*- coding: utf-8 -*-
-# Part of Odoo. See LICENSE file for full copyright and licensing details.
-
-import stock_dropshipping # noqa
diff --git a/addons/stock_dropshipping/models/stock_dropshipping.py b/addons/stock_dropshipping/models/stock_dropshipping.py
deleted file mode 100644
index 0c2e2424fa0..00000000000
--- a/addons/stock_dropshipping/models/stock_dropshipping.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# coding: utf-8
-# Part of Odoo. See LICENSE file for full copyright and licensing details.
-
-from openerp import models, api
-
-class AccountInvoice(models.Model):
- _inherit = 'account.invoice'
-
- @api.model
- def _anglo_saxon_sale_move_lines(self, i_line):
- for sale_line in i_line.sale_line_ids:
- for proc in sale_line.procurement_ids:
- if proc.purchase_line_id:
- # if the invoice line is related to sale order lines having one of its
- # procurement_ids with a purchase_line_id set, it means that it is a
- # confirmed dropship and in that case we mustn't create the cost of
- # sale line (because the product won't enter the stock)
- return []
- return super(AccountInvoice, self)._anglo_saxon_sale_move_lines(i_line)
diff --git a/addons/web/static/src/js/boot.js b/addons/web/static/src/js/boot.js
index 842858926a9..b84cd0f58f8 100644
--- a/addons/web/static/src/js/boot.js
+++ b/addons/web/static/src/js/boot.js
@@ -189,7 +189,7 @@
if (odoo.debug && !_.isEmpty(debug_jobs)) log.push('\nDebug: ', debug_jobs);
if (odoo.debug || !_.isEmpty(failed) || !_.isEmpty(unloaded)) {
- console[_.isEmpty(unloaded) ? 'info' : 'error'].apply(console, log);
+ console[_.isEmpty(failed) || _.isEmpty(unloaded) ? 'info' : 'error'].apply(console, log);
}
}
},
diff --git a/addons/web/static/src/js/control_panel.js b/addons/web/static/src/js/control_panel.js
index 56f02d90eaf..173d91aea25 100644
--- a/addons/web/static/src/js/control_panel.js
+++ b/addons/web/static/src/js/control_panel.js
@@ -76,6 +76,10 @@ var ControlPanel = Widget.extend({
return this._super();
},
+ destroy: function() {
+ this._clear_breadcrumbs_handlers();
+ return this._super.apply(this, arguments);
+ },
/**
* @return {Object} the Bus the ControlPanel is listening on
*/
@@ -108,7 +112,9 @@ var ControlPanel = Widget.extend({
// Render the breadcrumbs
if (status.breadcrumbs) {
- new_cp_content.$breadcrumbs = this._render_breadcrumbs(status.breadcrumbs);
+ this._clear_breadcrumbs_handlers();
+ this.$breadcrumbs = this._render_breadcrumbs(status.breadcrumbs);
+ new_cp_content.$breadcrumbs = this.$breadcrumbs;
}
// Detach control_panel old content and attach new elements
@@ -207,6 +213,17 @@ var ControlPanel = Widget.extend({
}
return $bc;
},
+ /**
+ * Private function that removes event handlers attached on the currently
+ * displayed breadcrumbs.
+ */
+ _clear_breadcrumbs_handlers: function () {
+ if (this.$breadcrumbs) {
+ _.each(this.$breadcrumbs, function ($bc) {
+ $bc.off();
+ });
+ }
+ },
/**
* Private function that updates the SearchView's visibility and extend the
* breadcrumbs area if the SearchView is not visible
diff --git a/addons/web/static/src/js/framework/view.js b/addons/web/static/src/js/framework/view.js
index 9b3d1751570..ded3ba10bb7 100644
--- a/addons/web/static/src/js/framework/view.js
+++ b/addons/web/static/src/js/framework/view.js
@@ -196,6 +196,12 @@ var View = Widget.extend({
get_context: function () {
return {};
},
+ destroy: function () {
+ if (this.$buttons) {
+ this.$buttons.off();
+ }
+ return this._super.apply(this, arguments);
+ },
set_scrollTop: function(scrollTop) {
this.scrollTop = scrollTop;
},
diff --git a/addons/web/static/src/js/view_manager.js b/addons/web/static/src/js/view_manager.js
index ec7ce95313a..dd730b62f4e 100644
--- a/addons/web/static/src/js/view_manager.js
+++ b/addons/web/static/src/js/view_manager.js
@@ -463,6 +463,14 @@ var ViewManager = Widget.extend(ControlPanelMixin, {
}
this.active_view.controller.do_load_state(state, warm);
},
+ destroy: function () {
+ if (this.control_elements) {
+ if (this.control_elements.$switch_buttons) {
+ this.control_elements.$switch_buttons.off();
+ }
+ }
+ return this._super.apply(this, arguments);
+ },
});
return ViewManager;
diff --git a/addons/web/static/src/js/views/form_relational_widgets.js b/addons/web/static/src/js/views/form_relational_widgets.js
index dd4c4fb0fb6..00bbd8b3c24 100644
--- a/addons/web/static/src/js/views/form_relational_widgets.js
+++ b/addons/web/static/src/js/views/form_relational_widgets.js
@@ -99,6 +99,9 @@ var FieldMany2One = common.AbstractField.extend(common.CompletionFieldMixin, com
delete this.$dropdown;
}
if (this.$input) {
+ if (this.$input.data('ui-autocomplete')) {
+ this.$input.autocomplete("destroy");
+ }
this.$input.closest(".modal .modal-content").off('scroll');
this.$input.off('keyup blur autocompleteclose autocompleteopen ' +
'focus focusout change keydown');
diff --git a/addons/web/static/src/js/views/form_view.js b/addons/web/static/src/js/views/form_view.js
index f517a94c819..9d3caf7d76a 100644
--- a/addons/web/static/src/js/views/form_view.js
+++ b/addons/web/static/src/js/views/form_view.js
@@ -94,6 +94,9 @@ var FormView = View.extend(common.FieldManagerMixin, {
});
},
start: function() {
+ if (this.$pager) {
+ this.$pager.off();
+ }
var self = this;
this.rendering_engine.set_fields_registry(this.fields_registry);
diff --git a/addons/web/static/src/js/views/graph_view.js b/addons/web/static/src/js/views/graph_view.js
index ea9d09636f5..308c1359248 100644
--- a/addons/web/static/src/js/views/graph_view.js
+++ b/addons/web/static/src/js/views/graph_view.js
@@ -129,6 +129,12 @@ var GraphView = View.extend({
this.widget.set_measure(this.active_measure);
}
},
+ destroy: function () {
+ if (this.$buttons) {
+ this.$buttons.find('button').off(); // remove jquery's tooltip() handlers
+ }
+ return this._super.apply(this, arguments);
+ },
});
core.view_registry.add('graph', GraphView);
diff --git a/addons/web/static/src/js/views/list_view.js b/addons/web/static/src/js/views/list_view.js
index 5bf94100898..e97b4eac93f 100644
--- a/addons/web/static/src/js/views/list_view.js
+++ b/addons/web/static/src/js/views/list_view.js
@@ -267,7 +267,7 @@ var ListView = View.extend({
render_buttons: function($node) {
if (!this.$buttons) {
this.$buttons = $(QWeb.render("ListView.buttons", {'widget': this}));
- this.$buttons.find('.o_list_button_add').click(this.proxy('do_add_record'));
+ this.$buttons.on('click', '.o_list_button_add', this.proxy('do_add_record'));
this.$buttons.appendTo($node);
}
},
diff --git a/addons/web/static/src/js/views/pivot_view.js b/addons/web/static/src/js/views/pivot_view.js
index 264fa2af985..be63f02248d 100644
--- a/addons/web/static/src/js/views/pivot_view.js
+++ b/addons/web/static/src/js/views/pivot_view.js
@@ -827,6 +827,12 @@ var PivotView = View.extend({
error: crash_manager.rpc_error.bind(crash_manager)
});
},
+ destroy: function () {
+ if (this.$buttons) {
+ this.$buttons.find('button').off(); // remove jquery's tooltip() handlers
+ }
+ return this._super.apply(this, arguments);
+ },
});
function traverse_tree(root, f, arg1, arg2, arg3) {
diff --git a/addons/web/static/src/js/widgets/sidebar.js b/addons/web/static/src/js/widgets/sidebar.js
index 03997db6c36..1e382c3d985 100644
--- a/addons/web/static/src/js/widgets/sidebar.js
+++ b/addons/web/static/src/js/widgets/sidebar.js
@@ -52,6 +52,10 @@ var Sidebar = Widget.extend({
event.preventDefault();
});
},
+ destroy: function() {
+ $(window).off(this.fileupload_id);
+ return this._super.apply(this, arguments);
+ },
redraw: function() {
this.$el.html(QWeb.render('Sidebar', {widget: this}));
diff --git a/addons/web_editor/static/src/js/backend.js b/addons/web_editor/static/src/js/backend.js
index 468fab0c728..17ce8c3c1a1 100644
--- a/addons/web_editor/static/src/js/backend.js
+++ b/addons/web_editor/static/src/js/backend.js
@@ -113,11 +113,16 @@ var FieldTextHtmlSimple = widget.extend({
},
text_to_html: function (text) {
var value = text || "";
- if (value.match(/^\s*$/)) {
- value = '
';
- } else {
- value = "
"+value.split(/
/).join("
")+"
";
- value = value.replace(/
<\/p>/g, '').replace('
', '
').replace('
', '');
+ try {
+ $(text)[0].innerHTML;
+ return text;
+ } catch (e) {
+ if (value.match(/^\s*$/)) {
+ value = '
';
+ } else {
+ value = "
"+value.split(/
/).join("
")+"
";
+ value = value.replace(/
<\/p>/g, '').replace('
', '
').replace('
', '');
+ }
}
return value;
},
@@ -213,7 +218,7 @@ var FieldTextHtml = widget.extend({
self.$iframe.css("height", (self.$body.find("#oe_snippets").length ? 500 : 300) + "px");
}
};
- $(window).on('resize', self.resize);
+ $(window).on('resize', this.resize);
var def = this._super.apply(this, arguments);
this.$translate.remove();
@@ -374,7 +379,7 @@ var FieldTextHtml = widget.extend({
}
},
destroy: function () {
- $(window).off('resize', self.resize);
+ $(window).off('resize', this.resize);
delete window.odoo[this.callback+"_editor"];
delete window.odoo[this.callback+"_content"];
delete window.odoo[this.callback+"_updown"];
diff --git a/addons/web_kanban/static/src/js/kanban_record.js b/addons/web_kanban/static/src/js/kanban_record.js
index 473ebc59e98..c784073f2a5 100644
--- a/addons/web_kanban/static/src/js/kanban_record.js
+++ b/addons/web_kanban/static/src/js/kanban_record.js
@@ -64,6 +64,7 @@ var KanbanRecord = Widget.extend({
qweb_context[p] = _.bind(this[p], this);
}
}
+ this.qweb_context = qweb_context;
this.content = this.qweb.render('kanban-box', qweb_context);
},
@@ -81,7 +82,18 @@ var KanbanRecord = Widget.extend({
},
start: function() {
+ var self = this;
this.add_widgets();
+ this.$('[tooltip]').each(function () {
+ var $el = $(this);
+ var tooltip = $el.attr('tooltip');
+ if (tooltip) {
+ $el.tooltip({
+ 'html': true,
+ 'title': self.qweb.render(tooltip, self.qweb_context)
+ });
+ }
+ });
},
renderElement: function () {
@@ -172,14 +184,15 @@ var KanbanRecord = Widget.extend({
if (elem == ev.currentTarget) {
ischild = false;
}
+ var test_event = events && events.click && (events.click.length > 1 || events.click[0].namespace !== "tooltip");
if (ischild) {
children.push(elem);
- if (events && events.click) {
+ if (test_event) {
// do not trigger global click if one child has a click event registered
trigger = false;
}
}
- if (trigger && events && events.click) {
+ if (trigger && test_event) {
_.each(events.click, function(click_event) {
if (click_event.selector) {
// For each parent of original target, check if a
diff --git a/addons/website/static/src/js/website.snippets.gallery.js b/addons/website/static/src/js/website.snippets.gallery.js
index cde906ca764..8cb8bf0ceaa 100644
--- a/addons/website/static/src/js/website.snippets.gallery.js
+++ b/addons/website/static/src/js/website.snippets.gallery.js
@@ -360,7 +360,16 @@ options.registry.gallery_img = options.Class.extend({
this.buildingBlock.make_active($parent);
$parent.data('snippet-editor').styles.gallery.reapply();
}).bind(this));
- }
+ },
+ on_focus: function () {
+ this._super.apply(this, arguments);
+ if (this._current_src && this._current_src !== this.$target.attr("src")) {
+ _.defer((function () {
+ snippet_editor.globalSelector.closest(this.$target.parent()).data('snippet-editor').styles.gallery.reapply();
+ }).bind(this));
+ }
+ this._current_src = this.$target.attr("src");
+ },
});
diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py
index 95af149ff60..262e169bfe0 100644
--- a/addons/website_sale/controllers/main.py
+++ b/addons/website_sale/controllers/main.py
@@ -723,7 +723,7 @@ class WebsiteSale(http.Controller):
return request.website.render("website_sale.payment", values)
@http.route(['/shop/payment/transaction/
'], type='json', auth="public", website=True)
- def payment_transaction(self, acquirer_id):
+ def payment_transaction(self, acquirer_id, **kwargs):
""" Json method that creates a payment.transaction, used to create a
transaction when the user clicks on 'pay now' button. After having
created the transaction, the event continues and the user is redirected
@@ -735,6 +735,16 @@ class WebsiteSale(http.Controller):
Transaction = request.env['payment.transaction'].sudo()
order = request.website.sale_get_order()
+ # In case the route is called directly from the JS (as done in Stripe payment method)
+ so_id = kwargs.get('so_id')
+ so_token = kwargs.get('so_token')
+ if so_id and so_token:
+ order = request.env['sale.order'].sudo().search([('id', '=', so_id), ('access_token', '=', so_token)])
+ elif so_id:
+ order = request.env['sale.order'].search([('id', '=', so_id)])
+ else:
+ order = request.website.sale_get_order()
+
if not order or not order.order_line or acquirer_id is None:
return request.redirect("/shop/checkout")
diff --git a/openerp/http.py b/openerp/http.py
index 45db589aa28..c54dea5a17a 100644
--- a/openerp/http.py
+++ b/openerp/http.py
@@ -806,7 +806,7 @@ class HttpRequest(WebRequest):
if request.httprequest.method == 'OPTIONS' and request.endpoint and request.endpoint.routing.get('cors'):
headers = {
'Access-Control-Max-Age': 60 * 60 * 24,
- 'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept'
+ 'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept, X-Debug-Mode'
}
return Response(status=200, headers=headers)