vendor: 14 bytes, lines 1-2
1(() => { 2 //
2src/Utils.js 3 var BeaconUtils = class { 4 static getScreenWidth() { 5 return window.innerWidth || document.documentElement.clientWidth; 6 } 7 static getScreenHeight() { 8 return window.innerHeight || document.documentElement.clientHeight; 9 } 10 static isNotValidScreensize(is_mobile, threshold) { 11 const screenWidth = this.getScreenWidth(); 12 const screenHeight = this.getScreenHeight(); 13 const isNotValidForMobile = is_mobile && (screenWidth > threshold.width || screenHeight > threshold.height); 14 const isNotValidForDesktop = !is_mobile && (screenWidth < threshold.width || screenHeight < threshold.height); 15 return isNotValidForMobile || isNotValidForDesktop; 16 } 17 static isPageCached() { 18 const signature = document.documentElement.nextSibling && document.documentElement.nextSibling.data ? document.documentElement.nextSibling.data : ""; 19 return signature && signature.includes("Debug: cached"); 20 } 21 static isIntersecting(rect) { 22 return rect.bottom >= 0 && rect.right >= 0 && rect.top <= (window.innerHeight || document.documentElement.clientHeight) && rect.left <= (window.innerWidth || document.documentElement.clientWidth); 23 } 24 static isPageScrolled() { 25 return window.pageYOffset > 0 || document.documentElement.scrollTop > 0; 26 } 27 }; 28 var Utils_default = BeaconUtils; 29 30
30// src/BeaconLcp.js 31 var BeaconLcp = class { 32 constructor(config, logger) { 33 this.config = config; 34 this.performanceImages = []; 35 this.logger = logger; 36 } 37 async run() { 38 try { 39 const above_the_fold_images = this._generateLcpCandidates(Infinity); 40 if (above_the_fold_images) { 41 this._initWithFirstElementWithInfo(above_the_fold_images); 42 this._fillATFWithoutDuplications(above_the_fold_images); 43 } 44 } catch (err) { 45 this.errorCode = "script_error"; 46 this.logger.logMessage("Script Error: " + err); 47 } 48 } 49 _generateLcpCandidates(count) { 50 const lcpElements = document.querySelectorAll(this.config.elements); 51 if (lcpElements.length <= 0) { 52 return []; 53 } 54 const potentialCandidates = Array.from(lcpElements); 55 const topCandidates = potentialCandidates.map((element) => { 56 if ("img" === element.nodeName.toLowerCase() && "picture" === element.parentElement.nodeName.toLowerCase()) { 57 return null; 58 } 59 let rect; 60 if ("picture" === element.nodeName.toLowerCase()) { 61 const imgElement = element.querySelector("img"); 62 if (imgElement) { 63 rect = imgElement.getBoundingClientRect(); 64 } else { 65 return null; 66 } 67 } else { 68 rect = element.getBoundingClientRect(); 69 } 70 return { 71 element, 72 rect 73 }; 74 }).filter((item) => item !== null).filter((item) => { 75 return item.rect.width > 0 && item.rect.height > 0 && Utils_default.isIntersecting(item.rect); 76 }).map((item) => ({ 77 item, 78 area: this._getElementArea(item.rect), 79 elementInfo: this._getElementInfo(item.element) 80 })).sort((a, b) => b.area - a.area).slice(0, count); 81 return topCandidates.map((candidate) => ({ 82 element: candidate.item.element, 83 elementInfo: candidate.elementInfo 84 })); 85 } 86 _getElementArea(rect) { 87 const visibleWidth = Math.min(rect.width, (window.innerWidth || document.documentElement.clientWidth) - rect.left); 88 const visibleHeight = Math.min(rect.height, (window.innerHeight || document.documentElement.clientHeight) - rect.top); 89 return visibleWidth * visibleHeight; 90 } 91 _getElementInfo(element) { 92 const nodeName = element.nodeName.toLowerCase(); 93 const element_info = { 94 type: "", 95 src: "", 96 srcset: "", 97 sizes: "", 98 sources: [], 99 bg_set: [], 100 current_src: "" 101 }; 102 const css_bg_url_rgx = /url\(\s*?['"]?\s*?(.+?)\s*?["']?\s*?\)/ig; 103 if (nodeName === "img" && element.srcset) { 104 element_info.type = "img-srcset"; 105 element_info.src = element.src; 106 element_info.srcset = element.srcset; 107 element_info.sizes = element.sizes; 108 element_info.current_src = element.currentSrc; 109 } else if (nodeName === "img") { 110 element_info.type = "img"; 111 element_info.src = element.src; 112 element_info.current_src = element.currentSrc; 113 } else if (nodeName === "video") { 114 element_info.type = "img"; 115 const source = element.querySelector("source"); 116 element_info.src = element.poster || (source ? source.src : ""); 117 element_info.current_src = element_info.src; 118 } else if (nodeName === "svg") { 119 const imageElement = element.querySelector("image"); 120 if (imageElement) { 121 element_info.type = "img"; 122 element_info.src = imageElement.getAttribute("href") || ""; 123 element_info.current_src = element_info.src; 124 } 125 } else if (nodeName === "picture") { 126 element_info.type = "picture"; 127 const img = element.querySelector("img"); 128 element_info.src = img ? img.src : ""; 129 element_info.sources = Array.from(element.querySelectorAll("source")).map((source) => ({ 130 srcset: source.srcset || "", 131 media: source.media || "", 132 type: source.type || "", 133 sizes: source.sizes || "" 134 })); 135 } else { 136 const computed_style = window.getComputedStyle(element, null); 137 const bg_props = [ 138 computed_style.getPropertyValue("background-image"), 139 getComputedStyle(element, ":after").getPropertyValue("background-image"), 140 getComputedStyle(element, ":before").getPropertyValue("background-image") 141 ].filter((prop) => prop !== "none"); 142 if (bg_props.length === 0) { 143 return null; 144 } 145 const full_bg_prop = bg_props[0]; 146 element_info.type = "bg-img"; 147 if (full_bg_prop.includes("image-set(")) { 148 element_info.type = "bg-img-set"; 149 } 150 if (!full_bg_prop || full_bg_prop === "" || full_bg_prop.includes("data:image")) { 151 return null; 152 } 153 const matches = [...full_bg_prop.matchAll(css_bg_url_rgx)]; 154 element_info.bg_set = matches.map((m) => m[1] ? { src: m[1].trim() + (m[2] ? " " + m[2].trim() : "") } : {}); 155 if (element_info.bg_set.every((item) => item.src === "")) { 156 element_info.bg_set = matches.map((m) => m[1] ? { src: m[1].trim() } : {}); 157 } 158 if (element_info.bg_set.length <= 0) { 159 return null; 160 } 161 if (element_info.bg_set.length > 0) { 162 element_info.src = element_info.bg_set[0].src; 163 if (element_info.type === "bg-img-set") { 164 element_info.src = element_info.bg_set; 165 } 166 } 167 } 168 return element_info; 169 } 170 _initWithFirstElementWithInfo(elements) { 171 const firstElementWithInfo = elements.find((item) => { 172 return item.elementInfo !== null && (item.elementInfo.src || item.elementInfo.srcset); 173 }); 174 if (!firstElementWithInfo) { 175 this.logger.logMessage("No LCP candidate found."); 176 this.performanceImages = []; 177 return; 178 } 179 this.performanceImages = [{ 180 ...firstElementWithInfo.elementInfo, 181 label: "lcp" 182 }]; 183 } 184 _fillATFWithoutDuplications(elements) {
185 elements.forEach(({ element, elementInfo }) => { 186 if (this._isDuplicateImage(element) || !elementInfo) { 187 return; 188 } 189 this.performanceImages.push({ ...elementInfo, label: "above-the-fold" }); 190 }); 191 } 192 _isDuplicateImage(image) { 193 const elementInfo = this._getElementInfo(image); 194 if (elementInfo === null) { 195 return false; 196 } 197 const isImageOrVideo = elementInfo.type === "img" || elementInfo.type === "img-srcset" || elementInfo.type === "video"; 198 const isBgImageOrPicture = elementInfo.type === "bg-img" || elementInfo.type === "bg-img-set" || elementInfo.type === "picture"; 199 return (isImageOrVideo || isBgImageOrPicture) && this.performanceImages.some((item) => item.src === elementInfo.src); 200 } 201 getResults() { 202 return this.performanceImages; 203 } 204 }; 205 var BeaconLcp_default = BeaconLcp; 206 207
207// src/BeaconLrc.js 208 var BeaconLrc = class { 209 constructor(config, logger) { 210 this.config = config; 211 this.logger = logger; 212 this.lazyRenderElements = []; 213 } 214 async run() { 215 try { 216 const elementsInView = this._getLazyRenderElements(); 217 if (elementsInView) { 218 this._processElements(elementsInView); 219 } 220 } catch (err) { 221 this.errorCode = "script_error"; 222 this.logger.logMessage("Script Error: " + err); 223 } 224 } 225 _getLazyRenderElements() { 226 const elements = document.querySelectorAll("[data-rocket-location-hash]"); 227 const svgUseTargets = this._getSvgUseTargets(); 228 if (elements.length <= 0) { 229 return []; 230 } 231 const validElements = Array.from(elements).filter((element) => { 232 if (this._skipElement(element)) { 233 return false; 234 } 235 if (svgUseTargets.includes(element)) { 236 this.logger.logColoredMessage(`Element skipped because of SVG: ${element.tagName}`, "orange"); 237 return false; 238 } 239 return true; 240 }); 241 return validElements.map((element) => ({ 242 element, 243 depth: this._getElementDepth(element), 244 distance: this._getElementDistance(element), 245 hash: this._getLocationHash(element) 246 })); 247 } 248 _getElementDepth(element) { 249 let depth = 0; 250 let parent = element.parentElement; 251 while (parent) { 252 depth++; 253 parent = parent.parentElement; 254 } 255 return depth; 256 } 257 _getElementDistance(element) { 258 const rect = element.getBoundingClientRect(); 259 const scrollTop = window.pageYOffset || document.documentElement.scrollTop; 260 return Math.max(0, rect.top + scrollTop - Utils_default.getScreenHeight()); 261 } 262 _skipElement(element) { 263 const skipStrings = this.config.skipStrings || ["memex"]; 264 if (!element || !element.id) return false; 265 return skipStrings.some((str) => element.id.toLowerCase().includes(str.toLowerCase())); 266 } 267 _shouldSkipElement(element, exclusions) { 268 if (!element) return false; 269 for (let i = 0; i < exclusions.length; i++) { 270 const [attribute, pattern] = exclusions[i]; 271 const attributeValue = element.getAttribute(attribute); 272 if (attributeValue && new RegExp(pattern, "i").test(attributeValue)) { 273 return true; 274 } 275 } 276 return false; 277 } 278 _checkLcrConflict(element) { 279 const conflictingElements = []; 280 const computedStyle = window.getComputedStyle(element); 281 const validMargins = ["marginTop", "marginRight", "marginBottom", "marginLeft"]; 282 const negativeMargins = validMargins.some((margin) => parseFloat(computedStyle[margin]) < 0); 283 const currentElementConflicts = negativeMargins || computedStyle.contentVisibility === "auto" || computedStyle.contentVisibility === "hidden"; 284 if (currentElementConflicts) { 285 conflictingElements.push({ 286 element, 287 conflicts: [ 288 negativeMargins && "negative margin", 289 computedStyle.contentVisibility === "auto" && "content-visibility:auto", 290 computedStyle.contentVisibility === "hidden" && "content-visibility:hidden" 291 ].filter(Boolean) 292 }); 293 } 294 Array.from(element.children).forEach((child) => { 295 const childStyle = window.getComputedStyle(child); 296 const validMargins2 = ["marginTop", "marginRight", "marginBottom", "marginLeft"]; 297 const childNegativeMargins = validMargins2.some((margin) => parseFloat(childStyle[margin]) < 0); 298 const childConflicts = childNegativeMargins || childStyle.position === "absolute" || childStyle.position === "fixed"; 299 if (childConflicts) { 300 conflictingElements.push({ 301 element: child, 302 conflicts: [ 303 childNegativeMargins && "negative margin", 304 childStyle.position === "absolute" && "position:absolute", 305 childStyle.position === "fixed" && "position:fixed" 306 ].filter(Boolean) 307 }); 308 } 309 }); 310 return conflictingElements; 311 } 312 _processElements(elements) {
313 elements.forEach(({ element, depth, distance, hash }) => { 314 if (this._shouldSkipElement(element, this.config.exclusions || [])) { 315 return; 316 } 317 if ("No hash detected" === hash) { 318 return; 319 } 320 const conflicts = this._checkLcrConflict(element); 321 if (conflicts.length > 0) { 322 this.logger.logMessage("Skipping element due to conflicts:", conflicts); 323 return; 324 } 325 const can_push_hash = element.parentElement && this._getElementDistance(element.parentElement) < this.config.lrc_threshold && distance >= this.config.lrc_threshold; 326 const color = can_push_hash ? "green" : distance === 0 ? "red" : ""; 327 this.logger.logColoredMessage(`${" ".repeat(depth)}${element.tagName} (Depth: ${depth}, Distance from viewport bottom: ${distance}px)`, color); 328 this.logger.logColoredMessage(`${" ".repeat(depth)}Location hash: ${hash}`, color); 329 this.logger.logColoredMessage(`${" ".repeat(depth)}Dimensions Client Height: ${element.clientHeight}`, color); 330 if (can_push_hash) { 331 this.lazyRenderElements.push(hash); 332 this.logger.logMessage(`Element pushed with hash: ${hash}`); 333 } 334 }); 335 } 336 _getXPath(element) { 337 if (element && element.id !== "") { 338 return `//*[@id="${element.id}"]`; 339 } 340 return this._getElementXPath(element); 341 } 342 _getElementXPath(element) { 343 if (element === document.body) { 344 return "/html/body"; 345 } 346 const position = this._getElementPosition(element); 347 return `${this._getElementXPath(element.parentNode)}/${element.nodeName.toLowerCase()}[${position}]`; 348 } 349 _getElementPosition(element) { 350 let pos = 1; 351 let sibling = element.previousElementSibling; 352 while (sibling) { 353 if (sibling.nodeName === element.nodeName) { 354 pos++; 355 } 356 sibling = sibling.previousElementSibling; 357 } 358 return pos; 359 } 360 _getLocationHash(element) { 361 return element.hasAttribute("data-rocket-location-hash") ? element.getAttribute("data-rocket-location-hash") : "No hash detected"; 362 } 363 _getSvgUseTargets() { 364 const useElements = document.querySelectorAll("use"); 365 const targets = /* @__PURE__ */ new Set(); 366 useElements.forEach((use) => { 367 let parent = use.parentElement; 368 while (parent && parent !== document.body) { 369 targets.add(parent); 370 parent = parent.parentElement; 371 } 372 }); 373 return Array.from(targets); 374 } 375 getResults() { 376 return this.lazyRenderElements; 377 } 378 }; 379 var BeaconLrc_default = BeaconLrc; 380 381
381// src/Logger.js 382 var Logger = class { 383 constructor(enabled) { 384 this.enabled = enabled; 385 } 386 logMessage(msg) { 387 if (!this.enabled) { 388 return; 389 } 390 console.log(msg); 391 } 392 logColoredMessage(msg, color = "green") { 393 if (!this.enabled) { 394 return; 395 } 396 console.log(`%c${msg}`, `color: ${color};`); 397 } 398 }; 399 var Logger_default = Logger; 400 401
401// src/BeaconManager.js 402 var BeaconManager = class { 403 constructor(config) { 404 this.config = config; 405 this.lcpBeacon = null; 406 this.lrcBeacon = null; 407 this.infiniteLoopId = null; 408 this.errorCode = ""; 409 this.logger = new Logger_default(this.config.debug); 410 } 411 async init() { 412 this.scriptTimer = /* @__PURE__ */ new Date(); 413 if (!await this._isValidPreconditions()) { 414 this._finalize(); 415 return; 416 } 417 if (Utils_default.isPageScrolled()) { 418 this.logger.logMessage("Bailing out because the page has been scrolled"); 419 this._finalize(); 420 return; 421 } 422 this.infiniteLoopId = setTimeout(() => { 423 this._handleInfiniteLoop(); 424 }, 1e4); 425 const isGeneratedBefore = await this._getGeneratedBefore(); 426 const shouldGenerateLcp = this.config.status.atf && (isGeneratedBefore === false || isGeneratedBefore.lcp === false); 427 const shouldGeneratelrc = this.config.status.lrc && (isGeneratedBefore === false || isGeneratedBefore.lrc === false); 428 if (shouldGenerateLcp) { 429 this.lcpBeacon = new BeaconLcp_default(this.config, this.logger); 430 await this.lcpBeacon.run(); 431 } else { 432 this.logger.logMessage("Not running BeaconLcp because data is already available or feature is disabled"); 433 } 434 if (shouldGeneratelrc) { 435 this.lrcBeacon = new BeaconLrc_default(this.config, this.logger); 436 await this.lrcBeacon.run(); 437 } else { 438 this.logger.logMessage("Not running BeaconLrc because data is already available or feature is disabled"); 439 } 440 if (shouldGenerateLcp || shouldGeneratelrc) { 441 this._saveFinalResultIntoDB(); 442 } else { 443 this.logger.logMessage("Not saving results into DB as no beacon features ran."); 444 this._finalize(); 445 } 446 } 447 async _isValidPreconditions() { 448 const threshold = { 449 width: this.config.width_threshold, 450 height: this.config.height_threshold 451 }; 452 if (Utils_default.isNotValidScreensize(this.config.is_mobile, threshold)) { 453 this.logger.logMessage("Bailing out because screen size is not acceptable"); 454 return false; 455 } 456 return true; 457 } 458 async _getGeneratedBefore() { 459 if (!Utils_default.isPageCached()) { 460 return false; 461 } 462 let data_check = new FormData(); 463 data_check.append("action", "rocket_check_beacon"); 464 data_check.append("rocket_beacon_nonce", this.config.nonce); 465 data_check.append("url", this.config.url); 466 data_check.append("is_mobile", this.config.is_mobile); 467 const beacon_data_response = await fetch(this.config.ajax_url, { 468 method: "POST", 469 credentials: "same-origin", 470 body: data_check 471 }).then((data) => data.json()); 472 return beacon_data_response.data; 473 } 474 _saveFinalResultIntoDB() { 475 const results = { 476 lcp: this.lcpBeacon ? this.lcpBeacon.getResults() : null, 477 lrc: this.lrcBeacon ? this.lrcBeacon.getResults() : null 478 }; 479 const data = new FormData(); 480 data.append("action", "rocket_beacon"); 481 data.append("rocket_beacon_nonce", this.config.nonce); 482 data.append("url", this.config.url); 483 data.append("is_mobile", this.config.is_mobile); 484 data.append("status", this._getFinalStatus()); 485 data.append("results", JSON.stringify(results)); 486 fetch(this.config.ajax_url, { 487 method: "POST", 488 credentials: "same-origin", 489 body: data, 490 headers: { 491 "wpr-saas-no-intercept": true 492 } 493 }).then((response) => response.json()).then((data2) => { 494 this.logger.logMessage(data2.data.lcp); 495 }).catch((error) => { 496 this.logger.logMessage(error); 497 }).finally(() => { 498 this._finalize(); 499 }); 500 } 501 _getFinalStatus() { 502 if ("" !== this.errorCode) { 503 return this.errorCode; 504 } 505 const scriptTime = (/* @__PURE__ */ new Date() - this.scriptTimer) / 1e3; 506 if (10 <= scriptTime) { 507 return "timeout"; 508 } 509 return "success"; 510 } 511 _handleInfiniteLoop() { 512 this._saveFinalResultIntoDB(); 513 } 514 _finalize() { 515 const beaconscript = document.querySelector('[data-name="wpr-wpr-beacon"]'); 516 beaconscript.setAttribute("beacon-completed", "true"); 517 clearTimeout(this.infiniteLoopId); 518 } 519 }; 520 var BeaconManager_default = BeaconManager; 521 522
522// src/BeaconEntryPoint.js 523 ((rocket_beacon_data) => { 524 if (!rocket_beacon_data) { 525 return; 526 } 527 const instance = new BeaconManager_default(rocket_beacon_data); 528 if (document.readyState !== "loading") { 529 setTimeout(() => { 530 instance.init(); 531 }, rocket_beacon_data.delay); 532 return; 533 } 534 document.addEventListener("DOMContentLoaded", () => { 535 setTimeout(() => { 536 instance.init(); 537 }, rocket_beacon_data.delay); 538 }); 539 })(window.rocket_beacon_data); 540 var BeaconEntryPoint_default = BeaconManager_default; 541})();
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.