1 2// "prop" method fix for previous versions of jQuery (1.5 and below) 3if( typeof jQuery.fn.prop === 'undefined' ) { 4 jQuery.fn.prop = jQuery.fn.attr; 5} 6 7jQuery(document).ready(function(){ 8 //Formatting free form currency fields to currency 9 jQuery(document).bind('gform_post_render', gformBindFormatPricingFields); 10}); 11 12function gformBindFormatPricingFields(){ 13 // Namespace the event and remove before adding to prevent double binding. 14 jQuery(".ginput_amount, .ginput_donation_amount").off('change.gform').on("change.gform", function(){ 15 gformFormatPricingField(this); 16 }); 17 18 jQuery(".ginput_amount, .ginput_donation_amount").each(function(){ 19 gformFormatPricingField(this); 20 }); 21} 22 23//------------------------------------------------ 24//---------- CURRENCY ---------------------------- 25//------------------------------------------------ 26function Currency(currency){ 27 this.currency = currency; 28 29 this.toNumber = function(text){ 30 31 if(this.isNumeric(text)) { 32 return parseFloat(text); 33 } 34 35 return gformCleanNumber(text, this.currency["symbol_right"], this.currency["symbol_left"], this.currency["decimal_separator"]); 36 }; 37 38 /** 39 * Attempts to clean the specified number and formats it as currency. 40 * 41 * @since 2.1.1.16 Allow the overriding of numerical checks. 42 * 43 * @param number int Number to be formatted. It can be a clean number, or an already formatted number. 44 * @param isNumeric bool Whether or not the number is guaranteed to be a clean, unformatted number. 45 * When false the function will attempt to clean the number. Defaults to false. 46 * 47 * @return string A number formatted as currency. 48 */ 49 this.toMoney = function(number, isNumeric){ 50 51 isNumeric = isNumeric || false; //isNumeric is an optional parameter. Defaults to false 52 53 if( ! isNumeric ) { 54 //Cleaning number, removing all formatting 55 number = gformCleanNumber(number, this.currency["symbol_right"], this.currency["symbol_left"], this.currency["decimal_separator"]); 56 } 57 58 if(number === false) { 59 return ""; 60 } 61 62 number = number + ""; 63 negative = ""; 64 if(number[0] == "-"){ 65 66 number = parseFloat(number.substr(1)); 67 negative = '-'; 68 } 69 70 money = this.numberFormat(number, this.currency["decimals"], this.currency["decimal_separator"], this.currency["thousand_separator"]); 71 72 if ( money == '0.00' ){ 73 negative = ''; 74 } 75 76 var symbol_left = this.currency["symbol_left"] ? this.currency["symbol_left"] + this.currency["symbol_padding"] : ""; 77 var symbol_right = this.currency["symbol_right"] ? this.currency["symbol_padding"] + this.currency["symbol_right"] : ""; 78 79 money = negative + this.htmlDecode(symbol_left) + money + this.htmlDecode(symbol_right); 80 81 return money; 82 }; 83 84 85 /** 86 * Formats a number given the specified parameters. 87 * 88 * @since Unknown 89 * 90 * @param number int Number to be formatted. Must be a clean, unformatted format. 91 * @param decimals int Number of decimals that the output should contain. 92 * @param dec_point string Character to use as the decimal separator. Defaults to ".". 93 * @param thousands_sep string Character to use as the thousand separator. Defaults to ",". 94 * @param padded bool Pads output with zeroes if the number is exact. For example, 1.200. 95 * 96 * @return string The formatted number. 97 */ 98 this.numberFormat = function(number, decimals, dec_point, thousands_sep, padded){ 99 100 var padded = typeof padded == 'undefined'; 101 number = (number+'').replace(',', '').replace(' ', ''); 102 var n = !isFinite(+number) ? 0 : +number, 103 prec = !isFinite(+decimals) ? 0 : Math.abs(decimals), 104 sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep, dec = (typeof dec_point === 'undefined') ? '.' : dec_point, 105 s = '', 106 107 toFixedFix = function (n, prec) { 108 var k = Math.pow(10, prec); 109 return '' + Math.round(n * k) / k; 110 }; 111 112 if(decimals == '0') { 113 114 n = n + 0.0000000001; // getting around floating point arithmetic issue when rounding. ( i.e. 4.005 is represented as 4.004999999999 and gets rounded to 4.00 instead of 4.01 ) 115 116 s = ('' + Math.round(n)).split('.'); 117 } else 118 if(decimals == -1) { 119 s = ('' + n).split('.'); 120 } else { 121 122 n = n + 0.0000000001; // getting around floating point arithmetic issue when rounding. ( i.e. 4.005 is represented as 4.004999999999 and gets rounded to 4.00 instead of 4.01 ) 123 124 // Fix for IE parseFloat(0.55).toFixed(0) = 0; 125 s = toFixedFix(n, prec).split('.'); 126 } 127 128 if (s[0].length > 3) { 129 s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep); 130 } 131 132 if(padded) { 133 if ((s[1] || '').length < prec) { 134 s[1] = s[1] || ''; 135 s[1] += new Array(prec - s[1].length + 1).join('0'); 136 } 137 } 138 139 return s.join(dec); 140 } 141 142 this.isNumeric = function(number){ 143 return gformIsNumber(number); 144 }; 145 146 this.htmlDecode = function(text) { 147 var c,m,d = text; 148 149 // look for numerical entities " 150 var arr=d.match(/&#[0-9]{1,5};/g); 151 152 // if no matches found in string then skip 153 if(arr!=null){ 154 for(var x=0;x<arr.length;x++){ 155 m = arr[x]; 156 c = m.substring(2,m.length-1); //get numeric part which is refernce to unicode character 157 // if its a valid number we can decode 158 if(c >= -32768 && c <= 65535){ 159 // decode every single match within string 160 d = d.replace(m, String.fromCharCode(c)); 161 }else{ 162 d = d.replace(m, ""); //invalid so replace with nada 163 } 164 } 165 } 166 return d; 167 }; 168} 169 170/** 171 * Gets a formatted number and returns a clean "decimal dot" number. 172 *
173 * Note: Input must be formatted according to the specified parameters (symbol_right, symbol_left, decimal_separator). 174 * @example input -> $1.20, output -> 1.2 175 * 176 * @since 2.1.1.16 Modified to support additional param in Currency.toMoney. 177 * 178 * @param text string The currency-formatted number. 179 * @param symbol_right string The symbol used on the right. 180 * @param symbol_left string The symbol used on the left. 181 * @param decimal_separator string The decimal separator being used. 182 * 183 * @return float The unformatted numerical value. 184 */ 185function gformCleanNumber(text, symbol_right, symbol_left, decimal_separator){ 186 var clean_number = '', 187 float_number = '', 188 digit = '', 189 is_negative = false; 190 191 //converting to a string if a number as passed 192 text = text + " "; 193 194 //Removing symbol in unicode format (i.e. ᅜ) 195 text = text.replace(/&.*?;/g, ""); 196 197 //Removing symbol from text 198 text = text.replace(symbol_right, ""); 199 text = text.replace(symbol_left, ""); 200 201 //Removing all non-numeric characters 202 for(var i=0; i<text.length; i++){ 203 digit = text.substr(i,1); 204 if( (parseInt(digit,10) >= 0 && parseInt(digit,10) <= 9) || digit == decimal_separator ) 205 clean_number += digit; 206 else if(digit == '-') 207 is_negative = true; 208 } 209 210 //Removing thousand separators but keeping decimal point 211 for(var i=0; i<clean_number.length; i++) { 212 digit = clean_number.substr(i,1); 213 if (digit >= '0' && digit <= '9') 214 float_number += digit; 215 else if(digit == decimal_separator){ 216 float_number += "."; 217 } 218 } 219 220 if(is_negative) 221 float_number = "-" + float_number; 222 223 return gformIsNumber(float_number) ? parseFloat(float_number) : false; 224} 225 226function gformGetDecimalSeparator(numberFormat){ 227 var s; 228 switch (numberFormat){ 229 case 'currency' : 230 var currency = new Currency(gf_global.gf_currency_config); 231 s = currency.currency["decimal_separator"]; 232 break; 233 case 'decimal_comma' : 234 s = ','; 235 break; 236 default : 237 s = "." 238 } 239 return s; 240} 241 242function gformIsNumber(n) { 243 return !isNaN(parseFloat(n)) && isFinite(n); 244} 245 246function gformIsNumeric(value, number_format){ 247 248 switch(number_format){ 249 case "decimal_dot" : 250 var r = new RegExp("^(-?[0-9]{1,3}(?:,?[0-9]{3})*(?:\.[0-9]+)?)$"); 251 return r.test(value); 252 break; 253 254 case "decimal_comma" : 255 var r = new RegExp("^(-?[0-9]{1,3}(?:\.?[0-9]{3})*(?:,[0-9]+)?)$"); 256 return r.test(value); 257 break; 258 } 259 return false; 260} 261 262//------------------------------------------------ 263//---------- MULTI-PAGE -------------------------- 264//------------------------------------------------ 265function gformDeleteUploadedFile(formId, fieldId, deleteButton){ 266 var parent = jQuery("#field_" + formId + "_" + fieldId); 267 268 var fileIndex = jQuery(deleteButton).parent().index(); 269 270 parent.find(".ginput_preview").eq(fileIndex).remove(); 271 272 //displaying single file upload field 273 parent.find('input[type="file"],.validation_message,#extensions_message_' + formId + '_' + fieldId).removeClass("gform_hidden"); 274 275 //displaying post image label 276 parent.find(".ginput_post_image_file").show(); 277 278 //clearing post image meta fields 279 parent.find("input[type=\"text\"]").val(''); 280 281 //removing file from uploaded meta 282 var filesJson = jQuery('#gform_uploaded_files_' + formId).val(); 283 284 if(filesJson){ 285 var files = jQuery.secureEvalJSON(filesJson); 286 if(files) { 287 var inputName = "input_" + fieldId; 288 var $multfile = parent.find("#gform_multifile_upload_" + formId + "_" + fieldId ); 289 if( $multfile.length > 0 ) { 290 files[inputName].splice(fileIndex, 1); 291 var settings = $multfile.data('settings'); 292 var max = settings.gf_vars.max_files; 293 jQuery("#" + settings.gf_vars.message_id).html(''); 294 if(files[inputName].length < max) 295 gfMultiFileUploader.toggleDisabled(settings, false); 296 297 } else { 298 files[inputName] = null; 299 } 300 301 jQuery('#gform_uploaded_files_' + formId).val(jQuery.toJSON(files)); 302 } 303 } 304} 305 306 307//------------------------------------------------ 308//---------- PRICE ------------------------------- 309//------------------------------------------------ 310var _gformPriceFields = new Array(); 311var _anyProductSelected; 312 313function gformIsHidden(element){ 314 return element.parents('.gfield').not(".gfield_hidden_product").css("display") == "none"; 315} 316 317function gformCalculateTotalPrice(formId){ 318 319 if(!_gformPriceFields[formId]) 320 return; 321 322 var price = 0; 323 324 _anyProductSelected = false; //Will be used by gformCalculateProductPrice(). 325 for(var i=0; i<_gformPriceFields[formId].length; i++){ 326 price += gformCalculateProductPrice(formId, _gformPriceFields[formId][i]); 327 } 328 329 //add shipping price if a product has been selected 330 if(_anyProductSelected){ 331 //shipping price 332 var shipping = gformGetShippingPrice(formId) 333 price += shipping; 334 } 335 336 //gform_product_total filter. Allows uers to perform custom price calculation 337 if(window["gform_product_total"]) 338 price = window["gform_product_total"](formId, price); 339 340 341 price = gform.applyFilters('gform_product_total', price, formId); 342 343 //updating total 344 var totalElement = jQuery(".ginput_total_" + formId); 345 if( totalElement.length > 0 ) { 346 347 var currentTotal = totalElement.next().val(), 348 formattedTotal = gformFormatMoney(price, true); 349 350 if (currentTotal != price) { 351 totalElement.next().val(price).change(); 352 } 353 354 if (formattedTotal != totalElement.first().text()) { 355 totalElement.html(formattedTotal); 356 } 357 358 } 359} 360 361function gformGetShippingPrice(formId){ 362 var shippingField = jQuery(".gfield_shipping_" + formId + " input[type=\"hidden\"], .gfield_shipping_" + formId + " select, .gfield_shipping_" + formId + " input:checked"); 363 var shipping = 0; 364 if(shippingField.length == 1 && !gformIsHidden(shippingField)){ 365 if(shippingField.attr("type") && shippingField.attr("type").toLowerCase() == "hidden") 366 shipping = shippingField.val(); 367 else 368 shipping = gformGetPrice(shippingField.val()); 369 } 370 371 return gformToNumber(shipping); 372} 373 374function gformGetFieldId(element){ 375 var id = jQuery(element).attr("id"); 376 var pieces = id.split("_"); 377 if(pieces.length <=0) 378 return 0; 379 380 var fieldId = pieces[pieces.length-1]; 381 return fieldId; 382 383} 384 385function gformCalculateProductPrice(form_id, productFieldId){ 386 387 var suffix = '_' + form_id + '_' + productFieldId; 388 389 390 //Drop down auto-calculating labels 391 jQuery('.gfield_option' + suffix + ', .gfield_shipping_' + form_id).find('select').each(function(){ 392 393 var dropdown_field = jQuery(this); 394 var selected_price = gformGetPrice(dropdown_field.val()); 395 var field_id = dropdown_field.attr('id').split('_')[2]; 396 dropdown_field.children('option').each(function(){ 397 var choice_element = jQuery(this);
398 var label = gformGetOptionLabel(choice_element, choice_element.val(), selected_price, form_id, field_id); 399 choice_element.html(label); 400 }); 401 }); 402 403 404 //Checkboxes labels with prices 405 jQuery('.gfield_option' + suffix).find('.gfield_checkbox').find('input:checkbox').each(function(){ 406 var checkbox_item = jQuery(this); 407 var id = checkbox_item.attr('id'); 408 var field_id = id.split('_')[2]; 409 var label_id = id.replace('choice_', '#label_'); 410 var label_element = jQuery(label_id); 411 var label = gformGetOptionLabel(label_element, checkbox_item.val(), 0, form_id, field_id); 412 label_element.html(label); 413 }); 414 415 416 //Radio button auto-calculating lables 417 jQuery('.gfield_option' + suffix + ', .gfield_shipping_' + form_id).find('.gfield_radio').each(function(){ 418 var selected_price = 0; 419 var radio_field = jQuery(this); 420 var id = radio_field.attr('id'); 421 var fieldId = id.split('_')[2]; 422 var selected_value = radio_field.find('input:radio:checked').val(); 423 424 if(selected_value) 425 selected_price = gformGetPrice(selected_value); 426 427 radio_field.find('input:radio').each(function(){ 428 var radio_item = jQuery(this); 429 var label_id = radio_item.attr('id').replace('choice_', '#label_'); 430 var label_element = jQuery(label_id); 431 if ( label_element ) { 432 var label = gformGetOptionLabel(label_element, radio_item.val(), selected_price, form_id, fieldId); 433 label_element.html(label); 434 } 435 }); 436 }); 437 438 var price = gformGetBasePrice(form_id, productFieldId); 439 var quantity = gformGetProductQuantity( form_id, productFieldId ); 440 441 //calculating options if quantity is more than 0 (a product was selected). 442 if( quantity > 0 ) { 443 444 jQuery('.gfield_option' + suffix).find('input:checked, select').each(function(){ 445 if(!gformIsHidden(jQuery(this))) 446 price += gformGetPrice(jQuery(this).val()); 447 }); 448 449 //setting global variable if quantity is more than 0 (a product was selected). Will be used when calculating total 450 _anyProductSelected = true; 451 } 452 453 price = price * quantity; 454 455 price = gformRoundPrice(price) ; 456 457 458 return price; 459} 460 461 462function gformGetProductQuantity(formId, productFieldId) { 463 464 //If product is not selected 465 if (!gformIsProductSelected(formId, productFieldId)) { 466 return 0; 467 } 468 469 var quantity, 470 quantityInput = jQuery('#ginput_quantity_' + formId + '_' + productFieldId), 471 numberFormat; 472 473 if (gformIsHidden(quantityInput)) { 474 return 0; 475 } 476 477 if (quantityInput.length > 0) { 478 479 quantity = quantityInput.val(); 480 481 } else { 482 483 quantityInput = jQuery('.gfield_quantity_' + formId + '_' + productFieldId + ' :input'); 484 quantity = 1; 485 486 if (quantityInput.length > 0) { 487 quantity = quantityInput.val(); 488 489 var htmlId = quantityInput.attr('id'), 490 fieldId = gf_get_input_id_by_html_id(htmlId); 491 492 numberFormat = gf_get_field_number_format( fieldId, formId, 'value' ); 493 } 494 495 } 496 497 if (!numberFormat) 498 numberFormat = 'currency'; 499 500 var decimalSeparator = gformGetDecimalSeparator(numberFormat); 501 502 quantity = gformCleanNumber(quantity, '', '', decimalSeparator); 503 if (!quantity) 504 quantity = 0; 505 506 return quantity; 507} 508 509 510function gformIsProductSelected( formId, productFieldId ) { 511 512 var suffix = "_" + formId + "_" + productFieldId; 513 514 var productField = jQuery("#ginput_base_price" + suffix + ", .gfield_donation" + suffix + " input[type=\"text\"], .gfield_product" + suffix + " .ginput_amount"); 515 if( productField.val() && ! gformIsHidden(productField) ){ 516 return true; 517 } 518 else 519 { 520 productField = jQuery(".gfield_product" + suffix + " select, .gfield_product" + suffix + " input:checked, .gfield_donation" + suffix + " select, .gfield_donation" + suffix + " input:checked"); 521 if( productField.val() && ! gformIsHidden(productField) ){ 522 return true; 523 } 524 } 525 526 return false; 527} 528 529function gformGetBasePrice(formId, productFieldId){ 530 531 var suffix = "_" + formId + "_" + productFieldId; 532 var price = 0; 533 var productField = jQuery("#ginput_base_price" + suffix+ ", .gfield_donation" + suffix + " input[type=\"text\"], .gfield_product" + suffix + " .ginput_amount"); 534 if(productField.length > 0){ 535 price = productField.val(); 536 537 //If field is hidden by conditional logic, don't count it for the total 538 if(gformIsHidden(productField)){ 539 price = 0; 540 } 541 } 542 else 543 { 544 productField = jQuery(".gfield_product" + suffix + " select, .gfield_product" + suffix + " input:checked, .gfield_donation" + suffix + " select, .gfield_donation" + suffix + " input:checked"); 545 var val = productField.val(); 546 if(val){ 547 val = val.split("|"); 548 price = val.length > 1 ? val[1] : 0; 549 } 550 551 //If field is hidden by conditional logic, don't count it for the total 552 if(gformIsHidden(productField)) 553 price = 0; 554 555 } 556 557 var c = new Currency(gf_global.gf_currency_config); 558 price = c.toNumber(price); 559 return price === false ? 0 : price; 560} 561 562function gformFormatMoney(text, isNumeric){ 563 if(!gf_global.gf_currency_config) 564 return text; 565 566 var currency = new Currency(gf_global.gf_currency_config); 567 return currency.toMoney(text, isNumeric); 568} 569 570function gformFormatPricingField(element){ 571 if(gf_global.gf_currency_config){ 572 var currency = new Currency(gf_global.gf_currency_config); 573 var price = currency.toMoney(jQuery(element).val()); 574 jQuery(element).val(price); 575 } 576} 577 578function gformToNumber(text){ 579 var currency = new Currency(gf_global.gf_currency_config); 580 return currency.toNumber(text); 581} 582 583function gformGetPriceDifference(currentPrice, newPrice){ 584 585 //getting price difference 586 var diff = parseFloat(newPrice) - parseFloat(currentPrice); 587 price = gformFormatMoney(diff, true); 588 if(diff > 0) 589 price = "+" + price; 590 591 return price; 592} 593 594function gformGetOptionLabel(element, selected_value, current_price, form_id, field_id){ 595 element = jQuery(element); 596 var price = gformGetPrice(selected_value); 597 var current_diff = element.attr('price'); 598 var original_label = element.html().replace(/<span(.*)<\/span>/i, "").replace(current_diff, ""); 599 600 var diff = gformGetPriceDifference(current_price, price); 601 diff = gformToNumber(diff) == 0 ? "" : " " + diff; 602 element.attr('price', diff); 603 604 //don't add <span> for drop down items (not supported) 605 var price_label = element[0].tagName.toLowerCase() == "option" ? " " + diff : "<span class='ginput_price'>" + diff + "</span>"; 606 var label = original_label + price_label; 607 608 //calling hook to allow for custom option formatting 609 if(window["gform_format_option_label"]) 610 label = gform_format_option_label(label, original_label, price_label, current_price, price, form_id, field_id); 611 612 return label; 613} 614 615function gformGetProductIds(parent_class, element){ 616 var classes = jQuery(element).hasClass(parent_class) ? jQuery(element).attr("class").split(" ") : jQuery(element).parents("." + parent_class).attr("class").split(" "); 617 for(var i=0; i<classes.length; i++){ 618 if(classes[i].substr(0, parent_class.length) == parent_class && classes[i] != parent_class) 619 return {formId: classes[i].split("_")[2], productFieldId: classes[i].split("_")[3]}; 620 } 621 return {formId:0, fieldId:0}; 622} 623 624function gformGetPrice(text){ 625 var val = text.split("|"); 626 var currency = new Currency(gf_global.gf_currency_config); 627 628 if(val.length > 1 && currency.toNumber(val[1]) !== false) 629 return currency.toNumber(val[1]); 630 631 return 0; 632} 633 634function gformRoundPrice(price){ 635 636 var currency = new Currency(gf_global.gf_currency_config); 637 var roundedPrice = currency.numberFormat( price, currency.currency['decimals'], '.', '' ); 638 639 return parseFloat( roundedPrice ); 640} 641 642function gformRegisterPriceField(item){ 643 644 if(!_gformPriceFields[item.formId]) 645 _gformPriceFields[item.formId] = new Array(); 646 647 //ignore price fields that have already been registered 648 for(var i=0; i<_gformPriceFields[item.formId].length; i++) 649 if(_gformPriceFields[item.formId][i] == item.productFieldId) 650 return; 651 652 //registering new price field 653 _gformPriceFields[item.formId].push(item.productFieldId); 654} 655 656function gformInitPriceFields(){ 657 658 jQuery(".gfield_price").each(function(){ 659 660 var productIds = gformGetProductIds("gfield_price", this); 661 gformRegisterPriceField(productIds); 662 663 jQuery( this ).on( 'change', 'input[type="text"], input[type="number"], select', function() { 664 665 var productIds = gformGetProductIds("gfield_price", this); 666 if(productIds.formId == 0) 667 productIds = gformGetProductIds("gfield_shipping", this); 668 669 jQuery(document).trigger('gform_price_change', [productIds, this]); 670 gformCalculateTotalPrice(productIds.formId); 671 }); 672 673 jQuery( this ).on( 'click', 'input[type="radio"], input[type="checkbox"]', function() { 674 675 var productIds = gformGetProductIds("gfield_price", this); 676 if(productIds.formId == 0) 677 productIds = gformGetProductIds("gfield_shipping", this); 678 679 jQuery(document).trigger('gform_price_change', [productIds, this]); 680 gformCalculateTotalPrice(productIds.formId); 681 }); 682 683 }); 684 685 for(formId in _gformPriceFields){ 686 687 //needed when implementing for in loops 688 if(!_gformPriceFields.hasOwnProperty(formId)) 689 continue; 690 691 gformCalculateTotalPrice(formId); 692 } 693 694} 695 696 697//------------------------------------------- 698//---------- PASSWORD ----------------------- 699//------------------------------------------- 700function gformShowPasswordStrength(fieldId){ 701 var password = document.getElementById( fieldId ).value, 702 confirm = document.getElementById( fieldId + '_2' ) ? document.getElementById( fieldId + '_2' ).value : ''; 703 704 var result = gformPasswordStrength( password, confirm ), 705 text = window[ 'gf_text' ][ "password_" + result ], 706 resultClass = result === 'unknown' ? 'blank' : result; 707 708 jQuery("#" + fieldId + "_strength").val(result);
709 jQuery("#" + fieldId + "_strength_indicator").removeClass("blank mismatch short good bad strong").addClass(resultClass).html(text); 710} 711 712// Password strength meter 713function gformPasswordStrength( password1, password2 ) { 714 715 if ( password1.length <= 0 ) { 716 return 'blank'; 717 } 718 719 var strength = wp.passwordStrength.meter( password1, wp.passwordStrength.userInputBlacklist(), password2 ); 720 721 switch ( strength ) { 722 723 case -1: 724 return 'unknown'; 725 726 case 2: 727 return 'bad'; 728 729 case 3: 730 return 'good'; 731 732 case 4: 733 return 'strong'; 734 735 case 5: 736 return 'mismatch'; 737 738 default: 739 return 'short'; 740 741 } 742 743} 744 745function gformToggleShowPassword( fieldId ) { 746 var $password = jQuery( '#' + fieldId ), 747 $button = $password.parent().find( 'button' ), 748 $icon = $button.find( 'span' ), 749 currentType = $password.attr( 'type' ); 750 751 switch ( currentType ) { 752 case 'password': 753 $password.attr( 'type', 'text' ); 754 $button.attr( 'label', $button.attr( 'data-label-hide' ) ); 755 $icon.removeClass( 'dashicons-hidden' ).addClass( 'dashicons-visibility' ); 756 break; 757 case 'text': 758 $password.attr( 'type', 'password' ); 759 $button.attr( 'label', $button.attr( 'data-label-show' ) ); 760 $icon.removeClass( 'dashicons-visibility' ).addClass( 'dashicons-hidden' ); 761 break; 762 } 763} 764 765//---------------------------- 766//------ CHECKBOX FIELD ------ 767//---------------------------- 768 769function gformToggleCheckboxes( toggleCheckbox ) { 770 771 var $toggle = jQuery( toggleCheckbox ).parent(), 772 $toggleLabel = $toggle.find( 'label' ), 773 $checkboxes = $toggle.parent().find( 'li:not( .gchoice_select_all )' ), 774 formId = gf_get_form_id_by_html_id( $toggle.parents( '.gfield' ).attr( 'id' ) ), 775 calcObj = rgars( window, 'gf_global/gfcalc/' + formId ); 776 777 // Set checkboxes state. 778 $checkboxes.each( function() { 779 780 // Set checkbox checked state. 781 jQuery( 'input[type="checkbox"]', this ).prop( 'checked', toggleCheckbox.checked ).trigger( 'change' ); 782 783 // Execute onclick event. 784 if ( typeof jQuery( 'input[type="checkbox"]', this )[0].onclick === 'function' ) { 785 jQuery( 'input[type="checkbox"]', this )[0].onclick(); 786 } 787 788 } ); 789 790 // Change toggle label. 791 if ( toggleCheckbox.checked ) { 792 $toggleLabel.html( $toggleLabel.data( 'label-deselect' ) ); 793 } else { 794 $toggleLabel.html( $toggleLabel.data( 'label-select' ) ); 795 } 796 797 if ( calcObj ) { 798 calcObj.runCalcs( formId, calcObj.formulaFields ); 799 } 800 801} 802 803 804//---------------------------- 805//------ LIST FIELD ---------- 806//---------------------------- 807 808function gformAddListItem( addButton, max ) { 809 810 var $addButton = jQuery( addButton ); 811 812 if( $addButton.hasClass( 'gfield_icon_disabled' ) ) { 813 return; 814 } 815 816 var $group = $addButton.parents( '.gfield_list_group' ), 817 $clone = $group.clone(), 818 $container = $group.parents( '.gfield_list_container' ), 819 tabindex = $clone.find( ':input:last' ).attr( 'tabindex' ); 820 821 // reset all inputs to empty state 822 $clone
823 .find( 'input, select, textarea' ).attr( 'tabindex', tabindex ) 824 .not( ':checkbox, :radio' ).val( '' ); 825 $clone.find( ':checkbox, :radio' ).prop( 'checked', false ); 826 827 $clone = gform.applyFilters( 'gform_list_item_pre_add', $clone, $group ); 828 829 $group.after( $clone ); 830 831 gformToggleIcons( $container, max ); 832 gformAdjustClasses( $container ); 833 834 gform.doAction( 'gform_list_post_item_add', $clone, $container ); 835 836} 837 838function gformDeleteListItem( deleteButton, max ) { 839 840 var $deleteButton = jQuery( deleteButton ), 841 $group = $deleteButton.parents( '.gfield_list_group' ), 842 $container = $group.parents( '.gfield_list_container' ); 843 844 $group.remove(); 845 846 gformToggleIcons( $container, max ); 847 gformAdjustClasses( $container ); 848 849 gform.doAction( 'gform_list_post_item_delete', $container ); 850 851} 852 853function gformAdjustClasses( $container ) { 854 855 var $groups = $container.find( '.gfield_list_group' ); 856 857 $groups.each( function( i ) { 858 859 var $group = jQuery( this ), 860 oddEvenClass = ( i + 1 ) % 2 == 0 ? 'gfield_list_row_even' : 'gfield_list_row_odd'; 861 862 $group.removeClass( 'gfield_list_row_odd gfield_list_row_even' ).addClass( oddEvenClass ); 863 864 } ); 865 866} 867 868function gformToggleIcons( $container, max ) { 869 870 var groupCount = $container.find( '.gfield_list_group' ).length, 871 $addButtons = $container.find( '.add_list_item' ); 872 873 $container.find( '.delete_list_item' ).css( 'visibility', groupCount == 1 ? 'hidden' : 'visible' ); 874 875 if ( max > 0 && groupCount >= max ) { 876 877 // store original title in the add button 878 $addButtons.data( 'title', $container.find( '.add_list_item' ).attr( 'title' ) ); 879 $addButtons.addClass( 'gfield_icon_disabled' ).attr( 'title', '' ); 880 881 } else if( max > 0 ) { 882 883 $addButtons.removeClass( 'gfield_icon_disabled' ); 884 885 if( $addButtons.data( 'title' ) ) { 886 $addButtons.attr( 'title', $addButtons.data( 'title' ) ); 887 } 888 889 } 890} 891 892//----------------------------------- 893//--------- REPEATER FIELD ---------- 894//----------------------------------- 895 896function gformAddRepeaterItem( addButton, max ) { 897 898 var $addButton = jQuery( addButton ); 899 900 if( $addButton.hasClass( 'gfield_icon_disabled' ) ) { 901 return; 902 } 903 904 var $item = $addButton.closest( '.gfield_repeater_item' ), 905 $clone = $item.clone(), 906 $container = $item.closest( '.gfield_repeater_container' ), 907 tabindex = $clone.find( ':input:last' ).attr( 'tabindex' ); 908 909 // reset all inputs to empty state 910 $clone 911 .find( 'input[type!="hidden"], select, textarea' ).attr( 'tabindex', tabindex ) 912 .not( ':checkbox, :radio' ).val( '' ); 913 $clone.find( ':checkbox, :radio' ).prop( 'checked', false ); 914 $clone.find('.validation_message').remove(); 915 916 $clone = gform.applyFilters( 'gform_repeater_item_pre_add', $clone, $item ); 917 918 $item.after( $clone ); 919 920 var $cells = $clone.children('.gfield_repeater_cell'); 921 $cells.each(function () { 922 var $subContainer = jQuery(this).find('.gfield_repeater_container').first(); 923 if ($subContainer.length > 0) { 924 resetContainerItems = function ($c) { 925 $c.children('.gfield_repeater_items').children('.gfield_repeater_item').each(function (i) { 926 var $children = jQuery(this).children('.gfield_repeater_cell'); 927 $children.each(function () { 928 var $subSubContainer = jQuery(this).find('.gfield_repeater_container').first(); 929 if ($subSubContainer.length > 0) { 930 resetContainerItems($subSubContainer); 931 } 932 }) 933 }) 934 $c.children('.gfield_repeater_items').children('.gfield_repeater_item').not(':first').remove(); 935 } 936 resetContainerItems($subContainer); 937 } 938 }) 939 940 gformResetRepeaterAttributes($container); 941 942 if ( typeof gformInitDatepicker == 'function' ) { 943 $container.find('.ui-datepicker-trigger').remove(); 944 $container.find('.hasDatepicker').removeClass('hasDatepicker'); 945 gformInitDatepicker(); 946 } 947 948 gformBindFormatPricingFields(); 949 950 gformToggleRepeaterButtons( $container, max ); 951 952 gform.doAction('gform_repeater_post_item_add', $clone, $container); 953 954} 955 956function gformDeleteRepeaterItem(deleteButton, max) { 957 958 var $deleteButton = jQuery(deleteButton), 959 $group = $deleteButton.closest('.gfield_repeater_item'), 960 $container = $group.closest('.gfield_repeater_container'); 961 962 $group.remove(); 963 964 gformResetRepeaterAttributes($container); 965 gformToggleRepeaterButtons($container, max); 966 967 gform.doAction('gform_repeater_post_item_delete', $container); 968 969} 970 971function gformResetRepeaterAttributes($container, depth, row) { 972 973 var cachedRadioSelection = null; 974 975 if (typeof depth === 'undefined') { 976 depth = 0; 977 } 978 979 if (typeof row === 'undefined') { 980 row = 0; 981 } 982 983 $container.children('.gfield_repeater_items').children('.gfield_repeater_item').each(function () { 984 var $children = jQuery(this).children('.gfield_repeater_cell'); 985 $children.each(function () { 986 var $cell = jQuery(this); 987 var $subContainer = jQuery(this).find('.gfield_repeater_container').first(); 988 989 if ($subContainer.length > 0) { 990 var newDepth = depth + 1; 991 gformResetRepeaterAttributes($subContainer, newDepth, row); 992 return; 993 } 994 995 jQuery(this).find('input, select, textarea, :checkbox, :radio').each(function () { 996 var $this = jQuery(this); 997 var name = $this.attr('name'); 998 999 if ( typeof name == 'undefined' ) { 1000 return; 1001 } 1002 1003 var regEx = /^(input_[^\[]*)((\[[0-9]+\])+)/, 1004 parts = regEx.exec(name); 1005 1006 if (!parts) { 1007 return; 1008 } 1009 var inputName = parts[1], 1010 arayParts = parts[2], 1011 regExIndex = /\[([0-9]+)\]/g, 1012 indexes = [], 1013 match = regExIndex.exec(arayParts); 1014 1015 while (match != null) { 1016 indexes.push(match[1]); 1017 match = regExIndex.exec(arayParts); 1018 } 1019 var newNameIndex = parts[1]; 1020 indexes = indexes.reverse(); 1021 var newId = ''; 1022 for (var n = indexes.length - 1; n >= 0; n--) { 1023 if (n == depth) { 1024 newNameIndex += '[' + row + ']'; 1025 newId += '-' + row; 1026 } else { 1027 newNameIndex += '[' + indexes[n] + ']'; 1028 newId += '-' + indexes[n]; 1029 } 1030 } 1031 1032 var currentId = $this.attr('id'); 1033 var $label = $cell.find("label[for='" + currentId + "']"); 1034 1035 if ( currentId ) { 1036 var matches = currentId.match(/((choice|input)_[0-9|_]*)-/); 1037 if ( matches && matches[2] ) { 1038 newId = matches[1] + newId; 1039 $label.attr('for', newId); 1040 $this.attr('id', newId); 1041 } 1042 } 1043 var newName = name.replace(parts[0], newNameIndex), 1044 newNameIsChecked = jQuery('input[name="'+ newName +'"]').is(':checked'); 1045 1046 if ( $this.is(':radio') && $this.is(':checked') && name !== newName && newNameIsChecked ) { 1047 if ( cachedRadioSelection !== null ) { 1048 cachedRadioSelection.prop('checked', true); 1049 } 1050 1051 $this.prop('checked', false); 1052 cachedRadioSelection = $this; 1053 } 1054 1055 $this.attr('name', newName); 1056 }); 1057 }); 1058 if (depth === 0) { 1059 row++; 1060 } 1061 }); 1062 1063 if ( cachedRadioSelection !== null ) { 1064 cachedRadioSelection.prop('checked', true); 1065 cachedRadioSelection = null; 1066 } 1067 1068} 1069 1070function gformToggleRepeaterButtons($container) { 1071 1072 var max = $container.closest('.gfield_repeater_wrapper').data('max_items'), 1073 groupCount = $container.children('.gfield_repeater_items').children('.gfield_repeater_item').length, 1074 $buttonsContainer = $container.children('.gfield_repeater_items').children('.gfield_repeater_item').children('.gfield_repeater_buttons'),
1075 $addButtons = $buttonsContainer.children('.add_repeater_item'); 1076 1077 $buttonsContainer.children('.remove_repeater_item').css('visibility', groupCount == 1 ? 'hidden' : 'visible'); 1078 1079 if (max > 0 && groupCount >= max) { 1080 1081 // store original title in the add button 1082 $addButtons.data('title', $buttonsContainer.children('.add_repeater_item').attr('title')); 1083 $addButtons.addClass('gfield_icon_disabled').attr('title', ''); 1084 1085 } else if (max > 0) { 1086 1087 $addButtons.removeClass('gfield_icon_disabled'); 1088 1089 if ($addButtons.data('title')) { 1090 $addButtons.attr('title', $addButtons.data('title')); 1091 } 1092 } 1093 1094 $container 1095 .children('.gfield_repeater_items') 1096 .children('.gfield_repeater_item') 1097 .children( '.gfield_repeater_cell').each(function (i) { 1098 var $subContainer = jQuery(this).find('.gfield_repeater_container').first(); 1099 if ($subContainer.length > 0) { 1100 gformToggleRepeaterButtons($subContainer); 1101 } 1102 }); 1103} 1104 1105 1106//----------------------------------- 1107//------ CREDIT CARD FIELD ---------- 1108//----------------------------------- 1109function gformMatchCard(id) { 1110 1111 var cardType = gformFindCardType(jQuery('#' + id).val()); 1112 var cardContainer = jQuery('#' + id).parents('.gfield').find('.gform_card_icon_container'); 1113 1114 if(!cardType) { 1115 1116 jQuery(cardContainer).find('.gform_card_icon').removeClass('gform_card_icon_selected gform_card_icon_inactive'); 1117 1118 } else { 1119 1120 jQuery(cardContainer).find('.gform_card_icon').removeClass('gform_card_icon_selected').addClass('gform_card_icon_inactive'); 1121 jQuery(cardContainer).find('.gform_card_icon_' + cardType).removeClass('gform_card_icon_inactive').addClass('gform_card_icon_selected'); 1122 } 1123} 1124 1125function gformFindCardType(value) { 1126 1127 if(value.length < 4) 1128 return false; 1129 1130 var rules = window['gf_cc_rules']; 1131 var validCardTypes = new Array(); 1132 1133 for(type in rules) { 1134 1135 //needed when implementing for in loops 1136 if(!rules.hasOwnProperty(type)) 1137 continue; 1138 1139 1140 for(i in rules[type]) { 1141 1142 if(!rules[type].hasOwnProperty(i)) 1143 continue; 1144 1145 if(rules[type][i].indexOf(value.substring(0, rules[type][i].length)) === 0) { 1146 validCardTypes[validCardTypes.length] = type; 1147 break; 1148 } 1149 1150 } 1151 } 1152 1153 return validCardTypes.length == 1 ? validCardTypes[0].toLowerCase() : false; 1154} 1155 1156function gformToggleCreditCard(){ 1157 if(jQuery("#gform_payment_method_creditcard").is(":checked")) 1158 jQuery(".gform_card_fields_container").slideDown(); 1159 else 1160 jQuery(".gform_card_fields_container").slideUp(); 1161} 1162 1163 1164//---------------------------------------- 1165//------ CHOSEN DROP DOWN FIELD ---------- 1166//---------------------------------------- 1167 1168function gformInitChosenFields(fieldList, noResultsText){ 1169 return jQuery(fieldList).each(function(){ 1170 1171 var element = jQuery( this ); 1172 1173 // RTL support 1174 if( jQuery( 'html' ).attr( 'dir' ) == 'rtl' ) { 1175 element.addClass( 'chosen-rtl chzn-rtl' ); 1176 } 1177 1178 // only initialize once 1179 if( element.is(":visible") && element.siblings(".chosen-container").length == 0 ){ 1180 var options = gform.applyFilters( 'gform_chosen_options', { no_results_text: noResultsText }, element ); 1181 element.chosen( options ); 1182 } 1183 1184 }); 1185} 1186 1187//---------------------------------------- 1188//--- CURRENCY FORMAT NUMBER FIELD ------- 1189//---------------------------------------- 1190 1191function gformInitCurrencyFormatFields(fieldList){ 1192 jQuery(fieldList).each(function(){ 1193 var $this = jQuery(this); 1194 $this.val( gformFormatMoney( jQuery(this).val() ) ); 1195 }).change( function( event ) { 1196 jQuery(this).val( gformFormatMoney( jQuery(this).val() ) ); 1197 }); 1198} 1199 1200 1201 1202//---------------------------------------- 1203//------ JS MERGE TAGS ------------------- 1204//---------------------------------------- 1205 1206var GFMergeTag = function() { 1207 1208 /** 1209 * Gets the merge tag value for the specified input Id 1210 * @param formId The current form Id 1211 * @param inputId The input Id to get the merge tag from. This could be a field id (i.e. 1) or a specific input Id for multi-input fields (i.e. 1.2) 1212 * @param modifier The merge tag modifier to be used. i.e. value, currency, price, etc... 1213 * @returns Returns a string containg the merge tag value for the spcified input Id 1214 */ 1215 GFMergeTag.getMergeTagValue = function( formId, inputId, modifier ) { 1216 1217 if ( modifier === undefined ) { 1218 modifier = ''; 1219 } 1220 modifier = modifier.replace(":", ""); 1221 1222 var fieldId = parseInt(inputId,10); 1223 var field = jQuery('#field_' + formId + '_' + fieldId); 1224 1225 var inputSelector = fieldId == inputId ? 'input[name^="input_' + fieldId + '"]' : 'input[name="input_' + inputId + '"]'; 1226 var input = field.find( inputSelector + ', select[name^="input_' + inputId + '"], textarea[name="input_' + inputId + '"]'); 1227 1228 // checking conditional logic 1229 var isVisible = window['gf_check_field_rule'] ? gf_check_field_rule( formId, fieldId, true, '' ) == 'show' : true, 1230 val; 1231 1232 if ( ! isVisible ) { 1233 return ''; 1234 } 1235 1236 //If value has been filtered, use it. Otherwise use default logic 1237 var value = gform.applyFilters( 'gform_value_merge_tag_' + formId + '_' + fieldId, false, input, modifier ); 1238 if ( value !== false ){ 1239 return value; 1240 } 1241 1242 value = ''; //Reset value to blank 1243 1244 switch ( modifier ) { 1245 case 'label': 1246 var label = field.find('.gfield_label').text(); 1247 return label; 1248 break; 1249 case 'qty': 1250 if ( field.hasClass('gfield_price') ){ 1251 val = gformGetProductQuantity( formId, fieldId ); 1252 return val === false || val === '' ? 0 : val; 1253 } 1254 break; 1255 1256 } 1257 1258 // Filter out unselected checkboxes and radio buttons 1259 if ( input.prop('type') === 'checkbox' || input.prop('type') === 'radio' ) { 1260 input = input.filter(':checked'); 1261 } 1262 1263 if ( input.length === 1 ) { 1264 if ( ( input.is('select') || input.prop('type') === 'radio' || input.prop('type') === 'checkbox' ) && modifier === '' ) { 1265 val = ( input.is('select') ) ? input.find('option:selected') : input.next('label').clone(); 1266 val.find('span').remove(); 1267 1268 if ( val.length === 1 ) { 1269 val = val.text(); 1270 } else { 1271 var option = []; 1272 for(var i=0; i<val.length; i++) { 1273 option[i] = jQuery(val[i]).text(); 1274 } 1275 1276 val = option; 1277 } 1278 } else if ( val === undefined ) { 1279 val = input.val(); 1280 } 1281 1282 if ( jQuery.isArray( val ) ) { 1283 // multiple select 1284 value = val.join(', '); 1285 } else if ( typeof val === 'string' ) { 1286 1287 value = GFMergeTag.formatValue( val, modifier ); 1288 1289 } else { 1290 // empty multiple select returns null, set it to '' 1291 value = ''; 1292 } 1293 } else if ( input.length > 1 ) { 1294 val = []; 1295 for(var i=0; i<input.length; i++) { 1296 if( ( input.prop('type') === 'checkbox' ) && modifier === '' ) { 1297 1298 var clone = jQuery(input[i]).next('label').clone(); 1299 clone.find('span').remove() 1300 val[i] = GFMergeTag.formatValue( clone.text(), modifier ); 1301 1302 clone.remove(); 1303 1304 } else { 1305 val[i] = GFMergeTag.formatValue( jQuery(input[i]).val(), modifier ); 1306 } 1307 } 1308 1309 value = val.join(', '); 1310 } 1311 1312 return value; 1313 } 1314 1315 /** 1316 * Parses the specified text for merge tags, and replaces all of them with the appropriate merge tag values. Returns the resulting string 1317 * @param formId The current form Id 1318 * @param text The text containing merge tags 1319 * @returns Retuns the original "text" strings with all merge tags replaced with the appropriate merge tag values 1320 */ 1321 GFMergeTag.replaceMergeTags = function( formId, text ) { 1322 1323 var mergeTags = GFMergeTag.parseMergeTags( text ); 1324 1325 for(i in mergeTags) { 1326 1327 if(! mergeTags.hasOwnProperty(i)) { 1328 continue; 1329 } 1330 1331 var inputId = mergeTags[i][1]; 1332 var fieldId = parseInt(inputId,10); 1333 var modifier = mergeTags[i][3] == undefined ? '' : mergeTags[i][3].replace(":", ""); 1334 1335 var value = GFMergeTag.getMergeTagValue( formId, inputId, modifier ); 1336 1337 text = text.replace( mergeTags[i][0], value ); 1338 } 1339 1340 return text; 1341 } 1342 1343 GFMergeTag.formatValue = function( value, modifier ) { 1344 1345 value = value.split( '|' ); 1346 var val = ''; 1347 if( value.length > 1 ) { 1348 val = modifier === 'price' || modifier === 'currency' ? gformToNumber( value[1] ) : value[0]; 1349 } else { 1350 val = value[0]; 1351 } 1352 1353 switch ( modifier ) { 1354 1355 case 'price': 1356 val = gformToNumber( val ); 1357 val = val === false ? '' : val; 1358 break; 1359 1360 case 'currency': 1361 val = gformFormatMoney( val, false ); 1362 val = val === false ? '' : val; 1363 break; 1364 1365 case 'numeric': 1366 val = gformToNumber( val ); 1367 return val === false ? 0 : val; 1368 break; 1369 } 1370 1371 return val; 1372 } 1373 1374 /** 1375 * Parses the merge tags in the specified text and returns an array of all the matched merge tags 1376 * 1377 * @param text The text with merge tags to be parsed 1378 * @param regEx The regular expression to be used to parse for merge tags. 1379 * 1380 * @returns Returns an array with all the merge tags that were matched in the original text 1381 */ 1382 GFMergeTag.parseMergeTags = function( text, regEx ) { 1383 1384 if( typeof regEx === 'undefined' ) { 1385 regEx = /{[^{]*?:(\d+(\.\d+)?)(:(.*?))?}/i; 1386 } 1387 1388 var matches = []; 1389 1390 while( regEx.test( text ) ) { 1391 var i = matches.length; 1392 matches[i] = regEx.exec( text ); 1393 text = text.replace( '' + matches[i][0], '' ); 1394 } 1395 1396 return matches; 1397 } 1398} 1399 1400new GFMergeTag(); 1401 1402 1403//---------------------------------------- 1404//------ CALCULATION FUNCTIONS ----------- 1405//---------------------------------------- 1406 1407var GFCalc = function(formId, formulaFields){ 1408 1409 this.formId = formId; 1410 this.formulaFields = formulaFields; 1411 1412 this.exprPatt = /^[0-9 -/*\(\)]+$/i; 1413 this.isCalculating = {}; 1414 1415 this.init = function(formId, formulaFields) { 1416 1417 var calc = this; 1418 jQuery(document).bind("gform_post_conditional_logic", function(){ 1419 calc.runCalcs( formId, formulaFields ); 1420 } ); 1421 1422 for(var i=0; i<formulaFields.length; i++) { 1423 var formulaField = jQuery.extend({}, formulaFields[i]); 1424 this.runCalc(formulaField, formId); 1425 this.bindCalcEvents(formulaField, formId); 1426 } 1427 1428 } 1429 1430 this.runCalc = function(formulaField, formId) { 1431 1432 var calcObj = this, 1433 field = jQuery('#field_' + formId + '_' + formulaField.field_id), 1434 formulaInput = field.hasClass( 'gfield_price' ) ? jQuery( '#ginput_base_price_' + formId + '_' + formulaField.field_id ) : jQuery( '#input_' + formId + '_' + formulaField.field_id ), 1435 previous_val = formulaInput.val(), 1436 formula = gform.applyFilters( 'gform_calculation_formula', formulaField.formula, formulaField, formId, calcObj ), 1437 expr = calcObj.replaceFieldTags( formId, formula, formulaField ).replace(/(\r\n|\n|\r)/gm,""), 1438 result = ''; 1439 1440 if(calcObj.exprPatt.test(expr)) { 1441 try { 1442 1443 //run calculation 1444 result = eval(expr); 1445 1446 } catch( e ) { } 1447 } 1448 1449 // if result is positive infinity, negative infinity or a NaN, defaults to 0 1450 if( ! isFinite( result ) ) 1451 result = 0; 1452 1453 // allow users to modify result with their own function 1454 if( window["gform_calculation_result"] ) { 1455 result = window["gform_calculation_result"](result, formulaField, formId, calcObj); 1456 if( window.console ) 1457 console.log( '"gform_calculation_result" function is deprecated since version 1.8! Use "gform_calculation_result" JS hook instead.' ); 1458 } 1459 1460 // allow users to modify result with their own function 1461 result = gform.applyFilters( 'gform_calculation_result', result, formulaField, formId, calcObj ); 1462 1463 // allow result to be custom formatted 1464 var formattedResult = gform.applyFilters( 'gform_calculation_format_result', false, result, formulaField, formId, calcObj ); 1465 1466 var numberFormat = gf_get_field_number_format(formulaField.field_id, formId); 1467 1468 //formatting number 1469 if( formattedResult !== false) { 1470 result = formattedResult; 1471 } 1472 else if( field.hasClass( 'gfield_price' ) || numberFormat == "currency") { 1473 1474 result = gformFormatMoney(result ? result : 0, true); 1475 } 1476 else { 1477 1478 var decimalSeparator = "."; 1479 var thousandSeparator = ","; 1480 1481 if(numberFormat == "decimal_comma"){ 1482 decimalSeparator = ","; 1483 thousandSeparator = "."; 1484 } 1485 1486 result = gformFormatNumber(result, !gformIsNumber(formulaField.rounding) ? -1 : formulaField.rounding, decimalSeparator, thousandSeparator); 1487 } 1488 1489 //If value doesn't change, abort. 1490 //This is needed to prevent an infinite loop condition with conditional logic 1491 if( result == previous_val ) 1492 return; 1493 1494 // if this is a calculation product, handle differently 1495 if(field.hasClass('gfield_price')) { 1496 jQuery('#input_' + formId + '_' + formulaField.field_id).text(result); 1497 formulaInput.val(result).trigger('change'); 1498 gformCalculateTotalPrice(formId); 1499 } else { 1500 formulaInput.val(result).trigger('change'); 1501 } 1502 1503 }; 1504 1505 this.runCalcs = function( formId, formulaFields ) {
1506 for(var i=0; i<formulaFields.length; i++) { 1507 var formulaField = jQuery.extend({}, formulaFields[i]); 1508 this.runCalc( formulaField, formId ); 1509 } 1510 } 1511 1512 this.bindCalcEvents = function(formulaField, formId) { 1513 1514 var calcObj = this; 1515 var formulaFieldId = formulaField.field_id; 1516 var matches = GFMergeTag.parseMergeTags( formulaField.formula ); 1517 1518 calcObj.isCalculating[formulaFieldId] = false; 1519 1520 for(var i in matches) { 1521 1522 if(! matches.hasOwnProperty(i)) 1523 continue; 1524 1525 var inputId = matches[i][1]; 1526 var fieldId = parseInt(inputId,10); 1527 var input = jQuery('#field_' + formId + '_' + fieldId).find('input[name="input_' + inputId + '"], select[name="input_' + inputId + '"]'); 1528 1529 if(input.prop('type') == 'checkbox' || input.prop('type') == 'radio') { 1530 jQuery(input).click(function(){ 1531 calcObj.bindCalcEvent(inputId, formulaField, formId, 0); 1532 }); 1533 } else 1534 if(input.is('select') || input.prop('type') == 'hidden') { 1535 jQuery(input).change(function(){ 1536 calcObj.bindCalcEvent(inputId, formulaField, formId, 0); 1537 }); 1538 } else { 1539 jQuery(input).keydown(function(){ 1540 calcObj.bindCalcEvent(inputId, formulaField, formId); 1541 }).change(function(){ 1542 calcObj.bindCalcEvent(inputId, formulaField, formId, 0); 1543 }); 1544 } 1545 1546 // allow users to add custom methods for triggering calculations 1547 gform.doAction( 'gform_post_calculation_events', matches[i], formulaField, formId, calcObj ); 1548 1549 } 1550 1551 } 1552 1553 this.bindCalcEvent = function(inputId, formulaField, formId, delay) { 1554 1555 var calcObj = this; 1556 var formulaFieldId = formulaField.field_id; 1557 1558 delay = delay == undefined ? 345 : delay; 1559 1560 if(calcObj.isCalculating[formulaFieldId][inputId]) 1561 clearTimeout(calcObj.isCalculating[formulaFieldId][inputId]); 1562 1563 calcObj.isCalculating[formulaFieldId][inputId] = window.setTimeout(function() { 1564 calcObj.runCalc(formulaField, formId); 1565 }, delay); 1566 1567 } 1568 1569 this.replaceFieldTags = function( formId, expr, formulaField ) { 1570 1571 var matches = GFMergeTag.parseMergeTags( expr ); 1572 1573 for(i in matches) { 1574 1575 if(! matches.hasOwnProperty(i)) 1576 continue; 1577 1578 var inputId = matches[i][1]; 1579 var fieldId = parseInt(inputId,10); 1580 1581 var modifier = 'value'; 1582 if( matches[i][3] ){ 1583 modifier = matches[i][3]; 1584 } 1585 else { 1586 var is_product_radio = jQuery('.gfield_price input[name=input_' + fieldId + ']').is('input[type=radio]'); 1587 var is_product_dropdown = jQuery('.gfield_price select[name=input_' + fieldId + ']').length > 0; 1588 var is_option_checkbox = jQuery('.gfield_price input[name="input_' + inputId + '"]').is('input[type=checkbox]'); 1589 1590 if( is_product_dropdown || is_product_radio || is_option_checkbox ) { 1591 modifier = 'price'; 1592 } 1593 } 1594 1595 var isVisible = window['gf_check_field_rule'] ? gf_check_field_rule( formId, fieldId, true, '' ) == 'show' : true; 1596 1597 var value = isVisible ? GFMergeTag.getMergeTagValue( formId, inputId, modifier ) : 0; 1598 1599 // allow users to modify value with their own function 1600 value = gform.applyFilters( 'gform_merge_tag_value_pre_calculation', value, matches[i], isVisible, formulaField, formId ); 1601 1602 value = this.cleanNumber( value, formId, fieldId, formulaField ); 1603 1604 expr = expr.replace( matches[i][0], value ); 1605 } 1606 1607 return expr; 1608 } 1609 1610 this.cleanNumber = function ( value, formId, fieldId, formulaField ) { 1611 1612 var numberFormat = gf_get_field_number_format( fieldId, formId ); 1613 1614 if( ! numberFormat ) { 1615 numberFormat = gf_get_field_number_format(formulaField.field_id, formId); 1616 } 1617 1618 var decimalSeparator = gformGetDecimalSeparator(numberFormat); 1619 1620 value = gformCleanNumber( value, '', '', decimalSeparator ); 1621 if( ! value ) 1622 value = 0; 1623 1624 return value; 1625 } 1626 1627 this.init(formId, formulaFields); 1628 1629 1630} 1631 1632function gformFormatNumber(number, rounding, decimalSeparator, thousandSeparator){ 1633 1634 if(typeof decimalSeparator == "undefined"){ 1635 if(window['gf_global']){ 1636 var currency = new Currency(gf_global.gf_currency_config); 1637 decimalSeparator = currency.currency["decimal_separator"]; 1638 } 1639 else{ 1640 decimalSeparator = "."; 1641 } 1642 } 1643 1644 if(typeof thousandSeparator == "undefined"){ 1645 if(window['gf_global']){ 1646 var currency = new Currency(gf_global.gf_currency_config); 1647 thousandSeparator = currency.currency["thousand_separator"]; 1648 } 1649 else{ 1650 thousandSeparator = ","; 1651 } 1652 } 1653 1654 var currency = new Currency(); 1655 return currency.numberFormat(number, rounding, decimalSeparator, thousandSeparator, false) 1656} 1657 1658function gformToNumber(text) { 1659 var currency = new Currency(gf_global.gf_currency_config); 1660 return currency.toNumber(text); 1661} 1662 1663/** 1664 * @deprecated. Use GFMergeTags.parseMergeTag() instead 1665 */ 1666function getMatchGroups(expr, patt) { 1667 1668 var matches = new Array(); 1669 1670 while(patt.test(expr)) { 1671 1672 var i = matches.length; 1673 matches[i] = patt.exec(expr) 1674 expr = expr.replace('' + matches[i][0], ''); 1675 1676 } 1677 1678 return matches; 1679} 1680 1681function gf_get_field_number_format(fieldId, formId, context) { 1682 1683 var fieldNumberFormats = rgars(window, 'gf_global/number_formats/{0}/{1}'.format(formId, fieldId)), 1684 format = false;
1685 1686 if (fieldNumberFormats === '') { 1687 return format; 1688 } 1689 1690 if (typeof context == 'undefined') { 1691 format = fieldNumberFormats.price !== false ? fieldNumberFormats.price : fieldNumberFormats.value; 1692 } else { 1693 format = fieldNumberFormats[context]; 1694 } 1695 1696 return format; 1697} 1698 1699 1700//---------------------------------------- 1701//------ JAVASCRIPT HOOK FUNCTIONS ------- 1702//---------------------------------------- 1703 1704var gform = { 1705 hooks: { action: {}, filter: {} }, 1706 addAction: function( action, callable, priority, tag ) { 1707 gform.addHook( 'action', action, callable, priority, tag ); 1708 }, 1709 addFilter: function( action, callable, priority, tag ) { 1710 gform.addHook( 'filter', action, callable, priority, tag ); 1711 }, 1712 doAction: function( action ) { 1713 gform.doHook( 'action', action, arguments ); 1714 }, 1715 applyFilters: function( action ) { 1716 return gform.doHook( 'filter', action, arguments ); 1717 }, 1718 removeAction: function( action, tag ) { 1719 gform.removeHook( 'action', action, tag ); 1720 }, 1721 removeFilter: function( action, priority, tag ) { 1722 gform.removeHook( 'filter', action, priority, tag ); 1723 }, 1724 addHook: function( hookType, action, callable, priority, tag ) { 1725 if ( undefined == gform.hooks[hookType][action] ) { 1726 gform.hooks[hookType][action] = []; 1727 } 1728 var hooks = gform.hooks[hookType][action]; 1729 if ( undefined == tag ) { 1730 tag = action + '_' + hooks.length; 1731 } 1732 if( priority == undefined ){ 1733 priority = 10; 1734 } 1735 1736 gform.hooks[hookType][action].push( { tag:tag, callable:callable, priority:priority } ); 1737 }, 1738 doHook: function( hookType, action, args ) { 1739 1740 // splice args from object into array and remove first index which is the hook name 1741 args = Array.prototype.slice.call(args, 1); 1742 1743 if ( undefined != gform.hooks[hookType][action] ) { 1744 var hooks = gform.hooks[hookType][action], hook; 1745 //sort by priority 1746 hooks.sort(function(a,b){return a["priority"]-b["priority"]}); 1747 for( var i=0; i<hooks.length; i++) { 1748 hook = hooks[i].callable; 1749 if(typeof hook != 'function')
1750 hook = window[hook]; 1751 if ( 'action' == hookType ) { 1752 hook.apply(null, args); 1753 } else { 1754 args[0] = hook.apply(null, args); 1755 } 1756 } 1757 } 1758 if ( 'filter'==hookType ) { 1759 return args[0]; 1760 } 1761 }, 1762 removeHook: function( hookType, action, priority, tag ) { 1763 if ( undefined != gform.hooks[hookType][action] ) { 1764 var hooks = gform.hooks[hookType][action]; 1765 for( var i=hooks.length-1; i>=0; i--) { 1766 if ((undefined==tag||tag==hooks[i].tag) && (undefined==priority||priority==hooks[i].priority)){ 1767 hooks.splice(i,1); 1768 } 1769 } 1770 } 1771 } 1772}; 1773 1774 1775 1776//---------------------------------------- 1777//------ reCAPTCHA FUNCTIONS ------------- 1778//---------------------------------------- 1779 1780/** 1781 * Callback function on the reCAPTCAH API script. 1782 * 1783 * @see GF_Field_CAPTCHA::get_field_input() in /includes/fields/class-gf-field-catpcha.php 1784 */ 1785function renderRecaptcha() { 1786 1787 jQuery( '.ginput_recaptcha' ).each( function() { 1788 1789 var $elem = jQuery( this ), 1790 parameters = { 1791 'sitekey': $elem.data( 'sitekey' ), 1792 'theme': $elem.data( 'theme' ), 1793 'tabindex': $elem.data( 'tabindex' ) 1794 }; 1795 1796 if ( ! $elem.is( ':empty' ) ) { 1797 return; 1798 } 1799 1800 if ( $elem.data( 'stoken' ) ) { 1801 parameters.stoken = $elem.data( 'stoken' ); 1802 } 1803 1804 var callback = false; 1805 1806 if ( $elem.data( 'size' ) == 'invisible' ) { 1807 callback = function( token ) { 1808 if ( token ) { 1809 $elem.closest('form').submit(); 1810 } 1811 } 1812 } 1813 1814 /** 1815 * Allows a custom callback function to be executed when the user successfully submits the captcha. 1816 * 1817 * @since 2.4.x The callback will be a function if reCAPTCHA v2 Invisible is used. 1818 * @since 2.2.5.20 1819 * 1820 * @param string|false|object The name of the callback function or the function object itself to be executed when the user successfully submits the captcha. 1821 * @param object $elem The jQuery object containing the div element with the ginput_recaptcha class for the current reCaptcha field. 1822 */ 1823 callback = gform.applyFilters( 'gform_recaptcha_callback', callback, $elem ); 1824 if ( callback ) { 1825 parameters.callback = callback; 1826 } 1827 1828 $elem.data( 'widget-id', grecaptcha.render( this.id, parameters ) ); 1829 1830 if ( parameters.tabindex ) { 1831 $elem.find( 'iframe' ).attr( 'tabindex', parameters.tabindex ); 1832 } 1833 1834 gform.doAction( 'gform_post_recaptcha_render', $elem ); 1835 1836 1837 } ); 1838 1839} 1840 1841//---------------------------------------- 1842//----- SINGLE FILE UPLOAD FUNCTIONS ----- 1843//---------------------------------------- 1844 1845function gformValidateFileSize( field, max_file_size ) { 1846 var validation_element; 1847 1848 // Get validation message element. 1849 if ( jQuery( field ).closest( 'div' ).siblings( '.validation_message' ).length > 0 ) { 1850 validation_element = jQuery( field ).closest( 'div' ).siblings( '.validation_message' ); 1851 } else { 1852 validation_element = jQuery( field ).siblings( '.validation_message' ); 1853 } 1854 1855 1856 // If file API is not supported within browser, return. 1857 if ( ! window.FileReader || ! window.File || ! window.FileList || ! window.Blob ) { 1858 return; 1859 } 1860 1861 // Get selected file. 1862 var file = field.files[0]; 1863 1864 // If selected file is larger than maximum file size, set validation message and unset file selection. 1865 if ( file && file.size > max_file_size ) { 1866 1867 // Set validation message. 1868 validation_element.text(file.name + " - " + gform_gravityforms.strings.file_exceeds_limit); 1869 1870 } else { 1871 1872 // Reset validation message. 1873 validation_element.text( '' ); 1874 1875 } 1876 1877} 1878 1879//---------------------------------------- 1880//------ MULTIFILE UPLOAD FUNCTIONS ------ 1881//---------------------------------------- 1882 1883(function (gfMultiFileUploader, $) { 1884 gfMultiFileUploader.uploaders = {}; 1885 var strings = typeof gform_gravityforms != 'undefined' ? gform_gravityforms.strings : {}; 1886 var imagesUrl = typeof gform_gravityforms != 'undefined' ? gform_gravityforms.vars.images_url : ""; 1887 1888 1889 $(document).bind('gform_post_render', function(e, formID){ 1890 1891 $("form#gform_" + formID + " .gform_fileupload_multifile").each(function(){ 1892 setup(this); 1893 }); 1894 var $form = $("form#gform_" + formID); 1895 if($form.length > 0){ 1896 $form.submit(function(){ 1897 var pendingUploads = false;
1898 $.each(gfMultiFileUploader.uploaders, function(i, uploader){ 1899 if(uploader.total.queued>0){ 1900 pendingUploads = true; 1901 return false; 1902 } 1903 }); 1904 if(pendingUploads){ 1905 alert(strings.currently_uploading); 1906 window["gf_submitting_" + formID] = false; 1907 $('#gform_ajax_spinner_' + formID).remove(); 1908 return false; 1909 } 1910 }); 1911 } 1912 1913 }); 1914 1915 $(document).bind("gform_post_conditional_logic", function(e,formID, fields, isInit){ 1916 if(!isInit){ 1917 $.each(gfMultiFileUploader.uploaders, function(i, uploader){ 1918 uploader.refresh(); 1919 }); 1920 } 1921 }); 1922 1923 $(document).ready(function () { 1924 if((typeof adminpage !== 'undefined' && adminpage === 'toplevel_page_gf_edit_forms')|| typeof plupload == 'undefined'){ 1925 $(".gform_button_select_files").prop("disabled", true); 1926 } else if (typeof adminpage !== 'undefined' && adminpage.indexOf('_page_gf_entries') > -1) { 1927 $(".gform_fileupload_multifile").each(function(){ 1928 setup(this); 1929 }); 1930 } 1931 }); 1932 1933 gfMultiFileUploader.setup = function (uploadElement){ 1934 setup( uploadElement ); 1935 }; 1936 1937 function setup(uploadElement){ 1938 var settings = $(uploadElement).data('settings'); 1939 1940 var uploader = new plupload.Uploader(settings); 1941 formID = uploader.settings.multipart_params.form_id; 1942 gfMultiFileUploader.uploaders[settings.container] = uploader; 1943 var formID; 1944 var uniqueID; 1945 1946 uploader.bind('Init', function(up, params) { 1947 if(!up.features.dragdrop) 1948 $(".gform_drop_instructions").hide(); 1949 var fieldID = up.settings.multipart_params.field_id; 1950 var maxFiles = parseInt(up.settings.gf_vars.max_files,10); 1951 var initFileCount = countFiles(fieldID); 1952 if(maxFiles > 0 && initFileCount >= maxFiles){ 1953 gfMultiFileUploader.toggleDisabled(up.settings, true); 1954 } 1955 1956 }); 1957 1958 gfMultiFileUploader.toggleDisabled = function (settings, disabled){ 1959 1960 var button = typeof settings.browse_button == "string" ? $("#" + settings.browse_button) : $(settings.browse_button); 1961 button.prop("disabled", disabled); 1962 }; 1963 1964 function addMessage(messagesID, message){ 1965 $("#" + messagesID).prepend("<li>" + htmlEncode(message) + "</li>"); 1966 } 1967 1968 uploader.init(); 1969 1970 uploader.bind('BeforeUpload', function(up, file){ 1971 up.settings.multipart_params.original_filename = file.name; 1972 }); 1973 1974 uploader.bind('FilesAdded', function(up, files) { 1975 var max = parseInt(up.settings.gf_vars.max_files,10), 1976 fieldID = up.settings.multipart_params.field_id, 1977 totalCount = countFiles(fieldID), 1978 disallowed = up.settings.gf_vars.disallowed_extensions, 1979 extension; 1980 1981 if( max > 0 && totalCount >= max){ 1982 $.each(files, function(i, file) { 1983 up.removeFile(file); 1984 return; 1985 }); 1986 return; 1987 } 1988 $.each(files, function(i, file) { 1989 1990 extension = file.name.split('.').pop(); 1991 1992 if($.inArray(extension, disallowed) > -1){ 1993 addMessage(up.settings.gf_vars.message_id, file.name + " - " + strings.illegal_extension); 1994 up.removeFile(file); 1995 return; 1996 } 1997 1998 if ((file.status == plupload.FAILED) || (max > 0 && totalCount >= max)){ 1999 up.removeFile(file); 2000 return; 2001 } 2002 2003 var size = typeof file.size !== 'undefined' ? plupload.formatSize(file.size) : strings.in_progress, 2004 removeFileJs = '$this=jQuery(this); var uploader = gfMultiFileUploader.uploaders.' + up.settings.container.id + ';uploader.stop();uploader.removeFile(uploader.getFile(\'' + file.id +'\'));$this.after(\'' + strings.cancelled + '\'); uploader.start();$this.remove();', 2005 statusMarkup = '<div id="{0}" class="ginput_preview">{1} ({2}) <b></b> <a href="javascript:void(0)" title="{3}" onclick="{4}" onkeypress="{4}">{5}</a></div>'; 2006 2007 /** 2008 * Filer the file upload markup as it is being uploaded.
2009 * 2010 * @param {string} statusMarkup Markup template used to render the status of the file being uploaded. 2011 * @param {plupload.File} file Instance of File being uploaded. See: https://www.plupload.com/docs/v2/File. 2012 * @param {int|string} size File size. 2013 * @param {object} strings Array of localized strings relating to the file upload UI. 2014 * @param {string} removeFileJs JS used to remove the file when the "Cancel" link is click/pressed. 2015 * @param {plupload.Uploader} up Instance of Uploader responsible for uploading current file. See: https://www.plupload.com/docs/v2/Uploader. 2016 */ 2017 statusMarkup = gform.applyFilters( 'gform_file_upload_status_markup', statusMarkup, file, size, strings, removeFileJs, up ) 2018 .format( file.id, htmlEncode( file.name ), size, strings.cancel_upload, removeFileJs, strings.cancel ); 2019 2020 $( '#' + up.settings.filelist ).prepend( statusMarkup ); 2021 2022 totalCount++; 2023 2024 }); 2025 2026 up.refresh(); // Reposition Flash 2027 2028 var formElementID = "form#gform_" + formID; 2029 var uidElementID = "input:hidden[name='gform_unique_id']"; 2030 var uidSelector = formElementID + " " + uidElementID; 2031 var $uid = $(uidSelector); 2032 if($uid.length==0){ 2033 $uid = $(uidElementID); 2034 } 2035 2036 uniqueID = $uid.val(); 2037 if('' === uniqueID){ 2038 uniqueID = generateUniqueID(); 2039 $uid.val(uniqueID); 2040 } 2041 2042 2043 if(max > 0 && totalCount >= max){ 2044 gfMultiFileUploader.toggleDisabled(up.settings, true); 2045 addMessage(up.settings.gf_vars.message_id, strings.max_reached) 2046 } 2047 2048 2049 up.settings.multipart_params.gform_unique_id = uniqueID; 2050 up.start(); 2051 2052 }); 2053 2054 uploader.bind('UploadProgress', function(up, file) { 2055 var html = file.percent + "%"; 2056 $('#' + file.id + " b").html(html); 2057 }); 2058 2059 uploader.bind('Error', function(up, err) { 2060 if(err.code === plupload.FILE_EXTENSION_ERROR){ 2061 var extensions = typeof up.settings.filters.mime_types != 'undefined' ? up.settings.filters.mime_types[0].extensions /* plupoad 2 */ : up.settings.filters[0].extensions; 2062 addMessage(up.settings.gf_vars.message_id, err.file.name + " - " + strings.invalid_file_extension + " " + extensions); 2063 } else if (err.code === plupload.FILE_SIZE_ERROR) { 2064 addMessage(up.settings.gf_vars.message_id, err.file.name + " - " + strings.file_exceeds_limit); 2065 } else { 2066 var m = "Error: " + err.code + 2067 ", Message: " + err.message + 2068 (err.file ? ", File: " + err.file.name : ""); 2069 2070 addMessage(up.settings.gf_vars.message_id, m); 2071 } 2072 $('#' + err.file.id ).html(''); 2073 2074 up.refresh(); // Reposition Flash 2075 }); 2076 2077 uploader.bind('ChunkUploaded', function(up, file, result) { 2078 var response = $.secureEvalJSON(result.response); 2079 if(response.status == "error"){ 2080 up.removeFile(file); 2081 addMessage(up.settings.gf_vars.message_id, file.name + " - " + response.error.message); 2082 $('#' + file.id ).html(''); 2083 } 2084 }); 2085 2086 uploader.bind('FileUploaded', function(up, file, result) { 2087 if( ! up.getFile(file.id) ) { 2088 // The file has been removed from the queue. 2089 return; 2090 } 2091 var response = $.secureEvalJSON(result.response); 2092 if(response.status == "error"){ 2093 addMessage(up.settings.gf_vars.message_id, file.name + " - " + response.error.message); 2094 $('#' + file.id ).html(''); 2095 return; 2096 } 2097 2098 var html = '<strong>' + htmlEncode(file.name) + '</strong>'; 2099 var formId = up.settings.multipart_params.form_id; 2100 var fieldId = up.settings.multipart_params.field_id; 2101 html = "<img " 2102 + "class='gform_delete' " 2103 + "src='" + imagesUrl + "/delete.png' " 2104 + "onclick='gformDeleteUploadedFile(" + formId + "," + fieldId + ", this);' " 2105 + "onkeypress='gformDeleteUploadedFile(" + formId + "," + fieldId + ", this);' " 2106 + "alt='"+ strings.delete_file + "' " 2107 + "title='" + strings.delete_file 2108 + "' /> " 2109 + html; 2110 2111 html = gform.applyFilters( 'gform_file_upload_markup', html, file, up, strings, imagesUrl ); 2112 2113 $( '#' + file.id ).html( html ); 2114 2115 if(file.percent == 100){ 2116 if(response.status && response.status == 'ok'){ 2117 addFile(fieldId, response.data); 2118 } else { 2119 addMessage(up.settings.gf_vars.message_id, strings.unknown_error + ': ' + file.name); 2120 } 2121 } 2122 2123 2124 2125 }); 2126 2127 function getAllFiles(){ 2128 var selector = '#gform_uploaded_files_' + formID, 2129 $uploadedFiles = $(selector), files; 2130 2131 files = $uploadedFiles.val(); 2132 files = (typeof files === "undefined") || files === '' ? {} : $.parseJSON(files); 2133 2134 return files; 2135 } 2136 2137 function getFiles(fieldID){ 2138 var allFiles = getAllFiles(); 2139 var inputName = getInputName(fieldID); 2140 2141 if(typeof allFiles[inputName] == 'undefined') 2142 allFiles[inputName] = []; 2143 return allFiles[inputName]; 2144 } 2145 2146 function countFiles(fieldID){ 2147 var files = getFiles(fieldID); 2148 return files.length; 2149 } 2150 2151 function addFile(fieldID, fileInfo){ 2152 2153 var files = getFiles(fieldID); 2154 2155 files.unshift(fileInfo); 2156 setUploadedFiles(fieldID, files); 2157 } 2158 2159 function setUploadedFiles(fieldID, files){ 2160 var allFiles = getAllFiles(); 2161 var $uploadedFiles = $('#gform_uploaded_files_' + formID); 2162 var inputName = getInputName(fieldID); 2163 allFiles[inputName] = files; 2164 $uploadedFiles.val($.toJSON(allFiles)); 2165 } 2166 2167 function getInputName(fieldID){ 2168 return "input_" + fieldID; 2169 } 2170 2171 // fixes drag and drop in IE10 2172 $("#" + settings.drop_element).on({ 2173 "dragenter": ignoreDrag, 2174 "dragover": ignoreDrag 2175 }); 2176 2177 function ignoreDrag( e ) { 2178 e.preventDefault(); 2179 } 2180 } 2181 2182 2183 function generateUniqueID() { 2184 return 'xxxxxxxx'.replace(/[xy]/g, function (c) { 2185 var r = Math.random() * 16 | 0, v = c == 'x' ? r : r & 0x3 | 0x8; 2186 return v.toString(16); 2187 }); 2188 } 2189 2190 function htmlEncode(value){ 2191 return $('<div/>').text(value).html(); 2192 } 2193 2194}(window.gfMultiFileUploader = window.gfMultiFileUploader || {}, jQuery)); 2195 2196 2197//---------------------------------------- 2198//------ GENERAL FUNCTIONS ------- 2199//---------------------------------------- 2200 2201function gformInitSpinner(formId, spinnerUrl) { 2202 2203 jQuery('#gform_' + formId).submit(function () { 2204 gformAddSpinner(formId, spinnerUrl); 2205 }); 2206 2207} 2208 2209function gformAddSpinner(formId, spinnerUrl) { 2210 2211 if (typeof spinnerUrl == 'undefined' || !spinnerUrl) { 2212 spinnerUrl = gform.applyFilters('gform_spinner_url', gf_global.spinnerUrl, formId); 2213 } 2214 2215 if (jQuery('#gform_ajax_spinner_' + formId).length == 0) { 2216 /** 2217 * Filter the element after which the AJAX spinner will be inserted. 2218 * 2219 * @since 2.0 2220 *
2221 * @param object $targetElem jQuery object containing all of the elements after which the AJAX spinner will be inserted. 2222 * @param int formId ID of the current form. 2223 */ 2224 var $spinnerTarget = gform.applyFilters('gform_spinner_target_elem', jQuery('#gform_submit_button_' + formId + ', #gform_wrapper_' + formId + ' .gform_next_button, #gform_send_resume_link_button_' + formId), formId); 2225 $spinnerTarget.after('<img id="gform_ajax_spinner_' + formId + '" class="gform_ajax_spinner" src="' + spinnerUrl + '" alt="" />'); 2226 } 2227 2228} 2229 2230//---------------------------------------- 2231//------ EVENT FUNCTIONS ----------------- 2232//---------------------------------------- 2233 2234var __gf_keyup_timeout; 2235 2236jQuery( document ).on( 'change keyup', '.gfield input, .gfield select, .gfield textarea', function( event ) { 2237 gf_raw_input_change( event, this ); 2238} ); 2239 2240function gf_raw_input_change( event, elem ) { 2241 2242 // clear regardless of event type for maximum efficiency ;) 2243 clearTimeout( __gf_keyup_timeout ); 2244 2245 var $input = jQuery( elem ), 2246 htmlId = $input.attr( 'id' ), 2247 fieldId = gf_get_input_id_by_html_id( htmlId ), 2248 formId = gf_get_form_id_by_html_id( htmlId ), 2249 /** 2250 * Filter the field meta generated by a raw input change. 2251 * 2252 * @since 2.4.1 2253 * 2254 * @param object fieldMeta An object containing the field ID and form ID of the triggering Gravity Forms field. 2255 * @param object $input The jQuery object for the triggering field element. 2256 * @param object event The raw JS event. 2257 */ 2258 fieldMeta = gform.applyFilters( 'gform_field_meta_raw_input_change', { fieldId: fieldId, formId: formId }, $input, event ); 2259 2260 fieldId = fieldMeta.fieldId; 2261 formId = fieldMeta.formId; 2262 2263 if( ! fieldId ) { 2264 return; 2265 } 2266 2267 var isChangeElem = $input.is( ':checkbox' ) || $input.is( ':radio' ) || $input.is( 'select' ), 2268 isKeyupElem = ! isChangeElem || $input.is( 'textarea' ); 2269 2270 if( event.type == 'keyup' && ! isKeyupElem ) { 2271 return; 2272 } else if( event.type == 'change' && ! isChangeElem && ! isKeyupElem ) { 2273 return; 2274 } 2275 2276 if( event.type == 'keyup' ) { 2277 __gf_keyup_timeout = setTimeout( function() { 2278 gf_input_change( elem, formId, fieldId ); 2279 }, 300 ); 2280 } else { 2281 gf_input_change( elem, formId, fieldId ); 2282 } 2283 2284} 2285 2286/** 2287 * Get the input id from a form element's HTML id. 2288 * 2289 * @param {string} htmlId The HTML id of a form element. 2290 * 2291 * @returns {string} inputId The input id. 2292 */ 2293function gf_get_input_id_by_html_id( htmlId ) { 2294 2295 var ids = gf_get_ids_by_html_id( htmlId ), 2296 id = ids[ ids.length - 1 ]; 2297 2298 if ( ids.length == 3 ) { 2299 ids.shift(); 2300 id = ids.join( '.' ); 2301 } 2302 2303 return id; 2304} 2305 2306/** 2307 * Get the form id from a form element's HTML id. 2308 * 2309 * @param {string} htmlId The HTML id of a form element. 2310 * 2311 * @returns {string} formId The form id. 2312 */ 2313function gf_get_form_id_by_html_id( htmlId ) { 2314 var ids = gf_get_ids_by_html_id( htmlId ); 2315 return ids[0]; 2316} 2317 2318/** 2319 * Get the form, field, and input id by a form elements HTML id. 2320 * 2321 * Note: Only multi-input fields will be return an input ID. 2322 * 2323 * @param {string} htmlId The HTML id of a form element. 2324 * 2325 * @returns {array} ids An array contain the form, field and input id. 2326 */ 2327function gf_get_ids_by_html_id( htmlId ) { 2328 var ids = htmlId ? htmlId.split( '_' ) : []; 2329 for( var i = ids.length - 1; i >= 0; i-- ) { 2330 if ( ! gformIsNumber( ids[ i ] ) ) { 2331 ids.splice( i, 1 ); 2332 } 2333 } 2334 return ids; 2335} 2336 2337function gf_input_change( elem, formId, fieldId ) { 2338 gform.doAction( 'gform_input_change', elem, formId, fieldId ); 2339} 2340 2341function gformExtractFieldId( inputId ) { 2342 var fieldId = parseInt( inputId.toString().split( '.' )[0],10 ); 2343 return ! fieldId ? inputId : fieldId; 2344} 2345 2346function gformExtractInputIndex( inputId ) { 2347 var inputIndex = parseInt( inputId.toString().split( '.' )[1],10 ); 2348 return ! inputIndex ? false : inputIndex; 2349} 2350 2351jQuery( document ).on( 'submit.gravityforms', '.gform_wrapper form', function( event ) { 2352 2353 var formWrapper = jQuery( this ).closest( '.gform_wrapper' ), 2354 formID = formWrapper.attr( 'id' ).split( '_' )[ 2 ], 2355 hasPages = formWrapper.find( '.gform_page' ).length > 0,
2356 sourcePage = parseInt( formWrapper.find( 'input[name^="gform_source_page_number_"]' ).val(), 10 ), 2357 targetPage = parseInt( formWrapper.find( 'input[name^="gform_target_page_number_"]' ).val(), 10 ), 2358 isSubmit = targetPage === 0, 2359 isNextSubmit = ! isSubmit && ( targetPage > sourcePage ), 2360 isSave = jQuery( '#gform_save_' + formID ).val() === '1', 2361 submitButton; 2362 2363 // Get the next or submit button. 2364 if ( hasPages ) { 2365 // Get the visible page. 2366 var visiblePage = formWrapper.find( '.gform_page:visible' ), 2367 buttonType = isNextSubmit ? 'next' : 'submit'; 2368 2369 submitButton = visiblePage.find( '.gform_page_footer [id^="gform_' + buttonType + '_button_"]' ); 2370 } else { 2371 submitButton = formWrapper.find( '#gform_submit_button_' + formID ); 2372 } 2373 2374 var isButtonHidden = ! submitButton.is(':visible'), 2375 abortSubmission = ! isSave && ( isSubmit || isNextSubmit ) && isButtonHidden; 2376 2377 // If we are not saving or returning to an earlier page and the next/submit button is hidden abort the submission. 2378 if ( abortSubmission ) { 2379 window[ 'gf_submitting_' + formID ] = false; 2380 formWrapper.find( '.gform_ajax_spinner' ).remove(); 2381 event.preventDefault(); 2382 } else if ( isSubmit || isSubmit ) { 2383 var $reCaptcha = formWrapper.find( '.ginput_recaptcha' ); 2384 2385 if ( $reCaptcha.length !== 0 && $reCaptcha.data( 'size' ) === 'invisible' ) { 2386 // Check for the verified invisible captcha token first. 2387 var $reCaptchaResponse = formWrapper.find( 'input[name="g-recaptcha-response"]' ); 2388 if ( $reCaptchaResponse.length === 0 ) { 2389 $reCaptchaResponse = $reCaptcha.find( '.g-recaptcha-response' ); 2390 } 2391 var token = $reCaptchaResponse.val(); 2392 if ( ! token ) { 2393 // Execute the invisible captcha. 2394 grecaptcha.execute($reCaptcha.data('widget-id')); 2395 // Once the reCaptcha is triggered, set gf_submitting to true, so the form could be submitted if the 2396 // reCaptcha modal is closed (by clicking on the area out of the modal or the reCaptcha response expires) 2397 window['gf_submitting_' + formID] = false; 2398 event.preventDefault(); 2399 } 2400 } 2401 } 2402 2403} ); 2404 2405 2406 2407//---------------------------------------- 2408//------ HELPER FUNCTIONS ---------------- 2409//---------------------------------------- 2410 2411if( ! window['rgars'] ) { 2412 function rgars( array, prop ) { 2413 2414 var props = prop.split( '/' ), 2415 value = array; 2416 2417 for( var i = 0; i < props.length; i++ ) { 2418 value = rgar( value, props[ i ] ); 2419 } 2420 2421 return value; 2422 } 2423} 2424 2425if( ! window['rgar'] ) { 2426 function rgar( array, prop ) { 2427 if ( typeof array[ prop ] != 'undefined' ) { 2428 return array[ prop ]; 2429 } 2430 return ''; 2431 } 2432} 2433 2434String.prototype.format = function () { 2435 var args = arguments; 2436 return this.replace(/{(\d+)}/g, function (match, number) { 2437 return typeof args[number] != 'undefined' ? args[number] : match; 2438 }); 2439};
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.