Search metro route, stations, & nearby
Filter by city
Loading cities…
Recently viewed
Your saved routes
' + esc(I18N.couldntLoadCities) + '
';
});
}
function highlightCityChip() {
cityChipEls.forEach(function (btn) {
var on = btn.dataset.city === activeCity;
btn.style.background = on ? '#ede9fe' : '#f8fafc';
btn.style.color = on ? '#5D4DA8' : '#475569';
btn.style.borderColor = on ? '#5D4DA8' : '#e2e8f0';
btn.style.fontWeight = on ? '700' : '500';
});
}
function applyCity(city) {
activeCity = city;
setCity(city);
if (city) {
activeCityName.textContent = city;
activeCityChip.classList.remove('d-none');
activeCityChip.style.display = 'inline-flex';
} else {
activeCityChip.classList.add('d-none');
activeCityChip.style.display = 'none';
}
highlightCityChip();
if (input.value.trim().length >= 2) triggerSearch(input.value.trim());
}
activeCityChip.addEventListener('click', function (e) {
e.stopPropagation();
applyCity('');
input.focus();
});
// ── Recently viewed (reads what page-footer.php already writes) ─────────
function renderRecent() {
var items = getRecent();
if (!items.length) { recentSection.classList.add('d-none'); return; }
recentSection.classList.remove('d-none');
recentList.innerHTML = '';
items.slice(0, 5).forEach(function (item) {
var m = typeMeta(item.type);
var a = document.createElement('a');
a.href = item.url;
a.className = 'text-decoration-none d-flex align-items-center gap-2 py-2 px-1 rounded-2';
a.style.cssText = 'color:#334155;font-size:.875rem;transition:background .12s';
a.onmouseover = function () { this.style.background = '#f8fafc'; };
a.onmouseout = function () { this.style.background = 'transparent'; };
a.innerHTML =
'' +
'' + esc(item.title) + '' +
(item.city ? '' + esc(item.city) + '' : '') +
'';
recentList.appendChild(a);
});
}
// ── Saved routes (reads window.YoMetroSavedRoutes, already implemented) ──
function renderSaved() {
var routes = getSaved();
if (!routes.length) { savedSection.classList.add('d-none'); return; }
savedSection.classList.remove('d-none');
savedList.innerHTML = '';
routes.slice(0, 3).forEach(function (r) {
var a = document.createElement('a');
a.href = r.url;
a.className = 'text-decoration-none d-flex align-items-center gap-2 py-2 px-1 rounded-2';
a.style.cssText = 'color:#334155;font-size:.875rem;transition:background .12s';
a.onmouseover = function () { this.style.background = '#f8fafc'; };
a.onmouseout = function () { this.style.background = 'transparent'; };
a.innerHTML =
'' +
'' + esc(r.fromName) + ' → ' + esc(r.toName) + '' +
'' + esc(r.networkShortName || '') + '';
savedList.appendChild(a);
});
if (routes.length > 3) {
var more = document.createElement('button');
more.type = 'button';
more.className = 'btn btn-link btn-sm p-0 mt-1 text-purple text-decoration-none';
more.style.fontSize = '.78rem';
more.textContent = '+ ' + (routes.length - 3) + ' ' + I18N.moreSavedSuffix;
more.onclick = function () {
var drawer = document.getElementById('savedRoutesDrawer');
if (drawer && window.bootstrap) window.bootstrap.Offcanvas.getOrCreateInstance(drawer).show();
closeDropdown();
};
savedList.appendChild(more);
}
}
// ── Dropdown open/close ───────────────────────────────────────────────────
function openDropdown() {
if (dropdownOpen) return;
dropdownOpen = true;
dropdown.classList.remove('d-none');
input.setAttribute('aria-expanded', 'true');
}
function closeDropdown() {
dropdownOpen = false;
dropdown.classList.add('d-none');
input.setAttribute('aria-expanded', 'false');
defaultPane.classList.remove('d-none');
resultsPane.classList.add('d-none');
}
function showDefaultPane() {
renderRecent();
renderSaved();
defaultPane.classList.remove('d-none');
resultsPane.classList.add('d-none');
openDropdown();
}
// ── Search — parallel Strapi queries across the three real entity types ──
var activeAbort = null;
function buildStationUrl(q) {
var url = STRAPI_BASE + '/api/' + "metro-stations" + '?fields[0]=name&fields[1]=slug&populate[city][fields][0]=name'
+ '&populate[metro_network][fields][0]=zone_id'
+ '&filters[name][$containsi]=' + encodeURIComponent(q)
+ '&pagination[pageSize]=5';
if (activeCity) url += '&filters[city][name][$eq]=' + encodeURIComponent(activeCity);
return url;
}
function buildNeighborhoodUrl(q) {
var url = STRAPI_BASE + '/api/' + "neighborhoods" + '?fields[0]=name&fields[1]=slug&populate[city][fields][0]=name'
+ '&populate[city][populate][metro_networks][fields][0]=zone_id'
+ '&populate[city][populate][metro_networks][fields][1]=network_status'
+ '&filters[name][$containsi]=' + encodeURIComponent(q)
+ '&pagination[pageSize]=5';
if (activeCity) url += '&filters[city][name][$eq]=' + encodeURIComponent(activeCity);
return url;
}
function buildAttractionUrl(q) {
var url = STRAPI_BASE + '/api/' + "attractions" + '?fields[0]=name&fields[1]=slug&populate[city][fields][0]=name'
+ '&filters[name][$containsi]=' + encodeURIComponent(q)
+ '&filters[active][$eq]=true'
+ '&pagination[pageSize]=5';
if (activeCity) url += '&filters[city][name][$eq]=' + encodeURIComponent(activeCity);
return url;
}
function triggerSearch(query) {
clearTimeout(debounceTimer);
if (activeAbort) { activeAbort.abort(); activeAbort = null; }
defaultPane.classList.add('d-none');
resultsPane.classList.remove('d-none');
resultsList.innerHTML =
'' +
'' + esc(I18N.searching) + '
';
openDropdown();
debounceTimer = setTimeout(function () {
var controller = new AbortController();
activeAbort = controller;
Promise.all([
fetch(buildStationUrl(query), { signal: controller.signal }).then(function (r) { return r.json(); }).catch(function () { return { data: [] }; }),
fetch(buildNeighborhoodUrl(query), { signal: controller.signal }).then(function (r) { return r.json(); }).catch(function () { return { data: [] }; }),
fetch(buildAttractionUrl(query), { signal: controller.signal }).then(function (r) { return r.json(); }).catch(function () { return { data: [] }; })
]).then(function (results) {
activeAbort = null;
var stations = (results[0].data || []).map(function (s) {
var zoneId = (s.metro_network && s.metro_network.zone_id != null) ? s.metro_network.zone_id : null;
return { type: 'station', name: s.name, city: s.city?.name || '', url: localeUrl('/' + s.slug, zoneId) };
});
var neighborhoods = (results[1].data || []).map(function (n) {
// Neighborhoods have no direct network relation — resolve zone_id
// via the city's metro_networks (first active one), same
// convention as nearby-search.php's $_nsCityZoneById.
var cityNetworks = (n.city && n.city.metro_networks) || [];
var activeNet = cityNetworks.find(function (net) { return net.network_status === 'active'; });
var zoneId = activeNet ? activeNet.zone_id : null;
return { type: 'nearby', name: n.name, city: n.city?.name || '', url: localeUrl('/metro-station-near-' + n.slug, zoneId) };
});
var attractions = (results[2].data || []).map(function (a) {
// travel-guide is an EN-only page bucket (see forceEnglishLinkTo() /
// static.php's EN-only split) — always unprefixed, regardless of
// the current locale, unlike the station/nearby results above.
return { type: 'attraction', name: a.name, city: a.city?.name || '', url: BASE_PATH + '/travel-guide/attraction-' + a.slug };
});
renderResults(query, stations.concat(neighborhoods, attractions));
}).catch(function (err) {
if (err.name === 'AbortError') return;
resultsList.innerHTML = '' + esc(I18N.searchUnavailable) + '
'; }); }, 280); } function renderResults(query, items) { resultsList.innerHTML = ''; if (!items.length) { var clearFilterHtml = I18N.clearFilterSentence.replace('{city}', '' + esc(activeCity) + ''); resultsList.innerHTML = '' +
'' +
'
';
return;
}
var order = ['station', 'nearby', 'attraction'];
var grouped = {};
items.forEach(function (item) {
if (!grouped[item.type]) grouped[item.type] = [];
grouped[item.type].push(item);
});
order.forEach(function (type) {
var group = grouped[type];
if (!group || !group.length) return;
var m = typeMeta(type);
var label = document.createElement('div');
label.style.cssText = 'padding:6px 12px 2px;font-size:.68rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:#94a3b8;';
label.textContent = m.label + 's'; // English pluralization; translated labels may already be plural-appropriate in their own language
resultsList.appendChild(label);
group.forEach(function (item) {
var a = document.createElement('a');
a.href = item.url;
a.className = 'd-flex align-items-center gap-2 text-decoration-none px-3 py-2';
a.style.cssText = 'color:#1e293b;font-size:.875rem;transition:background .12s;border-bottom:1px solid #f1f5f9';
a.onmouseover = function () { this.style.background = '#f0eeff'; };
a.onmouseout = function () { this.style.background = 'transparent'; };
var escapedQuery = query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
var highlighted = esc(item.name).replace(new RegExp('(' + escapedQuery + ')', 'gi'),
'$1');
a.innerHTML =
'' +
'' + highlighted + '' +
(item.city ? '' + esc(item.city) + '' : '') +
'';
a.addEventListener('click', function () {
// Pre-emptive write so it shows on return to home even before the
// destination page's own page-footer.php tracker fires — same
// shape/key so it dedupes cleanly either way.
try {
var list = getRecent().filter(function (r) { return r.url !== item.url; });
list.unshift({ url: item.url, title: item.name, type: item.type, city: item.city, ts: Date.now() });
lsSet(LS_RECENT, list.slice(0, 8));
} catch (e) {}
// GA4/GTM tracking — one push per search result actually clicked
// (the meaningful "search succeeded" signal here, since this box
// fires a live query on every keystroke — tracking each query
// would be noise, not signal).
try {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'ym_home_search_result_click',
search_query: query,
result_type: item.type,
result_name: item.name,
city_filter: activeCity || null
});
} catch (e) {}
});
resultsList.appendChild(a);
});
});
}
// ── Input events ──────────────────────────────────────────────────────────
input.addEventListener('focus', function () {
if (this.value.trim().length >= 2) triggerSearch(this.value.trim());
else showDefaultPane();
});
input.addEventListener('input', function () {
var q = this.value.trim();
clearBtn.classList.toggle('d-none', q.length === 0);
if (q.length === 0) showDefaultPane();
else if (q.length >= 2) triggerSearch(q);
});
clearBtn.addEventListener('click', function (e) {
e.stopPropagation();
clearTimeout(debounceTimer);
if (activeAbort) { activeAbort.abort(); activeAbort = null; }
input.value = '';
clearBtn.classList.add('d-none');
showDefaultPane();
input.focus();
});
document.addEventListener('click', function (e) {
if (!dropdown.contains(e.target) && e.target !== input && !activeCityChip.contains(e.target)) closeDropdown();
});
input.addEventListener('keydown', function (e) {
if (e.key === 'Escape') { closeDropdown(); input.blur(); }
});
// ── Init ──────────────────────────────────────────────────────────────────
loadCityChips();
if (activeCity) applyCity(activeCity);
})();
' + esc(I18N.noResultsPrefix) + ' ' + esc(query) + '
' + (activeCity ? '' + clearFilterHtml + '
' : '' + esc(I18N.tryStationPlace) + '
') + '22+
Metro Networks
50+
Metro Lines
830+
Metro Stations
90k+
Metro Routes
- Keep yourself before yellow line before boarding (generally all platform have it).
- Keep gap and distance from doors to allow other passengers to board the train.
- If Station staff suggest something please follow the instructions.
- Take care of your loose items like Saree, Dupatta, Dhoti and Bag etc. while boarding and de-boarding the train.
- Take care of your Bag/Purse/Luggage/Mobile while traveling or waiting at metro stations.
- Inform train operator in case any passenger/article stuck between train doors by pressing Passenger Emergency Alarm button/Handle.
- Take care and keep eye on the children & infants while traveling with them.
- Do not push co-passengers while boarding or de-boarding.
- Do not make noise or play music openly in train and metro premise.
- Do not fight with other passengers, if there is any issue get help from metro security.
- Do not try to enter/exit when train doors are being close. better late than never.
- Do not obstruct the closing of the train doors.
- Show your metro smart card or token at the entry gate or exit gate for the opening of flaps.
- Use of smart card gives you 10% discount on travel fee.
- Please ensure that entry or exit with a travel smart card was followed by a valid the system. In case of mismatch penalty will be payable as per business rule of metro department.
- Carrying token beyond exit gate is a punishable offence and attracts a fine or imprisonment.
- The refund of unused token can be returned within 60 minutes of purchase from purchasing station only.
- Kolkata Metro: First Metro in India First metro in India. It is first in India to have the third rail for power supply and the first to use fully metro coaches made in India by ICF & BEML.
- Delhi Metro: Largest Metro System in India India's largest rapid transit/metro system. Having constructed a massive network of about 389 Km with 285 stations (including NOIDA-Greater NOIDA Corridor and Rapid Metro, Gurugram).
- Rapid Metro Gurgaon: Fully Privately Financed India's first fully privately financed metro. Currently undertaken by Delhi Metro.
- Noida Metro: Operated under Delhi Metro Currently undertaken by Delhi Metro, contracted for one year to operate.
- Namma Metro: First metro in southern India First metro in southern India, the first to have the third rail for power supply in southern India, and the first to introduce Wi-Fi onboard trains.
- Mumbai Metro: India's first PPP Metro India's first public private partnership (PPP) metro system with Reliance group. 14 lines and line extensions are at different stages of execution.
- Jaipur Metro: Double Storey Elevated Double-story elevated road and Metro track project for the first time in the country.
- Chennai Metro - Connects Two lines through loop line First metro rail in the country to connect two lines (blue & green) through loop line to run direct service from the airport to central even though had interchange station at Alandur. First metro in India for underground stations with sliding doors.
- Kochi Metro: India's first CBTC metro system First Indian metro to go live with CBTC (communication-based train control ) signalling.
- Lucknow Metro: Fastest built and commissioned metro system in the world The fastest built and commissioned metro system in the world. Construction of the line begun on 27 September 2014 with the 8.5 km and began its commercial operation on 5 September 2017, making it the fastest built metro rail system in the country.
- Hyderabad Metro: India's First Driver less metro India's first metro to have CBTC and integrated telecommunications and supervision systems, i.e. driver less metro.