PageSourceSearch

https://theneomag.com/wp-content/plugins/wpc-product-options/assets/js/frontend.js?ver=3.1.6

js theneomag.com collected 2026-10-04 05:26:39 UTC 23,087 bytes, 605 lines download raw bytes

1'use strict';
2
3(function ($) {
4    $(function () {
5        // ready
6        wpcpo_init();
7
8        // tooltips
9        if (wpcpo_vars.tooltip_library === 'tippy') {
10            tippy('.wpcpo-tippy-tooltip', {
11                allowHTML: true, interactive: true,
12            });
13        }
14    });
15
16    $(document).on('woosq_loaded', function () {
17        // quick view
18        wpcpo_init();
19    });
20
21    $(document).on('found_variation', function (e, t) {
22        if ($(e['target']).closest('.woosb-product').length || $(e['target']).closest('.wooco-product').length || $(e['target']).closest('.woobt-product').length || $(e['target']).closest('.woofs-product').length || $(e['target']).closest('.woosg-product').length) {
23            return;
24        }
25
26        let $total = $(e['target']).closest('form.cart').find('.wpcpo-total');
27
28        $total.attr('data-price', t['display_price']);
29
30        wpcpo_update_total($total);
31    });
32
33    $(document).on('reset_data', function (e) {
34        if ($(e['target']).closest('.woosb-product').length || $(e['target']).closest('.wooco-product').length || $(e['target']).closest('.woobt-product').length || $(e['target']).closest('.woofs-product').length || $(e['target']).closest('.woosg-product').length) {
35            return;
36        }
37
38        let $total = $(e['target']).closest('form.cart').find('.wpcpo-total');
39
40        $total.attr('data-price', $total.attr('data-o_price'));
41
42        wpcpo_update_total($total);
43    });
44
45    $(document).on('woovr_selected', function (e, selected, variations) {
46        if (variations.closest('.woosb-product').length || variations.closest('.wooco-product').length || variations.closest('.woobt-product').length || variations.closest('.woofs-product').length || variations.closest('.woosg-product').length) {
47            return;
48        }
49
50        let purchasable = selected.attr('data-purchasable'),
51            $total = variations.closest('form.cart').find('.wpcpo-total');
52
53        if (purchasable === 'yes') {
54            $total.attr('data-price', selected.attr('data-price'));
55        } else {
56            $total.attr('data-price', $total.attr('data-o_price'));
57        }
58
59        wpcpo_update_total($total);
60    });
61
62    /* WPC Product Bundles */
63    $(document).on('woosb_calc_price', function (e, total_sale, total, total_html, price_suffix, $wrap) {
64        let wid = $wrap.attr('data-id'), $total = $('.wpcpo-total[data-product-id="' + wid + '"]');
65
66        $total.attr('data-price', total_sale);
67
68        wpcpo_update_total($total);
69    });
70
71    /* WPC Composite Products */
72    $(document).on('wooco_calc_price', function (e, total, total_regular, total_html, $wrap) {
73        let wid = $wrap.attr('data-id'), $total = $('.wpcpo-total[data-product-id="' + wid + '"]');
74
75        $total.attr('data-price', total);
76
77        wpcpo_update_total($total);
78    });
79
80    $(document).on('change keyup', 'form.cart [name=quantity]', function () {
81        let $this = $(this);
82
83        if ($this.closest('.woosb-product').length || $this.closest('.wooco-product').length || $this.closest('.woobt-product').length || $this.closest('.woofs-product').length || $this.closest('.woosg-product').length) {
84            return;
85        }
86
87        wpcpo_update_total($this.closest('form.cart').find('.wpcpo-total'));
88    });
89
90    $(document).on('change input', '.wpcpo-option-field', function () {
91        let $this = $(this), $options = $this.closest('.wpcpo-options');
92
93        if ($this.hasClass('field-select')) {
94            let $wrapper = $this.closest('.form-row'), $option = $this.find(':selected'), label = $option.data('label'),
95                type = $option.data('price-type'), price = $option.data('price'),
96                custom_price = $option.data('price-custom');
97            $wrapper.find('input[name$="label\]"]').attr('value', label);
98            $wrapper.find('input[name$="price_type\]"]').attr('value', type);
99            $wrapper.find('input[name$="price\]"]').attr('value', price);
100            $wrapper.find('input[name$="custom_price\]"]').attr('value', custom_price);
101        } else if ($this.hasClass('field-radio')) {
102            let $wrapper = $this.closest('.form-row'), $option = $wrapper.find(':checked'),
103                label = $option.data('label'), type = $option.data('price-type'),
104                custom_price = $option.data('price-custom'), price = $option.data('price'),
105                image = $option.data('image');
106            $wrapper.find('input[name$="label\]"]').attr('value', label);
107            $wrapper.find('input[name$="image\]"]').attr('value', image);
108            $wrapper.find('input[name$="price_type\]"]').attr('value', t
108ype);
109            $wrapper.find('input[name$="price\]"]').attr('value', price);
110            $wrapper.find('input[name$="custom_price\]"]').attr('value', custom_price);
111        } else if ($this.hasClass('field-dimensions')) {
112            let $dimensions = $this.closest('.wpcpo-option-dimensions'), dimensions = [];
113
114            $dimensions.find('.wpcpo-dimension').each(function () {
115                if ($(this).find('input').val() !== '') {
116                    let dimension = $(this).find('label').text() + ': ' + $(this).find('input').val();
117
118                    dimensions.push(dimension);
119                }
120            });
121
122            if (dimensions.length) {
123                $this.val(dimensions.join('; '));
124            } else {
125                $this.val('');
126            }
127        }
128
129        wpcpo_validate($options);
130        wpcpo_update_total($this.closest('form.cart').find('.wpcpo-total'));
131    });
132
133    $(document).on('blur', '.wpcpo-option-field', function () {
134        let $this = $(this), $options = $this.closest('.wpcpo-options');
135
136        wpcpo_validate($options);
137    });
138
139    $(document).on('change', '.wpcpo-option-field-dimension', function () {
140        let $this = $(this);
141
142        if (parseFloat($this.val()) < parseFloat($this.attr('min'))) {
143            $this.val($this.attr('min'));
144        }
145
146        $this.closest('.wpcpo-option-dimensions').find('.wpcpo-option-field').trigger('change');
147    });
148
149    $(document).on('keyup change', '.wpcpo-option-field', function () {
150        var $field = $(this);
151
152        if ($field.attr('maxlength') > 0) {
153            var value = $field.val();
154            var remaining = $field.attr('maxlength') - value.length;
155
156            $field.next('.wpcpo-chars-remaining').find('span').text(remaining);
157        }
158
159        if (wpcpo_vars.change_url) {
160            // update URL
161            var $options = $field.closest('.wpcpo-options');
162            var $form = $field.closest('form.cart');
163            var link = new URL($form.attr('action'));
164            var search = new URLSearchParams(link.search);
165            var new_link = '';
166
167            $options.find('.wpcpo-option').each(function () {
168                let $option = $(this), option_key = $option.data('key'), option_val = '';
169
170                if ($option.hasClass('wpcpo-option-checkbox') || $option.hasClass('wpcpo-option-image-checkbox') || $option.hasClass('wpcpo-option-color-checkbox')) {
171                    option_val = $.map($option.find(':checkbox:checked'), function (n, i) {
172                        return n.value;
173                    }).join(',');
174                }
175
176                if ($option.hasClass('wpcpo-option-select')) {
177                    option_val = $option.find('select').val();
178                }
179
180                if ($option.hasClass('wpcpo-option-radio') || $option.hasClass('wpcpo-option-image-radio') || $option.hasClass('wpcpo-option-color-radio')) {
181                    option_val = $option.find('input[type="radio"]:checked').length ? $option.find('input[type="radio"]:checked').val() : '';
182                }
183
184                if (option_val.length) {
185                    search.set(option_key, option_val);
186                } else {
187                    search.delete(option_key);
188                }
189            });
190
191            $('input[name="wpcpo_url"]').val(search.toString()).trigger('change');
192
193            if (search.toString() !== '') {
194                new_link = link + '?' + search.toString();
195            } else {
196                new_link = link;
197            }
198
199            window.history.replaceState(null, null, new_link);
200        }
201    });
202
203    $(document).on('click touch', '.wpcpo-clear-btn', function (e) {
204        e.preventDefault();
205
206        $('.wpcpo-option-field').each(function () {
207            $(this).val('').prop('checked', false).prop('selected', false).trigger('blur');
208        });
209
210        wpcpo_init();
211    });
212})(jQuery);
213
214function wpcpo_round(value, decimals) {
215    return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);
216}
217
218function wpcpo_format_money(number, places, symbol, thousand, decimal) {
219    number = number || 0;
220    places = !isNaN((places = Math.abs(places))) ? places : 2;
221    symbol = symbol !== undefined ? symbol : '$';
222    thousand = thousand || ',';
223    decimal = decimal || '.';
224
225    var negative = number < 0 ? '-' : '',
226        i = parseInt((number = wpcpo_round(Math.abs(+number || 0), places).toFixed(places)), 10) + '', j = 0;
227
228    if (i.length > 3) {
229        j = i.length % 3;
230    }
231
232    return (symbol + negative + (j ? i.substr(0, j) + thousand : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousand) + (places ? decimal + wpcpo_round(Math.abs(number - i), places).toFixed(places).slice(2) : ''));
233}
234
235function wpcpo_format_price(price) {
236    var price_html = '<span class="woocommerce-Price-amount amount">';
237    var price_formatted = wpcpo_format_money(price, wpcpo_vars.price_decimals, '', wpcpo_vars.price_thousand_separator, wpcpo_vars.price_decimal_separator);
238
239    switch (wpcpo_vars.price_format) {
240        case '%1$s%2$s':
241            //left
242            price_html += '<span class="woocommerce-Price-currencySymbol">' + wpcpo_vars.currency_symbol + '</span>' + price_formatted;
243            break;
244        case '%1$s %2$s':
245            //left with space
246            price_html += '<span class="woocommerce-Price-currencySymbol">' + wpcpo_vars.currency_symbol + '</span> ' + price_formatted;
247            break;
248        case '%2$s%1$s':
249            //right
250            price_html += price_formatted + '<span class="woocommerce-Price-currencySymbol">' + wpcpo_vars.currency_symbol + '</span>';
251            break;
252        case '%2$s %1$s':
253            //right with space
254            price_html += price_formatted + ' <span class="woocommerce-Price-currencySymbol">' + wpcpo_vars.currency_symbol + '</span>';
255            break;
256        default:
257            //default
258            price_html += '<span class="woocommerce-Price-currencySymbol">' + wpcpo_vars.currency_symbol + '</span> ' + price_formatted;
259    }
260
261    price_html += '</span>';
262
263    return price_html;
264}
265
266function wpcpo_get_custom_price(custom_price, quantity, product_price, value, total = 0) {
267    let length = value.length;
268    let words = wpcpo_words_count(value);
269
270    value = parseFloat(value.replace(/[^\d.]/g, ''));
271
272    custom_price = custom_price.toLowerCase().replace(/([vpqlws])+/gi, function (match, tag, char) {
273        switch (tag) {
274            case 'q':
275                return quantity;
276            case 'p':
277                return product_price;
278            case 'l':
279                return length;
280            case 'w':
281                return words;
282            case 'v':
283                return value === '' ? 1 : value;
284            case 's':
285                return total;
286        }
287    });
288
289    try {
290        custom_price = eval(custom_price.replace(/[^-()\d/*+.]/g, ''));
291    } catch (e) {
292        custom_price = 0;
293    }
294
295    if (isNaN(custom_price) || (custom_price === Infinity) || (custom_price === -Infinity)) {
296        custom_price = 0;
297    }
298
299    return custom_price;
300}
301
302function wpcpo_get_custom_dimensions_price($field, custom_price, quantity, product_price, value, total = 0) {
303    let $dimensions = $field.closest('.wpcpo-option-dimensions');
304
305    custom_price = custom_price.toLowerCase().replace(/([vpqlws])+/gi, function (match, tag, char) {
306        switch (tag) {
307            case 'q':
308                return quantity;
309            case 'p':
310                return product_price;
311            case 's':
312                return total;
313        }
314    });
315
316    custom_price = custom_price.toLowerCase().replace(/d(\d+)/gi, function (match, tag, char) {
317        if ($dimensions.find('.wpcpo-option-field-dimension-d' + tag).length && ($dimensions.find('.wpcpo-option-field-dimension-d' + tag).val() !== '')) {
318            return parseFloat($dimensions.find('.wpcpo-option-field-dimension-d' + tag).val());
319        } else {
320            return 0;
321        }
322    });
323
324    try {
325        custom_price = eval(custom_price.replace(/[^-()\d/*+.]/g, ''));
326    } catch (e) {
327        custom_price = 0;
328    }
329
330    if (isNaN(custom_price) || (custom_price === Infinity) || (custom_price === -Infinity)) {
331        custom_price = 0;
332    }
333
334    return custom_price;
335}
336
337function wpcpo_get_field_price($field, product_price, quantity = 1, total = 0) {
338    let field_price = 0, type = $field.data('price-type'), price = $field.data('price'),
339        custom_price = $field.data('price-custom'), value = $field.val();
340
341    if ($field.hasClass('field-select')) {
342        let $option = $field.find(':selected');
343
344        type = $option.data('price-type');
345        price = $option.data('price');
346        custom_price = $option.data('price-custom');
347    }
348
349    switch (type) {
350        case 'flat':
351            if (isNaN(price)) {
352                field_price = parseFloat(product_price) * parseFloat(price) / 100;
353            } else {
354                field_price = parseFloat(price);
355            }
356
357            break;
358        case 'custom':
359            if ($field.hasClass('field-dimensions')) {
360                field_price = wpcpo_get_custom_dimensions_price($field, custom_price, quantity, product_price, value, total);
361            } else {
362                field_price = wpcpo_get_custom_price(custom_price, quantity, product_price, value, total);
363            }
364
365            break;
366        default:
367            // qty
368            if (isNaN(price)) {
369                field_price = parseFloat(product_price) * parseFloat(price) / 100 * quantity;
370            } else {
371                field_price = parseFloat(price) * quantity;
372            }
373
374            break;
375    }
376
377    return field_price;
378}
379
380function wpcpo_update_total($total) {
381    let qty = parseFloat($total.closest('form.cart').find('[name=quantity]').val()),
382        price = parseFloat($total.attr('data-price')), type = $total.data('type'), name = $total.data('product-name'),
383        total = 0, fields = $total.closest('.wpcpo-wrapper').find('.wpcpo-option-field').get(), html = '',
384        qty_string = wpcpo_vars.is_rtl ? wpcpo_vars.quantity_symbol + qty : qty + wpcpo_vars.quantity_symbol,
385        selected = 0;
386
387    if ($total.attr('data-total') !== undefined) {
388        // Compatible with WPC Price by Quantity
389        total = parseFloat($total.attr('data-total'));
390    } else {
391        total = price * qty;
392    }
393
394    html += '<ul>';
395    html += `<li>
396<div class="wpcpo-col1"><span>${qty_string}</span> ${name}</div>
397<div class="wpcpo-col2"><strong><span class="amount">${wpcpo_format_price(total)}</span></strong></div>
398</li>`;
399
400    for (let field of fields) {
401        let $field = jQuery(field), enable_price = $field.data('enable-price'),
402            $price_label = $field.closest('.wpcpo-option').find('.label-price-' + $field.attr('id')),
403            value = $field.val();
404
405        if ($field.is(':checkbox') || $field.is(':radio')) {
406            if ($field.prop('checked')) {
407                value = $field.data('label');
408            } else {
409                value = '';
410            }
411        }
412
413        if ($field.is('select')) {
414            value = $field.find('option:selected').data('label');
415        }
416
417        $price_label.html(``);
418
419        if (value !== '' && value !== undefined) {
420            if (wpcpo_vars.summary_clear) {
421                selected++;
422            }
423
424            if (enable_price === 1 || wpcpo_vars.summary_free) {
425                let field_price = wpcpo_get_field_price($field, price, qty, total);
426
427                if (!isNaN(field_price)) {
428                    total += parseFloat(field_price);
429                }
430
431                if (!isNaN(field_price) || wpcpo_vars.summary_free) {
432                    if (isNaN(field_price)) {
433                        html += `<li class="wpcpo-free"><div class="wpcpo-col1"><span>${$field.data('title')}:</span> ${value}</div><div class="wpcpo-col2"><strong><span class="amount">${wpcpo_format_price(field_price)}</span></strong></div></li>`;
434                    } else {
435                        if (parseFloat(field_price) > 0) {
436                            $price_label.html(`(+${wpcpo_format_price(field_price)})`);
437                        } else {
438                            $price_label.html(`(${wpcpo_format_price(field_price)})`);
439                        }
440
441                        html += `<li><div class="wpcpo-col1"><span>${$field.data('title')}:</span> ${value}</div><div class="wpcpo-col2"><strong><span class="amount">${wpcpo_format_price(field_price)}</span></strong></div></li>`;
442                    }
443                }
444            }
445        }
446    }
447
448    html += `<li class="wpcpo-subtotal wpcpo-subtotal-${selected}"><span class="wpcpo-clear"><a class="wpcpo-clear-btn" href="javascript:void(0);">${wpcpo_vars.i18n_clear}</a></span><span class="wpcpo-subtotal-amount">${wpcpo_vars.i18n_subtotal}<span class="amount">${wpcpo_format_price(total)}</span></span></li>`;
449    html += '</ul>';
450
451    $total.html(html);
452
453    jQuery(document).trigger('wpcpo_update_total', [$total, total]);
454}
455
456function wpcpo_words_count(str) {
457    return str.split(' ').filter(function (n) {
458        return n != '';
459    }).length;
460}
461
462function wpcpo_validate($options) {
463    let valid = true, $btn = $options.closest('form.cart').find('.single_add_to_cart_button');
464
465    $options.find('.wpcpo-option-field').each(function () {
466        let $this = jQuery(this), $option = $this.closest('.wpcpo-option');
467
468        // Limit Checkbox
469        if ($this.is(':checkbox')) {
470            let $inputsCheck = $option.find('input:checked'), countCheckbox = $inputsCheck.get();
471            if (parseInt($option.data('limit')) > 0) {
472                if (countCheckbox.length >= parseInt($option.data('limit'))) {
473                    $option.find('input:checkbox:not(:checked)').attr('disabled', true);
474                } else {
475                    $option.find('input:checkbox').attr('disabled', false);
476                }
477                if (countCheckbox.length > parseInt($option.data('limit'))) {
478                    $option.addClass('wpcpo-has-error');
479                    valid = false;
480                } else {
481                    $option.removeClass('wpcpo-has-error');
482                }
483            }
484        }
485
486        // Required Checkbox & Radio
487        if ($this.is(':checkbox') || $this.is(':radio')) {
488            let $inputsCheck = $option.find('input:checked'), countCheckbox = $inputsCheck.get();
489            if ($option.hasClass('wpcpo-required')) {
490                if (countCheckbox.length > 0) {
491                    $option.find('.wpcpo-option-field').removeAttr('required');
492                    $option.removeClass('wpcpo-has-error');
493                } else {
494                    $option.find('.wpcpo-option-field').attr('required', 'required');
495                    $option.addClass('wpcpo-has-error');
496                    valid = false;
497                }
498            }
499        }
500
501        // Required Input
502        if ($this.prop('required')) {
503            if ($this.val() === '') {
504                $option.addClass('wpcpo-has-error');
505                valid = false;
506            } else {
507                $option.removeClass('wpcpo-has-error');
508            }
509        }
510    });
511
512    if (!valid) {
513        $btn.addClass('wpcpo-disabled');
514    } else {
515        $btn.removeClass('wpcpo-disabled');
516    }
517
518    jQuery(document).trigger('wpcpo_validate', [$options, valid]);
519}
520
521function wpcpo_init() {
522    if (jQuery('.wpcpo-color-picker').length) {
523        jQuery('.wpcpo-color-picker').wpColorPicker({
524            change: function (e, ui) {
525                setTimeout(function () {
526                    wpcpo_update_total(jQuery(e['target']).closest('.wpcpo-wrapper').find('.wpcpo-total'));
527                }, 100);
528            },
529        });
530    }
531
532    jQuery('.wpcpo-date-picker').each(function () {
533        var format = jQuery(this).attr('data-format');
534        var block = jQuery(this).attr('data-block');
535        var dpk_data = {dateFormat: format};
536
537        if ((block !== undefined) && (block !== '')) {
538            var block_dates = block.split(',');
539
540            if (block_dates.includes('past')) {
541                dpk_data.minDate = new Date();
542            } else {
543                if (block_dates.includes('future')) {
544                    dpk_data.maxDate = new Date();
545                }
546            }
547
548            dpk_data.onRenderCell = function onRenderCell(date, cellType) {
549                if (cellType === 'day') {
550                    const weekday = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
551                    var day_w = weekday[date.getDay()];
552                    var day_f = (('0' + (date.getMonth() + 1)).slice(-2)) + '/' + (('0' + date.getDate()).slice(-2)) + '/' + date.getFullYear();
553                    var isDisabled = block_dates.includes(day_w) || block_dates.includes(day_f);
554
555                    return {
556                        disabled: isDisabled,
557                    };
558                }
559            };
560        }
561
562        jQuery(this).wpcdpk(dpk_data);
563    });
564
565    jQuery('.wpcpo-time-picker').each(function () {
566        var format = jQuery(this).attr('data-format');
567
568        jQuery(this).wpcdpk({
569            timeFormat: format, timepicker: true, onlyTimepicker: true, classes: 'only-time',
570        });
571    });
572
573    jQuery('.wpcpo-date-time-picker').each(function () {
574        var date_format = jQuery(this).attr('data-date_format');
575        var time_format = jQuery(this).attr('data-time_format');
576
577        jQuery(this).wpcdpk({
578            dateFormat: date_format, timeFormat: time_format, timepicker: true,
579        });
580    });
581
582    jQuery('.wpcpo-date-range-picker').each(function () {
583        var format = jQuery(this).attr('data-format');
584
585        jQuery(this).wpcdpk({range: true, dateFormat: format, multipleDatesSeparator: ' - '});
586    });
587
588    jQuery('.wpcpo-option-field').trigger('change');
589
590    jQuery('.wpcpo-option-field').each(function () {
591        if (jQuery(this).attr('maxlength') > 0) {
592            jQuery(this).after('<small class="wpcpo-chars-remaining"><span>' + jQuery(this).attr('maxlength') + '</span> ' + wpcpo_vars.i18n_remaining + '</small>');
593        }
594    });
595
596    jQuery('.wpcpo-options').each(function () {
597        wpcpo_validate(jQuery(this));
598    });
599
600    jQuery('.wpcpo-total').each(function () {
601        wpcpo_update_total(jQuery(this));
602    });
603
604    jQuery(document).trigger('wpcpo_init');
605}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.