1/** 2 * Toweringmedia Social Login â Google Identity Services (Hyvä storefront) 3 * 4 * CSP-safe external script: no inline JS, jQuery, RequireJS, or eval. 5 * Loads https://accounts.google.com/gsi/client once via a shared Promise. 6 * Initializes every [data-tm-google-gis] wrapper on the page. 7 * 8 * Login/register use a Wayfair visual pill with a near-invisible GIS renderButton 9 * hitbox overlay. Account-link wrappers without the overlay still render GIS 10 * into [data-tm-google-gis-button] directly. 11 */ 12(function () { 13 'use strict'; 14 15 var googleGisPromise = null; 16 var INIT_ATTR = 'data-tm-google-gis-initialized'; 17 var OVERLAY_STYLE_ID = 'tm-google-gis-overlay-style'; 18 19 /** 20 * Inject Wayfair GIS overlay rules so opacity/hitbox work without a theme CSS rebuild. 21 */ 22 function ensureOverlayStyles() { 23 if (document.getElementById(OVERLAY_STYLE_ID)) { 24 return; 25 } 26 27 var style = document.createElement('style'); 28 style.id = OVERLAY_STYLE_ID; 29 style.textContent = [ 30 '.tm-google-gis-wrapper{position:relative!important;overflow:hidden!important;cursor:pointer!important;}', 31 '.tm-google-gis-hitbox{position:absolute!important;inset:0!important;z-index:2!important;opacity:0.01!important;overflow:hidden!important;}', 32 '.tm-google-gis-hitbox>div{position:absolute!important;inset:0!important;width:100%!important;height:100%!important;}', 33 '.tm-google-gis-hitbox iframe{width:100%!important;min-width:100%!important;height:100%!important;min-height:100%!important;border:0!important;}' 34 ].join(''); 35 document.head.appendChild(style); 36 } 37 38 /** 39 * @returns {Promise<void>} 40 */ 41 function loadGoogleGis() { 42 if (window.google && window.google.accounts && window.google.accounts.id) { 43 return Promise.resolve(); 44 } 45 46 if (googleGisPromise) { 47 return googleGisPromise; 48 } 49 50 googleGisPromise = new Promise(function (resolve, reject) { 51 var script = document.createElement('script'); 52 script.src = 'https://accounts.google.com/gsi/client'; 53 script.async = true; 54 script.defer = true; 55 script.onload = function () { 56 resolve(); 57 }; 58 script.onerror = function () { 59 reject(new Error('Failed to load Google GIS client')); 60 }; 61 document.head.appendChild(script); 62 }); 63 64 return googleGisPromise; 65 } 66 67 /** 68 * @returns {string} 69 */ 70 function getFormKey() { 71 var meta = document.querySelector('meta[name="form_key"]'); 72 73 if (meta && meta.getAttribute('content')) { 74 return meta.getAttribute('content'); 75 } 76 77 if (window.hyva && typeof window.hyva.getFormKey === 'function') { 78 try { 79 return window.hyva.getFormKey() || ''; 80 } catch (e) { 81 return ''; 82 } 83 } 84 85 return ''; 86 } 87 88 /** 89 * @param {HTMLFormElement} form 90 * @param {string} name 91 * @param {string} value 92 */ 93 function appendHiddenInput(form, name, value) { 94 if (value === null || value === undefined || value === '') { 95 return; 96 } 97 98 var input = document.createElement('input'); 99 input.type = 'hidden'; 100 input.name = name; 101 input.value = value; 102 form.appendChild(input); 103 } 104 105 /** 106 * @param {HTMLElement} wrapper 107 * @param {{ credential?: string }} response 108 */ 109 function submitCredential(wrapper, response) { 110 if (!response || !response.credential) { 111 return; 112 } 113 114 var callbackUrl = wrapper.dataset.callbackUrl; 115 if (!callbackUrl) { 116 return; 117 } 118 119 var form = document.createElement('form'); 120 form.method = 'POST'; 121 form.action = callbackUrl; 122 123 appendHiddenInput(form, 'provider', 'google'); 124 appendHiddenInput(form, 'credential', response.credential); 125 126 if (wrapper.dataset.returnUrl) { 127 appendHiddenInput(form, 'return_url', wrapper.dataset.returnUrl); 128 } 129 130 if (wrapper.dataset.mode === 'link') { 131 appendHiddenInput(form, 'link_mode', '1'); 132 } 133 134 appendHiddenInput(form, 'form_key', getFormKey()); 135 136 document.body.appendChild(form); 137 form.submit(); 138 } 139 140 /** 141 * @param {HTMLElement} wrapper 142 * @param {HTMLElement} buttonContainer 143 */ 144 function renderOverlayButton(wrapper, buttonContainer) { 145 var width = Math.floor(wrapper.getBoundingClientRect().width); 146 if (!width || width < 120) { 147 var configured = parseInt(wrapper.dataset.buttonWidth, 10); 148 width = !Number.isNaN(configured) && configured > 0 ? configured : 320; 149 } 150 151 buttonContainer.replaceChildren(); 152 window.google.accounts.id.renderButton(buttonContainer, { 153 type: 'standard', 154 theme: 'outline', 155 size: 'large', 156 shape: 'pill', 157 text: 'continue_with', 158 logo_alignment: 'left', 159 width: width 160 }); 161 } 162 163 /** 164 * @param {HTMLElement} wrapper 165 */ 166 function initWrapper(wrapper) { 167 if (wrapper.getAttribute(INIT_ATTR) === '1') { 168 return; 169 } 170 171 var clientId = wrapper.dataset.clientId; 172 if (!clientId) { 173 return; 174 } 175 176 wrapper.setAttribute(INIT_ATTR, '1'); 177 178 loadGoogleGis().then(function () { 179 if (!window.google || !window.google.accounts || !window.google.accounts.id) { 180 return; 181 } 182 183 var buttonContainer = wrapper.querySelector('[data-tm-google-gis-button]'); 184 if (!buttonContainer) { 185 return; 186 } 187 188 window.google.accounts.id.initialize({ 189 client_id: clientId, 190 use_fedcm_for_prompt: wrapper.dataset.useFedcm === 'true', 191 callback: function (response) { 192 submitCredential(wrapper, response); 193 } 194 }); 195 196 var usesOverlay = !!wrapper.querySelector('.tm-google-gis-visual'); 197 198 if (usesOverlay) { 199 ensureOverlayStyles(); 200 renderOverlayButton(wrapper, buttonContainer); 201 202 if (typeof ResizeObserver === 'function') { 203 var resizeTimer = null; 204 var observer = new ResizeObserver(function () { 205 window.clearTimeout(resizeTimer); 206 resizeTimer = window.setTimeout(function () { 207 renderOverlayButton(wrapper, buttonContainer); 208 }, 100); 209 }); 210 observer.observe(wrapper); 211 } 212 } else { 213 var buttonWidth = parseInt(wrapper.dataset.buttonWidth, 10); 214 if (Number.isNaN(buttonWidth) || buttonWidth <= 0) { 215 buttonWidth = 220; 216 } 217 218 window.google.accounts.id.renderButton(buttonContainer, { 219 type: 'standard', 220 theme: 'outline', 221 size: 'large', 222 text: wrapper.dataset.mode === 'link' ? 'continue_with' : 'signin_with', 223 width: buttonWidth 224 }); 225 } 226 227 if (wrapper.dataset.oneTap === 'true') { 228 window.google.accounts.id.prompt(); 229 } 230 }).catch(function () { 231 // Fail silently; Facebook/Apple links and OAuth fallbacks remain available. 232 }); 233 } 234 235 function initAll() { 236 var wrappers = document.querySelectorAll('[data-tm-google-gis]'); 237 if (!wrappers.length) { 238 return; 239 } 240 241 var i; 242 for (i = 0; i < wrappers.length; i++) { 243 initWrapper(wrappers[i]); 244 } 245 } 246 247 if (document.readyState === 'loading') { 248 document.addEventListener('DOMContentLoaded', initAll, { once: true }); 249 } else { 250 initAll(); 251 } 252})();
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.