Last active
January 22, 2025 23:15
-
-
Save marcos-velez/e945b417bd5f2dede28fa11bb83a51b3 to your computer and use it in GitHub Desktop.
This bookmarklet generates a clean and simple UI to browse real-time PATH train arrivals. Information is refreshed every 30 seconds.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 1. Paste this entire gist over at https://mrcoles.com/bookmarklet/ to generate a bookmarklet */ | |
/* 2. If desired, update the default PATH station code and heading [line #9 below, but refer to line 12 for station codes */ | |
/* 3. Use a meaningful (or fun!) name, like: "Simple PATH Times" or "🚊 Arrivals" */ | |
/* 4. Drag the generated bookmarklet link to your Bookmarks Toolbar */ | |
/* 6. Enjoy the clean, simple UI to browse PATH arrivals information */ | |
function(){ | |
sta = 'EXP'; dir = 'NY'; | |
let da = ['NJ', 'NY']; | |
let sa = new Map([["NWK", [0, "Newark"]], ["HAR", [1, "Harrison"]], ["JSQ", [2, "Journal Square"]], ["GRV", [3, "Grove Street"]], ["NEW", [4, "Newport / Pavonia"]], ["EXP", [5, "Exchange Place"]], ["HOB", [6, "Hoboken"]], ["WTC", [7, "World Trade Center"]], ["CHR", [8, "Christopher Street"]], ["09S", [9, "9th Street"]], ["14S", [10, "14th Street"]], ["23S", [11, "23rd Street"]], ["33S", [12, "33rd Street"]]]); | |
w = window; d = w.document; b = d.body; u = 'https://www.panynj.gov/bin/portauthority/ridepath.json'; | |
if (w.location.href.split('#')[0] != u) {alert('To use this bookmarklet, you must first navigate to:\n' + u + '\n\nYou will be taken there now. Once the page loads, click the bookmarklet again.' ); w.location.href = u; return; } | |
w.gei = function(i) { return d.getElementById(i); }; | |
w.rtt = function() { s = gei("ss").value; h = gei("sd").selectedIndex; jt = gei("jo").textContent; tt = ""; try { jd = JSON.parse(jt); if ((jd.results[s].destinations.length == 1) && (jd.results[s].destinations[0].label == "ToNY")) { h ^= 1; } jd.results[s].destinations[h].messages.forEach(t => {tt += `<tr><td class="sw"><div class="sw ci c${t.lineColor.split(',')[0]}"></div></td><td class="sw"><div class="sw ci c${t.lineColor.split(',')[1]}"></div></td><td class="sta">${t.headSign.replace(/via Hoboken/i, "(via Hoboken)")}</td><td class="at">${t.arrivalTimeMessage}</td></tr>`;});} catch { tt = '<tr><td colspan="4"><br />No results based on selected criteria</td></tr>'; } gei("tt").innerHTML = tts + tt + "</table>";}; | |
w.gjd = function() { fetch(u).then(response => response.text()).then(data => {gei("jo").textContent = data; gei("p2").textContent = 'Last updated on ' + (new Date()).toLocaleString().replace(', ', ' at '); iid=gei("iid").value; if (iid) { clearInterval(iid); } st(30); rtt();}).catch(error => console.error("Encountered an unexpected error when refreshing the train data! Error details: ", error)); }; | |
w.st = function(t) { tl = t - 1; gei('iid').value = setInterval(function () { gei('s1').textContent = tl; if (--tl < 1) { gjd(); tl = t;}}, 1000);}; | |
iid = gei("iid"); if (iid && (iid.value)) { clearInterval(iid.value); } | |
o = 'option'; se = 'select'; | |
let ss = `<${se} id="ss">`; sa.forEach((v, k) => {ss += `<${o} value="${v[0]}"` + ((k == sta) ? ' selected' : '') + `>${v[1]}</${o}>`;}); ss += `</${se}>`; | |
let sd = `<${se} id="sd">`; da.forEach(d => {sd += `<${o} value="${d}"` + ((d == dir) ? ' selected' : '') + `>${d}</${o}>`;}); sd += `</${se}>`; | |
let m = '<style> .sta {width: 250px; padding-left: 4px;} .at {width: 100px;} .sw {width: 8px;} .ci {height: 8px; border-radius: 50%;} .c4D92FB {background-color: #4D92FB;} .cFF9900 {background-color: #FF9900;} .cD93A30 {background-color: #D93A30;} .c65C100 {background-color: #65C100;} body, div, select, table, td, div, span, p {font: 9pt Consolas, Courier;} #p2 {font: italic 8pt Consolas, Courier;} table {border: 0;} td {padding: 0px;} @media only screen and (max-device-width: 480px) { .sta {width: 300px; padding-left: 4px;} td {font-size: 12pt;} }</style>'; | |
m += '\nTrains from ' + ss + ' towards ' + sd; | |
m += '<br /><br />' | |
m += '<span id="tt"></span>'; | |
tts = '<table>'; | |
tts += '<tr><td colspan="3" style="width: 270px;">Train to</td><td class="at">Arrives in</td></tr>'; | |
tts += '<tr><td colspan="3" style="width: 270px;">--------</td><td class="at">----------</td></tr>'; | |
b.innerHTML = m + '<br /><p id="p1">Train data will be refreshed in <span id="s1">30</span> seconds, or you can <a id="a1" href="#" onclick="gjd();">refresh it now</a>.</p><p id="p2"></p><input id="iid" type="hidden" value="" /><script id="jo" type="application/json">' + (gei("jo") ? gei("jo") : b).textContent + '</script>'; | |
rtt(); st(30); | |
d.querySelectorAll("select").forEach(e => {e.addEventListener('change', rtt);}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment