1/* Daily Updates floating CTA â loaded on /blog and the 5 hub pages. 2 * 3 * Injects a small bottom-right pill that expands into an inline form on click. 4 * Auto-hides for subscribed readers, dismissed-pill readers, and small viewports 5 * during page-load (lazy reveal after 8s to avoid stealing initial attention). 6 * 7 * Suppression cookies: 8 * premium_email â global "already a subscriber" cookie, set on any 9 * successful Drip identify across the site. 10 * hg_du_floater_off â set when reader clicks dismiss. 14 days. 11 * 12 * ES5 only. No dependencies. Renders shadow-DOM-free so the scoped CSS in 13 * blog-daily-updates-floater-v1.css governs presentation. 14 */ 15(function () { 16 'use strict'; 17 18 var SUBSCRIBED_COOKIE = 'premium_email'; 19 var DISMISS_COOKIE = 'hg_du_floater_off'; 20 var REVEAL_DELAY_MS = 8000; 21 22 function readCookie(name) { 23 var match = (' ' + document.cookie).match(new RegExp('[; ]' + name + '=([^;]+)')); 24 return match ? decodeURIComponent(match[1]) : null; 25 } 26 function setCookie(name, value, days) { 27 var d = new Date(); 28 d.setTime(d.getTime() + days * 86400 * 1000); 29 document.cookie = name + '=' + encodeURIComponent(value) + ';expires=' + d.toUTCString() + ';path=/;SameSite=Lax;Secure'; 30 } 31 function ready(fn) { 32 if (document.readyState !== 'loading') { fn(); return; } 33 document.addEventListener('DOMContentLoaded', fn); 34 } 35 36 ready(function () { 37 if (readCookie(SUBSCRIBED_COOKIE)) return; 38 if (readCookie(DISMISS_COOKIE)) return; 39 if (document.getElementById('hg-du-floater')) return; 40 41 var el = build(); 42 document.body.appendChild(el); 43 44 setTimeout(function () { el.classList.add('is-visible'); }, REVEAL_DELAY_MS); 45 46 el.querySelector('.hg-du-floater-pill').addEventListener('click', function (e) { 47 if (e.target && e.target.closest && e.target.closest('.hg-du-floater-pill-close')) return; 48 el.classList.add('is-expanded'); 49 var input = el.querySelector('input[type="email"]'); 50 if (input) input.focus(); 51 }); 52 53 el.querySelector('.hg-du-floater-pill-close').addEventListener('click', function (e) { 54 e.stopPropagation();
55 dismiss(el); 56 }); 57 el.querySelector('.hg-du-floater-card-close').addEventListener('click', function () { 58 el.classList.remove('is-expanded'); 59 }); 60 61 el.querySelector('.hg-du-floater-submit').addEventListener('click', function () { 62 submit(el); 63 }); 64 el.querySelector('input[type="email"]').addEventListener('keydown', function (e) { 65 if (e.key === 'Enter') { e.preventDefault(); submit(el); } 66 }); 67 }); 68 69 function build() { 70 var el = document.createElement('div'); 71 el.id = 'hg-du-floater'; 72 el.className = 'hg-du-floater'; 73 el.setAttribute('aria-live', 'polite'); 74 el.innerHTML = 75 '<button type="button" class="hg-du-floater-pill" aria-label="Open Hawaii Daily Updates signup">' + 76 '<i class="fa fa-envelope" aria-hidden="true"></i>' + 77 '<span>Daily Updates</span>' + 78 '<button type="button" class="hg-du-floater-pill-close" aria-label="Dismiss">×</button>' + 79 '</button>' + 80 '<div class="hg-du-floater-card" role="dialog" aria-label="Hawaii Daily Updates by Email">' + 81 '<button type="button" class="hg-du-floater-card-close" aria-label="Close">×</button>' + 82 '<h3>Hawaii Daily Updates</h3>' + 83 '<p>One short morning email at 9 AM HST with every new article that day. Free. Unsubscribe anytime.</p>' + 84 '<form class="hg-du-floater-form" onsubmit="return false;">' + 85 '<label for="hg-du-floater-email" class="sr-only">Email address</label>' + 86 '<input type="email" id="hg-du-floater-email" placeholder="Your email address" required />' + 87 '<button type="button" class="hg-du-floater-submit">Subscribe <i class="fa fa-arrow-right" aria-hidden="true"></i></button>' + 88 '</form>' + 89 '<div class="hg-du-floater-success"><i class="fa fa-check-circle" aria-hidden="true"></i> Mahalo! Check your inbox to confirm.</div>' + 90 '</div>'; 91 return el; 92 } 93 94 function dismiss(el) { 95 setCookie(DISMISS_COOKIE, '1', 14); 96 if (el.parentNode) el.parentNode.removeChild(el); 97 } 98 99 function submit(el) { 100 var input = el.querySelector('input[type="email"]'); 101 var btn = el.querySelector('.hg-du-floater-submit'); 102 var success = el.querySelector('.hg-du-floater-success'); 103 var form = el.querySelector('.hg-du-floater-form'); 104 if (!input || !btn || !success || !form) return; 105 var email = input.value.trim(); 106 if (!email || (input.validity && !input.validity.valid)) { input.focus(); return; } 107 var originalLabel = btn.innerHTML; 108 btn.innerHTML = '<i class="fa fa-spinner fa-spin"></i> Submitting...'; 109 btn.disabled = true; 110 111 if (typeof window._dcq !== 'undefined') { 112 window._dcq.push(['identify', { 113 email: email, 114 referral_url: window.location.href, 115 tags: ['Daily Updates', 'Blog Subscriber', 'Floater Signup'], 116 success: function () { 117 form.style.display = 'none'; 118 success.style.display = 'block'; 119 if (typeof window.createHGCookie === 'function') { 120 window.createHGCookie(SUBSCRIBED_COOKIE, email, 365); 121 } 122 if (typeof window.plausible === 'function') { 123 window.plausible('Daily Updates Subscribe', { 124 props: { variant: 'floater', source: window.location.pathname } 125 }); 126 } 127 setTimeout(function () { 128 if (el.parentNode) el.parentNode.removeChild(el); 129 }, 4500); 130 } 131 }]); 132 } else { 133 btn.innerHTML = originalLabel; 134 btn.disabled = false; 135 } 136 } 137})();
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.