PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.26.1
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.26.1
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / square / js / frontend.js

frontend.js in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.26.1, at square/js/frontend.js

302 lines 8.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 ( function() {
2 if ( ! window.frmSquareVars ) {
3 return;
4 }
5
6 const appId = frmSquareVars.appId;
7 const locationId = frmSquareVars.locationId;
8
9 // Track the state of the Square card element
10 let squareCardElementIsComplete = false;
11 let thisForm = null;
12 let running = 0;
13
14 let cardGlobal;
15
16 const buyerTokens = {};
17
18 // Track the state of each field in the card form
19 const cardFields = {
20 cardNumber: false,
21 expirationDate: false,
22 cvv: false,
23 postalCode: false
24 };
25
26 async function initializeCard( payments ) {
27 const cardElement = document.querySelector( '.frm-card-element' );
28 if ( ! cardElement ) {
29 return;
30 }
31
32 const card = await payments.card();
33 const cardStyle = frmSquareVars.style;
34 await card.attach( '.frm-card-element' );
35
36 card.configure( { style: cardStyle } );
37
38 // Add event listener to track when the card form is valid
39 card.addEventListener( 'focusClassRemoved', e => {
40 const field = e.detail.field;
41 const value = e.detail.currentState.isCompletelyValid;
42 cardFields[ field ] = value;
43
44 // Check if all fields are valid
45 squareCardElementIsComplete = Object.values( cardFields ).every( item => item === true );
46
47 // Update form submit button based on form validity
48 if ( thisForm ) {
49 if ( squareCardElementIsComplete ) {
50 enableSubmit();
51 } else {
52 disableSubmit( thisForm );
53 }
54 }
55 } );
56
57 return card;
58 }
59
60 /**
61 * Enable the submit button for the form.
62 */
63 function enableSubmit() {
64 if ( running > 0 ) {
65 return;
66 }
67
68 thisForm.classList.add( 'frm_loading_form' );
69 frmFrontForm.removeSubmitLoading( jQuery( thisForm ), 'enable', 0 );
70
71 // Trigger custom event for other scripts to hook into
72 const event = new CustomEvent( 'frmSquareLiteEnableSubmit', {
73 detail: { form: thisForm }
74 } );
75 document.dispatchEvent( event );
76 }
77
78 /**
79 * Disable submit button for a target form.
80 *
81 * @param {Element} form
82 * @return {void}
83 */
84 function disableSubmit( form ) {
85 jQuery( form ).find( 'input[type="submit"],input[type="button"],button[type="submit"]' ).not( '.frm_prev_page' ).attr( 'disabled', 'disabled' );
86
87 // Trigger custom event for other scripts to hook into
88 const event = new CustomEvent( 'frmSquareLiteDisableSubmit', {
89 detail: { form: form }
90 } );
91 document.dispatchEvent( event );
92 }
93
94 async function createPayment( event, token, verificationToken ) {
95 const tokenInput = document.createElement( 'input' );
96 tokenInput.type = 'hidden';
97 tokenInput.value = token;
98 tokenInput.setAttribute( 'name', 'square-token' );
99
100 const verificationInput = document.createElement( 'input' );
101 verificationInput.type = 'hidden';
102 verificationInput.value = verificationToken;
103 verificationInput.setAttribute( 'name', 'square-verification-token' );
104
105 // Use the thisForm variable that we set earlier
106 if ( thisForm ) {
107 thisForm.appendChild( tokenInput );
108 thisForm.appendChild( verificationInput );
109
110 if ( typeof frmFrontForm.submitFormManual === 'function' ) {
111 frmFrontForm.submitFormManual( event, thisForm );
112 } else {
113 // Fallback if submitFormManual is not available
114 thisForm.submit();
115 }
116 }
117 }
118
119 async function tokenize( paymentMethod ) {
120 const tokenResult = await paymentMethod.tokenize();
121
122 if ( tokenResult.status === 'OK' ) {
123 return tokenResult.token;
124 }
125
126 let errorMessage = `Tokenization failed with status: ${ tokenResult.status }`;
127 if ( tokenResult.errors ) {
128 errorMessage += ` and errors: ${ JSON.stringify( tokenResult.errors ) }`;
129 }
130
131 throw new Error( errorMessage );
132 }
133
134 // Required in SCA Mandated Regions: Learn more at https://developer.squareup.com/docs/sca-overview
135 async function verifyBuyer( payments, token ) {
136 const formData = new FormData( thisForm );
137 formData.append( 'action', 'frm_verify_buyer' );
138 formData.append( 'nonce', frmSquareVars.nonce );
139
140 // Remove a few fields so form validation does not incorrectly trigger.
141 formData.delete( 'frm_action' );
142 formData.delete( 'form_key' );
143 formData.delete( 'item_key' );
144
145 const response = await fetch( frmSquareVars.ajax, {
146 method: 'POST',
147 body: formData
148 } );
149
150 if ( ! response.ok ) {
151 throw new Error( 'Failed to verify buyer' );
152 }
153
154 const verificationData = await response.json();
155 if ( ! verificationData.success ) {
156 throw new Error( verificationData.data );
157 }
158
159 if ( buyerTokens[ verificationData.data.hash ] ) {
160 // Avoid a second verify buyer request if the verification data has not changed.
161 return buyerTokens[ verificationData.data.hash ];
162 }
163
164 const verificationDetails = verificationData.data.verificationDetails;
165 const verificationResults = await payments.verifyBuyer( token, verificationDetails );
166
167 buyerTokens[ verificationData.data.hash ] = verificationResults.token;
168
169 return verificationResults.token;
170 }
171
172 /**
173 * Display an error message in the payment form.
174 *
175 * @param {string} errorMessage
176 * @return {void}
177 */
178 function displayPaymentFailure( errorMessage ) {
179 if ( ! thisForm ) {
180 return;
181 }
182
183 const statusContainer = thisForm.querySelector( '.frm-card-errors' );
184 if ( statusContainer ) {
185 statusContainer.textContent = errorMessage;
186 }
187 }
188
189 async function squareInit() {
190 // Find the form containing the Square payment element
191 const cardContainer = document.querySelector( '.frm-card-element' );
192 if ( cardContainer ) {
193 thisForm = cardContainer.closest( 'form' );
194 if ( thisForm ) {
195 // Initially disable the submit button until card is valid
196 disableSubmit( thisForm );
197
198 // Add event listener for form submission
199 thisForm.addEventListener( 'submit', function( event ) {
200 event.preventDefault();
201 event.stopPropagation();
202
203 if ( ! squareCardElementIsComplete ) {
204 const statusContainer = thisForm.querySelector( '.frm-card-errors' );
205 if ( statusContainer ) {
206 statusContainer.textContent = 'Please complete all card details before submitting.';
207 }
208 } else {
209 handlePaymentMethodSubmission( event, cardGlobal );
210 }
211
212 return false;
213 } );
214 }
215 }
216
217 let payments;
218 try {
219 // Square requires HTTPS to work.
220 payments = window.Square.payments( appId, locationId );
221 } catch ( e ) {
222 const statusContainer = document.querySelector( '.frm-card-errors' );
223 statusContainer.classList.add( 'missing-credentials', 'frm_error' );
224 statusContainer.style.visibility = 'visible';
225 statusContainer.textContent = e.message;
226 return;
227 }
228
229 let card;
230 try {
231 card = await initializeCard( payments );
232 } catch ( e ) {
233 console.error( 'Initializing Card failed', e );
234 return;
235 }
236
237 cardGlobal = card;
238
239 /**
240 * @param {Object} $form
241 * @return {boolean} false if there are errors.
242 */
243 function validateFormSubmit( $form ) {
244 const errors = frmFrontForm.validateFormSubmit( $form );
245 const keys = Object.keys( errors );
246
247 if ( 1 === keys.length && errors[ keys[ 0 ] ] === '' ) {
248 // Pop the empty error that gets added by invisible recaptcha.
249 keys.pop();
250 }
251
252 return 0 === keys.length;
253 }
254
255 async function handlePaymentMethodSubmission( event, card ) {
256 try {
257 thisForm.classList.add( 'frm_js_validate' );
258
259 if ( ! validateFormSubmit( thisForm ) ) {
260 return;
261 }
262
263 // Increment running counter and disable the submit button
264 running++;
265 if ( thisForm ) {
266 disableSubmit( thisForm );
267 }
268
269 const token = await tokenize( card );
270 const verificationToken = await verifyBuyer( payments, token );
271 await createPayment( event, token, verificationToken );
272
273 // Decrement running counter after successful payment
274 running--;
275 if ( running === 0 && thisForm ) {
276 enableSubmit();
277 }
278 } catch ( e ) {
279 // Decrement running counter and re-enable submit if appropriate
280 running--;
281 if ( running === 0 && thisForm && squareCardElementIsComplete ) {
282 enableSubmit();
283 }
284 displayPaymentFailure( e.message );
285 }
286 }
287 }
288
289 document.addEventListener( 'DOMContentLoaded', async function() {
290 if ( ! window.Square ) {
291 console.error( 'Square.js failed to load properly' );
292 return;
293 }
294
295 squareInit();
296
297 jQuery( document ).on( 'frmPageChanged', function() {
298 squareInit();
299 } );
300 } );
301 }() );
302