diff --git a/addons/website_sale/static/src/js/website_sale.js b/addons/website_sale/static/src/js/website_sale.js
index dbd1b23bd5f..6f91dd8ca67 100644
--- a/addons/website_sale/static/src/js/website_sale.js
+++ b/addons/website_sale/static/src/js/website_sale.js
@@ -1,513 +1,689 @@
odoo.define('website_sale.cart', function (require) {
- "use strict";
+'use strict';
- require('web.dom_ready');
- var core = require('web.core');
- var _t = core._t;
+var sAnimations = require('website.content.snippets.animation');
+var core = require('web.core');
+var _t = core._t;
- var shopping_cart_link = $('ul#top_menu li a[href$="/shop/cart"]');
- var shopping_cart_link_counter;
- shopping_cart_link.popover({
- trigger: 'manual',
- animation: true,
- html: true,
- title: function () {
- return _t("My Cart");
- },
- container: 'body',
- placement: 'auto',
- template: '
'
- }).on("mouseenter",function () {
+var timeout;
+
+sAnimations.registry.websiteSaleCartLink = sAnimations.Class.extend({
+ selector: '#top_menu a[href$="/shop/cart"]',
+ read_events: {
+ 'mouseenter': '_onMouseEnter',
+ 'mouseleave': '_onMouseLeave',
+ },
+
+ /**
+ * @override
+ */
+ start: function () {
+ var def = this._super.apply(this, arguments);
+ if (this.editableMode) {
+ return def;
+ }
+
+ this.$el.popover({
+ trigger: 'manual',
+ animation: true,
+ html: true,
+ title: function () {
+ return _t("My Cart");
+ },
+ container: 'body',
+ placement: 'auto',
+ template: ''
+ });
+ return def;
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * @param {Event} ev
+ */
+ _onMouseEnter: function (ev) {
var self = this;
- clearTimeout(shopping_cart_link_counter);
- shopping_cart_link.not(self).popover('hide');
- shopping_cart_link_counter = setTimeout(function(){
- if($(self).is(':hover') && !$(".mycart-popover:visible").length)
- {
- $.get("/shop/cart", {'type': 'popover'})
- .then(function (data) {
- $(self).data("bs.popover").options.content = data;
- $(self).popover("show");
- $(".popover").on("mouseleave", function () {
- $(self).trigger('mouseleave');
- });
- });
+ clearTimeout(timeout);
+ $(this.selector).not(ev.currentTarget).popover('hide');
+ timeout = setTimeout(function () {
+ if (!self.$el.is(':hover') || $('.mycart-popover:visible').length) {
+ return;
}
+ $.get("/shop/cart", {
+ type: 'popover',
+ }).then(function (data) {
+ self.$el.data("bs.popover").config.content = data;
+ self.$el.popover("show");
+ $('.popover').on('mouseleave', function () {
+ self.$el.trigger('mouseleave');
+ });
+ });
}, 100);
- }).on("mouseleave", function () {
+ },
+ /**
+ * @private
+ * @param {Event} ev
+ */
+ _onMouseLeave: function (ev) {
var self = this;
setTimeout(function () {
- if (!$(".popover:hover").length) {
- if(!$(self).is(':hover')) {
- $(self).popover('hide');
- }
+ if ($('.popover:hover').length) {
+ return;
+ }
+ if (!self.$el.is(':hover')) {
+ self.$el.popover('hide');
}
}, 1000);
- });
+ },
+});
});
odoo.define('website_sale.website_sale_category', function (require) {
- "use strict";
+'use strict';
- require('web.dom_ready');
+var sAnimations = require('website.content.snippets.animation');
- if(!$('#o_shop_collapse_category').length) {
- return $.Deferred().reject("DOM doesn't contain '#o_shop_collapse_category'");
- }
+sAnimations.registry.websiteSaleCategory = sAnimations.Class.extend({
+ selector: '#o_shop_collapse_category',
+ read_events: {
+ 'click .fa-chevron-right': '_onOpenClick',
+ 'click .fa-chevron-down': '_onCloseClick',
+ },
- $('#o_shop_collapse_category').on('click', '.fa-chevron-right',function(){
- $(this).parent().siblings().find('.fa-chevron-down:first').click();
- $(this).parents('li').find('ul:first').show('normal');
- $(this).toggleClass('fa-chevron-down fa-chevron-right');
- });
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
- $('#o_shop_collapse_category').on('click', '.fa-chevron-down',function(){
- $(this).parent().find('ul:first').hide('normal');
- $(this).toggleClass('fa-chevron-down fa-chevron-right');
- });
+ /**
+ * @private
+ * @param {Event} ev
+ */
+ _onOpenClick: function (ev) {
+ var $fa = $(ev.currentTarget);
+ $fa.parent().siblings().find('.fa-chevron-down:first').click();
+ $fa.parents('li').find('ul:first').show('normal');
+ $fa.toggleClass('fa-chevron-down fa-chevron-right');
+ },
+ /**
+ * @private
+ * @param {Event} ev
+ */
+ _onCloseClick: function (ev) {
+ var $fa = $(ev.currentTarget);
+ $fa.parent().find('ul:first').hide('normal');
+ $fa.toggleClass('fa-chevron-down fa-chevron-right');
+ },
+});
});
odoo.define('website_sale.website_sale', function (require) {
- "use strict";
+'use strict';
- require('web.dom_ready');
- var base = require("web_editor.base");
- var ajax = require('web.ajax');
- var utils = require('web.utils');
- var core = require('web.core');
- var config = require('web.config');
- require("website.content.zoomodoo");
- var _t = core._t;
+var utils = require('web.utils');
+var core = require('web.core');
+var config = require('web.config');
+var sAnimations = require('website.content.snippets.animation');
+require("website.content.zoomodoo");
- if(!$('.oe_website_sale').length) {
- return $.Deferred().reject("DOM doesn't contain '.oe_website_sale'");
- }
+var _t = core._t;
- $('.oe_website_sale').each(function () {
- var oe_website_sale = this;
+sAnimations.registry.WebsiteSale = sAnimations.Class.extend({
+ selector: '.oe_website_sale',
+ read_events: {
+ 'change input[name="add_qty"]': '_onChangeAddQuantity',
+ 'mouseup .js_publish': '_onMouseupPublish',
+ 'touchend .js_publish': '_onMouseupPublish',
+ 'change .oe_cart input.js_quantity[data-product-id]': '_onChangeCartQuantity',
+ 'click .oe_cart a.js_add_suggested_products': '_onClickSuggestedProduct',
+ 'click a.js_add_cart_json': '_onClickAddCartJSON',
+ 'click .a-submit': '_onClickSubmit',
+ 'change form.js_attributes input, form.js_attributes select': '_onChangeAttribute',
+ 'mouseup form.js_add_cart_json label': '_onMouseupAddCartLabel',
+ 'touchend form.js_add_cart_json label': '_onMouseupAddCartLabel',
+ 'change .css_attribute_color input': '_onChangeColorAttribute',
+ 'change input.js_variant_change, select.js_variant_change, input.js_product_change, [data-attribute_value_ids]': '_onChangeVariant',
+ 'click .show_coupon': '_onClickShowCoupon',
+ 'submit .o_website_sale_search': '_onSubmitSaleSearch',
+ 'change select[name="country_id"]': '_onChangeCountry',
+ 'change #shipping_use_same': '_onChangeShippingUseSame',
+ 'click .toggle_summary': '_onToggleSummary',
+ },
- $(oe_website_sale).on("change", 'input[name="add_qty"]', function (event) {
- var product_ids = [];
- var product_dom = $(event.target).closest(".js_product").find(".js_add_cart_variants");
- var qty = $(event.target).closest('form').find('input[name="add_qty"]').val();
- var attribute_value_ids = product_dom.data("attribute_value_ids");
- _.each(attribute_value_ids, function(entry) {
- product_ids.push(entry[0]);
- });
+ /**
+ * @constructor
+ */
+ init: function () {
+ this._super.apply(this, arguments);
- if ($("#product_detail").length) {
- // display the reduction from the pricelist in function of the quantity
- ajax.jsonRpc("/shop/get_unit_price", 'call', {'product_ids': product_ids,'add_qty': parseInt(qty)})
- .then(function (data) {
- var current = attribute_value_ids;
- for(var j=0; j < current.length; j++){
- current[j][2] = data[current[j][0]];
- }
- product_dom.trigger("change");
- });
+ this._changeCartQuantity = _.debounce(this._changeCartQuantity.bind(this), 500);
+ this._changeCountry = _.debounce(this._changeCountry.bind(this), 500);
+ },
+ /**
+ * @override
+ */
+ start: function () {
+ var def = this._super.apply(this, arguments);
+ if (this.editableMode) {
+ return def;
+ }
+
+ _.each(this.$('div.js_product'), function (product) {
+ $('input.js_product_change', product).first().trigger('change');
+ });
+
+ _.each(this.$('.js_add_cart_variants'), function (add_variant) {
+ $('input.js_variant_change, select.js_variant_change', add_variant).first().trigger('change');
+ });
+
+ this.$('select[name="country_id"]').change();
+
+ this.$('#checkbox_cgv').trigger('change');
+
+ core.bus.on('resize', this, function () {
+ if (config.device.size_class === config.device.SIZES.XL) {
+ $('.toggle_summary_div').addClass('d-none d-xl-block');
}
});
- // change for css
- $(oe_website_sale).on('mouseup touchend', '.js_publish', function (ev) {
- $(ev.currentTarget).parents(".thumbnail").toggleClass("disabled");
+ // Do not activate image zoom for mobile devices, since it might prevent users from scrolling the page
+ if (!config.device.isMobile) {
+ var autoZoom = $('.ecom-zoomable').data('ecom-zoom-auto') || false,
+ factorZoom = parseFloat($('.ecom-zoomable').data('ecom-zoom-factor')) || 1.5,
+ attach = '#o-carousel-product';
+ _.each($('.ecom-zoomable img[data-zoom]'), function (el) {
+ onImageLoaded(el, function () {
+ var $img = $(el);
+ if (!_.str.endsWith(el.src, el.dataset.zoomImage) || // if zoom-img != img
+ el.naturalWidth >= $(attach).width() * factorZoom || el.naturalHeight >= $(attach).height() * factorZoom) {
+ $img.zoomOdoo({event: autoZoom ? 'mouseenter' : 'click', attach: attach});
+ } else {
+ $img.removeAttr('data-zoom'); // remove cursor
+ }
+ });
+ });
+ }
+
+ function onImageLoaded(img, callback) {
+ $(img).on('load', function () { callback(); });
+ if (img.complete) {
+ $(img).off('load');
+ callback();
+ }
+ }
+
+ return def;
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ _changeCartQuantity: function ($input, value, $dom_optional, line_id, productIDs) {
+ _.each($dom_optional, function (elem) {
+ $(elem).find('.js_quantity').text(value);
+ productIDs.push($(elem).find('span[data-product-id]').data('product-id'));
});
+ $input.data('update_change', true);
- var clickwatch = (function(){
- var timer = 0;
- return function(callback, ms){
- clearTimeout(timer);
- timer = setTimeout(callback, ms);
- };
- })();
-
- $(oe_website_sale).on("change", ".oe_cart input.js_quantity[data-product-id]", function () {
- var $input = $(this);
- if ($input.data('update_change')) {
+ this._rpc({
+ route: "/shop/cart/update_json",
+ params: {
+ line_id: line_id,
+ product_id: parseInt($input.data('product-id'), 10),
+ set_qty: value
+ },
+ }).then(function (data) {
+ $input.data('update_change', false);
+ var check_value = parseInt($input.val() || 0, 10);
+ if (isNaN(check_value)) {
+ check_value = 1;
+ }
+ if (value !== check_value) {
+ $input.trigger('change');
return;
}
- var value = parseInt($input.val() || 0, 10);
- if (isNaN(value)) {
- value = 1;
- }
- var $dom = $(this).closest('tr');
- //var default_price = parseFloat($dom.find('.text-danger > span.oe_currency_value').text());
- var $dom_optional = $dom.nextUntil(':not(.optional_product.info)');
- var line_id = parseInt($input.data('line-id'),10);
- var product_ids = [parseInt($input.data('product-id'),10)];
- clickwatch(function(){
- $dom_optional.each(function(){
- $(this).find('.js_quantity').text(value);
- product_ids.push($(this).find('span[data-product-id]').data('product-id'));
- });
- $input.data('update_change', true);
-
- ajax.jsonRpc("/shop/cart/update_json", 'call', {
- 'line_id': line_id,
- 'product_id': parseInt($input.data('product-id'), 10),
- 'set_qty': value
- }).then(function (data) {
- $input.data('update_change', false);
- var check_value = parseInt($input.val() || 0, 10);
- if (isNaN(check_value)) {
- check_value = 1;
- }
- if (value !== check_value) {
- $input.trigger('change');
- return;
- }
- var $q = $(".my_cart_quantity");
- if (data.cart_quantity) {
- $q.parents('li:first').removeClass('d-none');
- }
- else {
- window.location = '/shop/cart';
- }
-
- $q.html(data.cart_quantity).hide().fadeIn(600);
- $input.val(data.quantity);
- $('.js_quantity[data-line-id='+line_id+']').val(data.quantity).html(data.quantity);
-
- $(".js_cart_lines").first().before(data['website_sale.cart_lines']).end().remove();
- $(".js_cart_summary").first().before(data['website_sale.short_cart_summary']).end().remove();
-
- if (data.warning) {
- var cart_alert = $('.oe_cart').parent().find('#data_warning');
- if (cart_alert.length === 0) {
- $('.oe_cart').prepend(''+
- ' ' + data.warning + '
');
- }
- else {
- cart_alert.html(' ' + data.warning);
- }
- $input.val(data.quantity);
- }
- });
- }, 500);
- });
-
- $(oe_website_sale).on("click", ".oe_cart a.js_add_suggested_products", function () {
- $(this).prev('input').val(1).trigger('change');
- });
-
- // hack to add and remove from cart with json
- $(oe_website_sale).on('click', 'a.js_add_cart_json', function (ev) {
- ev.preventDefault();
- var $link = $(ev.currentTarget);
- var $input = $link.closest('.input-group').find("input");
- var product_id = +$input.closest('*:has(input[name="product_id"])').find('input[name="product_id"]').val();
- var min = parseFloat($input.data("min") || 0);
- var max = parseFloat($input.data("max") || Infinity);
- var quantity = ($link.has(".fa-minus").length ? -1 : 1) + parseFloat($input.val() || 0, 10);
- var new_qty = quantity > min ? (quantity < max ? quantity : max) : min;
- // if they are more of one input for this product (eg: option modal)
- $('input[name="'+$input.attr("name")+'"]').add($input).filter(function () {
- var $prod = $(this).closest('*:has(input[name="product_id"])');
- return !$prod.length || +$prod.find('input[name="product_id"]').val() === product_id;
- }).val(new_qty).change();
- return false;
- });
-
- $('.oe_website_sale, #comment').off('click', '.a-submit').on('click', '.a-submit', function (event) {
- if (!event.isDefaultPrevented() && !$(this).is(".disabled")) {
- event.preventDefault();
- $(this).closest('form').submit();
- }
- if ($(this).hasClass('a-submit-disable')){
- $(this).addClass("disabled");
- }
- if ($(this).hasClass('a-submit-loading')){
- var loading = '';
- var fa_span = $(this).find('span[class*="fa"]');
- if (fa_span.length){
- fa_span.replaceWith(loading);
- }
- else{
- $(this).append(loading);
- }
- }
- });
- $('form.js_attributes input, form.js_attributes select', oe_website_sale).on('change', function (event) {
- if (!event.isDefaultPrevented()) {
- event.preventDefault();
- $(this).closest("form").submit();
- }
- });
-
- // change price when they are variants
- $('form.js_add_cart_json label', oe_website_sale).on('mouseup touchend', function () {
- var $label = $(this);
- var $price = $label.parents("form:first").find(".oe_price .oe_currency_value");
- if (!$price.data("price")) {
- $price.data("price", parseFloat($price.text()));
- }
- var value = $price.data("price") + parseFloat($label.find(".badge span").text() || 0);
-
- var dec = value % 1;
- $price.html(value + (dec < 0.01 ? ".00" : (dec < 1 ? "0" : "") ));
- });
- // hightlight selected color
- $('.css_attribute_color input', oe_website_sale).on('change', function () {
- $('.css_attribute_color').removeClass("active");
- $('.css_attribute_color:has(input:checked)').addClass("active");
- });
-
- function price_to_str(price) {
- var l10n = _t.database.parameters;
- var precision = 2;
-
- if ($(".decimal_precision").length) {
- precision = parseInt($(".decimal_precision").last().data('precision'));
- }
- var formatted = _.str.sprintf('%.' + precision + 'f', price).split('.');
- formatted[0] = utils.insert_thousand_seps(formatted[0]);
- return formatted.join(l10n.decimal_point);
- }
-
- function update_product_image(event_source, product_id) {
- var $img;
- if ($('#o-carousel-product').length) {
- $img = $(event_source).closest('tr.js_product, .oe_website_sale').find('img.js_variant_img');
- $img.attr("src", "/web/image/product.product/" + product_id + "/image");
- $img.parent().attr('data-oe-model', 'product.product').attr('data-oe-id', product_id)
- .data('oe-model', 'product.product').data('oe-id', product_id);
-
- var $thumbnail = $(event_source).closest('tr.js_product, .oe_website_sale').find('img.js_variant_img_small');
- if ($thumbnail.length !== 0) { // if only one, thumbnails are not displayed
- $thumbnail.attr("src", "/web/image/product.product/" + product_id + "/image/90x90");
- $('.carousel').carousel(0);
- }
+ var $q = $(".my_cart_quantity");
+ if (data.cart_quantity) {
+ $q.parents('li:first').removeClass('d-none');
}
else {
- $img = $(event_source).closest('tr.js_product, .oe_website_sale').find('span[data-oe-model^="product."][data-oe-type="image"] img:first, img.product_detail_img');
- $img.attr("src", "/web/image/product.product/" + product_id + "/image");
- $img.parent().attr('data-oe-model', 'product.product').attr('data-oe-id', product_id)
- .data('oe-model', 'product.product').data('oe-id', product_id);
- }
- // reset zooming constructs
- $img.filter('[data-zoom-image]').attr('data-zoom-image', $img.attr('src'));
- if ($img.data('zoomOdoo') !== undefined) {
- $img.data('zoomOdoo').isReady = false;
- }
- }
-
- $(oe_website_sale).on('change', 'input.js_variant_change, select.js_variant_change, input.js_product_change, [data-attribute_value_ids]', function (ev) {
- var $parent = $(ev.target).closest('.js_product');
- var $ul = $parent.find('.js_add_cart_variants');
- var $product_id = $parent.find('.product_id').first();
- var $price = $parent.find(".oe_price:first .oe_currency_value");
- var $default_price = $parent.find(".oe_default_price:first .oe_currency_value");
- var $optional_price = $parent.find(".oe_optional:first .oe_currency_value");
- var variant_ids = $ul.data("attribute_value_ids");
- var values = [];
- var unchanged_values = $parent.find('div.oe_unchanged_value_ids').data('unchanged_value_ids') || [];
-
- $parent.find('input.js_variant_change:checked, select.js_variant_change').each(function () {
- values.push(+$(this).val());
- });
- values = values.concat(unchanged_values);
- var list_variant_id = parseInt($parent.find('input.js_product_change:checked').val());
-
- $parent.find("label").removeClass("text-muted css_not_available");
-
- var product_id = false;
- for (var k in variant_ids) {
- if (_.isEmpty(_.difference(variant_ids[k][1], values)) ||
- variant_ids[k][0] === list_variant_id) {
- $.when(base.ready()).then(function() {
- $price.html(price_to_str(variant_ids[k][2]));
- $default_price.html(price_to_str(variant_ids[k][3]));
- });
- if (variant_ids[k][3]-variant_ids[k][2]>0.01) {
- $default_price.closest('.oe_website_sale').addClass("discount");
- $optional_price.closest('.oe_optional').show().css('text-decoration', 'line-through');
- $default_price.parent().removeClass('d-none');
- } else {
- $optional_price.closest('.oe_optional').hide();
- $default_price.parent().addClass('d-none');
- }
- product_id = variant_ids[k][0];
- update_product_image(this, product_id);
- break;
- }
+ window.location = '/shop/cart';
}
- $parent.find("input.js_variant_change:radio, select.js_variant_change").each(function () {
- var $input = $(this);
- var id = +$input.val();
- var values = [id];
+ $q.html(data.cart_quantity).hide().fadeIn(600);
+ $input.val(data.quantity);
+ $('.js_quantity[data-line-id='+line_id+']').val(data.quantity).html(data.quantity);
- $parent.find("ul:not(:has(input.js_variant_change[value='" + id + "'])) input.js_variant_change:checked, select.js_variant_change").each(function () {
- values.push(+$(this).val());
- });
+ $(".js_cart_lines").first().before(data['website_sale.cart_lines']).end().remove();
+ $(".js_cart_summary").first().before(data['website_sale.short_cart_summary']).end().remove();
- for (var k in variant_ids) {
- if (!_.difference(values, variant_ids[k][1]).length) {
- return;
- }
- }
- $input.closest("label").addClass("css_not_available");
- $input.find("option[value='" + id + "']").addClass("css_not_available");
- });
-
- if (product_id) {
- $parent.removeClass("css_not_available");
- $product_id.val(product_id);
- $parent.find("#add_to_cart").removeClass("disabled");
- } else {
- $parent.addClass("css_not_available");
- $product_id.val(0);
- $parent.find("#add_to_cart").addClass("disabled");
- }
- });
-
- $('div.js_product', oe_website_sale).each(function () {
- $('input.js_product_change', this).first().trigger('change');
- });
-
- $('.js_add_cart_variants', oe_website_sale).each(function () {
- $('input.js_variant_change, select.js_variant_change', this).first().trigger('change');
- });
-
- $('.oe_website_sale').on('click', '.show_coupon', function(e) {
- $(e.currentTarget).hide();
- $('.coupon_form').removeClass('d-none');
- });
- $('.oe_cart').on('click', '.js_change_shipping', function() {
- if (!$('body.editor_enable').length) { //allow to edit button text with editor
- var $old = $('.all_shipping').find('.card.border_primary');
- $old.find('.btn-ship').toggle();
- $old.addClass('js_change_shipping');
- $old.removeClass('border_primary');
-
- var $new = $(this).parent('div.one_kanban').find('.card');
- $new.find('.btn-ship').toggle();
- $new.removeClass('js_change_shipping');
- $new.addClass('border_primary');
-
- var $form = $(this).parent('div.one_kanban').find('form.hide');
- $.post($form.attr('action'), $form.serialize()+'&xhr=1');
- }
- });
- $('.oe_cart').on('click', '.js_edit_address', function (ev) {
- ev.preventDefault();
- $(this).closest('div.one_kanban').find('form.d-none').attr('action', '/shop/address').submit();
- });
- $('.oe_cart').on('click', '.js_delete_product', function(e) {
- e.preventDefault();
- $(this).closest('tr').find('.js_quantity').val(0).trigger('change');
- });
-
- if ($('.oe_website_sale .dropdown_sorty_by').length) {
- // this method allow to keep current get param from the action, with new search query
- $('.oe_website_sale .o_website_sale_search').on('submit', function (event) {
- var $this = $(this);
- if (!event.isDefaultPrevented() && !$this.is(".disabled")) {
- event.preventDefault();
- var oldurl = $this.attr('action');
- oldurl += (oldurl.indexOf("?")===-1) ? "?" : "";
- var search = $this.find('input.search-query');
- window.location = oldurl + '&' + search.attr('name') + '=' + encodeURIComponent(search.val());
- }
- });
- }
-
- if ($(".checkout_autoformat").length) {
- $(oe_website_sale).on('change', "select[name='country_id']", function () {
- clickwatch(function() {
- if ($("#country_id").val()) {
- ajax.jsonRpc("/shop/country_infos/" + $("#country_id").val(), 'call', {mode: 'shipping'}).then(
- function(data) {
- // placeholder phone_code
- //$("input[name='phone']").attr('placeholder', data.phone_code !== 0 ? '+'+ data.phone_code : '');
-
- // populate states and display
- var selectStates = $("select[name='state_id']");
- // dont reload state at first loading (done in qweb)
- if (selectStates.data('init')===0 || selectStates.find('option').length===1) {
- if (data.states.length) {
- selectStates.html('');
- _.each(data.states, function(x) {
- var opt = $('