PageSourceSearch

https://action.aclu.org/files/aclu/js/js_d_ByE0i5XWDG2ishbvcxuhjVzCvnWAsLW4k0QcbDAyg.js

js aclu.org collected 2026-10-01 06:29:32 UTC 205,520 bytes, 4,523 lines download raw bytes

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">&nbsp;</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 + '&amp;session_id=' + sessionId + '&amp;m=1)"></div>';
2349          template += '<img src="https://' + typeSettings.subdomain + '/fp/clear.png?org_id=' + typeSettings.org_id + '&amp;session_id=' + sessionId + '&amp;m=2" />';
2350          template += '<script src="https://' + typeSettings.subdomain + '/fp/check.js?org_id=' + typeSettings.org_id + '&amp;session_id=' + sessionId + '&amp;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 + '&amp;session_id=' + sessionId + '" width="1" height="1">';
2352          template += '<param name="movie" value="https://' + typeSettings.subdomain + '/fp/fp.swf?org_id=' + typeSettings.org_id + '&amp;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.