PluginProbe
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder / 51.1.83
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder v51.1.83
51.1.84 51.1.85 51.1.83 51.1.82 51.1.81 51.1.79 51.1.78 51.1.77 51.1.76 51.1.74 51.1.75 51.1.65 51.1.64 51.1.63 trunk 51.1.14 51.1.2 51.1.35 51.1.36 51.1.37 51.1.38 51.1.39 51.1.44 51.1.45 51.1.46 All 39 releases
← All changes | includes/widgets/Woo_Product_Variations/script.js +46 -3 51.1.7651.1.83 View file →
@@ -34,8 +34,48 @@
34 34 const selects = form.querySelectorAll('select');
35 35 const updateCallbacks = [];
36 36 const runAll = () => updateCallbacks.forEach((cb) => cb());
37 37
38 + // Woo leaves out-of-stock options enabled in the native select when
39 + // "hide out of stock" is off. Hide/disable would then be a no-op,
40 + // so also read the variation JSON Woo already prints on the form.
41 + let productVariations = [];
42 + try {
43 + const raw = form.getAttribute('data-product_variations');
44 + productVariations = raw && raw !== 'false' ? JSON.parse(raw) : [];
45 + } catch (e) {
46 + productVariations = [];
47 + }
48 +
49 + const attributeMatches = (variationAttr, selected) => {
50 + if (!variationAttr) {
51 + return true;
52 + }
53 + return variationAttr === selected;
54 + };
55 +
56 + const valueIsAvailable = (attrName, val) => {
57 + if (!Array.isArray(productVariations) || !productVariations.length) {
58 + const opt = form.querySelector(`select[name="${attrName}"] option[value="${val}"]`);
59 + return !(opt && opt.disabled);
60 + }
61 + return productVariations.some((variation) => {
62 + if (!variation || variation.is_in_stock === false) {
63 + return false;
64 + }
65 + const attrs = variation.attributes || {};
66 + if (!attributeMatches(attrs[attrName], val)) {
67 + return false;
68 + }
69 + return Array.from(selects).every((other) => {
70 + if (other.name === attrName || !other.value) {
71 + return true;
72 + }
73 + return attributeMatches(attrs[other.name], other.value);
74 + });
75 + });
76 + };
77 +
38 78 selects.forEach((select) => {
39 79 const attrName = select.name;
40 80 const swatchesInfo = attrMap[attrName];
41 81 if (!swatchesInfo) {
@@ -83,8 +123,11 @@
83 123 btn.appendChild(span);
84 124 }
85 125
86 126 btn.addEventListener('click', () => {
127 + if (!valueIsAvailable(attrName, opt.value)) {
128 + return;
129 + }
87 130 select.value = opt.value;
88 131 select.dispatchEvent(new Event('change', { bubbles: true }));
89 132 if (window.jQuery) {
90 133 window.jQuery(select).trigger('change');
@@ -105,12 +148,12 @@
105 148 const current = select.value;
106 149 Array.from(container.children).forEach((btn) => {
107 150 const val = btn.dataset.value;
108 151 const opt = select.querySelector(`option[value="${val}"]`);
109 - const disabled = opt && opt.disabled;
152 + const unavailable = !valueIsAvailable(attrName, val) || !!(opt && opt.disabled);
110 153 btn.classList.toggle('is-active', current === val);
111 - btn.classList.toggle('is-disabled', !!disabled);
112 - if (disabled && unavailableBehavior === 'hide') {
154 + btn.classList.toggle('is-disabled', unavailable);
155 + if (unavailable && unavailableBehavior === 'hide') {
113 156 btn.style.display = 'none';
114 157 } else {
115 158 btn.style.display = '';
116 159 }