1/** 2 * Paytium Public JS 3 * 4 * @package PT 5 * @author David de Boer <[email protected]> 6 */ 7 8/* global jQuery, pt_script */ 9 10(function ($) { 11 'use strict'; 12 13 var currencySymbol = pt.currency_symbol; 14 15 function debug_log( message ) { 16 if ( pt.debug == true ) { 17 console.log( message ); 18 } 19 } 20 21 function initializePaytiumForm(ptForm) { 22 // Check if already initialized using data (which is not copied on simple clone) 23 // We do not rely on the class 'pt-form-initialized' because Elementor might clone the HTML including the class, 24 // but without the events/data. 25 if (ptForm.data('pt-initialized')) { 26 return; 27 } 28 ptForm.data('pt-initialized', true); 29 ptForm.addClass('pt-form-initialized'); 30 31 var ptFormCurrencySymbol = ptForm.data('currency') && getCurrencySymbol(ptForm.data('currency')) !== undefined ? 32 getCurrencySymbol(ptForm.data('currency')) : currencySymbol, 33 ptFormQtyDiscount = ptForm.find('input.pt-quantity-discount'), 34 ptFormQtyDiscountData = ptFormQtyDiscount.data('quantity-discount') ? ptFormQtyDiscount.data('quantity-discount') : false, 35 ptFormCurrentQtyDiscount = 0, 36 ptFormCurrentQty = 0, 37 ptFormAmountDiscount = ptForm.find('input.pt-amount-discount'), 38 ptFormAmountDiscountData = ptFormAmountDiscount.data('amount-discount') ? ptFormAmountDiscount.data('amount-discount') : false, 39 ptFormCurrentAmountDiscount = 0, 40 ptFormCurrentAmount = 0, 41 ptFormGeneralLimit = ptForm.find('.pt-general-items-left').data('general-items-left'), 42 ptFormAmounts = [], 43 ptFormFb = ptForm.hasClass('pt-fb-form'); 44 45 ptForm.find(".pt-cf-amount").each(function () { 46 if ($(this).is('select')) { 47 $($(this).children('option')).each(function () { 48 ptFormAmounts.push($(this).attr('data-pt-price')); 49 }) 50 } 51 else { 52 ptFormAmounts.push($(this).attr('data-pt-price')); 53 } 54 }); 55 56 // Add field that allows Paytium processing to know that JS was enabled on form 57 if (ptForm.find('input[name="pt-paytium-js-enabled"]').length === 0) { 58 $("<input>", {type: "hidden", name: 'pt-paytium-js-enabled', value: 1}).appendTo(ptForm); 59 } 60 61 // Enable form button with javascript, so it doesn't show to users that don't have JS enabled 62 ptForm.find('.pt-payment-btn') 63 .show(); 64 65 // 66 // START - Paytium No Payment 67 // 68 69 function isPaytiumNoPayment() { 70 71 var noPaymentFound = false; 72 73 ptForm.find("[id^=pt-paytium-no-payment]").each(function () { 74 noPaymentFound = true; 75 }); 76 77 return noPaymentFound; 78 } 79 80 // 81 // END - Paytium No Payment 82 // 83 84 // 85 // START - Show a warning about prefilled fields 86 // 87 88 ptForm.find(".pt-field-prefill-warning-hint").click(function () { 89 var ptPrefillWarningCounter = $(this).attr('data-pt-prefill-warning-counter'); 90 ptForm.find("#pt-prefill-warning-counter-" + ptPrefillWarningCounter).toggle("slow"); 91 }); 92 93 // 94 // END - Show a warning about prefilled fields 95 // 96 97 // 98 // START - Enable/disable discount apply button depending on input 99 // 100 101 ptForm.find('.pt-discount').on('keyup', function (event) { 102 var nameInput = ptForm.find('.pt-discount').val(); 103 if (nameInput.length > 0) { 104 ptForm.find('.pt-discount-button').prop('disabled', false); 105 } else { 106 ptForm.find('.pt-discount-button').prop('disabled', true); 107 } 108 }); 109 110 ptForm.find('.pt-discount-button').on('click.ptDiscountFieldButton', function (event) { 111 112 event.preventDefault(); 113 114 var formLoadID = ptForm.find('[name="pt-form-load"]').val(), 115 discountCode = ptForm.find('.pt-discount').val(), 116 associateWithEmail = false, 117 email = ''; 118 119 if ($(this).siblings('#pt-discount-associate-with-email').length) { 120 associateWithEmail = true; 121 email = $(this).parents('.pt-form-group-field-discount').siblings('.pt-form-group-field-email').children('input[type="email"]').val(); 122 } 123 124 var noEmailError = associateWithEmail && !email; 125 126 if (discountCode && formLoadID) { 127 128 $.ajax({ 129 url: paytium_localize_script_vars.admin_ajax_url, 130 type: 'POST', 131 dataType: 'json', 132 data: { 133 'action': "pt_ajax_check_discount_codes", 134 'data': {'formLoadID': formLoadID, 'discountCode': discountCode, 'email': email} 135 }, 136 success: function (response) { 137 138 if (response.status && !noEmailError) { 139 140 // Show success message after user applies valid discount code 141 ptForm.find('.pt-discount-true').show(); 142 ptForm.find('.pt-discount-false').hide(); 143 ptForm.find('.pt-discount-used').hide(); 144 145 // Remove discount fields if they are already added 146 ptForm.find(".pt-discount-type").remove(); 147 ptForm.find(".pt-discount-value").remove(); 148 ptForm.find(".pt-discount-times").remove(); 149 150 // If discount is valid, add discount fields to the form 151 $("<input>", { 152 type: "hidden", 153 name: 'pt-discount[type]', 154 class: 'pt-discount-type', 155 value: response.type 156 }).appendTo(ptForm); 157 $("<input>", { 158 type: "hidden", 159 name: 'pt-discount[value]', 160 class: 'pt-discount-value', 161 value: response.value 162 }).appendTo(ptForm); 163 $("<input>", { 164 type: "hidden", 165 name: 'pt-discount[times]', 166 class: 'pt-discount-times', 167 value: response.times 168 }).appendTo(ptForm); 169 170 171 } else { 172 173 // Show error message after user applies incorrect discount code 174 ptForm.find('.pt-discount-true').hide(); 175 if (response.used) { 176 ptForm.find('.pt-discount-email-error').hide(); 177 ptForm.find('.pt-discount-false').hide(); 178 ptForm.find('.pt-discount-used').show(); // discount feature 179 } 180 else if (noEmailError) { 181 ptForm.find('.pt-discount-used').hide(); 182 ptForm.find('.pt-discount-false').hide(); 183 ptForm.find('.pt-discount-email-error').show(); 184 } 185 else { 186 ptForm.find('.pt-discount-email-error').hide(); 187 ptForm.find('.pt-discount-used').hide(); 188 ptForm.find('.pt-discount-false').show(); 189 } 190 191 // Empty discount field and disable apply button, so user can try again 192 ptForm.find('.pt-discount').val(''); 193 ptForm.find('.pt-discount-button').prop('disabled', true); 194 195 // Remove discount fields if they are already added 196 ptForm.find(".pt-discount-type").remove(); // Don't use parseAmount for this one! 197 ptForm.find(".pt-discount-value").remove(); // Don't use parseAmount for this one! 198 ptForm.find(".pt-discount-times").remove(); // Don't use parseAmount for this one! 199 200 } 201 202 update_totals(); 203 204 }, 205 }); 206 } 207 }); 208 209 // 210 // END - Enable/disable discount apply button depending on input 211 // 212 213 // 214 // START - Add subscription first payment to [paytium_total /] shortcode 215 // 216 217 // If there is a subscription first payment, adjust form to allow that 218 if (ptForm.find("[id^=pt-subscription-first-payment]").length > 0) { 219 // Add "First payment" text and amount after the [paytium_total /] Shortcode 220 var ptFirstPayment = ptForm.find("[id^=pt-subscription-first-payment]").val(); 221 var ptFirstPaymentLabel = ptForm.find("[id^=pt-subscription-first-payment-label]").val(); 222 223 // If user set a First Payment Label, override the default translation with that 224 if (!ptFirstPaymentLabel) { 225 ptFirstPaymentLabel = paytium_localize_script_vars.subscription_first_payment; 226 } 227 228 if (ptForm.find('.pt-first-payment-amount').length === 0) { 229 ptForm.find('.pt-total-amount').after('<div class="pt-first-payment-amount">' + ptFirstPaymentLabel + ': ' + currencyFormattedAmount(ptFirstPayment, ptFormCurrencySymbol) + '</div>'); 230 } 231 } 232 233 // 234 // END - Add subscription first payment to [paytium_total /] shortcode 235 // 236 237 // 238 // START - Subscription interval options and optional on page load 239 // 240 241 // Uncheck subscription interval options on page load, especially for back button 242 ptForm.find('input[name="pt-subscription-interval-options"]:checked').each(function () { 243 $('input[name="pt-subscription-interval-options"]').prop('checked', false); 244 }); 245 246 // Make sure Yes is checked for subscription optional on page load, especially for back button 247 ptForm.find('input[name="pt-subscription-optional"]:checked').each(function () { 248 $('input[name="pt-subscription-optional"]:first').attr('checked', true); 249 }); 250 251 // 252 // END - Subscription interval options and optional on page load 253 // 254 255 // 256 // START - Add option amount labels to field label 257 // Add option amount labels for dropdown/radio to field label, so users can see what customers selected 258 // 259 260 // Checkbox with amounts, get all already checked checkboxes and process amounts and labels 261 ptForm.find('input[type=checkbox]:checked').filter('.pt-cf-amount').each(function () { 262 263 // 264 // Update amount 265 // 266 267 // Get id/name for checkbox form group amount
268 var ptCheckboxFormGroupAmountId = $(this).attr('name').replace('[amount]', '[amount][total]'); 269 270 // Get selected value 271 var ptCheckboxFieldValue = $(this).val(); 272 273 // Get total amount for this checkbox group 274 var ptCheckboxTotalValue = ptForm.find("[id='" + ptCheckboxFormGroupAmountId + "']").val(); 275 276 // Add selected value to total amount (don't remove those +'s) 277 var ptCheckboxNewTotalValue = +ptCheckboxTotalValue + +ptCheckboxFieldValue; 278 279 // Update the total value in value attribute 280 ptForm.find("[id='" + ptCheckboxFormGroupAmountId + "']").attr('value', parseAmount(ptCheckboxNewTotalValue)); 281 282 // Update total value in pt-price data attribute 283 ptForm.find("[id='" + ptCheckboxFormGroupAmountId + "']").attr('data-pt-price', parseAmount(ptCheckboxNewTotalValue)); 284 285 // 286 // Update label 287 // 288 289 // Get/convert checkbox group label ID 290 var ptCheckboxFormGroupLabelId = $(this).attr('name').replace('[amount]', '[label]'); 291 292 var ptCheckboxFormValue = $(this).attr('name').replace('[amount]', '[value]'); 293 294 // Get previously checked options 295 var ptCheckboxCurrentOptions = ptForm.find("[name='" + ptCheckboxFormGroupLabelId + "']").attr('data-pt-checked-options'); 296 297 ptCheckboxCurrentOptions = JSON.parse(ptCheckboxCurrentOptions); 298 299 // If previously checked options are not an array, this means it's empty 300 if (Object.keys(ptCheckboxCurrentOptions).length === 0) { 301 ptCheckboxCurrentOptions = {}; 302 } 303 304 ptCheckboxCurrentOptions[$(this).attr('data-pt-checkbox-id')] = $(this).parent().text(); 305 306 // Start string with current group label 307 var ptCheckboxCurrentOptionsString = ptForm.find("[name='" + ptCheckboxFormGroupLabelId + "']").attr('data-pt-original-label'); 308 309 // Convert current options to a string for HTML hidden field 310 311 var ptCheckboxFormValueString = ''; 312 for (var key in ptCheckboxCurrentOptions) { 313 ptCheckboxFormValueString += ptCheckboxFormValueString == '' ? ptCheckboxCurrentOptions[key] : ', ' + ptCheckboxCurrentOptions[key]; 314 } 315 316 // Convert to a format that is save for HTML fields 317 ptCheckboxCurrentOptions = JSON.stringify(ptCheckboxCurrentOptions); 318
319 // Add updated options to data-pt-checked-options attribute 320 ptForm.find("[name='" + ptCheckboxFormGroupLabelId + "']").attr('data-pt-checked-options', ptCheckboxCurrentOptions); 321 322 // Add current options string to hidden HTML field 323 ptForm.find("[name='" + ptCheckboxFormGroupLabelId + "']").attr('value', ptCheckboxCurrentOptionsString); 324 ptForm.find("[name='" + ptCheckboxFormValue + "']").attr('value', ptCheckboxFormValueString); 325 326 }); 327 328 // Radio amounts, try to get first option in radio buttons to use as default if an option is not selected yet 329 ptForm.find('input[type=radio]:checked').filter('.pt-cf-amount').each(function () { 330 331 var ptRadioCustomOption = $(this).parent().text(); 332 333 var ptRadioFormGroupId = $(this).attr('name').replace('[amount]', '[label]'); 334 335 var ptRadioFormValue = $(this).attr('name').replace('[amount]', '[value]'); 336 337 var ptRadioFormOptionId = $(this).attr('name').replace('[amount]', '[item_id]'); 338 339 var ptRadioFormOptionLimit = $(this).attr('name').replace('[amount]', '[limit]'); 340 341 var ptRadioOptionData = $(this).data(); 342 343 var ptRadioFormGroupLabel = ptForm.find("[name='" + ptRadioFormGroupId + "']").attr('data-pt-original-label'); 344 345 ptForm.find("[name='" + ptRadioFormValue + "']").val(function () { 346 return ptRadioCustomOption; 347 }); 348 349 ptForm.find("[name='" + ptRadioFormOptionId + "']").val(ptRadioOptionData.item_id); 350 ptForm.find("[name='" + ptRadioFormOptionLimit + "']").val(ptRadioOptionData.limit); 351 352 if ($(this).data('general_item_id')) { 353 354 var ptRadioFormOptionGeneralId = $(this).attr('name').replace('[amount]', '[general_item_id]'), 355 ptRadioFormOptionGeneralLimit = $(this).attr('name').replace('[amount]', '[general_limit]'); 356 357 ptForm.find("[name='" + ptRadioFormOptionGeneralId + "']").val(ptRadioOptionData.general_item_id); 358 ptForm.find("[name='" + ptRadioFormOptionGeneralLimit + "']").val(ptRadioOptionData.general_limit); 359 } 360 }); 361 362 // Dropdown amounts, try to get first option in Dropdown to use as default if an option is not selected yet 363 ptForm.find('select.pt-cf-amount').each(function () { 364 365 var ptDropdownCustomOption = $(this).find(':selected').text(); 366 367 var ptDropdownFormGroupId = $(this).attr('name').replace('[amount]', '[label]'); 368 369 var ptDropdownFormValue = $(this).attr('name').replace('[amount]', '[value]'); 370 371 ptForm.find("[name='" + ptDropdownFormValue + "']").val(function () { 372 return ptDropdownCustomOption; 373 }); 374 }); 375 376 // Get selected option for radio and dropdown amounts, when user selects them 377 ptForm.find('.pt-cf-amount').on('change', function () { 378 379 // Process radio buttons amount labels 380 if ($(this).is('input[type="radio"]')) { 381 382 var ptRadioCustomOption = $(this).parent().text(); 383 384 var ptRadioFormGroupId = $(this).attr('name').replace('[amount]', '[label]'); 385 386 var ptRadioFormValue = $(this).attr('name').replace('[amount]', '[value]'); 387 388 var ptRadioFormOptionId = $(this).attr('name').replace('[amount]', '[item_id]'); 389 390 var ptRadioFormOptionLimit = $(this).attr('name').replace('[amount]', '[limit]'); 391 392 var ptRadioOptionData = $(this).data(); 393 394 ptForm.find("[name='" + ptRadioFormValue + "']").val(function () { 395 return ptRadioCustomOption; 396 }); 397 398 ptForm.find("[name='" + ptRadioFormOptionId + "']").val(ptRadioOptionData.item_id); 399 ptForm.find("[name='" + ptRadioFormOptionLimit + "']").val(ptRadioOptionData.limit); 400 401 if ($(this).data('general_item_id')) { 402 403 var ptRadioFormOptionGeneralId = $(this).attr('name').replace('[amount]', '[general_item_id]'), 404 ptRadioFormOptionGeneralLimit = $(this).attr('name').replace('[amount]', '[general_limit]'); 405 406 ptForm.find("[name='" + ptRadioFormOptionGeneralId + "']").val(ptRadioOptionData.general_item_id); 407 ptForm.find("[name='" + ptRadioFormOptionGeneralLimit + "']").val(ptRadioOptionData.general_limit); 408 } 409 410 } 411 412 // Process dropdown amount labels 413 if ($(this).is('select')) { 414 415 var ptDropdownCustomOption = $(this).find(':selected').text(); 416 417 var ptDropdownFormGroupId = $(this).attr('name').replace('[amount]', '[label]'); 418 419 var ptDropdownFormValue = $(this).attr('name').replace('[amount]', '[value]'); 420 421 var ptDropdownFormOptionId = $(this).attr('name').replace('[amount]', '[item_id]'); 422 423 var ptDropdownFormOptionLimit = $(this).attr('name').replace('[amount]', '[limit]'); 424 425 var ptDropdownOptionData = $(this).find(':selected').data(); 426 427 ptForm.find("[name='" + ptDropdownFormValue + "']").val(function () { 428 return ptDropdownCustomOption; 429 }); 430 ptForm.find("[name='" + ptDropdownFormOptionId + "']").val(ptDropdownOptionData.item_id); 431 ptForm.find("[name='" + ptDropdownFormOptionLimit + "']").val(ptDropdownOptionData.limit); 432 433 if ($(this).find(':selected').data('general_item_id')) { 434 435 var ptDropdownFormOptionGeneralId = $(this).attr('name').replace('[amount]', '[general_item_id]'), 436 ptDropdownFormOptionGeneralLimit = $(this).attr('name').replace('[amount]', '[general_limit]'); 437 438 ptForm.find("[name='" + ptDropdownFormOptionGeneralId + "']").val(ptDropdownOptionData.general_item_id); 439 ptForm.find("[name='" + ptDropdownFormOptionGeneralLimit + "']").val(ptDropdownOptionData.general_limit); 440 } 441 442 } 443 444 }); 445 446 // 447 // END - Option label to field label 448 // 449 450 // 451 // START - Update total when a paid field changes 452 // 453 454 ptForm.find( '.pt-uea-custom-amount' ).on('keyup change', update_totals ); 455 ptForm.find( ':checkbox' ).change(update_checkbox_field); 456 ptForm.find( '.pt-cf-amount' ).on( 'change', update_totals ); 457 458 ptForm.find( '.pt-quantity-input' ).on( 'keyup mouseup change', function (e) { 459 let general_limit_control_result = general_limit_control($(this)); 460 if (general_limit_control_result !== undefined && !general_limit_control_result.result) { 461 $(this).val(general_limit_control_result.new_val); 462 alert(ptForm.find('.pt-general-items-left').text()); 463 } 464 update_totals(e); 465 } ); 466 467 ptForm.find( '.pt-paid-field' ).on( 'input', update_totals ); 468 469 ptForm.find( ':radio[name=pt-subscription-interval-options]' ).change(subscription_interval); 470 ptForm.find( ':radio[name=pt-subscription-optional]' ).change(subscription_optional); 471 472 473 // 474 // END - Update total when user enters amount (custom amount) 475 // 476 477 // 478 // START - UEA, Update individual open amounts (uea) 479 // 480 481 ptForm.find("input[id^=pt_uea_custom_amount_]").on('keyup change', update_open_field); 482 483 function update_open_field(i, element) { 484 485 var ptUEAFieldName = $(this).attr("name"); 486 var ptUEAFieldID = $(this).attr("id"); 487 var ptUEAFieldValue = $(this).val(); 488 489 ptForm.find("[id^=" + ptUEAFieldID + "]").val(parseAmount(ptUEAFieldValue)); 490 ptForm.find("[name*='" + ptUEAFieldName + "']").val(ptUEAFieldValue); // Don't use parseAmount for this one! 491 ptForm.find("[name*='" + ptUEAFieldName + "']").attr('data-pt-price', parseAmount(ptUEAFieldValue)); 492 $(this).parent().siblings('.pt-uea-custom-amount-formatted').val(parseAmount(ptUEAFieldValue)); 493 } 494 495 // 496 // END - UEA, Update individual open amounts (uea) user changes amount 497 // 498 499 function get_form_paid_fields() { 500 var fields = []; 501 502 ptForm.find( '.pt-cf-label-amount' ).each( function( index, element ) { fields.push( element ); }); // Label fields 503 ptForm.find( '.pt-uea-custom-amount' ).each( function( index, element ) { fields.push( element ); }); // Open amount fields 504 ptForm.find( 'select.pt-cf-amount' ).each( function( index, element ) { fields.push( element ); }); // Select fields
505 ptForm.find( 'input[type=radio].pt-cf-amount:checked' ).each( function( index, element ) { fields.push( element ); }); // Radio fields 506 ptForm.find( 'input[type=checkbox].pt-cf-amount' ).each( function( index, element ) { fields.push( element ); }); // Checkbox fields 507 ptForm.find( '.pt-paid-field' ).each( function( index, element ) { fields.push( element ); }); 508 509 return fields; 510 } 511 512 function get_form_total(discount = true) { 513 514 // Get all fields/amounts 515 var total = 0; 516 var fields = get_form_paid_fields(); 517 518 // Loop through each amount field 519 $( fields ).each( function( index, element ) { 520 521 // If a paid field is disabled (e.g. with interval options and subscriptions) don't process it 522 if ($(element).prop('disabled')) { 523 return false; 524 } 525 526 var fieldAmount = 0; 527 var $quantity_input = $( element ).siblings('.pt-quantity-input').length ? 528 $( element ).siblings('.pt-quantity-input') : 529 $( element ).siblings('.paytium-quantity-input').children('.pt-quantity-input'); 530 var quantity = $quantity_input.length ? $quantity_input.val() : 1; 531 if($(element).hasClass('pt-paid-field')) { 532 fieldAmount = $( element ).val() ? $( element ).attr('data-pt-price') * quantity : 0; 533 $( element ).siblings('[name$="[amount]"]').val(parseAmount(fieldAmount)); 534 } 535 else if($(element).hasClass('pt-uea-custom-amount')) { 536 fieldAmount = parseAmount($(element).val()) * quantity; 537 $(element).parent().siblings('.pt-uea-custom-amount-formatted').val(parseAmount(fieldAmount)); 538 } 539 else { 540 switch ($(element).prop('nodeName')) { 541 case 'SELECT' : 542 fieldAmount = $(element).find('option:selected').attr('data-pt-price') * quantity; 543 fieldAmount ? $(element).find('option:selected').val(parseAmount(fieldAmount)) : ''; 544 break; 545 default: 546 case 'INPUT' : 547 var type = $(element).attr('type'); 548 if (type == 'hidden' || type == 'text') { 549 fieldAmount = $(element).attr('data-pt-price') * quantity; 550 $(element).val(parseAmount(fieldAmount)); 551 } else if (type == 'radio' ) { 552 553 $quantity_input = $(element).parents('.pt-radio-group').find('.pt-quantity-input'); 554 quantity = $quantity_input.length ? $quantity_input.val() : 1; 555 fieldAmount = $(element).attr('data-pt-price') * quantity; 556 $(element).val(parseAmount(fieldAmount)); 557 } 558 else if (type == 'checkbox') { 559 fieldAmount = $(element).attr('data-pt-price') * quantity; 560 $(element).val(parseAmount(fieldAmount)); 561 if(!$(element).is(':checked')) { 562 fieldAmount = 0; 563 } 564 } 565 566 break; 567 568 } 569 570 } 571 total = parseFloat( total ) + parseAmount( fieldAmount ); 572 }); 573 574 return discount ? get_form_total_with_discount(total) : total; 575 } 576 577 function get_form_total_with_discount(total) { 578 579 let total_after_discount = total, 580 zero_tax = ptForm.find(".pt-zero-tax").length ? parseFloat(ptForm.find(".pt-zero-tax").val()) : 0, 581 total_without_zero_tax = total - zero_tax; 582 583 584 // If a discount is found, calculate the new total 585 if (ptForm.find(".pt-discount-type").length > 0 && ptForm.find(".pt-discount-value").length > 0) { 586 587 let discountType = ptForm.find(".pt-discount-type").val(); // Don't use parseAmount for this one! 588 let discountValue = ptForm.find(".pt-discount-value").val(); // Don't use parseAmount for this one! 589 590 let discount_first_payment = ptForm.find('#pt-discount-first-payment').length; 591 592 if (discountType.length > 0 && discountValue.length > 0 && !discount_first_payment) { 593 594 if ((discountType === 'percentage' )) { 595 total_after_discount = parseAmount(total_without_zero_tax * ((100 - discountValue) / 100)); 596 } 597 598 if ((discountType === 'amount' )) { 599 total_after_discount = parseAmount(total_without_zero_tax - discountValue); 600 } 601 602 } 603 } 604 605 return total_after_discount !== total ? total_after_discount + zero_tax : total; 606 } 607 608 function get_first_payment_amount() { 609 610 var first_payment_amount = ptForm.find(".pt-subscription-first-payment").val(), 611 discount_exclude_first_payment = ptForm.find('#pt-discount-exclude-first-payment').length; 612 613 if (discount_exclude_first_payment) return first_payment_amount; 614 615 if (ptForm.find(".pt-discount-type").length > 0 && ptForm.find(".pt-discount-value").length > 0 && first_payment_amount) { 616 617 var discountType = ptForm.find(".pt-discount-type").val(); // Don't use parseAmount for this one! 618 var discountValue = ptForm.find(".pt-discount-value").val(); // Don't use parseAmount for this one! 619 620 if (discountType.length > 0 && discountValue.length > 0) { 621 622 if ((discountType === 'percentage' )) { 623 first_payment_amount = parseAmount(first_payment_amount.replace(',','.') * ((100 - discountValue) / 100)); 624 } 625 626 if ((discountType === 'amount' )) { 627 first_payment_amount = parseAmount(first_payment_amount.replace(',','.') - discountValue); 628 } 629 } 630 } 631 return first_payment_amount; 632 } 633 634 function quantity_input_validation($quantity_input) { 635 // Get values from input box 636 637 update_checkbox_field($quantity_input) 638 639 var new_qty = $quantity_input.val(); 640 var step = $quantity_input.attr( 'step' ); 641 var max = $quantity_input.attr( 'max' ); 642 var min = $quantity_input.attr( 'min' ); 643 644 // Adjust default values if values are blank 645 if ( typeof min == 'undefined' ) 646 min = 0; 647 648 if ( typeof step == 'undefined') 649 step = 1; 650 651 // Max Value Validation 652 if ( +new_qty > +max && typeof max !== 'undefined' ) { 653 new_qty = max; 654 655 // Min Value Validation 656 } else if ( +new_qty < +min ) { 657 new_qty = min; 658 } 659 660 // Calculate remainder 661 var rem = ( new_qty - min ) % step; 662 663 // Step Value Value Validation 664 if ( rem != 0 ) { 665 new_qty = +new_qty + (+step - +rem); 666 667 // Max Value Validation 668 if ( +new_qty > +max ) { 669 new_qty = +new_qty - +step; 670 } 671 } 672 673 if (ptFormQtyDiscountData) { 674 675 let discountQtyCount = ptFormQtyDiscountData.length, 676 i = 0; 677 678 $(ptFormQtyDiscountData).each(function (k, v) { 679 680 if ( (ptFormCurrentQtyDiscount !== parseFloat(v.discount) && parseInt(new_qty) >= parseInt(v.quantity)) || 681 (ptFormCurrentQtyDiscount === parseFloat(v.discount) && parseInt(new_qty) < parseInt(v.quantity)) ) { 682 683 if (ptFormCurrentQtyDiscount > parseFloat(v.discount) && parseInt(new_qty) >= ptFormCurrentQty) { 684 return; 685 } 686 let data = v; 687 if (parseInt(new_qty) < parseInt(v.quantity)) { 688 if (k < discountQtyCount-1) { 689 data = ptFormQtyDiscountData[k+1]; 690 } 691 else { 692 i++; 693 return; 694 } 695 } 696 697 ptFormCurrentQtyDiscount = parseFloat(data.discount); 698 ptFormCurrentQty = parseInt(data.quantity); 699 700 let loaderContainer = $( '<div>', { 701 'class': 'pt-checkout-form-loading' 702 }).appendTo( ptForm ); 703 704 let loader = $( '<div>', { 705 'class': 'pt-loader' 706 }).appendTo( loaderContainer ); 707 708 $.ajax({ 709 url: paytium_localize_script_vars.admin_ajax_url, 710 type: 'POST', 711 dataType: 'json', 712 data: { 713 'action': "pt_ajax_quantity_discount", 714 'id': ptFormQtyDiscount.attr('id'), 715 'data': { 716 'current_qty': new_qty, 717 'qty': data.quantity, 718 'discount': data.discount, 719 'type': data.type 720 } 721 }, 722 success: function (response) { 723 724 if (response.error) { 725 726 ptFormCurrentQtyDiscount = 0; 727 ptFormCurrentQty = 0; 728 // Remove discount fields 729 ptForm.find(".pt-discount-type").remove(); 730 ptForm.find(".pt-discount-value").remove(); 731 ptForm.find(".pt-quantity-discount-hidden").remove(); 732 733 ptForm.find('.pt-discount-true').hide(); 734 735 update_totals(); 736 } 737 else { 738 // Remove discount fields 739 ptForm.find(".pt-discount-type").remove(); 740 ptForm.find(".pt-discount-value").remove(); 741 ptForm.find(".pt-quantity-discount-hidden").remove(); 742 743 ptForm.find('.pt-discount-true').hide(); 744 745 $("<input>", { 746 type: "hidden", 747 name: 'pt-quantity-discount', 748 class: 'pt-quantity-discount-hidden', 749 value: response.quantity 750 }).appendTo(ptForm); 751 $("<input>", { 752 type: "hidden", 753 name: 'pt-discount-uid', 754 class: 'pt-discount-uid', 755 value: response.uid 756 }).appendTo(ptForm); 757 $("<input>", { 758 type: "hidden", 759 name: 'pt-discount[type]', 760 class: 'pt-discount-type', 761 value: response.type 762 }).appendTo(ptForm); 763 $("<input>", { 764 type: "hidden", 765 name: 'pt-discount[value]', 766 class: 'pt-discount-value', 767 value: response.value 768 }).appendTo(ptForm); 769 770 ptForm.find('.pt-discount-true').show(); 771 772 update_totals(); 773 } 774 loaderContainer.remove(); 775 }, 776 }); 777 778 return false;
779 } 780 else if(parseInt(new_qty) < parseInt(v.quantity)) { 781 i++; 782 } 783 }); 784 785 if (discountQtyCount === i) { 786 ptFormCurrentQtyDiscount = 0; 787 ptFormCurrentQty = 0; 788 // Remove discount fields 789 ptForm.find(".pt-discount-type").remove(); 790 ptForm.find(".pt-discount-value").remove(); 791 ptForm.find(".pt-quantity-discount-hidden").remove(); 792 793 ptForm.find('.pt-discount-true').hide(); 794 795 update_totals(); 796 } 797 798 } 799 800 // Set the new value 801 $quantity_input.val( new_qty ); 802 } 803 804 // When custom subscription interval is checked or unchecked, process that change 805 function subscription_interval($interval) { 806 807 var $checkbox = $interval.length ? $interval.siblings(':checkbox') : $(this); 808 809 if (!$checkbox.length) { 810 return false; 811 } 812 813 // Make sure there is a value set 814 if (typeof $checkbox.attr('value') === 'undefined') { 815 return false; 816 } 817 818 // If checkbox was checked, update interval in hidden field 819 if ($checkbox.is(':checked') && ($interval instanceof $.Event)) { 820 821 var ptCheckboxFormLabel = $(this).attr('data-pt-label'); 822 var ptCheckboxFormValue = $(this).attr('value'); 823 var ptCheckboxFormPrice = $(this).attr('data-pt-price'); 824 825 // If users select "once" as interval, disable all subscriptions 826 if ((ptCheckboxFormValue === 'once') || (ptCheckboxFormValue === 'eenmalig')) { 827 828 ptForm.find("[id='pt-subscription-interval']").prop('disabled', true); 829 ptForm.find("[id='pt-subscription-times']").prop('disabled', true); 830 ptForm.find("[id='pt-subscription-first-payment']").prop('disabled', true); 831 832 } else { 833 834 // Help users by adding an s to an interval when they forget about it 835 if (!ptCheckboxFormValue.endsWith('s')) { 836 ptCheckboxFormValue = ptCheckboxFormValue + 's'; 837 } 838 839 ptForm.find("[id='pt-subscription-interval']").prop('disabled', false); 840 ptForm.find("[name='pt-subscription-interval-options']").prop('disabled', false); 841 ptForm.find("[id='pt-subscription-times']").prop('disabled', false); 842 ptForm.find("[id='pt-subscription-first-payment']").prop('disabled', false); 843 ptForm.find('.pt-subscription-custom-amount').prop('disabled', false); 844 845 // Update selected interval into subscription field 846 ptForm.find("[id='pt-subscription-interval']").attr('value', ptCheckboxFormValue); 847 } 848 849 if (ptCheckboxFormPrice) { 850 ptForm.find("[id='pt-subscription-custom-amount']").attr('value', ptCheckboxFormPrice); 851 ptForm.find("[id='pt-subscription-custom-amount']").attr('data-pt-price', ptCheckboxFormPrice); 852 ptForm.find("[id='pt-subscription-custom-value']").attr('value', ptCheckboxFormLabel); 853 } 854 855 } 856 857 update_totals(); 858 } 859 860 // When subscription optional is checked or unchecked, process that change 861 function subscription_optional($optional) { 862 863 var $checkbox = $optional.length ? $optional.siblings(':checkbox') : $(this); 864 865 if (!$checkbox.length) { 866 return false; 867 } 868 869 // Make sure there is a value set 870 if (typeof $checkbox.attr('value') === 'undefined') { 871 return false; 872 } 873 874 // If checkbox was checked, add to total, else deduct 875 if ($checkbox.is(':checked') && ($optional instanceof $.Event)) { 876 877 var $state = false;
878 var $stateRequired = false; 879 if ($(this).attr('value') === 'yes') { 880 $state = false; 881 $stateRequired = true; 882 } 883 884 if ($(this).attr('value') === 'no') { 885 $state = true; 886 $stateRequired = false; 887 } 888 889 ptForm.find("[id='pt-subscription-interval']").prop('disabled', $state); 890 ptForm.find("[name='pt-subscription-interval-options']").prop('disabled', $state); 891 ptForm.find("[name='pt-subscription-interval-options']").prop('required', $stateRequired); 892 ptForm.find("[id='pt-subscription-times']").prop('disabled', $state); 893 ptForm.find("[id='pt-subscription-first-payment']").prop('disabled', $state); 894 ptForm.find('.pt-subscription-custom-amount').prop('disabled', $state ); 895 } 896 897 update_totals(); 898 } 899 900 // When checkbox with amount is checked or unchecked, process that change 901 function update_checkbox_field($quantity_input) { 902 903 var $checkbox = $quantity_input.length ? (ptFormFb ? $quantity_input.parent().siblings(':checkbox:checked') : $quantity_input.siblings(':checkbox')) : $(this); 904 905 if(!$checkbox.length) { 906 return false; 907 } 908 909 // Make sure it's an amount checkbox by checking data attribute 'data-pt-price' is defined, otherwise abort. 910 if (typeof $checkbox.attr('data-pt-price') === 'undefined') { 911 return false; 912 } 913 914 var ptCheckboxFormGroupAmountId = $checkbox.attr('name').replace('[amount]', '[amount][total]'); 915 var total = 0; 916 $checkbox.parents('.pt-form-group-checkbox-new').find(':checked').each(function (index, element) { 917 let cbQty = $quantity_input.length && $(element).siblings('paytium-quantity-input') ? $(element).siblings('.paytium-quantity-input').children('.pt-quantity-input') : false; 918 total += cbQty ? parseFloat($(element).data('pt-price')) * parseFloat(cbQty.val()) : parseFloat($(element).val()); 919 }); 920 921 922 // Update the total value in value attribute 923 ptForm.find("[id='" + ptCheckboxFormGroupAmountId + "']").attr('value', parseAmount(total)); 924 925 // Update total value in pt-price data attribute 926 ptForm.find("[id='" + ptCheckboxFormGroupAmountId + "']").attr('data-pt-price', parseAmount(total)); 927 928 // If checkbox was checked, add to total, else deduct 929 if ($checkbox.is(':checked') && ($quantity_input instanceof $.Event)) { 930 931 // 932 // Update label 933 // 934 935 // Get/convert checkbox group label ID 936 var ptCheckboxFormGroupLabelId = $checkbox.attr('name').replace('[amount]', '[label]'); 937 938 var ptCheckboxFormValue = $(this).attr('name').replace('[amount]', '[value]'); 939 940 // Get previously checked options 941 var ptCheckboxCurrentOptions = ptForm.find("[name='" + ptCheckboxFormGroupLabelId + "']").attr('data-pt-checked-options'); 942 ptCheckboxCurrentOptions = JSON.parse(ptCheckboxCurrentOptions); 943 944 // If previously checked options are not an array, this means it's empty 945 if ( Object.keys(ptCheckboxCurrentOptions).length === 0 ) { 946 ptCheckboxCurrentOptions = {}; 947 } 948 949 // Get selected label, convert currency symbol to HTML entity 950 ptCheckboxCurrentOptions[$checkbox.attr('data-pt-checkbox-id')] = $checkbox.parent().text(); 951 952 // Start string with current group label 953 var ptCheckboxCurrentOptionsString = ptForm.find("[name='" + ptCheckboxFormGroupLabelId + "']").attr('data-pt-original-label'); 954 955 // Convert current options to a string for HTML hidden field 956 var ptCheckboxFormValueString = ''; 957 958 for (var key in ptCheckboxCurrentOptions) { 959 ptCheckboxFormValueString += ptCheckboxFormValueString == '' ? ptCheckboxCurrentOptions[key] : ', ' + ptCheckboxCurrentOptions[key]; 960 } 961 962 // Convert to a format that is save for HTML fields 963 ptCheckboxCurrentOptions = JSON.stringify(ptCheckboxCurrentOptions); 964
965 // Add updated options to data-pt-checked-options attribute 966 ptForm.find("[name='" + ptCheckboxFormGroupLabelId + "']").attr('data-pt-checked-options', ptCheckboxCurrentOptions); 967 968 969 // Add current options string to hidden HTML field 970 ptForm.find("[name='" + ptCheckboxFormGroupLabelId + "']").attr('value', ptCheckboxCurrentOptionsString); 971 ptForm.find("[name='" + ptCheckboxFormValue + "']").attr('value', ptCheckboxFormValueString); 972 973 // 974 // Update limit 975 // 976 977 var ptCheckboxFormGroupLimitData = $checkbox.attr('name').replace('[amount]', '[limit_data]'); 978 979 var ptCheckboxItemId = ptForm.find("[name='" + ptCheckboxFormGroupLimitData + "']").val(); 980 981 if ( ptCheckboxItemId !== undefined ) { 982 983 ptCheckboxItemId = JSON.parse(ptCheckboxItemId); 984 985 // console.log(ptCheckboxItemId); 986 987 if (Object.keys(ptCheckboxItemId).length === 0) { 988 ptCheckboxItemId = {}; 989 } 990 991 ptCheckboxItemId[$checkbox.data('item_id')] = { 992 'limit': $checkbox.data('limit'), 993 'quantity': $checkbox.siblings('.pt-quantity-input').val(), 994 }; 995 if ($checkbox.data('general_item_id')) { 996 ptCheckboxItemId[$checkbox.data('item_id')]['general_item_id'] = $checkbox.data('general_item_id'); 997 ptCheckboxItemId[$checkbox.data('item_id')]['general_limit'] = $checkbox.data('general_limit'); 998 } 999 1000 ptCheckboxItemId = JSON.stringify(ptCheckboxItemId); 1001 1002 ptForm.find("[name='" + ptCheckboxFormGroupLimitData + "']").val(ptCheckboxItemId); 1003 1004 } 1005 1006 } else if ($checkbox.not(':checked') && ($quantity_input instanceof $.Event) ) { 1007 1008 // 1009 // Update label 1010 // 1011 1012 // Get/convert checkbox group label ID 1013 var ptCheckboxFormGroupLabelId = $checkbox.attr('name').replace('[amount]', '[label]'); 1014 1015 var ptCheckboxFormValue = $(this).attr('name').replace('[amount]', '[value]'); 1016 1017 // Get previously checked options 1018 var ptCheckboxCurrentOptions = ptForm.find("[name='" + ptCheckboxFormGroupLabelId + "']").attr('data-pt-checked-options'); 1019 ptCheckboxCurrentOptions = JSON.parse(ptCheckboxCurrentOptions); 1020 1021 // If previously checked options are an array, remove the selected label 1022 if (typeof ptCheckboxCurrentOptions === 'object') { 1023 1024 // Only add the selected label if it's not in previously checked options array already 1025 1026 var ptCheckboxSelectedLabelId = $checkbox.attr('data-pt-checkbox-id'); 1027 1028 delete ptCheckboxCurrentOptions[ptCheckboxSelectedLabelId]; 1029 1030 // Start string with current group label 1031 var ptCheckboxCurrentOptionsString = ptForm.find("[name='" + ptCheckboxFormGroupLabelId + "']").attr('data-pt-original-label'); 1032 1033 // Convert current options to a string for HTML hidden field 1034 1035 var ptCheckboxFormValueString = ''; 1036 for (var key in ptCheckboxCurrentOptions) { 1037 ptCheckboxFormValueString += ptCheckboxFormValueString == '' ? ptCheckboxCurrentOptions[key] : ', ' + ptCheckboxCurrentOptions[key]; 1038 } 1039 1040 // Convert to a format that is save for HTML fields 1041 ptCheckboxCurrentOptions = JSON.stringify(ptCheckboxCurrentOptions); 1042
1043 // Add updated options to data-pt-checked-options attribute 1044 ptForm.find("[name='" + ptCheckboxFormGroupLabelId + "']").attr('data-pt-checked-options', ptCheckboxCurrentOptions); 1045 1046 // Add current options string to hidden HTML field 1047 ptForm.find("[name='" + ptCheckboxFormGroupLabelId + "']").attr('value', ptCheckboxCurrentOptionsString); 1048 ptForm.find("[name='" + ptCheckboxFormValue + "']").attr('value', ptCheckboxFormValueString); 1049 1050 } 1051 1052 // 1053 // Update limit 1054 // 1055 1056 var ptCheckboxFormGroupLimitData = $checkbox.attr('name').replace('[amount]', '[limit_data]'); 1057 1058 var ptCheckboxItemId = ptForm.find("[name='" + ptCheckboxFormGroupLimitData + "']").val(); 1059 1060 if ( ptCheckboxItemId !== undefined ) { 1061 1062 ptCheckboxItemId = JSON.parse(ptCheckboxItemId); 1063 1064 if (typeof ptCheckboxItemId === 'object') { 1065 1066 var ptCheckboxSelectedItemId = $checkbox.data('item_id'); 1067 1068 delete ptCheckboxItemId[ptCheckboxSelectedItemId]; 1069 1070 ptCheckboxItemId = JSON.stringify(ptCheckboxItemId); 1071 1072 ptForm.find("[name='" + ptCheckboxFormGroupLimitData + "']").val(ptCheckboxItemId); 1073 1074 } 1075 } 1076 } 1077 } 1078 1079 1080 function update_totals(e = false) { 1081 1082 if (e) { 1083 if($(e.target).attr('type') && $(e.target).attr('type') == 'number') { 1084 quantity_input_validation($(e.target)); 1085 } 1086 1087 if($(e.target).hasClass('paytium-spinner')) { 1088 let input = $(e.target).siblings('.pt-quantity-input'); 1089 if ($(input).attr('type') && $(input).attr('type') == 'number') { 1090 quantity_input_validation($(input)); 1091 } 1092 } 1093 } 1094 1095 var total = get_form_total(), 1096 first_payment_amount = get_first_payment_amount(); 1097 update_checkbox_field($(this)); 1098 1099 if (ptFormAmountDiscountData) { 1100 1101 let discountAmountCount = ptFormAmountDiscountData.length, 1102 i = 0; 1103 $(ptFormAmountDiscountData).each(function (k, v) { 1104 1105 let total_without_discount = parseFloat(get_form_total(false)); 1106 1107 if ( (ptFormCurrentAmountDiscount !== parseFloat(v.discount) && total_without_discount >= parseFloat(v.amount)) || 1108 (ptFormCurrentAmountDiscount === parseFloat(v.discount) && total_without_discount < parseFloat(v.amount)) ) { 1109 1110 if (ptFormCurrentAmountDiscount > parseFloat(v.discount) && total_without_discount >= ptFormCurrentAmount) { 1111 return; 1112 } 1113 let data = v; 1114 if (total_without_discount < parseFloat(v.amount)) { 1115 if (k < discountAmountCount-1) { 1116 data = ptFormAmountDiscountData[k+1]; 1117 } 1118 else { 1119 i++; 1120 return; 1121 } 1122 } 1123 1124 ptFormCurrentAmountDiscount = parseFloat(data.discount); 1125 ptFormCurrentAmount = parseInt(data.amount); 1126 1127 let loaderContainer = $( '<div>', { 1128 'class': 'pt-checkout-form-loading' 1129 }).appendTo( ptForm ); 1130 1131 let loader = $( '<div>', { 1132 'class': 'pt-loader' 1133 }).appendTo( loaderContainer ); 1134 1135 $.ajax({ 1136 url: paytium_localize_script_vars.admin_ajax_url, 1137 type: 'POST', 1138 dataType: 'json', 1139 data: { 1140 'action': "pt_ajax_amount_discount", 1141 'id': ptFormAmountDiscount.attr('id'), 1142 'data': { 1143 'current_amount': total_without_discount, 1144 'amount': data.amount, 1145 'discount': data.discount, 1146 'type': data.type 1147 } 1148 }, 1149 success: function (response) { 1150 1151 if (response.error) { 1152 1153 ptFormCurrentAmountDiscount = 0; 1154 ptFormCurrentAmount = 0; 1155 // Remove discount fields 1156 ptForm.find(".pt-discount-type").remove(); 1157 ptForm.find(".pt-discount-value").remove(); 1158 ptForm.find(".pt-amount-discount-hidden").remove(); 1159 1160 ptForm.find('.pt-discount-true').hide(); 1161 1162 total = get_form_total(); 1163 update_totals_helper(total,first_payment_amount) 1164 } 1165 else { 1166 // Remove discount fields 1167 ptForm.find(".pt-discount-type").remove(); 1168 ptForm.find(".pt-discount-value").remove(); 1169 ptForm.find(".pt-amount-discount-hidden").remove(); 1170 1171 ptForm.find('.pt-discount-true').hide(); 1172 1173 $("<input>", { 1174 type: "hidden", 1175 name: 'pt-amount-discount', 1176 class: 'pt-amount-discount-hidden', 1177 value: response.amount 1178 }).appendTo(ptForm); 1179 $("<input>", { 1180 type: "hidden", 1181 name: 'pt-discount-uid', 1182 class: 'pt-discount-uid', 1183 value: response.uid 1184 }).appendTo(ptForm); 1185 $("<input>", { 1186 type: "hidden", 1187 name: 'pt-discount[type]', 1188 class: 'pt-discount-type', 1189 value: response.type 1190 }).appendTo(ptForm); 1191 $("<input>", { 1192 type: "hidden", 1193 name: 'pt-discount[value]', 1194 class: 'pt-discount-value', 1195 value: response.value 1196 }).appendTo(ptForm); 1197 1198 ptForm.find('.pt-discount-true').show(); 1199 1200 total = get_form_total_with_discount(total_without_discount); 1201 update_totals_helper(total,first_payment_amount) 1202 } 1203 loaderContainer.remove(); 1204 }, 1205 }); 1206 return false;
1207 } 1208 else if(total_without_discount < parseFloat(v.amount)) { 1209 update_totals_helper(total,first_payment_amount); 1210 i++; 1211 } 1212 }); 1213 1214 if (discountAmountCount === i) { 1215 ptFormCurrentAmountDiscount = 0; 1216 ptFormCurrentAmount = 0; 1217 // Remove discount fields 1218 ptForm.find(".pt-discount-type").remove(); 1219 ptForm.find(".pt-discount-value").remove(); 1220 ptForm.find(".pt-amount-discount-hidden").remove(); 1221 1222 ptForm.find('.pt-discount-true').hide(); 1223 total = get_form_total(); 1224 1225 update_totals_helper(total,first_payment_amount) 1226 } 1227 else update_totals_helper(total,first_payment_amount); 1228 } 1229 else update_totals_helper(total,first_payment_amount); 1230 } 1231 1232 function update_totals_helper(total,first_payment_amount) { 1233 1234 ptForm.find('.pt-total-amount').html( currencyFormattedAmount( total, ptFormCurrencySymbol ) ); 1235 ptForm.find('.pt_amount').val( total ); 1236 1237 var ptFirstPaymentLabel = ptForm.find("[id^=pt-subscription-first-payment-label]").length ? 1238 ptForm.find("[id^=pt-subscription-first-payment-label]").val() + ': ' : 1239 paytium_localize_script_vars.subscription_first_payment + ' '; 1240 1241 ptForm.find('.pt-first-payment-amount').html( ptFirstPaymentLabel + currencyFormattedAmount(first_payment_amount, ptFormCurrencySymbol) ); 1242 1243 var minTotalInput = ptForm.find('.pt-total-minimum'); 1244 if (minTotalInput.length) { 1245 minTotalInput.val( total ); 1246 if (total >= minTotalInput.data('parsley-mintotal') && ptForm.find('div[id^=pt_total_errors]').find('ul').hasClass('filled')) { 1247 ptForm.find('div[id^=pt_total_errors]').find('ul').removeClass('filled'); 1248 } 1249 } 1250 1251 } 1252 update_totals(); 1253 1254 $(ptForm).off('submit').on('submit', function(e) { 1255 if (!validateFormAmounts()) e.preventDefault(); 1256 }); 1257 1258 function validateFormAmounts() { 1259 1260 let formAmounts = []; 1261 ptForm.find(".pt-cf-amount").each(function () { 1262 if ($(this).is('select')) { 1263 $($(this).children('option')).each(function () { 1264 let ptPrice = $(this).attr('data-pt-price'); 1265 formAmounts.push(ptPrice); 1266 }) 1267 } 1268 else { 1269 let ptPrice = $(this).attr('data-pt-price'); 1270 formAmounts.push(ptPrice); 1271 } 1272 }); 1273 1274 if (JSON.stringify(ptFormAmounts) !== JSON.stringify(formAmounts)) { 1275 window.alert(paytium_localize_script_vars.validation_failed); 1276 return false; 1277 } 1278 else return true; 1279 } 1280 1281 function submitFormProcessing(event) { 1282 1283 if (!validateFormAmounts()) return; 1284 1285 debug_log('click.ptPaymentBtn fired'); 1286 1287 if (ptForm.parsley({ 1288 excluded: 'input[type=button], input[type=submit], input[type=reset]', 1289 inputs: 'input, textarea, select, input[type=hidden], :hidden', 1290 }).validate()) { 1291 1292 // Run totals one more time to ensure the total amount is accurate 1293 update_totals(); 1294 1295 // 1296 // START - Process (custom) fields 1297 // 1298 1299 // Process individual fields 1300 $(ptForm.find("[id^=pt-field-]")).each(function (index, element) { 1301 1302 var ptFieldValue = $(element).val(); // Get the field value 1303 var ptUserLabel = document.getElementById(this.id).getAttribute('data-pt-user-label'); // Get the user defined field label 1304 var ptFieldType = document.getElementById(this.id).getAttribute('data-pt-field-type'); // Get the field type 1305 1306 // Get required attribute 1307 var required = $(element).attr("required"); 1308 1309 // Validate that required fields are filled 1310 if ((required == 'required') && ptFieldValue == '') { 1311 1312 window.alert(paytium_localize_script_vars.field_is_required.replace('%s', ptUserLabel)); 1313 debug_log('ProcessFailed'); 1314 return false;
1315 } 1316 1317 // Log everything to Console when troubleshooting 1318 debug_log($(element)); 1319 debug_log('Processing field (type, label, value, id): ' + ptFieldType + ', ' + ptUserLabel + ', ' + ptFieldValue + ', ' + this.id); 1320 1321 // 1322 // Add the user's field label to form post data, so it can be used as user-facing identifier for that field 1323 // 1324 1325 // Create unique field ID for the user's field label 1326 var ptUserLabelLabel = this.id + "-label"; 1327 1328 // Add the unique field ID and user's label to the form post data 1329 $("<input>", {type: "hidden", name: ptUserLabelLabel, value: ptUserLabel}).appendTo(ptForm); 1330 1331 // 1332 // Check if field is set as user_data="true" and store the preference if so 1333 // 1334 var ptUserData = document.getElementById(this.id).getAttribute('data-pt-user-data'); // Get the field type 1335 1336 if (ptUserData == 'true') { 1337 // Create unique field ID for the user's field label 1338 var ptUserDataLabel = this.id + "-user-data"; 1339 1340 // Add the unique field ID and user's label to the form post data 1341 $("<input>", {type: "hidden", name: ptUserDataLabel, value: ptUserData}).appendTo(ptForm); 1342 } 1343 1344 }); 1345 1346 // 1347 // END - Process (custom) fields 1348 // 1349 1350 // 1351 // START - Process subscription(s) 1352 // 1353 1354 // Process subscription fields 1355 $(ptForm.find("[id^=pt-subscription-]")).each(function (index, element) { 1356 1357 if (this.disabled) { 1358 return false; 1359 } 1360 1361 // Get the field value 1362 var ptFieldValue = $(element).val(); 1363 1364 // Get the field type 1365 // this.id is field type 1366 1367 // Log everything to Console when troubleshooting 1368 debug_log($(element)); 1369 debug_log('Processing ' + this.id + ', ' + ptFieldValue); 1370 1371 // Add the unique field ID and user's label to the form post data 1372 $("<input>", {type: "hidden", name: this.id, value: ptFieldValue}).appendTo(ptForm); 1373 1374 }); 1375 1376 // Process subscription first payment 1377 if (ptForm.find("[id^=pt-subscription-first-payment]").length > 0) { 1378 1379 // Get recurring amount/form total before first payment 1380 var ptRecurringTotal = ptForm.find(".pt_amount").val(); 1381 1382 // Add recurring amount 1383 $("<input>", { 1384 type: "hidden", 1385 name: 'pt-subscription-recurring-payment', 1386 value: ptRecurringTotal 1387 }).appendTo(ptForm); 1388 1389 // Add "First payment" text and amount after the [paytium_total /] Shortcode 1390 var ptFirstPayment = ptForm.find("[id^=pt-subscription-first-payment]").val(); 1391 1392 // Update total amount to first payment 1393 ptForm.find('.pt_amount').val(ptFirstPayment); 1394 1395 } 1396 1397 // 1398 // END - Process subscription fields 1399 // 1400 1401 // 1402 // START - Remove discount field if it's empty or type and value fields are missing 1403 // 1404 1405 if (ptForm.find(".pt-discount").length > 0 && !ptForm.find(".pt-discount").val()) { 1406 ptForm.find(".pt-discount").prop('disabled', 'true'); 1407 } 1408 1409 if (!ptForm.find('[name$="pt-discount[type]"]').length || !ptForm.find('[name$="pt-discount[value]"]').length) { 1410 ptForm.find(".pt-discount").prop('disabled', 'true'); 1411 } 1412 1413 // 1414 // END - Remove discount field if it's empty 1415 // 1416 1417 // If there is no amount entered or amount is too low to be processed by Mollie 1418 // block execution of script and show an alert. Why 1 euro? Lower amounts 1419 // are just not logical! 1420 if ((get_form_total() <= '0.99') && (isPaytiumNoPayment() == false)) { 1421 window.alert(paytium_localize_script_vars.amount_too_low); 1422 return false;
1423 } 1424 1425 // Enable the below line if you want to process the form without redirecting 1426 // The form data is not stored in Paytium at this point 1427 // Also see line 24 in /paytium/includes/process-payment-functions.php 1428 //return false; 1429 1430 // Unbind original form submit trigger before calling again to "reset" it and submit normally. 1431 ptForm.unbind('submit'); 1432 ptForm.submit(); 1433 1434 // Disable original payment button and change text for UI feedback while POST-ing to Mollie 1435 ptForm.find('.pt-payment-btn') 1436 .prop('disabled', true) 1437 .find('span') 1438 .text(paytium_localize_script_vars.processing_please_wait); 1439 1440 } 1441 1442 if (typeof event != 'undefined') { 1443 event.preventDefault(); 1444 } 1445 } 1446 1447 function check_item_limits(event) { 1448 1449 var data = {}; 1450 var $item_id_input; 1451 1452 event.preventDefault(); 1453 1454 $(ptForm.find('[name$="[item_id]"], .pt-checkbox-group')).each(function (index, element) { 1455 1456 var $limit_data = $(element).find('[name$="[limit_data]"]'); 1457 if($limit_data.length) { 1458 var json_data = JSON.parse($limit_data.val()); 1459 $.each(json_data, function (item_id, value) { 1460 data[item_id] = value; 1461 }) 1462 } 1463 else { 1464 var item_id = $(element).val(); 1465 var limit = $(element).siblings('[name$="[limit]"]').val(); 1466 var quantity = $(element).siblings('.pt-quantity-input').val(); 1467 data[item_id] = {'limit': limit, 'quantity': quantity}; 1468 } 1469 1470 }); 1471 1472 if(!$.isEmptyObject(data)) { 1473 1474 $.ajax({ 1475 url: paytium_localize_script_vars.admin_ajax_url, 1476 type: 'POST', 1477 dataType: 'json', 1478 data: { 1479 'action': "pt_ajax_check_item_limits", 1480 'data': data 1481 }, 1482 success: function (response) { 1483 1484 $('.limit-error-message').remove(); 1485 if (response.error) { 1486 $.each(response.limit_exceeded, function (item_id, data) { 1487 $item_id_input = $('[value="' + item_id + '"]').length ? $('[value="' + item_id + '"]') : $('[data-item_id="' + item_id + '"]'); 1488 1489 $item_id_input.before('<p class="limit-error-message">Limit reached! Only ' + data.items_left + ' items left</p>'); 1490 1491 }); 1492 } 1493 else { 1494 submitFormProcessing(); 1495 } 1496 }, 1497 1498 }); 1499 } 1500 1501 else { 1502 submitFormProcessing(); 1503 } 1504 1505 } 1506 1507 // 1508 // START - Paytium Links 1509 // 1510 1511 ptForm.find("[id^=pt-paytium-links]").each(function () { 1512 1513 // Helper function to sanitize input 1514 function sanitizeInput(input) { 1515 return input ? input.replace(/[^\w\s,-|]/gi, '') : ' '; // Allows alphanumeric, space, dash, dot, and pipe ("|") 1516 } 1517 1518 // Create an object with all data 1519 function getSearchParameters() { 1520 var prmstr = window.location.search.substr(1); 1521 prmstr = decodeURIComponent(prmstr); 1522 return prmstr !== null && prmstr !== "" ? transformToAssocArray(prmstr) : {}; 1523 } 1524 1525 function transformToAssocArray(prmstr) { 1526 var params = {}; 1527 var prmarr = prmstr.split("&"); 1528 for (var i = 0; i < prmarr.length; i++) { 1529 var tmparr = prmarr[i].split("="); 1530 var key = sanitizeInput(tmparr[0]); // Sanitize keys 1531 var value = sanitizeInput(tmparr[1]); // Sanitize values 1532 params[key] = value; 1533 } 1534 return params; 1535 } 1536 1537 var params = getSearchParameters(); 1538 1539 $.each(params, function (key, valueObj) { 1540 // Process each param and update the form 1541 ptForm.find("[id^=pt-field-]").each(function (index, element) { 1542 var ptUserLabel = document.getElementById(this.id).getAttribute('data-pt-user-label'); 1543 if (ptUserLabel == key && !$(element).hasClass('pt-field-checkbox')) { 1544 $(element).val(sanitizeInput(valueObj)); 1545 } 1546 }); 1547 1548 if (ptForm.find('#pt-paytium-pro').length) { 1549 ptForm.find(".pt-checkbox-group, .pt-radio-group").each(function (index, element) { 1550 let selector = $(element), 1551 ptUserLabel = selector.data('pt-user-label'); 1552 if (ptUserLabel == key) { 1553 let choices = valueObj.split('|'); 1554 $(choices).each(function () { 1555 $(selector).find('label[title="' + s
1555anitizeInput(this) + '"]').click(); 1556 }); 1557 } 1558 }); 1559 } 1560 1561 if (key === 'subscription_option') { 1562 ptForm.find('.pt-radio-group.pt-subscription-interval-options label[title="'+sanitizeInput(valueObj)+'"]').click(); 1563 } 1564 1565 if (key.toLowerCase() == 'quantity') { 1566 ptForm.find('.pt-quantity-input').val(sanitizeInput(valueObj)); 1567 } 1568 1569 if (key.toLowerCase() == 'bedrag' || key.toLowerCase() == 'amount') { 1570 var sanitizedValue = sanitizeInput(valueObj); 1571 ptForm.find("[name*='pt-amount']").val(sanitizedValue); 1572 ptForm.find('.pt-uea-custom-amount').val(sanitizedValue); 1573 1574 ptForm.find('.pt-uea-custom-amount-formatted').val(parseAmount(sanitizedValue)).attr('data-pt-price', parseAmount(sanitizedValue)); 1575 ptForm.find("[name*='pt-amount']").attr('data-pt-price', parseAmount(sanitizedValue)); 1576 ptForm.find('.pt-uea-custom-amount').attr('data-pt-price', parseAmount(sanitizedValue)); 1577 } 1578 }); 1579 1580 update_totals(); 1581 1582 ptForm.find("[id^=pt-paytium-links-auto-redirect]").each(function () { 1583 ptForm.find('.pt-payment-btn').click(submitFormProcessing()); 1584 }); 1585 1586 }); 1587 1588 // 1589 // END - Paytium Links 1590 // 1591 1592 ptForm.find('.pt-payment-btn').off('click.ptPaymentBtn').on('click.ptPaymentBtn', check_item_limits); 1593 1594 // Multiplier functionality 1595 ptForm.find('.pt_multiplier') 1596 .each(function () { 1597 pt_multiply($(this)); 1598 }) 1599 .on('change keyup', function () { 1600 pt_multiply($(this)); 1601 }); 1602 1603 function pt_multiply($this) { 1604 1605 let multiplier_id = $this.data('pt_multiplier_id'), 1606 multiplier_val = +$this.val(); 1607 1608 $(ptForm.find('.pt-multiplied-by')).each(function () { 1609 if ($(this).data('pt_multiplied_by').indexOf(multiplier_id) > -1) { 1610 1611 let multiplied_by = $(this).data('pt_multiplied_by'), 1612 amount_input = $(this).siblings('.pt-cf-amount'), 1613 amount_val = amount_input.val(), 1614 amount_html = $(this).siblings('.pt-quantity-amount'), 1615 multiplier = multiplier_val; 1616 1617 if (!$(this).data('start_amount')) { 1618 $(this).data('start_amount',+amount_val) 1619 } 1620 1621 if ($(this).data('pt_multiplied_by').length > multiplier_id.length) { 1622 1623 let multipliers_arr = multiplied_by.split(','); 1624 1625 $.each(multipliers_arr, function (i,v) { 1626 multiplier = multiplier_id !== v ? multiplier * ptForm.find('.pt_multiplier[data-pt_multiplier_id='+v+']').val() : multiplier; 1627 }) 1628 } 1629 1630 let new_amount = parseAmount($(this).data('start_amount') * multiplier); 1631 1632 amount_input.attr('data-pt-price', new_amount); 1633 amount_html.text(currencyFormattedAmount(new_amount, ptFormCurrencySymbol)); 1634 } 1635 }); 1636 1637 if (ptForm.find('.pt-discount-checkbox-with-condition').length) { 1638 1639 let discountCbGroup = ptForm.find('.pt-discount-checkbox-with-condition'), 1640 cb = discountCbGroup.find('.pt-discount-checkbox'); 1641 1642 if (multiplier_id === discountCbGroup.data('condition-id')) { 1643 if (multiplier_val >= discountCbGroup.data('condition-qty')) { 1644 cb.prop('disabled',false); 1645 } 1646 else { 1647 // Remove checkbox discount fields 1648 ptForm.find(".pt-discount-type").remove(); 1649 ptForm.find(".pt-discount-value").remove(); 1650 ptForm.find(".pt-discount-checkbox-hidden").remove(); 1651 1652 ptForm.find('.pt-discount-true').hide();
1653 cb.prop('checked',false).prop('disabled',true).parent().removeClass('checked'); 1654 } 1655 } 1656 $(ptForm.find('.pt-multiplied-by')); 1657 } 1658 update_totals(); 1659 } 1660 1661 1662 ptForm.find('.pt-discount-checkbox').on('change', function(e) { 1663 1664 let loaderContainer = $( '<div>', { 1665 'class': 'pt-checkout-form-loading' 1666 }).appendTo( ptForm ); 1667 1668 let loader = $( '<div>', { 1669 'class': 'pt-loader' 1670 }).appendTo( loaderContainer ); 1671 1672 $(this).prop('disabled',true); 1673 1674 let cb = $(this), 1675 checked = '', 1676 data = {}; 1677 1678 data.id = cb.attr('id'); 1679 if ($(this).parents('.pt-discount-checkbox-with-condition').length) { 1680 let cbGroup = $(this).parents('.pt-discount-checkbox-with-condition'), 1681 conditionId = cbGroup.data('condition-id'), 1682 conditionQty = cbGroup.data('condition-qty'), 1683 conditionField = ptForm.find('.pt_multiplier[data-pt_multiplier_id="'+conditionId+'"]'), 1684 conditionFieldVal = +conditionField.val(); 1685 1686 data.condition_qty = conditionQty; 1687 data.condition_field_val = conditionFieldVal; 1688 1689 if (conditionFieldVal < conditionQty) { 1690 $(this).prop('checked',false); 1691 return false; 1692 } 1693 } 1694 1695 1696 if ($(this).prop('checked')) { 1697 checked = true; 1698 $(this).parent().addClass('checked') 1699 } 1700 else { 1701 checked = false; 1702 cb.parent().removeClass('checked'); 1703 } 1704 1705 $.ajax({ 1706 url: paytium_localize_script_vars.admin_ajax_url, 1707 type: 'POST', 1708 dataType: 'json', 1709 data: { 1710 'action': "pt_ajax_discount_checkbox", 1711 'data': data 1712 }, 1713 success: function (response) { 1714 1715 if (response.error) { 1716 // $.each(response.limit_exceeded, function (item_id, data) { 1717 // $item_id_input = $('[value="' + item_id + '"]').length ? $('[value="' + item_id + '"]') : $('[data-item_id="' + item_id + '"]'); 1718 // 1719 // $item_id_input.before('<p class="limit-error-message">Limit reached! Only ' + data.items_left + ' items left</p>'); 1720 // 1721 // }); 1722 console.log('discount checkbox error'); 1723 } 1724 else { 1725 console.log('discount checkbox success'); 1726 1727 if (checked) { 1728 $("<input>", { 1729 type: "hidden", 1730 name: 'pt-discount-checkbox', 1731 class: 'pt-discount-checkbox-hidden', 1732 value: response.checkbox 1733 }).appendTo(ptForm); 1734 $("<input>", { 1735 type: "hidden", 1736 name: 'pt-discount-uid', 1737 class: 'pt-discount-uid', 1738 value: response.uid 1739 }).appendTo(ptForm); 1740 $("<input>", { 1741 type: "hidden", 1742 name: 'pt-discount[type]', 1743 class: 'pt-discount-type', 1744 value: response.type 1745 }).appendTo(ptForm); 1746 $("<input>", { 1747 type: "hidden", 1748 name: 'pt-discount[value]', 1749 class: 'pt-discount-value', 1750 value: response.value 1751 }).appendTo(ptForm); 1752 1753 ptForm.find('.pt-discount-true').show(); 1754 } 1755 else { 1756 // Remove discount fields 1757 ptForm.find(".pt-discount-type").remove(); 1758 ptForm.find(".pt-discount-value").remove(); 1759 ptForm.find(".pt-discount-checkbox-hidden").remove(); 1760 1761 ptForm.find('.pt-discount-true').hide(); 1762 } 1763 1764 update_totals(); 1765 } 1766 1767 cb.prop('disabled',false); 1768 loaderContainer.remove(); 1769 }, 1770 1771 }); 1772 }); 1773 1774 function general_limit_control(input) { 1775 1776 if (input !== undefined) { 1777 1778 if (input.hasClass('general-limit-qty')) { 1779 1780 let currentGeneralQty = 0, 1781 currentVal = input.val(); 1782 1783 ptForm.find(".general-limit-qty").each(function () { 1784 currentGeneralQty = currentGeneralQty + parseInt($(this).val()); 1785 }); 1786 1787 ptForm.find(".general-limit-item").each(function () { 1788 if ((($(this).attr('type') === 'radio' || $(this).attr('type') === 'checkbox') && $(this).prop('checked')) || 1789 $(this).attr('type') === 'select' || $(this).attr('label')) { 1790 currentGeneralQty = currentGeneralQty + 1; 1791 } 1792 }); 1793 1794 if (currentGeneralQty > ptFormGeneralLimit) { 1795 let newVal = currentVal - (currentGeneralQty - ptFormGeneralLimit); 1796 return {'result': false, 'new_val': newVal}; 1797 } 1798 } 1799 } 1800 } 1801 1802 var ptPaytiumDate = ptForm.find('.pt-paytium-date'); 1803 if (ptPaytiumDate.length > 0) { 1804 ptPaytiumDate.each(function() { 1805 if (!$(this).hasClass('hasDatepicker')) { 1806 $(this).datepicker({ 1807 dateFormat: 'dd-mm-yy', 1808 changeMonth: true, 1809 changeYear: true, 1810 }); 1811 } 1812 }); 1813 } 1814 1815 var ptPaytiumBirthday = ptForm.find('.pt-paytium-birthday'); 1816 if (ptPaytiumBirthday.length > 0) { 1817 ptPaytiumBirthday.each(function() { 1818 if (!$(this).hasClass('hasDatepicker')) { 1819 $(this).datepicker({ 1820 dateFormat: 'dd-mm-yy', 1821 changeMonth: true, 1822 changeYear: true, 1823 yearRange: '-85:+0' 1824 }); 1825 } 1826 }); 1827 } 1828 } 1829 1830 $(function () { 1831 var $body = $('body'); 1832
1833 // Make sure each checkbox change sets the appropriate hidden value (Yes/No) to record 1834 // to Paytium payment records. 1835 $body.on('change', '.pt-checkout-form .pt-field-checkbox', function () { 1836 var checkbox = $(this); 1837 var checkboxId = checkbox.prop('id'); 1838 var hiddenField = $body.find('#' + checkboxId + '_hidden'); // Hidden ID field is simply "_hidden" appended to checkbox ID field. 1839 1840 hiddenField.val(checkbox.is(':checked') ? 'Yes' : 'No'); // Change to "Yes" or "No" depending on checked or not. 1841 }); 1842 1843 // Function to initialize any uninitialized forms 1844 function initializeUninitializedForms() { 1845 $('.pt-checkout-form').each(function () { 1846 initializePaytiumForm($(this)); 1847 }); 1848 } 1849 1850 // Initialize forms on initial page load 1851 initializeUninitializedForms(); 1852 1853 // Periodically check for and initialize new forms (e.g., in Elementor popups) 1854 setInterval(initializeUninitializedForms, 500); // Check every 500 milliseconds 1855 }); 1856 1857 // Convert to formatted amount 1858 function currencyFormattedAmount(amount, currencySymbol) { 1859 amount = parseAmount( amount ) + ''; // Convert to string 1860 amount = Number(Math.round(amount+'e2')+'e-2').toFixed(2); 1861 amount = amount.replace( '.', pt.decimal_separator ); 1862 return currencySymbol == 'fr.' || currencySymbol == 'NOK' || currencySymbol == 'SEK' ? amount + " " + currencySymbol : currencySymbol + " " + amount; 1863 } 1864 1865 /** 1866 * Parse to a valid amount. 1867 * @returns float Valid number. 1868 */ 1869 function parseAmount( amount ) { 1870 if ( typeof amount == 'string' ) { 1871 amount = amount.replace( ',', '.' ); 1872 } 1873 1874 if ( isNaN( amount ) || amount == '' ) { 1875 amount = 0; 1876 } 1877 1878 amount = parseFloat( amount ); 1879 return roundToTwo( amount ); 1880 } 1881 1882 // https://stackoverflow.com/a/18358056/3389968 1883 function roundToTwo(num) { 1884 return +(Math.round(num + "e+2") + "e-2"); 1885 } 1886 1887 1888 window.Parsley 1889 .addValidator('filemaxmegabytes', { 1890 requirementType: 'string', 1891 validateString: function (value, requirement, parsleyInstance) { 1892 1893 var file = parsleyInstance.$element[0].files; 1894 var maxBytes = requirement * 1048576; 1895 1896 if (file.length == 0) { 1897 return true; 1898 } 1899 1900 var files_data = []; 1901 $(file).each(function(i,v){ 1902 if (v.size > maxBytes) { 1903 files_data.push(v.size); 1904 } 1905 }); 1906 1907 return files_data.length === 0; 1908 1909 }, 1910 messages: { 1911 en: 'File is to big. Maximum allowed size is %s MB.', 1912 nl: 'Het bestand is te groot, de maximale bestandsgrootte is %s MB.' 1913 } 1914 }) 1915 .addValidator('maxfiles', { 1916 requirementType: 'string', 1917 validateString: function (value, requirement, parsleyInstance) { 1918 1919 var file = parsleyInstance.$element[0].files; 1920 1921 if (file.length == 0) { 1922 return true; 1923 } 1924 1925 return file.length <= requirement; 1926 1927 }, 1928 messages: { 1929 en: 'Maximum of files can be uploaded at once is %s.', 1930 nl: 'Het maximum aantal bestanden dat tegelijkertijd verstuurd mag worden is %s. ' 1931 } 1932 }) 1933 .addValidator('filemimetypes', { 1934 requirementType: 'string', 1935 validateString: function (value, requirement, parsleyInstance) { 1936 1937 var file = parsleyInstance.$element[0].files; 1938 1939 if (file.length == 0) { 1940 return true; 1941 } 1942 1943 var allowedMimeTypes = requirement.replace(/\s/g, "").split(','); 1944 var files_data = []; 1945 1946 $(file).each(function(k,v){ 1947 1948 if (allowedMimeTypes.indexOf(v.type) == -1) { 1949 files_data.push(allowedMimeTypes.indexOf(v.type) == -1); 1950 } 1951 1952 }); 1953 1954 return files_data.length === 0; 1955 }, 1956 messages: { 1957 en: 'File mime type not allowed.' 1958 } 1959 }) 1960 .addValidator('postcode', { 1961 requirementType: 'string', 1962 validateString: function(value, requirement, parsleyInstance) { 1963 var postcode = parsleyInstance.value.match(/^\d{4}\s?\w{2}$/g); 1964 1965 return postcode !== null; 1966 }, 1967 messages: {
1968 en: 'The postcode entered is invalid, the format should be 1234AB.', 1969 nl: 'De ingevulde postcode is niet correct, en moet formaat 1234AB hebben.' 1970 } 1971 }) 1972 .addValidator('date', { 1973 requirementType: 'string', 1974 validateString: function (value, requirement, parsleyInstance) { 1975 1976 var reqs = value.split("-"), 1977 day = reqs[0], 1978 month = reqs[1], 1979 year = reqs[2].substring(0, 4); 1980 1981 // check if date is a valid 1982 var checkdate = new Date(year + "-" + month + "-" + day); 1983 return Boolean(+checkdate) && parseInt(checkdate.getDate(), 10) === parseInt( day, 10); 1984 1985 }, 1986 messages: { 1987 en: 'The date entered is invalid, the format should be DD-MM-YYYY.', 1988 nl: 'De ingevulde datum is niet correct, en moet formaat DD-MM-JJJJ hebben.' 1989 } 1990 }) 1991 .addValidator('open', { 1992 requirementType: 'string', 1993 validateString: function (value, requirement, parsleyInstance) { 1994 1995 let actualValue = $(parsleyInstance.$element).parents('.pt-uea-container-amount').siblings('.pt-uea-custom-amount-formatted').attr('data-pt-price'); 1996 1997 value = value.toString(); 1998 value = parseFloat(value.replace(/,/g, '.')); 1999 2000 requirement = requirement.toString(); 2001 requirement = parseFloat(requirement.replace(/,/g, '.')); 2002 2003 if (requirement <= value && value == actualValue) { 2004 return true; 2005 } 2006 return false; 2007 2008 }, 2009 messages: { 2010 en: 'The minimum amount is '+currencySymbol+'%s.', 2011 nl: 'Het minimum bedrag is '+currencySymbol+'%s.' 2012 } 2013 }) 2014 .addValidator('mintotal', { 2015 requirementType: 'string', 2016 validateString: function (value, requirement, parsleyInstance) { 2017 return parseFloat(value) >= requirement; 2018 }, 2019 messages: { 2020 en: 'The minimum amount is '+currencySymbol+'%s.', 2021 nl: 'Het minimum bedrag is '+currencySymbol+'%s.' 2022 } 2023 }) 2024 .addValidator('phone', { 2025 requirementType: 'string', 2026 validateString: function (value, requirement, parsleyInstance) { 2027 2028 if (value.match('^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\\s\\.0-9]*$')) { 2029 return true; 2030 } 2031 else { 2032 return false; 2033 } 2034 }, 2035 messages: { 2036 en: 'Please enter a valid phone number', 2037 nl: 'Voer alstublieft een geldig telefoonnummer in' 2038 } 2039 }); 2040 2041 2042 $(document).ready(function () { 2043 // Remove message after payment if more then once is shown 2044 $('.pt-payment-details-wrap').eq(1).remove(); 2045 2046 // Paytium login 2047 $('body').on('click', '.paytium-login-btn', function () { 2048 $('.paytium-login-form-overlay').fadeIn(200); 2049 $('html').addClass('paytium-overflow-hidden') 2050 }); 2051 2052 $('body').on('click', '.paytium-login-close', function () { 2053 $('.paytium-login-form-overlay').fadeOut(200); 2054 $('html').removeClass('paytium-overflow-hidden') 2055 }); 2056 2057 $('body').on('click', '.paytium-login-form-wrapper', function (e) { 2058 if ($(e.target).is('.paytium-login-form-wrapper')) { 2059 $('.paytium-login-form-overlay').fadeOut(200); 2060 $('html').removeClass('paytium-overflow-hidden') 2061 } 2062 }); 2063 2064 /* paytium custom quantity input */ 2065 $('body').on('click', '.paytium-spinner.increment', function () { 2066 let input = $(this).siblings('.pt-quantity-input[type=number]'), 2067 val = parseInt(input.val()), 2068 max = input.attr('max') ? parseInt(input.attr('max')) : '', 2069 step = input.attr('step') ? parseInt(input.attr('step')) : 1; 2070 2071 if ((max && val+step <= max) || !max) { 2072 input.val(val+step).trigger('change'); 2073 } 2074 }); 2075 $('body').on('click', '.paytium-spinner.decrement', function () { 2076 let input = $(this).siblings('.pt-quantity-input[type=number]'), 2077 val = parseInt(input.val()), 2078 min = input.attr('min') ? parseInt(input.attr('min')) : '', 2079 step = input.attr('step') ? parseInt(input.attr('step')) : 1; 2080 2081 if ((min && val-step >= min) || (!min && val-step >= 0)) { 2082 input.val(val-step).trigger('change'); 2083 } 2084 }); 2085 }); 2086 2087 function getCurrencySymbol(currencyCode) { 2088 var currencies = { 2089 EUR: 'â¬', 2090 USD: '$', 2091 GBP: '£', 2092 CHF: 'fr.', 2093 NOK: 'NOK', 2094 SEK: 'SEK' 2095 }; 2096 return currencies[currencyCode]; 2097 } 2098}(jQuery));
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.