1 2(function ($) { 3 var bs; 4 var recaptchaIsMounted = false; 5 6 if (typeof Drupal.ajax !== 'undefined') { 7 bs = Drupal.ajax.prototype.beforeSerialize 8 Drupal.ajax.prototype.beforeSerialize = function (element, options) { 9 bs.call(this, element, options); 10 $('.bt-leads-fragment', element).val(window.location.hash); 11 } 12 } 13 14 btLeadsRecaptchaCallback = function (context) { 15 $('.bt-leads-recaptcha', context).once('btLeadsRecaptchaCallback', function () { 16 var form = $(this).parents('form'), 17 recap = this, 18 ajaxSubmitHandler, 19 formSubmit = $(this).siblings('button[type="submit"], input[type="submit"]'), 20 placement = $(this).attr('data-size'), 21 isAjaxForm = Drupal.settings.ajax ? Drupal.settings.ajax[formSubmit.attr('id')] : undefined; 22 23 if(!window.grecaptcha) { 24 console.warn("g-recaptcha was not loaded. This means recaptcha won't work on the current page."); 25 return; 26 } 27 28 rcid = grecaptcha.render(recap, { 29 sitekey: $(recap).attr('data-sitekey'), 30 callback: function(token) { 31 $(form).addClass('bt-leads-recaptcha-submitted'); 32 $('.bt-leads-grecaptcha-response', $(form)).val(token); 33 if(isAjaxForm) { 34 formSubmit.on('mousedown', ajaxSubmitHandler); 35 } 36 if(placement === 'invisible') { 37 !isAjaxForm ? formSubmit.click() : formSubmit.mousedown(); 38 39 if(isAjaxForm) { 40 grecaptcha.reset(form.attr('bt-leads-recaptcha-rcid')); 41 } 42 } 43 44 if(token) { 45 console.info("Form submission successful after valid token response."); 46 } 47 else { 48 console.error("Form submission failed after returning an empty token response."); 49 } 50 } 51 }); 52 53 form.attr('bt-leads-recaptcha-rcid', rcid); 54 55 if(isAjaxForm) { 56 ajaxSubmitHandler = $._data(formSubmit.get(0), 'events')['mousedown'][0].handler; 57 formSubmit.unbind('mousedown'); 58 formSubmit.on('click', function(e) { 59 if(!$(form).hasClass('bt-leads-recaptcha-submitted')) { 60 e.preventDefault(); 61 62 grecaptcha.execute(form.attr('bt-leads-recaptcha-rcid')); 63 } 64 }); 65 66 $(form).ajaxComplete(function (event, xhr, settings) { 67 if (event.currentTarget.id == $(form).attr('id')) { 68 if ($('.g-recaptcha-response', recap).val() != '') { 69 $(form).removeClass('bt-leads-recaptcha-submitted'); 70 } 71 } 72 }); 73 } 74 else { 75 formSubmit.on('click', function(e) { 76 if(!$(form).hasClass('bt-leads-recaptcha-submitted')) { 77 e.preventDefault(); 78 grecaptcha.execute(form.attr('bt-leads-recaptcha-rcid')); 79 } 80 }); 81 } 82 }); 83 } 84 85 // Prevent accidental submits by users pressing the enter key whilst focused on form 86 // elements. For whatever reason validation is skipped in these circumstances. This 87 // ensures the form will only be submitted by clicking the button. 88 Drupal.behaviors.btLeadsPreventAccidentalSubmit = { 89 attach: function (context, settings) { 90 var $form = $('form.bt-leads-share-url-form'); 91 if ($form.length) { 92 // Restrict to input elements so new lines can be inserted into the textarea. 93 $form.on('keydown', 'input', function (e) { 94 if (e.keyCode === 13) { 95 e.preventDefault(); 96 e.stopPropagation(); 97 return false; 98 } 99 }) 100 } 101 } 102 } 103 104 // Appends hashes to share URLs. 105 Drupal.behaviors.btLeadsAddShareHashArgs = { 106 attach: function (context, settings) { 107 var $form = $('form.bt-leads-share-url-form'); 108 $form.find('#edit-social').find('a').each(function () { 109 var $t = $(this); 110 111 if (!$t.hasClass('btleads-processed')) { 112 var href = $t.attr('href'), 113 query = $t.attr('data-share-query'), 114 shareUrl = encodeURIComponent($t.attr('data-share-url')); 115 116 if (window.location.hash) { 117 shareUrl += encodeURIComponent(window.location.hash) 118 } 119 120 if (href.indexOf('?') === -1) { 121 href += '?'; 122 } else { 123 href += '&'; 124 } 125 href += query + '=' + shareUrl; 126 127 $t.attr('href', href).addClass('btleads-processed'); 128 } 129 }); 130 } 131 } 132 133 // Appends hashes to share URLs. 134 Drupal.behaviors.btLeadsOptInRequired = { 135 attach: function (context, settings) { 136 $('.bt-opt-required', context).once('btLeadsOptInRequired', function () { 137 $(this).submit(function() {
138 if(!$('input[name="bt_leads_optin"]:checked', this).length) { 139 alert('Please accept the terms to proceed.'); 140 return false; 141 } else { 142 return true; 143 } 144 }) 145 }) 146 } 147 } 148 149 function mountRecaptcha() { 150 const existingRecaptchaScript = document.querySelector('#bt-leads-recaptcha-async-load'); 151 if (existingRecaptchaScript) { 152 return; 153 } 154 155 if (!Drupal.settings.bt_leads_recaptcha || !Drupal.settings.bt_leads_recaptcha.should_load) { 156 return; 157 } 158 159 const recaptchaScript = document.createElement('script'); 160 const recaptchaUrl = "https://www.google.com/recaptcha/api.js?onload=btLeadsRecaptchaCallback&render=explicit"; 161 recaptchaScript.setAttribute('id', 'bt-leads-recaptcha-async-load'); 162 recaptchaScript.setAttribute('src', recaptchaUrl); 163 recaptchaScript.setAttribute('defer', 1); 164 recaptchaScript.setAttribute('async', 1); 165 document.head.appendChild(recaptchaScript); 166 167 const newlyMountedRecaptcha = document.querySelector('#bt-leads-recaptcha-async-load'); 168 if(newlyMountedRecaptcha) { 169 console.info("Successfully added Google\'s ReCaptcha library."); 170 recaptchaIsMounted = true; 171 } 172 else { 173 console.error("Something went wrong when mounting Google\'s ReCaptcha library to the page."); 174 } 175 } 176 177 // Helper function to determine if an element is within the client's viewport. 178 function isInViewport(element) { 179 var rect = element.getBoundingClientRect(); 180 return ( 181 rect.top >= 0 && 182 rect.left >= 0 && 183 rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && 184 rect.right <= (window.innerWidth || document.documentElement.clientWidth) 185 ); 186 } 187 188 189 btLeadsRecaptchaLoader = function(context, shouldLoad = false) { 190 var elements = $('.load-async-recaptcha'), 191 isVisible = false; 192 193 if(shouldLoad) { 194 mountRecaptcha(); 195 } 196 else { 197 // Load ReCaptcha if we scroll a controlled from into view. 198 document.addEventListener('scroll', function() { 199 elements.each(function(index, element) { 200 isVisible = isInViewport(element); 201 }); 202 if(isVisible) { 203 mountRecaptcha(); 204 } 205 }); 206 207 // Load ReCaptcha if, on page load, a controlled form is in the viewport. 208 window.onload = function(event) { 209 elements.each(function(index, element) { 210 isVisible = isInViewport(element); 211 }); 212 if(isVisible) { 213 mountRecaptcha(); 214 } 215 }; 216 217 // And, as a fallback, make sure recaptcha is mounted on a form interaction, if not already. 218 $('.load-async-recaptcha :input', context).on('focus', function () { 219 mountRecaptcha(); 220 }); 221 } 222 } 223 224 // Loads reCaptcha when a user starts to interact with a non-blacklisted form element. 225 Drupal.behaviors.btLeadsAsyncLoadRecaptcha = { 226 attach: function (context, settings) { 227 btLeadsRecaptchaLoader(context); 228 } 229 } 230})(jQuery)
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.