1window.overwriteForGtm = (currency, account, userId) => { 2 const SIGNUP_URL = '/authUser/register'; 3 const SIGNIN_URL = '/authUser/login'; 4 const ADD_TO_CART_URL = '/cart/buy'; 5 const ADD_PAYMENT_INFO_URL = '/cart/beforePay'; 6 const ADD_TO_CART_BUTTON_URL = '/cart/add'; 7 const TAG = '__event__tag__'; 8 const timeout = 500; 9 10 const originXHROpen = window.XMLHttpRequest.prototype.open; 11 window.XMLHttpRequest.prototype.open = function open() { 12 this.__url = arguments[1]; 13 if (window.pushGtmDataLayer && this.__url) { 14 if (this.__url.startsWith(SIGNUP_URL)) { 15 this[TAG] = true; 16 const _signup = signup.bind(this, () => this.removeEventListener('load', _signup)); 17 this.addEventListener('load', _signup); 18 } else if (this.__url.startsWith(SIGNIN_URL)) { 19 this[TAG] = true; 20 const _signin = signin.bind(this, () => this.removeEventListener('load', _signin)); 21 this.addEventListener('load', _signin); 22 } else if (this.__url.startsWith(ADD_TO_CART_URL)) { 23 this[TAG] = true; 24 const _addToCart = addToCart.bind(this, () => this.removeEventListener('load', _addToCart)); 25 this.addEventListener('load', _addToCart); 26 } else if (this.__url.startsWith(ADD_TO_CART_BUTTON_URL)) { 27 this[TAG] = true; 28 const _addToCartByButton = addToCartByButton.bind(this, () => this.removeEventListener('load', _addToCartByButton)); 29 this.addEventListener('load', _addToCartByButton); 30 } else if (this.__url.startsWith(ADD_PAYMENT_INFO_URL)) { 31 this[TAG] = true; 32 const _addPaymentInfo = addPaymentInfo.bind(this, () => this.removeEventListener('load', _addPaymentInfo)); 33 this.addEventListener('load', _addPaymentInfo); 34 } 35 } 36 return originXHROpen.apply(this, arguments); 37 }; 38 const originSend = window.XMLHttpRequest.prototype.send; 39 window.XMLHttpRequest.prototype.send = function send(...args) { 40 if (!this[TAG]) { 41 return originSend.apply(this, args); 42 } 43 const xhr = this; 44 const originOnReadyStateChange = xhr.onreadystatechange; 45 const originOnLoad = xhr.onload; 46 function delay(fn) { 47 return function (...params) { 48 setTimeout(() => { 49 fn && fn.apply(xhr, params); 50 }, timeout); 51 } 52 } 53 if (xhr.onreadystatechange) { 54 xhr.onreadystatechange = delay(originOnReadyStateChange); 55 } 56 if (xhr.onload) { 57 xhr.onload = delay(originOnLoad); 58 } 59 return originSend.apply(this, args); 60 }; 61 62 const delay = (time) => { 63 return new Promise((resolve) => { 64 setTimeout(resolve, time); 65 }); 66 }; 67 68 /** 69 * @param {ProgressEvent<XMLHttpRequestEventTarget>} ev 70 * @param {boolean} responseNotNull Whether the response is not null, default is `true` 71 * @return {XMLHttpRequestEventTarget & {__url: string}} 72 */ 73 function parseLoad(ev, responseNotNull = true) { 74 const target = ev.target; 75 const status = target.status; 76 if (status !== 200) { 77 throw new Error('status is not 200'); 78 } 79 if (responseNotNull) { 80 const response = target.response; 81 if (!response) { 82 throw new Error('response is null'); 83 } 84 } 85 return target; 86 } 87 88 /** 89 * @param {string} url 90 * @param {string} name 91 */ 92 function pickQueryString(url, name) { 93 const reg = new RegExp(`^.*[?&]${name}\\=([^=&]+).*$`); 94 const match = url.match(reg) 95 if (match && match[1]) { 96 return match[1]; 97 } 98 return void 0; 99 } 100 101 /** 102 * parse jsonp response 103 * @param {string} jsoncallback 104 * @param {string} response 105 */ 106 function jsonpResult(jsoncallback, response) { 107 const reg = new RegExp(`.*${jsoncallback}\\(([^\\)]+)\\).*$`); 108 const match = response.match(reg); 109 if (match && match[1]) { 110 try { 111 return JSON.parse(match[1]); 112 } catch (error) { 113 return match[1]; 114 } 115 } 116 return void 0; 117 } 118 119 /** 120 * @param {() => void} removeListener 121 * @param {ProgressEvent<XMLHttpRequestEventTarget>} ev 122 */ 123 function signup(removeListener, ev) { 124 removeListener(); 125 try { 126 const target = parseLoad(ev); 127 const url = target.__url; 128 if (!url.startsWith(SIGNUP_URL)) { 129 return; 130 } 131 const response = target.response; 132 const jsoncallback = pickQueryString(url, 'jsoncallback'); 133 if (jsoncallback) { 134 const jsonp = jsonpResult(jsoncallback, response); 135 if (jsonp && jsonp.code == 0) { 136 if (jsonp.user_info) { 137 const userInfo = jsonp.user_info; 138 userId = userInfo.id || ''; 139 account = userInfo.account || ''; 140 const comeFrom = userInfo.come_from || ''; 141 const firstName = userInfo.first_name || ''; 142 const lastName = userInfo.last_name || ''; 143 const email = userInfo.email || ''; 144 const phone = userInfo.phone || ''; 145 const country = userInfo.country || ''; 146 const cnty = userInfo.cnty || ''; 147 pushGtmDataLayer('signup', { userId, account, comeFrom, firstName, lastName, email, phone,
147country, cnty }); 148 } 149 if (jsonp.gtm_add_to_cart) { 150 const receive = jsonp.gtm_add_to_cart; 151 const price = +receive.price || 0; 152 const quantity = +receive.quantity || 1; 153 const productId = receive.productId; 154 pushGtmDataLayer('addToCart', { account, userId, price, currency, quantity, productId }); 155 } 156 } 157 } 158 } catch (error) { 159 // console.error(error); 160 } 161 } 162 163 /** 164 * @param {() => void} removeListener 165 * @param {ProgressEvent<XMLHttpRequestEventTarget>} ev 166 */ 167 function signin(removeListener, ev) { 168 removeListener(); 169 try { 170 const target = parseLoad(ev); 171 const url = target.__url; 172 if (!url.startsWith(SIGNIN_URL)) { 173 return; 174 } 175 const response = target.response; 176 const jsoncallback = pickQueryString(url, 'jsoncallback'); 177 if (jsoncallback) { 178 const jsonp = jsonpResult(jsoncallback, response); 179 if (jsonp && jsonp.code == 0) { 180 if (jsonp.user_info) { 181 const userInfo = jsonp.user_info; 182 userId = userInfo.id || ''; 183 account = userInfo.account || ''; 184 const comeFrom = userInfo.come_from || ''; 185 const email = userInfo.email || ''; 186 const phone = userInfo.phone || ''; 187 const country = userInfo.country || ''; 188 const cnty = userInfo.cnty || ''; 189 pushGtmDataLayer('signin', { userId, account, comeFrom, email, phone, country, cnty }); 190 } 191 if (jsonp.gtm_add_to_cart) { 192 const receive = jsonp.gtm_add_to_cart; 193 const price = +receive.price || 0; 194 const quantity = +receive.quantity || 1; 195 const productId = receive.productId; 196 pushGtmDataLayer('addToCart', { account, userId, price, currency, quantity, productId }); 197 } 198 } 199 } 200 } catch (error) { 201 // console.error(error); 202 } 203 } 204 205 /** 206 * @param {() => void} removeListener 207 * @param {ProgressEvent<XMLHttpRequestEventTarget>} ev 208 */ 209 function addToCart(removeListener, ev) { 210 removeListener(); 211 try { 212 const target = parseLoad(ev); 213 const url = target.__url; 214 if (!url.startsWith(ADD_TO_CART_URL)) { 215 return; 216 } 217 const response = target.response; 218 const data = JSON.parse(response); 219 if (data && data.status === 'success' && data.response) { 220 const receive = data.response; 221 const price = +receive.price || 0; 222 const price_usd = receive.price_usd || 0; 223 const quantity = +receive.quantity || 1; 224 const productId = receive.productId; 225 pushGtmDataLayer('addToCart', { account, userId, price, price_usd, currency, quantity, productId }); 226 } 227 } catch (error) { 228 // console.error(error); 229 } 230 } 231 232 233 /** 234 * @param {() => void} removeListener 235 * @param {ProgressEvent<XMLHttpRequestEventTarget>} ev 236 */ 237 function addToCartByButton(removeListener, ev) { 238 removeListener(); 239 try { 240 const target = parseLoad(ev); 241 const url = target.__url; 242 if (!url.startsWith(ADD_TO_CART_BUTTON_URL)) { 243 return; 244 } 245 const response = target.response; 246 const data = JSON.parse(response); 247 if (data && data.status === 'success' && data.response) { 248 const receive = data.response; 249 const price = +receive.price || 0; 250 const price_usd = receive.price_usd || 0; 251 const quantity = +receive.quantity || 1; 252 const productId = receive.productId; 253 pushGtmDataLayer('addToCartByButton', { account, userId, price, price_usd, currency, quantity, productId, price_usd }); 254 } 255 } catch (error) { 256 // console.error(error); 257 } 258 } 259 260 function addPaymentInfo(removeListener, ev) { 261 removeListener(); 262 try { 263 const target = parseLoad(ev); 264 const url = target.__url; 265 if (!url.startsWith(ADD_PAYMENT_INFO_URL)) { 266 return; 267 } 268 const response = target.response; 269 const data = JSON.parse(response); 270 if (data && data.status) { 271 const price = data.order_amount; 272 const orderNumber = data.order_number; 273 pushGtmDataLayer('addPaymentInfo', { account, userId, price, currency, orderNumber }); 274 } 275 } catch (error) { 276 // console.error(error); 277 } 278 } 279 280 const originFetch = window.fetch; 281 window.fetch = async function fetch(...args) { 282 if (args[0] === ADD_PAYMENT_INFO_URL) { 283 const result = originFetch(...args); 284 try { 285 await result.then(res => { 286 return res.clone().json(); 287 }).then(data => { 288 if (data && data.status) { 289 const price = data.order_amount; 290 const orderNumber = data.order_number; 291 pushGtmDataLayer('addPaymentInfo', { account, userId, price, currency, orderNumber }); 292 return delay(timeout); 293 } 294 }); 295 } catch (error) { 296 // console.error(error); 297 } 298 return await result; 299 } 300 return await originFetch(...args); 301 } 302};
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.