/* 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 += `
${t.headSign.replace(/via Hoboken/i, "(via Hoboken)")}${t.arrivalTimeMessage}`;});} catch { tt = '
No results based on selected criteria'; } gei("tt").innerHTML = tts + tt + "";}; 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]}`;}); ss += ``; let sd = `<${se} id="sd">`; da.forEach(d => {sd += `<${o} value="${d}"` + ((d == dir) ? ' selected' : '') + `>${d}`;}); sd += ``; let m = ''; m += '\nTrains from ' + ss + ' towards ' + sd; m += '

' m += ''; tts = ''; tts += ''; tts += ''; b.innerHTML = m + '

Train data will be refreshed in 30 seconds, or you can refresh it now.

'; rtt(); st(30); d.querySelectorAll("select").forEach(e => {e.addEventListener('change', rtt);}); }
Train toArrives in
------------------