/** * 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 += `
${subtitle}