From 68aeb4a997a99ac7dde426ad7a3c87205b4f89d2 Mon Sep 17 00:00:00 2001 From: Jacek Kowalski <Jacek@jacekk.info> Date: Wed, 12 Apr 2017 21:00:38 +0000 Subject: [PATCH] Replace "Lines" table with tram schedule function --- index.js | 249 +++++++----------------------- common.js | 141 +++++++++++++++++ lang_en.js | 1 index.html | 10 proxy.php | 22 ++ README.md | 3 lang_pl.js | 1 7 files changed, 230 insertions(+), 197 deletions(-) diff --git a/README.md b/README.md index 47500c6..be8188f 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,9 @@ - yellow - delayed 4 or more minutes, - red - delayed 10 or more minutes. +Clicking on the table row loads the schedule for the selected tram +- listing next stops and predicted departure times for each one. + ### Auto-refresh The list is automatically updated every 20 seconds. It is possible to manually diff --git a/common.js b/common.js new file mode 100644 index 0000000..bd564a6 --- /dev/null +++ b/common.js @@ -0,0 +1,141 @@ +// Special directions +var special_directions = { + 'Zajezdnia Nowa Huta' : 'NH', + 'Zajezdnia Podgórze' : 'P', +}; + +// Webservice-related functions +function parseVehicle(vehicleId) { + if(!vehicleId) return; + if(vehicleId.substr(0, 15) != '635218529567218') { + console.log('Unknown vehicle, vehicleId=' + vehicleId); + return; + } + + var id = parseInt(vehicleId.substr(15)) - 736; + var prefix; + var type; + var low; // low floor: 0 = no, 1 - semi, 2 - full + + // Single exception - old id used in one case + if(id == 831) { + id = 216; + } + + if(101 <= id && id <= 173) { + prefix = 'HW'; + type = 'E1'; + low = 0; + + if((108 <= id && id <= 113) || id == 127 || id == 131 || id == 132 || id == 134 || (137 <= id && id <= 139) || (148 <= id && id <= 150) || (153 <= id && id <= 166) || id == 161) { + prefix = 'RW'; + } + } else if(201 <= id && id <= 293) { + prefix = 'RZ'; + type = '105Na'; + low = 0; + + if(246 <= id) { + prefix = 'HZ'; + } + if(id == 290) { + type = '105Nb'; + } + } else if(301 <= id && id <= 328) { + prefix = 'RF'; + type = 'GT8S'; + low = 0; + + if(id == 313) { + type = 'GT8C' + low = 1; + } + } else if(401 <= id && id <= 440) { + prefix = 'HL'; + type = 'EU8N'; + low = 1; + } else if(451 <= id && id <= 462) { + prefix = 'HK'; + type = 'N8S-NF'; + low = 0; + + if((451 <= id && id <= 453) || id == 462) { + type = 'N8C-NF'; + low = 1; + } + } else if(601 <= id && id <= 650) { + prefix = 'RP'; + type = 'NGT6 (3)'; + low = 2; + + if(id <= 613) { + type = 'NGT6 (1)'; + } else if (id <= 626) { + type = 'NGT6 (2)'; + } + } else if(801 <= id && id <= 824) { + prefix = 'RY'; + type = 'NGT8'; + low = 2; + } else if(id == 899) { + prefix = 'RY'; + type = '126N'; + low = 2; + } else if(901 <= id && id <= 936) { + prefix = 'RG'; + type = '2014N'; + low = 2; + + if(915 <= id) { + prefix = 'HG'; + } + } else if(id === 999) { + prefix = 'HX'; + type = '405N-Kr'; + low = 1; + } else { + console.log('Unknown vehicle, vehicleId=' + vehicleId + ', id=' + id); + return; + } + + return { + vehicleId: vehicleId, + prefix: prefix, + id: id, + num: prefix + id, + type: type, + low: low + }; +} + +// Element mangling +function deleteChildren(element) { + while(element.lastChild) element.removeChild(element.lastChild); +} + +function addElementWithText(parent, element, text) { + var elem = document.createElement(element); + elem.appendChild(document.createTextNode(text)); + parent.appendChild(elem); + return elem; +} + +function addCellWithText(parent, text) { + return addElementWithText(parent, 'td', text); +} + +function addParaWithText(parent, text) { + return addElementWithText(parent, 'p', text); +} + +function setText(element, text) { + deleteChildren(element); + element.appendChild(document.createTextNode(text)); +} + +// Other functions +var decodeEntitiesTextArea = document.createElement('textarea'); +function decodeEntities(text) { + decodeEntitiesTextArea.innerHTML = text; + return decodeEntitiesTextArea.value; +} diff --git a/index.html b/index.html index 6e13172..56850eb 100644 --- a/index.html +++ b/index.html @@ -66,6 +66,7 @@ </table> </div> <div class="col-md-6"> + <!-- <h3 data-translate="header_lines">Lines</h3> <table class="table table-condensed"> @@ -79,21 +80,21 @@ <tbody id="times-lines"> </tbody> </table> + --> - <!-- + <p data-translate="help_click_for_schedule">Click on an entry in the departures timetable to see the tram's schedule.</p> + <h3 id="route-line"></h3> <table class="table table-condensed"> <thead> <tr> - <th>Stop</th> + <th>Time</th> <th>Stop</th> </tr> </thead> <tbody id="route-table"> - </tbody> </table> - --> <p class="small"> <span data-translate="help_legend">Legend:</span> @@ -119,6 +120,7 @@ </div> <script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha384-3ceskX3iaEnIogmQchP8opvBy3Mi7Ce34nWjpBIwVTHfGYWQS9jwHDVRnpKKHJg7" crossorigin="anonymous"></script> <script tyle="text/javascript" src="lang_en.js" id="lang_script"></script> + <script tyle="text/javascript" src="common.js"></script> <script type="text/javascript" src="index.js"></script> </body> </html> diff --git a/index.js b/index.js index a909e8e..a5aba2b 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,4 @@ -//var ttss_base = 'http://www.ttss.krakow.pl/internetservice/services'; +//var ttss_base = 'http://www.ttss.krakow.pl/internetservice'; var ttss_base = '/proxy.php'; var ttss_refresh = 20000; // 20 seconds @@ -7,7 +7,7 @@ var language = 'en'; var lang_select = document.getElementById('lang-select'); -var stop_id = ''; +var stop_id; var stop_name = document.getElementById('stop-name'); var stop_name_form = stop_name.form; var stop_name_autocomplete = document.getElementById('stop-name-autocomplete'); @@ -19,13 +19,12 @@ var times_stop_name = document.getElementById('times-stop-name'); var times_alerts = document.getElementById('times-alerts'); var times_table = document.getElementById('times-table'); -var times_lines = document.getElementById('times-lines'); +//var times_lines = document.getElementById('times-lines'); -/* +var route_id; var route_xhr; var route_line = document.getElementById('route-line'); var route_table = document.getElementById('route-table'); -*/ var refresh_button = document.getElementById('refresh'); var refresh_text = document.getElementById('refresh-text'); @@ -83,109 +82,6 @@ return lang.time_minutes_prefix + ((actual.getTime() - planned.getTime()) / 1000 / 60) + lang.time_minutes_suffix; } -function parseVehicle(vehicleId) { - if(!vehicleId) return; - if(vehicleId.substr(0, 15) != '635218529567218') { - console.log('Unknown vehicle, vehicleId=' + vehicleId); - return; - } - - var id = parseInt(vehicleId.substr(15)) - 736; - var prefix; - var type; - var low; // low floor: 0 = no, 1 - semi, 2 - full - - // Single exception - old id used in one case - if(id == 831) { - id = 216; - } - - if(101 <= id && id <= 173) { - prefix = 'HW'; - type = 'E1'; - low = 0; - - if((108 <= id && id <= 113) || id == 127 || id == 131 || id == 132 || id == 134 || (137 <= id && id <= 139) || (148 <= id && id <= 150) || (153 <= id && id <= 166) || id == 161) { - prefix = 'RW'; - } - } else if(201 <= id && id <= 293) { - prefix = 'RZ'; - type = '105Na'; - low = 0; - - if(246 <= id) { - prefix = 'HZ'; - } - if(id == 290) { - type = '105Nb'; - } - } else if(301 <= id && id <= 328) { - prefix = 'RF'; - type = 'GT8S'; - low = 0; - - if(id == 313) { - type = 'GT8C' - low = 1; - } - } else if(401 <= id && id <= 440) { - prefix = 'HL'; - type = 'EU8N'; - low = 1; - } else if(451 <= id && id <= 462) { - prefix = 'HK'; - type = 'N8S-NF'; - low = 0; - - if((451 <= id && id <= 453) || id == 462) { - type = 'N8C-NF'; - low = 1; - } - } else if(601 <= id && id <= 650) { - prefix = 'RP'; - type = 'NGT6 (3)'; - low = 2; - - if(id <= 613) { - type = 'NGT6 (1)'; - } else if (id <= 626) { - type = 'NGT6 (2)'; - } - } else if(801 <= id && id <= 824) { - prefix = 'RY'; - type = 'NGT8'; - low = 2; - } else if(id == 899) { - prefix = 'RY'; - type = '126N'; - low = 2; - } else if(901 <= id && id <= 936) { - prefix = 'RG'; - type = '2014N'; - low = 2; - - if(915 <= id) { - prefix = 'HG'; - } - } else if(id === 999) { - prefix = 'HX'; - type = '405N-Kr'; - low = 1; - } else { - console.log('Unknown vehicle, vehicleId=' + vehicleId + ', id=' + id); - return; - } - - return { - vehicleId: vehicleId, - prefix: prefix, - id: id, - num: prefix + id, - type: type, - low: low - }; -} - function displayVehicle(vehicleInfo) { if(!vehicleInfo) return document.createTextNode(''); @@ -210,30 +106,6 @@ .replace('$floor', floor_type); return span; -} - -function deleteChildren(element) { - while(element.lastChild) element.removeChild(element.lastChild); -} - -function addElementWithText(parent, element, text) { - var elem = document.createElement(element); - elem.appendChild(document.createTextNode(text)); - parent.appendChild(elem); - return elem; -} - -function addCellWithText(parent, text) { - return addElementWithText(parent, 'td', text); -} - -function addParaWithText(parent, text) { - return addElementWithText(parent, 'p', text); -} - -function setText(element, text) { - deleteChildren(element); - element.appendChild(document.createTextNode(text)); } function fail(message, more) { @@ -271,21 +143,21 @@ nav.className = nav.className.replace(' loading', ''); } -function loadTimes(stopId, clearRoute) { +function loadTimes(stopId) { if(!stopId) stopId = stop_id; if(!stopId) return; if(times_timer) clearTimeout(times_timer); if(times_xhr) times_xhr.abort(); - console.log('loadTimes(' + stopId + ', ' + clearRoute + ')'); + console.log('loadTimes(' + stopId + ')'); window.location.hash = '#!' + language + stop_id; refresh_button.removeAttribute('disabled'); loading_start(); times_xhr = $.get( - ttss_base + '/passageInfo/stopPassages/stop' + ttss_base + '/services/passageInfo/stopPassages/stop' + '?stop=' + encodeURIComponent(stopId) + '&mode=departure' ).done(function(data) { @@ -293,13 +165,7 @@ setText(page_title, lang.page_title_stop_name.replace('$stop', data.stopName)); deleteChildren(times_alerts); deleteChildren(times_table); - deleteChildren(times_lines); - /* - if(clearRoute) { - deleteChildren(route_line); - deleteChildren(route_table); - } - */ + //deleteChildren(times_lines); for(var i = 0, il = data.generalAlerts.length; i < il; i++) { addParaWithText(times_alerts, data.generalAlerts[i].title); @@ -315,6 +181,7 @@ addCellWithText(tr, ''); tr.className = 'active'; + tr.addEventListener('click', function(tripId){ return function(){ loadRoute(tripId); } }(data.old[i].tripId) ); times_table.appendChild(tr); } @@ -337,60 +204,69 @@ } else if(parseInt(delay) > 3) { tr.className = 'warning'; } + + tr.addEventListener('click', function(tripId){ return function(){ loadRoute(tripId); } }(data.actual[i].tripId) ); times_table.appendChild(tr); } + /* for(var i = 0, il = data.routes.length; i < il; i++) { var tr = document.createElement('tr'); addCellWithText(tr, data.routes[i].name); addCellWithText(tr, data.routes[i].directions.join(' - ')); addCellWithText(tr, data.routes[i].authority); - - /* - tr.addEventListener('click', function(routeId, routeTr){ return function(e) { - var trs = tr.parentNode; - for(var i = 0; i < trs.childNodes.length; i++) { - trs.childNodes[i].removeAttribute('class'); - } - routeTr.className = 'warning'; - - if(route_xhr) route_xhr.abort(); - route_xhr = $.get( - ttss_base + '/routeInfo/routeStops' - + '?routeId=' + encodeURIComponent(routeId) - ).done(function(data) { - setText(route_line, data.route.name + ': ' - + data.route.directions.join(' - ')); - deleteChildren(route_table); - - routeTr.className = 'success'; - - for(var i = 0, il = data.stops.length; i < il; i++) { - var tr = document.createElement('tr'); - addCellWithText(tr, data.stops[i].name); - route_table.appendChild(tr); - } - }).fail(fail_ajax); - }}(data.routes[i].id, tr)); - */ - times_lines.appendChild(tr); - - for(var j = 0, jl = data.routes[i].alerts.length; j < jl; j++) { - addParaWithText( - times_alerts, - lang.line_alert_pattern - .replace('$line', data.routes[i].name) - .replace('$alert', data.routes[i].alerts[j].title) - ); - } } + */ startTimer(new Date()); fail_hide(); - times_timer = setTimeout(function(){ loadTimes(); }, ttss_refresh); + times_timer = setTimeout(function(){ loadTimes(); loadRoute(); }, ttss_refresh); }).fail(fail_ajax).always(loading_end); +} + +function loadRoute(tripId) { + if(!tripId) tripId = route_id; + if(!tripId) return; + + console.log('loadRoute(' + tripId + ')'); + route_id = tripId; + + if(route_xhr) route_xhr.abort(); + route_xhr = $.get( + ttss_base + '/services/tripInfo/tripPassages' + + '?tripId=' + encodeURIComponent(tripId) + + '&mode=departure' + ).done(function(data) { + if(!data.routeName || !data.directionText || data.old.length + data.actual.length == 0) { + route_id = null; + return; + } + + setText(route_line, data.routeName + ' ' + data.directionText); + deleteChildren(route_table); + + for(var i = 0, il = data.old.length; i < il; i++) { + var tr = document.createElement('tr'); + addCellWithText(tr, data.old[i].actualTime || data.old[i].plannedTime); + addCellWithText(tr, data.old[i].stop_seq_num + '. ' + data.old[i].stop.name); + + tr.className = 'active'; + route_table.appendChild(tr); + } + + for(var i = 0, il = data.actual.length; i < il; i++) { + var tr = document.createElement('tr'); + addCellWithText(tr, data.actual[i].actualTime || data.actual[i].plannedTime); + addCellWithText(tr, data.actual[i].stop_seq_num + '. ' + data.actual[i].stop.name); + + if(data.actual[i].status == 'STOPPING') { + tr.className = 'success'; + } + route_table.appendChild(tr); + } + }).fail(fail_ajax); } function startTimer(date) { @@ -426,12 +302,6 @@ )); } }, interval); -} - -var decodeEntitiesTextArea = document.createElement('textarea'); -function decodeEntities(text) { - decodeEntitiesTextArea.innerHTML = text; - return decodeEntitiesTextArea.value; } function translate() { @@ -541,11 +411,12 @@ e.preventDefault(); if(!stop_name_autocomplete.value) return; stop_id = stop_name_autocomplete.value; - loadTimes(stop_id, true); + loadTimes(stop_id); }); refresh_button.addEventListener('click', function(e) { - loadTimes(stop_id); + loadTimes(); + loadRoute(); }); alert_close.addEventListener('click', function(e) { diff --git a/lang_en.js b/lang_en.js index 21fe684..b7e4467 100644 --- a/lang_en.js +++ b/lang_en.js @@ -51,6 +51,7 @@ status_delayed_4: 'Delayed 4′+', status_delayed_10: 'Delayed 10′+', + help_click_for_schedule: 'Click on an entry in the departures timetable to see the tram\'s schedule.', help_legend: 'Legend:', help_text: 'Relative times (eg. 3 min) are real-time arrivals based on tram location data. Absolute times (eg. 8:01) are scheduled departures, shown when the tram cannot be located. "?" means unknown delay.', help_hover_for_more: 'Hover the icon for more details.', diff --git a/lang_pl.js b/lang_pl.js index c42f216..1a9422c 100644 --- a/lang_pl.js +++ b/lang_pl.js @@ -51,6 +51,7 @@ status_delayed_4: 'Opóźniony 4′+', status_delayed_10: 'Opóźniony 10′+', + help_click_for_schedule: 'Kliknij na wpis w tabeli odjazdów by zobaczyć rozkład jazdy danego tramwaju.', help_legend: 'Legenda:', help_text: 'Względne czasy (np. 3 min) są podawane na podstawie faktycznej lokalizacji tramwajów. Czasy bezwzględne (np. 8:01) to odjazdy rozkładowe, pokazywane gdy tramwaj nie może być zlokalizowany. "?" oznacza nieznane opóźnienie.', help_hover_for_more: 'Najedź na ikonę, by uzyskać więcej informacji.', diff --git a/proxy.php b/proxy.php index ff9eb34..dad3670 100644 --- a/proxy.php +++ b/proxy.php @@ -1,20 +1,34 @@ <?php -$base_proxy = 'http://www.ttss.krakow.pl/internetservice/services'; +$base_proxy = 'http://www.ttss.krakow.pl/internetservice'; $method = [ - '/lookup/autocomplete/json' => [ + '/services/lookup/autocomplete/json' => [ 'query' => function() { return TRUE; }, ], - '/passageInfo/stopPassages/stop' => [ + '/services/passageInfo/stopPassages/stop' => [ 'stop' => 'ctype_alnum', 'mode' => function($mode) { return in_array($mode, ['arrival', 'departure']); }, ], - '/routeInfo/routeStops' => [ + '/services/tripInfo/tripPassages' => [ + 'tripId' => 'ctype_digit', + 'mode' => function($mode) { return in_array($mode, ['arrival', 'departure']); }, + #'vehicleId' => 'ctype_digit', + ], + '/services/routeInfo/routeStops' => [ 'routeId' => 'ctype_alnum' ], ]; +$rewrite = [ + '/lookup/autocomplete/json' => '/services/lookup/autocomplete/json', + '/passageInfo/stopPassages/stop' => '/services/passageInfo/stopPassages/stop', + '/routeInfo/routeStops' => '/services/routeInfo/routeStops', +]; $path = $_SERVER['PATH_INFO']; +if(isset($rewrite[$path])) { + $path = $rewrite[$path]; +} + if(!isset($method[$path])) { header('HTTP/1.1 403 Forbidden'); die('Forbidden'); -- Gitblit v1.9.1