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