1let browsingId; 2let isUserLoggedIn; 3 4function getCookieValue(cookieName) { 5 const allCookies = document.cookie.split("; "); 6 const foundCookie = allCookies.find((cookie) => 7 cookie.startsWith(cookieName + "=") 8 ); 9 return foundCookie ? decodeURIComponent(foundCookie.split("=")[1]) : null; 10} 11 12function setCookie(name, value, days) { 13 let expires = ""; 14 if (days) { 15 let date = new Date(); 16 date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000); 17 expires = "; expires=" + date.toUTCString(); 18 } 19 document.cookie = 20 name + "=" + encodeURIComponent(value) + expires + "; path=/"; 21} 22 23function updateCookieExpiration(name, days) { 24 const cookieValue = getCookieValue(name); 25 if (cookieValue !== null) { 26 // Cookie exists, so update it with the new expiration date 27 setCookie(name, cookieValue, days); 28 } 29} 30 31function deleteCookie(name) { 32 document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; 33} 34 35function generateUUID() { 36 return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) { 37 let r = (Math.random() * 16) | 0, 38 v = c === "x" ? r : (r & 0x3) | 0x8; 39 return v.toString(16); 40 }); 41} 42 43function parseURL(url) { 44 try { 45 // Create a new URL object 46 const parsedUrl = new URL(url); 47 48 // Extract the components of the URL 49 const components = { 50 href: parsedUrl.href, // The full URL 51 protocol: parsedUrl.protocol, // Protocol (e.g., 'http:' or 'https:') 52 host: parsedUrl.host, // Hostname and port (e.g., 'example.com:80') 53 hostname: parsedUrl.hostname, // Hostname (e.g., 'example.com') 54 port: parsedUrl.port, // Port (e.g., '80') 55 pathname: parsedUrl.pathname, // Path (e.g., '/path/to/resource') 56 search: parsedUrl.search, // Query string (e.g., '?key=value') 57 searchParams: parsedUrl.searchParams, // URLSearchParams object to handle query parameters 58 hash: parsedUrl.hash, // Fragment identifier (e.g., '#section') 59 }; 60 61 // Convert URLSearchParams to a plain object 62 components.queryParams = {}; 63 parsedUrl.searchParams.forEach((value, key) => { 64 components.queryParams[key] = value; 65 }); 66 67 return components; 68 } catch (error) { 69 console.error("Invalid URL:", error); 70 return; 71 } 72} 73 74// User Browsing Specific Scripts 75async function getBrowsingData() { 76 try { 77 if (!browsingId) { 78 return; 79 } 80 const response = await fetch( 81 `${window.location.origin}/Browsing.php?id=${browsingId}` 82 ); 83 if (!response.ok || response.error) { 84 throw new Error("Network response was not ok"); 85 } 86 const data = await response.json(); 87 return data; 88 } catch (e) { 89 reject(e); 90 } 91} 92 93async function modifyBrowsingData({ fieldKey, fieldValue }) { 94 try { 95 if (!browsingId) { 96 return; 97 } 98 99 let browsingData; 100 101 // Check For Existing Data 102 const existingData = await getBrowsingData(); 103 104 // Error Occured On Fetch - Throw Error 105 if (existingData?.error) { 106 throw existingData.error; 107 } 108 109 browsingData = existingData || {}; 110 111 112 113 switch (fieldKey) { 114 case "accessories": 115 // If Accessories Does Not Exist - Create Array 116 if (!browsingData.hasOwnProperty(fieldKey)) { 117 browsingData[fieldKey] = []; 118 } 119 120 // If Accessories Does Not Include Value - Add To Array 121 if (!browsingData[fieldKey].includes(fieldValue)) { 122 if (browsingData[fieldKey].length < 4) { 123 browsingData[fieldKey].push(fieldValue); 124 } else { 125 browsingData[fieldKey].shift(); 126 browsingData[fieldKey].push(fieldValue); 127 } 128 } 129 break; 130 case "config_id": 131 // Clear config only when explicitly passed empty/null; otherwise save latest config id. 132 if (fieldValue === null || fieldValue === undefined || fieldValue === "") { 133 delete browsingData[fieldKey]; 134 } else { 135 browsingData[fieldKey] = fieldValue; 136 } 137 break; 138 default: 139 browsingData[fieldKey] = fieldValue; 140 } 141 142 if(Object.keys(browsingData).length === 0) { 143 return; 144 } 145 146 // Submit Browsing Data 147 const response = await fetch( 148 `${window.location.origin}/Browsing.php?action=modify`, 149 { 150 method: "POST", 151 headers: { 152 "Content-Type": "application/json", 153 }, 154 body: JSON.stringify({ 155 id: browsingId, 156 data: browsingData, 157 user: !!isUserLoggedIn, 158 }), 159 } 160 ); 161 162 if (!response.ok || response.error) { 163 throw new Error("Network response was not ok"); 164 } 165 } catch (e) { 166 console.error("Error Modifying Browsing Data: " + e); 167 throw e; 168 } 169} 170 171async function executeBrowsingDataUpdates() { 172 try { 173 // Get Current URL 174 const currentURL = parseURL(window.location.href); 175 176 const isAccessoriesViewPage = 177 currentURL.pathname.includes("Accessories") && 178 currentURL.queryParams?.action === "view-product" && 179 currentURL.queryParams?.us_part_number.length > 0; 180 181 const isConfiguratorPage = 182 currentURL.pathname.includes("/models/") && 183 currentURL.pathname.includes("/configure"); 184 185 const isBuildSavedPage = 186 currentURL.pathname.includes("/models.php") && 187 currentURL.queryParams?.action === "save_configuration"; 188 189 // Accessory View Page 190 if (isAccessoriesViewPage) { 191 // Add Accessory To Browsing Data 192 await modifyBrowsingData({ 193 fieldKey: "accessories", 194 fieldValue: currentURL.queryParams.us_part_number, 195 }); 196 } 197 198 // Configurator 199 if (isConfiguratorPage) { 200 const modelId = 201 productArr && Object.keys(productArr).length 202 ? productArr.product_id 203 : currentURL.pathname 204 .split("/") 205 .filter( 206 (segment) => 207 segment && segment !== "models" && segment !== "configure" 208 )[0]; 209 if (modelId) { 210 await modifyBrowsingData({ 211 fieldKey: "config_id", 212 fieldValue: modelId, 213 }); 214 } 215 } 216 217 } catch (e) { 218 console.error("Error executeBrowsingDataUpdates: " + e); 219 return; 220 } 221} 222 223window.addEventListener("DOMContentLoaded", async function () { 224 isUserLoggedIn = getCookieValue("gigya_users_id"); 225 const hasBrowsingId = getCookieValue("yamaha_browsing_id") || false; 226 227 const loggedOutReferrer = document.referrer.includes("manage_account"); 228 229 if (isUserLoggedIn && hasBrowsingId) { 230 deleteCookie("yamaha_browsing_id"); 231 } 232 233 // Re-read the cookie after page load â PHP may have set it via Set-Cookie header 234 const freshBrowsingId = getCookieValue("yamaha_browsing_id"); 235 236 if (!isUserLoggedIn && !freshBrowsingId && !loggedOutReferrer) { 237 const yamaha_browsing_id = generateUUID();
238 setCookie("yamaha_browsing_id", yamaha_browsing_id, 14); 239 } else if (freshBrowsingId) { 240 updateCookieExpiration("yamaha_browsing_id", 14); 241 } 242 243 // Set Global Browsing ID 244 browsingId = 245 getCookieValue("yamaha_browsing_id") || getCookieValue("gigya_users_id"); 246 247 // Check Against URL And Update Browsing Data If Applicable 248 await executeBrowsingDataUpdates(); 249});
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.