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 } else if ($this.hasClass('field-uploads')) { 128 // Show selected file name on mobile/desktop 129 let $fileName = $this.closest('.wpcpo-option').find('.wpcpo-file-name'); 130 if ($fileName.length) { 131 if (this.files && this.files.length > 0) { 132 $fileName.text(this.files[0].name); 133 } else { 134 $fileName.text(''); 135 } 136 } 137 } 138 139 wpcpo_validate($options); 140 wpcpo_update_total($this.closest('form.cart').find('.wpcpo-total')); 141 }); 142 143 $(document).on('blur', '.wpcpo-option-field', function () { 144 let $this = $(this), $options = $this.closest('.wpcpo-options'); 145 146 wpcpo_validate($options); 147 }); 148 149 $(document).on('change', '.wpcpo-option-field-dimension', function () { 150 let $this = $(this); 151 152 if (parseFloat($this.val()) < parseFloat($this.attr('min'))) { 153 $this.val($this.attr('min')); 154 } 155 156 $this.closest('.wpcpo-option-dimensions').find('.wpcpo-option-field').trigger('change'); 157 }); 158 159 $(document).on('keyup change', '.wpcpo-option-field', function () { 160 var $field = $(this); 161 162 if ($field.attr('maxlength') > 0) { 163 var value = $field.val(); 164 var remaining = $field.attr('maxlength') - value.length; 165 166 $field.next('.wpcpo-chars-remaining').find('span').text(remaining); 167 } 168 169 if (wpcpo_vars.change_url) { 170 // update URL 171 var $options = $field.closest('.wpcpo-options'); 172 var $form = $field.closest('form.cart'); 173 var link = new URL($form.attr('action')); 174 var search = new URLSearchParams(link.search); 175 var new_link = ''; 176 177 $options.find('.wpcpo-option').each(function () { 178 let $option = $(this), option_key = $option.data('key'), option_val = ''; 179 180 if ($option.hasClass('wpcpo-option-checkbox') || $option.hasClass('wpcpo-option-image-checkbox') || $option.hasClass('wpcpo-option-color-checkbox')) { 181 option_val = $.map($option.find(':checkbox:checked'), function (n, i) { 182 return n.value; 183 }).join(','); 184 } 185 186 if ($option.hasClass('wpcpo-option-select')) { 187 option_val = $option.find('select').val(); 188 } 189 190 if ($option.hasClass('wpcpo-option-radio') || $option.hasClass('wpcpo-option-image-radio') || $option.hasClass('wpcpo-option-color-radio')) { 191 option_val = $option.find('input[type="radio"]:checked').length ? $option.find('input[type="radio"]:checked').val() : ''; 192 } 193 194 if (option_val.length) { 195 search.set(option_key, option_val); 196 } else { 197 search.delete(option_key); 198 } 199 }); 200 201 $('input[name="wpcpo_url"]').val(search.toString()).trigger('change'); 202 203 if (search.toString() !== '') { 204 new_link = link + '?' + search.toString(); 205 } else { 206 new_link = link; 207 } 208 209 window.history.replaceState(null, null, new_link); 210 } 211 }); 212 213 $(document).on('click touch', '.wpcpo-clear-btn', function (e) { 214 e.preventDefault(); 215 216 $('.wpcpo-option-field').each(function () { 217 $(this).val('').prop('checked', false).prop('selected', false).trigger('blur'); 218 }); 219 220 wpcpo_init(); 221 }); 222})(jQuery); 223 224function wpcpo_round(value, decimals) { 225 return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals); 226} 227 228function wpcpo_format_money(number, places, symbol, thousand, decimal) { 229 number = number || 0; 230 places = !isNaN((places = Math.abs(places))) ? places : 2; 231 symbol = symbol !== undefined ? symbol : '$'; 232 thousand = thousand || ','; 233 decimal = decimal || '.'; 234 235 var negative = number < 0 ? '-' : '', 236 i = parseInt((number = wpcpo_round(Math.abs(+number || 0), places).toFixed(places)), 10) + '', j = 0; 237 238 if (i.length > 3) { 239 j = i.length % 3; 240 } 241 242 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) : '')); 243} 244 245function wpcpo_format_price(price) { 246 var price_html = '<span class="woocommerce-Price-amount amount">'; 247 var price_formatted = wpcpo_format_money(price, wpcpo_vars.price_decimals, '', wpcpo_vars.price_thousand_separator, wpcpo_vars.price_decimal_separator); 248 249 switch (wpcpo_vars.price_format) { 250 case '%1$s%2$s': 251 //left 252 price_html += '<span class="woocommerce-Price-currencySymbol">' + wpcpo_vars.currency_symbol + '</span>' + price_formatted; 253 break; 254 case '%1$s %2$s': 255 //left with space 256 price_html += '<span class="woocommerce-Price-currencySymbol">' + wpcpo_vars.currency_symbol + '</span> ' + price_formatted; 257 break; 258 case '%2$s%1$s': 259 //right 260 price_html += price_formatted + '<span class="woocommerce-Price-currencySymbol">' + wpcpo_vars.currency_symbol + '</span>'; 261 break; 262 case '%2$s %1$s': 263 //right with space 264 price_html += price_formatted + ' <span class="woocommerce-Price-currencySymbol">' + wpcpo_vars.currency_symbol + '</span>'; 265 break; 266 default: 267 //default 268 price_html += '<span class="woocommerce-Price-currencySymbol">' + wpcpo_vars.currency_symbol + '</span> ' + price_formatted; 269 } 270 271 price_html += '</span>'; 272 273 return price_html; 274} 275 276function wpcpo_get_custom_price(custom_price, quantity, product_price, value, total = 0) { 277 let length = value.length; 278 let words = wpcpo_words_count(value); 279 280 value = parseFloat(value.replace(/[^\d.]/g, '')); 281 282 custom_price = custom_price.toLowerCase().replace(/([vpqlws])+/gi, function (match, tag, char) { 283 switch (tag) { 284 case 'q': 285 return quantity; 286 case 'p': 287 return product_price; 288 case 'l': 289 return length; 290 case 'w': 291 return words; 292 case 'v': 293 return value === '' ? 1 : value; 294 case 's': 295 return total; 296 } 297 }); 298 299 try {
300 custom_price = eval(custom_price.replace(/[^-()\d/*+.]/g, '')); 301 } catch (e) { 302 custom_price = 0; 303 } 304 305 if (isNaN(custom_price) || (custom_price === Infinity) || (custom_price === -Infinity)) { 306 custom_price = 0; 307 } 308 309 return custom_price; 310} 311 312function wpcpo_get_custom_dimensions_price($field, custom_price, quantity, product_price, value, total = 0) { 313 let $dimensions = $field.closest('.wpcpo-option-dimensions'); 314 315 custom_price = custom_price.toLowerCase().replace(/([vpqlws])+/gi, function (match, tag, char) { 316 switch (tag) { 317 case 'q': 318 return quantity; 319 case 'p': 320 return product_price; 321 case 's': 322 return total; 323 } 324 }); 325 326 custom_price = custom_price.toLowerCase().replace(/d(\d+)/gi, function (match, tag, char) { 327 if ($dimensions.find('.wpcpo-option-field-dimension-d' + tag).length && ($dimensions.find('.wpcpo-option-field-dimension-d' + tag).val() !== '')) { 328 return parseFloat($dimensions.find('.wpcpo-option-field-dimension-d' + tag).val()); 329 } else { 330 return 0; 331 } 332 }); 333 334 try { 335 custom_price = eval(custom_price.replace(/[^-()\d/*+.]/g, '')); 336 } catch (e) { 337 custom_price = 0; 338 } 339 340 if (isNaN(custom_price) || (custom_price === Infinity) || (custom_price === -Infinity)) { 341 custom_price = 0; 342 } 343 344 return custom_price; 345} 346 347function wpcpo_get_field_price($field, product_price, quantity = 1, total = 0) { 348 let field_price = 0, type = $field.data('price-type'), price = $field.data('price'), 349 custom_price = $field.data('price-custom'), value = $field.val(); 350 351 if ($field.hasClass('field-select')) { 352 let $option = $field.find(':selected'); 353 354 type = $option.data('price-type'); 355 price = $option.data('price'); 356 custom_price = $option.data('price-custom'); 357 } 358 359 switch (type) { 360 case 'flat': 361 if (isNaN(price)) { 362 field_price = parseFloat(product_price) * parseFloat(price) / 100; 363 } else { 364 field_price = parseFloat(price); 365 } 366 367 break; 368 case 'custom': 369 if ($field.hasClass('field-dimensions')) { 370 field_price = wpcpo_get_custom_dimensions_price($field, custom_price, quantity, product_price, value, total); 371 } else { 372 field_price = wpcpo_get_custom_price(custom_price, quantity, product_price, value, total); 373 } 374 375 break; 376 default: 377 // qty 378 if (isNaN(price)) { 379 field_price = parseFloat(product_price) * parseFloat(price) / 100 * quantity; 380 } else { 381 field_price = parseFloat(price) * quantity; 382 } 383 384 break; 385 } 386 387 return field_price; 388} 389 390function wpcpo_update_total($total) { 391 let qty = parseFloat($total.closest('form.cart').find('[name=quantity]').val()), 392 price = parseFloat($total.attr('data-price')), type = $total.data('type'), name = $total.data('product-name'), 393 total = 0, fields = $total.closest('.wpcpo-wrapper').find('.wpcpo-option-field').get(), html = '', 394 qty_string = wpcpo_vars.is_rtl ? wpcpo_vars.quantity_symbol + qty : qty + wpcpo_vars.quantity_symbol, 395 selected = 0; 396 397 if ($total.attr('data-total') !== undefined) { 398 // Compatible with WPC Price by Quantity 399 total = parseFloat($total.attr('data-total')); 400 } else { 401 total = price * qty; 402 } 403 404 html += '<ul>'; 405 html += `<li> 406<div class="wpcpo-col1"><span>${qty_string}</span> ${name}</div> 407<div class="wpcpo-col2"><strong><span class="amount">${wpcpo_format_price(total)}</span></strong></div> 408</li>`; 409 410 for (let field of fields) { 411 let $field = jQuery(field), enable_price = $field.data('enable-price'), 412 $price_label = $field.closest('.wpcpo-option').find('.label-price-' + $field.attr('id')), 413 value = $field.val(); 414 415 if ($field.is(':checkbox') || $field.is(':radio')) { 416 if ($field.prop('checked')) { 417 value = $field.data('label'); 418 } else { 419 value = ''; 420 } 421 } 422 423 if ($field.is('select')) { 424 value = $field.find('option:selected').data('label'); 425 } 426 427 $price_label.html(``); 428 429 if (value !== '' && value !== undefined) { 430 if (wpcpo_vars.summary_clear) { 431 selected++; 432 } 433 434 if (enable_price === 1 || wpcpo_vars.summary_free) { 435 let field_price = wpcpo_get_field_price($field, price, qty, total); 436 437 if (!isNaN(field_price)) { 438 total += parseFloat(field_price); 439 } 440 441 if (!isNaN(field_price) || wpcpo_vars.summary_free) { 442 if (isNaN(field_price)) { 443 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>`; 444 } else { 445 if (parseFloat(field_price) > 0) { 446 $price_label.html(`(+${wpcpo_format_price(field_price)})`); 447 } else { 448 $price_label.html(`(${wpcpo_format_price(field_price)})`); 449 } 450 451 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>`; 452 } 453 } 454 } 455 } 456 } 457 458 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>`; 459 html += '</ul>'; 460 461 $total.html(html); 462 463 jQuery(document).trigger('wpcpo_update_total', [$total, total]); 464} 465 466function wpcpo_words_count(str) { 467 return str.split(' ').filter(function (n) { 468 return n != ''; 469 }).length; 470} 471 472function wpcpo_validate($options) { 473 let valid = true, $btn = $options.closest('form.cart').find('.single_add_to_cart_button'); 474 475 $options.find('.wpcpo-option-field').each(function () {
476 let $this = jQuery(this), $option = $this.closest('.wpcpo-option'); 477 478 // Skip validation for options hidden by conditional logic 479 if ($option.data('wpcpo-hidden') === true) { 480 $option.removeClass('wpcpo-has-error'); 481 $option.find('.wpcpo-option-field').removeAttr('required'); 482 return; 483 } 484 485 // Limit Checkbox 486 if ($this.is(':checkbox')) { 487 let $inputsCheck = $option.find('input:checked'), countCheckbox = $inputsCheck.get(); 488 if (parseInt($option.data('limit')) > 0) { 489 if (countCheckbox.length >= parseInt($option.data('limit'))) { 490 $option.find('input:checkbox:not(:checked)').attr('disabled', true); 491 } else { 492 $option.find('input:checkbox').attr('disabled', false); 493 } 494 if (countCheckbox.length > parseInt($option.data('limit'))) { 495 $option.addClass('wpcpo-has-error'); 496 valid = false; 497 } else { 498 $option.removeClass('wpcpo-has-error'); 499 } 500 } 501 } 502 503 // Required Checkbox & Radio 504 // Note: do NOT use the `required` attribute on checkbox/radio inputs â 505 // image-checkbox and color-checkbox inputs are visually hidden via CSS 506 // and cannot be focused by browser native validation ("not focusable" error). 507 // Validation is handled entirely via wpcpo-has-error class + disabled button. 508 if ($this.is(':checkbox') || $this.is(':radio')) { 509 let $inputsCheck = $option.find('input:checked'), countCheckbox = $inputsCheck.get(); 510 if ($option.hasClass('wpcpo-required')) { 511 if (countCheckbox.length > 0) { 512 $option.removeClass('wpcpo-has-error'); 513 } else { 514 $option.addClass('wpcpo-has-error'); 515 valid = false; 516 } 517 } 518 } 519 520 // Required Input 521 if ($this.prop('required')) { 522 if ($this.val() === '') { 523 $option.addClass('wpcpo-has-error'); 524 valid = false; 525 } else { 526 $option.removeClass('wpcpo-has-error'); 527 } 528 } 529 }); 530 531 if (!valid) { 532 $btn.addClass('wpcpo-disabled'); 533 } else { 534 $btn.removeClass('wpcpo-disabled'); 535 } 536 537 jQuery(document).trigger('wpcpo_validate', [$options, valid]); 538} 539 540function wpcpo_init() { 541 if (jQuery('.wpcpo-color-picker').length) { 542 jQuery('.wpcpo-color-picker').wpColorPicker({ 543 change: function (e, ui) { 544 setTimeout(function () { 545 wpcpo_update_total(jQuery(e['target']).closest('.wpcpo-wrapper').find('.wpcpo-total')); 546 }, 100); 547 }, 548 }); 549 } 550 551 jQuery('.wpcpo-date-picker').each(function () { 552 var format = jQuery(this).attr('data-format'); 553 var block = jQuery(this).attr('data-block'); 554 var dpk_data = {dateFormat: format}; 555 556 if ((block !== undefined) && (block !== '')) { 557 var block_dates = block.split(','); 558 559 if (block_dates.includes('past')) { 560 dpk_data.minDate = new Date(); 561 } else { 562 if (block_dates.includes('future')) { 563 dpk_data.maxDate = new Date(); 564 } 565 } 566 567 dpk_data.onRenderCell = function onRenderCell(date, cellType) { 568 if (cellType === 'day') { 569 const weekday = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday']; 570 var day_w = weekday[date.getDay()]; 571 var day_f = (('0' + (date.getMonth() + 1)).slice(-2)) + '/' + (('0' + date.getDate()).slice(-2)) + '/' + date.getFullYear(); 572 var isDisabled = block_dates.includes(day_w) || block_dates.includes(day_f); 573 574 return { 575 disabled: isDisabled, 576 }; 577 } 578 }; 579 } 580 581 jQuery(this).wpcdpk(dpk_data); 582 }); 583 584 jQuery('.wpcpo-time-picker').each(function () { 585 var format = jQuery(this).attr('data-format'); 586 587 jQuery(this).wpcdpk({ 588 timeFormat: format, timepicker: true, onlyTimepicker: true, classes: 'only-time', 589 }); 590 }); 591 592 jQuery('.wpcpo-date-time-picker').each(function () { 593 var date_format = jQuery(this).attr('data-date_format'); 594 var time_format = jQuery(this).attr('data-time_format'); 595 596 jQuery(this).wpcdpk({ 597 dateFormat: date_format, timeFormat: time_format, timepicker: true, 598 }); 599 }); 600 601 jQuery('.wpcpo-date-range-picker').each(function () { 602 var format = jQuery(this).attr('data-format'); 603 604 jQuery(this).wpcdpk({range: true, dateFormat: format, multipleDatesSeparator: ' - '}); 605 }); 606 607 jQuery('.wpcpo-option-field').trigger('change'); 608 609 jQuery('.wpcpo-option-field').each(function () { 610 if (jQuery(this).attr('maxlength') > 0) { 611 jQuery(this).after('<small class="wpcpo-chars-remaining"><span>' + jQuery(this).attr('maxlength') + '</span> ' + wpcpo_vars.i18n_remaining + '</small>'); 612 } 613 }); 614 615 jQuery('.wpcpo-options').each(function () { 616 wpcpo_validate(jQuery(this)); 617 }); 618 619 jQuery('.wpcpo-total').each(function () { 620 wpcpo_update_total(jQuery(this)); 621 }); 622 623 jQuery(document).trigger('wpcpo_init'); 624}
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.