odoo.define('website_sale.cart', function (require) {
'use strict';
var publicWidget = require('web.public.widget');
var core = require('web.core');
var _t = core._t;
var timeout;
publicWidget.registry.websiteSaleCartLink = publicWidget.Widget.extend({
selector: '#top_menu a[href$="/shop/cart"]',
events: {
'mouseenter': '_onMouseEnter',
'mouseleave': '_onMouseLeave',
'click': '_onClick',
},
/**
* @constructor
*/
init: function () {
this._super.apply(this, arguments);
this._popoverRPC = null;
},
/**
* @override
*/
start: function () {
this.$el.popover({
trigger: 'manual',
animation: true,
html: true,
title: function () {
return _t("My Cart");
},
container: 'body',
placement: 'auto',
template: '
'
});
return this._super.apply(this, arguments);
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* @private
* @param {Event} ev
*/
_onMouseEnter: function (ev) {
var self = this;
clearTimeout(timeout);
$(this.selector).not(ev.currentTarget).popover('hide');
timeout = setTimeout(function () {
if (!self.$el.is(':hover') || $('.mycart-popover:visible').length) {
return;
}
self._popoverRPC = $.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');
});
});
}, 300);
},
/**
* @private
* @param {Event} ev
*/
_onMouseLeave: function (ev) {
var self = this;
setTimeout(function () {
if ($('.popover:hover').length) {
return;
}
if (!self.$el.is(':hover')) {
self.$el.popover('hide');
}
}, 1000);
},
/**
* @private
* @param {Event} ev
*/
_onClick: function (ev) {
// When clicking on the cart link, prevent any popover to show up (by
// clearing the related setTimeout) and, if a popover rpc is ongoing,
// wait for it to be completed before going to the link's href. Indeed,
// going to that page may perform the same computation the popover rpc
// is already doing.
clearTimeout(timeout);
if (this._popoverRPC && this._popoverRPC.state() === 'pending') {
ev.preventDefault();
var href = ev.currentTarget.href;
this._popoverRPC.then(function () {
window.location.href = href;
});
}
},
});
});
odoo.define('website_sale.website_sale_category', function (require) {
'use strict';
var publicWidget = require('web.public.widget');
publicWidget.registry.websiteSaleCategory = publicWidget.Widget.extend({
selector: '#o_shop_collapse_category',
events: {
'click .fa-chevron-right': '_onOpenClick',
'click .fa-chevron-down': '_onCloseClick',
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* @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';
var core = require('web.core');
var config = require('web.config');
var publicWidget = require('web.public.widget');
var VariantMixin = require('sale.VariantMixin');
var wSaleUtils = require('website_sale.utils');
const wUtils = require('website.utils');
require("web.zoomodoo");
publicWidget.registry.WebsiteSale = publicWidget.Widget.extend(VariantMixin, {
selector: '.oe_website_sale',
events: _.extend({}, VariantMixin.events || {}, {
'change form .js_product:first 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',
'click .show_coupon': '_onClickShowCoupon',
'submit .o_wsale_products_searchbar_form': '_onSubmitSaleSearch',
'change select[name="country_id"]': '_onChangeCountry',
'change #shipping_use_same': '_onChangeShippingUseSame',
'click .toggle_summary': '_onToggleSummary',
'click #add_to_cart, #buy_now, #products_grid .o_wsale_product_btn .a-submit': 'async _onClickAdd',
'click input.js_product_change': 'onChangeVariant',
'change .js_main_product [data-attribute_exclusions]': 'onChangeVariant',
'change oe_optional_products_modal [data-attribute_exclusions]': 'onChangeVariant',
}),
/**
* @constructor
*/
init: function () {
this._super.apply(this, arguments);
this._changeCartQuantity = _.debounce(this._changeCartQuantity.bind(this), 500);
this._changeCountry = _.debounce(this._changeCountry.bind(this), 500);
this.isWebsite = true;
delete this.events['change .main_product:not(.in_cart) input.js_quantity'];
delete this.events['change [data-attribute_exclusions]'];
},
/**
* @override
*/
start() {
const def = this._super(...arguments);
this._applyHashFromSearch();
_.each(this.$('div.js_product'), function (product) {
$('input.js_product_change', product).first().trigger('change');
});
// This has to be triggered to compute the "out of stock" feature and the hash variant changes
this.triggerVariantChange(this.$el);
this.$('select[name="country_id"]').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');
}
});
this._startZoom();
window.addEventListener('hashchange', () => {
this._applyHash();
this.triggerVariantChange(this.$el);
});
return def;
},
/**
* The selector is different when using list view of variants.
*
* @override
*/
getSelectedVariantValues: function ($container) {
var combination = $container.find('input.js_product_change:checked')
.data('combination');
if (combination) {
return combination;
}
return VariantMixin.getSelectedVariantValues.apply(this, arguments);
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
_applyHash: function () {
var hash = window.location.hash.substring(1);
if (hash) {
var params = $.deparam(hash);
if (params['attr']) {
var attributeIds = params['attr'].split(',');
var $inputs = this.$('input.js_variant_change, select.js_variant_change option');
_.each(attributeIds, function (id) {
var $toSelect = $inputs.filter('[data-value_id="' + id + '"]');
if ($toSelect.is('input[type="radio"]')) {
$toSelect.prop('checked', true);
} else if ($toSelect.is('option')) {
$toSelect.prop('selected', true);
}
});
this._changeColorAttribute();
}
}
},
/**
* Sets the url hash from the selected product options.
*
* @private
*/
_setUrlHash: function ($parent) {
var $attributes = $parent.find('input.js_variant_change:checked, select.js_variant_change option:selected');
var attributeIds = _.map($attributes, function (elem) {
return $(elem).data('value_id');
});
history.replaceState(undefined, undefined, '#attr=' + attributeIds.join(','));
},
/**
* Set the checked color active.
*
* @private
*/
_changeColorAttribute: function () {
$('.css_attribute_color').removeClass("active")
.filter(':has(input:checked)')
.addClass("active");
},
/**
* @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);
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;
}
if (!data.cart_quantity) {
return window.location = '/shop/cart';
}
wSaleUtils.updateCartNavBar(data);
$input.val(data.quantity);
$('.js_quantity[data-line-id='+line_id+']').val(data.quantity).html(data.quantity);
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);
}
});
},
/**
* @private
*/
_changeCountry: function () {
if (!$("#country_id").val()) {
return;
}
this._rpc({
route: "/shop/country_infos/" + $("#country_id").val(),
params: {
mode: $("#country_id").attr('mode'),
},
}).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 || data.state_required) {
selectStates.html('');
_.each(data.states, function (x) {
var opt = $('