PluginProbe
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder / 51.1.83
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder v51.1.83
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 51.1.47 51.1.49 All 37 releases
king-addons / includes / widgets / Woo_Product_Variations / script.js

script.js in King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder 51.1.83, at includes/widgets/Woo_Product_Variations/script.js

209 lines 7.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Woo Product Variations widget behavior.
3 *
4 * Enhances variation selects with swatches.
5 */
6 (function ($) {
7 "use strict";
8
9 const INIT_FLAG = "kaWooVariationsInit";
10
11 const initVariations = (wrap) => {
12 if (!wrap || !wrap.dataset) return;
13 if (wrap.dataset[INIT_FLAG] === "1") return;
14 wrap.dataset[INIT_FLAG] = "1";
15
16 const form = wrap.querySelector('form.variations_form');
17 if (!form) return;
18
19 if (wrap.dataset.swatches !== 'yes') return;
20
21 let map = {};
22 try {
23 map = wrap.dataset.swatchesMap ? JSON.parse(wrap.dataset.swatchesMap) : {};
24 } catch (e) {
25 map = {};
26 }
27
28 const unavailableBehavior = map.unavailable || 'disable';
29 const showSelected = map.show_selected === 'yes';
30 const shape = map.shape || 'square';
31 const attrMap = (map.map) || {};
32 const source = map.source || 'auto';
33
34 const selects = form.querySelectorAll('select');
35 const updateCallbacks = [];
36 const runAll = () => updateCallbacks.forEach((cb) => cb());
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
78 selects.forEach((select) => {
79 const attrName = select.name;
80 const swatchesInfo = attrMap[attrName];
81 if (!swatchesInfo) {
82 return;
83 }
84
85 const container = document.createElement('div');
86 container.className = 'ka-woo-variations__swatches';
87
88 const selectedText = document.createElement('div');
89 selectedText.className = 'ka-woo-variations__selected';
90
91 const options = Array.from(select.options).filter((opt) => opt.value !== '');
92 options.forEach((opt) => {
93 const btn = document.createElement('button');
94 btn.type = 'button';
95 btn.className = 'ka-woo-variations__swatch';
96 if (shape === 'round') {
97 btn.classList.add('ka-woo-variations__swatch--round');
98 }
99 btn.dataset.value = opt.value;
100
101 const info = swatchesInfo[opt.value] || {};
102
103 if (source === 'text') {
104 const span = document.createElement('span');
105 span.className = 'ka-woo-variations__swatch-text';
106 span.textContent = info.label || opt.text;
107 btn.appendChild(span);
108 } else if (info.image) {
109 const img = document.createElement('img');
110 img.src = info.image;
111 img.alt = info.label || opt.text;
112 img.className = 'ka-woo-variations__swatch-img';
113 btn.appendChild(img);
114 } else if (info.color) {
115 const span = document.createElement('span');
116 span.className = 'ka-woo-variations__swatch-color';
117 span.style.background = info.color;
118 btn.appendChild(span);
119 } else {
120 const span = document.createElement('span');
121 span.className = 'ka-woo-variations__swatch-text';
122 span.textContent = info.label || opt.text;
123 btn.appendChild(span);
124 }
125
126 btn.addEventListener('click', () => {
127 if (!valueIsAvailable(attrName, opt.value)) {
128 return;
129 }
130 select.value = opt.value;
131 select.dispatchEvent(new Event('change', { bubbles: true }));
132 if (window.jQuery) {
133 window.jQuery(select).trigger('change');
134 }
135 runAll();
136 });
137
138 container.appendChild(btn);
139 });
140
141 select.style.display = 'none';
142 select.insertAdjacentElement('afterend', container);
143 if (showSelected) {
144 container.insertAdjacentElement('afterend', selectedText);
145 }
146
147 const updateStates = () => {
148 const current = select.value;
149 Array.from(container.children).forEach((btn) => {
150 const val = btn.dataset.value;
151 const opt = select.querySelector(`option[value="${val}"]`);
152 const unavailable = !valueIsAvailable(attrName, val) || !!(opt && opt.disabled);
153 btn.classList.toggle('is-active', current === val);
154 btn.classList.toggle('is-disabled', unavailable);
155 if (unavailable && unavailableBehavior === 'hide') {
156 btn.style.display = 'none';
157 } else {
158 btn.style.display = '';
159 }
160 });
161 if (showSelected) {
162 const label = (swatchesInfo[current] && swatchesInfo[current].label) || current || '';
163 const prefix = select.getAttribute('aria-label') || '';
164 selectedText.textContent = label ? `${prefix}: ${label}` : '';
165 }
166 };
167
168 select.addEventListener('change', runAll);
169 updateCallbacks.push(updateStates);
170 });
171
172 runAll();
173
174 // Sync with WooCommerce variation script events.
175 if (window.jQuery) {
176 const $form = window.jQuery(form);
177 $form.on('woocommerce_update_variation_values woocommerce_variation_has_changed reset_data found_variation hide_variation', runAll);
178 const resetBtn = form.querySelector('.reset_variations');
179 if (resetBtn) {
180 resetBtn.addEventListener('click', () => {
181 setTimeout(runAll, 50);
182 });
183 }
184 }
185 };
186
187 const initAll = (root) => {
188 const ctx = root && root.querySelectorAll ? root : document;
189 ctx.querySelectorAll(".ka-woo-variations").forEach(initVariations);
190 };
191
192 document.addEventListener("DOMContentLoaded", () => initAll(document));
193
194 $(window).on("elementor/frontend/init", function () {
195 elementorFrontend.hooks.addAction(
196 "frontend/element_ready/woo_product_variations.default",
197 function ($scope) {
198 initAll($scope && $scope[0] ? $scope[0] : document);
199 }
200 );
201 });
202 })(jQuery);
203
204
205
206
207
208
209