1(function (Saf, $, undefined) { 2 3 /** 4 * Drupal behavior. 5 */ 6 Drupal.behaviors.secureAutofill = { 7 attach: function (context, settings) { 8 // Set up global variables and initiate processing. 9 $('body').once(function () { 10 11 // The node we are operating on. 12 Saf.nid = Drupal.settings.springboard.currentNid; 13 14 // Store URL parameters. If the parameter does not exist 15 // null is returned, if exists but empty, "" is returned. 16 Saf.afParam = Saf.getParameterByName('af'); 17 Saf.gsParam = Saf.getParameterByName('gs'); 18 Saf.noSave = Saf.getParameterByName('nosave'); 19 Saf.aaParam = Saf.getParameterByName('aa'); 20 21 // Make sure aa and gs aren't interchangeable. 22 if (Saf.aaParam !== null && isNaN(Saf.aaParam)) { 23 return false; 24 } 25 if (Saf.gsParam !== null && !isNaN(Saf.gsParam)) { 26 return false; 27 } 28 29 // Whether to show a "Hi user" greeting. 30 Saf.showWelcome = false; 31 32 // Is persistent gift strings enabled? 33 Saf.global = settings.secure_prepopulate.secure_prepopulate_global_gift_strings; 34 35 // Get the gs cookie lifetime 36 Saf.globalExpireUTC = settings.secure_prepopulate.secure_prepopulate_dynamic_gift_strings_cookie_lifetime; 37 Saf.globalExpire = new Date(); 38 Saf.globalExpire.setTime(Saf.globalExpireUTC); 39 40 // Is the current node excluded from global gift strings. 41 Saf.globalOmit = settings.secure_prepopulate.secure_prepopulate_gs_omit; 42 43 if (Saf.noSave) { 44 Saf.globalOmit = 1; 45 } 46 47 // Gift string from RMS params. 48 Saf.gsRMSValue = null; 49 Saf.rmsURL = settings.secure_prepopulate.market_source_remote_app_url || null; 50 Saf.rmsAppID = settings.secure_prepopulate.market_source_remote_app_id || null; 51 Saf.rmsGSFetchComplete = false; 52 53 // Read the node-specific gs cookie. 54 Saf.gsNodeCookie = $.cookie("gs-" + Saf.nid); 55 Saf.fundraiser = settings.fundraiser || null; 56 57 Saf.allowAdvocacyForms = settings.secure_prepopulate.secure_prepopulate_gift_strings_for_non_donation_forms; 58 if (Saf.allowAdvocacyForms != null) { 59 Saf.global = 1; 60 Saf.globalOmit = 0; 61 } 62 63 if (Saf.fundraiser && !Saf.gsNodeCookie && Saf.gsParam == null && Saf.aaParam == null && Saf.rmsURL && Saf.rmsAppID) { 64 // If this is a fundraiser form, and there's no gs param 65 // or node-specific cookie, try RMS. 66 // This in turn will call processGiftStrings(). 67 Saf.processRmsGiftStrings(); 68 } 69 else { 70 // Initiate processing of gift strings on any form type. 71 Saf.processGiftStrings(); 72 } 73 74 // Always run autofill. 75 Saf.processAutoFill(); 76 77 }); 78 } 79 }; // End Drupal.behaviors.secureAutofill 80 81 82})(window.SpringboardSaf = window.SpringboardSaf || {}, jQuery); 83; 84(function (Saf, $, undefined) { 85 86 // Helper function to get url params. 87 Saf.getParameterByName = function (name, url) { 88 if (!url) { 89 url = window.location.href; 90 } 91 name = name.replace(/[\[\]]/g, "\\$&"); 92 var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), 93 results = regex.exec(url); 94 if (!results) return null; 95 if (!results[2]) return ''; 96 return results[2].replace(/\+/g, " "); 97 } 98 99 Saf.getCrossDomainMethod = function () { 100 //Detect browser support for CORS. 101 if ('withCredentials' in new XMLHttpRequest()) { 102 return 'json'; 103 } 104 // IE-specific "CORS" XDR. 105 else if (typeof XDomainRequest !== "undefined") { 106 // IE9 doesn't seem to work with cookie values. 107 if (navigator.appVersion.indexOf("MSIE 9.") !== -1) { 108 return 'jsonp'; 109 } 110 return 'json'; 111 } 112 // Fallback is to use JSONP. 113 return 'jsonp'; 114 } 115 116})(window.SpringboardSaf = window.SpringboardSaf || {}, jQuery); 117; 118(function (Saf, $, undefined) { 119 120 // This function should only be called from 121 // Drupal.behaviors.secureAutoFill in secure-prepopulate.js. 122 // Variables starting with "Saf." are initialized there. 123 Saf.processAutoFill = function () { 124 // Handle secure prepopulate querystring. 125 // Check for js cookie first, if it's in place then use it rather than af. 126 // Cookie is based on nid. 127 var afCookie = null; 128 129 if (Saf.nid) { 130 afCookie = $.cookie("af-" + Saf.nid); 131 } 132 133 // If this is an offline form, use the AF if present, otherwise use regular logic. 134 Saf.offline = Drupal.settings.fundraiserOffline; 135 if (typeof (Saf.offline) == "undefined" || Saf.offline === false) { 136 Saf.offline = Saf.getParameterByName('offline'); 137 } 138 if (!afCookie || (Saf.offline && Saf.offline == 'true')) {
139 // Get af from URL if it wasn't in our cookie. 140 var af = Saf.afParam 141 if (af) { 142 // Set to null so this hash can be set server-side. 143 var afHash = null; 144 } 145 } 146 147 // Use the cookie if we have it and didn't set af above. 148 if (afCookie && typeof (af) == 'undefined') { 149 af = afCookie; 150 // Get per-user hash. 151 afHash = $.cookie("af-" + Saf.nid + '-hash'); 152 } 153 154 // Decrypt whichever value we chose to use above. 155 if (typeof (af) !== 'undefined' && typeof (afHash) !== 'undefined') { 156 processAutoFillAjax(af, afHash, afCookie); 157 } else if (Saf.autoFillFallback) { 158 Saf.autoFillFallback(processAutoFillAjaxResults); 159 } else if (Saf.postAutoFill) { 160 Saf.postAutoFill(); 161 } 162 }; 163 164 function processAutoFillAjax(af, afHash, afCookie) { 165 166 // Post af to 'get_amounts' callback, assemble request params and respond. 167 $.post("/js/secure_prepopulate/get_values", { 168 js_callback: "get_values", 169 js_module: "secure_prepopulate", 170 af: af, 171 user_hash: afHash, 172 nid: Saf.nid 173 }).done(function (data) { 174 // If response code is successful, take action. 175 if (data && data.response && data.response.code == 200 && data.content) { 176 processAutoFillAjaxResults(data, af, afHash, afCookie); 177 if (Saf.postAutoFill) Saf.postAutoFill(); 178 } else if (Saf.autoFillFallback) { 179 Saf.autoFillFallback(processAutoFillAjaxResults); 180 } 181 // End response handler. 182 }); 183 } 184 185 186 function processAutoFillAjaxResults(data, af, afHash, afCookie) { 187 188 // Set secure_prepop_autofilled field. 189 $('input[name*=secure_prepop_autofilled]').val(true); 190 191 // Show welcome message with link to 'not me' 192 Saf.showWelcome = true; 193 194 // Iterate through returned object and populate appropriate fields. 195 for (var key in data.content) { 196 if (data.content.hasOwnProperty(key)) { 197 // Email is keyed as "email", but appears on donation forms as "mail". 198 if (key === "email") { 199 $("input[name*='\[mail\]']").val(data.content[key]); 200 } 201 else { 202 // Populate input fields matching key with value returned from callback. 203 $("input[name*='\[" + key + "\]']").val(data.content[key]); 204 // Populate selects. 205 206 $("select[name*='\[" + key + "\]']").each(function () { 207 var currentVal = $(this).val(); 208 $('option[value="' + data.content[key] + '"]', this).prop('selected', true); 209 if (key === "country") { 210 updateStateCountry(this, data, key, currentVal); 211 } 212 }); 213 // Special handling for springboard form keys, which are prefixed with 'sbp_' 214 // Populate input fields matching key with value returned from callback. 215 $("input[name*='\[" + 'sbp_' + key + "\]']").val(data.content[key]); 216 // Populate selects. 217 $("select[name*='\[" + 'sbp_' + key + "\]']").each(function () { 218 var currentVal = $(this).val(); 219 $('option[value="' + data.content[key] + '"]', this).prop('selected', true); 220 if (key === "sbp_country") { 221 updateStateCountry(this, data, key, currentVal); 222 } 223 }); 224 // TODO handle select fields, radios, and checkboxes. 225 } 226 227 // Set welcome message from drupal.settings. 228 if (key === "first_name" && Saf.showWelcome === true && Saf.nid) { 229 var firstName = data.content[key]; 230 var markup = Drupal.settings.secure_prepopulate.secure_prepopulate_not_me; 231 // Replace FIRSTNAME with first name. 232 markup = markup.replace(/FIRSTNAME/g, firstName); 233 $('form.webform-client-form').before(markup); 234 // Special handling for 'not me' link. 235 $('#notme').click(Saf.autoFillFallbackNotMe || function (event) { 236 event.preventDefault(); 237 if (typeof (Saf.nid) !== 'undefined') { 238 // Clear af and gs cookies if they're set. 239 if (typeof ($.cookie('af-' + Saf.nid) !== 'undefined')) { 240 $.cookie('af-' + Saf.nid, null, { path: '/', secure: true }); 241 } 242 // Unset user hash. 243 if (typeof ($.cookie('af-' + Saf.nid + '-hash') !== 'undefined')) { 244 $.cookie('af-' + Saf.nid + '-hash', null, { path: '/', secure: true }); 245 } 246 // Unset gift string hash. 247 if (typeof ($.cookie('gs-' + Saf.nid) !== 'undefined')) { 248 $.cookie('gs-' + Saf.nid, null, { path: '/', secure: true }); 249 } 250 // Unset gift string hash. 251 if (typeof ($.cookie('gs-global') !== 'undefined')) { 252 $.cookie('gs-global', null, { path: '/', secure: true }); 253 } 254 // Unset user hash. 255 if (typeof ($.cookie('gs-' + Saf.nid + '-hash') !== 'undefined')) { 256 $.cookie('gs-' + Saf.nid + '-hash', null, { path: '/', secure: true }); 257 } 258 if (typeof ($.cookie('gs-' + Saf.nid + '-selected') !== 'undefined')) { 259 $.cookie('gs-' + Saf.nid + '-selected', null, { path: '/', secure: true }); 260 } 261 if (typeof ($.cookie('gs-global-hash') !== 'undefined')) { 262 $.cookie('gs-' + Saf.nid + '-hash', null, { path: '/', secure: true }); 263 } 264 // Remove querystring from url. 265 window.location = window.location.pathname; 266 } 267 }); 268 } 269 } 270 } 271 272 // Don't set the af cookie for offline forms. 273 if (Saf.nid && !afCookie && af && !afHash && (!Saf.offline || Saf.offline !== 'true')) { 274 // Set af cookie if it wasn't before. 275 // This cookie will expire at end of session. 276 $.cookie("af-" + Saf.nid, af, { path: '/', secure: true }); 277 // Set the per-user hash. 278 if (data.content.userhash) { 279 $.cookie("af-" + Saf.nid + "-hash", data.content.userhash, { path: '/', secure: true }); 280 } 281 } 282 // Issue a custom trigger so that page wrapper js can respond. 283 $(document).trigger('secure_prepop_autofilled'); 284 285 // End data check. 286 } 287 288 function updateStateCountry(countryField, data, key, currentCountry) { 289 var currentState = $('select[name*="state\]"]').val() || $('input[name*="state\]"]').val(); 290 var stateData = data.content.hasOwnProperty('state') && data.content['state']; 291 // The state field needs updating if the country has changed 292 // or the state value is missing but present in the data. 293 var needsUpdate = data.content[key] !== currentCountry || (!currentState && stateData) 294 if (needsUpdate) { 295 $(countryField).trigger('change'); 296 $(countryField).ajaxComplete(function () { 297 if (stateData) { 298 $('option[value="' + data.content['state'] + '"]', $('select[name*="[state]"]')).prop('selected', true); 299 $('input[name*="[state]"]').val(data.content['state']); 300 } 301 }); 302 } 303 } 304 305})(window.SpringboardSaf = window.SpringboardSaf || {}, jQuery); 306; 307(function (Saf, $, undefined) { 308 309 // This function should only be called from 310 // Drupal.behaviors.secureAutoFill in secure-prepopulate.js.
311 Saf.processRmsGiftStrings = function () { 312 313 var gsRMSFetchURL = Saf.rmsURL + '/' + Saf.rmsAppID + '/get'; 314 $.ajax({ 315 url: gsRMSFetchURL + '?cookie_prefix=gift_string&host=' + location.hostname, 316 type: 'GET', 317 dataType: Saf.getCrossDomainMethod(), 318 xhrFields: { 319 withCredentials: true 320 }, 321 success: function(data) { 322 323 // Grab the gift string from RMS. 324 var rmsGs = data.gs || null; 325 326 // If this is the first time the RMS has been called after 327 // the module has been enabled, there won't be a gift string. 328 // Check for a global cookie, grab its value and delete it. 329 if (!rmsGs) { 330 Saf.gsRMSValue = $.cookie("gs-global"); 331 if (Saf.gsRMSValue) { 332 // Tell setCookie it needs to set the RMS cookie. 333 Saf.rmsGSFetchComplete = 'failed'; 334 } 335 } 336 else { 337 Saf.rmsGSFetchComplete = true; 338 // The RMS does not send the gs value encoded, as SP expects it. 339 Saf.gsRMSValue = encodeURIComponent(rmsGs); 340 } 341 342 Saf.processGiftStrings(); 343 344 }, 345 error: function () { 346 Saf.processGiftStrings(); 347 } 348 }); 349 }; 350 351 Saf.processGiftStrings = function () { 352 353 // Initialize some local variables. 354 var gs; 355 var globalCookie = $.cookie("gs-global"); 356 // There is a "gs" parameter in the query. 357 if (Saf.gsParam != null) { 358 gs = Saf.gsParam; 359 // The sole purpose of the gsHash variable is to prevent 360 // RMS gs processing if the "not me" link provided by 361 // secure AF is clicked. The hash cookie is deleted, 362 // in that case. 363 // Set null value and get from php later. 364 var gsHash = null; 365 366 // Value for saving to Salesforce. 367 setGsFlag('Personalized URL') 368 } 369 else if (Saf.aaParam) { 370 var gsHash = null; 371 setGsFlag('Dynamic Ask') 372 gs = Saf.aaParam; 373 } 374 else if (Saf.fundraiser) { 375 // Only execute this code on fundraiser nodes. 376 // First check if there's a gs for this nid. 377 // If there is, we use that. These are session 378 // cookies, so unless the user has browser set 379 // to keep sessions permanent, they are short-lived. 380 if (Saf.nid && Saf.gsNodeCookie) { 381 gs = Saf.gsNodeCookie; 382 gsHash = $.cookie("gs-" + Saf.nid + '-hash'); 383 setGsFlag('Personalized URL'); 384 } 385 else if(Saf.global && Saf.globalOmit != 1) { 386 // Can we get a global from rms? 387 if (Saf.gsRMSValue) { 388 gs = Saf.gsRMSValue; 389 setGsFlag('Persistent Gift String'); 390 } 391 else if (globalCookie) { 392 // Global cookies have a configurable lifetime. 393 gs = globalCookie; 394 setGsFlag('Persistent Gift String'); 395 } 396 if (gs) { 397 // The global hash is used to activate/deactivate both 398 // RMS and Global gift strings. If it does not exist, nothing 399 // happens. 400 gsHash = $.cookie('gs-global-hash'); 401 // Both RMS and Global set a "pgs_cookie, presently. 402 } 403 } 404 } 405 406 // Decrypt whichever value we chose to use above. 407 if (gs != null && typeof (gsHash) !== 'undefined') { 408 // Post GS to 'get_amounts' callback, assemble request params and respond. 409 processGiftStringsAjax(gs, gsHash); 410 // End 411 } 412 else { 413 setGsFlag('None'); 414 } 415 }; 416 417 function setGsFlag(flag) { 418 $('input[name*="gs_flag"]').val(flag); 419 } 420 421 function processGiftStringsAjax(gs, gsHash) { 422 $.post( "/js/secure_prepopulate/get_amounts", { 423 js_callback: "get_amounts", 424 js_module: "secure_prepopulate", 425 gs: gs, 426 user_hash: gsHash, 427 nid: Saf.nid, 428 }).done(function (data) { 429 // If response code is successful, take action. 430 if (data && data.response && data.response.code == 200 && data.content) { 431 processGiftStringsAjaxResults(data, gs); 432 } 433 // End response handler. 434 }); 435 } 436 437 function processGiftStringsAjaxResults(data, gs) { 438 439 // Parse amounts and defaults into their appropriate fields if we are 440 // on a fundraiser node. 441 442 if (Saf.fundraiser) { 443 Saf.updateFields(data); 444 445 // Try to read "last submitted value cookie," if it's present and there are errors, 446 // set that value as default. 447 if ($('div.error').length > 0) { 448 selectedCookie = $.cookie('gs-' + Saf.nid + '-selected'); 449 if (selectedCookie && ($.isNumeric(selectedCookie) || selectedCookie === "other")) { 450 Saf.setRegularDefault(selectedCookie); 451 Saf.setRecurringDefault(selectedCookie); 452 var frequencies = Drupal.settings.defaultRecurringFrequencies; 453 $.each(frequencies, function(key, frequency) { 454 Saf.setFrequencyDefault(selectedCookie, frequency); 455 }); 456 } 457 } 458 459 460 // Set node-specific cookie. 461 // This cookie will expire at end of session, unless 462 // user has browser configured to preserve session cookies. 463 if (Saf.nid && gs && Saf.gsParam) { 464 $.cookie("gs-" + Saf.nid, gs, {path: '/', secure: true}); 465 // Set the per-user hash. 466 if (data.content.userhash) { 467 $.cookie("gs-" + Saf.nid + "-hash", data.content.userhash, {path: '/', secure: true}); 468 } 469 } 470 } 471 472 // Set the global cookie. Do this even if we are not 473 // currently on a fundraiser node. All that is required 474 // is that the gs url parameter exists. 475 if (gs && (Saf.gsParam || Saf.rmsGSFetchComplete == 'failed') && Saf.global && !Saf.noSave) { 476 gsCookieSet(gs, data); 477 } 478 479 // After adding the new amount form items re-run behaviors. 480 Drupal.attachBehaviors(); 481 482 // End data check. 483 } 484 485 function gsCookieSet(gs, data) { 486 487 // If the RMS is enabled use that for storing global gs. 488 if (Saf.rmsURL && Saf.rmsAppID) { 489 490 // Send gs value to RMS if it has not already been fetched. 491 if (Saf.gsParam || Saf.rmsGSFetchComplete == 'failed') { 492 var gsRMSSetURL = Saf.rmsURL + '/' + Saf.rmsAppID + '/set'; 493 $.ajax({ 494 url: gsRMSSetURL + '?gs=' + gs, 495 type: 'GET', 496 dataType: Saf.getCrossDomainMethod(), 497 xhrFields: { 498 withCredentials: true 499 }, 500 }); 501 } 502 } 503 504 // Always set the global cookie, in case user has disabled third party cookies.. 505 $.cookie("gs-global", gs, {expires: Saf.globalExpire, path: '/', secure: true}); 506 507 // Set the per-user hash. This is used to verify/activate both the RMS 508 // and Global cookies 509 if (data.content.userhash) { 510 $.cookie("gs-global-hash", data.content.userhash, {expires: Saf.globalExpire, path: '/', secure: true}); 511 } 512 } 513 514})(window.SpringboardSaf = window.SpringboardSaf || {}, jQuery); 515; 516(function (Saf, $, undefined) { 517 518 // Called from secure-prepopulate-gs.js. 519 Saf.updateFields = function(data) { 520 // Parse amounts and defaults into their appropriate fields. 521 updateAmounts(data); 522 updateDefault(data); 523 updateRecurring(data); 524 updateRecurringDefault(data); 525 updateFrequencies(data); 526 updateFrequenciesDefault(data); 527 }; 528 529 function updateAmounts(data) { 530 if (typeof (data.content.amounts) !== 'undefined') { 531 var labels = ''; 532 if (typeof data.content.amounts_label != 'undefined') { 533 labels = data.content.amounts_label.split("|"); 534 } 535 // If this is a designations form, special handling of amounts. 536 if ($('#webform-component-designations').length) { 537 // Iterate through each designation group, unless overridden. 538 $("div.designation-group-wrapper:not(.overridden)").each(function(){ 539 // Replace amounts for each designation. 540 541 // Take the last amount form item, alter its label and value, and insert before the 'other' form item. 542 var lastAmount = $('[id^="default-amounts-"] .form-item', this).last(
542).clone(true); 543 // Uncheck last amount. 544 $(lastAmount).children('input').attr('checked', false); 545 546 // Now remove all recurring regular options from the form. 547 $('[id^="default-amounts-"] .form-item', this).remove(); 548 549 // Next, iterate and process amounts. 550 var amounts = data.content.amounts.split("|"); 551 for (var i = 0, len = amounts.length; i < len; i++) { 552 // Set amount value. 553 $(lastAmount).children('input').val(amounts[i]); 554 // Set amount label, use appropriate currency. 555 if (Drupal.settings.fundraiser.currency.symbol) { 556 var symbol = Drupal.settings.fundraiser.currency.symbol; 557 } 558 else { 559 var symbol = "$"; 560 } 561 $(lastAmount).children('label').text(symbol + amounts[i]); 562 if (labels.length) { 563 $(lastAmount).children('label').text(labels[i]); 564 } 565 // Set element ID and corresponding label. 566 $('input', lastAmount).attr('id', 'edit-submitted-designations-designation-box-1-default-amounts-1-' + amounts[i]); 567 $('label', lastAmount).attr('for', 'edit-submitted-designations-designation-box-1-default-amounts-1-' + amounts[i]); 568 // Insert after last amount. 569 $('[id^="default-amounts-"]', this).append(lastAmount); 570 // Show the new amount. 571 $(lastAmount).show(); 572 // Reset last amount. 573 var lastAmount = $('[id^="default-amounts-"] .form-item', this).last().clone(true); 574 // Uncheck last amount. 575 $(lastAmount).children('input').attr('checked', false); 576 } 577 578 }); 579 } else if (($('input[name*=recurs_monthly]').attr("type") != "hidden") || ($('input[name*=recurs_monthly]').attr("type") == "hidden" && $('input[name*=recurs_monthly]').val() != "recurs")) { 580 // Find and replace amount. 581 // If this is a user choice form with or without dual ask, set amounts. 582 // If this is a one-time-only form, set amounts. Don't set amounts for recurring-only forms. 583 var amounts = data.content.amounts.split("|"); 584 setAmounts(amounts, labels); 585 // End handling for non-designation amounts. 586 } 587 // End handling for amounts. 588 } 589 } 590 591 function updateDefault(data) { 592 // Set 'default' amount. 593 if (typeof(data.content.default) !== 'undefined') { 594 // If this is a designations form, special handling of amounts. 595 if ($('#webform-component-designations').length) { 596 // Replace the designation default amount for each designations item. 597 // Iterate through each designation group, unless overridden. 598 $("div.designation-group-wrapper:not(.overridden)").each(function(){ 599 // Get the default amount as returned and attempt to set it for each designation. 600 var amounts = $('[id^="default-amounts-"] .form-item input:visible', this); 601 // Iterate through amounts, set value if possible. 602 for (var i = 0, len = amounts.length; i < len; i++) { 603 if (amounts[i].value == data.content.default) { 604 // Uncheck all other values first. 605 $('[id^="default-amounts-"] .form-item input', this).attr('checked', false); 606 // Now set ours. 607 $(amounts[i]).attr('checked', 'checked'); 608 } 609 } 610 }); 611 } 612 else if (($('input[name*=recurs_monthly]').attr("type") != "hidden") || ($('input[name*=recurs_monthly]').attr("type") == "hidden" && $('input[name*=recurs_monthly]').val() != "recurs")) { 613 // Find and replace amount. 614 // If this is a user choice form with or without dual ask, set default. 615 // If this is a one-time-only form, set default. Don't set default for recurring-only forms. 616 Saf.setRegularDefault(data.content.default); 617 // End handling for non-designation default. 618 } 619 } 620 } 621 622 function updateRecurring(data) { 623 624 if (typeof (data.content.recurring_amounts) !== 'undefined') { 625 var labels = ''; 626 if (typeof data.content.recurring_amounts_label != 'undefined') { 627 labels = data.content.recurring_amounts_label.split("|"); 628 } 629 // If this is a designations form, special handling of amounts. 630 if ($('#webform-component-designations').length) { 631 // Iterate through each designation group, unless overridden. 632 $("div.designation-group-wrapper:not(.overridden)").each(function(){ 633 // Replace amounts for each designation. 634 635 // Take the last amount form item, alter its label and value, and insert before the 'other' form item. 636 var lastAmount = $('[id^="recurring-amounts-"] .form-item', this).last(
636).clone(true); 637 // Uncheck last amount. 638 $(lastAmount).children('input').attr('checked', false); 639 640 // Now remove all recurring regular options from the form. 641 $('[id^="recurring-amounts-"] .form-item', this).remove(); 642 643 // Next, iterate and process amounts. 644 var recurring_amounts = data.content.recurring_amounts.split("|"); 645 for (var i = 0, len = recurring_amounts.length; i < len; i++) { 646 // Set amount value. 647 $(lastAmount).children('input').val(recurring_amounts[i]); 648 // Set amount label, use appropriate currency. 649 if (Drupal.settings.fundraiser.currency.symbol) { 650 var symbol = Drupal.settings.fundraiser.currency.symbol; 651 } 652 else { 653 var symbol = "$"; 654 } 655 $(lastAmount).children('label').text(symbol + recurring_amounts[i]); 656 if (labels.length) { 657 $(lastAmount).children('label').text(labels[i]); 658 } 659 // Set element ID and corresponding label. 660 $('input', lastAmount).attr('id', 'edit-submitted-designations-designation-box-1-recurring-amounts-1-' + recurring_amounts[i]); 661 $('label', lastAmount).attr('for', 'edit-submitted-designations-designation-box-1-recurring-amounts-1-' + recurring_amounts[i]); 662 // Insert after last amount. 663 $('[id^="recurring-amounts-"]', this).append(lastAmount); 664 // Show the new amount. 665 $(lastAmount).show(); 666 // Reset last amount. 667 var lastAmount = $('[id^="recurring-amounts-"] .form-item', this).last().clone(true); 668 // Uncheck last amount. 669 $(lastAmount).children('input').attr('checked', false); 670 } 671 672 }); 673 } 674 else { 675 // Begin handling of 676 // non-designation recurring amounts. 677 // Get amounts from return. 678 var amounts = data.content.recurring_amounts.split("|"); 679 680 // If this is a one-time-only form, take no action. 681 // If this is a user choice form without dual ask, take no action. 682 // If this is a user choice form with dual ask, set the recurring amounts. 683 if ($('input[name*=recurs_monthly]').attr("type") != "hidden" && $("div[id^=edit-submitted-][id$=recurring-amount] input:first").val() != '') { 684 setRecurringAmounts(amounts, labels); 685 } else if ($('input[name*=recurs_monthly]').attr("type") == "hidden" && $('input[name*=recurs_monthly]').val() == "recurs") { 686 // If this is a recurring-only form, set the regular amounts. 687 688 setAmounts(amounts, labels); 689 } 690 // End handling for non-designation recurring amounts. 691 } 692 } 693 } 694 695 function updateRecurringDefault(data) { 696 // Set recurring default. 697 if (typeof(data.content.recurring_default) !== 'undefined') { 698 // If this is a designations form, special handling of amounts. 699 if ($('#webform-component-designations').length) { 700 // Replace the designation recurring default amount for each designations item. 701 // Iterate through each designation group, unless overridden. 702 $("div.designation-group-wrapper:not(.overridden)").each(function(){ 703 // Get the recurring amount as returned and attempt to set it. 704 var recurring_amounts = $('[id^="recurring-amounts-"] .form-item input', this); 705 // Iterate through amounts, set value if possible. 706 for (var i = 0, len = recurring_amounts.length; i < len; i++) { 707 if (recurring_amounts[i].value == data.content.recurring_default) { 708 // Uncheck all other values first. 709 $('[id^="recurring-amounts-"] .form-item input', this).attr('checked', false); 710 // Now set ours. 711 $(recurring_amounts[i]).attr('checked', 'checked'); 712 } 713 } 714 }); 715 } 716 else { 717 // If this is a one-time-only form, take no action. 718 // If this is a user choice form without dual ask, take no action. 719 // If this is a user choice form with dual ask, set the recurring default amount. 720 if ($('input[name*=recurs_monthly]').attr("type") != "hidden" && $("div[id^=edit-submitted-][id$=recurring-amount] .form-type-radio:first input").val() != '') { 721 Saf.setRecurringDefault(data.content.recurring_default); 722 } else if ($('input[name*=recurs_monthly]').attr("type") == "hidden" && $('input[name*=recurs_monthly]').val() == "recurs") { 723 // If this is a recurring-only form, set the regular default amount. 724 Saf.setRegularDefault(data.content.recurring_default); 725 } 726 } 727 } 728 } 729 730 function updateFrequencies(data) { 731 var frequencies = Drupal.settings.defaultRecurringFrequencies; 732 733 $.each(frequencies, function(key, frequency) { 734 735 if (typeof(data.content[frequency + "_amounts"]) !== 'undefined') { 736 // If this is a designations form, special handling of amounts. 737 if ($('#webform-component-designations').length) { 738 // Iterate through each designation group, unless overridden. 739 $("div.designation-group-wrapper:not(.overridden)").each(function () { 740 // Replace amounts for each designation. 741 var frequencyClass = frequency; 742 // Take the last amount form item, clone it. 743 var lastAmount = $('[id^="' + frequencyClass + '-amounts-"] .form-item', this).last(
743).clone(true); 744 // Uncheck last amount 745 $(lastAmount).children('input').attr('checked', false); 746 747 // Remove existing frequency amounts 748 $('[id^="' + frequencyClass + '-amounts-"] .form-item', this).remove(); 749 750 // Process new amounts. 751 var amounts = data.content[frequency + "_amounts"].split("|"); 752 var labels = ''; 753 if (typeof data.content[frequency + "_amounts_label"] != 'undefined') { 754 labels = data.content[frequency + "_amounts_label"].split("|"); 755 } 756 757 for (var i = 0, len = amounts.length; i < len; i++) { 758 // Set amount value. 759 $(lastAmount).children('input').val(amounts[i]); 760 761 // Set amount label with currency. 762 if (Drupal.settings.fundraiser.currency.symbol) { 763 var symbol = Drupal.settings.fundraiser.currency.symbol; 764 } else { 765 var symbol = "$"; 766 } 767 $(lastAmount).children('label').text(symbol + amounts[i]); 768 if (labels.length) { 769 $(lastAmount).children('label').text(labels[i]); 770 } 771 772 // Set element ID and label. 773 $('input', lastAmount).attr('id', 'edit-submitted-designations-designation-box-1-' + frequencyClass + '-amounts-1-' + amounts[i]); 774 $('label', lastAmount).attr('for', 'edit-submitted-designations-designation-box-1-' + frequencyClass + '-amounts-1-' + amounts[i]); 775 776 // Append the new amount. 777 $('[id^="' + frequencyClass + '-amounts-"]', this).append(lastAmount); 778 $(lastAmount).show(); 779 780 // Clone for next iteration. 781 var lastAmount = $('[id^="' + frequencyClass + '-amounts-"] .form-item', this).last().clone(true); 782 $(lastAmount).children('input').attr('checked', false); 783 } 784 }); 785 } 786 else { 787 // Begin handling of non-designation recurring amounts. 788 // Get amounts from return. 789 var amounts = data.content[frequency + "_amounts"].split("|"); 790 var labels = ''; 791 if (typeof data.content[frequency + "_amounts_label"] != 'undefined') { 792 labels = data.content[frequency + "_amounts_label"].split("|"); 793 } 794 // If this is a one-time-only form, take no action. 795 // If this is a user choice form without dual ask, take no action. 796 // If this is a user choice form with dual ask, set the recurring amounts. 797 var frequencyClass = frequency.replace(/_/g, '-'); 798 if ($('input[name*=recurs_monthly]').attr("type") != "hidden" && $("input[id$=" + frequencyClass + "-amount] input:first").val() != '') { 799 setFrequenciesAmounts(amounts, labels, frequency); 800 } else if ($('input[name*=recurs_monthly]').attr("type") == "hidden" && $('input[name*=recurs_monthly]').val() != "NO_RECURR") { 801 // If this is a recurring-only form, set the regular amounts. 802 setAmounts(amounts, labels); 803 } 804 // End handling for non-designation recurring amounts. 805 } 806 } 807 }); 808 } 809 810 function updateFrequenciesDefault(data) { 811 // Set recurring default. 812 var frequencies = Drupal.settings.defaultRecurringFrequencies; 813 814 $.each(frequencies, function(key, frequency) { 815 var frequencyClass = frequency.replace(/_/g, '-'); 816 817 if (typeof(data.content[frequency + '_default']) !== 'undefined') { 818 819 // If this is a designations form, special handling of amounts. 820 if ($('#webform-component-designations').length) { 821 var frequencyClass = frequency; 822 // Replace the designation recurring default amount for each designations item. 823 // Iterate through each designation group, unless overridden. 824 $("div.designation-group-wrapper:not(.overridden)").each(function () { 825 // Get the recurring amount as returned and attempt to set it. 826 var frequency_amounts = $('[id^="' + frequencyClass + '-amounts-"] .form-item input', this); 827 // Iterate through amounts, set value if possible. 828 for (var i = 0, len = frequency_amounts.length; i < len; i++) { 829 if (frequency_amounts[i].value == data.content[frequency + '_default']) { 830 // Uncheck all other values first. 831 $('[id^="' +frequencyClass + '-amounts-"] .form-item input', this).attr('checked', false); 832 // Now set ours. 833 $(frequency_amounts[i]).attr('checked', 'checked'); 834 } 835 } 836 }); 837 } 838 else { 839 // If this is a one-time-only form, take no action. 840 // If this is a user choice form without dual ask, take no action. 841 // If this is a user choice form with dual ask, set the recurring default amount. 842 if ($('input[name*=recurs_monthly]').attr("type") != "hidden" && $("div[id^=edit-frequencies][id$=" + frequencyClass + "-amount] .form-type-radio:first input").val() != '') { 843 Saf.setFrequencyDefault(data.content[frequency + '_default'], frequency); 844 } else if ($('input[name*=recurs_monthly]').attr("type") == "hidden" && $('input[name*=recurs_monthly]').val() != "NO_RECURR") { 845 // If this is a recurring-only form, set the regular default amount. 846 Saf.setRegularDefault(data.content[frequency + '_default']); 847 } 848 } 849 } 850 }); 851 } 852 853 854 // Helper function to override amounts onent. 855 function setAmounts(amounts, labels) { 856 // Find and replace amount. 857 // Take last form item, alter its label and value, and insert before the 'other' form item. 858 var lastAmount = $('div[id^=edit-submitted-][id$=amount]:not([id$=recurring-amount]) .form-type-radio').last().clone(true); 859 // Uncheck last amount. 860 $(lastAmount).children('input').attr('checked', false); 861 862 // Remove all regular options from the form. 863 $('div[id^=edit-submitted-][id$=amount]:not([id$=recurring-amount]) .form-type-radio').remove(); 864 865 // If the last amount's value is 'other', add it back to the end of the form item. 866 if ($('input', lastAmount).val() == 'other') { 867 var otherAmount = $(lastAmount).clone(true); 868 } 869 870 for (var i = 0, len = amounts.length; i < len; i++) { 871 // Set amount value. 872 $(lastAmount).children('input').val(amounts[i]); 873 // Set amount label, use appropriate currency. 874 if (typeof(Drupal.settings.fundraiser) !== "undefined" && typeof(Drupal.settings.fundraiser.currency) !== "undefined" && typeof(Drupal.settings.fundraiser.currency.symbol) !== "undefined") { 875 var symbol = Drupal.settings.fundraiser.currency.symbol; 876 } 877 else { 878 var symbol = "$"; 879 } 880 $(lastAmount).children('label').text(symbol + amounts[i]); 881 if (labels.length) { 882 $(lastAmount).children('label').text(labels[i]); 883 } 884 885 // Set element ID. 886 var oldId = $('input', lastAmount).attr('id').split('-'); 887 oldId.splice(-1,1); 888 oldId = oldId.join('-'); 889 var newId = oldId + '-' + i; 890 $('input', lastAmount).attr('id', newId); 891 892 var oldLabel = $('label', lastAmount).attr('for').split('-'); 893 oldLabel.splice(-1,1); 894 oldLabel = oldLabel.join('-'); 895 var newLabel = oldLabel + '-' + i; 896 $('label', lastAmount).attr('for', newLabel); 897 898 // Remove and then add the default classes. 899 lastAmount.removeClass(); 900 lastAmount.addClass('form-item form-type-radio form-item-submitted-donation-recurring-amount control-group'); 901 // Insert after last amount. 902 $('div[id^=edit-submitted-][id$=amount]:not([id$=recurring-amount])').append(lastAmount); 903 // Show the new amount. 904 $(lastAmount).show(); 905 // Reset last amount. 906 var lastAmount = $('div[id^=edit-submitted-][id$=amount]:not([id$=recurring-amount]) .form-item').last().clone(true); 907 // Uncheck last amount. 908 $(lastAmount).children('input').attr('checked', false); 909 } 910 911 // If we have an other amount, append it now. 912 if (typeof(otherAmount) !== "undefined") { 913 // Set element ID. 914 var oldId = $('input', otherAmount).attr('id').split('-'); 915 oldId.splice(-1,1); 916 oldId = oldId.join('-'); 917 var newId = oldId + '-' + amounts.length; 918 $('input', otherAmount).attr('id', newId); 919 920 var oldLabel = $('label', otherAmount).attr('for').split('-'); 921 oldLabel.splice(-1,1); 922 oldLabel = oldLabel.join('-'); 923 var newLabel = oldLabel + '-' + amounts.length; 924 $('label', otherAmount).attr('for', newLabel); 925 926 $('div[id^=edit-submitted-][id$=amount]:not([id$=recurring-amount])').append(otherAmount); 927 } 928 } 929 930 // Helper function to override recurring amounts. 931 function setRecurringAmounts(recurring_amounts, labels) { 932 // Find and replace amount. 933 // Take last form item, alter its label and value, and insert before the 'other' form item. 934 var lastAmount = $('div[id^=edit-submitted-][id$=recurring-amount] .form-type-radio').last().clone(true); 935 // Uncheck last amount. 936 $(lastAmount).children('input').attr('checked', false); 937 938 if (lastAmount.length > 0) { 939 // Remove all recurring options from the form. 940 $('div[id^=edit-submitted-][id$=recurring-amount] .form-type-radio').remove(); 941 942 // If the last amount's value is 'other', add it back to the end of the form item. 943 if ($('input', lastAmount).val() == 'other') { 944 var otherAmount = $(lastAmount).clone(true); 945 } 946 947 // Next, iterate and process amounts. 948 for (var i = 0, len = recurring_amounts.length; i < len; i++) { 949 // Set amount value. 950 $(lastAmount).children('input').val(recurring_amounts[i]); 951 // Set amount label, use appropriate currency. 952 if (typeof(Drupal.settings.fundraiser) !== "undefined" && typeof(Drupal.settings.fundraiser.currency) !== "undefined" && typeof(Drupal.settings.fundraiser.currency.symbol) !== "undefined") { 953 var symbol = Drupal.settings.fundraiser.currency.symbol; 954 } 955 else { 956 var symbol = "$"; 957 } 958 $(lastAmount).children('label').text(symbol + recurring_amounts[i]); 959 if (labels.length) { 960 $(lastAmount).children('label').text(labels[i]); 961 } 962 963 // Set element ID. 964 var oldId = $('input', lastAmount).attr('id').split('-'); 965 oldId.splice(-1,1); 966 oldId = oldId.join('-') + '-' + i; 967 var newId = oldId + i; 968 $('input', lastAmount).attr('id', newId); 969 970 var oldLabel = $('label', lastAmount).attr('for').split('-'); 971 oldLabel.splice(-1,1); 972 oldLabel = oldLabel.join('-') + '-' + i; 973 var newLabel = oldLabel + i; 974 $('label', lastAmount).attr('for', newLabel); 975 976 // Remove and then add the default classes. 977 lastAmount.removeClass(); 978 lastAmount.addClass('form-item form-type-radio form-item-submitted-donation-recurring-amount control-group'); 979 // Insert after last amount. 980 $('div[id^=edit-submitted-][id$=recurring-amount]').append(lastAmount); 981 // Show the new amount. 982 $(lastAmount).show(); 983 // Reset last amount. 984 var lastAmount = $('div[id^=edit-submitted-][id$=recurring-amount] .form-item').last().clone(true); 985 // Uncheck last amount. 986 $(lastAmount).children('input').attr('checked', false); 987 } 988 989 // If we have an other amount, append it now. 990 if (typeof(otherAmount) !== "undefined") { 991 // Set element ID. 992 var oldId = $('input', otherAmount).attr('id').split('-'); 993 oldId.splice(-1,1); 994 oldId = oldId.join('-'); 995 var newId = oldId + '-' + recurring_amounts.length; 996 $('input', otherAmount).attr('id', newId); 997 998 var oldLabel = $('label', otherAmount).attr('for').split('-'); 999 oldLabel.splice(-1,1); 1000 oldLabel = oldLabel.join('-'); 1001 var newLabel = oldLabel + '-' + recurring_amounts.length; 1002 $('label', otherAmount).attr('for', newLabel); 1003 1004 $('div[id^=edit-submitted-][id$=recurring-amount]').append(otherAmount); 1005 } 1006 } 1007 1008 } 1009 1010 // Helper function to override recurring amounts. 1011 function setFrequenciesAmounts(frequency_amounts, labels, frequency) { 1012 // Find and replace amount. 1013 // Take last form item, alter its label and value, and insert before the 'other' form item. 1014 var frequencyClass = frequency.replace(/_/g, '-'); 1015 1016 var lastAmount = $('div[id^=edit-frequencies-][id$=' + frequencyClass + '-amount] .form-type-radio').last().clone(true); 1017 // Uncheck last amount. 1018 $(lastAmount).children('input').attr('checked', false); 1019 1020 if (lastAmount.length > 0) { 1021 // Remove all recurring options from the form. 1022 $('div[id^=edit-frequencies-][id$=' +frequencyClass + '-amount] .form-type-radio').remove(); 1023 1024 // If the last amount's value is 'other', add it back to the end of the form item. 1025 if ($('input', lastAmount).val() == 'other') { 1026 var otherAmount = $(lastAmount).clone(true); 1027 } 1028 1029 // Next, iterate and process amounts. 1030 for (var i = 0, len = frequency_amounts.length; i < len; i++) { 1031 // Set amount value. 1032 $(lastAmount).children('input').val(frequency_amounts[i]); 1033 // Set amount label, use appropriate currency. 1034 if (typeof(Drupal.settings.fundraiser) !== "undefined" && typeof(Drupal.settings.fundraiser.currency) !== "undefined" && typeof(Drupal.settings.fundraiser.currency.symbol) !== "undefined") { 1035 var symbol = Drupal.settings.fundraiser.currency.symbol; 1036 } 1037 else { 1038 var symbol = "$"; 1039 } 1040 $(lastAmount).children('label').text(symbol + frequency_amounts[i]); 1041 1042 if (labels.length) { 1043 $(lastAmount).children('label').text(labels[i]); 1044 } 1045 1046 // Set element ID. 1047 var oldId = $('input', lastAmount).attr('id').split('-'); 1048 oldId.splice(-1,1); 1049 oldId = oldId.join('-') + '-' + i; 1050 var newId = oldId + i; 1051 $('input', lastAmount).attr('id', newId); 1052 1053 var oldLabel = $('label', lastAmount).attr('for').split('-'); 1054 oldLabel.splice(-1,1); 1055 oldLabel = oldLabel.join('-') + '-' + i; 1056 var newLabel = oldLabel + i; 1057 $('label', lastAmount).attr('for', newLabel); 1058 1059 // Remove and then add the default classes. 1060 lastAmount.removeClass(); 1061 lastAmount.addClass('form-item form-type-radio form-item-submitted-donation-' + frequencyClass + '-amount control-group'); 1062 // Insert after last amount. 1063 $('div[id^=edit-frequencies-][id$=' +frequencyClass + '-amount]').append(lastAmount); 1064 // Show the new amount. 1065 $(lastAmount).show(); 1066 // Reset last amount. 1067 var lastAmount = $('div[id^=edit-frequencies-][id$=' + frequencyClass + '-amount] .form-item').last().clone(true); 1068 // Uncheck last amount. 1069 $(lastAmount).children('input').attr('checked', false); 1070 } 1071 1072 // If we have an other amount, append it now. 1073 if (typeof(otherAmount) !== "undefined") { 1074 // Set element ID. 1075 var oldId = $('input', otherAmount).attr('id').split('-'); 1076 oldId.splice(-1,1); 1077 oldId = oldId.join('-'); 1078 var newId = oldId + '-' + frequency_amounts.length; 1079 $('input', otherAmount).attr('id', newId); 1080 1081 var oldLabel = $('label', otherAmount).attr('for').split('-'); 1082 oldLabel.splice(-1,1); 1083 oldLabel = oldLabel.join('-'); 1084 var newLabel = oldLabel + '-' + frequency_amounts.length; 1085 $('label', otherAmount).attr('for', newLabel); 1086 1087 $('div[id^=edit-frequencies-][id$=' + frequencyClass + '-amount]').append(otherAmount); 1088 } 1089 } 1090 } 1091 1092 1093 // Helper function to set regular default. 1094 Saf.setRegularDefault = function(regular_default) { 1095 // Get the default amount as returned and attempt to set it. 1096 var amounts = $('div[id^=edit-submitted-][id$=-amount]:not([id$=recurring-amount]) .form-item input'); 1097 // Iterate through amounts, set value if possible. 1098 for (var i = 0, len = amounts.length; i < len; i++) { 1099 if (amounts[i].value == regular_default) { 1100 // Uncheck all other values first. 1101 $('div[id^=edit-submitted-][id$=-amount]:not([id$=recurring-amount]) .form-item input').attr('checked', false); 1102 // Now set ours. 1103 $(amounts[i]).attr('checked', 'checked'); 1104 } 1105 } 1106 } 1107 1108 // Helper function to set recurring de
1108fault. 1109 Saf.setRecurringDefault = function(recurring_default) { 1110 // Get the recurring_default amount as returned and attempt to set it. 1111 var amounts = $('div[id^=edit-submitted-][id$=recurring-amount]:not([id$=donation-amount]) .form-item input'); 1112 // Iterate through amounts, set value if possible. 1113 for (var i = 0, len = amounts.length; i < len; i++) { 1114 if (amounts[i].value == recurring_default) { 1115 // Uncheck all other values first. 1116 $('div[id^=edit-submitted-][id$=recurring-amount]:not([id$=donation-amount]) .form-item input').attr('checked', false); 1117 // Now set ours. 1118 $(amounts[i]).attr('checked', 'checked'); 1119 } 1120 } 1121 } 1122 1123 // Helper function to set recurring default. 1124 Saf.setFrequencyDefault = function(frequency_default, frequency) { 1125 var frequencyClass = frequency.replace(/_/g, '-'); 1126 1127 // Get the frequency_default amount as returned and attempt to set it. 1128 var amounts = $('div[id^=edit-frequencies-][id$=' + frequencyClass +'-amount]:not([id$=donation-amount]) .form-item input'); 1129 // Iterate through amounts, set value if possible. 1130 for (var i = 0, len = amounts.length; i < len; i++) { 1131 if (amounts[i].value == frequency_default) { 1132 // Uncheck all other values first. 1133 $('div[id^=edit-frequencies-][id$=' + frequencyClass +'-amount]:not([id$=donation-amount]) .form-item input').attr('checked', false); 1134 // Now set ours. 1135 $(amounts[i]).attr('checked', 'checked'); 1136 } 1137 } 1138 } 1139 1140})(window.SpringboardSaf = window.SpringboardSaf || {}, jQuery); 1141; 1142jQuery.cookie=function(name,value,options){if(typeof value!='undefined'){options=options||{};if(value===null){value='';options.expires=-1}var expires='';if(options.expires&&(typeof options.expires=='number'||options.expires.toUTCString)){var date;if(typeof options.expires=='number'){date=new Date();date.setTime(date.getTime()+(options.expires*24*60*60*1000))}else{date=options.expires}expires='; expires='+date.toUTCString()}var path=options.path?'; path='+(options.path):'';var domain=options.domain?'; domain='+(options.domain):'';var secure=options.secure?'; secure':'';document.cookie=[name,'=',encodeURIComponent(value),expires,path,domain,secure].join('')}else{var cookieValue=null;if(document.cookie&&document.cookie!=''){var cookies=document.cookie.split(';');for(var i=0;i<cookies.length;i++){var cookie=jQuery.trim(cookies[i]);if(cookie.substring(0,name.length+1)==(name+'=')){cookieValue=decodeURIComponent(cookie.substring(name.length+1));break}}}return cookieValue}}; 1143; 1144/** 1145 * Store and parse market source data in cookies. 1146 */ 1147Drupal.behaviors.marketSourceInit = { 1148 attach: function(context) { (function($) { 1149 1150 $('body:not(.marketsource-processed)', context).each(function(i) { 1151 if (typeof Drupal.settings.market_source === 'undefined' || 1152 typeof Drupal.settings.market_source.qs_keys === 'undefined') { 1153 return; 1154 } 1155 1156 var qs_keys = Drupal.settings.market_source.qs_keys; 1157 1158 // Create an element to parse the URI. 1159 var uri = document.createElement('a'); 1160 uri.href = location.href; 1161 1162 /** 1163 * Parse the raw querystring into an object. 1164 */ 1165 var urlParams = {}; 1166 (function () { 1167 var parsed, 1168 regex = /([^&=]+)=?([^&]*)/g, 1169 decode = function (value) { 1170 // Regex for replacing addition symbol with a space and encode unencoded percent signs. 1171 try { 1172 return decodeURIComponent(value.replace(/\+/g, " ")); 1173 } catch (e) { 1174 return decodeURIComponent(value.replace(/\+/g, " ").replace(/%(?!\d+)/g, '%25')); 1175 } 1176 }, 1177 querystring = uri.search.substring(1); 1178 while (parsed = regex.exec(querystring)) { 1179 var keyname = new String(decode(parsed[1])); 1180 urlParams[keyname.toLowerCase()] = decode(parsed[2]); 1181 } 1182 })(); 1183 1184 /** 1185 * Sets a cookie. 1186 */ 1187 var setCookie = function (name, value, noOverwrite) { 1188 if (noOverwrite) { 1189 // make sure this cookie doesn't exist already 1190 var cookie = getCookie(name); 1191 if (cookie != false && cookie != null && cookie != '') { 1192 return; 1193 } 1194 } 1195 if (typeof $.cookie !== 'undefined') { 1196 name = 'market_source__' + name; 1197 if (typeof Drupal.settings.market_source.cookie_domain !== 'undefined') { 1198 $.cookie(name, value, { path: Drupal.settings.market_source.cookie_path, domain: Drupal.settings.market_source.cookie_domain, secure: true }); 1199 } 1200 else { 1201 $.cookie(name, value, { path: Drupal.settings.market_source.cookie_path, secure: true }); 1202 } 1203 } 1204 }; 1205 1206 /** 1207 * Reads data from a cookie. 1208 */ 1209 var getCookie = function (name) { 1210 var retval = false;
1211 if (typeof $.cookie !== 'undefined') { 1212 name = 'market_source__' + name; 1213 retval = $.cookie(name); 1214 } 1215 return retval; 1216 }; 1217 1218 /** 1219 * Check the querystring keys for existing cookie values. 1220 */ 1221 var applyParams = function (params) { 1222 for (var key in qs_keys) { 1223 // Check the querystring for this key. 1224 if (typeof params[key] !== 'undefined') { 1225 qs_keys[key]['value'] = params[key]; 1226 if (qs_keys[key]['persistence'] != 'direct') { 1227 // Save this value as a cookie. 1228 setCookie(key, params[key], qs_keys[key]['persistence'] == 'on'); 1229 } 1230 } 1231 if (qs_keys[key]['persistence'] != 'direct') { 1232 // Is there already a cookie set? 1233 var cookie = getCookie(key); 1234 if (cookie != false && cookie != null && cookie != '') { 1235 // Store the cookie's value in our qs_keys. 1236 qs_keys[key]['value'] = cookie; 1237 } 1238 } 1239 } 1240 }; 1241 1242 /** 1243 * Handle referrers as a special case. 1244 */ 1245 var applyReferrer = function (preset) { 1246 var referrer 1247 if (typeof preset !== 'undefined' && typeof preset['referrer'] !== 'undefined') { 1248 referrer = preset['referrer']; 1249 } 1250 else { 1251 var referrer = document.referrer; 1252 } 1253 1254 if (referrer == '') { 1255 referrer = '(none)'; 1256 } 1257 var cookie; 1258 if (typeof qs_keys['initial_referrer']['value'] !== 'undefined') { 1259 cookie = getCookie('initial_referrer'); 1260 if (cookie == false || cookie == null || cookie == '') { 1261 // Store the referrer value in our qs_keys. 1262 qs_keys['initial_referrer']['value'] = referrer; 1263 // Set initial_referrer cookie. 1264 setCookie('initial_referrer', qs_keys['initial_referrer']['value']); 1265 } else { 1266 qs_keys['initial_referrer']['value'] = cookie; 1267 } 1268 } 1269 if (typeof qs_keys['referrer']['value'] !== 'undefined') { 1270 if (referrer == '(none)') { 1271 // browser isn't providing a referrer, so check for one from before 1272 cookie = getCookie('referrer'); 1273 if (cookie != false && cookie != null && cookie != '') { 1274 qs_keys['referrer']['value'] = cookie; 1275 } 1276 } else { 1277 // Store the referrer value in our qs_keys. 1278 qs_keys['referrer']['value'] = referrer; 1279 // Set the referrer cookie. 1280 setCookie('referrer', qs_keys['referrer']['value']); 1281 } 1282 } 1283 }; 1284 1285 /** 1286 * Populate the market source fields in this page's webforms. 1287 */ 1288 var marketSourceFormPopulate = function() { 1289 if (typeof Drupal.settings.market_source.form_keys === 'undefined') { 1290 return; 1291 } 1292 1293 // Set a maximum length for each key's value. 1294 var maxlength = 255; 1295 if (typeof Drupal.settings.market_source.maxlength !== 'undefined') { 1296 maxlength = Drupal.settings.market_source.maxlength; 1297 } 1298 1299 // add search engine, search string, and user agent fields to qs_keys 1300 var qs_keys = Drupal.settings.market_source.qs_keys; 1301 if (typeof qs_keys['initial_referrer'] !== 'undefined' && typeof qs_keys['search_engine'] !== 'undefined' 1302 && qs_keys['search_engine']['value'] == null 1303 ) { 1304 if (/http(s?)\:\/\/www\.google\./.test(qs_keys['initial_referrer']['value'])) { 1305 qs_keys['search_engine']['value'] = 'Google'; 1306 } 1307 else if (/http(s?)\:\/\/search\.msn/.test(qs_keys['initial_referrer']['value'])) { 1308 qs_keys['search_engine']['value'] = 'MSN'; 1309 } 1310 else if (/http(s?)\:\/\/search\.yahoo/.test(qs_keys['initial_referrer']['value'])) { 1311 qs_keys['search_engine']['value'] = 'Yahoo!'; 1312 } 1313 else if (/http(s?)\:\/\/www\.bing/.test(qs_keys['initial_referrer']['value'])) { 1314 qs_keys['search_engine']['value'] = 'Bing'; 1315 } 1316 else if (/http(s?)\:\/\/msxml\.excite\.com/.test(qs_keys['initial_referrer']['value'])) { 1317 qs_keys['search_engine']['value'] = 'Excite'; 1318 } 1319 else if (/http(s?)\:\/\/search\.lycos\.com/.test(qs_keys['initial_referrer']['value'])) { 1320 qs_keys['search_engine']['value'] = 'Lycos'; 1321 } 1322 else if (/http(s?)\:\/\/www\.alltheweb\.com/.test(qs_keys['initial_referrer']['value'])) { 1323 qs_keys['search_engine']['value'] = 'All The Web'; 1324 } 1325 else if (/http(s?)\:\/\/search\.aol\.com/.test(qs_keys['initial_referrer']['value'])) { 1326 qs_keys['search_engine']['value'] = 'AOL'; 1327 } 1328 else if (/http(s?)\:\/\/(www)?\.ask\.co/.test(qs_keys['initial_referrer']['value'])) { 1329 qs_keys['search_engine']['value'] = 'Ask.com'; 1330 } 1331 else if (/http(s?)\:\/\/www\.hotbot\.com/.test(qs_keys['initial_referrer']['value'])) { 1332 qs_keys['search_engine']['value'] = 'HotBot'; 1333 } 1334 else if (/http(s?)\:\/\/www\.metacrawler\.com/.test(qs_keys['initial_referrer']['value'])) { 1335 qs_keys['search_engine']['value'] = 'Metacrawler'; 1336 } 1337 else if (/http(s?)\:\/\/search\.earthlink\.net/.test(qs_keys['initial_referrer']['value'])) { 1338 qs_keys['search_engine']['value'] = 'Earthlink'; 1339 } 1340 } 1341 if (typeof qs_keys['initial_referrer'] !== 'undefined' && typeof qs_keys['search_string'] !== 'undefined' 1342 && qs_keys['search_string']['value'] == null 1343 ) { 1344 // just Bing and Yahoo!. Google hides its search strings behind a redirect these days.
1345 if (/http(s?)\:\/\/search\.yahoo/.test(qs_keys['initial_referrer']['value'])) { 1346 var matches = /(\?|\&)p\=([^\&]+)/.exec(qs_keys['initial_referrer']['value']); 1347 if (matches != null && typeof(matches[2]) !== 'undefined') { 1348 qs_keys['search_string']['value'] = decodeURIComponent(matches[2].replace(/\+/g, '%20')); 1349 } 1350 } 1351 else if (/http(s?)\:\/\/www\.bing/.test(qs_keys['initial_referrer']['value'])) { 1352 var matches = /(\?|\&)q\=([^\&]+)/.exec(qs_keys['initial_referrer']['value']); 1353 if (matches != null && typeof(matches[2]) !== 'undefined') { 1354 qs_keys['search_string']['value'] = decodeURIComponent(matches[2].replace(/\+/g, '%20')); 1355 } 1356 } 1357 } 1358 if (typeof qs_keys['user_agent'] !== 'undefined') { 1359 qs_keys['user_agent']['value'] = navigator.userAgent; 1360 } 1361 1362 // Iterate across all webforms on the page. 1363 for (var form_id in Drupal.settings.market_source.form_keys) { 1364 // Iterate across all form keys in this webform. 1365 var form_keys = Drupal.settings.market_source.form_keys[form_id]; 1366 for (var key in form_keys) { 1367 // Is this key set in qs_keys object? 1368 if (typeof qs_keys[key]['value'] !== 'undefined') { 1369 var value = qs_keys[key]['value']; 1370 if (typeof value === 'string') { 1371 value = value.substring(0, maxlength); 1372 }
1373 // Handle referrers as a special case. 1374 if (key == 'initial_referrer' || key == 'referrer') { 1375 if (value == '(none)') { 1376 value = null; 1377 } 1378 } 1379 // If the value is not null, set the value. 1380 if (value != null) { 1381 //var selector = 'form#' + form_id + ' #' + form_keys[key] + ':not(.marketsource-processed)'; 1382 var selector = 'form#' + form_id + ' input[name="' + form_keys[key] + '"]:not(.marketsource-processed)'; 1383 1384 // Set the value. 1385 $(selector, context) 1386 .val(qs_keys[key]['value']) 1387 .addClass('marketsource-processed'); 1388 } 1389 } 1390 } 1391 } 1392 }; 1393 1394 var crossDomainMethod = function() { 1395 //Detect browser support for CORS. 1396 if ('withCredentials' in new XMLHttpRequest()) { 1397 return 'json'; 1398 } 1399 // IE-specific "CORS" XDR. 1400 else if (typeof XDomainRequest !== "undefined") { 1401 // IE9 doesn't seem to work with cookie values. 1402 if (navigator.appVersion.indexOf("MSIE 9.") !== -1) { 1403 return 'jsonp'; 1404 } 1405 return 'json'; 1406 } 1407 // Fallback is to use JSONP. 1408 return 'jsonp'; 1409 }; 1410 1411 // If the remote market source application is configured check that for ms values. 1412 if ( 1413 Drupal.settings.market_source_remote 1414 && Drupal.settings.market_source_remote.app_id 1415 && Drupal.settings.market_source_remote.app_url 1416 ) { 1417 // Determine the data type for this request. 1418 var dataType = crossDomainMethod(); 1419 1420 // Create an array of values to be joined into the app request url. 1421 var rmsUrl = [ 1422 Drupal.settings.market_source_remote.app_url, 1423 Drupal.settings.market_source_remote.app_id, 1424 (dataType === 'jsonp') ? 'get-jsonp' : 'get' 1425 ]; 1426 1427 // Create an array of values to be joined into the app request url's querystring. 1428 var rmsParams = [ 1429 (dataType === 'jsonp') ? 'callback=?' : '', 1430 'host=' + encodeURIComponent(uri['hostname']) 1431 ]; 1432 1433 $.ajax({ 1434 url: rmsUrl.join('/') + '?' + rmsParams.join('&'), 1435 type: 'GET', 1436 dataType: dataType, 1437 xhrFields: { 1438 withCredentials: true 1439 }, 1440 success: function (data) { 1441 applyParams(data); 1442 applyParams(urlParams); 1443 applyReferrer(data); 1444 marketSourceFormPopulate() 1445 }, 1446 error: function () { //Add these parameters to display the required response 1447 applyParams(urlParams); 1448 applyReferrer(); 1449 marketSourceFormPopulate(); 1450 } 1451 }); 1452 } 1453 // Else apply only the url parameters. 1454 else { 1455 applyParams(urlParams); 1456 applyReferrer(); 1457 marketSourceFormPopulate(); 1458 } 1459 1460 }).addClass('marketsource-processed'); 1461 1462 })(jQuery); } 1463}; 1464; 1465(function ($) { 1466 1467 // Makes ajax call to social share endpoint clicking share link 1468 // Grabs social share referrer URL and appends it to link 1469 // Opens popup social window. 1470 // Prevents double share due to repreated link clcking or popup blockers. 1471 Drupal.behaviors.sb_social = { 1472 attach: function (context, settings) { 1473 $('.social-share-link').each(function () { 1474 var link = window.location.href; 1475 // Drupal once to limit clicks on ajax page reload. 1476 $(this).once('popup', function() { 1477 $(this).click(function (e) { 1478 // Setup some vars we use later. 1479 var $elem = $(this); 1480 var $url = Drupal.settings.basePath; 1481 var service; 1482 1483 // Build social share ajax URLS. 1484 if ($(this).hasClass('facebook')) { 1485 $url += 'sb_social/share_event/facebook/'; 1486 service = 'facebook'; 1487 } 1488 if ($(this).hasClass('twitter')) { 1489 $url += 'sb_social/share_event/twitter/'; 1490 service = 'twitter'; 1491 } 1492 if ($(this).hasClass('email')) { 1493 $url += 'sb_social/share_event/email/'; 1494 service = 'email'; 1495 } 1496 if ($(this).hasClass('bluesky')) { 1497 $url += 'sb_social/share_event/bluesky/'; 1498 service = 'bluesky'; 1499 } 1500 $url = $url + Drupal.settings.sb_social.id + '/'; 1501 $url = $url + Drupal.settings.sb_social.id_type + '/'; 1502 $url = $url + Drupal.settings.sb_social.market_source + '/'; 1503 if (typeof Drupal.settings.sb_social.submission_id !== 'undefined') { 1504 $url = $url + '?sid=' + Drupal.settings.sb_social.submission_id; 1505 } 1506 1507 // Make the ajax call to register the share with Drupal (and Salesforce). 1508 jQuery.ajax({ 1509 beforeSend: function () {
1510 // Don't do the ajax call if this link has already been clicked 1511 // and the popup window has been blocked or is still open. 1512 if ($elem.hasClass('social-processed')) { 1513 return false; 1514 } 1515 }, 1516 url: $url, 1517 success: function (response) { 1518 // The response is a link to the page, with a social 1519 // share parameter appended. 1520 // The shorten module has an option to 'www' instead of 'http' 1521 // which breaks twitter integration. add http to links. 1522 if (response.indexOf("http") === -1) { 1523 response = 'https://' + response; 1524 } 1525 link = encodeURIComponent(response); 1526 }, 1527 // Don't use async because we have to wait for the updated link. 1528 async: false 1529 }); 1530 1531 // Mark this link as clicked. 1532 $(this).addClass('social-processed'); 1533 1534 //Open the popup or email app. 1535 var settings = Drupal.settings.sb_social; 1536 1537 switch (service) { 1538 case 'twitter': 1539 t = socialPopup(this, 'https://twitter.com/intent/tweet?text=' + encodeURIComponent(settings.twitter_message) + '&url=' + link); 1540 e.returnValue = false; 1541 e.preventDefault(); 1542 break; 1543 case 'facebook': 1544 socialPopup(this, 'https://facebook.com/sharer.php?u=' + link); 1545 e.returnValue = false; 1546 e.preventDefault(); 1547 break; 1548 case 'email': 1549 $elem.attr('href', ' mailto:?subject=' + encodeURIComponent(settings.email_subject) + '&body=' + encodeURIComponent(settings.email_message) + "%0D%0A%0D%0A" + link); 1550 $(this).removeClass('social-processed'); 1551 break; 1552 case 'bluesky': 1553 t = socialPopup(this, 'https://bsky.app/intent/compose?text=' + encodeURIComponent(settings.bluesky_message) + ' ' + link); 1554 e.returnValue = false; 1555 e.preventDefault(); 1556 break; 1557 } 1558 }); 1559 }); 1560 }); 1561 } 1562 }; 1563 1564 // Popup opener. 1565 var socialPopup = function (item, path) { 1566 1567 if (!path) { 1568 console.log("path must not be empty"); 1569 return false; 1570 } 1571 1572 var options = { 1573 windowName: 'sbSocialPopup', 1574 windowOptions: 'width=550,height=420', 1575 callback: function (item) { 1576 // The callback function gets fired (by setInterval) when the window 1577 // is closed, thereby re-enabling subsequent ajax calls 1578 // to get new social share IDs. 1579 $(item).removeClass('social-processed'); 1580 window.sbSocialPopup = null; 1581 } 1582 }; 1583 1584 // If the window already exists, just update the location, otherwise 1585 // open one. 1586 if (window.sbSocialPopup) { 1587 // Firefox won't focus an already open window unless you close it first. 1588 if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) { 1589 window.clearInterval(window.oauthInterval); 1590 window.sbSocialPopup.close(); 1591 window.sbSocialPopup = window.open(path, options.windowName, options.windowOptions); 1592 } 1593 else { 1594 window.sbSocialPopup.location.href = path; 1595 } 1596 } 1597 else { 1598 window.sbSocialPopup = window.open(path, options.windowName, options.windowOptions); 1599 } 1600 window.sbSocialPopup.focus(); 1601 1602 //If the window is closed, re-enable the social share click event 1603 //that was previously disabled to prevent double clicks. 1604 var x = 0; 1605 window.oauthInterval = window.setInterval(function () { 1606 x++; 1607 if ((window.sbSocialPopup && window.sbSocialPopup.closed) || x === 30) { 1608 window.clearInterval(window.oauthInterval); 1609 options.callback(item); 1610 } 1611 }, 1000, x); 1612 }; 1613 1614})(jQuery); 1615 1616; 1617(function($) { 1618 1619 Drupal.behaviors.braintreePaypal = { 1620 attach: function(context, settings) { 1621 settings = settings.braintree; 1622 settings.paypal.autofill = 'always'; 1623 $(document).on('braintree.methodChange', function (event, paymentMethod) { 1624 if (paymentMethod == 'paypal') { 1625 compactPaypal(true); 1626 } 1627 else if (paymentMethod == 'applepay' && settings.hasOwnProperty('applepay') && settings.applepay.hasOwnProperty('compact') && settings.applepay.compact === true) {
1628 // If the selected method is applepay, check if applepay is set for compact mode--if this is the case, then we take no action since the corresponding 1629 // version of this file for applepay will handle the compacting logic. 1630 } 1631 else if (paymentMethod === 'daf' && Drupal.settings.hasOwnProperty('springboard_daf') && Drupal.settings.springboard_daf.hasOwnProperty('compact') && Drupal.settings.springboard_daf.compact === true) { 1632 // If the selected method is applepay, check if applepay is set for compact mode--if this is the case, then we take no action since the corresponding 1633 // version of this file for applepay will handle the compacting logic. 1634 } 1635 else { 1636 // We are switching from paypal to a method that is not set to compact, so show all the form fields. 1637 compactPaypal(false); 1638 } 1639 }); 1640 $('body').once('braintree-autofilled', function () { 1641 $(document).on('braintree.autoFilled', function(event, btInstance, payLoad, autofilled) { 1642 if (btInstance.settings.currentPaymentMethod == 'paypal' && autofilled && !btInstance.btPaypalAutoSubmitted) { 1643 populatePhone(payLoad); 1644 if (verifyPaypalFields(payLoad)) { 1645 // Set this variable so the main script knows we submitted. 1646 btInstance.btPaypalAutoSubmitted = true; 1647 1648 if (btInstance.$allSubmits.length > 1) { 1649 // Designation form. 1650 btInstance.$submit.trigger('click', ['submit']); 1651 } 1652 else { 1653 // Don't change original submit behavior for non-designation forms. 1654 btInstance.$form.submit(); 1655 } 1656 1657 } 1658 else { 1659 // Missing required fields, expose them. 1660 compactPaypal(false); 1661 } 1662 } 1663 }); 1664 }); 1665 1666 var verifyPaypalFields = function(obj) { 1667 var remoteDonorFields = ['email', 'firstName', 'lastName', 'address', 'state', 'zip']; 1668 for (var i = 0; i < remoteDonorFields.length; i++) { 1669 if (!obj.hasOwnProperty(remoteDonorFields[i]) || !obj[remoteDonorFields[i]]) { 1670 return false; 1671 } 1672 } 1673 return true; 1674 }; 1675 1676 var populatePhone = function(obj) { 1677 var phone = null; 1678 var billingPhone = $("#webform-component-billing-information input[name$='sbp_phone]']"); 1679 var donorPhone = $("#webform-component-donor-information input[name$='sbp_phone]']"); 1680 if (billingPhone.length) { 1681 phone = $(billingPhone); 1682 } 1683 if (donorPhone.length) { 1684 phone = $(donorPhone); 1685 } 1686 if (phone && obj.hasOwnProperty('phone') && obj.phone != '') { 1687 $(phone).val(obj.phone); 1688 } 1689 }; 1690 1691 var compactPaypal = function(collapse) { 1692 if (settings.paypal && settings.paypal.compact && hasDefaultFields()) { 1693 var fieldsetsVisible = $('#webform-component-donor-information:visible, #webform-component-billing-information:visible').length > 0; 1694 var currentState = settings.paypal.collapsed; 1695 var layout = settings.paypal.form_layout || false; 1696 if (collapse && fieldsetsVisible) { 1697 if (layout == 'two_column_donation') { 1698 $('#left').hide(); 1699 } 1700 $('#webform-component-donor-information').hide(); 1701 $('#webform-component-billing-information').hide(); 1702 settings.paypal.collapsed = true; 1703 if (settings.applepay !== undefined) { 1704 settings.applepay.collapsed = true; 1705 } 1706 if (Drupal.settings.springboard_daf !== undefined) { 1707 Drupal.settings.springboard_daf.collapsed = true; 1708 } 1709 } else if (!collapse && !fieldsetsVisible) { 1710 if (layout == 'two_column_donation') { 1711 $('#left').show(); 1712 } 1713 $('#webform-component-donor-information').show(); 1714 $('#webform-component-billing-information').show(); 1715 settings.paypal.collapsed = false; 1716 if (settings.applepay !== undefined) { 1717 settings.applepay.collapsed = false;
1718 } 1719 if (Drupal.settings.springboard_daf !== undefined) { 1720 Drupal.settings.springboard_daf.collapsed = false; 1721 } 1722 } 1723 } 1724 }; 1725 1726 var hasDefaultFields = function() { 1727 var fundraiserDefaultFields = { 1728 donorDefaults: [ 1729 'first_name', 1730 'last_name', 1731 'mail', 1732 ], 1733 billingDefaults: [ 1734 'address', 1735 'address_line_2', 1736 'city', 1737 'country', 1738 'state', 1739 'zip', 1740 ], 1741 }; 1742 1743 var notHidden = function() { 1744 return $(this).attr('type') != 'hidden'; 1745 }; 1746 1747 var donorInfo = $('#webform-component-donor-information :input').filter(notHidden); 1748 1749 var billingInfo = $('#webform-component-billing-information :input').filter(notHidden); 1750 var onlyDefaults = true; 1751 $.each(donorInfo, function(key, value) { 1752 var n = $(value).attr('name').match(/[^[\]]+(?=])/g)[1]; 1753 if ($.inArray(n, fundraiserDefaultFields.donorDefaults) < 0 && n != 'sbp_phone') { 1754 onlyDefaults = false; 1755 return; 1756 } 1757 }); 1758 $.each(billingInfo, function(key, value) { 1759 var n = $(value).attr('name').match(/[^[\]]+(?=])/g)[1]; 1760 if ($.inArray(n, fundraiserDefaultFields.billingDefaults) < 0 && n != 'sbp_phone') { 1761 onlyDefaults = false; 1762 return; 1763 } 1764 }); 1765 return onlyDefaults; 1766 }; 1767 1768 1769 }, 1770 1771 }; 1772})(jQuery); 1773; 1774(function($) { 1775 Drupal.behaviors.zipLookup = { 1776 attach: function(context, settings) { 1777 var fields = Drupal.settings.zip_lookup || {}; 1778 if (fields.ids) { 1779 $('form.webform-client-form').each(function(i, v) { 1780 configUpdateCityAndStateByZip(fields.ids.zip, fields.ids.city, fields.ids.state, fields.ids.country, v); 1781 }); 1782 } 1783 1784 function configUpdateCityAndStateByZip(zipId, cityId, stateId, countryId, v) { 1785 var zipObj = $(zipId + " input", v); 1786 var cityObj = $(cityId + " input", v); 1787 var stateObj = $(stateId + " select", v); 1788 var skipCountry = false; 1789 if (countryId == false) { 1790 skipCountry = true; 1791 var countryObj = {}; 1792 countryObj.val = function() { 1793 return 'US'; 1794 } 1795 } 1796 else { 1797 var countryObj = $(countryId + " select", v); 1798 } 1799 // Make sure only 1 form field matches each of the ID parameters supplied. 1800 if (zipObj.length == 1 && cityObj.length == 1 && stateObj.length == 1 && (countryObj.length == 1 || skipCountry == true)) { 1801 zipObj.blur(function() { 1802 // Only make the ajax request if we've got a valid 5-digit zip code, US is the selected country, and either the city or state field are empty. 1803 if ((/^\d{5}$/.test($(this).val())) && countryObj.val() == 'US' && (cityObj.val().trim() === "" || stateObj.val().trim() === "")) { 1804 $.ajax({ 1805 url: "/zip_lookup/autopop-city-state-by-zip", 1806 dataType: "json", 1807 type: "POST", 1808 data: { 1809 zip: $(this).val() 1810 } 1811 }).done(function(data) { 1812 if (cityObj.val().trim() == "") { 1813 cityObj.val(data.city); 1814 } 1815 if (stateObj.val().trim() == "") { 1816 // Trigger change for Florida. 1817 stateObj.val(data.state_id).change(); 1818 1819 // Overwrite the HTML of the span used to display the select box value on responsive forms 1820 var targetOption = stateObj.find("option[value=" + data.state_id + "]"); 1821 stateObj.next().filter(".custom-select").find("span > span").html(targetOption.html()); 1822 } 1823 }); 1824 } 1825 }); 1826 } 1827 } 1828 }, 1829 1830 }; 1831 1832})(jQuery); 1833; 1834(function ($) { 1835 Drupal.behaviors.formEditProtection = { 1836 attach: function (context, settings) { 1837 $(document).ready(function() { 1838 $(Drupal.settings.formEditProtectionSelector, context).once(function () { 1839 var actionTaken = false;
1840 var targetForm = $(this); 1841 var originalFormHTML = targetForm.html(); 1842 function preventExitCheck() { 1843 if (actionTaken || originalFormHTML != targetForm.html()) { // Detect HTML-related form changes 1844 return 'You must submit this form to save its changes.'; 1845 } 1846 return ''; 1847 } 1848 $(this).find('input, textarea').keydown(function () { 1849 actionTaken = true; 1850 }); 1851 $(this).find('input').click(function () { 1852 actionTaken = true; 1853 }); 1854 $(this).find('select, checkbox, radio').change(function () { 1855 actionTaken = true; 1856 }); 1857 // Prevent false-positives for refresh or clicking links: 1858 $(document).keydown(function(e) { 1859 if (e.keyCode == 82 && (e.ctrlKey || e.metaKey)) { 1860 if (preventExitCheck() == '') { 1861 window.onbeforeunload = null; 1862 } 1863 } 1864 }); 1865 $('a').click(function () { 1866 if (preventExitCheck() == '') { 1867 window.onbeforeunload = null; 1868 } 1869 }); 1870 $(window).on('beforeunload', function() { 1871 return preventExitCheck(); 1872 }); 1873 $(this).submit(function () { 1874 window.onbeforeunload = null; 1875 }); 1876 }); 1877 }); 1878 } 1879 }; 1880})(jQuery); 1881; 1882(function($) { 1883 Drupal.behaviors.braintreeApplepay = { 1884 attach: function(context, settings) { 1885 settings = settings.braintree; 1886 settings.applepay.autofill = 'always'; 1887 1888 $(document).on('braintree.methodChange', function(event, paymentMethod) { 1889 if (paymentMethod == 'applepay') { 1890 compactApplepay(true); 1891 } 1892 else if (paymentMethod == 'paypal' && settings.hasOwnProperty('paypal') && settings.paypal.hasOwnProperty('compact') && settings.paypal.compact === true) { 1893 // If the selected method is paypal, check if paypal is set for compact mode--if this is the case, then we take no action since the corresponding 1894 // version of this file for paypal will handle the compacting logic. 1895 } 1896 else if (paymentMethod === 'daf' && Drupal.settings.hasOwnProperty('springboard_daf') && Drupal.settings.springboard_daf.hasOwnProperty('compact') && Drupal.settings.springboard_daf.compact === true) { 1897 // If the selected method is applepay, check if applepay is set for compact mode--if this is the case, then we take no action since the corresponding 1898 // version of this file for applepay will handle the compacting logic. 1899 } 1900 else if (paymentMethod == 'venmo' && settings.hasOwnProperty('venmo') && settings.venmo.hasOwnProperty('compact') && settings.venmo.compact === true) { 1901 // If the selected method is venmo, check if venmo is set for compact mode--if this is the case, then we take no action since the corresponding 1902 // version of this file for venmo will handle the compacting logic. 1903 } 1904 else { 1905 // We are switching from applepay to a method that is not set to compact, so show all the form fields. 1906 compactApplepay(false); 1907 } 1908 }); 1909 1910 $(document).on('braintree.autoFilled', function(event, btInstance, payLoad, autofilled) { 1911 if (btInstance.settings.currentPaymentMethod == 'applepay' && autofilled) { 1912 populatePhone(payLoad); 1913 if (!verifyApplepayFields(payLoad)) { 1914 // Missing required fields, expose them. 1915 compactApplepay(false); 1916 } 1917 } 1918 }); 1919 1920 var verifyApplepayFields = function(obj) { 1921 var remoteDonorFields = ['email', 'firstName', 'lastName', 'address', 'state', 'zip']; 1922 for (var i = 0; i < remoteDonorFields.length; i++) { 1923 if (!obj.hasOwnProperty(remoteDonorFields[i]) || !obj[remoteDonorFields[i]]) { 1924 return false; 1925 } 1926 } 1927 return true; 1928 }; 1929 1930 var populatePhone = function(obj) { 1931 var phone = null; 1932 var billingPhone = $('#webform-component-billing-information input[name$="sbp_phone]"]'); 1933 var donorPhone = $('#webform-component-donor-information input[name$="sbp_phone]"]'); 1934 if (billingPhone.length) { 1935 phone = $(billingPhone); 1936 } 1937 if (donorPhone.length) { 1938 phone = $(donorPhone); 1939 } 1940 if (phone && obj.hasOwnProperty('phone') && obj.phone != '') { 1941 $(phone).val(obj.phone); 1942 } 1943 }; 1944 1945 var compactApplepay = function (collapse) { 1946 if (settings.applepay && settings.applepay.compact && hasDefaultFields()) { 1947 var fieldsetsVisible = $('#webform-component-donor-information:visible, #
1947webform-component-billing-information:visible').length > 0; 1948 var currentState = settings.applepay.collapsed; 1949 var layout = settings.applepay.form_layout || false; 1950 if (collapse && fieldsetsVisible) { 1951 if (layout == 'two_column_donation') { 1952 $('#left').hide(); 1953 } 1954 $('#webform-component-donor-information').hide(); 1955 $('#webform-component-billing-information').hide(); 1956 settings.applepay.collapsed = true; 1957 if (settings.paypal !== undefined) { 1958 settings.paypal.collapsed = true; 1959 } 1960 if (Drupal.settings.springboard_daf !== undefined) { 1961 Drupal.settings.springboard_daf.collapsed = true; 1962 } 1963 } else if (!collapse && !fieldsetsVisible) { 1964 if (layout == 'two_column_donation') { 1965 $('#left').show(); 1966 } 1967 $('#webform-component-donor-information').show(); 1968 $('#webform-component-billing-information').show(); 1969 settings.applepay.collapsed = false; 1970 if (settings.paypal !== undefined) { 1971 settings.paypal.collapsed = false; 1972 } 1973 if (Drupal.settings.springboard_daf !== undefined) { 1974 Drupal.settings.springboard_daf.collapsed = true; 1975 } 1976 } 1977 } 1978 }; 1979 1980 var hasDefaultFields = function() { 1981 var fundraiserDefaultFields = { 1982 donorDefaults: [ 1983 'first_name', 1984 'last_name', 1985 'mail', 1986 ], 1987 billingDefaults: [ 1988 'address', 1989 'address_line_2', 1990 'city', 1991 'country', 1992 'state', 1993 'zip', 1994 ], 1995 }; 1996 1997 var notHidden = function() { 1998 return $(this).attr('type') != 'hidden'; 1999 }; 2000 2001 var donorInfo = $('#webform-component-donor-information :input').filter(notHidden); 2002 2003 var billingInfo = $('#webform-component-billing-information :input').filter(notHidden); 2004 var onlyDefaults = true; 2005 $.each(donorInfo, function(key, value) { 2006 var n = $(value).attr('name').match(/[^[\]]+(?=])/g)[1]; 2007 if ($.inArray(n, fundraiserDefaultFields.donorDefaults) < 0 && n != 'sbp_phone') { 2008 onlyDefaults = false; 2009 return; 2010 } 2011 }); 2012 $.each(billingInfo, function(key, value) { 2013 var n = $(value).attr('name').match(/[^[\]]+(?=])/g)[1]; 2014 if ($.inArray(n, fundraiserDefaultFields.billingDefaults) < 0 && n != 'sbp_phone') { 2015 onlyDefaults = false; 2016 return; 2017 } 2018 }); 2019 return onlyDefaults; 2020 }; 2021 }, 2022 }; 2023})(jQuery); 2024; 2025/** 2026 * @file 2027 */ 2028 2029(function($) { 2030 Drupal.behaviors.springboardForms = { 2031 attach: function (context, settings) { 2032 2033 $('.webform-client-form #edit-submit').once(function() { 2034 $('.webform-client-form #edit-submit').click(function() { 2035 var button = $(this); 2036 // Disable the button. This prevents double/triple mouse clicking. 2037 if ($('form.webform-client-form')[0].checkValidity) { 2038 if ($('form.webform-client-form')[0].checkValidity()) { 2039 // If we have a jQuery validator present, validate that first. 2040 if ($.validator) { 2041 if (!$('form.webform-client-form').validate().form()) { 2042 return; 2043 } 2044 } 2045 $(this).hide(); 2046 $('.fundraiser_submit_message').hide(); 2047 $('.webform-user-thank-you').remove(); 2048 $(this).after('<div class="webform-user-wrapper"><p class="webform-user-thank-you">' + Drupal.t("Thank you, your submission is processing") + '.</p><div class="webform-user-spinner"></div></div>'); 2049 } 2050 } 2051 else { 2052 button.hide(); 2053 $('.fundraiser_submit_message').hide(); 2054 button.after('<div class="webform-user-wrapper"><p class="webform-user-thank-you">' + Drupal.t("Thank you, your submission is processing") + '.</p><div class="webform-user-spinner"></div></div>'); 2055 } 2056 }); 2057 }); 2058 } // attach.function 2059 // drupal.behaviors. 2060 } 2061})(jQuery); 2062; 2063(function($) { 2064 Drupal.behaviors.springboard_cookie = { 2065 attach: function(context, settings) { 2066 $('body').once(function() { 2067 // Is the Springboard cookie set on this client? 2068 var cookie = $.cookie(Drupal.settings.springboard_cookie.name); 2069 if (!cookie) { 2070 // No cookie, so make sure cookies are enabled. 2071 $.cookie('cookies_enabled', '1', { path: '/', secure: true }); 2072 if ($.cookie('cookies_enabled') == '1') { 2073 // Call out to the server for a cookie. 2074 $.post( 2075 '/js/springboard_cookie/new_cookie', 2076 { 2077 js_callback: 'new_cookie', 2078 js_module: 'springboard_cookie' 2079 }, 2080 function(data, status) { 2081 // Save the cookie to this client. 2082 var settings = { 2083 expires: parseInt(data.expires), 2084 path: data.path, 2085 secure: true, 2086 }; 2087 if (Drupal.settings.springboard_cookie.domain != '') { 2088 settings.domain = Drupal.settings.springboard_cookie.domain; 2089 } 2090 $.cookie( 2091 Drupal.settings.springboard_cookie.name, 2092 data.cookie, 2093 settings 2094 ); 2095 } 2096 ); 2097 } 2098 } 2099 2100 }) 2101 } 2102 }; 2103})(jQuery); 2104; 2105/*global jQuery */ 2106/*jshint browser:true */ 2107/*! 2108* FitVids 1.1 2109*
2110* Copyright 2013, Chris Coyier - http://css-tricks.com + Dave Rupert - http://daverupert.com 2111* Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/ 2112* Released under the WTFPL license - http://sam.zoy.org/wtfpl/ 2113* 2114*/ 2115 2116(function( $ ){ 2117 2118 "use strict"; 2119 2120 $.fn.fitVids = function( options ) { 2121 var settings = { 2122 customSelector: null 2123 }; 2124 2125 if(!document.getElementById('fit-vids-style')) { 2126 // appendStyles: https://github.com/toddmotto/fluidvids/blob/master/dist/fluidvids.js 2127 var head = document.head || document.getElementsByTagName('head')[0]; 2128 var css = '.fluid-width-video-wrapper{width:100%;position:relative;padding:0;}.fluid-width-video-wrapper iframe,.fluid-width-video-wrapper object,.fluid-width-video-wrapper embed {position:absolute;top:0;left:0;width:100%;height:100%;}'; 2129 var div = document.createElement('div'); 2130 div.innerHTML = '<p>x</p><style id="fit-vids-style">' + css + '</style>'; 2131 head.appendChild(div.childNodes[1]); 2132 } 2133 2134 if ( options ) { 2135 $.extend( settings, options ); 2136 } 2137 2138 return this.each(function(){ 2139 var selectors = [ 2140 "iframe[src*='player.vimeo.com']", 2141 "iframe[src*='youtube.com']", 2142 "iframe[src*='youtube-nocookie.com']", 2143 "iframe[src*='kickstarter.com'][src*='video.html']", 2144 "object", 2145 "embed" 2146 ]; 2147 2148 if (settings.customSelector) { 2149 selectors.push(settings.customSelector); 2150 } 2151 2152 var $allVideos = $(this).find(selectors.join(',')); 2153 $allVideos = $allVideos.not("object object"); // SwfObj conflict patch 2154 2155 $allVideos.each(function(){ 2156 var $this = $(this); 2157 if (this.tagName.toLowerCase() === 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; } 2158 var height = ( this.tagName.toLowerCase() === 'object' || ($this.attr('height') && !isNaN(parseInt($this.attr('height'), 10))) ) ? parseInt($this.attr('height'), 10) : $this.height(), 2159 width = !isNaN(parseInt($this.attr('width'), 10)) ? parseInt($this.attr('width'), 10) : $this.width(), 2160 aspectRatio = height / width; 2161 if(!$this.attr('id')){ 2162 var videoID = 'fitvid' + Math.floor(Math.random()*999999); 2163 $this.attr('id', videoID); 2164 } 2165 $this.wrap('<div class="fluid-width-video-wrapper"></div>').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100)+"%"); 2166 $this.removeAttr('height').removeAttr('width'); 2167 }); 2168 }); 2169 }; 2170// Works with either jQuery or Zepto 2171})( window.jQuery || window.Zepto ); 2172; 2173(function ($) { 2174 2175/** 2176 * A progressbar object. Initialized with the given id. Must be inserted into 2177 * the DOM afterwards through progressBar.element. 2178 * 2179 * method is the function which will perform the HTTP request to get the 2180 * progress bar state. Either "GET" or "POST". 2181 * 2182 * e.g. pb = new progressBar('myProgressBar'); 2183 * some_element.appendChild(pb.element); 2184 */ 2185Drupal.progressBar = function (id, updateCallback, method, errorCallback) { 2186 var pb = this; 2187 this.id = id; 2188 this.method = method || 'GET'; 2189 this.updateCallback = updateCallback; 2190 this.errorCallback = errorCallback; 2191 2192 // The WAI-ARIA setting aria-live="polite" will announce changes after users 2193 // have completed their current activity and not interrupt the screen reader. 2194 this.element = $('<div class="progress" aria-live="polite"></div>').attr('id', id); 2195 this.element.html('<div class="bar"><div class="filled"></div></div>' + 2196 '<div class="percentage"></div>' + 2197 '<div class="message"> </div>'); 2198}; 2199 2200/** 2201 * Set the percentage and status message for the progressbar. 2202 */ 2203Drupal.progressBar.prototype.setProgress = function (percentage, message) { 2204 if (percentage >= 0 && percentage <= 100) { 2205 $('div.filled', this.element).css('width', percentage + '%'); 2206 $('div.percentage', this.element).html(percentage + '%'); 2207 } 2208 $('div.message', this.element).html(message); 2209 if (this.updateCallback) { 2210 this.updateCallback(percentage, message, this); 2211 } 2212}; 2213 2214/** 2215 * Start monitoring progress via Ajax. 2216 */ 2217Drupal.progressBar.prototype.startMonitoring = function (uri, delay) { 2218 this.delay = delay; 2219 this.uri = uri; 2220 this.sendPing(); 2221}; 2222 2223/** 2224 * Stop monitoring progress via Ajax. 2225 */ 2226Drupal.progressBar.prototype.stopMonitoring = function () { 2227 clearTimeout(this.timer); 2228 // This allows monitoring to be stopped from within the callback. 2229 this.uri = null; 2230}; 2231 2232/** 2233 * Request progress data from server. 2234 */ 2235Drupal.progressBar.prototype.sendPing = function () { 2236 if (this.timer) { 2237 clearTimeout(this.timer); 2238 } 2239 if (this.uri) { 2240 var pb = this; 2241 // When doing a post request, you need non-null data. Otherwise a 2242 // HTTP 411 or HTTP 406 (with Apache mod_security) error may result. 2243 $.ajax({ 2244 type: this.method, 2245 url: this.uri, 2246 data: '', 2247 dataType: 'json', 2248 success: function (progress) { 2249 // Display errors. 2250 if (progress.status == 0) { 2251 pb.displayError(progress.data); 2252 return; 2253 } 2254 // Update display. 2255 pb.setProgress(progress.percentage, progress.message); 2256 // Schedule next timer.
2257 pb.timer = setTimeout(function () { pb.sendPing(); }, pb.delay); 2258 }, 2259 error: function (xmlhttp) { 2260 pb.displayError(Drupal.ajaxError(xmlhttp, pb.uri)); 2261 } 2262 }); 2263 } 2264}; 2265 2266/** 2267 * Display errors on the page. 2268 */ 2269Drupal.progressBar.prototype.displayError = function (string) { 2270 var error = $('<div class="messages error"></div>').html(string); 2271 $(this.element).before(error).hide(); 2272 2273 if (this.errorCallback) { 2274 this.errorCallback(this); 2275 } 2276}; 2277 2278})(jQuery); 2279; 2280/* 2281 This is a copy of the commerce_vantiv metrix.js file. It has the same behavior 2282 name as commerce vantiv metrix.js to prevent collisions if both gateways 2283 are enabled on the same page. Two behaviors with the same name will not load 2284 twice. It is identical to the other file. If one is updated, the other should 2285 be updated as well. 2286*/ 2287(function ($) { 2288 Drupal.behaviors.commerceLitleMetrix = { 2289 attach: function (context, settings) { 2290 if (typeof (settings.metrixThreat) != "undefined") { 2291 2292 var metrixSettings = settings.metrixThreat; 2293 var hashedSettings; 2294 //var container 2295 $.each(metrixSettings, function (type, typeSettings) { 2296 var template = ''; 2297 var container = $('.metrix-container-' + type); 2298 2299 // Determine the correct session_id input field based on the payment type. 2300 // Support 'bank account', 'cc' (credit), 'googlepay', and 'applepay'. 2301 var session_id_input; 2302 switch (type) { 2303 case 'cc': 2304 session_id_input = $('input[name*="[payment_fields][credit][session_id]"]'); 2305 break; 2306 case 'googlepay': 2307 session_id_input = $('input[name*="[payment_fields][googlepay][session_id]"]'); 2308 break; 2309 case 'applepay': 2310 session_id_input = $('input[name*="[payment_fields][applepay][session_id]"]'); 2311 break; 2312 case 'echeck': 2313 case 'bank account': 2314 session_id_input = $('input[name*="[payment_fields][bank account][session_id]"]'); 2315 break; 2316 } 2317 2318 if (!typeSettings.dev_mode) { 2319 if (!Date.now) { 2320 Date.now = function () { 2321 return new Date().getTime(); 2322 } 2323 } 2324 var time = Date.now(); 2325 var min = parseInt(0, 10); 2326 var max = parseInt(time, 10); 2327 var rand = Math.floor(Math.random() * (max - min + 1)) + min; 2328 var sessionId = typeSettings.prefix + '-' + rand; 2329 } 2330 else { 2331 sessionId = typeSettings.prefix + '-' + typeSettings.dev_mode_id; 2332 } 2333 2334 // Set the session ID value only if the input exists. This prevents errors 2335 // if the expected input field is not present on the form. 2336 if (session_id_input?.length) { 2337 session_id_input.val(sessionId); 2338 } 2339 2340 // If CC and echeck are on the same form, and have identical settings 2341 // only render the metrix code once. 2342 if (hashedSettings === JSON.stringify(typeSettings)) { 2343 return; 2344 } 2345 2346 hashedSettings = JSON.stringify(typeSettings) 2347 2348 template += '<div style="background:url(https://' + typeSettings.subdomain + '/fp/clear.png?org_id=' + typeSettings.org_id + '&session_id=' + sessionId + '&m=1)"></div>'; 2349 template += '<img src="https://' + typeSettings.subdomain + '/fp/clear.png?org_id=' + typeSettings.org_id + '&session_id=' + sessionId + '&m=2" />'; 2350 template += '<script src="https://' + typeSettings.subdomain + '/fp/check.js?org_id=' + typeSettings.org_id + '&session_id=' + sessionId + '&pageid=##' + typeSettings.page_id + '##"></script>'; 2351 template += '<object type="application/x-shockwave-flash" data="https://' + typeSettings.subdomain + '/fp/fp.swf?org_id=' + typeSettings.org_id + '&session_id=' + sessionId + '" width="1" height="1">'; 2352 template += '<param name="movie" value="https://' + typeSettings.subdomain + '/fp/fp.swf?org_id=' + typeSettings.org_id + '&session_id=' + sessionId + '" /><param name="wmode" value="transparent" /> <div></div></object>'; 2353 container.html(template); 2354 }); 2355 } 2356 2357 } 2358 } 2359})(jQuery); 2360; 2361;(function(biapVals, $) { 2362 $(document).on('BraintreePaymentInstance', function(e, BraintreePaymentInstance, error) { 2363 // send message to parent.js to check if user's iOS supports braintree Apple Pay on embedded form 2364 window.parent.postMessage('braintree', '*'); 2365 BraintreePaymentInstance.addPaymentMethod('applepay', (function() { 2366 var BIAP = { 2367 applePayInstance: null 2368 }; 2369 var BI = BraintreePaymentInstance; 2370 2371 if (typeof biapVals.form == "undefined" && typeof BI.$form != "undefined") { 2372 biapVals.form = BI.$form; 2373 } 2374 2375 $('body').once('braintreeApplePay', function () { 2376 $(document).on('ajaxStart', function (e, x) { 2377 if (typeof e.currentTarget == "undefined" || typeof e.currentTarget.activeElement == "undefined") { 2378 return; 2379 } 2380 if (typeof $(e.currentTarget.activeElement).attr('name') == "undefined") { 2381 return; 2382 } 2383 2384 // Unset the processed classes when the currency is changed. The normal 2385 // "once" behavior doesn't work because the form is being replaced. Or 2386 // rather, it works too well. Without this, switching among currencies 2387 // multiple times causes the braintree fields to go missing if multiple 2388 // currencies have a braintree gateway. 2389 if ($(e.currentTarget.activeElement).attr('name').indexOf('user_selected_currency') != -1) { 2390 $('body').removeClass('braintreeApplePay-processed'); 2391 if (typeof biapVals.callbacks != "undefined") { 2392 // Braintree CC removes the submit handlers when the page loads. 2393 // If braintree is on a default currency and the currency is 2394 // switched, and the alternate currency does not have braintree cc 2395 // the submit handlers are not re-applied.This is a 2396 // workaround to ensure the submit handlers are re-applied. 2397 if (typeof BI.$form[0] != "undefined") {
2398 $.data(BI.$form[0], 'events')['submit'] = biapVals.callbacks; 2399 } 2400 } 2401 } 2402 }); 2403 }); 2404 2405 BIAP.preboot = function() { 2406 // If Apple Pay is enabled, check if the browser supports it. 2407 if ($.inArray('applepay', BI.settings.enabledMethods) >= 0) { 2408 var supports_applepay = true; 2409 if (!window.ApplePaySession) { 2410 error('This device does not support Apple Pay.'); 2411 supports_applepay = false; 2412 } 2413 if (supports_applepay && !ApplePaySession.canMakePayments()) { 2414 error('This device is not capable of making Apple Pay payments.'); 2415 supports_applepay = false; 2416 } 2417 if (!supports_applepay) { 2418 // Remove the Apple Pay option. 2419 BI.removePaymentMethod('applepay'); 2420 } 2421 } 2422 }; 2423 2424 BIAP.isEnabled = function() { 2425 return BI.settings.enabledMethods.indexOf('applepay') >= 0; 2426 }; 2427 2428 BIAP.setInstance = function(applePayInstance) { 2429 BIAP.applePayInstance = applePayInstance; 2430 return BIAP; 2431 }; 2432 2433 var fEnableFieldsSubmit = false; 2434 BIAP.enableFieldsSubmit = function() { 2435 // When autofill is enabled, we only want to validate the amount field. 2436 // Since the donation validation submission handler is already on the 2437 // queue, we need to insert our submission handler function before the 2438 // donation validation. 2439 BIAP.callbacks = $.extend(true, [], $.data(BI.$form[0], 'events')['submit']); 2440 // Need to make this global for ajax compat. 2441 if (undefined === biapVals.callbacks) { 2442 biapVals.callbacks = BIAP.callbacks; 2443 } 2444 2445 var guid = 128; 2446 if (undefined !== BIAP.callbacks && BIAP.callbacks.length) { 2447 guid = BIAP.callbacks[0].guid - 1; 2448 }
2449 $.data(BI.$form[0], 'events')['submit'].splice(0, BIAP.callbacks.length, { 2450 data: null, 2451 guid: guid, 2452 handler: BIAP.submitFields, 2453 namespace: '', 2454 origType: 'submit', 2455 quick: null, 2456 selector: null, 2457 type: 'submit' 2458 }); 2459 fEnableFieldsSubmit = true; 2460 return BIAP; 2461 }; 2462 2463 BIAP.disableFieldsSubmit = function() { 2464 if (fEnableFieldsSubmit) { 2465 $.data(BI.$form[0], 'events')['submit'] = biapVals.callbacks; 2466 } 2467 2468 BIAP.applepayFieldsCreated = false; 2469 fEnableFieldsSubmit = false; 2470 return BIAP; 2471 }; 2472 2473 BIAP.resetFieldsSubmit = function() { 2474 BIAP.disableFieldsSubmit().enableFieldsSubmit(); 2475 return BIAP; 2476 }; 2477 2478 BIAP.submitFields = function(event) { 2479 if (BI.settings.currentPaymentMethod != 'applepay') { 2480 return; 2481 } 2482 2483 // Check the current version of the dom for amount fields. 2484 BI.findAmountFields(); 2485 // Ensure that the appropiate amount field is validated before submit. 2486 var frequency = BI.$recursValue; 2487 2488 var notHidden = true; 2489 if ($.inArray(frequency, ["recurs", "sb_fs_quarterly", "sb_fs_semi", "sb_fs_annually"]) != -1) { 2490 if (frequency === 'recurs') { 2491 notHidden = BI.$recurringAmount.attr("type") != "hidden" 2492 } 2493 else { 2494 notHidden = BI.$form.find('input[name="frequencies[' + frequency + '_amount]"]').length > 0; 2495 } 2496 } 2497 // Not recurring only. 2498 // Not Other amount only. 2499 // Must be dual ask 2500 if (BI.$recurs.attr("type") != "hidden" 2501 && $.inArray(frequency, ["recurs", "sb_fs_quarterly", "sb_fs_semi", "sb_fs_annually"]) != -1 2502 && notHidden) { 2503 2504 switch (BI.$recursValue) { 2505 case 'recurs': 2506 var checked = BI.$recurringAmount.filter(':checked').val(); 2507 break; 2508 2509 case 'sb_fs_quarterly': 2510 if (BI.$recurringQuarterlyAmount.length) { 2511 checked = BI.$recurringQuarterlyAmount.filter(':checked').val() 2512 } 2513 break; 2514 2515 case 'sb_fs_semi': 2516 if (BI.$recurringSemiAmount.length) { 2517 checked = BI.$recurringSemiAmount.filter(':checked').val(); 2518 } 2519 break; 2520 2521 case 'sb_fs_annually': 2522 if (BI.$recurringAnnuallyAmount.length) { 2523 checked = BI.$recurringAnnuallyAmount.filter(':checked').val(); 2524 } 2525 break; 2526 } 2527 2528 // Check for other only configuration. 2529 if (typeof checked === 'undefined' && BI.$recurringOtherAmount.length) { 2530 switch (BI.$recursValue) { 2531 case 'recurs': 2532 if ('other' == BI.$recurringAmount.filter(':hidden').val() || !BI.$recurringAmount.length) { 2533 checked = 'other'; 2534 } 2535 break; 2536 2537 case 'sb_fs_quarterly': 2538 if ('other' == BI.$recurringQuarterlyAmount.filter(':hidden').val() || !BI.$recurringQuarterlyAmount.length) { 2539 checked = 'other'; 2540 } 2541 break; 2542 2543 case 'sb_fs_semi': 2544 if ('other' == BI.$recurringSemiAmount.filter(':hidden').val() || !BI.$recurringSemiAmount.length) { 2545 checked = 'other'; 2546 } 2547 break; 2548 2549 case 'sb_fs_annually': 2550 if ('other' == BI.$recurringAnnuallyAmount.filter(':hidden').val() || !BI.$recurringAnnuallyAmount.length) { 2551 checked = 'other'; 2552 } 2553 break; 2554 } 2555 } 2556 2557 if (checked == 'other' 2558 && Drupal.settings.fundraiser.donationValidate.element('input[name="submitted[donation][recurring_other_amount]"]') === false) { 2559 $('input[name="submitted[donation][recurring_other_amount]"]').focus(); 2560 event.stopImmediatePropagation(); 2561 event.preventDefault(); 2562 return; 2563 } 2564 } 2565 else { 2566 var checked = BI.$amount.filter(':checked').val(); 2567 // Check for other only configuration. 2568 if ( 2569 typeof checked === 'undefined' 2570 && ('other' == BI.$amount.filter(':hidden').val() || !BI.$amount.length) 2571 && BI.$otherAmount.length 2572 ) { 2573 checked = 'other'; 2574 } 2575 if (checked == 'other' && Drupal.settings.fundraiser.donationValidate.element('input[name="submitted[donation][other_amount]"]') === false) { 2576 $('input[name="submitted[donation][other_amount]"]').focus(); 2577 event.stopImmediatePropagation(); 2578 event.preventDefault(); 2579 return; 2580 } 2581 } 2582 2583 if (!BI.$form.find('input[name=payment_method_nonce]').val().length) { 2584 event.preventDefault(); 2585 2586 // Ensure appropriate amount is present. 2587 BI.updateAmount(); 2588 2589 // Check for addon. We don't do this in frTotal because we don't want the addon amount in the summary or anywhere else. 2590 // We ONLY want this in the amount displayed on the braintree payment preview. 2591 if (Drupal.settings.fundraiserAddon) { 2592 addon = Drupal.fundraiserAddon.prototype; 2593 if (typeof(Drupal.settings.fundraiser.fundraiserAddon) == "undefined") { 2594 var addon = addon.calcAddon(); 2595 BI.amount = parseFloat(BI.amount) + parseFloat(addon); 2596 } 2597 } 2598 2599 var paymentRequest = BIAP.applePayInstance.createPaymentRequest({ 2600 total: { 2601 label: BI.settings.storeName, 2602 amount: BI.amount 2603 }, 2604 requiredBillingContactFields: ['postalAddress', 'name'], 2605 requiredShippingContactFields: ['email'] 2606 }); 2607 2608 var session = new ApplePaySession(3, paymentRequest); 2609 2610 session.onvalidatemerchant = function(event) { 2611 var domain = window.location.hostname; 2612 if (document.location.ancestorOrigins.length) { 2613 // If we have an iframe involved, Apple expects the parent's 2614 // TLD for merchant validation. 2615 domain = new URL(document.location.ancestorOrigins[0]).hostname; 2616 } 2617 BIAP.applePayInstance.performValidation({ 2618 validationURL: event.validationURL, 2619 displayName: BI.settings.storeName, 2620 domainName: domain 2621 }, function (validationErr, merchantSession) { 2622 if (validationErr) { 2623 // You should show an error to the user, e.g. 'Apple Pay failed to 2624 // load.' 2625 error('Error validating merchant:', validationErr); 2626 session.abort(); 2627 return; 2628 } 2629 session.completeMerchantValidation(merchantSession); 2630 }); 2631 }; 2632 2633 session.onpaymentauthorized = function (event) { 2634 BIAP.applePayInstance.tokenize({ 2635 token: event.payment.token 2636 }, function(tokenizeErr, payload) { 2637 if (tokenizeErr) { 2638 error('Error tokenizing Apple Pay:', tokenizeErr); 2639 session.completePayment(ApplePaySession.STATUS_FAILURE); 2640 return; 2641 } 2642 2643 session.completePayment(ApplePaySession.STATUS_SUCCESS); 2644 BI.$form.find('input[name=payment_method_nonce]').val(payload.nonce);
2645 $.data(BI.$form[0], 'events')['submit'] = biapVals.callbacks; 2646 var autofill = BI.settings.applepay.autofill; 2647 if (autofill != 'never') { 2648 var autofilled = BI.autofill({ 2649 firstName: event.payment.billingContact.givenName, 2650 lastName: event.payment.billingContact.familyName, 2651 email: event.payment.shippingContact.emailAddress, 2652 address: event.payment.billingContact.addressLines[0], 2653 address2: undefined == event.payment.billingContact.addressLines[1] ? '' : event.payment.billingContact.addressLines[1], 2654 city: event.payment.billingContact.locality, 2655 country: event.payment.billingContact.countryCode.toUpperCase(), 2656 state: event.payment.billingContact.administrativeArea, 2657 zip: event.payment.billingContact.postalCode 2658 }, autofill); 2659 } 2660 2661 if (BI.$allSubmits.length > 1) { 2662 BI.$submit.trigger('click', ['submit']); 2663 } 2664 else { 2665 // Don't change the original submit behavior for non-designation forms. 2666 BI.$form.submit(); 2667 } 2668 // Otherwise the user will need to press submit again. 2669 }); 2670 }; 2671 2672 session.begin(); 2673 } 2674 }; 2675 2676 BIAP.createFields = function(clientInstance) { 2677 BI.setClientInstance(clientInstance); 2678 if (BIAP.applepayFieldsCreated) { 2679 return BIAP; 2680 } 2681 2682 braintree.applePay.create({ 2683 client: BI.clientInstance 2684 }, function (error_message, applePayInstance) { 2685 if (error_message) { 2686 error(error_message); 2687 BI.removePaymentMethod('applepay'); 2688 return; 2689 } 2690 2691 BIAP.setInstance(applePayInstance); 2692 2693 var promise = ApplePaySession.canMakePaymentsWithActiveCard(applePayInstance.merchantIdentifier); 2694 promise.then(function(canMakePaymentsWithActiveCard) { 2695 if (canMakePaymentsWithActiveCard) { 2696 BI.disableHostedFieldsSubmit().disablePaypalFieldsSubmit(); 2697 BIAP.resetFieldsSubmit(); 2698 BIAP.applepayFieldsCreated = true; 2699 } 2700 else { 2701 BI.removePaymentMethod('applepay'); 2702 } 2703 }); 2704 }); 2705 return BIAP; 2706 }; 2707 2708 BIAP.teardown = function() { 2709 BIAP.disableFieldsSubmit(); 2710 }; 2711 2712 return BIAP; 2713 })()); 2714 }); 2715})( 2716 window.braintreeAppleValues = window.braintreeAppleValues || {}, 2717 jQuery); 2718; 2719/** 2720 * @file 2721 * JavaScript behaviors for the front-end display of webforms. 2722 */ 2723 2724(function ($) { 2725 2726Drupal.behaviors.webform = Drupal.behaviors.webform || {}; 2727 2728Drupal.behaviors.webform.attach = function (context) { 2729 // Calendar datepicker behavior. 2730 Drupal.webform.datepicker(context); 2731}; 2732 2733Drupal.webform = Drupal.webform || {}; 2734 2735Drupal.webform.datepicker = function (context) { 2736 $('div.webform-datepicker').each(function () { 2737 var $webformDatepicker = $(this); 2738 var $calendar = $webformDatepicker.find('input.webform-calendar'); 2739 2740 // Ensure the page we're on actually contains a datepicker. 2741 if ($calendar.length == 0) { 2742 return; 2743 } 2744 2745 var startDate = $calendar[0].className.replace(/.*webform-calendar-start-(\d{4}-\d{2}-\d{2}).*/, '$1').split('-'); 2746 var endDate = $calendar[0].className.replace(/.*webform-calendar-end-(\d{4}-\d{2}-\d{2}).*/, '$1').split('-'); 2747 var firstDay = $calendar[0].className.replace(/.*webform-calendar-day-(\d).*/, '$1'); 2748 // Convert date strings into actual Date objects. 2749 startDate = new Date(startDate[0], startDate[1] - 1, startDate[2]); 2750 endDate = new Date(endDate[0], endDate[1] - 1, endDate[2]); 2751 2752 // Ensure that start comes before end for datepicker. 2753 if (startDate > endDate) { 2754 var laterDate = startDate; 2755 startDate = endDate; 2756 endDate = laterDate; 2757 } 2758 2759 var startYear = startDate.getFullYear(); 2760 var endYear = endDate.getFullYear(); 2761 2762 // Set up the jQuery datepicker element. 2763 $calendar.datepicker({ 2764 dateFormat: 'yy-mm-dd', 2765 yearRange: startYear + ':' + endYear, 2766 firstDay: parseInt(firstDay), 2767 minDate: startDate, 2768 maxDate: endDate, 2769 onSelect: function (dateText, inst) { 2770 var date = dateText.split('-'); 2771 $webformDatepicker.find('select.year, input.year').val(+date[0]).trigger('change'); 2772 $webformDatepicker.find('select.month').val(+date[1]).trigger('change'); 2773 $webformDatepicker.find('select.day').val(+date[2]).trigger('change'); 2774 }, 2775 beforeShow: function (input, inst) { 2776 // Get the select list values. 2777 var year = $webformDatepicker.find('select.year, input.year').val();
2778 var month = $webformDatepicker.find('select.month').val(); 2779 var day = $webformDatepicker.find('select.day').val(); 2780 2781 // If empty, default to the current year/month/day in the popup. 2782 var today = new Date(); 2783 year = year ? year : today.getFullYear(); 2784 month = month ? month : today.getMonth() + 1; 2785 day = day ? day : today.getDate(); 2786 2787 // Make sure that the default year fits in the available options. 2788 year = (year < startYear || year > endYear) ? startYear : year; 2789 2790 // jQuery UI Datepicker will read the input field and base its date off 2791 // of that, even though in our case the input field is a button. 2792 $(input).val(year + '-' + month + '-' + day); 2793 } 2794 }); 2795 2796 // Prevent the calendar button from submitting the form. 2797 $calendar.click(function (event) { 2798 $(this).focus(); 2799 event.preventDefault(); 2800 }); 2801 }); 2802} 2803 2804})(jQuery); 2805; 2806(function ($) { 2807 2808 Drupal.behaviors.floridaDisclaimer = { 2809 attach: function (context, settings) { 2810 settings = settings || Drupal.settings; 2811 2812 $('body').once(function(){ 2813 showDisclaimer(); 2814 }); 2815 2816 $('#edit-submitted-billing-information-state').change(function() { 2817 showDisclaimer(); 2818 }); 2819 2820 // Respond to custom autofill trigger. 2821 $(document).on('secure_prepop_autofilled', function() { 2822 showDisclaimer(); 2823 }); 2824 2825 function showDisclaimer() { 2826 if ($('#edit-submitted-billing-information-state').length && $('#edit-submitted-billing-information-state option:selected').text() == 'Florida') { 2827 $('p.donation_disclaimer').text(settings.florida_disclaimer.disclaimer_text); 2828 } 2829 else { 2830 $('p.donation_disclaimer').text(''); 2831 } 2832 } 2833 2834 } 2835 }; 2836 2837})(jQuery); 2838; 2839(function (FrTotal, FrFee, $, undefined) { 2840 2841 // Dynamically replaces the [js:formatted-donation-amount] token 2842 Drupal.behaviors.fundraiser_total = { 2843 attach: function (context, settings) { 2844 2845 // Check if there is a token on the page. 2846 if (!$('span.js-formatted-donation-amount').length) { 2847 return; 2848 } 2849 2850 // Start the token replacement. 2851 FrTotal.initializeVars(); 2852 FrTotal.updateTotal(settings); 2853 2854 // Define the event handlers for the total amount re-calculation. 2855 $('body').once('fundraiser-total', function() { 2856 FrTotalSetClickEvents(settings); 2857 }); 2858 } 2859 }; 2860 2861 // Find the fields we need to calulate the total. 2862 FrTotal.initializeVars = function () { 2863 FrTotal.processingFeeField = $('input[name*="[processing_fee]"]'); 2864 FrTotal.paymentMethodFields = $('input[name*="[payment_method]"]'); 2865 FrTotal.recursMonthlyField = $('input[name*="recurs_monthly"]'); 2866 FrTotal.otherAmountField = $('input[name*="[other_amount]"]'); 2867 FrTotal.recurringOtherAmountField = $('input[name*="[recurring_other_amount]"]'); 2868 FrTotal.donationAmountFields = $('input[name*="donation][amount]"]'); 2869 FrTotal.donationRecurringAmountFields = $('input[name*="donation][recurring_amount]"]'); 2870 FrTotal.donationQuarterlyFreqAmounts = $('input[name*="frequencies[sb_fs_quarterly_amount]"]'); 2871 FrTotal.donationSemiAnnualFreqAmounts = $('input[name*="frequencies[sb_fs_semi_amount]"]'); 2872 FrTotal.donationAnnuallyFreqAmounts = $('input[name*="frequencies[sb_fs_annually_amount]"]'); 2873 }; 2874 2875 // Retrieve the current donation amount from webform fields. 2876 FrTotal.getCurrentAmount = function (settings) { 2877 2878 var recursSelected = false; 2879 var recursSelect = FrTotal.recursMonthlyField; 2880 if (recursSelect) { 2881 var recursSelectType = recursSelect.attr('type'); 2882 } 2883 var currentAmount = 0; 2884 // fundraiser.recurring_settings does not exist on billing update form. 2885 var dualAsk = (settings.fundraiser.recurring_settings) ? settings.fundraiser.recurring_settings.recurring_dual_ask_amounts : false; 2886 2887 if (!settings.fundraiserTickets) { 2888 if (recursSelectType && recursSelectType == 'hidden') { 2889 if (recursSelect.val() !== 'NO_RECURR') { 2890 recursSelected = recursSelect.val(); 2891 } 2892 } 2893 else { 2894 if (FrTotal.recursMonthlyField && FrTotal.recursMonthlyField.filter(':checked').val()) { 2895 recursSelected = FrTotal.recursMonthlyField.filter(':checked').val(); 2896 } 2897 } 2898 2899 if ((!recursSelected || recursSelected === 'NO_RECURR' || (dualAsk == false && recursSelected))) { 2900 2901 currentAmount = FrTotal.donationAmountFields.filter(":checked").val(); 2902 2903 if (currentAmount == 'other') { 2904 currentAmount = FrTotal.otherAmountField.val(); 2905 } 2906 else if ( 2907 typeof currentAmount === 'undefined' 2908 && FrTotal.otherAmountField.length 2909 && ('other' == FrTotal.donationAmountFields.filter(":hidden").val() || !FrTotal.donationAmountFields.length) 2910 ) { 2911 currentAmount = FrTotal.otherAmountField.val(); 2912 } 2913 } 2914 else { 2915 if (recursSelected === 'recurs') { 2916 currentAmount = FrTotal.donationRecurringAmountFields.filter(':checked').val(); 2917 } 2918 2919 if (recursSelected !== 'NO_RECURR') { 2920 currentAmount = FrTotal.donationRecurringAmountFields.filter(':checked').val(); 2921 } 2922 2923 if (settings.fundraiser.multi_frequency) { 2924 2925 if (recursSelected === 'sb_fs_quarterly') { 2926 currentAmount = FrTotal.donationQuarterlyFreqAmounts.filter(':checked').val(); 2927 } 2928 2929 if (recursSelected === 'sb_fs_semi') { 2930 currentAmount = FrTotal.donationSemiAnnualFreqAmounts.filter(':checked').val(); 2931 } 2932 2933 if (recursSelected === 'sb_fs_annually') { 2934 currentAmount = FrTotal.donationAnnuallyFreqAmounts.filter(':checked').val(); 2935 } 2936 } 2937 2938 if (currentAmount == 'other') { 2939 currentAmount = FrTotal.recurringOtherAmountField.val(); 2940 } 2941 else if ( 2942 typeof currentAmount === 'undefined' 2943 && FrTotal.recurringOtherAmountField.length 2944 && ('other' == FrTotal.donationRecurringAmountFields.filter(":hidden").val() || !FrTotal.donationRecurringAmountFields.length) 2945 ) { 2946 // damn when does this happen? 2947 currentAmount = FrTotal.recurringOtherAmountField.val(); 2948 } 2949 } 2950 } 2951 2952 if (settings.fdNid) { 2953 currentAmount = Drupal.fundraiserDesignations.prototype.calcTotalMinusFee(); 2954 } 2955 2956 if (settings.fundraiserTickets) { 2957 currentAmount = Drupal.fundraiserTickets.prototype.calcTotalMinusFee(); 2958 } 2959 2960 if (isNaN(parseFloat(currentAmount))) { 2961 currentAmount = 0; 2962 } 2963 return currentAmount; 2964 }; 2965 2966 // Update the total. 2967 FrTotal.updateTotal = function (settings) { 2968 2969 if (settings.fundraiser.next_donation_amount) { 2970 // We're on the sustainers billing update form. 2971 var donationAmount = settings.fundraiser.next_donation_amount; 2972 } 2973 else { 2974 // We're on a donation form. 2975 donationAmount = FrTotal.getCurrentAmount(settings); 2976 if (typeof(donationAmount) == "undefined") { 2977 donationAmount = 0; 2978 } 2979 } 2980 2981 if (settings.fundraiserTickets) { 2982 FrTotal.tickets = Drupal.fundraiserTickets.prototype;
2983 if (typeof(settings.fundraiser.fundraiser_fee) == "undefined") { 2984 var addon = FrTotal.tickets.calcExtra(); 2985 donationAmount = donationAmount + addon; 2986 } 2987 } 2988 2989 if (typeof(settings.fundraiser.fundraiser_fee) != "undefined") { 2990 2991 if (FrTotal.paymentMethodFields.attr('type') != "hidden") { 2992 var $method = FrTotal.paymentMethodFields.filter(':checked').val(); 2993 } 2994 else { 2995 $method = FrTotal.paymentMethodFields.val(); 2996 } 2997 2998 if (typeof(settings.fundraiser.fundraiser_fee[$method]) !== "undefined" || $method === 'free_tickets') { 2999 if ($method !== 'free_tickets') { 3000 var feeSettings = settings.fundraiser.fundraiser_fee[$method]; 3001 var processingFee = FrFee.getFee(feeSettings, donationAmount); 3002 } 3003 if (settings.fundraiserTickets) { 3004 addon = FrTotal.tickets.calcExtra(); 3005 donationAmount = donationAmount + addon; 3006 } 3007 if ($.isNumeric(processingFee) && FrTotal.processingFeeField.is(':checked')) { 3008 donationAmount = parseFloat(donationAmount) + parseFloat(processingFee); 3009 } 3010 } 3011 } 3012
3013 if (typeof(settings.premiums) !== "undefined") { 3014 // Check for shipping charge, if present add to donation amount. 3015 var premiumShipping = $('.form-item-selected-premium-id input:checked').parents('.form-type-radio').siblings('.shipping-amount').data('attribute-shipping-amount'); 3016 3017 if (premiumShipping) { 3018 donationAmount = parseFloat(premiumShipping.replace("$", "")) + parseFloat(donationAmount); 3019 } 3020 } 3021 3022 if ($('span.js-formatted-donation-amount').length) { 3023 FrTotal.replaceToken(donationAmount); 3024 } 3025 3026 // Trigger for other modules to hook into the calculation (Togetherpay, 3027 // hide/show disaclaimer based on total amount). 3028 $(document).trigger("donation-total-update", [donationAmount]); 3029 3030 return donationAmount; 3031 }; 3032 3033 // Replace the token. 3034 FrTotal.replaceToken = function(donationAmount) { 3035 var settings = Drupal.settings; 3036 var symbol = settings.fundraiser.currency.symbol; 3037 var dec = settings.fundraiser.currency.decimals; 3038 var sep = settings.fundraiser.currency.decimal_separator; 3039 var thou = settings.fundraiser.currency.thousands_separator; 3040 var newAmount = symbol + (parseFloat(donationAmount)).formatMoney(dec, sep, thou); 3041 $('span.js-formatted-donation-amount').text(newAmount); 3042 }; 3043 3044 function FrTotalSetClickEvents(settings) { 3045 FrTotal.paymentMethodFields.on('change', function () { 3046 FrTotal.updateTotal(settings); 3047 }); 3048 if (typeof FrTotal.processingFeeField !== "undefined") { 3049 FrTotal.processingFeeField.on('change', function () { 3050 FrTotal.updateTotal(settings); 3051 }); 3052 } 3053 FrTotal.recursMonthlyField.on('change', function () { 3054 FrTotal.updateTotal(settings); 3055 }); 3056 FrTotal.otherAmountField.on('keyup', function () { 3057 FrTotal.updateTotal(settings); 3058 }); 3059 FrTotal.otherAmountField.on('focus', function () { 3060 FrTotal.updateTotal(settings); 3061 }); 3062 FrTotal.recurringOtherAmountField.on('keyup', function () { 3063 FrTotal.updateTotal(settings); 3064 }); 3065 FrTotal.donationAmountFields.on('change', function () { 3066 FrTotal.updateTotal(settings); 3067 }); 3068 FrTotal.donationRecurringAmountFields.on('change', function () { 3069 FrTotal.updateTotal(settings); 3070 }); 3071 FrTotal.donationQuarterlyFreqAmounts.on('change', function(){ 3072 FrTotal.updateTotal(settings); 3073 }); 3074 FrTotal.donationSemiAnnualFreqAmounts.on('change', function(){ 3075 FrTotal.updateTotal(settings); 3076 }); 3077 FrTotal.donationAnnuallyFreqAmounts.on('change', function(){ 3078 FrTotal.updateTotal(settings); 3079 }); 3080 } 3081 3082 Number.prototype.formatMoney = function(c, d, t) { 3083 var n = this, c = isNaN(c = Math.abs(c)) ? 2 : c, d = d == undefined ? "," : d, t = t == undefined ? "." : t, s = n < 0 ? "-" : "", i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "", j = (j = i.length) > 3 ? j % 3 : 0; 3084 return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : ""); 3085 }; 3086 3087})( 3088 window.FundraiserTotal = window.FundraiserTotal || {}, 3089 window.FundraiserFee = window.FundraiserFee || {}, 3090 jQuery); 3091; 3092(function (FrFee, $, undefined) { 3093 3094 // Functions shared by the frontend and backend javascript. 3095 FrFee.appendMessage = function(processingFee, donationAmount, feeCheckboxControl, feeSettings, drupalSettings) { 3096 3097 var settings = drupalSettings; 3098 var symbol = settings.fundraiser.currency.symbol; 3099 var dec = settings.fundraiser.currency.decimals; 3100 var sep = settings.fundraiser.currency.decimal_separator; 3101 var thou = settings.fundraiser.currency.thousands_separator; 3102 var newAmount = symbol + (parseFloat(processingFee) + parseFloat(donationAmount)).formatMoney(dec, sep, thou); 3103 var message = feeSettings.fee_message.replace('[fundraiser-fee-total]', newAmount); 3104 feeCheckboxControl.append('<div class="processing-fee-message">' + message + '</div>'); 3105 3106 FrFee.pfField = $('input[name$="[designation_funds_pf]"]'); 3107 if (FrFee.pfField.length) { 3108 FrFee.pfField.val(processingFee); 3109 } 3110 3111 }; 3112 3113 FrFee.getFee = function(feeSettings, donationAmount){ 3114 3115 var processingFee = 0; 3116 3117 if (feeSettings.fee_percentage.length) { 3118 var feePercentage = feeSettings.fee_percentage * 0.01; 3119 processingFee = parseFloat((donationAmount * feePercentage)) 3120 } 3121 3122 if (feeSettings.fee_dollar_amount.length && donationAmount != 0) { 3123 processingFee = processingFee + parseFloat(feeSettings.fee_dollar_amount) 3124 } 3125 3126 processingFee = processingFee.toFixed(Drupal.settings.fundraiser.currency.decimals); 3127 3128 return processingFee; 3129 }; 3130 3131 Number.prototype.formatMoney = function(c, d, t) { 3132 var n = this, c = isNaN(c = Math.abs(c)) ? 2 : c, d = d == undefined ? "," : d, t = t == undefined ? "." : t, s = n < 0 ? "-" : "", i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "", j = (j = i.length) > 3 ? j % 3 : 0; 3133 return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : ""); 3134 }; 3135 3136})(window.FundraiserFee = window.FundraiserFee || {}, jQuery); 3137; 3138(function (FrFee, FrTotal, FrDiscount, $, undefined) { 3139 3140 // Fee javascript for webform client forms. 3141 Drupal.behaviors.fundraiser_fee = { 3142 attach: function(context, settings) { 3143 3144 FrFee.initializeVars(settings); 3145 3146 if (settings.fundraiserTickets) { 3147 FrFee.tickets = Drupal.fundraiserTickets.prototype; 3148 } 3149 3150 FrFee.updateFeeFrontEnd(Drupal.settings); 3151 3152 // This was moved into "once" to make fees fully compatible with 3153 // the currency switcher. It gets re-initialized after any ajax event 3154 // in manner that is compatible with the currency switcher, so that the 3155 // switcher's event binding happens last. 3156 $('body').once('fundraiser-fee-frontend', function() { 3157 initializeEvents(settings); 3158 if (FrFee.userSelectedCurrency.length > 0) { 3159 $(document).on('ajaxSuccess', function (event, xhr, ajaxSettings) { 3160 // This is for the currency switcher. "Success" is used so that 3161 // "Complete" in the currency switcher code predominates if currency 3162 // switching is enabled. 3163 initializeEvents(settings); 3164 }); 3165 3166 // This is for the currency switcher. "Stop" is used so that 3167 // This runs after the "complete" event in the currency switcher 3168 // code. 3169 $(document).on('ajaxStop', function (event, xhr, ajaxSettings) { 3170 FrFee.updateFeeFrontEnd(settings); 3171 }); 3172 } 3173 }); 3174 3175 } 3176 }; 3177 3178 var initializeEvents = function (settings) { 3179 FrFee.paymentMethodFields.on('change', function () { 3180 FrFee.updateFeeFrontEnd(settings); 3181 }); 3182 FrFee.processingFeeField.on('change', function () { 3183 FrFee.updateFeeFrontEnd(settings); 3184 }); 3185 FrFee.recursMonthlyField.on('change', function () { 3186 FrFee.updateFeeFrontEnd(settings); 3187 }); 3188 FrFee.otherAmountField.on('keyup', function () { 3189 FrFee.updateFeeFrontEnd(settings); 3190 }); 3191 FrFee.recurringOtherAmountField.on('keyup', function () { 3192 FrFee.updateFeeFrontEnd(settings); 3193 }); 3194 FrFee.donationAmountFields.on('change', function () { 3195 FrFee.updateFeeFrontEnd(settings); 3196 }); 3197 FrFee.donationRecurringAmountFields.on('change', function () { 3198 FrFee.updateFeeFrontEnd(settings); 3199 }); 3200 FrFee.donationQuarterlyFreqAmounts.on('change', function () { 3201 FrFee.updateFeeFrontEnd(settings); 3202 }); 3203 FrFee.donationSemiAnnualFreqAmounts.on('change', function () { 3204 FrFee.updateFeeFrontEnd(settings); 3205 }); 3206 FrFee.donationAnnuallyFreqAmounts.on('change', function () { 3207 FrFee.updateFeeFrontEnd(settings); 3208 }); 3209 3210 } 3211 3212 FrFee.initializeVars = function (settings) { 3213 FrFee.paymentMethodFields = $('input[name*="[payment_method]"]'); 3214 FrFee.processingFeeField = $('input[name*="[processing_fee]"]'); 3215 FrFee.recursMonthlyField = $('input[name*="recurs_monthly"]'); 3216 FrFee.otherAmountField = $('input[name*="[other_amount]"]'); 3217 FrFee.recurringOtherAmountField = $('input[name*="[recurring_other_amount]"]'); 3218 FrFee.donationAmountFields = $('input[name*="donation][amount]"]'); 3219 FrFee.donationRecurringAmountFields = $('input[name*="donation][recurring_amount]"]'); 3220 FrFee.donationQuarterlyFreqAmounts = $('input[name*="frequencies[sb_fs_quarterly_amount]"]'); 3221 FrFee.donationSemiAnnualFreqAmounts = $('input[name*="frequencies[sb_fs_semi_amount]"]'); 3222 FrFee.donationAnnuallyFreqAmounts = $('input[name*="frequencies[sb_fs_annually_amount]"]'); 3223 FrFee.userSelectedCurrency = $('select[name*="user_selected_currency"]'); 3224 }; 3225 3226 // This func is namespaced so it can be called from fundraiser_designations.js 3227 FrFee.updateFeeFrontEnd = function (settings) {
3228 if (typeof(settings.fundraiser.fundraiser_fee) != "undefined") { 3229 var feeCheckboxControl = FrFee.processingFeeField.closest('.webform-component.control-group'); 3230 feeCheckboxControl.find('.processing-fee-message').remove(); 3231 3232 if (FrFee.paymentMethodFields.attr('type') != "hidden") { 3233 var $method = FrFee.paymentMethodFields.filter(':checked').val(); 3234 } 3235 else { 3236 $method = FrFee.paymentMethodFields.val(); 3237 } 3238 3239 if (typeof(settings.fundraiser.fundraiser_fee[$method]) !== "undefined") { 3240 FrTotal.initializeVars(); 3241 var donationAmount = FrTotal.getCurrentAmount(settings); 3242 if (typeof(donationAmount) == "undefined") { 3243 return false; 3244 } 3245 var feeSettings = settings.fundraiser.fundraiser_fee[$method]; 3246 if (typeof(feeSettings.fee_help_text) != "undefined" ) { 3247 var help = feeSettings.fee_help_text; 3248 if (help.length > 0) { 3249 feeCheckboxControl.find('label[for*=processing-fee-1]').text(help); 3250 } 3251 } 3252 3253 var processingFee = FrFee.getFee(feeSettings, donationAmount); 3254 3255 if (settings.fundraiserTickets) { 3256 FrFee.tickets.ticketRow(processingFee); 3257 var addon = FrFee.tickets.calcExtra(); 3258 var origDonationAmount = donationAmount; 3259 donationAmount = donationAmount + addon; 3260 //if (FrDiscount.initVars) { 3261 // FrDiscount.initVars(Drupal.settings); 3262 // if (FrDiscount.hasCode !== false) { 3263 // processingFee = FrFee.getFee(feeSettings, origDonationAmount); 3264 // FrFee.tickets.ticketRow(processingFee); 3265 // } 3266 //} 3267 if (origDonationAmount > 0) { 3268 feeCheckboxControl.show(); 3269 } 3270 else { 3271 $('#fundraiser-tickets-processing-fee').remove(); 3272 FrFee.processingFeeField.prop('checked', false); 3273 feeCheckboxControl.hide(); 3274 FrFee.tickets.ticketRow(processingFee); 3275 FrFee.tickets.setAmounts(); 3276 } 3277 } 3278 else { 3279 feeCheckboxControl.show(); 3280 } 3281 3282 if ($.isNumeric(processingFee) && FrFee.processingFeeField.is(':checked')) { 3283 $('input[name*="processing_fee_amount]"]').val(processingFee); 3284 FrFee.appendMessage(processingFee, donationAmount, feeCheckboxControl, feeSettings, settings); 3285 } 3286 } 3287 else { 3288 FrFee.processingFeeField.prop('checked', false); 3289 feeCheckboxControl.hide(); 3290 } 3291 } 3292 }; 3293 3294})( 3295 window.FundraiserFee = window.FundraiserFee || {}, 3296 window.FundraiserTotal = window.FundraiserTotal || {}, 3297 window.FundraiserDiscount = window.FundraiserDiscount || {}, 3298 jQuery); 3299; 3300eval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('(2($){$.c.f=2(p){p=$.d({g:"!@#$%^&*()+=[]\\\\\\\';,/{}|\\":<>?~`.- ",4:"",9:""},p);7 3.b(2(){5(p.G)p.4+="Q";5(p.w)p.4+="n";s=p.9.z(\'\');x(i=0;i<s.y;i++)5(p.g.h(s[i])!=-1)s[i]="\\\\"+s[i];p.9=s.O(\'|\');6 l=N M(p.9,\'E\');6 a=p.g+p.4;a=a.H(l,\'\');$(3).J(2(e){5(!e.r)k=o.q(e.K);L k=o.q(e.r);5(a.h(k)!=-1)e.j();5(e.u&&k==\'v\')e.j()});$(3).B(\'D\',2(){7 F})})};$.c.I=2(p){6 8="n";8+=8.P();p=$.d({4:8},p);7 3.b(2(){$(3).f(p)})};$.c.t=2(p){6 m="A";p=$.d({4:m},p);7 3.b(2(){$(3).f(p)})}})(C);',53,53,'||function|this|nchars|if|var|return|az|allow|ch|each|fn|extend||alphanumeric|ichars|indexOf||preventDefault||reg|nm|abcdefghijklmnopqrstuvwxyz|String||fromCharCode|charCode||alpha|ctrlKey||allcaps|for|length|split|1234567890|bind|jQuery|contextmenu|gi|false|nocaps|replace|numeric|keypress|which|else|RegExp|new|join|toUpperCase|ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('|'),0,{})); 3301; 3302/** 3303 * jQuery Validation Plugin 1.9.0 3304 * 3305 * http://bassistance.de/jquery-plugins/jquery-plugin-validation/ 3306 * http://docs.jquery.com/Plugins/Validation 3307 * 3308 * Copyright (c) 2006 - 2011 Jörn Zaefferer 3309 * 3310 * Dual licensed under the MIT and GPL licenses: 3311 * http://www.opensource.org/licenses/mit-license.php 3312 * http://www.gnu.org/licenses/gpl.html 3313 */
3314(function(c){c.extend(c.fn,{validate:function(a){if(this.length){var b=c.data(this[0],"validator");if(b)return b;this.attr("novalidate","novalidate");b=new c.validator(a,this[0]);c.data(this[0],"validator",b);if(b.settings.onsubmit){a=this.find("input, button");a.filter(".cancel").click(function(){b.cancelSubmit=true});b.settings.submitHandler&&a.filter(":submit").click(function(){b.submitButton=this});this.submit(function(d){function e(){if(b.settings.submitHandler){if(b.submitButton)var f=c("<input type='hidden'/>").attr("name", 3315b.submitButton.name).val(b.submitButton.value).appendTo(b.currentForm);b.settings.submitHandler.call(b,b.currentForm);b.submitButton&&f.remove();return false}return true}b.settings.debug&&d.preventDefault();if(b.cancelSubmit){b.cancelSubmit=false;return e()}if(b.form()){if(b.pendingRequest){b.formSubmitted=true;return false}return e()}else{b.focusInvalid();return false}})}return b}else a&&a.debug&&window.console&&console.warn("nothing selected, can't validate, returning nothing")},valid:function(){if(c(this[0]).is("form"))return this.validate().form(); 3316else{var a=true,b=c(this[0].form).validate();this.each(function(){a&=b.element(this)});return a}},removeAttrs:function(a){var b={},d=this;c.each(a.split(/\s/),function(e,f){b[f]=d.attr(f);d.removeAttr(f)});return b},rules:function(a,b){var d=this[0];if(a){var e=c.data(d.form,"validator").settings,f=e.rules,g=c.validator.staticRules(d);switch(a){case "add":c.extend(g,c.validator.normalizeRule(b));f[d.name]=g;if(b.messages)e.messages[d.name]=c.extend(e.messages[d.name],b.messages);break;case "remove":if(!b){delete f[d.name]; 3317return g}var h={};c.each(b.split(/\s/),function(j,i){h[i]=g[i];delete g[i]});return h}}d=c.validator.normalizeRules(c.extend({},c.validator.metadataRules(d),c.validator.classRules(d),c.validator.attributeRules(d),c.validator.staticRules(d)),d);if(d.required){e=d.required;delete d.required;d=c.extend({required:e},d)}return d}});c.extend(c.expr[":"],{blank:function(a){return!c.trim(""+a.value)},filled:function(a){return!!c.trim(""+a.value)},unchecked:function(a){return!a.checked}});c.validator=function(a, 3318b){this.settings=c.extend(true,{},c.validator.defaults,a);this.currentForm=b;this.init()};c.validator.format=function(a,b){if(arguments.length==1)return function(){var d=c.makeArray(arguments);d.unshift(a);return c.validator.format.apply(this,d)};if(arguments.length>2&&b.constructor!=Array)b=c.makeArray(arguments).slice(1);if(b.constructor!=Array)b=[b];c.each(b,function(d,e){a=a.replace(RegExp("\\{"+d+"\\}","g"),e)});return a};c.extend(c.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error", 3319validClass:"valid",errorElement:"label",focusInvalid:true,errorContainer:c([]),errorLabelContainer:c([]),onsubmit:true,ignore:":hidden",ignoreTitle:false,onfocusin:function(a){this.lastActive=a;if(this.settings.focusCleanup&&!this.blockFocusCleanup){this.settings.unhighlight&&this.settings.unhighlight.call(this,a,this.settings.errorClass,this.settings.validClass);this.addWrapper(this.errorsFor(a)).hide()}},onfocusout:function(a){if(!this.checkable(a)&&(a.name in this.submitted||!this.optional(a)))this.element(a)}, 3320onkeyup:function(a){if(a.name in this.submitted||a==this.lastElement)this.element(a)},onclick:function(a){if(a.name in this.submitted)this.element(a);else a.parentNode.name in this.submitted&&this.element(a.parentNode)},highlight:function(a,b,d){a.type==="radio"?this.findByName(a.name).addClass(b).removeClass(d):c(a).addClass(b).removeClass(d)},unhighlight:function(a,b,d){a.type==="radio"?this.findByName(a.name).removeClass(b).addClass(d):c(a).removeClass(b).addClass(d)}},setDefaults:function(a){c.extend(c.validator.defaults, 3321a)},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.",url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date (ISO).",number:"Please enter a valid number.",digits:"Please enter only digits.",creditcard:"Please enter a valid credit card number.",equalTo:"Please enter the same value again.",accept:"Please enter a value with a valid extension.",maxlength:c.validator.format("Please enter no more than {0} characters."), 3322minlength:c.validator.format("Please enter at least {0} characters."),rangelength:c.validator.format("Please enter a value between {0} and {1} characters long."),range:c.validator.format("Please enter a value between {0} and {1}."),max:c.validator.format("Please enter a value less than or equal to {0}."),min:c.validator.format("Please enter a value greater than or equal to {0}.")},autoCreateRanges:false,prototype:{init:function(){function a(e){var f=c.data(this[0].form,"validator"),g="on"+e.type.replace(/^validate/, 3323"");f.settings[g]&&f.settings[g].call(f,this[0],e)}this.labelContainer=c(this.settings.errorLabelContainer);this.errorContext=this.labelContainer.length&&this.labelContainer||c(this.currentForm);this.containers=c(this.settings.errorContainer).add(this.settings.errorLabelContainer);this.submitted={};this.valueCache={};this.pendingRequest=0;this.pending={};this.invalid={};this.reset();var b=this.groups={};c.each(this.settings.groups,function(e,f){c.each(f.split(/\s/),function(g,h){b[h]=e})});var d= 3324this.settings.rules;c.each(d,function(e,f){d[e]=c.validator.normalizeRule(f)});c(this.currentForm).validateDelegate("[type='text'], [type='password'], [type='file'], select, textarea, [type='number'], [type='search'] ,[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], [type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'] ","focusin focusout keyup",a).val
3324idateDelegate("[type='radio'], [type='checkbox'], select, option","click", 3325a);this.settings.invalidHandler&&c(this.currentForm).bind("invalid-form.validate",this.settings.invalidHandler)},form:function(){this.checkForm();c.extend(this.submitted,this.errorMap);this.invalid=c.extend({},this.errorMap);this.valid()||c(this.currentForm).triggerHandler("invalid-form",[this]);this.showErrors();return this.valid()},checkForm:function(){this.prepareForm();for(var a=0,b=this.currentElements=this.elements();b[a];a++)this.check(b[a]);return this.valid()},element:function(a){this.lastElement= 3326a=this.validationTargetFor(this.clean(a));this.prepareElement(a);this.currentElements=c(a);var b=this.check(a);if(b)delete this.invalid[a.name];else this.invalid[a.name]=true;if(!this.numberOfInvalids())this.toHide=this.toHide.add(this.containers);this.showErrors();return b},showErrors:function(a){if(a){c.extend(this.errorMap,a);this.errorList=[];for(var b in a)this.errorList.push({message:a[b],element:this.findByName(b)[0]});this.successList=c.grep(this.successList,function(d){return!(d.name in a)})}this.settings.showErrors? 3327this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){c.fn.resetForm&&c(this.currentForm).resetForm();this.submitted={};this.lastElement=null;this.prepareForm();this.hideErrors();this.elements().removeClass(this.settings.errorClass)},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(a){var b=0,d;for(d in a)b++;return b},hideErrors:function(){this.addWrapper(this.toHide).hide()},valid:function(){return this.size()== 33280},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{c(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").focus().trigger("focusin")}catch(a){}},findLastActive:function(){var a=this.lastActive;return a&&c.grep(this.errorList,function(b){return b.element.name==a.name}).length==1&&a},elements:function(){var a=this,b={};return c(this.currentForm).find("input, select, textarea").not(":submit, :reset, :image, [disabled]").not(this.settings.ignore).filter(function(){!this.name&& 3329a.settings.debug&&window.console&&console.error("%o has no name assigned",this);if(this.name in b||!a.objectLength(c(this).rules()))return false;return b[this.name]=true})},clean:function(a){return c(a)[0]},errors:function(){return c(this.settings.errorElement+"."+this.settings.errorClass,this.errorContext)},reset:function(){this.successList=[];this.errorList=[];this.errorMap={};this.toShow=c([]);this.toHide=c([]);this.currentElements=c([])},prepareForm:function(){this.reset();this.toHide=this.errors().add(this.containers)}, 3330prepareElement:function(a){this.reset();this.toHide=this.errorsFor(a)},check:function(a){a=this.validationTargetFor(this.clean(a));var b=c(a).rules(),d=false,e;for(e in b){var f={method:e,parameters:b[e]};try{var g=c.validator.methods[e].call(this,a.value.replace(/\r/g,""),a,f.parameters);if(g=="dependency-mismatch")d=true;else{d=false;if(g=="pending"){this.toHide=this.toHide.not(this.errorsFor(a));return}if(!g){this.formatAndAdd(a,f);return false}}}catch(h){this.settings.debug&&window.console&&console.log("exception occured when checking element "+ 3331a.id+", check the '"+f.method+"' method",h);throw h;}}if(!d){this.objectLength(b)&&this.successList.push(a);return true}},customMetaMessage:function(a,b){if(c.metadata){var d=this.settings.meta?c(a).metadata()[this.settings.meta]:c(a).metadata();return d&&d.messages&&d.messages[b]}},customMessage:function(a,b){var d=this.settings.messages[a];return d&&(d.constructor==String?d:d[b])},findDefined:function(){for(var a=0;a<arguments.length;a++)if(arguments[a]!==undefined)return arguments[a]},defaultMessage:function(a, 3332b){return this.findDefined(this.customMessage(a.name,b),this.customMetaMessage(a,b),!this.settings.ignoreTitle&&a.title||undefined,c.validator.messages[b],"<strong>Warning: No message defined for "+a.name+"</strong>")},formatAndAdd:function(a,b){var d=this.defaultMessage(a,b.method),e=/\$?\{(\d+)\}/g;if(typeof d=="function")d=d.call(this,b.parameters,a);else if(e.test(d))d=jQuery.format(d.replace(e,"{$1}"),b.parameters);this.errorList.push({message:d,element:a});this.errorMap[a.name]=d;this.submitted[a.name]= 3333d}
3333,addWrapper:function(a){if(this.settings.wrapper)a=a.add(a.parent(this.settings.wrapper));return a},defaultShowErrors:function(){for(var a=0;this.errorList[a];a++){var b=this.errorList[a];this.settings.highlight&&this.settings.highlight.call(this,b.element,this.settings.errorClass,this.settings.validClass);this.showLabel(b.element,b.message)}if(this.errorList.length)this.toShow=this.toShow.add(this.containers);if(this.settings.success)for(a=0;this.successList[a];a++)this.showLabel(this.successList[a]); 3334if(this.settings.unhighlight){a=0;for(b=this.validElements();b[a];a++)this.settings.unhighlight.call(this,b[a],this.settings.errorClass,this.settings.validClass)}this.toHide=this.toHide.not(this.toShow);this.hideErrors();this.addWrapper(this.toShow).show()},validElements:function(){return this.currentElements.not(this.invalidElements())},invalidElements:function(){return c(this.errorList).map(function(){return this.element})},showLabel:function(a,b){var d=this.errorsFor(a);if(d.length){d.removeClass(this.settings.validClass).addClass(this.settings.errorClass); 3335d.attr("generated")&&d.html(b)}else{d=c("<"+this.settings.errorElement+"/>").attr({"for":this.idOrName(a),generated:true}).addClass(this.settings.errorClass).html(b||"");if(this.settings.wrapper)d=d.hide().show().wrap("<"+this.settings.wrapper+"/>").parent();this.labelContainer.append(d).length||(this.settings.errorPlacement?this.settings.errorPlacement(d,c(a)):d.insertAfter(a))}if(!b&&this.settings.success){d.text("");typeof this.settings.success=="string"?d.addClass(this.settings.success):this.settings.success(d)}this.toShow= 3336this.toShow.add(d)},errorsFor:function(a){var b=this.idOrName(a);return this.errors().filter(function(){return c(this).attr("for")==b})},idOrName:function(a){return this.groups[a.name]||(this.checkable(a)?a.name:a.id||a.name)},validationTargetFor:function(a){if(this.checkable(a))a=this.findByName(a.name).not(this.settings.ignore)[0];return a},checkable:function(a){return/radio|checkbox/i.test(a.type)},findByName:function(a){var b=this.currentForm;return c(document.getElementsByName(a)).map(function(d, 3337e){return e.form==b&&e.name==a&&e||null})},getLength:function(a,b){switch(b.nodeName.toLowerCase()){case "select":return c("option:selected",b).length;case "input":if(this.checkable(b))return this.findByName(b.name).filter(":checked").length}return a.length},depend:function(a,b){return this.dependTypes[typeof a]?this.dependTypes[typeof a](a,b):true},dependTypes:{"boolean":function(a){return a},string:function(a,b){return!!c(a,b.form).length},"function":function(a,b){return a(b)}},optional:function(a){return!c.validator.methods.required.call(this, 3338c.trim(a.value),a)&&"dependency-mismatch"},startRequest:function(a){if(!this.pending[a.name]){this.pendingRequest++;this.pending[a.name]=true}},stopRequest:function(a,b){this.pendingRequest--;if(this.pendingRequest<0)this.pendingRequest=0;delete this.pending[a.name];if(b&&this.pendingRequest==0&&this.formSubmitted&&this.form()){c(this.currentForm).submit();this.formSubmitted=false}else if(!b&&this.pendingRequest==0&&this.formSubmitted){c(this.currentForm).triggerHandler("invalid-form",[this]);this.formSubmitted= 3339false}},previousValue:function(a){return c.data(a,"previousValue")||c.data(a,"previousValue",{old:null,valid:true,message:this.defaultMessage(a,"remote")})}},classRuleSettings:{required:{required:true},email:{email:true},url:{url:true},date:{date:true},dateISO:{dateISO:true},dateDE:{dateDE:true},number:{number:true},numberDE:{numberDE:true},digits:{digits:true},creditcard:{creditcard:true}},addClassRules:function(a,b){a.constructor==String?this.classRuleSettings[a]=b:c.extend(this.classRuleSettings, 3340a)},classRules:function(a){var b={};(a=c(a).attr("class"))&&c.each(a.split(" "),function(){this in c.validator.classRuleSettings&&c.extend(b,c.validator.classRuleSettings[this])});return b},attributeRules:function(a){var b={};a=c(a);for(var d in c.validator.methods){var e;if(e=d==="required"&&typeof c.fn.prop==="function"?a.prop(d):a.attr(d))b[d]=e;else if(a[0].getAttribute("type")===d)b[d]=true}b.maxlength&&/-1|2147483647|524288/.test(b.maxlength)&&delete b.maxlength;return b}
3340,metadataRules:function(a){if(!c.metadata)return{}; 3341var b=c.data(a.form,"validator").settings.meta;return b?c(a).metadata()[b]:c(a).metadata()},staticRules:function(a){var b={},d=c.data(a.form,"validator");if(d.settings.rules)b=c.validator.normalizeRule(d.settings.rules[a.name])||{};return b},normalizeRules:function(a,b){c.each(a,function(d,e){if(e===false)delete a[d];else if(e.param||e.depends){var f=true;switch(typeof e.depends){case "string":f=!!c(e.depends,b.form).length;break;case "function":f=e.depends.call(b,b)}if(f)a[d]=e.param!==undefined? 3342e.param:true;else delete a[d]}});c.each(a,function(d,e){a[d]=c.isFunction(e)?e(b):e});c.each(["minlength","maxlength","min","max"],function(){if(a[this])a[this]=Number(a[this])});c.each(["rangelength","range"],function(){if(a[this])a[this]=[Number(a[this][0]),Number(a[this][1])]});if(c.validator.autoCreateRanges){if(a.min&&a.max){a.range=[a.min,a.max];delete a.min;delete a.max}if(a.minlength&&a.maxlength){a.rangelength=[a.minlength,a.maxlength];delete a.minlength;delete a.maxlength}}a.messages&&delete a.messages; 3343return a},normalizeRule:function(a){if(typeof a=="string"){var b={};c.each(a.split(/\s/),function(){b[this]=true});a=b}return a},addMethod:function(a,b,d){c.validator.methods[a]=b;c.validator.messages[a]=d!=undefined?d:c.validator.messages[a];b.length<3&&c.validator.addClassRules(a,c.validator.normalizeRule(a))},methods:{required:function(a,b,d){if(!this.depend(d,b))return"dependency-mismatch";switch(b.nodeName.toLowerCase()){case "select":return(a=c(b).val())&&a.length>0;case "input":if(this.checkable(b))return this.getLength(a, 3344b)>0;default:return c.trim(a).length>0}},remote:function(a,b,d){if(this.optional(b))return"dependency-mismatch";var e=this.previousValue(b);this.settings.messages[b.name]||(this.settings.messages[b.name]={});e.originalMessage=this.settings.messages[b.name].remote;this.settings.messages[b.name].remote=e.message;d=typeof d=="string"&&{url:d}||d;if(this.pending[b.name])return"pending";if(e.old===a)return e.valid;e.old=a;var f=this;this.startRequest(b);var g={};g[b.name]=a;c.ajax(c.extend(true,{url:d, 3345mode:"abort",port:"validate"+b.name,dataType:"json",data:g,success:function(h){f.settings.messages[b.name].remote=e.originalMessage;var j=h===true;if(j){var i=f.formSubmitted;f.prepareElement(b);f.formSubmitted=i;f.successList.push(b);f.showErrors()}else{i={};h=h||f.defaultMessage(b,"remote");i[b.name]=e.message=c.isFunction(h)?h(a):h;f.showErrors(i)}e.valid=j;f.stopRequest(b,j)}},d));return"pending"},minlength:function(a,b,d){return this.optional(b)||this.getLength(c.trim(a),b)>=d},maxlength:function(a, 3346b,d){return this.optional(b)||this.getLength(c.trim(a),b)<=d},rangelength:function(a,b,d){a=this.getLength(c.trim(a),b);return this.optional(b)||a>=d[0]&&a<=d[1]},min:function(a,b,d){return this.optional(b)||a>=d},max:function(a,b,d){return this.optional(b)||a<=d},range:function(a,b,d){return this.optional(b)||a>=d[0]&&a<=d[1]},email:function(a,b){return this.optional(b)||/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(a)}, 3347url:function(a,b){return this.optional(b)||/^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(a)}, 3348date:function(a,b){return this.optional(b)||!/Invalid|NaN/.test(new Date(a))},dateISO:function(a,b){return this.optional(b)||/^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(a)},number:function(a,b){return this.optional(b)||/^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(a)},digits:function(a,b){return this.optional(b)||/^\d+$/.test(a)},creditcard:function(a,b){if(this.optional(b))return"dependency-mismatch";if(/[^0-9 -]+/.test(a))return false;var d=0,e=0,f=false;a=a.replace(/\D/g,"");for(var g=a.length-1;g>= 33490;g--){e=a.charAt(g);e=parseInt(e,10);if(f)if((e*=2)>9)e-=9;d+=e;f=!f}return d%10==0}
3349,accept:function(a,b,d){d=typeof d=="string"?d.replace(/,/g,"|"):"png|jpe?g|gif";return this.optional(b)||a.match(RegExp(".("+d+")$","i"))},equalTo:function(a,b,d){d=c(d).unbind(".validate-equalTo").bind("blur.validate-equalTo",function(){c(b).valid()});return a==d.val()}}});c.format=c.validator.format})(jQuery); 3350(function(c){var a={};if(c.ajaxPrefilter)c.ajaxPrefilter(function(d,e,f){e=d.port;if(d.mode=="abort"){a[e]&&a[e].abort();a[e]=f}});else{var b=c.ajax;c.ajax=function(d){var e=("port"in d?d:c.ajaxSettings).port;if(("mode"in d?d:c.ajaxSettings).mode=="abort"){a[e]&&a[e].abort();return a[e]=b.apply(this,arguments)}return b.apply(this,arguments)}}})(jQuery); 3351(function(c){!jQuery.event.special.focusin&&!jQuery.event.special.focusout&&document.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.handle.call(this,e)}c.event.special[b]={setup:function(){this.addEventListener(a,d,true)},teardown:function(){this.removeEventListener(a,d,true)},handler:function(e){arguments[0]=c.event.fix(e);arguments[0].type=b;return c.event.handle.apply(this,arguments)}}});c.extend(c.fn,{validateDelegate:function(a, 3352b,d){return this.bind(b,function(e){var f=c(e.target);if(f.is(a))return d.apply(f,arguments)})}})})(jQuery); 3353; 3354(function (Dv, $, undefined) { 3355 // Clear payment fields so they won't be populated on back button. 3356 var doUnload = function () { 3357 $('.fundraiser-payment-fields input[type="text"]').each(function (i, el) { 3358 var $el = $(el); 3359 $el.val(''); 3360 try { 3361 $el.rules('remove'); 3362 } 3363 catch (err) { 3364 if (window.console) { 3365 console.error(err) 3366 console.error('error href: ' + window.location.href) 3367 } 3368 } 3369 }); 3370 }; 3371 window.unload = window.onbeforeunload = doUnload; 3372 3373 Drupal.behaviors.springboardForms = { 3374 attach: function (context, settings) { 3375 var clearElement = function($selector) { 3376 $selector 3377 .val('') 3378 .removeClass('valid') 3379 .next('label') 3380 .remove() 3381 .end() 3382 .parents('.success') 3383 .removeClass('success') 3384 .end() 3385 .parents('.error') 3386 .removeClass('error'); 3387 }; 3388 3389 $(document).ready(function() { 3390 // Turn autocomplete off on CC and CVV form elements. 3391 $('input[name*="card_number"], input[name*="card_cvv"]').attr('autocomplete', 'off'); 3392 3393 // Helper function, provides the total display. 3394 // @todo: This is almost certainly dead code, but on the off chance a client 3395 // is using a quantity select on donation forms, the loose selector match has been 3396 // tightened to only match on a select named "quantity", instead of just containing 3397 // that word. 3398 function _recalculate_quantity_total() { 3399 if (!$('select[name*="[quantity]"]').length) { 3400 return; 3401 } 3402 3403 $('#quantity-total').empty(); 3404 var amount = $('input[type="radio"][name*="amount"]:checked:visible').val(); 3405 if (amount == 'other') { 3406 amount = $('input[name*="other_amount"]').val(); 3407 } 3408 // Prevent total from displaying NaN if other amount input is 3409 // incorrectly formatted. 3410 var total = 0.00; 3411 if (!isNaN(amount)) { 3412 total = $('select[name*="[quantity]"]').val() * amount; 3413 $('#quantity-total').html('Total: ' + Drupal.settings.fundraiser.currency.symbol + total); 3414 } 3415 $('select[name*="[quantity]"]').once('total-processed').after('<span id="quantity-total">Total: ' + Drupal.settings.fundraiser.currency.symbol + total + '</span>'); 3416 } 3417 3418 // When the amount changes, change the displayed total. 3419 $('select[name*="[quantity]"], input[name*="amount"], input[name*="other_amount"], input[name*="recurs_monthly"]').change(_recalculate_quantity_total()); 3420 3421 // Custom Validation Regex rules: AMEX, VISA, MASTERCARD, DISCOVER, Diner's Club, JCB 3422 $.validator.addMethod('creditcard', function(value, element) { 3423 return this.optional(element) || /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5]\d{14}$|^2(?:2(?:2[1-9]|[3-9]\d)|[3-6]\d\d|7(?:[01]\d|20))\d{12}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/i.test(value); 3424 // Doesn't work for Australian Bankcard, Dankort (PBS) cards or 3425 // Switch/Solo (Paymentech). 3426 // Bankcard regexp below needs fixing: 3427 //^5610\5[6-9]d{2}\d{4}\d{4}$ 3428 }, Drupal.t("Enter a valid credit card number")); 3429
3430 // Custom amount validation 3431 $.validator.addMethod('amount', function(value, element) { 3432 // Add regexp 3433 return this.optional(element) || /^[0-9]*(\.\d{1,3})*(,\d{1,3})?$/i.test(value); 3434 }, Drupal.t("Enter a valid amount")); 3435 3436 // Custom zipcode validation 3437 $.validator.addMethod('zipcode', function(value, element) { 3438 // Validate zip code when country is US. 3439 var country_field = $(':input[name*="[country]"]'); 3440 if (country_field.length && country_field.val() == 'US') { 3441 return this.optional(element) || /(^\d{5}((-|\s)\d{4})?$)|(^[ABCEGHJKLMNPRSTVXY]{1}\d{1}[A-Z]{1} *\d{1}[A-Z]{1}\d{1}$)/i.test(value); 3442 } 3443 return true; 3444 }, Drupal.t("Enter a valid zipcode")); 3445 3446 var recurs_monthly = $('input[type="checkbox"][name*="[recurs_monthly]["], input[type="radio"][name*="[recurs_monthly]"]:checked'); 3447 Dv.frequencyCur = recurs_monthly.val(); 3448 3449 $('input[type="checkbox"][name*="[recurs_monthly]["], input[type="radio"][name*="[recurs_monthly]"]') 3450 .on('change focus', function(){ 3451 recurs_monthly = $('input[type="checkbox"][name*="[recurs_monthly]["], input[type="radio"][name*="[recurs_monthly]"]:checked'); 3452 Dv.frequencyCur = recurs_monthly.val(); 3453 }); 3454 3455 3456 // Instantiate Form Validation 3457 Drupal.settings.fundraiser.donationValidate = $('.fundraiser-donation-form').validate({ 3458 // Custom keyup function checking for tab key (9) and when value is empty 3459 onkeyup: function (element, event) { 3460 if ($(element).next('.error').length){ 3461 if (event.which === 9 && element.value === "") { 3462 return; 3463 } else { 3464 this.element(element); 3465 } 3466 } 3467 }, 3468 onfocusout: function (element) { 3469 3470 var recurs_monthly = $('input[type="checkbox"][name*="[recurs_monthly]["], input[type="radio"][name*="[recurs_monthly]"]:checked'); 3471 var newFrequency = recurs_monthly.val(); 3472 3473 setTimeout(function() { 3474 3475 if (element.name.indexOf('recurring_other_amount') != -1) { 3476 if (Dv.frequencyCur !== newFrequency) { 3477 return; 3478 } 3479 } 3480 3481 // Bypass validation for form field added by dtd plugin. 3482 if (element.name == 'doublethedonation_company_name_input') { 3483 return; 3484 } 3485 3486 // Callback for real-time onfocusout of form elements. 3487 var isValid; 3488 try { 3489 isValid = $(element).valid(); 3490 } 3491 catch(err) { 3492 if (window.console) { 3493 console.error(err) 3494 console.error('error href: ' + window.location.href) 3495 } 3496 } 3497 3498 if (typeof validateKeyCallback == 'undefined') { 3499 return; 3500 } 3501 3502 if (isValid == 0) { 3503 // Set status to 0. 3504 validateKeyCallback.status = 0; 3505 validateKeyCallback.error(element); 3506 } 3507 else if (isValid == 1) { 3508 // Set status to 1. 3509 validateKeyCallback.status = 1; 3510 validateKeyCallback.success(element); 3511 } 3512 }, 500); 3513 }, 3514 3515 highlight: function(element) { 3516 $element = $(element); 3517 var single = $element.attr('name') == 'submitted[donation][amount]'; 3518 var recurring = $element.attr('name') == 'submitted[donation][recurring_amount]'; 3519 var QuarterlyFreqAmounts = $element.attr('name') == 'frequencies[sb_fs_quarterly_amount]'; 3520 var SemiAnnualFreqAmounts = $element.attr('name') == 'frequencies[sb_fs_semi_amount]'; 3521 var AnnuallyFreqAmounts = $element.attr('name') == 'frequencies[sb_fs_annually_amount]'; 3522 3523 if (single || recurring || QuarterlyFreqAmounts || SemiAnnualFreqAmounts || AnnuallyFreqAmounts) { 3524 var $error = $element.next('label.error'); 3525 if ($error.length) { 3526 if (single) { 3527 $error.detach().appendTo('#edit-submitted-donation-amount'); 3528 } 3529 else if (recurring) { 3530 $error.detach().appendTo('#edit-submitted-donation-recurring-amount'); 3531 } 3532 else if (QuarterlyFreqAmounts) { 3533 $error.detach().appendTo('#edit-frequencies-sb-fs-quarterly-amount'); 3534 } 3535 else if (SemiAnnualFreqAmounts) { 3536 $error.detach().appendTo('#edit-frequencies-sb-fs-semi-amount'); 3537 } 3538 else if (AnnuallyFreqAmounts) { 3539 $error.detach().appendTo('#edit-frequencies-sb-fs-annually-amount'); 3540 } 3541 } 3542 3543 $element.parent('.control-group').removeClass('success').addClass('error').siblings('.control-group').removeClass('success').addClass('error'); 3544 } 3545 else { 3546 $(element).removeClass('valid'); 3547 $(element).addClass('key-validate'); 3548 $(element).closest('.control-group').removeClass('success').addClass('error'); 3549 } 3550 }, 3551 3552 success: function(element) { 3553 $element = $(element); 3554 var single = $element.prev('input[name="submitted[donation][amount]"]').length; 3555 var recurring = $element.prev('input[name="submitted[donation][recurring_amount]"]').length; 3556 var QuarterlyFreqAmounts = $element.prev('input[name*="frequencies[sb_fs_quarterly_amount]"]').length; 3557 var SemiAnnualFreqAmounts = $element.prev('input[name*="frequencies[sb_fs_semi_amount]"]').length; 3558 var AnnuallyFreqAmounts = $element.prev('input[name*="frequencies[sb_fs_annually_amount]"]').length; 3559 3560 if (single || recurring || QuarterlyFreqAmounts || SemiAnnualFreqAmounts || AnnuallyFreqAmounts) { 3561 if (single) { 3562 $element.detach().appendTo('#edit-submitted-donation-amount'); 3563 } 3564 else if (recurring) { 3565 $element.detach().appendTo('#edit-submitted-donation-recurring-amount'); 3566 } 3567 else if (QuarterlyFreqAmounts) { 3568 $element.detach().appendTo('#edit-frequencies-sb-fs-quarterly-amount'); 3569 } 3570 else if (SemiAnnualFreqAmounts) { 3571 $element.detach().appendTo('#edit-frequencies-sb-fs-semi-amount'); 3572 } 3573 else if (AnnuallyFreqAmounts) { 3574 $element.detach().appendTo('#edit-frequencies-sb-fs-annually-amount'); 3575 } 3576 } 3577 else { 3578 $element.text('OK').addClass('valid').closest('.control-group').removeClass('error').addClass('success'); 3579 } 3580 } 3581 }); 3582 3583 // On change and keyup check form status 3584 $(".fundraiser-donation-form :input.key-validate").bind('change keyup', function() { 3585 Drupal.settings.fundraiser.donationValidate.element('#' + $(this).attr('id')); 3586 }); 3587 3588 // Track isValid status of each Braintree hosted field, if we are using that payment method. 3589 var braintreeFields = false;
3590 if ($('.braintree-hosted-field').length) { 3591 braintreeFields = {'number' : false, 'expirationMonth' : false , 'expirationYear' : false , 'cvv' : false }; 3592 $(document).on('braintree.fieldEvent', function(event, param) { 3593 var field = param.fields[param.emittedBy]; 3594 var $field = $(field.container); 3595 if (param.emittedBy == 'cvv') { 3596 braintreeFields[param.emittedBy] = field.isValid && !field.isEmpty; 3597 } 3598 else { 3599 braintreeFields[param.emittedBy] = field.isValid; 3600 } 3601 3602 if (!braintreeFields[param.emittedBy]) { 3603 if (param.emittedBy == 'number') { 3604 $field.addClass('error'); 3605 } 3606 else { 3607 $field.closest('.control-group').removeClass('success').addClass('error'); 3608 } 3609 } 3610 else { 3611 if (param.emittedBy == 'number') { 3612 $field.removeClass('error').addClass('success'); 3613 } 3614 else { 3615 $field.closest('.control-group').removeClass('error').addClass('success'); 3616 } 3617 } 3618 }); 3619 } 3620 3621 var formIsValid = function() { 3622 // If we are using Braintree, both the braintree form and the drupal 3623 // fields must validate. 3624 var standardFormValid = Drupal.settings.fundraiser.donationValidate.form(); 3625 if (!standardFormValid) { 3626 return false; 3627 } 3628 //BRAINTREE 3629 else if (undefined !== Drupal.braintreeInstance) { 3630 if (Drupal.braintreeInstance.$cardonfile && Drupal.braintreeInstance.$cardonfile != 'new') { 3631 return true; 3632 } 3633 else if (Drupal.settings.braintree.currentPaymentMethod == 'paypal' || Drupal.settings.braintree.currentPaymentMethod == 'applepay') { 3634 if (!Drupal.settings.fundraiserTickets && !Drupal.settings.fdNid) { 3635 // Check recurring setting and validate appropriate amount fields. 3636 var $amount = $('input[name="submitted[donation][amount]"]'); 3637 var $recurringAmount = $('input[name="submitted[donation][recurring_amount]"]'); 3638 var $recurringQuarterlyAmount = $('input[name="frequencies[sb_fs_quarterly_amount]"]'); 3639 var $recurringSemiAmount = $('input[name="frequencies[sb_fs_semi_amount]"]'); 3640 var $recurringAnnuallyAmount = $('input[name="frequencies[sb_fs_annually_amount]"]'); 3641 3642 var $otherAmount = $('input[name="submitted[donation][other_amount]"]'); 3643 var $recurringOtherAmount = $('input[name="submitted[donation][recurring_other_amount]"]'); 3644 // Check if recurring setting is a checkbox or radios. 3645 if ($('input[name*="[recurs_monthly][recurs]"]').length) { 3646 // Checkboxes have special settings. 3647 var $recurs = $('input[name*="[recurs_monthly][recurs]"]'); 3648 if ($recurs.attr('checked') == 'checked') { 3649 $recursValue = $('input[name*="[recurs_monthly][recurs]"]').val(); 3650 } 3651 else { 3652 $recursValue = false; 3653 } 3654 } 3655 else { 3656 var $recurs = $('input[name*="[recurs_monthly]"]'); 3657 var $recursValue = $('input[name*="[recurs_monthly]"]').filter(':checked').val(); 3658 } 3659 3660 var notHidden = true; 3661 if ($.inArray($recursValue, ["recurs", "sb_fs_quarterly", "sb_fs_semi", "sb_fs_annually"]) != -1) { 3662 if ($recursValue === 'recurs') { 3663 notHidden = $recurringAmount.attr("type") != "hidden" 3664 } 3665 else { 3666 notHidden = $('input[name="frequencies[' + $recursValue + '_amount]"]').length > 0; 3667 } 3668 } 3669 3670 // Determine if this is a one-time or recurring dual ask form and take appropriate action. 3671 if ($recurs.attr("type") != "hidden" 3672 && $.inArray($recursValue, ["recurs", "sb_fs_quarterly", "sb_fs_semi", "sb_fs_annually"]) != -1 3673 && notHidden) { 3674 3675 switch ($recursValue) { 3676 case 'recurs':
3677 var $checked = $recurringAmount.filter(':checked').val(); 3678 break; 3679 3680 case 'sb_fs_quarterly': 3681 if ($recurringQuarterlyAmount.length) { 3682 $checked = $recurringQuarterlyAmount.filter(':checked').val() 3683 } 3684 break; 3685 3686 case 'sb_fs_semi': 3687 if ($recurringSemiAmount.length) { 3688 $checked = $recurringSemiAmount.filter(':checked').val(); 3689 } 3690 break; 3691 3692 case 'sb_fs_annually': 3693 if ($recurringAnnuallyAmount.length) { 3694 $checked = $recurringAnnuallyAmount.filter(':checked').val(); 3695 } 3696 break; 3697 } 3698 3699 // Check for other only configuration. 3700 if (typeof $checked === 'undefined' && $recurringOtherAmount.length) { 3701 switch ($recursValue) { 3702 case 'recurs': 3703 if ('other' == $recurringAmount.filter(':hidden').val() || !$recurringAmount.length) { 3704 $checked = $recurringOtherAmount.val(); 3705 } 3706 break; 3707 3708 case 'sb_fs_quarterly': 3709 // Any of the new frequencies can use the recurring amount field if there is only one 3710 // recurring frequency active. 3711 if ('other' == $recurringQuarterlyAmount.filter(':hidden').val() || !$recurringQuarterlyAmount.length) { 3712 $checked = $recurringOtherAmount.val(); 3713 } 3714 break; 3715 3716 case 'sb_fs_semi': 3717 // Any of the new frequencies can use the recurring amount field if there is only one 3718 // recurring frequency active. 3719 if ('other' == $recurringSemiAmount.filter(':hidden').val() || !$recurringSemiAmount.length) { 3720 $checked = $recurringOtherAmount.val(); 3721 } 3722 break; 3723 3724 case 'sb_fs_annually': 3725 // Any of the new frequencies can use the recurring amount field if there is only one 3726 // recurring frequency active. 3727 if ('other' == $recurringAnnuallyAmount.filter(':hidden').val() || !$recurringAnnuallyAmount.length) { 3728 $checked = $recurringOtherAmount.val(); 3729 } 3730 break; 3731 } 3732 } 3733 3734 } 3735 else { 3736 var $checked = $amount.filter(':checked').val(); 3737 if ($checked == 'other') { 3738 $checked = $otherAmount.val(); 3739 } 3740 // Other only, no radios. 3741 else if ( 3742 typeof $checked === 'undefined' 3743 && $otherAmount.length 3744 && ($amount.filter(':hidden').val() == 'other' || !$amount.length) 3745 ) { 3746 $checked = $otherAmount.val(); 3747 } 3748 } 3749 3750 // If we don't have a selected amount, return invalid. 3751 if (typeof($checked) === "undefined" || !$checked.length) { 3752 return false; 3753 } 3754 } 3755 3756 // If we have a valid amount, ensure we have a nonce. 3757 var $nonce = $('input[name=payment_method_nonce]'); 3758 return $nonce.length > 0; 3759 } 3760 // Process credit card only if Braintree fields are populated. 3761 else if (braintreeFields !== false && braintreeFields.number !== false) { 3762 var isBillingUpdate = undefined !== Drupal.settings.braintree.billing_update_type; 3763 var $isOcd = $('input[name$="[cardonfile]"][value!="new"]'); 3764 var braintreeFieldsAreValid = function() { 3765 if ($isOcd.filter(':checked').length) { 3766 return true; 3767 } 3768 3769 // Considered valid when not on a billing update form and all 3770 // fields are filled out, or on a billing update form and either 3771 // no fields are filled out or all fields are filled out. 3772 var returnValue = true; 3773 var atLeastOneTrue = false;
3774 $.each(braintreeFields, function(index, value) { 3775 if (!value) { 3776 returnValue = false; 3777 // We can return early if not on a billing update form. 3778 if (!isBillingUpdate) { 3779 return false; 3780 } 3781 } 3782 else { 3783 atLeastOneTrue = true; 3784 } 3785 }); 3786 3787 if (!returnValue && isBillingUpdate && !atLeastOneTrue) { 3788 returnValue = true; 3789 } 3790 3791 return returnValue; 3792 }; 3793 3794 return braintreeFieldsAreValid(); 3795 } 3796 } 3797 // END BRAINTREEE 3798 3799 return true; 3800 }; 3801 // END formIsValid 3802 3803 var $submit = $('.fundraiser-donation-form #edit-submit'); 3804 var $submitMessage = $('.fundraiser_submit_message'); 3805 3806 var $span = $('<span/>').addClass('donation-processing-spinner'); 3807 var $processtext = Drupal.t('Processing') + ' '; 3808 var $p = $('<p/>').addClass('donation-processing').text($processtext).append($span); 3809 var $div = $('<div/>').addClass('donation-processing-wrapper').append($p); 3810 $div.hide(); 3811 3812 // Add the processing button now since the background needs to be loaded 3813 // and doing it on submit might cause the background not to load in 3814 // time. 3815 $submit.once().after($div); 3816 3817 // On submission hide the button and replace it with a new value. 3818 // Wrap the click in a once trigger to be sure that we bind it only 3819 // once. 3820 $('.fundraiser-donation-form').once(function() { 3821 $('.fundraiser-donation-form').on('submit.donationValidate', function() { 3822 // Validate the form 3823 if (formIsValid()) { 3824 $submit.add($submitMessage).hide(); 3825 $div.show(); 3826 3827 // Scroll to donate button if it's not in view. 3828 var docTop = $(window).scrollTop(); 3829 var docBottom = docTop + $(window).height(); 3830 var divTop = $div.offset().top; 3831 var divBottom = divTop + $div.height(); 3832 // Offset in pixels, so that element we scroll to isn't on edge. 3833 var offset = 50; 3834 if (divBottom > docBottom || divTop < docTop) { 3835 var newTop = parseInt(divTop); 3836 if (divBottom > docBottom) { 3837 newTop += offset; 3838 } 3839 else { 3840 newTop -= offset; 3841 } 3842 $('html, body').animate({ 3843 scrollTop: newTop 3844 }, 100); 3845 } 3846 3847 return true; 3848 } 3849 return false; 3850 }); 3851 }); 3852 3853 // If this is a Braintree paypal submission and the user closed the 3854 // paypal popup, set the submit button back to its initial state. 3855 $(document).on('braintree.error', function(e, error_msg) { 3856 if (typeof error_msg.code !== 'undefined' && error_msg.code == 'PAYPAL_POPUP_CLOSED') { 3857 $div.hide(); 3858 $submit.add($submitMessage).show(); 3859 } 3860 }); 3861 3862 // Iterate validation settings and apply rules. 3863 var $selector; 3864 if (Drupal.settings.fundraiser && Drupal.settings.fundraiser.js_validation_settings) { 3865 for ($key in Drupal.settings.fundraiser.js_validation_settings) { 3866 $selector = $('input[name*="' + $key + '"]'); 3867 if ($selector.length) { 3868 $selector.rules('add', Drupal.settings.fundraiser.js_validation_settings[$key]); 3869 } 3870 } 3871 } 3872 3873 // Other Amount 3874 var $other_amount = $('input[name*="[other_amount]"][type!="hidden"]'); 3875 $($other_amount).blur(function () { 3876 var otherAmountField = $(this); 3877 if (otherAmountField.parent().children('.field-suffix').length > 0) { 3878 var errorMessage = otherAmountField.parent().children('label.error').detach(); 3879 otherAmountField.parent().children('.description').after(errorMessage); 3880 } 3881 }); 3882 3883 if ($other_amount.length) { 3884 $other_amount.each(function() { 3885 $(this).rules('add', { 3886 required: function(element) { 3887 return $('input[type="radio"][name$="[amount]"]:checked').length == 0 || $('input[type="radio"][name$="[amount]"][value="other"]:visible').is(":checked"); 3888 }, 3889 amount: true, 3890 min: parseFloat(Drupal.settings.fundraiserWebform.minimum_donation_amount), 3891 max: parseFloat(Drupal.settings.fundraiserWebform.fundraiser_maximum_other_amount), 3892 messages: { 3893 required: Drupal.t("This field is required"), 3894 amount: Drupal.t("Enter a valid amount"), 3895 min: Drupal.t("The amount entered is less than the minimum donation amount.") 3896 } 3897 }); 3898 }); 3899 } 3900 3901 var $recurring_other_amount = $('input[name$="[recurring_other_amount]"]'); 3902 $($recurring_other_amount).blur(function () { 3903 var recurringOtherAmountField = $(this); 3904 if (recurringOtherAmountField.parent().children('.field-suffix').length > 0) { 3905 var errorMessage = recurringOtherAmountField.parent().children('label.error').detach(); 3906 recurringOtherAmountField.parent().children('.description').after(errorMessage); 3907 } 3908 }); 3909 3910 var recurringOtherRuleEnabled = false;
3911 if ($recurring_other_amount.length) { 3912 $recurring_other_amount.each(function() { 3913 var $this = $(this); 3914 var enableRecurringOtherRule = function() { 3915 $this.rules('add', { 3916 required: function(element) { 3917 var frequency = $('input[type="checkbox"][name*="[recurs_monthly]["], input[type="radio"][name*="[recurs_monthly]"]:checked').val(); 3918 if (frequency === 'recurs') { 3919 var req = $('input[type="radio"][name$="[recurring_amount]"]:checked').length == 0 3920 || $('input[type="radio"][name$="[recurring_amount]"][value="other"]:visible').is(":checked"); 3921 3922 return req; 3923 } 3924 else { 3925 var req = $('input[type="radio"][name$="[' + frequency + '_amount]"]:checked').length == 0 3926 || $('input[type="radio"][name$="[' + frequency + '_amount]"][value="other"]:visible').is(":checked"); 3927 return req; 3928 } 3929 }, 3930 amount: true, 3931 min: function(){ 3932 var frequency = $('input[type="checkbox"][name*="[recurs_monthly]["], input[type="radio"][name*="[recurs_monthly]"]:checked').val(); 3933 if (frequency === 'recurs') { 3934 return parseFloat(Drupal.settings.fundraiserWebform.recurring_minimum_donation_amount) 3935 } 3936 else { 3937 if ($('input[type="radio"][name$="[' + frequency + '_amount]"]:checked').length) { 3938 var min = Drupal.settings.fundraiser.recurring_settings[frequency + '_minimum_donation_amount']; 3939 return parseFloat(min) 3940 } 3941 return parseFloat(Drupal.settings.fundraiserWebform.recurring_minimum_donation_amount) 3942 } 3943 }, 3944 max: parseFloat(Drupal.settings.fundraiserWebform.fundraiser_maximum_other_amount), 3945 messages: { 3946 required: Drupal.t("This field is required"), 3947 amount: Drupal.t("Enter a valid amount"), 3948 min: Drupal.t("The amount entered is less than the minimum donation amount.") 3949 }, 3950 }); 3951 recurringOtherRuleEnabled = true; 3952 }; 3953 3954 // If the recurring other amount is hidden by default (in the case 3955 // of dual ask amounts), we need to add it's rule when it becomes 3956 // visible. 3957 if (!$this.is(':visible') && !recurringOtherRuleEnabled) { 3958 $('input[type="checkbox"][name*="[recurs_monthly]["], input[type="radio"][name*="[recurs_monthly]"]') 3959 .on('change', function(e) { 3960 var $target = $(e.target); 3961 var frequency = $target.val(); 3962 if ($target.is(':checked') && 3963 ( frequency == 'recurs' 3964 || frequency == 'sb_fs_quarterly' 3965 || frequency == 'sb_fs_semi' 3966 || frequency == 'sb_fs_annually' 3967 )) { 3968 enableRecurringOtherRule(); 3969 } 3970 }); 3971 } 3972 else { 3973 enableRecurringOtherRule(); 3974 } 3975 }); 3976 3977 $('input[name*="frequencies["], input[name="submitted[donation][amount]"], input[name="submitted[donation][recurring_amount]"]').change(function() { 3978 if ($(this).filter(':checked').length) { 3979 $(this).parent('.control-group').removeClass('error').addClass('success').siblings('.control-group').removeClass('error').addClass('success'); 3980 } 3981 }) 3982 } 3983 3984 // If neither "other" field is present, add validation for the amount 3985 // radios. 3986 var recurSettings = Drupal.settings.fundraiser.recurring_settings; 3987 // Multifrequency == at least two recurring frequencies are active on the form. 3988 var multiFrequency = typeof(Drupal.settings.fundraiser.multi_frequency) != "undefined" 3989 3990 if (!$other_amount.length 3991 || !recurSettings.recurs_show_other_amount == 0 3992 || !recurSettings.sb_fs_quarterly_show_other_amount == 0 3993 || !recurSettings.sb_fs_semi_show_other_amount == 0 3994 || !recurSettings.sb_fs_annually_show_other_amount == 0 3995 ) { 3996 3997 var selector = []; 3998 var recurringRuleEnabled = false;
3999 4000 if (!$other_amount.length && $recurring_other_amount.length) { 4001 if ($('input[name="submitted[donation][amount]"]:first').length > 0) { 4002 selector.push($('input[name="submitted[donation][amount]"]:first')); 4003 } 4004 } 4005 if (!$other_amount.length && !$recurring_other_amount.length) { 4006 if ($('input[name="submitted[donation][amount]"]:first').length > 0) { 4007 selector.push($('input[name="submitted[donation][amount]"]:first')); 4008 } 4009 } 4010 4011 if (typeof(recurSettings) != "undefined") { 4012 $.each(recurSettings.active_frequencies, function(key, values) { 4013 if (key === 'NO_RECURR') { 4014 return; 4015 } 4016 4017 var freq = key + '_show_other_amount'; 4018 if (recurSettings[freq] == 0) { 4019 if (!multiFrequency || key =='recurs') { 4020 if($('input[name="submitted[donation][recurring_amount]"]:first').length > 0) { 4021 selector.push($('input[name="submitted[donation][recurring_amount]"]:first')); 4022 } 4023 } 4024 if (multiFrequency && key !== 'recurs') { 4025 if ($('input[name="frequencies[' + key + '_amount]"]:first').length > 0) { 4026 selector.push($('input[name="frequencies[' + key + '_amount]"]:first')); 4027 } 4028 } 4029 } 4030 }); 4031 } 4032 4033 $.each(selector, function() { 4034 4035 var $this = this; 4036 4037 var enableRecurringRule = function() { 4038 $this.rules('add', { 4039 required: function(element) { 4040 return $this.siblings('input[type=radio]').filter(':checked').length == 0; 4041 }, 4042 messages: { 4043 required: Drupal.t("This field is required"), 4044 }, 4045 }); 4046 recurringRuleEnabled = true; 4047 }; 4048 4049 if (!$this.is(':visible') && !recurringRuleEnabled) { 4050 $('input[type="checkbox"][name*="[recurs_monthly]["], input[type="radio"][name*="[recurs_monthly]"]').on('change', function(e) { 4051 var $target = $(e.target); 4052 var frequency = $target.val(); 4053 if ($target.is(':checked') && 4054 ( frequency == 'recurs' 4055 || frequency == 'sb_fs_quarterly' 4056 || frequency == 'sb_fs_semi' 4057 || frequency == 'sb_fs_annually' 4058 )) { 4059 enableRecurringRule(); 4060 } 4061 }); 4062 } 4063 else { 4064 enableRecurringRule(); 4065 } 4066 }); 4067 4068 $('input[name="submitted[donation][amount]"]').change(function() { 4069 if ($(this).filter(':checked').length) { 4070 $(this).parent('.control-group').removeClass('error').addClass('success').siblings('.control-group').removeClass('error').addClass('success'); 4071 } 4072 }); 4073 } 4074 4075 $('input[name="submitted[donation][amount]"], input[name="submitted[donation][recurring_amount]"]').change(function(){ 4076 $('input[name="submitted[donation][other_amount]"]').removeClass('key-validate'); 4077 $('input[name="submitted[donation][recurring_other_amount]"]').removeClass('key-validate'); 4078 }); 4079 4080 // Focus and Blur conditional functions for non-recurring other amount. 4081 $('input[type="radio"][name*="[amount]"]').change(function(){ 4082 if ($(this).val() == 'other') { 4083 $('input[name*="[other_amount]"]').focus(); 4084 } 4085 else { 4086 clearElement($('input[name*="[other_amount]"]')); 4087 } 4088 }); 4089 4090 $('input[name*="[other_amount]"]').focus(function () { 4091 $('input[type="radio"][name*="[amount]"][value="other"]').attr('checked', 'checked').trigger('multiCurrency'); 4092 }); 4093 4094 // Focus and Blur conditional functions for recurring other amount. 4095 if (typeof(recurSettings) != "undefined") { 4096 $.each(recurSettings.active_frequencies, function(key, values) { 4097 if (key === 'NO_RECURR') { 4098 return; 4099 } 4100 if (!multiFrequency || key =='recurs') { 4101 $('input[type="radio"][name*="[recurring_amount]"]').change(function(){ 4102 if ($(this).val() == 'other') { 4103 $('input[name*="[recurring_other_amount]"]').focus(); 4104 } 4105 else { 4106 clearElement($('input[name*="[recurring_other_amount]"]')); 4107 } 4108 }); 4109 } 4110 if (multiFrequency && key !== 'recurs') { 4111 $('input[type="radio"][name*="[' + key + '_amount]"]').change(function(){ 4112 if ($(this).val() == 'other') { 4113 $('input[name*="[recurring_other_amount]"]').focus(); 4114 } 4115 else { 4116 clearElement($('input[name*="[recurring_other_amount]"]')); 4117 } 4118 }); 4119 } 4120 }); 4121 } 4122 4123 $('input[name*="[recurring_other_amount]"]').focus(function(){ 4124 var $recursValue = $('input[name*="[recurs_monthly]"]').filter(':checked').val(); 4125 switch($recursValue) { 4126 case 'recurs': 4127 $('input[type="radio"][name*="[recurring_amount]"][value="other"]').attr('checked', 'checked').trigger('multiCurrency');; 4128 break; 4129 4130 default: 4131 if (multiFrequency) { 4132 $('input[type="radio"][name*="[' + $recursValue + '_amount]"][value="other"]').attr('checked', 'checked').trigger('multiCurrency');; 4133 } 4134 else { 4135 $('input[type="radio"][name*="[recurring_amount]"][value="other"]').attr('checked', 'checked').trigger('multiCurrency');; 4136 } 4137 } 4138 }); 4139 4140 // Runs on Other Amount field 4141 $('input[name*="other_amount"], input[name*="fee_amount"], input[name*="addon-amount"]').blur(function(){ 4142 var value = this.value; 4143 // check for custom validation function object 4144 if (undefined == window.customValidation) { 4145 // If the value has length and includes at least one integer 4146 if (value.length && this.value.match(/\d/g)) { 4147 // Replace commas used as decimal place in international currency. 4148 if (value.match(/\,/)) { 4149 var count = value.length; 4150 var pos = value.lastIndexOf(","); 4151 if (pos !== -1) { 4152 // Is the comma the third-to-last character in the amount? Replace it with a decimal. 4153 var delimiterPosition = count - (pos + 1); 4154 if (delimiterPosition === 2) { 4155 value = value.substring(0, pos) + '.' + value.substring(pos + 1); 4156 } 4157 } 4158 } 4159 // if no period period 4160 if (!value.match(/\./)) { 4161 // no decimals: strip all other chars, add decimal and 00 4162 value = value.replace(/[^\d]+/g,'') + '.00'; 4163 } else { 4164 // Remove all non-integer/period chars 4165 value = value.replace(/[^\d\.]+/g,'') 4166 // make first decimal unique 4167 .replace(/\./i,'-') 4168 // replace subsequent decimals 4169 .replace(/\./g,'') 4170 // set first back to normal 4171 .replace('-','.') 4172 // match the last two digits, removing others 4173 .match(/\d+\.\d{0,2}|\.\d{0,2}/); 4174 var newValue = value[0]; 4175 if (newValue.match(/\.\d{2}/)) { 4176 } else if (newValue.match(/\.\d{1}/)) { 4177 value += '0'; 4178 } else { 4179 value += '00'; 4180 } 4181 } 4182 this.value = value; 4183 // total should be recalculated as value has changed without triggering .change() event handler. 4184 _recalculate_quantity_total();
4185 $(this).valid(); 4186 } 4187 } else { 4188 window.customValidation(value); 4189 $(this).valid(); 4190 } 4191 }); 4192 4193 addPhoneValidation($("input.phone-validation[type=text]"), settings); 4194 4195 // Ability to override the default message 4196 jQuery.extend(jQuery.validator.messages, { 4197 required: Drupal.t("This field is required"), 4198 remote: Drupal.t("Please fix this field"), 4199 email: Drupal.t("Enter a valid email address"), 4200 url: Drupal.t("Enter a valid URL"), 4201 date: Drupal.t("Enter a valid date"), 4202 dateISO: Drupal.t("Enter a valid date (ISO)"), 4203 number: Drupal.t("Must be a number"), // changed 4204 digits: Drupal.t("Enter only digits"), 4205 creditcard: Drupal.t("Enter a valid credit card number"), 4206 equalTo: Drupal.t("Enter the same value again"), 4207 accept: Drupal.t("Enter a value with a valid extension"), 4208 maxlength: jQuery.validator.format(Drupal.t("Enter no more than {0} characters")), 4209 minlength: jQuery.validator.format(Drupal.t("Enter at least {0} characters")), 4210 rangelength: jQuery.validator.format(Drupal.t("Enter a value between {0} and {1} characters long")), 4211 range: jQuery.validator.format(Drupal.t("Enter a value between {0} and {1}")), 4212 max: jQuery.validator.format(Drupal.t("Enter a value less than or equal to {0}")), 4213 min: jQuery.validator.format(Drupal.t("Enter a value greater than or equal to {0}")) 4214 }); 4215 4216 // Small helper item 4217 $('select').each(function(){ 4218 if ($(this).next().is('select')) { 4219 $(this).next().addClass('spacer'); 4220 } 4221 }); 4222 4223 // Implementing our own alert close 4224 // Bootstrap.js uses the .on method, not added until jQuery 1.7 4225 $('.close').click(function(){ 4226 $(this).closest('.alert').fadeOut(); 4227 }); 4228 }); // window.ready 4229 function addPhoneValidation($telInput, settings) { 4230 if (!$telInput.length) { 4231 return; // Add formatting 4232 } 4233 4234 $telInput.on("change keyup", function (event) { 4235 // Don't reformat backspace/delete and shift/tab so correcting mistakes is easier 4236 if ( 4237 event.keyCode != 46 && 4238 event.keyCode != 8 && 4239 event.keyCode != 9 && 4240 event.keyCode != 16 4241 ) { 4242 var val_old = $(this).val(); 4243 var newString = new libphonenumber.AsYouType("US").input(val_old); 4244 $(this) //.trigger("focus") // @NOTE Removed, as this was creating a behavior that required 2 clicks or 4245 // tabs to escape the field. With this removed, I am not finding the phone# field behavior to be 4246 // negatively impacted 4247 .val("") 4248 .val(newString); 4249 } 4250 }); // Add validation 4251 4252 if ($.validator) { 4253 var validatePhoneUS = function validatePhoneUS( 4254 phoneNumber, 4255 element 4256 ) { 4257 try { 4258 return ( 4259 this.optional(element) || 4260 (phoneNumber.length > 9 && 4261 libphonenumber.parsePhoneNumber(phoneNumber, "US").isValid()) 4262 ); 4263 } 4264 catch (error) { 4265 // In practice parsePhoneNumber() returns undefined and throws an 4266 // Error when the number can't be parsed: NOT_A_NUMBER, TOO_SHORT, 4267 // TOO_LONG, INVALID_COUNTRY. 4268 if (error.stack && error.message) { 4269 if (window.console) { 4270 console.log(error.message); 4271 } 4272 return false; 4273 } 4274 // An error unknown to libphonejs 4275 else { 4276 throw error; 4277 } 4278 } 4279 }; 4280 4281 if ("phoneUS" in $.validator.methods) { 4282 $.validator.methods.phoneUS = validatePhoneUS; 4283 } else { 4284 $.validator.addMethod( 4285 "phoneUS", 4286 validatePhoneUS, 4287 Drupal.t("Please specify a valid US phone number") 4288 ); 4289 } 4290 4291 $telInput.rules("add", { 4292 phoneUS: true, 4293 }); 4294 } 4295 } 4296 } // attach.function 4297 } // drupal.behaviors 4298})( 4299 window.DonationValidation = window.DonationValidation || {}, 4300 jQuery); 4301 4302; 4303(function ($) { 4304 Drupal.behaviors.dualAskAmounts = { 4305 attach: function (context, settings) { 4306 $(window).ready(function () { 4307 4308 // Validate the recurring other amount field. 4309 if ($('input[name$="recurring_other_amount]"]')[0]) { 4310 4311 // Find the relevant fields for validation context. 4312 var recurs_monthly = $('input[type="checkbox"][name*="[recurs_monthly]["], input[type="radio"][name*="[recurs_monthly]"]:checked'); 4313 var frequency = recurs_monthly.val(); 4314 var recurring_other = $('input[name$="recurring_other_amount]"]'); 4315 var allFreq = Drupal.settings.defaultRecurringFrequencies; 4316 // Add a rule for the default frequency. 4317 addRule(frequency); 4318 4319 // Add a rule for the selected frequency. 4320 $('input[type="checkbox"][name*="[recurs_monthly]["], input[type="radio"][name*="[recurs_monthly]"]') 4321 .on('change', function (e) { 4322 var $target = $(e.target); 4323 var frequency = $target.val(); 4324 if ($target.is(':checked') && 4325 ( frequency == 'recurs' 4326 || frequency == 'sb_fs_quarterly' 4327 || frequency == 'sb_fs_semi' 4328 || frequency == 'sb_fs_annually' 4329 )) { 4330 if ($('input[type="radio"][name*="[recurs_monthly]"]').length) { 4331 var oneTime = $('input[type="radio"][name*="[recurs_monthly]"][value*="NO_RECURR"]').length 4332 var radSize = $('input[type="radio"][name*="[recurs_monthly]"]').length; 4333 if ((oneTime == 1 && radSize > 2) || oneTime == 0 && radSize > 1) { 4334 clearOther(recurring_other); 4335 } 4336 } 4337 addRule(frequency); 4338 } 4339 }) 4340 4341 } 4342 }); // window.ready 4343 4344 var clearOther = function ($selector) { 4345 4346 $selector 4347 .val('') 4348 .removeClass('valid') 4349 .next('label') 4350 .remove() 4351 .end() 4352 .parents('.success') 4353 .removeClass('success') 4354 .end() 4355 .parents('.error') 4356 .removeClass('error'); 4357 }; 4358 4359 4360 function addRule(frequency) { 4361 4362 $('input[name$="recurring_other_amount]"]').rules("add", {
4363 // Require the amount validation. 4364 amount: true, 4365 // Minimum amount validation. 4366 min: function () { 4367 4368 // If the default frequency is "recurs" or "NO_RECURR" the other amount field gets 4369 // the 'recurs" minimum. The minimum is reset when a new frequency is chosen. 4370 var min = parseFloat(Drupal.settings.fundraiserWebform.recurring_minimum_donation_amount); 4371 var allFreq = Drupal.settings.defaultRecurringFrequencies; 4372 4373 // Validate minimum for non-monthly recurring. We exclude recurring here because it might not 4374 // have a value yet on legacy forms. 4375 if (frequency !== 'recurs' && $.inArray(frequency, allFreq) !== -1) { 4376 var freqMin = Drupal.settings.fundraiser.recurring_settings[frequency + '_minimum_donation_amount']; 4377 min = parseFloat(freqMin) 4378 } 4379 return min; 4380 }, 4381 required: { 4382 depends: function (element) { 4383 if (frequency === 'recurs') { 4384 var req = $('input[type="radio"][name$="[recurring_amount]"]:checked').length == 0 4385 || $('input[type="radio"][name$="[recurring_amount]"][value="other"]:visible').is(":checked"); 4386 return req; 4387 } 4388 else if (frequency !== 'NO_RECURR') { 4389 var req = $('input[type="radio"][name$="[' + frequency + '_amount]"]:checked').length == 0 4390 || $('input[type="radio"][name$="[' + frequency + '_amount]"][value="other"]:visible').is(":checked"); 4391 return req; 4392 } 4393 } 4394 }, 4395 4396 messages: { 4397 amount: Drupal.t("Enter a valid amount"), 4398 min: Drupal.t("The amount entered is less than the minimum donation amount."), 4399 required: Drupal.t("This field is required"), 4400 } 4401 }); 4402 } 4403 4404 } // attach.function 4405 } // drupal.behaviors 4406})(jQuery); 4407; 4408(function (mF, $, undefined) { 4409 Drupal.behaviors.multiFrequency = { 4410 attach: function (context, settings) { 4411 4412 // Swap the labels on the recurring other amount field for 4413 // to match the currently selected frequency. 4414 mF.otherWrapper = $('div[id*="recurring-other-amount"].form-item'); 4415 var recurs = $('input[name*="recurs_monthly"]'); 4416 recurs.find(":checked").trigger('click'); 4417 mF.otherWrapper.once('recurring-other-processed', function() { 4418 hideDescription(recurs.filter(':checked').val()) 4419 recurs.on('click', function(){ 4420 var selected = $(this).val(); 4421 hideDescription(selected) 4422 }); 4423 4424 }); 4425 } // attach.function 4426 }; // drupal.behaviors 4427 4428 var hideDescription = function(selected) { 4429 var spans = mF.otherWrapper.find('div.description').find("span"); 4430 spans.each(function(){ 4431 var className = 'min-' + selected; 4432 if ($(this).hasClass(className)) { 4433 $(this).show(); 4434 } 4435 else { 4436 $(this).hide(); 4437 } 4438 }) 4439 } 4440 4441 4442})(window.SpringboardMultiFrequency = window.SpringboardMultiFrequency || {}, jQuery); 4443; 4444Drupal.behaviors.fundraiserGatewayBehavior = { 4445 4446 attach: function(context, settings) { (function($) { 4447 // Payment selection triggered changes. 4448 function paymentImages() { 4449 var gateway = $(this).val(); 4450 var paymentId = this.id; 4451 var text = Drupal.settings.fundraiser[gateway].text; 4452 var labelImg = Drupal.settings.fundraiser[gateway].selected_image; 4453 // Automatically change submit button text when payment gateway selected. 4454 if (typeof(text) !== "undefined") { 4455 var oldText = $("#edit-submit").val().toUpperCase(); 4456 $("#edit-submit").val(text); 4457 var fsm = $(".fundraiser_submit_message"); 4458 if (fsm.length > 0) { 4459 var fsmHtml = fsm.html().replace(oldText, text.toUpperCase()); 4460 fsm.html(fsmHtml); 4461 } 4462 } 4463 $('label[for='+paymentId+'] img').attr('src', labelImg); 4464 $("input[name='submitted[payment_information][payment_method]']").each(function(gateway) { 4465 if (!$(this).is(":checked")) { 4466 gateway = $(this).val(); 4467 var paymentId = this.id; 4468 var labelImg = Drupal.settings.fundraiser[gateway].unselected_image; 4469 $('label[for='+paymentId+'] img').attr('src', labelImg); 4470 } 4471 }); 4472 } 4473 4474 // Change payment method image on hover 4475 function hoverInImage() { 4476 var gateway = $(this).attr('data-gateway'); 4477 var paymentId = this.id; 4478 var labelImg = Drupal.settings.fundraiser[gateway].selected_image; 4479 $(this).attr('src', labelImg); 4480 } 4481 4482 // Change payment method image after hover to selected default. 4483 function hoverOutImage() { 4484 var gateway = $(this).attr('data-gateway'); 4485 var parentLabel = $(this).parent(); 4486 var labelParent = parentLabel.attr('for'); 4487 var checked = $('#' + labelParent).is(':checked'); 4488 if (!checked) { 4489 var labelImg = Drupal.settings.fundraiser[gateway].unselected_image; 4490 $(this).attr('src', labelImg); 4491 } 4492 } 4493 4494 // Call change to payment method images and submit button on page load and selection/hover. 4495 try { 4496 if (Drupal.settings.fundraiser.enabled_count >= 1) { 4497 // Set button text when page first loaded 4498 // Loop over payment method radio fields to find selected 4499 var paymentMethods = $('input[class*="fundraiser-payment-methods"]'); 4500 var paymentMethodSelected; 4501 for(var i = 0; i < paymentMethods.length; i++){ 4502 if(paymentMethods[i].checked){ 4503 paymentMethodSelected = paymentMethods[i]; 4504 } 4505 } 4506 if (paymentMethodSelected == undefined) { 4507 paymentMethodSelected = paymentMethods[0]; 4508 } 4509 // Call our button/image change function with checked payment method on load. 4510 paymentImages.call(paymentMethodSelected); 4511 4512 // Change payment option image based on payment selection and hover. 4513 $('input[class*="fundraiser-payment-methods"]').change(paymentImages); 4514 } 4515 } catch (e) { 4516 console.log(e); 4517 } 4518 // Show payment option "selected" images when rolling over. 4519 $('img[id*="payment-option-img"]').hover(hoverInImage, hoverOutImage); 4520 4521 })(jQuery); } 4522}; 4523;
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.