# king-addons/51.1.83/includes/extensions/Woo_Builder/script.js

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

- Page: https://pluginprobe.com/plugins/king-addons/51.1.83/code/includes/extensions/Woo_Builder/script.js
- Raw: https://pluginprobe.com/plugins/king-addons/51.1.83/raw/includes/extensions/Woo_Builder/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/extensions/Woo_Builder/script.js#L10-L20`.

```javascript
(function (factory) {
    if (typeof window.jQuery === 'undefined') {
        return;
    }
    factory(window.jQuery);
})(function ($) {
    'use strict';

    const $rulesContainer = $('#ka-woo-rules');
    if (!$rulesContainer.length || typeof $.fn.select2 === 'undefined') {
        return;
    }

    const restRoot = (window.wpApiSettings && window.wpApiSettings.root) ? window.wpApiSettings.root : '';
    const restNonce = (window.wpApiSettings && window.wpApiSettings.nonce) ? window.wpApiSettings.nonce : '';
    const noValueTypes = ['always', 'all_products', 'cart', 'checkout', 'my_account', 'is_shop'];

    const productTypeOptions = [
        {id: 'simple', text: 'Simple'},
        {id: 'variable', text: 'Variable'},
        {id: 'grouped', text: 'Grouped'},
        {id: 'external', text: 'External/Affiliate'}
    ];

    const endpoints = {
        product_in: {url: restRoot + 'kingaddons/v1/ajaxselect2/getPostsByPostType/', params: {query_slug: 'product'}},
        product_cat_in: {url: restRoot + 'kingaddons/v1/ajaxselect2/getTaxonomies/', params: {query_slug: 'product_cat'}},
        product_cat_archive_in: {url: restRoot + 'kingaddons/v1/ajaxselect2/getTaxonomies/', params: {query_slug: 'product_cat'}},
        product_tag_archive_in: {url: restRoot + 'kingaddons/v1/ajaxselect2/getTaxonomies/', params: {query_slug: 'product_tag'}},
        product_tag_in: {url: restRoot + 'kingaddons/v1/ajaxselect2/getTaxonomies/', params: {query_slug: 'product_tag'}},
        products: {url: restRoot + 'kingaddons/v1/ajaxselect2/getPostsByPostType/', params: {query_slug: 'product'}},
        product_categories: {url: restRoot + 'kingaddons/v1/ajaxselect2/getTaxonomies/', params: {query_slug: 'product_cat'}},
        product_cat_archives: {url: restRoot + 'kingaddons/v1/ajaxselect2/getTaxonomies/', params: {query_slug: 'product_cat'}},
        product_tags: {url: restRoot + 'kingaddons/v1/ajaxselect2/getTaxonomies/', params: {query_slug: 'product_tag'}},
    };

    const getPlaceholder = () => {
        if (window.KingAddonsWooBuilder && window.KingAddonsWooBuilder.labels && window.KingAddonsWooBuilder.labels.valuePlaceholder) {
            return window.KingAddonsWooBuilder.labels.valuePlaceholder;
        }
        return '';
    };

    const initRule = ($rule, idx) => {
        const $type = $rule.find('.ka-woo-rule-type');
        const $values = $rule.find('.ka-woo-rule-values');

        $type.attr('name', 'ka_woo_rule_type[' + idx + ']');
        $values.attr('name', 'ka_woo_rule_values[' + idx + '][]');

        const typeVal = $type.val() || '';

        if (noValueTypes.includes(typeVal)) {
            if ($values.hasClass('select2-hidden-accessible')) {
                $values.select2('destroy');
            }
            $values.prop('disabled', true).val(null);
            return;
        }

        $values.prop('disabled', false);

        if ($values.hasClass('select2-hidden-accessible')) {
            $values.select2('destroy');
        }

        const ajaxConfig = endpoints[typeVal] || null;
        const select2Options = {
            width: '100%',
            allowClear: true,
            placeholder: getPlaceholder(),
        };

        if (ajaxConfig && restRoot) {
            select2Options.ajax = {
                url: ajaxConfig.url,
                dataType: 'json',
                delay: 120,
                headers: restNonce ? {'X-WP-Nonce': restNonce} : {},
                data: function (params) {
                    const query = Object.assign({}, ajaxConfig.params || {});
                    if (params && params.term) {
                        query.s = params.term;
                    }
                    if ($values.data('selected-ids')) {
                        query.ids = $values.data('selected-ids');
                    }
                    return query;
                },
                processResults: function (data) {
                    return data;
                }
            };
        } else if (typeVal === 'product_type_in' || typeVal === 'product_types') {
            select2Options.data = productTypeOptions;
        }

        $values.select2(select2Options);

        // Clear pre-set data-selected-ids after init to avoid duplicate queries.
        $values.removeData('selected-ids');
    };

    const rebuildIndexes = () => {
        $rulesContainer.find('.ka-woo-rule').each((idx, el) => initRule($(el), idx));
    };

    $rulesContainer.on('click', '.ka-woo-remove-rule', function () {
        if ($rulesContainer.find('.ka-woo-rule').length <= 1) {
            return;
        }
        $(this).closest('.ka-woo-rule').remove();
        rebuildIndexes();
    });

    $('#ka-woo-add-rule').on('click', function () {
        const $first = $rulesContainer.find('.ka-woo-rule').first();
        if (!$first.length) {
            return;
        }
        const $clone = $first.clone();
        $clone.find('option').prop('selected', false);
        $clone.find('.ka-woo-rule-values').empty();
        $clone.appendTo($rulesContainer);
        rebuildIndexes();
    });

    $rulesContainer.on('change', '.ka-woo-rule-type', function () {
        const $rule = $(this).closest('.ka-woo-rule');
        initRule($rule, $rulesContainer.find('.ka-woo-rule').index($rule));
    });

    $rulesContainer.find('.ka-woo-rule-values').each(function () {
        const existingValues = $(this).val();
        if (existingValues && existingValues.length) {
            $(this).data('selected-ids', Array.isArray(existingValues) ? existingValues.join(',') : existingValues);
        }
    });

    rebuildIndexes();
});

(function () {
    'use strict';

    const defaultPanels = ['#customer_details', '.woocommerce-checkout-payment', '.woocommerce-checkout-review-order'];

    const resolvePanels = (container) => {
        const customSelectors = Array.from(container.querySelectorAll('.ka-woo-checkout-step')).map((step) => step.dataset.target || '');
        const mapped = customSelectors.some(Boolean) ? customSelectors : defaultPanels;
        return mapped.map((selector, idx) => ({ selector, idx }));
    };

    const togglePanels = (stepsMap, activeIndex, scroll) => {
        stepsMap.forEach((item, idx) => {
            if (!item.selector) {
                return;
            }
            document.querySelectorAll(item.selector).forEach((el) => {
                if (idx === activeIndex) {
                    el.classList.remove('ka-woo-hidden');
                } else {
                    el.classList.add('ka-woo-hidden');
                }
            });
        });

        if (scroll && scroll === 'yes') {
            const targetSelector = stepsMap[activeIndex] ? stepsMap[activeIndex].selector : null;
            const target = targetSelector ? document.querySelector(targetSelector) : null;
            if (target) {
                target.scrollIntoView({ behavior: 'smooth', block: 'start' });
            }
        }
    };

    const initSteps = () => {
        document.querySelectorAll('.ka-woo-checkout-steps--pro').forEach((container) => {
            const steps = Array.from(container.querySelectorAll('.ka-woo-checkout-step'));
            if (!steps.length) {
                return;
            }
            let current = 0;
            const scrollTop = container.dataset.scrollTop || 'no';
            const stepsMap = resolvePanels(container);
            const wrapper = container.parentElement;
            const enableNav = wrapper?.dataset.enableNav === 'true';
            const navPrev = wrapper?.querySelector('.ka-woo-checkout-steps__prev');
            const navNext = wrapper?.querySelector('.ka-woo-checkout-steps__next');
            const form = document.querySelector('form.checkout');
            const submitButton = form ? form.querySelector('button[type="submit"]') : null;
            const errorClass = 'ka-woo-checkout-step--error';
            const serverErrors = document.querySelector('.woocommerce-NoticeGroup-checkout, .woocommerce-error');

            const validateCurrent = () => {
                const panelSelector = stepsMap[current] ? stepsMap[current].selector : null;
                if (!panelSelector || !form) {
                    return true;
                }
                const panel = document.querySelector(panelSelector);
                if (!panel) {
                    return true;
                }
                const fields = panel.querySelectorAll('input, select, textarea');
                let valid = true;
                fields.forEach((field) => {
                    if (typeof field.reportValidity === 'function') {
                        if (!field.reportValidity()) {
                            valid = false;
                        }
                    }
                });
                return valid;
            };

            const setActive = (idx) => {
                current = idx;
                steps.forEach((step, i) => step.classList.toggle('is-active', i === current));
                togglePanels(stepsMap, current, scrollTop);
                if (enableNav && navPrev && navNext) {
                    navPrev.disabled = current === 0;
                    const isLast = current >= steps.length - 1;
                    navNext.dataset.isLast = isLast ? 'true' : 'false';
                    const defaultNext = container.dataset.nextText || navNext.textContent;
                    const submitText = container.dataset.submitText || navNext.textContent;
                    navNext.textContent = isLast ? submitText : defaultNext;
                    navNext.classList.toggle('is-submit', isLast);
                    if (submitButton) {
                        submitButton.disabled = !isLast;
                    }
                }
                steps.forEach((step) => step.classList.remove(errorClass));
            };

            steps.forEach((step, idx) => {
                step.addEventListener('click', () => setActive(idx));
            });

            if (enableNav && navPrev && navNext) {
                navPrev.addEventListener('click', () => {
                    setActive(Math.max(0, current - 1));
                });
                navNext.addEventListener('click', (e) => {
                    if (!validateCurrent()) {
                        e.preventDefault();
                        return;
                    }
                    if (navNext.dataset.isLast === 'true') {
                        if (submitButton) {
                            submitButton.click();
                        } else if (form) {
                            form.dispatchEvent(new Event('submit', { cancelable: true, bubbles: true }));
                        }
                        return;
                    }
                    setActive(Math.min(steps.length - 1, current + 1));
                });
            }

            setActive(0);

            // React to Woo checkout errors: highlight step containing error.
            document.body.addEventListener('checkout_error', () => {
                const errorField = document.querySelector('.woocommerce-error, .woocommerce-invalid');
                if (!errorField) {
                    return;
                }
                const errorStepIdx = stepsMap.findIndex((map) => map.selector && errorField.closest(map.selector));
                if (errorStepIdx >= 0) {
                    steps[errorStepIdx]?.classList.add(errorClass);
                    setActive(errorStepIdx);
                    errorField.scrollIntoView({ behavior: 'smooth', block: 'center' });
                }
            });

            // React to Woo AJAX errors (server-side validation)
            if (serverErrors) {
                const observer = new MutationObserver(() => {
                    const err = document.querySelector('.woocommerce-error, .woocommerce-invalid');
                    if (!err) {
                        return;
                    }
                    const idx = stepsMap.findIndex((map) => map.selector && err.closest(map.selector));
                    if (idx >= 0) {
                        steps[idx]?.classList.add(errorClass);
                        setActive(idx);
                        err.scrollIntoView({ behavior: 'smooth', block: 'center' });
                    }
                });
                observer.observe(serverErrors.parentElement || document.body, { childList: true, subtree: true });
            }
        });
    };

    const initSticky = () => {
        const items = document.querySelectorAll('[data-ka-sticky="true"]');
        items.forEach((el) => {
            const offset = parseInt(el.dataset.kaStickyOffset || '20', 10);
            const breakpoint = parseInt(el.dataset.kaStickyBreakpoint || '768', 10);
            const footer = document.querySelector('.site-footer, footer');

            const applySticky = () => {
                if (window.innerWidth < breakpoint) {
                    el.classList.remove('ka-woo-sticky-ready');
                    el.style.top = '';
                    el.style.maxHeight = '';
                    el.style.overflow = '';
                    return;
                }
                let available = window.innerHeight - offset - 20;
                if (footer) {
                    const rect = footer.getBoundingClientRect();
                    if (rect.top > 0) {
                        available = Math.min(available, rect.top - offset - 10);
                    }
                }
                el.classList.add('ka-woo-sticky-ready');
                el.style.top = offset + 'px';
                if (available > 100) {
                    el.style.maxHeight = available + 'px';
                    el.style.overflow = 'auto';
                }
            };

            const ro = new ResizeObserver(() => applySticky());
            ro.observe(document.body);
            if (footer) {
                const fo = new ResizeObserver(() => applySticky());
                fo.observe(footer);
            }
            // Adjust on content changes inside sticky container
            const contentObserver = new MutationObserver(() => applySticky());
            contentObserver.observe(el, { childList: true, subtree: true });
            applySticky();
            window.addEventListener('resize', applySticky, { passive: true });
        });
    };

    const initPayments = () => {
        document.querySelectorAll('.ka-woo-checkout-payment').forEach((wrapper) => {
            const icons = wrapper.dataset.kaIcons ? JSON.parse(wrapper.dataset.kaIcons) : {};
            const placeorder = wrapper.dataset.kaPlaceorder ? JSON.parse(wrapper.dataset.kaPlaceorder) : {};
            const accordion = wrapper.dataset.kaAccordion === 'true';
            const methods = wrapper.querySelectorAll('.wc_payment_methods .wc_payment_method');
            const orderButton = wrapper.querySelector('.place-order button[type="submit"]') || document.querySelector('.place-order button[type="submit"]');

            const applyIcons = () => {
                methods.forEach((method) => {
                    const input = method.querySelector('input[name="payment_method"]');
                    const label = input ? wrapper.querySelector('label[for="' + input.id + '"]') : null;
                    if (!input || !label) {
                        return;
                    }
                    const gid = input.value;
                    if (icons && icons[gid] && !label.querySelector('.ka-woo-payment-icon')) {
                        const img = document.createElement('img');
                        img.src = icons[gid];
                        img.alt = gid;
                        img.className = 'ka-woo-payment-icon';
                        label.appendChild(img);
                    }
                });
            };

            const updatePlaceOrder = () => {
                if (!orderButton) return;
                const selected = wrapper.querySelector('input[name="payment_method"]:checked');
                if (!selected) return;
                const gid = selected.value;
                if (placeorder && placeorder[gid]) {
                    orderButton.textContent = placeorder[gid];
                }
            };

            const toggleAccordion = () => {
                if (!accordion) return;
                methods.forEach((method) => {
                    const input = method.querySelector('input[name="payment_method"]');
                    const box = method.querySelector('.payment_box');
                    const active = input && input.checked;
                    method.classList.toggle('is-active', !!active);
                    if (box) {
                        box.style.display = active ? '' : 'none';
                    }
                });
            };

            methods.forEach((method) => {
                const input = method.querySelector('input[name="payment_method"]');
                if (input) {
                    input.addEventListener('change', () => {
                        updatePlaceOrder();
                        toggleAccordion();
                    });
                }
            });

            applyIcons();
            updatePlaceOrder();
            toggleAccordion();
        });
    };

    document.addEventListener('DOMContentLoaded', () => {
        initSteps();
        initSticky();
        initPayments();
    });
})();






```
