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_Cart_Table / 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_Cart_Table/script.js

188 lines 5.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Woo Cart Table widget behavior.
3 *
4 * Handles cart quantity updates and item removal via AJAX.
5 * Exposes a global initializer for other cart-related widgets.
6 */
7 (function ($) {
8 "use strict";
9
10 const FLAG = "kaCartTableInit";
11
12 const KACartTable = window.KACartTable || (() => {
13 const getKeyFromInput = (input) => {
14 const name = input.getAttribute('name') || '';
15 const match = name.match(/cart\[(.+?)\]\[qty\]/);
16 return match ? match[1] : '';
17 };
18
19 const getKeyFromRemove = (link) => {
20 const href = link.getAttribute('href') || '';
21 try {
22 const url = new URL(href, window.location.href);
23 return url.searchParams.get('remove_item') || '';
24 } catch (e) {
25 return '';
26 }
27 };
28
29 const setNotices = (wrapper, notices) => {
30 let container = document.querySelector('.woocommerce-notices-wrapper');
31 if (!container) {
32 container = document.createElement('div');
33 container.className = 'woocommerce-notices-wrapper';
34 wrapper.prepend(container);
35 }
36 container.innerHTML = notices || '';
37 };
38
39 const applyFragments = (wrapper, data) => {
40 if (data.cart_html) {
41 wrapper.innerHTML = data.cart_html;
42 }
43
44 // Allow re-binding after HTML replacement.
45 if (wrapper && wrapper.dataset) {
46 delete wrapper.dataset[FLAG];
47 }
48
49 if (data.totals_html !== undefined) {
50 document.querySelectorAll('.ka-woo-cart-totals').forEach((totals) => {
51 totals.innerHTML = data.totals_html || '';
52 });
53 }
54
55 if (data.cross_sells_html !== undefined) {
56 document.querySelectorAll('.ka-woo-cart-cross-sells').forEach((cross) => {
57 cross.innerHTML = data.cross_sells_html || '';
58 });
59 if (window.KACartCrossSells && typeof window.KACartCrossSells.init === "function") {
60 window.KACartCrossSells.init();
61 }
62 }
63
64 setNotices(wrapper, data.notices || '');
65 initWrapper(wrapper);
66
67 document.body.dispatchEvent(new Event('wc_fragments_refreshed'));
68 };
69
70 const request = (wrapper, payload) => {
71 const ajaxUrl = wrapper.dataset.ajaxUrl;
72 const nonce = wrapper.dataset.nonce;
73 if (!ajaxUrl || !nonce) {
74 return Promise.resolve();
75 }
76
77 const body = new URLSearchParams();
78 body.append('action', 'ka_cart_update');
79 body.append('nonce', nonce);
80 // Empty-cart copy, so the block rendered after the last item is removed
81 // matches the one a full page load produces.
82 ['emptyTitle', 'emptyMessage', 'emptyPrimaryText', 'emptyPrimaryUrl', 'emptySecondaryText', 'emptySecondaryUrl']
83 .forEach((prop) => {
84 const key = prop.replace(/[A-Z]/g, (c) => '_' + c.toLowerCase());
85 body.append(key, wrapper.dataset[prop] || '');
86 });
87 Object.entries(payload).forEach(([k, v]) => body.append(k, v));
88
89 wrapper.classList.add('loading');
90
91 return fetch(ajaxUrl, {
92 method: 'POST',
93 headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
94 body: body.toString(),
95 credentials: 'same-origin',
96 })
97 .then((res) => res.json())
98 .then((res) => {
99 if (res && res.success) {
100 applyFragments(wrapper, res.data || {});
101 }
102 })
103 .catch(() => {})
104 .finally(() => wrapper.classList.remove('loading'));
105 };
106
107 const bindEvents = (wrapper) => {
108 if (!wrapper || !wrapper.dataset) return;
109 if (wrapper.dataset[FLAG] === "1") return;
110 wrapper.dataset[FLAG] = "1";
111
112 const form = wrapper.querySelector('.woocommerce-cart-form');
113 if (!form) return;
114
115 form.addEventListener('submit', (e) => {
116 e.preventDefault();
117 const updates = [...form.querySelectorAll('input[name^="cart["][name$="[qty]"]')]
118 .map((input) => ({ key: getKeyFromInput(input), qty: input.value }))
119 .filter((item) => item.key);
120 updates.reduce(
121 (chain, item) => chain.then(() => request(wrapper, { op: 'qty', cart_item_key: item.key, qty: item.qty })),
122 Promise.resolve()
123 );
124 });
125
126 form.addEventListener('change', (e) => {
127 const target = e.target;
128 if (!(target instanceof HTMLInputElement)) return;
129 if (target.name && target.name.startsWith('cart[')) {
130 const key = getKeyFromInput(target);
131 if (key) {
132 request(wrapper, { op: 'qty', cart_item_key: key, qty: target.value });
133 }
134 }
135 });
136
137 form.addEventListener('click', (e) => {
138 const target = e.target;
139 if (!(target instanceof HTMLElement)) return;
140 if (target.closest('a.remove')) {
141 e.preventDefault();
142 const link = target.closest('a.remove');
143 const key = getKeyFromRemove(link);
144 if (key) {
145 request(wrapper, { op: 'remove', cart_item_key: key });
146 }
147 }
148 });
149 };
150
151 const initWrapper = (wrapper) => {
152 bindEvents(wrapper);
153 };
154
155 const init = (root) => {
156 const ctx = root && root.querySelectorAll ? root : document;
157 ctx.querySelectorAll('.ka-cart-table').forEach((wrapper) => {
158 initWrapper(wrapper);
159 });
160 };
161
162 return { init };
163 })();
164
165 window.KACartTable = KACartTable;
166
167 const initInScope = ($scope) => {
168 const root = $scope && $scope[0] ? $scope[0] : document;
169 KACartTable.init(root);
170 };
171
172 document.addEventListener("DOMContentLoaded", () => KACartTable.init(document));
173
174 $(window).on("elementor/frontend/init", function () {
175 elementorFrontend.hooks.addAction(
176 "frontend/element_ready/woo_cart_table.default",
177 function ($scope) {
178 initInScope($scope);
179 }
180 );
181 });
182 })(jQuery);
183
184
185
186
187
188