[FIX] sale, *: fix pill variant styling

*: sale_product_configurator

Enterprise PR: odoo/enterprise#42551

Steps to reproduce:

1. Install website_sale
2. Create product P
	- Go to Attributes & Variants tab
	- Add a line
	- Create and edit attribute "PILL"
		- Display Type = Pills
		- Add some attribute values
		- Save & Close
	- Add the attribute values in the list view
	- Save the product
3. Go to website product page

Issue:

The pills have a visible radio button inside, requiring users to click
on the radio button to change the variant. In V15, there was no radio
button, and users could click anywhere on the variant container to
change the variant.

The change in behaviour happened because the jquery code for handling
button clicks has changed. In V15 jquery, clicking a button would
trigger a change event, which would then be captured by the owl event
selector `change [data-attribute_exclusions]`, and the
`onChangeVariant` method was called.

In version 16, jQuery no longer triggers a change event when clicking
a button.

Solution:

Hide the radio input visually, then convert the variant text to a
label. When clicking on the label, the corresponding radio input
is checked.

This means that the whole button is not clickable anymore, only the
text.

opw-3185147

closes odoo/odoo#130615

X-original-commit: dc7af6a4c555740b2c2b13efe57cd971e14dc67f
Related: odoo/enterprise#45103
Signed-off-by: Stefan-Calin Crainiciuc (stcc) <stcc@odoo.com>
Signed-off-by: Valentin Chevalier <vcr@odoo.com>
This commit is contained in:
stcc-odoo
2023-08-03 10:43:30 +02:00
parent 768ac198a3
commit 2b095b8b1e
6 changed files with 117 additions and 2 deletions
@@ -73,6 +73,7 @@
cursor: default !important;
&.btn.active {
color: $white;
background-color: map-get($theme-colors, 'primary');
}
&:not(.active) {
@@ -13,6 +13,7 @@ var _t = core._t;
var VariantMixin = {
events: {
'change .css_attribute_color input': '_onChangeColorAttribute',
'change .o_variant_pills input' :'_onChangePillsAttribute',
'change .main_product:not(.in_cart) input.js_quantity': 'onChangeAddQuantity',
'change [data-attribute_exclusions]': 'onChangeVariant'
},
@@ -717,6 +718,14 @@ var VariantMixin = {
.addClass("active");
},
_onChangePillsAttribute: function (ev) {
var $parent = $(ev.target).closest('.js_product');
$parent.find('.o_variant_pills')
.removeClass("active")
.filter(':has(input:checked)')
.addClass("active");
},
/**
* Extension point for website_sale
*
@@ -196,6 +196,13 @@ label.css_attribute_color.css_not_available {
color: map-get($grays, '600');
background-color: map-get($grays, '200');
}
input {
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
opacity: 0;
}
}
}
@@ -2,6 +2,17 @@
import { registry } from "@web/core/registry";
function fail(errorMessage) {
const tour = registry.get("tourManager");
tour._consume_tour(tour.running_tour, errorMessage);
}
function assert(current, expected, info) {
if (current !== expected) {
fail(info + ': "' + current + '" instead of "' + expected + '".');
}
}
registry.category("web_tour.tours").add('tour_shop_archived_variant_multi', {
test: true,
url: '/shop?search=Test Product 2',
@@ -41,3 +52,46 @@ registry.category("web_tour.tours").add('tour_shop_archived_variant_multi', {
run: function () {},
},
]});
registry.category("web_tour.tours").add('test_09_pills_variant', {
test: true,
url: '/shop?search=Test Product 2',
steps: () => [
{
content: "select Test Product",
trigger: '.oe_product_cart a:containsExact("Test Product 2")',
},
{
content: "check there are two radio boxes, both hidden",
trigger: '.js_main_product',
run: function() {
var buttons = $('input.js_variant_change');
function isVisuallyHidden(elem) {
const style = window.getComputedStyle(elem);
return style.display === "none" ||
style.visibility === "hidden" ||
style.opacity === "0" ||
(style.width === "0px" && style.height === "0px")
}
assert(buttons.length, 2, "there should be two radio inputs")
assert(isVisuallyHidden(buttons[0]), true, "first radio input is not hidden")
assert(isVisuallyHidden(buttons[1]), true, "second radio input is not hidden")
assert(buttons[0].checked, true, "first radio input should be checked")
},
},
{
content: "click on the second variant label",
trigger: 'label:contains("Small")',
},
{
content: 'check second variant is selected',
trigger: 'li.o_variant_pills.active:contains("Small")',
run: function () {
var button = $('input.js_variant_change[data-attribute_name="Size"][data-value_name="Small"]');
assert(button.length, 1, "there should be one radio input")
assert(button[0].checked, true, "the radio input should be checked")
}
},
]});
@@ -402,3 +402,46 @@ class TestUi(HttpCaseWithUserDemo, HttpCaseWithUserPortal):
product_template.product_variant_ids[-1].active = False
self.start_tour("/", 'tour_shop_archived_variant_multi', login="portal")
def test_09_pills_variant(self):
"""The goal of this test is to make sure that you can click anywhere on a pill
and still trigger a variant change. The radio input be visually hidden.
Using "portal" to have various users in the tests.
"""
attribute_1 = self.env['product.attribute'].create([
{
'name': 'Size',
'create_variant': 'always',
'display_type': 'pills',
},
])
attribute_values = self.env['product.attribute.value'].create([
{
'name': 'Large',
'attribute_id': attribute_1.id,
'sequence': 1,
},
{
'name': 'Small',
'attribute_id': attribute_1.id,
'sequence': 2,
},
])
product_template = self.env['product.template'].create({
'name': 'Test Product 2',
'is_published': True,
})
self.env['product.template.attribute.line'].create([
{
'attribute_id': attribute_1.id,
'product_tmpl_id': product_template.id,
'value_ids': [(6, 0, attribute_values.ids)],
},
])
self.start_tour("/", 'test_09_pills_variant', login="portal")
@@ -82,10 +82,11 @@
t-att-data-is_custom="ptav.is_custom"
t-att-data-is_single_and_custom="single_and_custom"
t-att-autocomplete="off"/>
<div class="radio_input_value o_variant_pills_input_value">
<label class="radio_input_value o_variant_pills_input_value"
t-att-for="ptav.id">
<span t-field="ptav.name"/>
<t t-call="website_sale.badge_extra_price"/>
</div>
</label>
</li>
</t>
</ul>