Improved www.ttss.krakow.pl
Jacek Kowalski
2017-04-17 4b0eda2a43298f2a3ac6c21b8d5eabe2a1590acc
commit | author | age
68aeb4 1 //var ttss_base = 'http://www.ttss.krakow.pl/internetservice';
c25e91 2 var ttss_base = '/proxy.php';
JK 3 var ttss_refresh = 20000; // 20 seconds
4
f50bae 5 var page_title = document.getElementsByTagName('title')[0];
5de24f 6 var ignore_hashchange = false;
f50bae 7
9e9b25 8 var language = 'pl';
9e6757 9 var lang_select = document.getElementById('lang-select');
JK 10
8f89f0 11 var stop_id = '';
c25e91 12 var stop_name = document.getElementById('stop-name');
JK 13 var stop_name_form = stop_name.form;
14 var stop_name_autocomplete = document.getElementById('stop-name-autocomplete');
15 var stop_name_autocomplete_xhr;
e95a73 16 var stop_name_autocomplete_timer;
c25e91 17
JK 18 var times_xhr;
19 var times_timer;
20 var times_stop_name = document.getElementById('times-stop-name');
21 var times_alerts = document.getElementById('times-alerts');
22 var times_table = document.getElementById('times-table');
68aeb4 23 //var times_lines = document.getElementById('times-lines');
c25e91 24
68aeb4 25 var route_id;
c25e91 26 var route_xhr;
JK 27 var route_line = document.getElementById('route-line');
28 var route_table = document.getElementById('route-table');
29
30 var refresh_button = document.getElementById('refresh');
31 var refresh_text = document.getElementById('refresh-text');
32 var refresh_time;
33 var refresh_timer;
34
35 var alert = document.getElementById('alert');
36 var alert_text = document.getElementById('alert-text');
37 var alert_close = document.getElementById('alert-close');
38
0f9bcf 39 var nav = document.getElementsByTagName('nav')[0];
4b0eda 40 var vehicle_data = document.getElementById('vehicle-data');
JK 41 var vehicle_data_style = document.getElementById('vehicle-data-style');
ac721d 42
c25e91 43 function parseStatus(status) {
JK 44     switch(status.status) {
45         case 'STOPPING':
9e6757 46             return lang.boarding_sign;
c25e91 47         case 'PREDICTED':
JK 48             if(status.actualRelativeTime <= 0)
9e6757 49                 return lang.boarding_sign;
c25e91 50             if(status.actualRelativeTime >= 60)
9e6757 51                 return lang.time_minutes_prefix + Math.floor(status.actualRelativeTime / 60) + lang.time_minutes_suffix;
JK 52             return lang.time_seconds_prefix + status.actualRelativeTime + lang.time_seconds_suffix;
c25e91 53         case 'DEPARTED':
9e6757 54             return lang.time_minutes_ago_prefix + Math.floor(-status.actualRelativeTime / 60) + lang.time_minutes_ago_suffix;
c25e91 55         default:
JK 56             return status.mixedTime;
57     }
58 }
59
60 function parseTime(date, time) {
61     var result = new Date(date.getFullYear(), date.getMonth(), date.getDay());
62     var time_split = time.split(':');
63     result.setHours(time_split[0]);
64     result.setMinutes(time_split[1]);
65     
66     if(result.getTime() - date.getTime() > 72000000) {
67         result.setTime(result.getTime() - 86400000);
68     }
69     
70     if(date.getTime() - result.getTime() > 72000000) {
71         result.setTime(result.getTime() + 86400000);
72     }
73     
74     return result;
75 }
76
77 function parseDelay(status) {
9e6757 78     if(!status.actualTime) return lang.unknown_sign;
JK 79     if(!status.plannedTime) return lang.unknown_sign;
c25e91 80     
JK 81     var now = new Date();
82     var actual = parseTime(now, status.actualTime);
83     var planned = parseTime(now, status.plannedTime);
84     
9e6757 85     return lang.time_minutes_prefix + ((actual.getTime() - planned.getTime()) / 1000 / 60) + lang.time_minutes_suffix;
c25e91 86 }
JK 87
8fb34c 88 function displayVehicle(vehicleInfo) {
JK 89     if(!vehicleInfo) return document.createTextNode('');
90     
91     var span = document.createElement('span');
92     span.className = 'vehicleInfo';
9e6757 93     
JK 94     var floor_type = '';
8fb34c 95     if(vehicleInfo.low == 0) {
9e6757 96         setText(span, lang.high_floor_sign);
JK 97         floor_type = lang.high_floor;
8fb34c 98     } else if(vehicleInfo.low == 1) {
9e6757 99         setText(span, lang.partially_low_floor_sign);
JK 100         floor_type = lang.partially_low_floor;
8fb34c 101     } else if(vehicleInfo.low == 2) {
9e6757 102         setText(span, lang.low_floor_sign);
JK 103         floor_type = lang.low_floor;
8fb34c 104     }
9e6757 105     
JK 106     span.title = lang.tram_type_pattern
107         .replace('$num', vehicleInfo.num)
108         .replace('$type', vehicleInfo.type)
109         .replace('$floor', floor_type);
110     
8fb34c 111     return span;
c25e91 112 }
JK 113
114 function fail(message, more) {
115     if(times_timer) clearTimeout(times_timer);
116     
117     setText(alert_text, message);
118     alert.style.display = 'block';
119     
572390 120     console.log(message + (more ? ' More details follow.' : ''));
c25e91 121     if(more) console.log(more);
JK 122 }
123
124 function fail_ajax(data) {
125     // abort() is not a failure
126     if(data.readyState == 0 && data.statusText == 'abort') return;
127     
128     if(data.status == 0) {
9e6757 129         fail(lang.error_request_failed_connectivity, data);
c25e91 130     } else if (data.statusText) {
9e6757 131         fail(lang.error_request_failed_status.replace('$status', data.statusText), data);
c25e91 132     } else {
9e6757 133         fail(lang.error_request_failed, data);
c25e91 134     }
JK 135 }
136
e54544 137 function fail_hide() {
JK 138     alert.style.display = 'none';
139 }
140
ac721d 141 function loading_start() {
0f9bcf 142     nav.className += ' loading';
ac721d 143 }
JK 144
145 function loading_end() {
0f9bcf 146     nav.className = nav.className.replace(' loading', '');
ac721d 147 }
JK 148
68aeb4 149 function loadTimes(stopId) {
c25e91 150     if(!stopId) stopId = stop_id;
JK 151     if(!stopId) return;
152     
153     if(times_timer) clearTimeout(times_timer);
154     if(times_xhr) times_xhr.abort();
155     
68aeb4 156     console.log('loadTimes(' + stopId + ')');
969115 157     stop_id = stopId;
9e6757 158     
5de24f 159     ignore_hashchange = true;
969115 160     window.location.hash = '#!' + language + stopId;
5de24f 161     ignore_hashchange = false;
c25e91 162     refresh_button.removeAttribute('disabled');
JK 163     
ac721d 164     loading_start();
c25e91 165     times_xhr = $.get(
68aeb4 166         ttss_base + '/services/passageInfo/stopPassages/stop'
c25e91 167             + '?stop=' + encodeURIComponent(stopId)
JK 168             + '&mode=departure'
169     ).done(function(data) {
170         setText(times_stop_name, data.stopName);
9e6757 171         setText(page_title, lang.page_title_stop_name.replace('$stop', data.stopName));
c25e91 172         deleteChildren(times_alerts);
JK 173         deleteChildren(times_table);
68aeb4 174         //deleteChildren(times_lines);
c25e91 175         
JK 176         for(var i = 0, il = data.generalAlerts.length; i < il; i++) {
09944e 177             addParaWithText(times_alerts, data.generalAlerts[i].title);
c25e91 178         }
JK 179         
180         for(var i = 0, il = data.old.length; i < il; i++) {
181             var tr = document.createElement('tr');
182             addCellWithText(tr, data.old[i].patternText);
8fb34c 183             var dir_cell = addCellWithText(tr, data.old[i].direction);
4b0eda 184             var vehicle = parseVehicle(data.actual[i].vehicleId);
JK 185             dir_cell.appendChild(displayVehicle(vehicle));
186             addCellWithText(tr, vehicle.num).className = 'vehicleData';
c25e91 187             var status = parseStatus(data.old[i]);
JK 188             addCellWithText(tr, status);
189             addCellWithText(tr, '');
190             
191             tr.className = 'active';
68aeb4 192             tr.addEventListener('click', function(tripId){ return function(){ loadRoute(tripId); } }(data.old[i].tripId) );
c25e91 193             times_table.appendChild(tr);
JK 194         }
195         
196         for(var i = 0, il = data.actual.length; i < il; i++) {
197             var tr = document.createElement('tr');
198             addCellWithText(tr, data.actual[i].patternText);
8fb34c 199             var dir_cell = addCellWithText(tr, data.actual[i].direction);
4b0eda 200             var vehicle = parseVehicle(data.actual[i].vehicleId);
JK 201             dir_cell.appendChild(displayVehicle(vehicle));
202             addCellWithText(tr, vehicle.num).className = 'vehicleData';
c25e91 203             var status = parseStatus(data.actual[i]);
e2b283 204             var status_cell = addCellWithText(tr, status);
c25e91 205             var delay = parseDelay(data.actual[i]);
e2b283 206             var delay_cell = addCellWithText(tr, delay);
c25e91 207             
9e6757 208             if(status == lang.boarding_sign) {
e2b283 209                 tr.className = 'success';
JK 210                 status_cell.className = 'status-boarding';
211             } else if(parseInt(delay) > 9) {
212                 tr.className = 'danger';
213                 delay_cell.className = 'status-delayed';
214             } else if(parseInt(delay) > 3) {
215                 tr.className = 'warning';
216             }
68aeb4 217             
JK 218             tr.addEventListener('click', function(tripId){ return function(){ loadRoute(tripId); } }(data.actual[i].tripId) );
c25e91 219             times_table.appendChild(tr);
JK 220         }
221         
68aeb4 222         /*
c25e91 223         for(var i = 0, il = data.routes.length; i < il; i++) {
JK 224             var tr = document.createElement('tr');
225             addCellWithText(tr, data.routes[i].name);
226             addCellWithText(tr, data.routes[i].directions.join(' - '));
227             addCellWithText(tr, data.routes[i].authority);
228             times_lines.appendChild(tr);
229         }
68aeb4 230         */
c25e91 231         
JK 232         startTimer(new Date());
e54544 233         fail_hide();
c25e91 234         
68aeb4 235         times_timer = setTimeout(function(){ loadTimes(); loadRoute(); }, ttss_refresh);
ac721d 236     }).fail(fail_ajax).always(loading_end);
68aeb4 237 }
JK 238
239 function loadRoute(tripId) {
240     if(!tripId) tripId = route_id;
241     if(!tripId) return;
242     
243     console.log('loadRoute(' + tripId + ')');
244     route_id = tripId;
245     
246     if(route_xhr) route_xhr.abort();
247     route_xhr = $.get(
248         ttss_base + '/services/tripInfo/tripPassages'
249             + '?tripId=' + encodeURIComponent(tripId)
250             + '&mode=departure'
251     ).done(function(data) {
252         if(!data.routeName || !data.directionText || data.old.length + data.actual.length == 0) {
253             route_id = null;
254             return;
255         }
256         
257         setText(route_line, data.routeName + ' ' + data.directionText);
258         deleteChildren(route_table);
259         
260         for(var i = 0, il = data.old.length; i < il; i++) {
261             var tr = document.createElement('tr');
262             addCellWithText(tr, data.old[i].actualTime || data.old[i].plannedTime);
263             addCellWithText(tr, data.old[i].stop_seq_num + '. ' + data.old[i].stop.name);
264             
265             tr.className = 'active';
73da94 266             tr.addEventListener('click', function(stopId){ return function(){ loadTimes(stopId); } }(data.old[i].stop.shortName) );
68aeb4 267             route_table.appendChild(tr);
JK 268         }
269         
270         for(var i = 0, il = data.actual.length; i < il; i++) {
271             var tr = document.createElement('tr');
272             addCellWithText(tr, data.actual[i].actualTime || data.actual[i].plannedTime);
273             addCellWithText(tr, data.actual[i].stop_seq_num + '. ' + data.actual[i].stop.name);
274             
275             if(data.actual[i].status == 'STOPPING') {
276                 tr.className = 'success';
277             }
73da94 278             tr.addEventListener('click', function(stopId){ return function(){ loadTimes(stopId); } }(data.actual[i].stop.shortName) );
68aeb4 279             route_table.appendChild(tr);
JK 280         }
281     }).fail(fail_ajax);
c25e91 282 }
JK 283
284 function startTimer(date) {
285     if(date) {
9e6757 286         setText(refresh_text, lang.last_refreshed.replace('$time', lang.time_now));
c25e91 287         refresh_time = date;
JK 288     }
289     if(!refresh_time) return;
290     if(refresh_timer) clearInterval(refresh_timer);
291     
292     var now = new Date();
293     var ms = now.getTime() - refresh_time.getTime();
294     
295     var interval = 1000;
296     if(ms >= 120000) interval = 60000;
297     
298     refresh_timer = setInterval(function() {
299         var now = new Date();
300         var ms = now.getTime() - refresh_time.getTime();
301         
302         if(ms >= 120000) {
9e6757 303             setText(refresh_text, lang.last_refreshed.replace(
JK 304                 '$time',
305                 lang.time_minutes_ago_prefix + Math.floor(ms / 60000)
306                     + lang.time_minutes_ago_suffix
307             ));
c25e91 308             startTimer();
JK 309         } else {
9e6757 310             setText(refresh_text, lang.last_refreshed.replace(
JK 311                 '$time',
312                 lang.time_seconds_ago_prefix + Math.floor(ms / 1000)
313                     + lang.time_seconds_ago_suffix
314             ));
c25e91 315         }
JK 316     }, interval);
b50208 317 }
JK 318
9e6757 319 function translate() {
JK 320     var elements = document.querySelectorAll('*[data-translate]');
321     
322     var text_name;
323     for(var i = 0; i < elements.length; i++) {
324         text_name = elements[i].dataset.translate;
325         if(lang[text_name] == undefined) {
326             console.log('Missing translation: ' + text_name);
327             continue;
328         }
329         setText(elements[i], lang[text_name]);
330     }
331     
332     stop_name.setAttribute('placeholder', lang.stop_name_placeholder);
333     
334     if(stop_name_autocomplete.value) {
335         setText(refresh_text, lang.select_stop_click_go);
336     } else {
337         setText(refresh_text, lang.enter_stop_name_to_begin);
338     }
5de24f 339     
5ac72e 340     setText(page_title, lang.page_title);
JK 341     
960548 342     if(!stop_id) return;
JK 343     
5de24f 344     loadTimes();
JK 345     loadRoute();
9e6757 346 }
JK 347
348 function change_language(lang) {
349     if(!lang || lang.length != 2) return;
350     if(lang == language) return;
351     lang_select.value = lang;
352     if(!lang_select.value) {
353         lang_select.value = language;
354         return;
355     }
356     language = lang;
357     
358     var script = document.createElement('script');
359     script.type = 'text/javascript';
360     script.src = 'lang_' + lang + '.js';
361     script.id = 'lang_script';
362     script.onload = translate;
363     
364     document.body.removeChild(document.getElementById('lang_script'));
365     document.body.appendChild(script);
366     
5de24f 367     ignore_hashchange = true;
9e6757 368     window.location.hash = '#!' + language + stop_id;
5de24f 369     ignore_hashchange = false;
9e6757 370 }
JK 371
372 function hash() {
5de24f 373     if(ignore_hashchange) return;
JK 374     
9e6757 375     if(window.location.hash.match(/^#![0-9]+$/)) {
JK 376         loadTimes(parseInt(window.location.hash.substr(2)));
377     } else if(window.location.hash.match(/^#![a-z]{2}[0-9]*$/)) {
378         var stop = parseInt(window.location.hash.substr(4));
379         if(stop) stop_id = stop;
380         change_language(window.location.hash.substr(2, 2));
381     }
382 }
383
e95a73 384 function stop_autocomplete() {
JK 385     if(stop_name_autocomplete_xhr) stop_name_autocomplete_xhr.abort();
386     
387     stop_name_autocomplete_xhr = $.get(
ced309 388         'stops.php?query=' + encodeURIComponent(stop_name.value)
e95a73 389     ).done(function(data) {
JK 390         deleteChildren(stop_name_autocomplete);
ced309 391         for(var i = 0, il = data.length; i < il; i++) {
JK 392             if(data[i].type != 'stop') continue;
e95a73 393             if(data[i].id > 6000) continue;
JK 394             var opt = document.createElement('option');
395             opt.value = data[i].id;
9edf7f 396             setText(opt, data[i].name);
e95a73 397             stop_name_autocomplete.appendChild(opt);
JK 398         }
399         
400         if(!stop_id) setText(refresh_text, lang.select_stop_click_go);
401     }).fail(fail_ajax);
402 }
403
c25e91 404 function init() {
JK 405     if(!window.jQuery) {
9e6757 406         fail(lang.jquery_not_loaded);
c25e91 407         return;
JK 408     }
409     
410     $.ajaxSetup({
411         dataType: 'json',
12310b 412         timeout: 10000,
9e6757 413     });
JK 414     
415     lang_select.addEventListener('input', function(e) {
416         change_language(lang_select.value);
c25e91 417     });
JK 418     
419     stop_name.addEventListener('input', function(e) {
420         if(!stop_name.value) return;
e95a73 421         if(stop_name_autocomplete_timer) clearTimeout(stop_name_autocomplete_timer);
c25e91 422         
e95a73 423         stop_name_autocomplete_timer = setTimeout(stop_autocomplete, 100);
c25e91 424     });
JK 425     
9e6757 426     setText(refresh_text, lang.enter_stop_name_to_begin);
c25e91 427     
JK 428     stop_name_form.addEventListener('submit', function(e) {
429         e.preventDefault();
430         if(!stop_name_autocomplete.value) return;
969115 431         loadTimes(stop_name_autocomplete.value);
c25e91 432     });
JK 433     
4b0eda 434     refresh_button.addEventListener('click', function() {
68aeb4 435         loadTimes();
JK 436         loadRoute();
c25e91 437     });
JK 438     
4b0eda 439     alert_close.addEventListener('click', function() {
c25e91 440         alert.style.display = 'none';
JK 441     });
492fc5 442     
4b0eda 443     vehicle_data.addEventListener('click', function(e) {
JK 444         e.preventDefault();
445         vehicle_data.style.display = 'none';
446         setText(vehicle_data_style, '.vehicleData { display: table-cell; }')
447     });
448     
9e6757 449     hash();
JK 450     
451     window.addEventListener('hashchange', hash);
572390 452     
JK 453     checkVersionInit();
c25e91 454 }
JK 455
456 init();