PluginProbe ʕ •ᴥ•ʔ
Weight Based Shipping Table Rate for WooCommerce – Flexible Shipping / 6.11.0
Weight Based Shipping Table Rate for WooCommerce – Flexible Shipping v6.11.0
6.12.1 6.12.0 6.11.0 6.10.0 6.9.1 6.9.0 6.8.1 6.8.0 6.7.4 6.7.3 6.7.2 6.7.0 4.21.7 4.22.0 4.22.1 4.23.0 4.23.1 4.23.2 4.23.3 4.24.0 4.24.1 4.24.10 4.24.11 4.24.12 4.24.13 4.24.14 4.24.15 4.24.16 4.24.17 4.24.18 4.24.19 4.24.2 4.24.4 4.24.6 4.24.7 4.24.8 4.24.9 4.25.0 4.25.1 4.25.2 4.25.4 4.25.5 4.25.6 4.25.7 4.25.8 4.3.0 4.3.1 4.4.0 4.4.1 4.5.0 4.5.1 4.6.0 4.6.1 4.7.0 4.7.1 4.7.2 4.8.0 4.8.1 4.8.3 4.8.4 4.8.5 4.9.0 5.0.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.0.9 5.1.0 5.1.1 5.1.2 5.1.3 5.2.0 5.3.0 5.3.1 5.3.3 5.3.4 5.3.5 6.0.0 6.1.0 6.1.1 6.1.2 6.2.0 6.2.1 6.2.2 6.2.3 6.2.4 6.3.0 trunk 6.4.0 1.4 6.4.1 1.4.1 6.4.2 1.5 6.4.3 1.6 6.4.5 1.6.1 6.5.0 1.6.2 6.5.1 1.7 6.5.2 1.8 6.5.3 1.9 6.5.4 1.9.1 6.5.5 1.9.10 6.5.6 1.9.11 6.5.7 1.9.12 6.5.8 1.9.2 6.6.0 1.9.3 6.6.1 1.9.4 6.6.2 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0 2.0.1 2.1 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 3.0.6 3.0.7 3.1 3.1.1 3.1.10 3.1.11 3.1.12 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.10.0 3.11.0 3.11.1 3.11.2 3.11.3 3.11.4 3.12.0 3.13.0 3.14.0 3.14.1 3.14.2 3.14.3 3.14.4 3.15.0 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.2.0 3.3.1 3.3.10 3.3.11 3.3.12 3.3.13 3.3.14 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9 3.4.0 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.8.0 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.15 3.9.16 3.9.17 3.9.18 3.9.19 3.9.2 3.9.20 3.9.21 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.9 4.0.0 4.0.1 4.0.10 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.10.0 4.10.1 4.11.0 4.11.1 4.11.2 4.11.3 4.11.4 4.11.5 4.11.6 4.11.7 4.11.8 4.11.9 4.12.0 4.13.0 4.13.1 4.13.2 4.13.3 4.14.0 4.14.1 4.14.2 4.15.0 4.16.0 4.16.1 4.16.2 4.17.0 4.18.0 4.18.1 4.18.2 4.18.3 4.18.4 4.18.5 4.18.6 4.19.0 4.19.1 4.2.0 4.20.0 4.20.1 4.20.2 4.20.3 4.21.0 4.21.1 4.21.2 4.21.3 4.21.4 4.21.5
flexible-shipping / assets / js / shipping-method-block-checkout.js
flexible-shipping / assets / js Last commit date
admin.js 2 weeks ago admin.min.js 2 weeks ago beacon-clicked.js 2 weeks ago beacon-clicked.min.js 2 weeks ago contextual-info.js 2 weeks ago contextual-info.min.js 2 weeks ago duplicate-methods.js 2 weeks ago duplicate-methods.min.js 2 weeks ago new-rules-table-popup.js 2 weeks ago onboarding.js 2 weeks ago rules-settings.js 2 weeks ago shipping-method-block-checkout.js 2 weeks ago shipping-method-block-checkout.min.js 2 weeks ago
shipping-method-block-checkout.js
312 lines
1 ( function() {
2 const config = window.__fsShippingMethodLogoBlocks || {};
3
4 const ensureArray = ( value ) => ( Array.isArray( value ) ? value : [] );
5
6 const getMetaValue = ( metaData, key ) => {
7 if ( ! Array.isArray( metaData ) ) {
8 return null;
9 }
10
11 const item = metaData.find( ( entry ) => entry && entry.key === key );
12 return item ? item.value : null;
13 };
14
15 const decodeBase64 = ( value ) => {
16 if ( ! value || 'string' !== typeof value ) {
17 return '';
18 }
19
20 try {
21 return window.atob( value );
22 } catch ( error ) {
23 return '';
24 }
25 };
26
27 const getRateDescription = ( rate ) => {
28 if ( ! rate ) {
29 return '';
30 }
31
32 const encodedDescription = getMetaValue( rate.meta_data, config.description_encoded_key || 'description_base64encoded' );
33 if ( encodedDescription ) {
34 const decodedDescription = decodeBase64( encodedDescription );
35 if ( decodedDescription ) {
36 return decodedDescription;
37 }
38 }
39
40 return getMetaValue( rate.meta_data, config.description_key || 'description' ) || '';
41 };
42
43 const getNormalizedText = ( value ) => ( value || '' ).replace( /\s+/g, ' ' ).trim();
44
45 const getNormalizedHtmlText = ( value ) => {
46 const wrapper = document.createElement( 'div' );
47 wrapper.innerHTML = value || '';
48
49 return getNormalizedText( wrapper.textContent || '' );
50 };
51
52 const isVisible = ( element ) => {
53 let current = element;
54
55 while ( current && current !== document.body ) {
56 const style = window.getComputedStyle( current );
57
58 if ( 'none' === style.display || 'hidden' === style.visibility ) {
59 return false;
60 }
61
62 current = current.parentElement;
63 }
64
65 return Boolean( element );
66 };
67
68 const descriptionMatchesElement = ( description, element ) => {
69 if ( ! description || ! isVisible( element ) ) {
70 return false;
71 }
72
73 const descriptionText = getNormalizedHtmlText( description );
74
75 return '' !== descriptionText && getNormalizedText( element.textContent || '' ).includes( descriptionText );
76 };
77
78 const getRateId = ( rate ) => rate?.rate_id || rate?.id || '';
79
80 const isFlexibleShippingRate = ( rate ) => {
81 if ( ! rate ) {
82 return false;
83 }
84
85 return ensureArray( config.method_ids ).includes( rate.method_id );
86 };
87
88 const escapeCssValue = ( value ) => {
89 if ( window.CSS && 'function' === typeof window.CSS.escape ) {
90 return window.CSS.escape( value );
91 }
92
93 return value.replace( /["\\]/g, '\\$&' );
94 };
95
96 const getOptionForRate = ( rateId ) => {
97 if ( ! rateId ) {
98 return null;
99 }
100
101 const selector = `.wc-block-components-radio-control__option input[value="${ escapeCssValue( rateId ) }"]`;
102 const input = document.querySelector( selector );
103
104 return input ? input.closest( '.wc-block-components-radio-control__option' ) : null;
105 };
106
107 const findDescriptionElement = ( option, input ) => {
108 const selector = '[id$="__secondary-description"], [id$="__description"]';
109
110 if ( input ) {
111 const describedBy = input.getAttribute( 'aria-describedby' );
112 if ( describedBy ) {
113 const descriptionIds = describedBy.split( /\s+/ ).filter( Boolean );
114
115 for ( const id of descriptionIds ) {
116 const element = document.getElementById( id );
117 if ( element && element.matches( selector ) ) {
118 return element;
119 }
120 }
121 }
122 }
123
124 return option ? option.querySelector( selector ) : null;
125 };
126
127 const getInsertionAnchor = ( option, input ) => {
128 if ( ! option ) {
129 return null;
130 }
131
132 const labelGroup = option.querySelector( '.wc-block-components-radio-control__label-group' );
133 if ( labelGroup ) {
134 return labelGroup;
135 }
136
137 return findDescriptionElement( option, input ) || option.querySelector( 'label' ) || option;
138 };
139
140 const createLogoNode = ( logoUrl, logoAlt ) => {
141 const wrapper = document.createElement( 'span' );
142 wrapper.classList.add( config.wrapper_class || 'flexible-shipping-method-logo-block' );
143 wrapper.style.display = 'block';
144 wrapper.style.marginTop = '6px';
145
146 const image = document.createElement( 'img' );
147 image.src = logoUrl;
148 image.alt = logoAlt || '';
149 image.style.maxHeight = '40px';
150 image.style.width = 'auto';
151 image.loading = 'lazy';
152
153 wrapper.appendChild( image );
154
155 return wrapper;
156 };
157
158 const createDescriptionNode = ( description ) => {
159 const wrapper = document.createElement( 'div' );
160 wrapper.className = config.description_class || 'shipping-method-description flexible-shipping-method-description-block wc-block-components-radio-control__secondary-description';
161 wrapper.innerHTML = description;
162
163 return wrapper;
164 };
165
166 const getRatesFromCart = ( cartData ) => {
167 if ( ! cartData || ! Array.isArray( cartData.shippingRates ) ) {
168 return [];
169 }
170
171 const rates = [];
172
173 cartData.shippingRates.forEach( ( shippingPackage ) => {
174 const packageRates = shippingPackage?.shipping_rates ?? [];
175 packageRates.forEach( ( rate ) => rates.push( rate ) );
176 } );
177
178 return rates;
179 };
180
181 const renderLogos = () => {
182 if ( ! window.wp || ! window.wp.data || 'function' !== typeof window.wp.data.select ) {
183 return;
184 }
185
186 const cartStore = window.wp.data.select( 'wc/store/cart' );
187 if ( ! cartStore || 'function' !== typeof cartStore.getCartData ) {
188 return;
189 }
190
191 const rates = getRatesFromCart( cartStore.getCartData() );
192 if ( ! rates.length ) {
193 return;
194 }
195
196 rates.forEach( ( rate ) => {
197 if ( ! isFlexibleShippingRate( rate ) ) {
198 return;
199 }
200
201 const description = getRateDescription( rate );
202 const logoUrl = getMetaValue( rate.meta_data, config.logo_url_key || 'method_logo_url' );
203 const option = getOptionForRate( getRateId( rate ) );
204 if ( ! option ) {
205 return;
206 }
207
208 const wrapperClass = config.wrapper_class || 'flexible-shipping-method-logo-block';
209 const descriptionClass = ( config.description_class || 'shipping-method-description flexible-shipping-method-description-block wc-block-components-radio-control__secondary-description' )
210 .split( ' ' )
211 .filter( Boolean )
212 .map( ( className ) => `.${ className }` )
213 .join( '' );
214 const existingDescription = descriptionClass ? option.querySelector( descriptionClass ) : null;
215 const existingLogo = option.querySelector( `.${ wrapperClass }` );
216 const input = option.querySelector( 'input' );
217 const nativeDescription = findDescriptionElement( option, input );
218 const insertionAnchor = getInsertionAnchor( option, input );
219 const logoAlt = getMetaValue( rate.meta_data, config.logo_alt_key || 'method_logo_alt' ) || '';
220 const hasNativeDescription = descriptionMatchesElement( description, nativeDescription );
221
222 if ( description ) {
223 if ( hasNativeDescription ) {
224 if ( existingDescription ) {
225 existingDescription.remove();
226 }
227 } else if ( existingDescription ) {
228 if ( existingDescription.innerHTML !== description ) {
229 existingDescription.innerHTML = description;
230 }
231 } else if ( insertionAnchor ) {
232 insertionAnchor.insertAdjacentElement( 'afterend', createDescriptionNode( description ) );
233 }
234 } else if ( existingDescription ) {
235 existingDescription.remove();
236 }
237
238 const descriptionAnchor = option.querySelector( descriptionClass ) || nativeDescription || insertionAnchor;
239
240 if ( ! logoUrl ) {
241 if ( existingLogo ) {
242 existingLogo.remove();
243 }
244 return;
245 }
246
247 if ( existingLogo ) {
248 const existingImage = existingLogo.querySelector( 'img' );
249
250 if ( existingImage ) {
251 if ( existingImage.src !== logoUrl ) {
252 existingImage.src = logoUrl;
253 }
254
255 if ( existingImage.alt !== logoAlt ) {
256 existingImage.alt = logoAlt;
257 }
258 }
259
260 if ( descriptionAnchor && existingLogo.previousElementSibling !== descriptionAnchor ) {
261 descriptionAnchor.insertAdjacentElement( 'afterend', existingLogo );
262 }
263
264 return;
265 }
266
267 const logoNode = createLogoNode( logoUrl, logoAlt );
268
269 if ( descriptionAnchor ) {
270 descriptionAnchor.insertAdjacentElement( 'afterend', logoNode );
271 return;
272 }
273
274 const label = option.querySelector( 'label' ) || option;
275 label.appendChild( logoNode );
276 } );
277 };
278
279 const boot = () => {
280 let scheduled = false;
281
282 const scheduleRender = () => {
283 if ( scheduled ) {
284 return;
285 }
286
287 scheduled = true;
288 window.requestAnimationFrame( () => {
289 scheduled = false;
290 renderLogos();
291 } );
292 };
293
294 if ( window.wp && window.wp.data && 'function' === typeof window.wp.data.subscribe ) {
295 window.wp.data.subscribe( scheduleRender );
296 }
297
298 new MutationObserver( scheduleRender ).observe( document.body, {
299 childList: true,
300 subtree: true,
301 } );
302
303 scheduleRender();
304 };
305
306 if ( 'loading' === document.readyState ) {
307 document.addEventListener( 'DOMContentLoaded', boot );
308 } else {
309 boot();
310 }
311 }() );
312