PageSourceSearch

https://www.arnoldcr.org/wp-content/plugins/give-recurring/assets/js/give-recurring_ver-1.15.0.js

js arnoldcr.org collected 2026-10-04 17:17:08 UTC 18,459 bytes, 570 lines download raw bytes

1/* globals Give*/
2/**
3 * Give Frontend Recurring JS
4 *
5 * Scripts function in frontend form.
6 */
7var Give_Recurring_Vars;
8
9jQuery( document ).ready( function( $ ) {
10
11	var doc = $( document );
12
13	var Give_Recurring = {
14
15		/**
16		 * Initialize
17		 */
18		init: function() {
19			/**
20			 * Call notifyUserOnLevels.
21			 */
22			doc.on( 'give_donation_value_updated', function( e, parent_form, amount ) {
23
24				// If event is called when field blurred.
25				if ( ! parent_form ) {
26					parent_form = $( this ).closest( 'form.give-form' ); // If parent form is empty, assign the current form object.
27				}
28
29					var give_total = ('undefined' === typeof amount) ? parent_form.find( 'input[name="give-amount"]' ).val() : amount,
30						price_id  = parent_form.find('input[name="give-price-id"]').val(),
31						give_is_donation_recurring = parent_form.find('input[name="_give_is_donation_recurring"]').data('_give_recurring'),
32						give_is_price_option = parent_form.find('input[name="_give_is_donation_recurring"]').data('_give_price_option');
33
34				// Return if donation recurring type is Donor choice.
35				if( 'yes_donor' === give_is_donation_recurring || 'set' === give_is_price_option ) {
36					return false;
37				}
38
39				Give_Recurring.notifyUserOnLevels( parent_form, give_total, price_id );
40
41			} );
42
43			/**
44			 * Call notify user on gateway change.
45			 */
46			doc.on( 'give_gateway_loaded', function( e, response, form_id ) {
47
48				var form = $( e.currentTarget.activeElement ).closest( 'form.give-form' );
49				if ( 0 === form.length ) {
50					form = $( '#' + form_id );
51				}
52
53				var amount = form.find( 'input[name="give-amount"]' ).val(),
54					price_id = form.find( 'input[name="give-price-id"]' ).val(),
55					give_is_donation_recurring = form.find( 'input[name="_give_is_donation_recurring"]' ).data( '_give_recurring' ),
56					give_is_price_option = form.find('input[name="_give_is_donation_recurring"]').data('_give_price_option');
57
58				// Return if donation recurring type is Donor choice.
59				if ( 'yes_donor' === give_is_donation_recurring || 'set' === give_is_price_option ) {
60					var recurring_period_label = form.find( '.give-recurring-period' );
61					Give_Recurring.fetchRecurringPeriodText( recurring_period_label );
62					return false;
63				}
64
65				var decimal = Give.form.fn.getInfo( 'decimal_separator', form );
66				amount = Give.fn.unFormatCurrency( amount, decimal );
67
68				Give_Recurring.notifyUserOnLevels( form, amount, price_id );
69			} );
70
71			Give_Recurring.confirm_subscription_cancellation();
72			Give_Recurring.conditional_account_creation();
73
74			$( '.give-recurring-period' ).on( 'click', function() {
75				var $this = $( this ),
76					form = $this.closest( 'form.give-form' );
77
78				if ( $this.is( ':checked' ) ) {
79					Give_Recurring.fetchRecurringPeriodText( $this );
80				} else {
81					form.find( '#give-recurring-modal-period-wrap' ).hide();
82					form.find( '#give-recurring-modal-period' ).html( '' );
83				}
84			} );
85
86			$( '.give-recurring-donors-choice-period' ).on( 'change', function() {
87
88				Give_Recurring.fetchRecurringPeriodText( $( this ) );
89			});
90
91			// Trigger formatting function when gateway changes.
92			doc.on( 'give_gateway_loaded', this.conditionalPeriodDropdown );
93			doc.on( 'blur', '.give-donation-amount .give-recurring-text-input', this.edit_renewal_amount );
94
95			Give_Recurring.conditionalPeriodDropdown();
96			Give_Recurring.changeGiveIsDonationRecurring();
97			Give_Recurring.update_payment_method();
98		},
99
100		/**
101		 * Display Recurring Period Label in Modal PopUp.
102		 *
103		 * @param label Period Label.
104		 * @param form Form.
105		 *
106		 * @since 1.5.8
107		 */
108		displayModalLabel: function( label, form ) {
109			if ( label !== "once" && label !== "" ) {
110				form.find( '#give-recurring-modal-period-wrap' ).show();
111				form.find( '#give-recurring-modal-period' ).html( label.charAt(0).toUpperCase() + label.slice(1) );
112			} else if ( label === "once" ) {
113				form.find( '#give-recurring-modal-period-wrap' ).hide();
114				form.find( '#give-recurring-modal-period' ).html( '' );
115			}
116		},
117
118		/**
119		 * Fetch Recurring Period Text
120		 *
121		 * @param $this this object.
122		 *
123		 * @since 1.5.8
124		 */
125		fetchRecurringPeriodText: function( $this ) {
126
127			var recurringPeriod = $this.data( 'period' );
128			var recurringPeriodLabel = $this.data( 'period-label' );
129			var form = $this.closest( 'form.give-form' );
130			var currentRecurringPeriod = form.find( '.give-recurring-donors-choice-period' ).val();
131			var prettyPeriods = Give_Recurring_Vars.pretty_periods;
132
133			if ( $this.is( 'select' ) ) {
134				recurringPeriodLabel = $this.closest( 'div.give-recurring-donors-choice' )
135					.find( '.give-recurring-period' )
136					.data( 'period-label' );
137				recurringPeriod = $this.closest( 'div.give-recurring-donors-choice' )
138					.find( '.give-recurring-period' )
139					.data( 'period' );
140			}
141
142			// Replace texts in label onlt if donor can change the recurring period.
143			if ( currentRecurringPeriod ) {
144				recurringPeriodLabel = recurringPeriodLabel.replace( new RegExp( recurringPeriod, 'g' ), currentRecurringPeriod );
145				recurringPeriodLabel = recurringPeriodLabel.replace( new RegExp( prettyPeriods[ recurringPeriod ], 'g' ), prettyPeriods[ currentRecurringPeriod ] );
146			}
147
148			// Display Recurring Label if recurring is opted.
149			if ( this.isRecurringOpted(form) ) {
150				Give_Recurring.displayModalLabel( recurringPeriodLabel, form );
151			} else {
152				form.find( '#give-recurring-modal-period-wrap' ).hide();
153				form.find( '#give-recurring-modal-period' ).html( '' );
154			}
155		},
156
157		/**
158		 * Notify users with message about the type of donation based on level.
159		 *
160		 * @since 1.4
161		 * @since 1.8.1 Remove Ajax and Update message through JS.
162		 */
163		notifyUserOnLevels: function( form, amount, price_id ) {
164
165			var data = JSON.parse( form.find( 'input[name="give_recurring_donation_details"]' ).val() );
166
167			// Return if form is not recurring or recurring option is donor choice.
168			if ( false === data.is_recurring || 'yes_donor' === data.give_recurring_option ) {
169				return false;
170			}
171
172			var multi_level_message = data.multi[ price_id ].give_recurring_pretty_text,
173				multi_level_lower_message = multi_level_message.toLowerCase();
174
175			amount = Give.fn.formatCurrency( amount, {
176				currency: Give.form.fn.getInfo( 'currency_code', form ),
177				symbol: Give.form.fn.getInfo( 'currency_symbol', form ),
178				position: Give.form.fn.getInfo( 'currency_position', form )
179			}, form );
180
181			var multi_level_message_html = Give_Recurring_Vars.multi_level_message_pre_text + ' <span class="amount">' + amount + '</span> ' + multi_level_lower_message + '.';
182
183			form.find( '.give-recurring-multi-level-message' ).html( multi_level_message_html );
184
185			// Update recurring hidden field with the change based on the type of donation.
186			if ( 'once' !== multi_level_lower_message ) {
187				form.find( '#_give_is_donation_recurring' ).val( 1 );
188			} else {
189				form.find( '#_give_is_donation_recurring' ).val( 0 );
190			}
191
192			// Display Modal Label when recurring is enabled.
193			Give_Recurring.displayModalLabel( multi_level_message, form );
194			Give_Recurring.register_checkbox( form );
195
196		},
197
198		changeGiveIsDonationRecurring: function () {
199			$( '.give-form' ).on( 'change', '.give-recurring-donors-choice', function () {
200				var give_is_donation_recurring = '0';
201				var recurring_period = $( this ).find( '.give-recurring-period:checked' ).val();
202
203				if ( 'undefined' !== typeof(
204						recurring_period
205					) && 'on' === recurring_period ) {
206					give_is_donation_recurring = 1;
207				}
208
209				var form = $( this ).closest( 'form' );
210				form.find( '._give_is_donation_recurring' ).val( give_is_donation_recurring );
211				Give_Recurring.register_checkbox( form );
212			} );
213		},
214
215		/**
216		 * Toggle account creation fields if donor elects not to give recurring.
217		 *
218		 * If email access is not enabled, no guest donations are allowed.
219		 * Therefore, if the donor doesn't give recurring no account is necessary.
220		 */
221		conditional_account_creation: function() {
222
223			// Only w/o Email Access Enabled
224			if ( Give_Recurring_Vars.email_access ) {
225				return false;
226			}
227
228			// fire once donation form gateway is change.
229			doc.on( 'give_gateway_loaded', function( ev, response, form_id ) {
230				// Trigger float-labels
231				Give_Recurring.register_checkbox( $( 'form#' + form_id ) );
232			} );
233
234			// On Page Load: When page loads loop through each form and show hide fields.
235			$( 'form[id^=give-form].give-recurring-form' ).each( function () {
236				Give_Recurring.register_checkbox( $( this ) );
237			} );
238
239			// Preserve Create account checkbox checked on login cancel ajax.
240			$( document ).ajaxComplete( function ( event, xhr, settings ) {
241				var get_action = Give_Recurring.get_parameter( 'action', settings.data );
242				if ( 'give_cancel_login' === get_action ) {
243					var form_id = Give_Recurring.get_parameter( 'form_id', settings.data );
244					Give_Recurring.register_checkbox( $( 'form#give-form-' + form_id ) );
245				}
246			} );
247		},
248
249		/**
250		 * Get specific parameter value from Query string.
251		 *
252		 * @param string parameter Parameter of query string.
253		 * @param object data Set of data.
254		 *
255		 * @return bool
256		 */
257		get_parameter: function ( parameter, data ) {
258
259			if ( ! parameter ) {
260				return false;
261			}
262
263			if ( ! data ) {
264				data = window.location.href;
265			}
266
267			var parameter = parameter.replace( /[\[]/, "\\\[" ).replace( /[\]]/, "\\\]" );
268			var expr = parameter + "=([^&#]*)";
269			var regex = new RegExp( expr );
270			var results = regex.exec( data );
271
272			if ( null !== results ) {
273				return results[1];
274			} else {
275				return false;
276			}
277		},
278
279		/**
280		 * Disable Enable the register user checkbox
281		 *
282		 * @since 1.5.5
283		 *
284		 * @param form
285		 */
286		register_checkbox: function( form ) {
287
288			// Only w/o Email Access Enabled
289			if ( Give_Recurring_Vars.email_access ) {
290				return false;
291			}
292
293			// check if guest donation is allow or not.
294			var recurring_logged = form.find( '.give-logged-in-only' ).val();
295
296			// if guest donation is not allow then return false.
297			if ( 'undefined' !== typeof( recurring_logged ) && 1 === parseInt( recurring_logged ) ) {
298				var is_recurring = form.find( '._give_is_donation_recurring' ).val();
299
300				if ( 'undefined' !== typeof( is_recurring ) && 1 === parseInt( is_recurring ) ) {
301					Give_Recurring.disable_register_checkbox( form );
302				} else {
303					Give_Recurring.enable_register_checkbox( form );
304				}
305			}
306		},
307
308		/**
309		 * Remove the Disable checkbox option so that user can check and uncheck if s/he want to register or not
310		 *
311		 * @since 1.5.5
312		 *
313		 * @param form
314		 */
315		enable_register_checkbox: function ( form ) {
316			var create_account_html = form.find( '[name="give_create_account"]' );
317			create_account_html.removeClass( 'give-disabled' );
318			create_account_html.closest( 'span' ).removeClass( 'hint--top hint--bou
318nce' );
319		},
320
321		/**
322		 * Add the Disable checkbox option so that user can not  check and uncheck if s/he want to register or not
323		 *
324		 * @since 1.5.5
325		 *
326		 * @param form
327		 */
328		disable_register_checkbox: function ( form ) {
329			var create_account_html = form.find( '[name="give_create_account"]' );
330			create_account_html.attr( 'checked', true );
331			create_account_html.addClass( 'give-disabled' );
332			create_account_html.closest( 'span' ).addClass( 'hint--top hint--bounce' );
333		},
334
335		/**
336		 * Confirm Cancellation
337		 */
338		confirm_subscription_cancellation: function() {
339
340			$( '.give-cancel-subscription' ).on( 'click touchend', function() {
341				var response = confirm( Give_Recurring_Vars.messages.confirm_cancel );
342				// Cancel form submit if user rejects confirmation.
343				if ( response !== true ) {
344					return false;
345				}
346			} );
347
348		},
349
350		/**
351		 * Conditional "Period" dropdown
352		 *
353		 * Some gateways don't support "daily" frequency.
354		 *
355		 * @since 1.5
356		 */
357		conditionalPeriodDropdown: function( response ) {
358
359			// Loop through selected gateways on page.
360			$( '.give-gateway-option-selected' ).each( function() {
361
362				var $form = $( this ).parents( '.give-form' ),
363					gateway = $( this ).find( 'input' ).val(),
364					period_select = $form.find( '.give-recurring-donors-choice-period' ),
365					period = period_select.val(),
366					day_option = $form.find( '.give-recurring-donors-choice-period option[value="day"]' );
367
368				// Authorize doesn't support daily.
369				if ( 'authorize' === gateway || 'razorpay' === gateway ) {
370
371					// Only proceed if day is selected.
372					if ( 'day' !== period ) {
373						return;
374					}
375
376					// Disable and select next option.
377					day_option.prop( 'disabled', true ).next().prop( 'selected', true );
378
379					// Only show alert when switching gateways and not on page load.
380					if ( 'undefined' !== typeof response ) {
381						alert( Give_Recurring_Vars.messages.daily_forbidden );
382					}
383
384				} else {
385
386					// Ensure that daily option is disabled.
387					day_option.prop( 'disabled', false );
388
389				}
390
391			} );
392
393		},
394
395		/**
396		 * Update Payment method.
397		 *
398		 * @since 1.7
399		 */
400		update_payment_method: function() {
401
402			$( 'form[name="give-recurring-form"]' ).submit( function( e ) {
403				e.preventDefault();
404
405				// this form object.
406				var this_form = $( this ),
407					update_button = this_form.find( '#give-recurring-update-submit' ),
408					loading_animation = this_form.find( 'input[type="submit"].give-submit + .give-loading-animation' ),
409					give_payment_update_form = this_form.get( 0 ),
410					complete_purchase_val = this_form.find( '#give-recurring-update-submit' ).val(),
411					action = $( 'input[name="give_action"]' ).val();
412
413				loading_animation.fadeIn();
414
415				// HTML5 required check validity.
416				if ( typeof give_payment_update_form.checkValidity === 'function' && give_payment_update_form.checkValidity() === false ) {
417
418					// Don't leave any hanging loading animations.
419					loading_animation.fadeOut();
420
421					// Check for Safari (doesn't support HTML5 required).
422					if ( (navigator.userAgent.indexOf( 'Safari' ) !== - 1 && navigator.userAgent.indexOf( 'Chrome' ) === - 1) === false ) {
423						// Not safari: Support HTML5 "required" so skip the rest of this function
424						return;
425					}
426
427				}
428
429				/**
430				 * Stripe payment method will only update if donor will submit form because Stripe JS SDK need to generate payment method then save it on server.
431				 * This code prevent submitting form on ajax if subscription gateway is Stripe.
432				 *
433				 * @see https://github.com/impress-org/give-recurring/issues/998
434				 */
435				if(
436					-1 !== Give.form.fn.getInfo('gateway', this_form ).indexOf('stripe') &&
437					'recurring_update_payment' === action
438				) {
439					return;
440				}
441
442				// Update submit button text.
443				update_button.val( give_global_vars.purchase_loading );
444
445				// Disable the form donation button.
446				update_button.attr( 'disabled', 'disabled' );
447
448				$.ajax( {
449					type: 'POST',
450					url: give_global_vars.ajaxurl,
451					data: this_form.serialize(),
452					success: function( response ) {
453						if ( response.success ) {
454							loading_animation.fadeOut();
455							this_form.find( '.give_errors' ).remove();
456							update_button.val( complete_purchase_val );
457							update_button.prop( 'disabled', false );
458						}
459
460						window.location.href = response.data.url;
461					}
462				} );
463
464			} );
465		},
466
467		/**
468		 * Edit renewal amount.
469		 *
470		 * @since 1.8
471		 */
472		edit_renewal_amount:function( e, $parent_form ) {
473			var parent_form = ('undefined' !== typeof $parent_form) ? $parent_form : $( this ).closest( 'form' ),
474				this_value = $( this ).val(),
475				decimal_separator = Give.form.fn.getInfo( 'decimal_separator', parent_form ),
476				value_min = Give.form.fn.getMinimumAmount( parent_form ),
477				value_max = Give.form.fn.getMaximumAmount( parent_form ),
478				value_now = (this_value === 0 || '' === this_value ) ? value_min : Give.fn.unFormatCurrency( this_value, decimal_separator ),
479				formatted_total = Give.form.fn.formatAmount( value_now, parent_form, {} );
480
481			$( this ).val( formatted_total );
482
483			// Does this number have an accepted min/max value?
484			if ( ! Give_Recurring.isValidRenewalAmount( parent_form ) ) {
485
486				// It doesn't... add invalid class.
487				$( this ).addClass( 'give-invalid-amount' );
488
489				// Disable submit
490				Give.form.fn.disable( parent_form, true );
491				var invalid_minimum_notice = parent_form.find( '.give-invalid-minimum' ),
492					invalid_maximum_notice = parent_form.find( '.give-invalid-maximum' );
493
494				// If no error present, create it, insert, slide down (show).
495				if ( 0 === invalid_minimum_notice.length && value_now < value_min ) {
496					Give.notice.fn.renderNotice( 'bad_minimum', parent_form );
497				} else if( value_now >= value_min ) {
498					invalid_minimum_notice.slideUp( 300, function() { $( this ).remove(); } );
499				}
500
501				// For maximum custom amount error.
502				if ( 0 === invalid_maximum_notice.length && value_now > value_max ) {
503					Give.notice.fn.renderNotice( 'bad_maximum', parent_form );
504				} else if (value_now <= value_max ){
505					invalid_maximum_notice.slideUp( 300, function() { $( this ).remove(); } );
506				}
507
508			} else {
509
510				// Remove error message class from price field.
511				$( this ).removeClass( 'give-invalid-amount' );
512
513				// Minimum amount met - slide up error & remove it from DOM.
514				parent_form.find( '.give-invalid-minimum, .give-invalid-maximum' ).slideUp( 300, function() {
515					$( this ).remove();
516				} );
517
518				// Re-enable submit.
519				Give.form.fn.disable( parent_form, false );
520			}
521
522			// Added this trigger so that we can extend the functionality.
523			doc.trigger( 'give_recurring_donation_amount_updated', [ parent_form, value_now ] );
524		},
525
526		/**
527		 * Is Renewal amount valid?
528		 *
529		 * @since 1.8
530		 *
531		 * @param $form
532		 * @returns {boolean}
533		 */
534		isValidRenewalAmount: function( $form ) {
535			// Return true, if custom amount is not enabled.
536			if ( $form.find( 'input[name="give-form-minimum"]' ).length <= 0 ) {
537				return true;
538			}
539
540			var min_amount = Give.form.fn.getMinimumAmount( $form ),
541				max_amount = Give.form.fn.getMaximumAmount( $form ),
542				amount = Give.form.fn.getAmount( $form );
543
544			// Don't allow zero donation amounts.
545			if ( 0 === amount ) {
546				return false;
547			}
548
549			return (
550				((- 1 < amount) && amount >= min_amount && amount <= max_amount)
551			);
552		},
553
554		/**
555		 * Return whether or not donor opt in for subscription.
556		 *
557		 * @since 1.11.0
558		 *
559		 * @param {object} $form
560		 * @return {boolean}
561		 */
562		isRecurringOpted: function ($form){
563			var $field = $form.find( '.give-recurring-period:checked' );
564			return $field &&  $field.val();
565		}
566	};
567
568	Give_Recurring.init();
569
570} );

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.