1/** 2 * Trigger after DOMLoaded. 3 * Init the auto fill after DOM has been loaded. 4 */ 5 document.addEventListener('DOMContentLoaded', () => { 6 if ( document.querySelector( '.donationWidget' ) ) { 7 8 let autoFill = WPACAutoFill(); 9 10 let params = new URLSearchParams(document.location.search.substring(1)); 11 if (params.get('email_hash') !== null) { 12 autoFill.hash = params.get('email_hash'); 13 } 14 else { 15 autoFill.hash = autoFill.getHashCookie(); 16 } 17 18 19 if ( autoFill.hash ) { 20 let intervalID = window.setInterval( () => { 21 if ( null !== autoFill.raisenowHasLoaded() && autoFill.raisenowHasLoaded() ) { 22 if (rnw.tamaro.instance) { 23 rnw.tamaro.instance.paymentForm.data['wpac_donation_suggestion'] = wpac_prefill.suggestion; 24 } 25 26 autoFill.insertContainer(); 27 autoFill.insertAlert(); 28 autoFill.insertSpin(); 29 autoFill.eventListeners(); 30 clearInterval( intervalID ); 31 } 32 }, 500); 33 } 34 } 35}); 36 37/** 38 * WPACAutoFill object. 39 * 40 * @returns {object} autoFill 41 */ 42function WPACAutoFill() { 43 const autoFill = {} 44 45 autoFill.hash = ""; 46 47 autoFill.personalFields = { 48 'first_name': 'stored_customer_firstname', 49 'last_name': 'stored_customer_lastname', 50 'email': 'stored_customer_email', 51 } 52 53 autoFill.fieldsMapping = { 54 ...autoFill.personalFields, 55 ...wpac_prefill.fields_map, // Fields to be filled set on plugin settings page. See ThemeIntegration/PreFillContact.php for more info. 56 }; 57 58 autoFill.text = { 59 'default': wpac_prefill.i18n.default, 60 'success': wpac_prefill.i18n.success, 61 'failure': wpac_prefill.i18n.failure, 62 }; 63 64 autoFill.wrapper = null; 65 autoFill.container = null; 66 autoFill.alert = null; 67 autoFill.link = null; 68 autoFill.spin = null; 69 70 /** 71 * Insert alert element into DOM. 72 */ 73 autoFill.insertContainer = () => { 74 autoFill.wrapper = document.querySelector('.payment-profile-block .widget-block-content'); 75 autoFill.container = document.createElement('div'); 76 77 autoFill.container.className = 'autofill--container'; 78 autoFill.wrapper.parentNode.insertBefore( autoFill.container, autoFill.wrapper ); 79 } 80 81 /** 82 * Insert alert element into DOM. 83 */ 84 autoFill.insertAlert = () => { 85 autoFill.alert = document.createElement('div'); 86 87 autoFill.alert.innerHTML = autoFill.text.default; 88 autoFill.alert.className = 'alert alert--warning alert--autofill'; 89 autoFill.container.appendChild( autoFill.alert ); 90 } 91 92 /** 93 * Insert spin loader element into DOM. 94 */ 95 autoFill.insertSpin = () => { 96 autoFill.spin = document.createElement('div'); 97 98 autoFill.spin.className = 'spin spin-hidden'; 99 autoFill.alert.after( autoFill.spin ); 100 } 101 102 /** 103 * Update button label to give users a feedback. 104 */ 105 autoFill.updateButtonLabel = ( text ) => { 106 let btn = document.querySelector('.button--autofill'); 107 btn.innerHTML = text; 108 } 109 110 /** 111 * Show Spin 112 */ 113 autoFill.showSpin = () => { 114 autoFill.spin.classList.remove('spin-hidden'); 115 } 116 117 /** 118 * Hide Spin 119 */ 120 autoFill.hideSpin = () => { 121 autoFill.spin.classList.add('spin-hidden'); 122 } 123 124 /** 125 * Change alert text. 126 * 127 * @param {string} textKey 128 */ 129 autoFill.changeAlertText = ( textKey ) => { 130 autoFill.alert.innerHTML = autoFill.text[ textKey ]; 131 } 132 133 /** 134 * Check if RaiseNow form has loaded. 135 * 136 * @returns boolean True if loaded, false if not loaded yet. 137 */ 138 autoFill.raisenowHasLoaded = () => { 139 return document.querySelector('.tamaro-widget .payment-amounts') ? true : false; 140 } 141 142 /** 143 * Bind autoFill.fillForm to button click. 144 */ 145 autoFill.eventListeners = () => { 146 autoFill.link = document.querySelector( '.alert--autofill .alert-link' ); 147 autoFill.link.addEventListener( 'click', autoFill.fetchUserData ); 148 } 149 150 /** 151 * Fill form with user data. 152 * 153 * @param Object Object with the mapping of API returned fields keys and form fields names. 154 */ 155 autoFill.fillForm = ( fields ) => { 156 for (let key in fields) { 157 let field = document.querySelector(`[name="${key}"]`); 158 159 if (!field) continue; 160 161 // Set Tamaro widget wrapper as .input-filled 162 document.querySelector(`.${key}`).classList.remove('input-empty'); 163 document.querySelector(`.${key}`).classList.add('input-filled'); 164 165 // actually change the rnw variable that stores the field data 166 if (rnw.tamaro.instance) { 167 rnw.tamaro.instance.paymentForm.data[key] = fields[key]; 168 rnw.tamaro.instance.paymentForm.data['wpac_form_prefill'] = true; 169 170 } 171 172 // Select 173 if ( field.hasAttribute( 'options' ) ) { 174 autoFill.selectOption( field, key ); 175 continue; 176 } 177
178 // Inputs 179 document.querySelector(`[name="${key}"]`).value = fields[key]; 180 181 // Trigger change 182 let e = new Event('change'); 183 field.dispatchEvent(e); 184 } 185 } 186 187 /** 188 * Set the selected option to key. 189 * @param Object field 190 * @param string key 191 */ 192 autoFill.selectOption = ( field, key ) => { 193 field.options.forEach((option, i) => { 194 if (option.value === key) select.selectedIndex = i; 195 }); 196 } 197 198 /** 199 * Fetch user data trough AJAX and trigger form auto-fill. 200 */ 201 autoFill.fetchUserData = () => { 202 let url = wpac_prefill.ajax_url; 203 204 let params = { 205 method: 'POST', 206 credentials: 'same-origin', 207 headers: { 208 'Content-Type': 'application/x-www-form-urlencoded', 209 'Cache-Control': 'no-cache', 210 }, 211 body: new URLSearchParams({ 212 action: wpac_prefill.action, 213 wpac_nonce: wpac_prefill.nonce, 214 wpac_hash: autoFill.hash 215 }) 216 }; 217 218 autoFill.showSpin(); 219 220 fetch(url, params) 221 .then(function (response) { 222 return response.text(); 223 }) 224 .then(function (data) { 225 let parsed = JSON.parse( data ); 226 let fields = []; 227 228 autoFill.handleErrors( parsed ); 229 230 if ( parsed.status === 'success' ) { 231 autoFill.hideSpin(); 232 autoFill.alert.classList.remove( 'alert--warning' ); 233 autoFill.alert.classList.add( 'alert--success' ); 234 autoFill.changeAlertText('success'); 235 236 Object.keys(parsed.contact).forEach(key => { 237 fields[ autoFill.fieldsMapping[ key ] ] = parsed.contact[ key ]; 238 }); 239 240 autoFill.fillForm( fields ); 241 return; 242 } 243 }).catch(function (error) { 244 window.setTimeout( function() { 245 autoFill.hideSpin(); 246 autoFill.alert.classList.remove( 'alert--warning' ); 247 autoFill.alert.classList.add( 'alert--failure' ); 248 autoFill.changeAlertText('failure'); 249 }, 500 ); 250 }); 251 } 252 253 /** 254 * Handle response errors for valid requests. 255 * 256 * @param {object} response 257 * @returns {object} response 258 */ 259 autoFill.handleErrors = ( response ) => { 260 if ( response === -1 || response === null ) 261 throw 'Oups, the form could not be auto filled.'; 262 return response; 263 } 264 265 /** 266 * Get a cookie. 267 * @returns string Hash if it exists or empty string. 268 */ 269 autoFill.getHashCookie = () => { 270 let name = "wpac-hash="; 271 let decodedCookie = decodeURIComponent(document.cookie); 272 let ca = decodedCookie.split(';'); 273 274 for(var i = 0; i < ca.length; i++) { 275 var c = ca[i]; 276 while (c.charAt(0) == ' ') { 277 c = c.substring(1); 278 } 279 if (c.indexOf(name) == 0) { 280 return c.substring(name.length, c.length); 281 } 282 } 283 return ""; 284 } 285 286 return autoFill; 287} 288
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.