let pdfBlobUrl = null; // JavaScript function ensureFreshEmbed() { const container = document.getElementById("stickerFrameContainer"); if (!container) return null; // Ensure we control the container content container.replaceChildren(); // Create a fresh, trusted without any untrusted attributes const emb = document.createElement("embed"); emb.id = "stickerFrame"; emb.className = "sticker-frame"; emb.setAttribute("type", "application/pdf"); emb.style.display = "none"; emb.setAttribute("aria-hidden", "true"); emb.removeAttribute("src"); emb.onclick = null; container.appendChild(emb); return emb; } function closeModal() { const modal = document.getElementById("stickerModal"); modal.style.display = "none"; // Break the viewer’s connection and remove the node const emb = document.getElementById("stickerFrame"); if (emb) { emb.removeAttribute("src"); // detach PDF first emb.remove(); // kill the viewer instance } if (pdfBlobUrl) { URL.revokeObjectURL(pdfBlobUrl); pdfBlobUrl = null; } } function openStickerModal(stickerUrl, vin) { const modal = document.getElementById("stickerModal"); const loading = document.getElementById("stickerLoading"); const downloadBtn = document.getElementById("downloadBtn"); // Helper to detect mobile browsers function isMobile() { return /Mobi|Android|iPhone|iPad|iPod/i.test(navigator.userAgent); } // Fresh embed each open (desktop only) const frame = ensureFreshEmbed(); // Reset UI loading.style.display = "block"; frame.style.display = "none"; downloadBtn.style.display = "none"; downloadBtn.onclick = null; modal.style.display = "flex"; fetch(stickerUrl, { method: "GET" }) .then((res) => { if (!res.ok) throw new Error(`HTTP ${res.status}`); return res.blob(); }) .then((blob) => { // Revoke previous blob (after detaching any old src) if (pdfBlobUrl) URL.revokeObjectURL(pdfBlobUrl); pdfBlobUrl = URL.createObjectURL(blob); pdfBlobUrl = typeof pdfBlobUrl === "string" && pdfBlobUrl.startsWith("blob:") ? pdfBlobUrl : ""; // MOBILE FALLBACK if (isMobile()) { // Open PDF in a new browser tab or viewer const newWindow = window.open(pdfBlobUrl, "_blank"); if (!newWindow) { // Popup blocked or failed — show fallback message loading.innerHTML = "Unable to open PDF. Please allow popups."; return; } // Close modal since PDF opened externally modal.style.display = "none"; loading.style.display = "none"; downloadBtn.style.display = "inline-block"; // Attribute-safe assignment for download downloadBtn.onclick = () => { const a = document.createElement("a"); a.setAttribute("href", pdfBlobUrl); a.setAttribute("download", `window-sticker-${vin}.pdf`); document.body.appendChild(a); a.click(); document.body.removeChild(a); }; return; // stop here for mobile } // DESKTOP BEHAVIOR (keep modal embed) frame.setAttribute("src", pdfBlobUrl); frame.style.display = "block"; loading.style.display = "none"; downloadBtn.style.display = "inline-block"; downloadBtn.onclick = () => { const a = document.createElement("a"); a.setAttribute("href", pdfBlobUrl); a.setAttribute("download", `window-sticker-${vin}.pdf`); document.body.appendChild(a); a.click(); document.body.removeChild(a); }; }) .catch((err) => { loading.innerHTML = "Failed to load sticker."; console.error("Sticker fetch error:", err); }); } function getWarrantyDataSet() { const escapeHtml = (value) => String(value || "") .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); const formatMiles = (milesValue) => { if ( milesValue === null || milesValue === undefined || milesValue === -Infinity ) { return "-"; } const normalized = String(milesValue).trim(); if ( !normalized || normalized.toUpperCase() === "N/A" || normalized === "-" ) { return "-"; } if (/^-?\d+$/.test(normalized)) { const num = Number(normalized); if (isNaN(num)) return "-"; const formatted = Math.abs(num).toLocaleString("en-US"); return `${formatted} mi`; } return normalized; }; const formatMonths = (monthsValue) => { if (monthsValue === null || monthsValue === undefined) { return "N/A"; } const normalized = String(monthsValue).trim(); if ( !normalized || normalized.toUpperCase() === "N/A" || normalized === "-" ) { return "N/A"; } if (/^-?\d+$/.test(normalized)) { return `${normalized} months`; } return normalized; }; const buildFootnoteHtml = (footnoteText) => { const normalizedFootnote = String(footnoteText || "").trim(); if (!normalizedFootnote) { return ""; } const isLongFootnote = normalizedFootnote.length > 140; const textClass = isLongFootnote ? "warranty-footnote-text is-collapsed" : "warranty-footnote-text"; const toggleLink = isLongFootnote ? "" : ""; return ( "

" + escapeHtml(normalizedFootnote) + "" + toggleLink + "

" ); }; const formatCoverageDetails = (item) => { const months = String(item.WARRANTY_MONTHS || "").trim(); const miles = String(item.WARRANTY_MILES || "").trim(); const monthsLabel = months || "N/A"; const milesLabel = miles && /^\d+$/.test(miles) ? Number(miles).toLocaleString("en-US") : miles || "N/A"; const detail = `${monthsLabel} months/${milesLabel} miles`; const footnote = String(item.FOOTNOTE || "").trim(); return ( "" + escapeHtml(detail) + "" + buildFootnoteHtml(footnote) ); }; const buildCoverageLabel = (label, details) => { return ( "
" + escapeHtml(label) + "
" ); }; const nestedWarrantyItems = window.__warrantyData && window.__warrantyData.VHR && Array.isArray(window.__warrantyData.VHR.VEHICLE) && window.__warrantyData.VHR.VEHICLE.length && window.__warrantyData.VHR.VEHICLE[0].WARRANTY_SECTION && Array.isArray( window.__warrantyData.VHR.VEHICLE[0].WARRANTY_SECTION.WARRANTY_ITEMS, ) ? window.__warrantyData.VHR.VEHICLE[0].WARRANTY_SECTION.WARRANTY_ITEMS : []; const injectedWarrantyItems = nestedWarrantyItems.length ? nestedWarrantyItems : Array.isArray(window.__warrantyItems) && window.__warrantyItems.length ? window.__warrantyItems : []; if (injectedWarrantyItems.length) { return injectedWarrantyItems.map((item) => { const warrantyType = String(item.WARRANTY_TYPE || item.warrantyType || "Coverage").trim() || "Coverage"; const tooltipText = String( item.FOOTNOTE || item.footnote || item.tooltip || "", ).trim(); const remainingMiles = formatMiles( item.REMAINING_MILES || item.remainingMiles, ); const remainingMonths = formatMonths( item.REMAINING_MONTHS || item.remainingMonths, ); const status = String(item.STATUS || item.status || "") .trim() .toUpperCase(); return [ buildCoverageLabel( warrantyType, tooltipText || `${warrantyType} coverage details`, ), remainingMiles, remainingMonths, status, formatCoverageDetails({ WARRANTY_MONTHS: item.WARRANTY_MONTHS || item.warrantyMonths, WARRANTY_MILES: item.WARRANTY_MILES || item.warrantyMiles, FOOTNOTE: item.FOOTNOTE || item.footnote, }), ]; }); } return []; } function setWarrantyDebugMessage(section, text, isError = false) { if (!section) return; const debugElement = section.querySelector("#warrantyDebugMessage"); if (!debugElement) return; debugElement.textContent = text || ""; debugElement.classList.remove("text-muted", "text-danger", "text-success"); debugElement.classList.add(isError ? "text-danger" : "text-muted"); } function resolveWarrantyJsonUrl(section) { const sectionConfiguredUrl = section ? section.getAttribute("data-warranty-json-url") || "" : ""; const globalConfiguredUrl = typeof window.__warrantyJsonUrl === "string" ? window.__warrantyJsonUrl : ""; return (sectionConfiguredUrl || globalConfiguredUrl || "").trim(); } function loadWarrantyData(section) { const warrantyJsonUrl = resolveWarrantyJsonUrl(section); if (!warrantyJsonUrl) { const error = new Error( "Warranty JSON URL is not configured. Set data-warranty-json-url on the warranty section.", ); setWarrantyDebugMessage(section, error.message, true); return Promise.reject(error); } setWarrantyDebugMessage( section, `Loading warranty data from ${warrantyJsonUrl}`, ); return fetch(warrantyJsonUrl, { method: "GET", headers: { Accept: "application/json", }, }) .then((response) => { if (!response.ok) { throw new Error(`Failed to load warranty JSON: ${response.status}`); } return response.json(); }) .then((data) => { window.__warrantyData = data; setWarrantyDebugMessage(section, "Warranty data loaded."); return data; }) .catch((error) => { console.error("[warranty] unable to load warranty JSON", error); setWarrantyDebugMessage( section, error.message || "Unable to load warranty data.", true, ); throw error; }); } function getWarrantyTooltipText(element) { return ( element.getAttribute("title") || element.getAttribute("data-original-title") || "" ); } function getWarrantyNativeTooltipElement() { let tooltipElement = document.getElementById("warranty-native-tooltip"); if (!tooltipElement) { tooltipElement = document.createElement("div"); tooltipElement.id = "warranty-native-tooltip"; tooltipElement.className = "warranty-native-tooltip"; tooltipElement.setAttribute("role", "tooltip"); tooltipElement.style.display = "none"; document.body.appendChild(tooltipElement); } return tooltipElement; } function showWarrantyNativeTooltip(target) { const text = getWarrantyTooltipText(target); if (!text) return; const tooltipElement = getWarrantyNativeTooltipElement(); tooltipElement.textContent = text; tooltipElement.style.display = "block"; const targetRect = target.getBoundingClientRect(); const tooltipRect = tooltipElement.getBoundingClientRect(); const scrollX = window.pageXOffset || document.documentElement.scrollLeft; const scrollY = window.pageYOffset || document.documentElement.scrollTop; let top = targetRect.top + scrollY - tooltipRect.height - 8; if (top < scrollY + 8) { top = targetRect.bottom + scrollY + 8; } let left = targetRect.left + scrollX + targetRect.width / 2 - tooltipRect.width / 2; const minLeft = scrollX + 8; const maxLeft = scrollX + window.innerWidth - tooltipRect.width - 8; left = Math.max(minLeft, Math.min(left, maxLeft)); tooltipElement.style.top = top + "px"; tooltipElement.style.left = left + "px"; } function hideWarrantyNativeTooltip() { const tooltipElement = document.getElementById("warranty-native-tooltip"); if (tooltipElement) { tooltipElement.style.display = "none"; } } function toggleWarrantyFootnote(event) { if (event && typeof event.preventDefault === "function") { event.preventDefault(); } if (event && typeof event.stopPropagation === "function") { event.stopPropagation(); } const link = event && event.target ? event.target : null; if (!link) return; const textElement = link.previousElementSibling; if (!textElement) return; const section = link.closest("#warranty"); const seeMoreLabel = (section && section.dataset && section.dataset.msgSeeMore) || "See more"; const seeLessLabel = (section && section.dataset && section.dataset.msgSeeLess) || "See less"; const expanded = !textElement.classList.contains("is-collapsed"); textElement.classList.toggle("is-collapsed", expanded); link.textContent = expanded ? seeMoreLabel : seeLessLabel; link.setAttribute("aria-expanded", expanded ? "false" : "true"); } window.toggleWarrantyFootnote = toggleWarrantyFootnote; function bindWarrantyNativeTooltipFallback(tooltipTargets) { tooltipTargets.forEach((element) => { if (element.dataset.warrantyFallbackBound === "1") return; element.dataset.warrantyFallbackBound = "1"; element.addEventListener("mouseenter", () => showWarrantyNativeTooltip(element), ); element.addEventListener("focus", () => showWarrantyNativeTooltip(element)); element.addEventListener("mouseleave", hideWarrantyNativeTooltip); element.addEventListener("blur", hideWarrantyNativeTooltip); element.addEventListener("click", (event) => { event.preventDefault(); event.stopPropagation(); showWarrantyNativeTooltip(element); }); element.addEventListener("keydown", (event) => { if (event.key === "Escape") { hideWarrantyNativeTooltip(); } }); }); if (!window.__warrantyNativeTooltipOutsideClickBound) { document.addEventListener("click", (event) => { if (!event.target.closest(".warranty-tooltip-icon")) { hideWarrantyNativeTooltip(); } }); window.__warrantyNativeTooltipOutsideClickBound = true; } } function initWarrantyTooltips(section) { const tooltipTargets = section.querySelectorAll( "[data-toggle='tooltip'], [data-bs-toggle='tooltip']", ); if (!tooltipTargets.length) return; if ( window.jQuery && window.jQuery.fn && typeof window.jQuery.fn.tooltip === "function" ) { try { const jqTargets = window.jQuery(tooltipTargets); jqTargets.tooltip("dispose"); jqTargets.tooltip({ trigger: "hover focus click", container: "body", }); return; } catch (error) {} } if (window.bootstrap && typeof window.bootstrap.Tooltip === "function") { try { tooltipTargets.forEach((element) => { const existing = window.bootstrap.Tooltip.getInstance(element); if (existing) existing.dispose(); new window.bootstrap.Tooltip(element, { trigger: "hover focus click", container: "body", }); }); return; } catch (error) {} } bindWarrantyNativeTooltipFallback(tooltipTargets); } function formatCoverageInput(rawValue) { let value = rawValue.replace(/[^0-9]/g, ""); const integerPart = value || ""; const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ","); return formattedInteger; } function normalizeCoverageValue(rawValue) { return rawValue.replace(/,/g, "").trim(); } function isValidCoverageValue(rawValue) { const normalized = normalizeCoverageValue(rawValue); if (!normalized) { return false; } return /^\d+$/.test(normalized); } function setCoverageValidationState( input, messageElement, isValid, messageText, ) { if (!input) { return; } input.classList.toggle("is-invalid", !isValid); input.classList.toggle("is-valid", isValid); input.setAttribute("aria-invalid", isValid ? "false" : "true"); if (messageElement) { if (messageText) { if (isValid) { messageElement.innerHTML = " " + messageText; } else { messageElement.textContent = messageText; } messageElement.classList.remove("d-none", "text-danger", "text-success"); messageElement.classList.add(isValid ? "text-success" : "text-danger"); } else { messageElement.textContent = ""; messageElement.classList.add("d-none"); messageElement.classList.remove("text-danger", "text-success"); } } else { } } function clearCoverageValidationState(input, messageElement) { if (!input) return; input.classList.remove("is-invalid"); input.classList.remove("is-valid"); input.setAttribute("aria-invalid", "false"); if (messageElement) { messageElement.textContent = ""; messageElement.classList.add("d-none"); messageElement.classList.remove("text-danger", "text-success"); } } function getWarrantyMessage(section, key, fallback) { if (!section || !section.dataset) { return fallback; } const value = section.dataset[key]; return value && String(value).trim() !== "" ? value : fallback; } function getWarrantyItemValue(item, camelKey, upperKey) { if (!item) { return null; } if (item[camelKey] !== undefined && item[camelKey] !== null) { return item[camelKey]; } if (item[upperKey] !== undefined && item[upperKey] !== null) { return item[upperKey]; } return null; } function parseWarrantyLimitValue(rawValue) { const normalized = String(rawValue == null ? "" : rawValue).trim(); if (!normalized || normalized === "-" || /^N\/?A$/i.test(normalized)) { return { kind: "na", value: null }; } if (/^(UNLIMITED|LIFETIME)$/i.test(normalized)) { return { kind: "unlimited", value: null }; } const digitsOnly = normalized.replace(/,/g, ""); if (/^-?\d+$/.test(digitsOnly)) { return { kind: "number", value: parseInt(digitsOnly, 10) }; } return { kind: "na", value: null }; } function formatWarrantyMonths(months, section) { if (months == null || months < 0) { return "-"; } const monthLabel = getWarrantyMessage(section, "msgMonth", "month"); const monthsLabel = getWarrantyMessage(section, "msgMonths", "months"); return months === 1 ? `1 ${monthLabel}` : `${months} ${monthsLabel}`; } function formatWarrantyMilesLeft(value, section) { if (value == null || Number.isNaN(Number(value))) { return "-"; } return Number(value).toLocaleString("en-US"); } function getWarrantyStatusIconHtml(status, table) { const normalizedStatus = String(status == null ? "" : status) .trim() .toUpperCase(); const section = table ? table.closest("#warranty") : null; const successIconSrc = table ? table.getAttribute("data-icon-success") || "../fullReport/img/icon-success-pass.png" : "../fullReport/img/icon-success-pass.png"; const expiredIconSrc = table ? table.getAttribute("data-icon-expired") || "../fullReport/img/icon-expired.png" : "../fullReport/img/icon-expired.png"; const activeTitle = getWarrantyMessage(section, "msgStatusActive", "Active"); const expiredTitle = getWarrantyMessage( section, "msgStatusExpired", "Expired", ); const activeAria = getWarrantyMessage( section, "msgCoverageActive", "Coverage active", ); const expiredAria = getWarrantyMessage( section, "msgCoverageExpired", "Coverage expired", ); if (normalizedStatus === "ACTIVE") { return ( "" +
      activeTitle +
      "" ); } if (normalizedStatus === "EXPIRED") { return ( "" +
      expiredTitle +
      "" ); } return normalizedStatus ? `${normalizedStatus}` : "-"; } function recalculateWarrantyTable(section, currentMileage) { if (!section) { return; } const table = section.querySelector("#warrantyDetail"); if (!table) { return; } const rows = table.querySelectorAll("tbody tr"); if (!rows.length) { return; } const ageRaw = table.getAttribute("data-warranty-age"); const parsedAge = parseWarrantyLimitValue(ageRaw); const currentAge = parsedAge.kind === "number" ? parsedAge.value : null; rows.forEach((row) => { const cells = row.querySelectorAll("td"); if (cells.length < 5) { return; } const milesRaw = row.getAttribute("data-warranty-miles"); const monthsRaw = row.getAttribute("data-warranty-months"); const item = row.__warrantyItem || { warrantyMiles: milesRaw, warrantyMonths: monthsRaw, }; const milesLimit = parseWarrantyLimitValue( getWarrantyItemValue(item, "warrantyMiles", "WARRANTY_MILES"), ); const monthsLimit = parseWarrantyLimitValue( getWarrantyItemValue(item, "warrantyMonths", "WARRANTY_MONTHS"), ); let status = "N/A"; let statusClass = "text-muted"; let remainingMileageText = "N/A"; let remainingTimeText = "N/A"; if (milesLimit.kind !== "na" || monthsLimit.kind !== "na") { const hasMileageCheck = milesLimit.kind === "number"; const hasAgeCheck = monthsLimit.kind === "number" && currentAge != null; const remainingMileage = hasMileageCheck ? milesLimit.value - currentMileage : null; const isMileageExpired = hasMileageCheck && remainingMileage <= 0; const isAgeExpired = hasAgeCheck && currentAge >= monthsLimit.value; if (milesLimit.kind === "unlimited" && monthsLimit.kind === "unlimited") { status = "ACTIVE"; statusClass = "text-success"; remainingMileageText = getWarrantyMessage( section, "msgUnlimitedMilesLeft", "Unlimited miles left", ); remainingTimeText = getWarrantyMessage( section, "msgLifetime", "Lifetime", ); } else if (isMileageExpired || isAgeExpired) { status = "EXPIRED"; statusClass = "text-danger"; remainingMileageText = isMileageExpired || !hasMileageCheck ? "-" : formatWarrantyMilesLeft(remainingMileage, section); remainingTimeText = "-"; } else { const isActiveByMileage = !hasMileageCheck || remainingMileage > 0; const isActiveByAge = !hasAgeCheck || currentAge <= monthsLimit.value; if (isActiveByMileage && isActiveByAge) { status = "ACTIVE"; statusClass = "text-success"; remainingMileageText = milesLimit.kind === "unlimited" ? getWarrantyMessage( section, "msgUnlimitedMilesLeft", "Unlimited miles left", ) : hasMileageCheck ? formatWarrantyMilesLeft(remainingMileage, section) : "N/A"; remainingTimeText = monthsLimit.kind === "unlimited" ? getWarrantyMessage(section, "msgLifetime", "Lifetime") : hasAgeCheck ? formatWarrantyMonths( Math.max(Math.floor(monthsLimit.value - currentAge), 0), section, ) : "N/A"; } else { status = "EXPIRED"; statusClass = "text-danger"; remainingMileageText = "-"; remainingTimeText = "-"; } } } cells[1].textContent = remainingMileageText; cells[2].textContent = remainingTimeText; cells[3].classList.remove("text-danger", "text-success", "text-muted"); cells[3].classList.add(statusClass); cells[3].setAttribute("data-status", status); cells[3].innerHTML = getWarrantyStatusIconHtml(status, table); }); } function bindWarrantyInteractions(section) { if (!section || section.dataset.warrantyInteractionsBound === "1") { return; } const input = section.querySelector("#coverage"); const button = section.querySelector("#coverageBtn"); if (input) { input.addEventListener("input", handleCoverageInput); } if (button) { button.addEventListener("click", handleCoverageButtonClick); } section.addEventListener("click", (event) => { const toggleLink = event.target.closest(".warranty-see-more"); if (!toggleLink || !section.contains(toggleLink)) { return; } event.preventDefault(); toggleWarrantyFootnote({ target: toggleLink }); }); section.dataset.warrantyInteractionsBound = "1"; } function renderWarrantyRows(tableElement, dataSet) { let tbody = tableElement.querySelector("tbody"); if (!tbody) { tbody = document.createElement("tbody"); tableElement.appendChild(tbody); } tbody.innerHTML = ""; const getStatusClass = (statusValue) => { const normalizedStatus = String(statusValue || "") .trim() .toLowerCase(); if (normalizedStatus === "expired" || normalizedStatus === "expited") { return "text-danger"; } if (normalizedStatus === "active") { return "text-success"; } return ""; }; dataSet.forEach((row) => { const tr = document.createElement("tr"); row.forEach((cellValue, columnIndex) => { const td = document.createElement("td"); if (columnIndex === 0) { td.innerHTML = cellValue; } else if (columnIndex === 4) { td.innerHTML = cellValue; } else if (columnIndex === 3) { const normalizedStatus = String(cellValue || "").trim(); td.textContent = normalizedStatus || "-"; } else { td.textContent = cellValue; } if (columnIndex === 3) { const statusClass = getStatusClass(cellValue); if (statusClass) { td.classList.add(statusClass); } } tr.appendChild(td); }); tbody.appendChild(tr); }); const section = tableElement.closest("#warranty"); if (!dataSet.length) { setWarrantyDebugMessage( section, "Warranty data loaded, but no rows were found.", true, ); } else { setWarrantyDebugMessage( section, `Loaded ${dataSet.length} warranty row(s).`, ); } } function handleCoverageInput(event) { const input = event && event.target ? event.target : null; if (!input) return; const section = input.closest("#warranty"); const messageElement = section ? section.querySelector("#coverageMessage") : null; input.value = formatCoverageInput(input.value || ""); const normalized = normalizeCoverageValue(input.value || ""); if (!normalized) { clearCoverageValidationState(input, messageElement); return; } setCoverageValidationState( input, messageElement, true, getWarrantyMessage(section, "msgGood", "Looks good!"), ); } function handleCoverageButtonClick(event) { const target = event && event.target ? event.target : null; const section = target ? target.closest("#warranty") : null; if (!section) { return; } const input = section.querySelector("#coverage"); const messageElement = section.querySelector("#coverageMessage"); const preloader = section.querySelector("#warrantyPreloader"); if (!input) { return; } if (preloader) { preloader.classList.remove("d-none"); } const hidePreloaderSoon = () => { if (!preloader) { return; } setTimeout(() => { preloader.classList.add("d-none"); }, 120); }; const normalized = normalizeCoverageValue(input.value || ""); if (!normalized) { setCoverageValidationState( input, messageElement, false, getWarrantyMessage(section, "msgEnterMileage", "Enter Mileage"), ); input.focus(); hidePreloaderSoon(); return; } if (!isValidCoverageValue(input.value || "")) { setCoverageValidationState( input, messageElement, false, getWarrantyMessage( section, "msgValidMileage", "Enter a valid non-negative mileage.", ), ); input.focus(); hidePreloaderSoon(); return; } setCoverageValidationState( input, messageElement, true, getWarrantyMessage(section, "msgGood", "Looks good!"), ); recalculateWarrantyTable(section, parseInt(normalized, 10)); hidePreloaderSoon(); } window.handleCoverageInput = handleCoverageInput; window.handleCoverageButtonClick = handleCoverageButtonClick; function initWarrantyTables() { const warrantySections = document.querySelectorAll("#warranty"); if (!warrantySections.length) { return; } warrantySections.forEach((section, index) => { try { const table = section.querySelector("#warrantyDetail"); const existingRows = table ? table.querySelectorAll("tbody tr") : []; const hasServerRenderedRows = existingRows.length > 0; const dataSet = getWarrantyDataSet(); if (!table) { setWarrantyDebugMessage(section, "Warranty table was not found.", true); return; } bindWarrantyInteractions(section); if (hasServerRenderedRows) { initWarrantyTooltips(section); return; } if (!dataSet.length && !section.dataset.warrantyLoadingStarted) { section.dataset.warrantyLoadingStarted = "1"; loadWarrantyData(section) .then(() => { const loadedDataSet = getWarrantyDataSet(); renderWarrantyRows(table, loadedDataSet); initWarrantyTooltips(section); }) .catch(() => { // error already logged and shown in UI }); return; } renderWarrantyRows(table, dataSet); initWarrantyTooltips(section); } catch (error) { console.error("[warranty] init error", index + 1, error); } }); } window.initWarrantyTables = initWarrantyTables; function initFullReportPage() { if (window.__fullReportMainInitialized) { return; } window.__fullReportMainInitialized = true; const links = document.querySelectorAll("a.backtotop-link"); for (var i = 0; i < links.length; i++) { (function (link) { var targetId = link.getAttribute("data-top-id"); if (targetId) { var targetDiv = document.getElementById(targetId); if (targetDiv) { link.addEventListener("click", function (e) { e.preventDefault(); targetDiv.scrollIntoView({ behavior: "smooth" }); }); } } })(links[i]); } document.querySelectorAll(".open-sticker-modal").forEach(function (btn) { btn.addEventListener("click", function (e) { e.preventDefault(); const url = btn.getAttribute("data-url"); const vin = btn.getAttribute("data-vin"); const make = (btn.getAttribute("data-make") || "").toLowerCase(); const year = parseInt(btn.getAttribute("data-year"), 10); if (!url || !vin) { console.error("Sticker URL or VIN missing"); return; } // Ford family vehicles → open window sticker in modal var fordFamily = ["ford", "lincoln", "mercury"]; var fordStickerThresholdYear = 2008; if (fordFamily.indexOf(make) !== -1 && !Number.isNaN(year) && year >= fordStickerThresholdYear) { openStickerModal(url, vin); } else { // All other makes → open loading page in new tab with sticker URL as param var docType = btn.getAttribute("data-doc-type") || "window-sticker"; var basePath = url.substring(0, url.indexOf("/process")); var stickerUrlWithName = url.replace( "/process?", "/process/" + docType + "-" + vin + "?", ); var loadingPageUrl = basePath + "/report/fullReport/windowStickerLoading.html" + "?stickerUrl=" + encodeURIComponent(stickerUrlWithName) + "&tabTitle=" + encodeURIComponent(docType + "-" + vin) + "&errorUrl=" + encodeURIComponent( basePath + "/report/fullReport/windowStickerError.html", ); window.open(loadingPageUrl, "_blank"); } }); }); const closeModalBtn = document.getElementById("closeModalBtn"); if (closeModalBtn) { closeModalBtn.addEventListener("click", closeModal); } initWarrantyTables(); } if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", initFullReportPage); } else { initFullReportPage(); } // Good practice: don't overwrite window.onclick window.addEventListener("click", (e) => { const modal = document.getElementById("stickerModal"); if (e.target === modal) closeModal(); }); function backToTop(topname) { document.getElementById(topname).scrollIntoView(); }