live update of next station via javascript

This commit is contained in:
Daniel Friesel 2019-10-29 21:18:46 +01:00
parent f13b4755c7
commit 663b4dc6d8
4 changed files with 102 additions and 8 deletions

View file

@ -2405,6 +2405,36 @@ sub startup {
} }
); );
$self->helper(
'journey_to_ajax_route' => sub {
my ( $self, $journey ) = @_;
my @route;
for my $station ( @{ $journey->{route_after} } ) {
my $station_desc = $station->[0];
if ( $station->[1]{rt_arr} ) {
$station_desc .= $station->[1]{sched_arr}->strftime(';%s');
$station_desc .= $station->[1]{rt_arr}->strftime(';%s');
if ( $station->[1]{rt_dep} ) {
$station_desc
.= $station->[1]{sched_dep}->strftime(';%s');
$station_desc .= $station->[1]{rt_dep}->strftime(';%s');
}
else {
$station_desc .= ';0;0';
}
}
else {
$station_desc .= ';0;0;0;0';
}
push( @route, $station_desc );
}
return join( '|', @route );
}
);
$self->helper( $self->helper(
'get_user_status' => sub { 'get_user_status' => sub {
my ( $self, $uid ) = @_; my ( $self, $uid ) = @_;

View file

@ -1,14 +1,40 @@
var j_departure = 0;
var j_duration = 0; var j_duration = 0;
var j_arrival = 0; var j_arrival = 0;
var j_dest = '';
var j_stops = [];
function upd_journey_data() { function upd_journey_data() {
$('.countdown').each(function() { $('.countdown').each(function() {
j_duration = $(this).data('duration'); var journey_data = $(this).data('journey');
j_arrival = $(this).data('arrival'); if (journey_data) {
journey_data = journey_data.split(';');
j_departure = parseInt(journey_data[0]);
j_arrival = parseInt(journey_data[1]);
j_duration = j_arrival - j_departure;
}
var journey_dest = $(this).data('dest');
if (journey_dest) {
j_dest = journey_dest;
}
var stops = $(this).data('route');
if (stops) {
stops = stops.split('|');
j_stops = [];
for (var stop_id in stops) {
var stopdata = stops[stop_id].split(';');
for (var i = 1; i < 5; i++) {
stopdata[i] = parseInt(stopdata[i]);
}
j_stops.push(stopdata);
}
}
}); });
} }
function upd_countdown() { function upd_countdown() {
var now = Date.now() / 1000; var now = Date.now() / 1000;
if (j_arrival > 0) { if (j_departure > now) {
$('.countdown').text('Abfahrt in ' + Math.round((j_departure - now)/60) + ' Minuten');
} else if (j_arrival > 0) {
if (j_arrival > now) { if (j_arrival > now) {
$('.countdown').text('Ankunft in ' + Math.round((j_arrival - now)/60) + ' Minuten'); $('.countdown').text('Ankunft in ' + Math.round((j_arrival - now)/60) + ' Minuten');
} else { } else {
@ -16,6 +42,22 @@ function upd_countdown() {
} }
} }
} }
function hhmm(epoch) {
var date = new Date(epoch * 1000);
var h = date.getHours();
var m = date.getMinutes();
return (h < 10 ? '0' + h : h) + ':' + (m < 10 ? '0' + m : m);
}
function odelay(sched, rt) {
if (sched < rt) {
return ' (+' + ((rt - sched) / 60) + ')';
}
else if (sched == rt) {
return '';
}
return ' (' + ((rt - sched) / 60) + ')';
}
function tvly_run(link, req, err_callback) { function tvly_run(link, req, err_callback) {
var error_icon = '<i class="material-icons">error</i>'; var error_icon = '<i class="material-icons">error</i>';
var progressbar = $('<div class="progress"><div class="indeterminate"></div></div>'); var progressbar = $('<div class="progress"><div class="indeterminate"></div></div>');
@ -74,6 +116,26 @@ function tvly_journey_progress() {
progress = 1; progress = 1;
} }
$('.progress .determinate').css('width', (progress * 100) + '%'); $('.progress .determinate').css('width', (progress * 100) + '%');
for (stop in j_stops) {
var stop_name = j_stops[stop][0];
var sched_arr = j_stops[stop][1];
var rt_arr = j_stops[stop][2];
var sched_dep = j_stops[stop][3];
var rt_dep = j_stops[stop][4];
if (stop_name == j_dest) {
$('.next-stop').html('');
break;
}
if ((rt_arr != 0) && (rt_arr - now > 0)) {
$('.next-stop').html(stop_name + '<br/>' + hhmm(rt_arr) + odelay(sched_arr, rt_arr));
break;
}
if ((rt_dep != 0) && (rt_dep - now > 0)) {
$('.next-stop').html(stop_name + '<br/>' + hhmm(rt_arr) + ' → ' + hhmm(rt_dep) + odelay(sched_dep, rt_dep));
break;
}
}
setTimeout(tvly_journey_progress, 5000); setTimeout(tvly_journey_progress, 5000);
} }
} }

View file

@ -1 +1 @@
function upd_journey_data(){$(".countdown").each(function(){j_duration=$(this).data("duration"),j_arrival=$(this).data("arrival")})}function upd_countdown(){var t=Date.now()/1e3;j_arrival>0&&(j_arrival>t?$(".countdown").text("Ankunft in "+Math.round((j_arrival-t)/60)+" Minuten"):$(".countdown").text("Ziel erreicht"))}function tvly_run(t,a,e){var n='<i class="material-icons">error</i>',i=$('<div class="progress"><div class="indeterminate"></div></div>');t.hide(),t.after(i),$.post("/action",a,function(a){a.success?$(location).attr("href",a.redirect_to):(M.toast({html:n+" "+a.error}),i.remove(),e&&e(),t.append(" "+n),t.show())})}function tvly_update(){$.get("/ajax/status_card.html",function(t){$(".statuscol").html(t),tvly_reg_handlers(),upd_journey_data(),setTimeout(tvly_update,4e4)}).fail(function(){$(".sync-failed-marker").css("display","block"),upd_countdown(),setTimeout(tvly_update,5e3)})}function tvly_update_public(){var t;$(".publicstatuscol").each(function(){t=$(this).data("user")}),$.get("/ajax/status/"+t+".html",function(t){$(".publicstatuscol").html(t),upd_journey_data(),setTimeout(tvly_update_public,4e4)}).fail(function(){$(".sync-failed-marker").css("display","block"),upd_countdown(),setTimeout(tvly_update_public,5e3)})}function tvly_journey_progress(){var t=Date.now()/1e3,a=0;j_duration>0&&(a=1-(j_arrival-t)/j_duration,a<0&&(a=0),a>1&&(a=1),$(".progress .determinate").css("width",100*a+"%"),setTimeout(tvly_journey_progress,5e3))}function tvly_reg_handlers(){$(".action-checkin").click(function(){var t=$(this);tvly_run(t,{action:"checkin",station:t.data("station"),train:t.data("train"),dest:t.data("dest")})}),$(".action-checkout").click(function(){var t=$(this),a={action:"checkout",station:t.data("station"),force:t.data("force")};tvly_run(t,a,function(){t.append(" Ohne Echtzeitdaten auschecken?"),t.data("force",!0)})}),$(".action-undo").click(function(){var t=$(this);tvly_run(t,{action:"undo",undo_id:t.data("id")})}),$(".action-cancelled-from").click(function(){var t=$(this);tvly_run(t,{action:"cancelled_from",station:t.data("station"),train:t.data("train")})}),$(".action-cancelled-to").click(function(){var t=$(this);tvly_run(t,{action:"cancelled_to",station:t.data("station"),force:!0})}),$(".action-delete").click(function(){var t=$(this),a={action:"delete",id:t.data("id"),checkin:t.data("checkin"),checkout:t.data("checkout")};really_delete=confirm("Diese Zugfahrt wirklich löschen? Der Eintrag wird sofort aus der Datenbank entfernt und kann nicht wiederhergestellt werden."),really_delete&&tvly_run(t,a)}),$(".action-share").click(function(){navigator.share?(shareObj={text:$(this).data("text")},$(this).data("url")&&(shareObj.url=$(this).data("url")),navigator.share(shareObj)):$(this).data("url")&&(location.href=$(this).data("url"))}),!$(".action-share").length||navigator.share||$(".action-share").data("url")||$(".action-share").css("display","none")}var j_duration=0,j_arrival=0;$(document).ready(function(){tvly_reg_handlers(),$(".statuscol .autorefresh").length&&(upd_journey_data(),setTimeout(tvly_update,4e4),setTimeout(tvly_journey_progress,5e3)),$(".publicstatuscol .autorefresh").length&&(upd_journey_data(),setTimeout(tvly_update_public,4e4),setTimeout(tvly_journey_progress,5e3)),$("a[href]").click(function(){$("nav .preloader-wrapper").addClass("active")})}); function upd_journey_data(){$(".countdown").each(function(){var t=$(this).data("journey");t&&(t=t.split(";"),j_departure=parseInt(t[0]),j_arrival=parseInt(t[1]),j_duration=j_arrival-j_departure);var a=$(this).data("dest");a&&(j_dest=a);var e=$(this).data("route");if(e){e=e.split("|"),j_stops=[];for(var n in e){for(var r=e[n].split(";"),o=1;o<5;o++)r[o]=parseInt(r[o]);j_stops.push(r)}}})}function upd_countdown(){var t=Date.now()/1e3;j_departure>t?$(".countdown").text("Abfahrt in "+Math.round((j_departure-t)/60)+" Minuten"):j_arrival>0&&(j_arrival>t?$(".countdown").text("Ankunft in "+Math.round((j_arrival-t)/60)+" Minuten"):$(".countdown").text("Ziel erreicht"))}function hhmm(t){var a=new Date(1e3*t),e=a.getHours(),n=a.getMinutes();return(e<10?"0"+e:e)+":"+(n<10?"0"+n:n)}function odelay(t,a){return t<a?" (+"+(a-t)/60+")":t==a?"":" ("+(a-t)/60+")"}function tvly_run(t,a,e){var n='<i class="material-icons">error</i>',r=$('<div class="progress"><div class="indeterminate"></div></div>');t.hide(),t.after(r),$.post("/action",a,function(a){a.success?$(location).attr("href",a.redirect_to):(M.toast({html:n+" "+a.error}),r.remove(),e&&e(),t.append(" "+n),t.show())})}function tvly_update(){$.get("/ajax/status_card.html",function(t){$(".statuscol").html(t),tvly_reg_handlers(),upd_journey_data(),setTimeout(tvly_update,4e4)}).fail(function(){$(".sync-failed-marker").css("display","block"),upd_countdown(),setTimeout(tvly_update,5e3)})}function tvly_update_public(){var t;$(".publicstatuscol").each(function(){t=$(this).data("user")}),$.get("/ajax/status/"+t+".html",function(t){$(".publicstatuscol").html(t),upd_journey_data(),setTimeout(tvly_update_public,4e4)}).fail(function(){$(".sync-failed-marker").css("display","block"),upd_countdown(),setTimeout(tvly_update_public,5e3)})}function tvly_journey_progress(){var t=Date.now()/1e3,a=0;if(j_duration>0){a=1-(j_arrival-t)/j_duration,a<0&&(a=0),a>1&&(a=1),$(".progress .determinate").css("width",100*a+"%");for(stop in j_stops){var e=j_stops[stop][0],n=j_stops[stop][1],r=j_stops[stop][2],o=j_stops[stop][3],i=j_stops[stop][4];if(e==j_dest){$(".next-stop").html("");break}if(0!=r&&r-t>0){$(".next-stop").html(e+"<br/>"+hhmm(r)+odelay(n,r));break}if(0!=i&&i-t>0){$(".next-stop").html(e+"<br/>"+hhmm(r)+" → "+hhmm(i)+odelay(o,i));break}}setTimeout(tvly_journey_progress,5e3)}}function tvly_reg_handlers(){$(".action-checkin").click(function(){var t=$(this);tvly_run(t,{action:"checkin",station:t.data("station"),train:t.data("train"),dest:t.data("dest")})}),$(".action-checkout").click(function(){var t=$(this),a={action:"checkout",station:t.data("station"),force:t.data("force")};tvly_run(t,a,function(){t.append(" Ohne Echtzeitdaten auschecken?"),t.data("force",!0)})}),$(".action-undo").click(function(){var t=$(this);tvly_run(t,{action:"undo",undo_id:t.data("id")})}),$(".action-cancelled-from").click(function(){var t=$(this);tvly_run(t,{action:"cancelled_from",station:t.data("station"),train:t.data("train")})}),$(".action-cancelled-to").click(function(){var t=$(this);tvly_run(t,{action:"cancelled_to",station:t.data("station"),force:!0})}),$(".action-delete").click(function(){var t=$(this),a={action:"delete",id:t.data("id"),checkin:t.data("checkin"),checkout:t.data("checkout")};really_delete=confirm("Diese Zugfahrt wirklich löschen? Der Eintrag wird sofort aus der Datenbank entfernt und kann nicht wiederhergestellt werden."),really_delete&&tvly_run(t,a)}),$(".action-share").click(function(){navigator.share?(shareObj={text:$(this).data("text")},$(this).data("url")&&(shareObj.url=$(this).data("url")),navigator.share(shareObj)):$(this).data("url")&&(location.href=$(this).data("url"))}),!$(".action-share").length||navigator.share||$(".action-share").data("url")||$(".action-share").css("display","none")}var j_departure=0,j_duration=0,j_arrival=0,j_dest="",j_stops=[];$(document).ready(function(){tvly_reg_handlers(),$(".statuscol .autorefresh").length&&(upd_journey_data(),setTimeout(tvly_update,4e4),setTimeout(tvly_journey_progress,5e3)),$(".publicstatuscol .autorefresh").length&&(upd_journey_data(),setTimeout(tvly_update_public,4e4),setTimeout(tvly_journey_progress,5e3)),$("a[href]").click(function(){$("nav .preloader-wrapper").addClass("active")})});

View file

@ -5,8 +5,10 @@
<span class="card-title">Eingecheckt in <%= $journey->{train_type} %> <%= $journey->{train_no} %></span> <span class="card-title">Eingecheckt in <%= $journey->{train_type} %> <%= $journey->{train_no} %></span>
<p> <p>
<div class="center-align countdown" <div class="center-align countdown"
data-duration="<%= $journey->{journey_duration} // 0 %>" data-journey="<%= $journey->{real_departure}->epoch %>;<%= <%= $journey->{real_arrival}->epoch %>"
data-arrival="<%= $journey->{real_arrival}->epoch %>"> data-route="<%= journey_to_ajax_route($journey) %>"
data-dest="<%= $journey->{arr_name} %>"
>
% if ($journey->{boarding_countdown} > 120) { % if ($journey->{boarding_countdown} > 120) {
Einfahrt in <%= sprintf('%.f', $journey->{boarding_countdown} / 60) %> Minuten<br/> Einfahrt in <%= sprintf('%.f', $journey->{boarding_countdown} / 60) %> Minuten<br/>
% } % }
@ -108,7 +110,7 @@
noch nicht bekannt noch nicht bekannt
% } % }
</div> </div>
<div class="center-align hide-on-small-only"> <div class="center-align hide-on-small-only next-stop">
% for my $station (@{$journey->{route_after}}) { % for my $station (@{$journey->{route_after}}) {
% if ($station->[0] eq $journey->{arr_name}) { % if ($station->[0] eq $journey->{arr_name}) {
% last; % last;
@ -133,7 +135,7 @@
</div> </div>
<div style="clear: both;"> <div style="clear: both;">
</div> </div>
<div class="hide-on-med-and-up" style="margin-top: 2ex;"> <div class="hide-on-med-and-up next-stop" style="margin-top: 2ex;">
% for my $station (@{$journey->{route_after}}) { % for my $station (@{$journey->{route_after}}) {
% if ($station->[0] eq $journey->{arr_name}) { % if ($station->[0] eq $journey->{arr_name}) {
% last; % last;