# king-addons/51.1.83/includes/widgets/Woo_Product_Variations/script.js

King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder, version 51.1.83. 209 lines.

- Page: https://pluginprobe.com/plugins/king-addons/51.1.83/code/includes/widgets/Woo_Product_Variations/script.js
- Raw: https://pluginprobe.com/plugins/king-addons/51.1.83/raw/includes/widgets/Woo_Product_Variations/script.js
- Modified: 2026-09-16T13:52:08+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/king-addons/51.1.83/code/includes/widgets/Woo_Product_Variations/script.js#L10-L20`.

```javascript
/**
 * Woo Product Variations widget behavior.
 *
 * Enhances variation selects with swatches.
 */
(function ($) {
    "use strict";

    const INIT_FLAG = "kaWooVariationsInit";

    const initVariations = (wrap) => {
        if (!wrap || !wrap.dataset) return;
        if (wrap.dataset[INIT_FLAG] === "1") return;
        wrap.dataset[INIT_FLAG] = "1";

        const form = wrap.querySelector('form.variations_form');
        if (!form) return;

        if (wrap.dataset.swatches !== 'yes') return;

        let map = {};
        try {
            map = wrap.dataset.swatchesMap ? JSON.parse(wrap.dataset.swatchesMap) : {};
        } catch (e) {
            map = {};
        }

        const unavailableBehavior = map.unavailable || 'disable';
        const showSelected = map.show_selected === 'yes';
        const shape = map.shape || 'square';
        const attrMap = (map.map) || {};
        const source = map.source || 'auto';

        const selects = form.querySelectorAll('select');
        const updateCallbacks = [];
        const runAll = () => updateCallbacks.forEach((cb) => cb());

        // Woo leaves out-of-stock options enabled in the native select when
        // "hide out of stock" is off. Hide/disable would then be a no-op,
        // so also read the variation JSON Woo already prints on the form.
        let productVariations = [];
        try {
            const raw = form.getAttribute('data-product_variations');
            productVariations = raw && raw !== 'false' ? JSON.parse(raw) : [];
        } catch (e) {
            productVariations = [];
        }

        const attributeMatches = (variationAttr, selected) => {
            if (!variationAttr) {
                return true;
            }
            return variationAttr === selected;
        };

        const valueIsAvailable = (attrName, val) => {
            if (!Array.isArray(productVariations) || !productVariations.length) {
                const opt = form.querySelector(`select[name="${attrName}"] option[value="${val}"]`);
                return !(opt && opt.disabled);
            }
            return productVariations.some((variation) => {
                if (!variation || variation.is_in_stock === false) {
                    return false;
                }
                const attrs = variation.attributes || {};
                if (!attributeMatches(attrs[attrName], val)) {
                    return false;
                }
                return Array.from(selects).every((other) => {
                    if (other.name === attrName || !other.value) {
                        return true;
                    }
                    return attributeMatches(attrs[other.name], other.value);
                });
            });
        };

        selects.forEach((select) => {
            const attrName = select.name;
            const swatchesInfo = attrMap[attrName];
            if (!swatchesInfo) {
                return;
            }

            const container = document.createElement('div');
            container.className = 'ka-woo-variations__swatches';

            const selectedText = document.createElement('div');
            selectedText.className = 'ka-woo-variations__selected';

            const options = Array.from(select.options).filter((opt) => opt.value !== '');
            options.forEach((opt) => {
                const btn = document.createElement('button');
                btn.type = 'button';
                btn.className = 'ka-woo-variations__swatch';
                if (shape === 'round') {
                    btn.classList.add('ka-woo-variations__swatch--round');
                }
                btn.dataset.value = opt.value;

                const info = swatchesInfo[opt.value] || {};

                if (source === 'text') {
                    const span = document.createElement('span');
                    span.className = 'ka-woo-variations__swatch-text';
                    span.textContent = info.label || opt.text;
                    btn.appendChild(span);
                } else if (info.image) {
                    const img = document.createElement('img');
                    img.src = info.image;
                    img.alt = info.label || opt.text;
                    img.className = 'ka-woo-variations__swatch-img';
                    btn.appendChild(img);
                } else if (info.color) {
                    const span = document.createElement('span');
                    span.className = 'ka-woo-variations__swatch-color';
                    span.style.background = info.color;
                    btn.appendChild(span);
                } else {
                    const span = document.createElement('span');
                    span.className = 'ka-woo-variations__swatch-text';
                    span.textContent = info.label || opt.text;
                    btn.appendChild(span);
                }

                btn.addEventListener('click', () => {
                    if (!valueIsAvailable(attrName, opt.value)) {
                        return;
                    }
                    select.value = opt.value;
                    select.dispatchEvent(new Event('change', { bubbles: true }));
                    if (window.jQuery) {
                        window.jQuery(select).trigger('change');
                    }
                    runAll();
                });

                container.appendChild(btn);
            });

            select.style.display = 'none';
            select.insertAdjacentElement('afterend', container);
            if (showSelected) {
                container.insertAdjacentElement('afterend', selectedText);
            }

            const updateStates = () => {
                const current = select.value;
                Array.from(container.children).forEach((btn) => {
                    const val = btn.dataset.value;
                    const opt = select.querySelector(`option[value="${val}"]`);
                    const unavailable = !valueIsAvailable(attrName, val) || !!(opt && opt.disabled);
                    btn.classList.toggle('is-active', current === val);
                    btn.classList.toggle('is-disabled', unavailable);
                    if (unavailable && unavailableBehavior === 'hide') {
                        btn.style.display = 'none';
                    } else {
                        btn.style.display = '';
                    }
                });
                if (showSelected) {
                    const label = (swatchesInfo[current] && swatchesInfo[current].label) || current || '';
                    const prefix = select.getAttribute('aria-label') || '';
                    selectedText.textContent = label ? `${prefix}: ${label}` : '';
                }
            };

            select.addEventListener('change', runAll);
            updateCallbacks.push(updateStates);
        });

        runAll();

        // Sync with WooCommerce variation script events.
        if (window.jQuery) {
            const $form = window.jQuery(form);
            $form.on('woocommerce_update_variation_values woocommerce_variation_has_changed reset_data found_variation hide_variation', runAll);
            const resetBtn = form.querySelector('.reset_variations');
            if (resetBtn) {
                resetBtn.addEventListener('click', () => {
                    setTimeout(runAll, 50);
                });
            }
        }
    };

    const initAll = (root) => {
        const ctx = root && root.querySelectorAll ? root : document;
        ctx.querySelectorAll(".ka-woo-variations").forEach(initVariations);
    };

    document.addEventListener("DOMContentLoaded", () => initAll(document));

    $(window).on("elementor/frontend/init", function () {
        elementorFrontend.hooks.addAction(
            "frontend/element_ready/woo_product_variations.default",
            function ($scope) {
                initAll($scope && $scope[0] ? $scope[0] : document);
            }
        );
    });
})(jQuery);







```
