[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:
+1
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user