1/** 2 * Frontend functionality for subscribers and tags. 3 * 4 * @since 1.9.6 5 * 6 * @author ConvertKit 7 */ 8 9/** 10 * Remove the url subscriber_id url param 11 * 12 * The 'ck_subscriber_id' should only be set on URLs included on 13 * links from a ConvertKit email with no other URL parameters. 14 * This function removes the parameters so a customer won't share 15 * a URL with their subscriber ID in it. 16 * 17 * @param {string} url URL. 18 */ 19function convertKitRemoveSubscriberIDFromURL(url) { 20 // Parse URL. 21 const url_object = new URL(url); 22 const ck_subscriber_id = url_object.searchParams.get('ck_subscriber_id'); 23 24 // If ck_subscriber_id is null, it's not included in the URL. 25 // Don't modify the URL. 26 if (ck_subscriber_id === null) { 27 return; 28 } 29 30 // Remove ck_subscriber_id from URL params. 31 url_object.searchParams.delete('ck_subscriber_id'); 32 33 // Get title and string of parameters. 34 const title = document.getElementsByTagName('title')[0].innerHTML; 35 let params = url_object.searchParams.toString(); 36 37 // Only add '?' if there are parameters. 38 if (params.length > 0) { 39 params = '?' + params; 40 } 41 42 // Update history. 43 window.history.replaceState( 44 null, 45 title, 46 url_object.pathname + params + url_object.hash 47 ); 48 49 // Emit custom event with the removed subscriber ID. 50 convertKitEmitCustomEvent('kit_subscriber_id_removed_from_url', { 51 id: ck_subscriber_id, 52 }); 53} 54 55/** 56 * Emit a custom event with optional detail data. 57 * 58 * This function creates and dispatches a custom event with the specified 59 * event name and detail data. 60 * 61 * @since 2.5.0 62 * 63 * @param {string} eventName The name of the custom event to emit. 64 * @param {Object} [detail={}] Optional detail data to include with the event. 65 */ 66function convertKitEmitCustomEvent(eventName, detail) { 67 const event = new CustomEvent(eventName, { detail }); 68 document.dispatchEvent(event); 69} 70 71/* eslint-disable no-unused-vars */ 72/** 73 * Handles form submissions when reCAPTCHA is enabled. 74 * 75 * @param {string} token reCAPTCHA token. 76 */ 77function convertKitRecaptchaFormSubmit(token) { 78 // Find submit button with the data-callback attribute. 79 const submitButton = document.querySelector( 80 '[type="submit"][data-callback="convertKitRecaptchaFormSubmit"]' 81 ); 82 83 // Get the parent form of the submit button. 84 const form = submitButton.closest('form'); 85 86 // Submit the form, using requestSubmit() so any submit event listeners are honored 87 // e.g. the Member Content login form, which submits using AJAX. 88 form.requestSubmit(); 89} 90 91// Scope the function to the window object as webpack will wrap everything in a closure, 92// resulting in the function not being available globally. 93window.convertKitRecaptchaFormSubmit = convertKitRecaptchaFormSubmit; 94 95/** 96 * Handles form submissions when Cloudflare Turnstile is enabled. 97 * 98 * Turnstile auto-populates a hidden `cf-turnstile-response` input inside the 99 * enclosing form once the challenge is solved, so we just need to submit the 100 * containing form when the callback fires. 101 * 102 * @param {string} token Turnstile response token. 103 */ 104function convertKitTurnstileFormSubmit(token) { 105 // Find the Turnstile widget div with the data-callback attribute. 106 const widget = document.querySelector( 107 '.cf-turnstile[data-callback="convertKitTurnstileFormSubmit"]' 108 ); 109 110 if (!widget) { 111 return; 112 } 113 114 // Get the parent form of the widget. 115 const form = widget.closest('form'); 116 117 if (!form) { 118 return; 119 } 120 121 // Submit the form, using requestSubmit() so any submit event listeners are honored 122 // e.g. the Member Content login form, which submits using AJAX. 123 form.requestSubmit(); 124} 125 126// Scope the function to the window object as webpack will wrap everything in a closure, 127// resulting in the function not being available globally. 128window.convertKitTurnstileFormSubmit = convertKitTurnstileFormSubmit; 129/* eslint-enable no-unused-vars */ 130 131/** 132 * Register events on frontend. 133 * 134 * @since 3.2.0 135 */ 136if (typeof convertkit !== 'undefined') { 137 document.addEventListener('DOMContentLoaded', function () { 138 // Removes `ck_subscriber_id` from the URI. 139 convertKitRemoveSubscriberIDFromURL(window.location.href); 140 141 // Set a cookie if any scripts with data-kit-limit-per-session attribute exist. 142 if ( 143 document.querySelectorAll('script[data-kit-limit-per-session="1"]') 144 .length > 0 145 ) { 146 document.cookie = 'ck_non_inline_form_displayed=1; path=/'; 147 if (convertkit.debug) { 148 console.log( 149 'Set `ck_non_inline_form_displayed` cookie for non-inline form limit' 150 ); 151 } 152 } 153 }); 154}
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.