1/** 2 * Frontend functionality for subscribers and tags. 3 * 4 * @since 1.9.6 5 * 6 * @author ConvertKit 7 */ 8 9/** 10 * Gets the subscriber ID for the given email address, storing 11 * it in the `ck_subscriber_id` cookie if it exists. 12 * 13 * Typically called when the user completes a ConvertKit Form 14 * that has either "Auto-confirm new subscribers" or 15 * "Send subscriber to thank you page" enabled (both scenarios 16 * include a ck_subscriber_id). 17 * 18 * @since 1.9.6 19 * 20 * @param {string} emailAddress Email Address 21 */ 22function convertStoreSubscriberEmailAsIDInCookie(emailAddress) { 23 if (convertkit.debug) { 24 console.log('convertStoreSubscriberEmailAsIDInCookie'); 25 console.log(emailAddress); 26 } 27 28 fetch(convertkit.ajaxurl, { 29 method: 'POST', 30 headers: { 31 'Content-Type': 'application/x-www-form-urlencoded', 32 'X-WP-Nonce': convertkit.nonce, 33 }, 34 body: new URLSearchParams({ 35 email: emailAddress, 36 }), 37 }) 38 .then(function (response) { 39 if (convertkit.debug) { 40 console.log(response); 41 } 42 43 return response.json(); 44 }) 45 .then(function (result) { 46 if (convertkit.debug) { 47 console.log(result); 48 } 49 50 // Emit custom event with subscriber ID. 51 convertKitEmitCustomEvent('convertkit_user_subscribed', { 52 id: result.id, 53 email: emailAddress, 54 }); 55 }) 56 .catch(function (error) { 57 if (convertkit.debug) { 58 console.error(error); 59 } 60 }); 61} 62 63/** 64 * Remove the url subscriber_id url param 65 * 66 * The 'ck_subscriber_id' should only be set on URLs included on 67 * links from a ConvertKit email with no other URL parameters. 68 * This function removes the parameters so a customer won't share 69 * a URL with their subscriber ID in it. 70 * 71 * @param {string} url URL. 72 */ 73function convertKitRemoveSubscriberIDFromURL(url) { 74 // Parse URL. 75 const url_object = new URL(url); 76 const ck_subscriber_id = url_object.searchParams.get('ck_subscriber_id'); 77 78 // If ck_subscriber_id is null, it's not included in the URL. 79 // Don't modify the URL. 80 if (ck_subscriber_id === null) { 81 return; 82 } 83 84 // Remove ck_subscriber_id from URL params. 85 url_object.searchParams.delete('ck_subscriber_id'); 86 87 // Get title and string of parameters. 88 const title = document.getElementsByTagName('title')[0].innerHTML; 89 let params = url_object.searchParams.toString(); 90 91 // Only add '?' if there are parameters. 92 if (params.length > 0) { 93 params = '?' + params; 94 } 95 96 // Update history. 97 window.history.replaceState( 98 null, 99 title, 100 url_object.pathname + params + url_object.hash 101 ); 102 103 // Emit custom event with the removed subscriber ID. 104 convertKitEmitCustomEvent('kit_subscriber_id_removed_from_url', { 105 id: ck_subscriber_id, 106 }); 107} 108 109/** 110 * Utility function to pause for the given number of milliseconds 111 * 112 * @since 1.9.6 113 * @param {number} milliseconds Number of milliseconds to pause for. 114 */ 115function convertKitSleep(milliseconds) { 116 const start = new Date().getTime(); 117 for (let i = 0; i < 1e7; i++) { 118 if (new Date().getTime() - start > milliseconds) { 119 break; 120 } 121 } 122} 123 124/** 125 * Emit a custom event with optional detail data. 126 * 127 * This function creates and dispatches a custom event with the specified 128 * event name and detail data. 129 * 130 * @since 2.5.0 131 * 132 * @param {string} eventName The name of the custom event to emit. 133 * @param {Object} [detail={}] Optional detail data to include with the event. 134 */ 135function convertKitEmitCustomEvent(eventName, detail) { 136 const event = new CustomEvent(eventName, { detail }); 137 document.dispatchEvent(event); 138} 139 140/* eslint-disable no-unused-vars */ 141/** 142 * Handles form submissions when reCAPTCHA is enabled. 143 * 144 * @param {string} token reCAPTCHA token. 145 */ 146function convertKitRecaptchaFormSubmit(token) { 147 // Find submit button with the data-callback attribute. 148 const submitButton = document.querySelector( 149 '[type="submit"][data-callback="convertKitRecaptchaFormSubmit"]' 150 ); 151 152 // Get the parent form of the submit button. 153 const form = submitButton.closest('form'); 154 155 // Submit the form. 156 form.submit(); 157} 158 159// Scope the function to the window object as webpack will wrap everything in a closure, 160// resulting in the function not being available globally. 161window.convertKitRecaptchaFormSubmit = convertKitRecaptchaFormSubmit; 162/* eslint-enable no-unused-vars */ 163 164/** 165 * Register events on frontend. 166 * 167 * @since 3.2.0 168 */ 169if (typeof convertkit !== 'undefined') { 170 document.addEventListener('DOMContentLoaded', function () { 171 // Removes `ck_subscriber_id` from the URI. 172 convertKitRemoveSubscriberIDFromURL(window.location.href); 173 174 // Store subscriber ID as a cookie from the email address used when a ConvertKit Form is submitted. 175 document.addEventListener('click', function (e) { 176 // Check if the form submit button was clicked, or the span element was clicked and its parent is the form submit button. 177 if ( 178 !e.target.matches('.formkit-submit') && 179 (!e.target.parentElement || 180 !e.target.parentElement.matches('.formkit-submit')) 181 ) { 182 if (convertkit.debug) { 183 console.log('not a ck form'); 184 } 185 186 return; 187 } 188 189 // Get email address.
190 const emailAddress = document.querySelector( 191 'input[name="email_address"]' 192 ).value; 193 194 // If the email address is empty, don't attempt to get the subscriber ID by email. 195 if (!emailAddress.length) { 196 if (convertkit.debug) { 197 console.log('email empty'); 198 } 199 200 return; 201 } 202 203 // If the email address is invalid, don't attempt to get the subscriber ID by email. 204 const validator = 205 /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 206 if (!validator.test(emailAddress.toLowerCase())) { 207 if (convertkit.debug) { 208 console.log('email not an email address'); 209 } 210 211 return; 212 } 213 214 // Wait a moment before sending the AJAX request. 215 convertKitSleep(2000); 216 convertStoreSubscriberEmailAsIDInCookie(emailAddress); 217 }); 218 219 // Set a cookie if any scripts with data-kit-limit-per-session attribute exist. 220 if ( 221 document.querySelectorAll('script[data-kit-limit-per-session="1"]') 222 .length > 0 223 ) { 224 document.cookie = 'ck_non_inline_form_displayed=1; path=/'; 225 if (convertkit.debug) { 226 console.log( 227 'Set `ck_non_inline_form_displayed` cookie for non-inline form limit' 228 ); 229 } 230 } 231 }); 232}
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.