/** * CHANGAN CS55 PLUS 4TH GEN OWNER'S MANUAL - MULTILINGUAL SPA CONTROLLER * Fluent Multilingual & RTL Support: English (en), Persian (fa / فارسی), and Chinese (zh / 中文) */ (function () { 'use strict'; // I18N Localization Dictionary const I18N = { en: { searchPlaceholder: "Search manual (e.g., adaptive cruise, start engine, fuses, TPMS)...", searchModalPlaceholder: "Search topics, keywords, or switches...", searchEmpty: "Type keywords to search across all manual topics...", searchNoResults: (q) => `No results found for "${q}".`, tabManual: "📖 Manual", tabSwitches: "🎛️ Switches", tabVisual: "🖼️ Visual", breadcrumbManual: "Manual", prevTopic: "← Previous Topic", nextTopic: "Next Topic →", topicNotFound: "Topic Not Found", topicNotFoundDesc: "The requested topic could not be loaded.", returnHome: "Return to Home", visualTitle: "Visual Diagram Index", visualSubtitle: "Interactive Exterior & Interior Overview Diagrams", switchesTitle: "Vehicle Switches & Buttons", switchesSubtitle: "Interactive guide to key fob, stalks, shifter, center console & AC", clusterTitle: "Instrument Cluster", clusterSubtitle: "Digital speedometer, tachometer, menus and drive modes", lampsTitle: "Warning & Indicator Lamps", lampsSubtitle: "Meanings of all 34 dashboard warning lamps and indicators", drivingTitle: "Driving the Vehicle", drivingSubtitle: "Keyless engine start, electronic shifter and EPB auto hold", adasTitle: "Assisted Driving (ADAS)", adasSubtitle: "ACC, lane centering, 360 camera & APA auto parking", emergencyTitle: "Emergency Situations", emergencySubtitle: "Towing, battery jump start, fuse box and roadside emergency", backHomeLabel: "Car Models", searchScope: "Searching inside CS55 PLUS Manual" }, fa: { searchPlaceholder: "جستجو در راهنمای CS55 پلاس (مانند: کروز کنترل، استارت، فیوزها، باد تایر)...", searchModalPlaceholder: "جستجوی مباحث یا کلیدهای CS55 پلاس...", searchEmpty: "کلمه مورد نظر را برای جستجو در راهنمای CS55 پلاس وارد نمایید...", searchNoResults: (q) => `هیچ نتیجه‌ای در راهنمای CS55 پلاس برای «${q}» یافت نشد.`, tabManual: "📖 راهنما", tabSwitches: "🎛️ کلیدها", tabVisual: "🖼️ تصاویر", breadcrumbManual: "راهنما", prevTopic: "مبحث قبلی →", nextTopic: "← مبحث بعدی", topicNotFound: "مبحث مورد نظر یافت نشد", topicNotFoundDesc: "محتوای بخش درخواستی بارگذاری نشد.", returnHome: "بازگشت به صفحه اصلی", visualTitle: "راهنمای تصویری قطعات خودرو", visualSubtitle: "نقشه و نمودارهای تصویری تعاملی از تجهیزات بیرونی و داخلی خودرو", switchesTitle: "کلیدها و ادوات کنترلی خودرو", switchesSubtitle: "راهنمای تعاملی ریموت، اهرم‌ها، شیفتر دنده، کنسول وسط و تهویه", clusterTitle: "صفحه کیلومتر و آمپر", clusterSubtitle: "کیلومترشمار دیجیتال، دور موتور، منوها و حالت‌های رانندگی", lampsTitle: "چراغ‌های هشدار و راهنما", lampsSubtitle: "تفسیر کامل ۳۴ چراغ اخطار و نشانگر صفحه آمپر", drivingTitle: "رانندگی با خودرو", drivingSubtitle: "استارت بدون کلید، شیفتر دنده الکترونیکی و توقف خودکار (Auto Hold)", adasTitle: "سامانه‌های کمکی راننده (ADAS)", adasSubtitle: "کروز کنترل تطبیقی، رادار بین خطوط، دوربین ۳۶۰ و پارک خودکار", emergencyTitle: "شرایط اضطراری و امداد", emergencySubtitle: "بکسل، باتری‌به‌باتری، جعبه فیوزها و ابزار اضطراری", backHomeLabel: "مدل‌های خودرو", searchScope: "جستجو در راهنمای اختصاصی CS55 پلاس" }, zh: { searchPlaceholder: "搜索 CS55 PLUS 手册(如:自适应巡航、启动发动机、保险丝、胎压)...", searchModalPlaceholder: "搜索 CS55 PLUS 章节、关键词或开关按键...", searchEmpty: "输入关键词搜索 CS55 PLUS 手册内容...", searchNoResults: (q) => `未在 CS55 PLUS 手册中找到包含 "${q}" 的结果。`, tabManual: "📖 指南", tabSwitches: "🎛️ 按键", tabVisual: "🖼️ 图解", breadcrumbManual: "驾驶指南", prevTopic: "← 上一节", nextTopic: "下一节 →", topicNotFound: "内容未找到", topicNotFoundDesc: "请求的章节内容无法加载。", returnHome: "返回首页", visualTitle: "图片索引", visualSubtitle: "整车外饰与内饰示意图", switchesTitle: "全车开关按键", switchesSubtitle: "钥匙、控制手柄、怀挡、中控与空调按键", clusterTitle: "仪表界面", clusterSubtitle: "全液晶仪表界面与行车电脑设置", lampsTitle: "警示灯和指示灯", lampsSubtitle: "34种仪表指示灯和故障警示灯图解说明", drivingTitle: "驾驶车辆", drivingSubtitle: "自动挡启动、电子怀挡与自动驻车使用", adasTitle: "辅助驾驶", adasSubtitle: "自适应巡航、360全景影像与泊车辅助", emergencyTitle: "紧急情况", emergencySubtitle: "搭电启动、应急拖车与随车工具", backHomeLabel: "所有车型", searchScope: "正在检索 CS55 PLUS 专属车主手册" } }; // Global State const urlParams = new URLSearchParams(window.location.search); const urlLang = urlParams.get('lang'); const storedLang = localStorage.getItem('cs55_manual_lang') || 'en'; let initialLang = (urlLang && ['en', 'fa', 'zh'].includes(urlLang)) ? urlLang : storedLang; if (!['en', 'fa', 'zh'].includes(initialLang)) initialLang = 'en'; if (urlLang && ['en', 'fa', 'zh'].includes(urlLang)) { localStorage.setItem('changan_user_lang_selected', 'true'); localStorage.setItem('cs55_manual_lang', urlLang); } const carParam = (urlParams.get('car') || 'cs55plus').toLowerCase(); const isX5 = (carParam === 'x5plus' || carParam === 'x5plus_2026'); const currentCarKey = isX5 ? 'x5plus' : 'cs55plus'; const state = { currentCar: currentCarKey, currentCarName: isX5 ? 'Changan X5 PLUS 2026' : 'Changan CS55 PLUS', currentLang: initialLang, // 'en' | 'fa' | 'zh' currentView: 'welcome', // 'welcome' | 'topic' | 'switches' | 'visual' currentTopicId: null, currentPlateId: null, currentSwitchId: isX5 ? 'PG770285' : 'PG725359', plates: {}, welcome: {}, contents: {}, searchIndex: [], allTopicsList: [], dataCache: { en: null, fa: null, zh: null } }; // DOM Elements const dom = { sidebarScroll: document.getElementById('sidebarScroll'), mainContent: document.getElementById('mainContent'), langToggleBtn: document.getElementById('langToggleBtn'), currentLangIcon: document.getElementById('currentLangIcon'), currentLangLabel: document.getElementById('currentLangLabel'), langMenu: document.getElementById('langMenu'), langDropdownWrapper: document.querySelector('.lang-dropdown-wrapper'), menuToggleBtn: document.getElementById('menuToggleBtn'), sidebar: document.getElementById('appSidebar'), headerSearchInput: document.getElementById('headerSearchInput'), searchModal: document.getElementById('searchModal'), searchModalInput: document.getElementById('searchModalInput'), searchModalClose: document.getElementById('searchModalClose'), searchModalResults: document.getElementById('searchModalResults'), lightboxModal: document.getElementById('lightboxModal'), lightboxImg: document.getElementById('lightboxImg'), lightboxClose: document.getElementById('lightboxClose'), navTabManual: document.getElementById('navTabManual'), navTabSwitches: document.getElementById('navTabSwitches'), navTabVisual: document.getElementById('navTabVisual'), firstVisitModal: document.getElementById('firstVisitModal'), btnBackHome: document.getElementById('btnBackHome'), backHomeLabel: document.getElementById('backHomeLabel'), carModelBadge: document.getElementById('carModelBadge'), carModelSub: document.getElementById('carModelSub') }; // Initialize App async function init() { setupEventListeners(); setupFirstVisitModal(); applyLanguageDirection(state.currentLang); updateLanguageButtonUI(state.currentLang); updateLocalizedUI(state.currentLang); await loadDataForLanguage(state.currentLang); handleRoute(); window.addEventListener('hashchange', handleRoute); } // Setup First-Time Visitor Language Modal function setupFirstVisitModal() { const hasChosenLang = localStorage.getItem('changan_user_lang_selected'); if (!hasChosenLang && dom.firstVisitModal) { setTimeout(() => { dom.firstVisitModal.classList.add('open'); }, 350); } document.querySelectorAll('.lang-choice-btn').forEach(btn => { btn.addEventListener('click', () => { const selected = btn.getAttribute('data-lang'); if (['en', 'fa', 'zh'].includes(selected)) { localStorage.setItem('changan_user_lang_selected', 'true'); setLanguage(selected); if (dom.firstVisitModal) dom.firstVisitModal.classList.remove('open'); } }); }); } // Set Language and re-render async function setLanguage(lang) { if (!['en', 'fa', 'zh'].includes(lang)) return; state.currentLang = lang; localStorage.setItem('cs55_manual_lang', lang); applyLanguageDirection(lang); updateLanguageButtonUI(lang); updateLocalizedUI(lang); await loadDataForLanguage(lang); buildFlatTopicsList(); renderSidebarNavigation(); handleRoute(); } // RTL / LTR Direction function applyLanguageDirection(lang) { const isRtl = (lang === 'fa'); document.documentElement.setAttribute('dir', isRtl ? 'rtl' : 'ltr'); document.documentElement.setAttribute('lang', lang); } // Update Header Button UI function updateLanguageButtonUI(lang) { const icons = { en: '🇬🇧', fa: '🇮🇷', zh: '🇨🇳' }; const labels = { en: 'English', fa: 'فارسی', zh: '中文' }; if (dom.currentLangIcon) dom.currentLangIcon.textContent = icons[lang] || '🌐'; if (dom.currentLangLabel) dom.currentLangLabel.textContent = labels[lang] || lang; // Update active highlight in dropdown document.querySelectorAll('.lang-option').forEach(btn => { btn.classList.toggle('active', btn.getAttribute('data-lang') === lang); }); } // Update Static Localized UI Strings function updateLocalizedUI(lang = state.currentLang) { const t = I18N[lang] || I18N.en; const isX5 = (state.currentCar === 'x5plus'); // Scoped car badges and subheadings if (dom.carModelBadge) { dom.carModelBadge.textContent = isX5 ? 'X5 PLUS' : 'CS55 PLUS'; } if (dom.carModelSub) { if (isX5) { dom.carModelSub.textContent = (lang === 'fa') ? 'راهنمای کاربری نسل دوم ۲۰۲۶' : (lang === 'zh' ? '第二代官方车主指南' : "2nd Gen Sport Driver's Guide"); } else { dom.carModelSub.textContent = (lang === 'fa') ? 'راهنمای کاربری نسل چهارم' : (lang === 'zh' ? '第四代官方车主指南' : "4th Gen Owner's Guide"); } } // Scoped Search Placeholder per car if (isX5) { if (lang === 'fa') { if (dom.headerSearchInput) dom.headerSearchInput.placeholder = 'جستجو در راهنمای اختصاصی X5 پلاس (مانند: کروز کنترل، استارت، فیوزها)...'; if (dom.searchModalInput) dom.searchModalInput.placeholder = 'جستجوی مباحث یا کلیدهای چانگان X5 پلاس...'; } else if (lang === 'zh') { if (dom.headerSearchInput) dom.headerSearchInput.placeholder = '搜索 X5 PLUS 手册(如:自适应巡航、启动发动机、保险丝、胎压)...'; if (dom.searchModalInput) dom.searchModalInput.placeholder = '搜索 X5 PLUS 章节、关键词或开关按键...'; } else { if (dom.headerSearchInput) dom.headerSearchInput.placeholder = 'Search inside X5 PLUS Manual (e.g., adaptive cruise, start engine, fuses)...'; if (dom.searchModalInput) dom.searchModalInput.placeholder = 'Search topics or switches in Changan X5 PLUS...'; } } else { if (dom.headerSearchInput) dom.headerSearchInput.placeholder = t.searchPlaceholder; if (dom.searchModalInput) dom.searchModalInput.placeholder = t.searchModalPlaceholder; } if (dom.navTabManual) dom.navTabManual.textContent = t.tabManual; if (dom.navTabSwitches) dom.navTabSwitches.textContent = t.tabSwitches; if (dom.navTabVisual) dom.navTabVisual.textContent = t.tabVisual; if (dom.backHomeLabel) dom.backHomeLabel.textContent = t.backHomeLabel; } // Load Data for Specific Language async function loadDataForLanguage(lang) { if (state.dataCache[lang]) { const cached = state.dataCache[lang]; state.plates = cached.plates; state.welcome = cached.welcome; state.contents = cached.contents; state.searchIndex = cached.searchIndex; buildFlatTopicsList(); renderSidebarNavigation(); return; } try { let platesRes, welcomeRes, quickentryRes, manualRes, searchIndexRes; const isX5 = (state.currentCar === 'x5plus'); const basePath = isX5 ? 'data/x5plus/' : 'data/'; if (lang === 'fa') { // Persian Data [platesRes, welcomeRes, quickentryRes] = await Promise.all([ fetch(`${basePath}plates_fa.json`).then(r => r.json()).catch(() => fetch(`${basePath}plates_en.json`).then(r => r.json()).catch(() => ({}))), fetch(`${basePath}welcome_fa.json`).then(r => r.json()).catch(() => fetch(`${basePath}welcome_en.json`).then(r => r.json()).catch(() => ({}))), fetch(`${basePath}quickentry_fa.json`).then(r => r.json()).catch(() => fetch(`${basePath}quickentry_en.json`).then(r => r.json()).catch(() => ({}))) ]); try { manualRes = await fetch(`${basePath}manual_fa.json`).then(r => r.json()); } catch (e) { manualRes = await fetch(`${basePath}manual_en.json`).then(r => r.json()); } try { searchIndexRes = await fetch(`${basePath}search_index_fa.json`).then(r => r.json()); } catch (e) { searchIndexRes = await fetch(`${basePath}search_index.json`).then(r => r.json()); } } else if (lang === 'zh') { // Chinese Data manualRes = await fetch(`${basePath}manual_zh.json`).then(r => r.json()); platesRes = manualRes.allPlate || {}; welcomeRes = manualRes.welcome || {}; quickentryRes = {}; searchIndexRes = await fetch(`${basePath}search_index.json`).then(r => r.json()).catch(() => []); } else { // English Data [platesRes, welcomeRes, quickentryRes, manualRes, searchIndexRes] = await Promise.all([ fetch(`${basePath}plates_en.json`).then(r => r.json()).catch(() => ({})), fetch(`${basePath}welcome_en.json`).then(r => r.json()).catch(() => ({})), fetch(`${basePath}quickentry_en.json`).then(r => r.json()).catch(() => ({})), fetch(`${basePath}manual_en.json`).then(r => r.json()), fetch(`${basePath}search_index.json`).then(r => r.json()).catch(() => []) ]); } state.plates = platesRes || {}; state.welcome = welcomeRes || {}; state.contents = {}; if (quickentryRes) Object.assign(state.contents, quickentryRes); if (manualRes && manualRes.contents) Object.assign(state.contents, manualRes.contents); state.searchIndex = searchIndexRes || []; // Cache data state.dataCache[lang] = { plates: state.plates, welcome: state.welcome, contents: state.contents, searchIndex: state.searchIndex }; buildFlatTopicsList(); renderSidebarNavigation(); } catch (err) { console.error('Error loading manual data for language ' + lang + ':', err); } } // Build Ordered List of Topics for Next / Prev Navigation function buildFlatTopicsList() { state.allTopicsList = []; for (const plate of Object.values(state.plates)) { if (plate.children) { for (const cat of plate.children) { for (const item of cat.children || []) { if (item.id && !state.allTopicsList.some(t => t.id === item.id)) { state.allTopicsList.push({ id: item.id, title: item.title, title_zh: item.title_zh, plateKey: plate.key, plateTitle: plate.title, category: cat.title }); } } } } } } // Event Listeners function setupEventListeners() { // Mobile Drawer Toggle if (dom.menuToggleBtn) { dom.menuToggleBtn.addEventListener('click', () => { dom.sidebar.classList.toggle('open'); }); } // Language Dropdown Toggle if (dom.langToggleBtn && dom.langMenu) { dom.langToggleBtn.addEventListener('click', (e) => { e.stopPropagation(); const isOpen = dom.langMenu.classList.toggle('open'); if (dom.langDropdownWrapper) dom.langDropdownWrapper.classList.toggle('open', isOpen); dom.langToggleBtn.setAttribute('aria-expanded', isOpen); }); // Language Option Selection document.querySelectorAll('.lang-option').forEach(btn => { btn.addEventListener('click', (e) => { e.stopPropagation(); const selectedLang = btn.getAttribute('data-lang'); if (selectedLang) { setLanguage(selectedLang); dom.langMenu.classList.remove('open'); if (dom.langDropdownWrapper) dom.langDropdownWrapper.classList.remove('open'); dom.langToggleBtn.setAttribute('aria-expanded', 'false'); } }); }); // Close dropdown on click outside document.addEventListener('click', () => { if (dom.langMenu) dom.langMenu.classList.remove('open'); if (dom.langDropdownWrapper) dom.langDropdownWrapper.classList.remove('open'); if (dom.langToggleBtn) dom.langToggleBtn.setAttribute('aria-expanded', 'false'); }); } // Nav Tabs if (dom.navTabManual) { dom.navTabManual.addEventListener('click', () => { setActiveNavTab('manual'); location.hash = '#welcome'; }); } if (dom.navTabSwitches) { dom.navTabSwitches.addEventListener('click', () => { setActiveNavTab('switches'); const defaultSwitch = (state.currentCar === 'x5plus') ? 'PG770285' : 'PG725359'; location.hash = `#switches-${defaultSwitch}`; }); } if (dom.navTabVisual) { dom.navTabVisual.addEventListener('click', () => { setActiveNavTab('visual'); location.hash = '#visual'; }); } // Header Search if (dom.headerSearchInput) { dom.headerSearchInput.addEventListener('focus', () => { openSearchModal(dom.headerSearchInput.value); }); } // Search Modal if (dom.searchModalClose) { dom.searchModalClose.addEventListener('click', closeSearchModal); } if (dom.searchModal) { dom.searchModal.addEventListener('click', (e) => { if (e.target === dom.searchModal) closeSearchModal(); }); } if (dom.searchModalInput) { dom.searchModalInput.addEventListener('input', (e) => { executeSearch(e.target.value); }); } // Lightbox Modal if (dom.lightboxClose) { dom.lightboxClose.addEventListener('click', closeLightbox); } if (dom.lightboxModal) { dom.lightboxModal.addEventListener('click', (e) => { if (e.target === dom.lightboxModal) closeLightbox(); }); } // Keyboard ESC document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { closeSearchModal(); closeLightbox(); } }); // Content delegate for image zoom & internal links dom.mainContent.addEventListener('click', (e) => { // Lightbox on image if (e.target.tagName === 'IMG' && !e.target.classList.contains('no-zoom')) { openLightbox(e.target.src); } }); } function setActiveNavTab(tab) { [dom.navTabManual, dom.navTabSwitches, dom.navTabVisual].forEach(el => { if (el) el.classList.remove('active'); }); if (tab === 'manual' && dom.navTabManual) dom.navTabManual.classList.add('active'); if (tab === 'switches' && dom.navTabSwitches) dom.navTabSwitches.classList.add('active'); if (tab === 'visual' && dom.navTabVisual) dom.navTabVisual.classList.add('active'); } // Routing Handler function handleRoute() { const hash = location.hash.replace('#', '') || 'welcome'; // Close mobile drawer on route change if (dom.sidebar) dom.sidebar.classList.remove('open'); if (hash === 'welcome' || hash === '' || hash === 'home') { state.currentView = 'welcome'; state.currentTopicId = null; setActiveNavTab('manual'); renderWelcomeView(); } else if (hash.startsWith('topic-')) { const topicId = hash.replace('topic-', ''); state.currentView = 'topic'; state.currentTopicId = topicId; setActiveNavTab('manual'); loadAndRenderTopic(topicId); } else if (hash.startsWith('switches-')) { const defaultSwitch = (state.currentCar === 'x5plus') ? 'PG770285' : 'PG725359'; const switchId = hash.replace('switches-', '') || defaultSwitch; state.currentView = 'switches'; state.currentSwitchId = switchId; setActiveNavTab('switches'); renderSwitchesView(switchId); } else if (hash === 'visual') { state.currentView = 'visual'; setActiveNavTab('visual'); renderVisualIndexView(); } else { // Direct topic ID fallback state.currentView = 'topic'; state.currentTopicId = hash; setActiveNavTab('manual'); loadAndRenderTopic(hash); } } // Render Sidebar function renderSidebarNavigation() { if (!dom.sidebarScroll) return; const lang = state.currentLang; let html = ''; for (const [plateKey, plate] of Object.entries(state.plates)) { if (plate.plateType === 'dynamicPlate' || plateKey === 'homeslides' || plate.plateType === 'replenish') { continue; } const title = plate.title || plate.title_zh || ''; const desc = plate.desc || plate.desc_zh || ''; const iconSrc = plate.bg || 'assets/images/ui/da3cc931-0dcf-4556-a205-3ae8b59ceaea.png'; html += `
${title}
${title}
${desc || ''}
▶
`; if (plate.children) { for (const cat of plate.children) { const catTitle = cat.title || cat.title_zh || ''; html += `
${catTitle}
`; for (const item of cat.children || []) { const itemTitle = item.title || item.title_zh || ''; const activeCls = state.currentTopicId === item.id ? 'active' : ''; html += ` ${itemTitle} `; } html += `
`; } } html += `
`; } dom.sidebarScroll.innerHTML = html; } // Toggle Accordion in Sidebar function toggleAccordion(plateKey) { const body = document.getElementById(`plate-body-${plateKey}`); const header = body ? body.previousElementSibling : null; if (body && header) { body.classList.toggle('open'); header.classList.toggle('open'); } } // Render Welcome Hero function renderWelcomeView() { const lang = state.currentLang; const t = I18N[lang] || I18N.en; const welcome = state.welcome || {}; const isX5 = (state.currentCar === 'x5plus'); const defaultTitle = isX5 ? (lang === 'fa' ? 'راهنمای کاربری چانگان X5 پلاس ۲۰۲۶' : (lang === 'zh' ? '长安第二代 X5 PLUS 驾驶指南' : "Changan X5 PLUS 2026 Owner's Manual")) : (lang === 'fa' ? 'راهنمای کاربری چانگان CS55 پلاس' : (lang === 'zh' ? '长安第四代 CS55 PLUS 驾驶指南' : "Changan CS55 PLUS Owner's Manual")); const defaultSubtitle = isX5 ? (lang === 'fa' ? 'راهنمای جامع تعاملی، مشخصات فنی و ادوات کنترلی خودرو' : (lang === 'zh' ? '全功能互动车主指南与车辆技术规范' : "Comprehensive Driver, Controls & Operating Guide")) : (lang === 'fa' ? 'راهنمای جامع کاربری، مشخصات فنی و سرویس‌های دوره‌ای خودرو' : (lang === 'zh' ? '第四代全功能互动车主指南' : "Comprehensive Driver & Vehicle Operating Guide")); const title = welcome.title || defaultTitle; const subtitle = welcome.subtitle || defaultSubtitle; const defaultCarImg = isX5 ? 'assets/images/ui/x5plus_car_card.jpg' : 'assets/images/ui/cs55plus_car_card.jpg'; let carImg = welcome.img || defaultCarImg; if (carImg.startsWith('./static/content/images/')) { carImg = 'assets/images/ui/' + carImg.split('/').pop(); } const switchLink = isX5 ? '#switches-PG770285' : '#switches-PG725359'; const clusterLink = isX5 ? '#topic-PG770036' : '#topic-TT493534'; const warningLink = isX5 ? '#switches-PG770285' : '#switches-PG725437'; const drivingLink = isX5 ? '#topic-PG770071' : '#topic-TT482690'; const adasLink = isX5 ? '#topic-PG770128' : '#topic-TT482806'; const emergencyLink = isX5 ? '#topic-PG770238' : '#topic-TT482834'; dom.mainContent.innerHTML = `
${isX5 ? 'Changan X5 PLUS 2026' : 'Changan CS55 PLUS'}

${title}

${subtitle}

🎛️
${t.switchesTitle}
${t.switchesSubtitle}
🖥️
${t.clusterTitle}
${t.clusterSubtitle}
⚠️
${t.lampsTitle}
${t.lampsSubtitle}
🚗
${t.drivingTitle}
${t.drivingSubtitle}
🛡️
${t.adasTitle}
${t.adasSubtitle}
🆘
${t.emergencyTitle}
${t.emergencySubtitle}
${welcome.reminder || ''}
`; dom.mainContent.scrollTop = 0; } // Load and render a topic async function loadAndRenderTopic(topicId) { const lang = state.currentLang; const t = I18N[lang] || I18N.en; let topicData = state.contents[topicId]; if (!topicData) { dom.mainContent.innerHTML = `

${t.topicNotFound}

${t.topicNotFoundDesc}

${t.returnHome}
`; return; } // Identify surrounding topics for Next / Prev const currentIndex = state.allTopicsList.findIndex(item => item.id === topicId); const prevTopic = currentIndex > 0 ? state.allTopicsList[currentIndex - 1] : null; const nextTopic = currentIndex >= 0 && currentIndex < state.allTopicsList.length - 1 ? state.allTopicsList[currentIndex + 1] : null; const title = topicData.title || topicData.title_zh || ''; const subtitle = (lang !== 'zh' && topicData.title_zh) ? topicData.title_zh : ''; const cat = topicData.cat || topicData.cat_zh || ''; const htmlContent = (lang === 'zh') ? (topicData.html_zh || topicData.html) : (topicData.html || topicData.html_zh); // Expand parent plate in sidebar highlightActiveTopicInSidebar(topicId); dom.mainContent.innerHTML = `
${cat ? `${cat}` : ''} ${topicId}

${title}

${subtitle ? `
${subtitle}
` : ''}
${htmlContent || ''}
`; dom.mainContent.scrollTop = 0; } // Highlight active topic in sidebar function highlightActiveTopicInSidebar(topicId) { document.querySelectorAll('.topic-list-item').forEach(el => { el.classList.toggle('active', el.getAttribute('data-id') === topicId); }); const activeLink = document.querySelector(`.topic-list-item[data-id="${topicId}"]`); if (activeLink) { const plateBody = activeLink.closest('.plate-body'); if (plateBody && !plateBody.classList.contains('open')) { plateBody.classList.add('open'); const header = plateBody.previousElementSibling; if (header) header.classList.add('open'); } } } // Render Switches View function renderSwitchesView(switchId) { const lang = state.currentLang; const t = I18N[lang] || I18N.en; // Discover all switch modules dynamically let switchKeys = Object.keys(state.contents).filter(k => Array.isArray(state.contents[k]?.html)); if (switchKeys.length === 0) { switchKeys = (state.currentCar === 'x5plus') ? ['PG770285', 'PG770339', 'PG770376', 'PG770362', 'PG770370', 'PG770355', 'PG770320', 'PG770332', 'PG770390'] : ['PG725359', 'PG764631', 'PG764651', 'PG725383', 'PG725399', 'PG725409', 'PG725425', 'PG725437']; } const activeSwitchId = (switchId && state.contents[switchId]) ? switchId : switchKeys[0]; let tabsHtml = ''; for (const key of switchKeys) { const item = state.contents[key]; if (!item) continue; const title = item.title || item.title_zh || ''; const activeCls = (key === activeSwitchId) ? 'active' : ''; tabsHtml += ` `; } const currentSwitch = state.contents[activeSwitchId] || {}; const title = currentSwitch.title || currentSwitch.title_zh || ''; const cat = currentSwitch.cat || currentSwitch.cat_zh || ''; const buttons = currentSwitch.html || []; let cardsHtml = ''; for (const btn of buttons) { const btnTitle = btn.title || btn.title_zh || ''; const btnSub = btn.subTitle || btn.subTitle_zh || ''; const btnDetail = btn.detail || btn.detail_zh || ''; const bigImg = btn.bigImg ? `${btnTitle}` : ''; const subImg = btn.subImg ? `${btnTitle}` : ''; cardsHtml += `
${bigImg ? `
${bigImg}
` : ''}
${subImg}
${btnTitle}
${btnSub ? `
${btnSub}
` : ''}
${btnDetail}
`; } dom.mainContent.innerHTML = `
${cat || t.switchesTitle} ${switchId}

${title}

${tabsHtml}
${cardsHtml}
`; dom.mainContent.scrollTop = 0; } // Render Visual Index View function renderVisualIndexView() { const lang = state.currentLang; const t = I18N[lang] || I18N.en; const homeslide = state.plates['homeslides'] || {}; const imgList = homeslide.imgList || []; let sectionsHtml = ''; for (const sec of imgList) { const secTitle = sec.title || sec.title_zh || ''; const dots = sec.dots || []; let dotsHtml = ''; for (const d of dots) { const dotTitle = d.title || d.title_zh || ''; dotsHtml += ` 📍 ${dotTitle} `; } sectionsHtml += `

${secTitle}

${secTitle}
${dotsHtml}
`; } dom.mainContent.innerHTML = `

${t.visualTitle}

${t.visualSubtitle}
${sectionsHtml}
`; dom.mainContent.scrollTop = 0; } // Real-time Search Modal function openSearchModal(initialQuery = '') { if (!dom.searchModal) return; dom.searchModal.classList.add('open'); if (dom.searchModalInput) { dom.searchModalInput.value = initialQuery; dom.searchModalInput.focus(); executeSearch(initialQuery); } } function closeSearchModal() { if (dom.searchModal) dom.searchModal.classList.remove('open'); if (dom.headerSearchInput) dom.headerSearchInput.value = ''; } function executeSearch(query) { if (!dom.searchModalResults) return; const q = (query || '').trim().toLowerCase(); const lang = state.currentLang; const t = I18N[lang] || I18N.en; if (!q) { dom.searchModalResults.innerHTML = `
${t.searchEmpty}
`; return; } const results = []; const seenIds = new Set(); // 1. Search indexed topics (snippets, keywords, titles) if (state.searchIndex && state.searchIndex.length > 0) { for (const idxItem of state.searchIndex) { const title = (idxItem.title || '').toLowerCase(); const titleZh = (idxItem.title_zh || '').toLowerCase(); const keywords = (idxItem.keywords || '').toLowerCase(); const snippet = (idxItem.snippet || '').toLowerCase(); const cat = (idxItem.cat || '').toLowerCase(); let score = 0; if (title === q || titleZh === q) score += 100; else if (title.startsWith(q) || titleZh.startsWith(q)) score += 60; else if (title.includes(q) || titleZh.includes(q)) score += 40; else if (keywords.includes(q)) score += 30; else if (cat.includes(q)) score += 20; else if (snippet.includes(q)) score += 15; if (score > 0) { seenIds.add(idxItem.id); results.push({ id: idxItem.id, title: idxItem.title, title_zh: idxItem.title_zh, category: idxItem.cat, snippet: idxItem.snippet, score }); } } } // 2. Search allTopicsList fallback for (const item of state.allTopicsList) { if (seenIds.has(item.id)) continue; const title = (item.title || '').toLowerCase(); const titleZh = (item.title_zh || '').toLowerCase(); const cat = (item.category || '').toLowerCase(); let score = 0; if (title === q || titleZh === q) score += 100; else if (title.startsWith(q) || titleZh.startsWith(q)) score += 50; else if (title.includes(q) || titleZh.includes(q)) score += 30; else if (cat.includes(q)) score += 10; if (score > 0) { seenIds.add(item.id); results.push({ ...item, score }); } } // 3. Search switch buttons for (const [qid, item] of Object.entries(state.contents)) { if (item.dirname === 'quickentry' && Array.isArray(item.html)) { for (const btn of item.html) { const bTitle = (btn.title || '').toLowerCase(); const bTitleZh = (btn.title_zh || '').toLowerCase(); const bDetail = (btn.detail || '').toLowerCase(); if (bTitle.includes(q) || bTitleZh.includes(q) || bDetail.includes(q)) { results.push({ id: qid, isSwitch: true, title: btn.title, title_zh: btn.title_zh, category: item.title, snippet: btn.detail, score: 25 }); } } } } results.sort((a, b) => b.score - a.score); if (results.length === 0) { dom.searchModalResults.innerHTML = `
${t.searchNoResults(query)}
`; return; } let html = `
🚗 ${t.searchScope} ${results.length} results
`; for (const r of results.slice(0, 30)) { const displayTitle = r.title || r.title_zh || ''; const subTitle = (lang !== 'zh' && r.title_zh) ? r.title_zh : ''; const href = r.isSwitch ? `#switches-${r.id}` : `#topic-${r.id}`; html += `
${r.category || ''}
${highlightQuery(displayTitle, q)} ${subTitle ? `(${subTitle})` : ''}
${r.snippet ? `
${highlightQuery(r.snippet.slice(0, 160), q)}...
` : ''}
`; } dom.searchModalResults.innerHTML = html; } function highlightQuery(text, query) { if (!text || !query) return text || ''; const escaped = query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); const regex = new RegExp(`(${escaped})`, 'gi'); return text.replace(regex, '$1'); } // Lightbox Modal function openLightbox(src) { if (!dom.lightboxModal || !dom.lightboxImg) return; dom.lightboxImg.src = src; dom.lightboxModal.classList.add('open'); } function closeLightbox() { if (!dom.lightboxModal) return; dom.lightboxModal.classList.remove('open'); if (dom.lightboxImg) dom.lightboxImg.src = ''; } // Expose global methods window.app = { init, setLanguage, toggleAccordion, closeSearchModal, openLightbox, closeLightbox, navigateToTopic: (tid) => { location.hash = `#topic-${tid}`; } }; // Start app on DOMContentLoaded if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();