diff options
Diffstat (limited to 'templates')
24 files changed, 972 insertions, 639 deletions
diff --git a/templates/_error.html.ep b/templates/_error.html.ep index 4abfb4e..8585f90 100644 --- a/templates/_error.html.ep +++ b/templates/_error.html.ep @@ -1,5 +1,5 @@ <div class="error"><strong>Fehler:</strong> -<pre> +<p style="font-family: Monospace;"> %= $error -</pre> +</p> </div> diff --git a/templates/_intersection_infobox.html.ep b/templates/_intersection_infobox.html.ep deleted file mode 100644 index cb27d19..0000000 --- a/templates/_intersection_infobox.html.ep +++ /dev/null @@ -1,22 +0,0 @@ -<div class="container" id="infobox2" style="margin-top: 1ex; margin-bottom: 1ex;"> -<div class="journey" id="jdata" -data-req="<%= stash('ajax_req') %>" -data-route="<%= stash('ajax_route') %>" -data-poly="<%= stash('ajax_polyline') %>" -> - <strong><%= stash('train1_no') %></strong> - und - <strong><%= stash('train2_no') %></strong> - werden sich wahrscheinlich - % if (my $t = stash('time')) { - gegen <strong><%= $t->strftime('%H:%M') %> Uhr</strong> - % } - % if (my $p = stash('likely_pair')) { - zwischen <strong><%= $p->[0] %></strong> und <strong><%= $p->[1] %></strong> - % } - % if (not stash('time')) { - nicht - % } - begegnen. -</div> -</div> diff --git a/templates/_map_infobox.html.ep b/templates/_map_infobox.html.ep index f1da392..16625f5 100644 --- a/templates/_map_infobox.html.ep +++ b/templates/_map_infobox.html.ep @@ -1,6 +1,6 @@ <div class="container" id="infobox" style="margin-top: 1ex; margin-bottom: 1ex;"> <div class="journey" id="jdata" -data-req="<%= stash('ajax_req') %>" +data-req="<%= stash('ajax_req') =~ s{#}{%23}gr %>" data-route="<%= stash('ajax_route') %>" data-poly="<%= stash('ajax_polyline') %>" > @@ -15,7 +15,9 @@ data-poly="<%= stash('ajax_polyline') %>" <div class="nextstop"> % if ($next->{type} eq 'present' and $next->{station}{dep} and $next->{station}{arr}) { Aufenthalt in <strong><%= $next->{station}{name} %></strong> - an Gleis <strong><%= $next->{station}{platform} %></strong> + % if ($next->{station}{platform}) { + an Gleis <strong><%= $next->{station}{platform} %></strong> + % } bis <strong><%= $next->{station}{dep}->strftime('%H:%M') %></strong> % if ($next->{station}{dep_delay}) { %= sprintf('(%+d)', $next->{station}{dep_delay}) @@ -23,7 +25,9 @@ data-poly="<%= stash('ajax_polyline') %>" % } % elsif ($next->{type} eq 'present' and $next->{station}{dep}) { Abfahrt in <strong><%= $next->{station}{name} %></strong> - von Gleis <strong><%= $next->{station}{platform} %></strong> + % if ($next->{station}{platform}) { + von Gleis <strong><%= $next->{station}{platform} %></strong> + % } um <strong><%= $next->{station}{dep}->strftime('%H:%M') %></strong> % if ($next->{station}{dep_delay}) { %= sprintf('(%+d)', $next->{station}{dep_delay}) @@ -32,7 +36,9 @@ data-poly="<%= stash('ajax_polyline') %>" % elsif ($next->{type} eq 'present' and $next->{station}{arr}) { Endstation erreicht um <strong><%= $next->{station}{arr}->strftime('%H:%M') %></strong> - auf Gleis <strong><%= $next->{station}{platform} %></strong> + % if ($next->{station}{platform}) { + auf Gleis <strong><%= $next->{station}{platform} %></strong> + % } % if ($next->{station}{arr_delay}) { %= sprintf('(%+d)', $next->{station}{arr_delay}) % } @@ -40,7 +46,9 @@ data-poly="<%= stash('ajax_polyline') %>" % elsif ($next->{type} eq 'present' and $next->{station}{arr}) { Zug steht in <strong><%= $next->{station}{arr}->strftime('%H:%M') %></strong> - auf Gleis <strong><%= $next->{station}{platform} %></strong> + % if ($next->{station}{platform}) { + auf Gleis <strong><%= $next->{station}{platform} %></strong> + % } % } % elsif ($next->{type} eq 'next' and $next->{station}{arr}) { Nächster Halt: @@ -49,12 +57,16 @@ data-poly="<%= stash('ajax_polyline') %>" % if ($next->{station}{arr_delay}) { %= sprintf('(%+d)', $next->{station}{arr_delay}) % } - auf Gleis <strong><%= $next->{station}{platform} %></strong> + % if ($next->{station}{platform}) { + auf Gleis <strong><%= $next->{station}{platform} %></strong> + % } % } % elsif ($next->{type} eq 'next') { Nächster Halt: <strong><%= $next->{station}{name} %></strong> - auf Gleis <strong><%= $next->{station}{platform} %></strong> + % if ($next->{station}{platform}) { + auf Gleis <strong><%= $next->{station}{platform} %></strong> + % } % } </div> % } diff --git a/templates/_train_attr.html.ep b/templates/_train_attr.html.ep new file mode 100644 index 0000000..1b40d12 --- /dev/null +++ b/templates/_train_attr.html.ep @@ -0,0 +1,18 @@ +% if ($attr->{series}) { + <span>BR <%= $attr->{series} %></span> +% } +% if ($attr->{vmax}) { + <span><%= $attr->{vmax} %> km/h</span> +% } +% if ($attr->{length}) { + <span>⇤ <%= $attr->{length} %>m ⇥</span> +% } +% if ($attr->{weight}) { + <span><%= $attr->{weight} %>t</span> +% } +% if ($attr->{brakingPercentage}) { + <span>λ=<%= $attr->{brakingPercentage} %></span> +% } +% if ($with_station and $attr->{range}[0]) { + <span>ab <%= $attr->{range}[0] %></span> +% } diff --git a/templates/_train_details.html.ep b/templates/_train_details.html.ep index 098678f..2c18da2 100644 --- a/templates/_train_details.html.ep +++ b/templates/_train_details.html.ep @@ -2,12 +2,10 @@ <div> % if ($departure->{train_no} or $departure->{train_line}) { <span class="train-line <%= $linetype %>"><%= $departure->{train_type} %> - <%= $departure->{train_line} // $departure->{train_no} %></span> + %= $departure->{train_line} // $departure->{train_no} + </span> <span class="train-no"><%= $departure->{train_line} ? $departure->{train_no} : q{} %></span> % } -% else { - <span class="train-line"><%= $departure->{train} // q{???} %></span> -% } </div> <div> % if ($departure->{origin}) { @@ -16,33 +14,11 @@ % } <span class="train-dest"><%= $departure->{destination} // q{???} %></span> </div> -<!-- -% if ($departure->{is_cancelled}) { - <div class="minfo">Fahrt fällt aus</div> -% } -% elsif (defined $departure->{delay} and $departure->{delay} > 0) { - <div class="minfo">+<%= $departure->{delay} %> -% if ($departure->{departure_is_cancelled}) { - (endet hier) -% } - </div> -% } -% if (@{$departure->{replaced_by}}) { -% for my $replacement (@{$departure->{replaced_by}}) { - <span class="replaced">Ersatzzug: <%= $replacement %></span> -% } -% } -% if (@{$departure->{replacement_for}}) { -% for my $replacement (@{$departure->{replacement_for}}) { - <span class="replacement">Ersatzzug für <%= $replacement %></span> -% } -% } ---> </div> <!-- mheader --> <div class="mfooter"> <div class="dataline"> <div> - <div class="arrival"> + <div class="arrival <%= $departure->{arrival_hidden} ? 'timehidden' : q{} %>"> % if ($departure->{is_cancelled} and $departure->{sched_arrival}) { <span class="minfo">An: ––:––</span><br/>Plan: <%= $departure->{sched_arrival} %> % } @@ -51,33 +27,71 @@ % } % elsif ($departure->{arrival}) { % if ($departure->{arrival} ne $departure->{sched_arrival}) { - An: <span class="minfo"><%= $departure->{arrival} %></span> + % if (($departure->{arrival_delay} // 0) < 0) { + An: <span class="undelay"><%= $departure->{arrival} %></span> + % } + % else { + An: <span class="minfo"><%= $departure->{arrival} %></span> + % } <br/>Plan: <%= $departure->{sched_arrival} %> % } % else { An: <%= $departure->{arrival} %> % } % } +% elsif ($departure->{sched_arrival}) { + An: <%= $departure->{sched_arrival} %> +% } +% elsif ($departure->{prep_time}) { + Ein: <%= $departure->{prep_time} %> +% } +% if ($departure->{tz_offset} and $departure->{local_sched_arr}) { + <br/>Lokal: <%= $departure->{local_sched_arr}->strftime('%H:%M') %> +% } </div> </div> <div> <div class="platform"> +% if (@{$departure->{replaced_by}}) { +% for my $replacement (@{$departure->{replaced_by}}) { + <span class="replaced">Ersatzfahrt: <a href="/z/<%= $replacement %>/<%= stash('station_name') // q{} %>"><%= $replacement %></a></span><br/> +% } +% } +% if (@{$departure->{replacement_for}}) { +% for my $replacement (@{$departure->{replacement_for}}) { + <span class="replacement">Ersatzfahrt für <a href="/z/<%= $replacement %>/<%= stash('station_name') // q{} %>"><%= $replacement %></a></span><br/> +% } +% } % if ($departure->{arrival_is_cancelled} and $departure->{departure_is_cancelled}) { <span class="minfo">Fahrt fällt aus</span> % } % else { +% my $left = ''; +% my $right = ''; +% if ($departure->{wr_direction} and $departure->{wr_direction} =~ m{l}) { +% $left = '◀ '; +% } +% elsif ($departure->{wr_direction} and $departure->{wr_direction} =~ m{r}) { +% $right = ' ▶'; +% } % if ($departure->{scheduled_platform} and $departure->{platform} % and $departure->{scheduled_platform} ne $departure->{platform}) { - <span class="minfo">Gleis <%= $departure->{platform} %></span> + <span class="minfo"><%= $left %>Gleis <%= $departure->{platform} %><%= $right %></span> % } % elsif ($departure->{scheduled_platform} or $departure->{platform}) { - Gleis <%= $departure->{platform} // $departure->{scheduled_platform} %> + <%= $left %>Gleis <%= $departure->{platform} // $departure->{scheduled_platform} %><%= $right %> % } % } +% if ($departure->{arrival_hidden} and not $departure->{prep_time}) { + <br/><span class="timehidden">Nur Einstieg</span> +% } +% if ($departure->{departure_hidden}) { + <br/><span class="timehidden">Nur Ausstieg</span> +% } </div> </div> <div> - <div class="departure"> + <div class="departure <%= $departure->{departure_hidden} ? 'timehidden' : q{} %>"> % if ($departure->{is_cancelled} and $departure->{sched_departure}) { <span class="minfo">Ab: ––:––</span><br/>Plan: <%= $departure->{sched_departure} %> % } @@ -93,30 +107,96 @@ Ab: <%= $departure->{departure} %> % } % } +% elsif ($departure->{sched_departure}) { + Ab: <%= $departure->{sched_departure} %> +% } +% if ($departure->{tz_offset} and $departure->{local_sched_dep}) { + <br/>Lokal: <%= $departure->{local_sched_dep}->strftime('%H:%M') %> +% } </div> </div> </div> <!-- dataline --> +% if (my $wr = $departure->{wr}) { + <div class="wagonorder-preview"> +% my $left = defined $wr->direction ? $wr->direction == 100 ? q{} : '←' : q{}; +% my $right = defined $wr->direction ? $wr->direction == 100 ? '→' : q{} : q{}; +% if ($departure->{wr_direction} and $departure->{wr_direction} =~ m{l}) { +% $left = '◀'; +% $right = q{}; +% } +% elsif ($departure->{wr_direction} and $departure->{wr_direction} =~ m{r}) { +% $left = q{}; +% $right = '▶'; +% } + <a href="/carriage-formation?<%= $departure->{wr_link} %>&e=<%= $departure->{wr_direction} // '' %>"> + %= $left + % for my $entry ((defined $departure->{wr_direction_num} and $departure->{wr_direction_num} != $wr->direction) ? reverse @{$departure->{wr_preview} // []} : @{$departure->{wr_preview} // []}) { + % if ($entry->[1]) { + <span class="<%= $entry->[1] %>"><%= $entry->[0] %></span> + % } + % else { + %= $entry->[0] + % } + % } + %= $right + </a> + </div> +% } <div class="verbose"> % if ($departure->{trip_id}) { - <a class="smallbutton" href="/map/<%= $departure->{trip_id} %>/<%= $departure->{train_line} // 0 %>?from=<%= $station_name %>"><i class="material-icons" aria-hidden="true">map</i> Karte</a> -% } -% if ($departure->{wr_link} or ($icetype and $icetype->[1] and $departure->{train_type} ne 'Bus')) { -% if ($departure->{wr_link}) { - <a class="smallbutton" href="/_wr/<%= $departure->{train_no} %>/<%= $departure->{wr_link} %>"><i class="material-icons" aria-hidden="true">compare_arrows</i> Wagenreihung -% if ($icetype and $icetype->[1]) { - (Plan: <%= $icetype->[0] %>)<br/> -% } - </a> +% if (stash('station_name')) { + <a class="smallbutton" href="/map/<%= $departure->{trip_id} =~ s{#}{%23}gr %>/<%= $departure->{train_line} || 0 %>?from=<%= stash('station_name') %>&dbris=<%= param('dbris') %>&efa=<%= param('efa') // q{} %>&hafas=<%= param('hafas') // q{} %>"><i class="material-icons" aria-hidden="true">map</i> Karte</a> +% } +% else { + <a class="smallbutton" href="/map/<%= $departure->{trip_id} =~ s{#}{%23}gr %>/<%= $departure->{train_line} || 0 %>?dbris=<%= param('dbris') %>&efa=<%= param('efa') // q{} %>&hafas=<%= param('hafas') // q{} %>"><i class="material-icons" aria-hidden="true">map</i> Karte</a> % } % } +% if ($departure->{wr_link}) { + <a class="smallbutton" href="/carriage-formation?<%= $departure->{wr_link} %>&e=<%= $departure->{wr_direction} // '' %>"><i class="material-icons" aria-hidden="true">train</i> <%= $departure->{wr_text} || 'Wagen' %> + </a> +% } +% if ($departure->{trip_id} and param('dbris') and param('dbris') eq 'bahn.de') { + <a class="smallbutton" href="https://bahn.expert/details/x/h/<%= Mojo::Util::url_escape( $departure->{trip_id} ) %>"><img src="/static/icons/bahn-expert.svg">Details</a> +% } elsif ($departure->{train_type} and $departure->{train_no} and (not param('hafas') or param('hafas') eq 'DB')) { + <a class="smallbutton" href="https://bahn.expert/details/<%= $departure->{train_type} %>%20<%= $departure->{train_no} %>/<%= ($departure->{date} // DateTime->now(time_zone => 'Europe/Berlin'))->iso8601 %>?evaNumberAlongRoute=<%= $departure->{eva} %>"><img src="/static/icons/bahn-expert.svg">Details</a> +% } +% for my $link (@{$departure->{links}}) { + <a class="smallbutton" href="<%= $link->[1] %>"><i class="material-icons" aria-hidden="true">warning</i> <%= $link->[0] %></a> +% } </div> +% if (not $departure->{departure_is_cancelled}) { +% if (my $u = $departure->{utilization}) { + <div class="verbose"> +% my ($text, $icon1, $icon2) = utilization_icon($u); + <%= $text %><span style="padding-right: 0.5em;">.</span> 1. <i class="material-icons" aria-hidden="true" style="padding-right: 0.5em; vertical-align: bottom;"><%= $icon1 %></i> 2. <i class="material-icons" aria-hidden="true" style="vertical-align: bottom;"><%= $icon2 %></i> + </div> +% } +% elsif (my $o = $departure->{occupancy}) { + <div class="verbose"> +% my ($text, $icon) = occupancy_icon($o); + <%= $text %><span style="padding-right: 0.5em;">.</span> <i class="material-icons" aria-hidden="true" style="padding-right: 0.5em; vertical-align: bottom;"><%= $icon %></i></i> + </div> +% } +% } +% +% if ($departure->{missing_realtime}) { + <div class="verbose"> + <i class="material-icons no-realtime" aria-hidden="true" style="padding-right: 0.5em; vertical-align: bottom;">gps_off</i> Echtzeitdaten fehlen. Ob die Zugfahrt wie im Fahrplan vorgesehen stattfindet, ist nicht bekannt. + </div> +% } +% elsif ($departure->{no_realtime_yet}) { + <div class="verbose"> + <i class="material-icons" aria-hidden="true" style="padding-right: 0.5em; vertical-align: bottom;">gps_off</i> Für diese Zugfahrt sind derzeit nur Fahrplandaten bekannt. + </div> +% } + % if ($departure->{moreinfo} and @{$departure->{moreinfo}}) { - Meldungen: - <ul> + Meldungen + <ul class="messages"> % for my $pair (@{$departure->{moreinfo}}) { <li> -% if ($pair->[0]->isa('DateTime')) { +% if (ref($pair->[0]) eq 'DateTime') { % if ($pair->[0]->day != $dt_now->day) { % $pair->[0]->set_locale('de_DE'); %= $pair->[0]->strftime('%a %H:%M') @@ -124,16 +204,22 @@ % else { %= $pair->[0]->strftime('%H:%M') % } + <span class="reason"> +%= $pair->[1] + </span> % } % else { +% if ($pair->[1]{icon}) { + <i class="material-icons"><%= $pair->[1]{icon} %></i> +% } %= $pair->[0] % if (length($pair->[0]) > 25) { <br/> % } + <span class="reason"> +%= $pair->[1]{text} + </span> % } - <span class="reason"> -%= $pair->[1] - </span> </li> % } % if ($departure->{route_info}) { @@ -142,11 +228,33 @@ </ul> % } % if ($departure->{route_pre_diff} and $departure->{route_post_diff}) { - Fahrtverlauf: +% if ($departure->{date}) { + Fahrtverlauf am +% if (stash('train') !~ m{[|]}) { + <a href="<%= url_for('train', train => stash('train'))->query({detailed => param('detailed'), past => param('past'), rt => param('rt'), hafas => param('hafas'), date => $departure->{date}->clone->subtract(days => 1)->strftime('%d.%m.%Y'), highlight => param('highlight') // stash('station')}) %>">◀</a> +% } +%= $departure->{date}->strftime('%d.%m.%Y') +% if (stash('train') !~ m{[|]}) { + <a href="<%= url_for('train', train => stash('train'))->query({detailed => param('detailed'), past => param('past'), rt => param('rt'), hafas => param('hafas'), date => $departure->{date}->clone->add(days => 1)->strftime('%d.%m.%Y'), highlight => param('highlight') // stash('station')}) %>">▶</a> +% } +% } <ul class="mroute"> % for my $stop (@{$departure->{route_pre_diff}}) { - <li> - <a href="/<%= $stop->{name} %>#<%= $departure->{train_type} . $departure->{train_no} %>" class=" +% if ($stop->{is_annotated} and $stop->{prod_name}) { + <li class="annotation"> +% if ($stop->{prod_name}) { +%= $stop->{prod_name} +% } +% if ($stop->{direction}) { + → <%= $stop->{direction} %> +% } +% if ($stop->{operator}) { + (<%= $stop->{operator} %>) +% } + </li> +% } + <li class="<%= $stop->{isPast} ? 'past-stop' : 'future-stop' %>"> + <a href="<%= url_for('station', station => $stop->{eva} // $stop->{name})->query({detailed => param('detailed'), past => param('past'), rt => param('rt'), dbris => param('dbris'), efa => param('efa'), hafas => param('hafas')}) %>#<%= ((param('dbris') or param('hafas')) and $departure->{trip_id}) ? ($departure->{trip_id} =~ s{[ #|]}{x}gr) : (($departure->{train_type} // q{x}) . ($departure->{train_no} // q{x})) %>" class=" % if ($stop->{isAdditional}) { additional-stop % } @@ -159,18 +267,89 @@ % else { generic-stop % } -% if ($stop->{rt_dep}) { - "><%= $stop->{sched_dep}->strftime('%H:%M') %> (heute <%= $stop->{rt_dep}->strftime('%H:%M') %>) <%= $stop->{name} %></a> +% if (($stop->{rt_dep} and $stop->{dep_delay}) or (not $stop->{rt_dep} and $stop->{rt_arr} and $stop->{arr_delay})) { + "><span class="time-sched-only"><%= ($stop->{sched_dep} // $stop->{sched_arr})->strftime('%H:%M') %></span> <span class="time-delayed"><%= ($stop->{rt_dep} // $stop->{rt_arr})->strftime('%H:%M') %></span> +% } +% elsif (($stop->{rt_dep} and defined $stop->{dep_delay}) or (not $stop->{rt_dep} and $stop->{rt_arr} and defined $stop->{arr_delay})) { + "><span class="time-sched-ontime"><%= ($stop->{sched_dep} // $stop->{sched_arr}) ? ($stop->{sched_dep} // $stop->{sched_arr})->strftime('%H:%M') : q{} %></span> % } % else { - "><%= $stop->{sched_dep} ? $stop->{sched_dep}->strftime('%H:%M') : q{} %> <%= $stop->{name} %></a> + "><span class="time-sched"><%= ($stop->{sched_dep} // $stop->{sched_arr}) ? ($stop->{sched_dep} // $stop->{sched_arr})->strftime('%H:%M') : q{} %></span> +% } +% if ($stop->{tz_offset} and $stop->{local_dt_da}) { + (lokal <%= $stop->{local_dt_da}->strftime('%H:%M') %>) +% } + <%= $stop->{name} %></a> +% if ($stop->{load}{FIRST} or $stop->{load}{SECOND}) { +% my ($text, $icon1, $icon2) = utilization_icon([$stop->{load}{FIRST}, $stop->{load}{SECOND}]); + % if ($icon1 ne 'help_outline') { + <i class="material-icons" aria-hidden="true"><%= $icon1 %></i> + % } + <i class="material-icons" aria-hidden="true"><%= $icon2 %></i> % } </li> % } - <li class="<%= $departure->{is_cancelled} ? 'cancelled-stop' : q{} %>"><%= $departure->{departure} // $departure->{arrival} // q{} %> <strong><%= $station_name %></strong></li> +% if (stash('station_name')) { +% if ($departure->{is_annotated} and $departure->{prod_name}) { + <li class="annotation"> +% if ($departure->{prod_name}) { +%= $departure->{prod_name} +% } +% if ($departure->{direction}) { + → <%= $departure->{direction} %> +% } +% if ($departure->{operator}) { + (<%= $departure->{operator} %>) +% } + </li> +% } + <li class="<%= $departure->{is_cancelled} ? 'cancelled-stop' : q{} %> <%= $departure->{isPast} ? 'past-stop' : 'future-stop' %>"> +% if ($departure->{departure} and $departure->{sched_departure} and $departure->{departure} ne $departure->{sched_departure}) { + <span class="time-sched-only"><%= $departure->{sched_departure} // $departure->{sched_arrival} // q{} %></span><span class="time-delayed"> +% } +% elsif ($departure->{departure} and $departure->{sched_departure} and $departure->{departure} eq $departure->{sched_departure} and not $departure->{no_realtime_yet}) { + <span class="time-sched-ontime"> +% } +% elsif ($departure->{arrival} and $departure->{sched_arrival} and $departure->{arrival} ne $departure->{sched_arrival}) { + <span class="time-sched-only"><%= $departure->{sched_departure} // $departure->{sched_arrival} // q{} %></span><span class="time-delayed"> +% } +% elsif ($departure->{arrival} and $departure->{sched_arrival} and $departure->{arrival} eq $departure->{sched_arrival} and not $departure->{no_realtime_yet}) { + <span class="time-sched-ontime"> +% } +% else { + <span class="time-sched"> +% } +%= $departure->{departure} // $departure->{arrival} // $departure->{sched_departure} // $departure->{sched_arrival} // q{} + </span> +% if ($departure->{tz_offset} and $departure->{local_dt_da}) { + (lokal <%= $departure->{local_dt_da}->strftime('%H:%M') %>) +% } + <strong><%= stash('station_name') %></strong> +% if (my $u = $departure->{utilization}) { +% my ($text, $icon1, $icon2) = utilization_icon($u); + % if ($icon1 ne 'help_outline') { + <i class="material-icons" aria-hidden="true"><%= $icon1 %></i> + % } + <i class="material-icons" aria-hidden="true"><%= $icon2 %></i> +% } + </li> +% } % for my $stop (@{$departure->{route_post_diff}}) { - <li> - <a href="/<%= $stop->{name} %>#<%= $departure->{train_type} . $departure->{train_no} %>" class=" +% if ($stop->{is_annotated} and $stop->{prod_name}) { + <li class="annotation"> +% if ($stop->{prod_name}) { +%= $stop->{prod_name} +% } +% if ($stop->{direction}) { + → <%= $stop->{direction} %> +% } +% if ($stop->{operator}) { + (<%= $stop->{operator} %>) +% } + </li> +% } + <li class="<%= $stop->{isPast} ? 'past-stop' : 'future-stop' %>"> + <a href="<%= url_for('station', station => $stop->{eva} // $stop->{name})->query({detailed => param('detailed'), past => param('past'), rt => param('rt'), dbris => param('dbris'), efa => param('efa'), hafas => param('hafas')}) %>#<%= ((param('dbris') or param('hafas')) and $departure->{trip_id}) ? ($departure->{trip_id} =~ s{[ #|]}{x}gr) : (($departure->{train_type} // q{x}) . ($departure->{train_no} // q{x})) %>" class=" % if ($stop->{isAdditional}) { additional-stop % } @@ -183,14 +362,54 @@ % else { generic-stop % } -% if ($stop->{rt_arr}) { - "><%= $stop->{sched_arr}->strftime('%H:%M') %> (heute <%= $stop->{rt_arr}->strftime('%H:%M') %>) <%= $stop->{name} %></a> +% if (($stop->{rt_arr} and $stop->{arr_delay}) or (not $stop->{rt_arr} and $stop->{rt_dep} and $stop->{dep_delay})) { + "><span class="time-sched-only"><%= ($stop->{sched_arr} // $stop->{sched_dep})->strftime('%H:%M') %></span> <span class="time-delayed"><%= ($stop->{rt_arr} // $stop->{rt_dep})->strftime('%H:%M') %></span> +% } +% elsif (($stop->{rt_arr} and defined $stop->{arr_delay}) or (not $stop->{rt_arr} and $stop->{rt_dep} and defined $stop->{dep_delay})) { + "><span class="time-sched-ontime"><%= ($stop->{sched_arr} // $stop->{sched_dep}) ? ($stop->{sched_arr} // $stop->{sched_dep})->strftime('%H:%M') : q{} %></span> % } % else { - "><%= $stop->{sched_arr} ? $stop->{sched_arr}->strftime('%H:%M') : q{} %> <%= $stop->{name} %></a> + "><span class="time-sched"><%= ($stop->{sched_arr} // $stop->{sched_dep}) ? ($stop->{sched_arr} // $stop->{sched_dep})->strftime('%H:%M') : q{} %></span> +% } +% if ($stop->{tz_offset} and $stop->{local_dt_ad}) { + (lokal <%= $stop->{local_dt_ad}->strftime('%H:%M') %>) +% } + <%= $stop->{name} %></a> +% if ($stop->{load}{FIRST} or $stop->{load}{SECOND}) { +% my ($text, $icon1, $icon2) = utilization_icon([$stop->{load}{FIRST}, $stop->{load}{SECOND}]); + % if ($icon1 ne 'help_outline') { + <i class="material-icons" aria-hidden="true"><%= $icon1 %></i> + % } + <i class="material-icons" aria-hidden="true"><%= $icon2 %></i> % } </li> % } </ul> <!-- mroute --> % } +% if ($departure->{operators} and @{$departure->{operators} // []}) { + <div class="details">Betrieb: <%= join(q{, }, @{ $departure->{operators} // [] } ) %></div> +% } +% if ($departure->{details} and @{$departure->{details}}) { + <div class="details">Details: + <ul> +% for my $pair (@{$departure->{details}}) { + <li> +% if ($pair->[1]{icon}) { + <i class="material-icons"><%= $pair->[1]{icon} %></i> +% } +%= $pair->[0] +% if (length($pair->[0]) > 25) { + <br/> +% } + <span class="reason"> +%= $pair->[1]{text} + </span> + </li> +% } +% if ($departure->{route_info}) { + <li><%= $departure->{route_info} %></li> +% } + </ul> + </div> +% } </div> <!-- mfooter --> diff --git a/templates/_wagon.html.ep b/templates/_wagon.html.ep new file mode 100644 index 0000000..dccecc0 --- /dev/null +++ b/templates/_wagon.html.ep @@ -0,0 +1,97 @@ +% my $bg = ''; +% my $extra_class = ''; +% if ($wagon->has_first_class) { +% $extra_class .= ' firstclass'; +% } +% if ($wagon->is_locomotive or $wagon->is_powercar) { +% $extra_class .= ' powercar'; +% } +% if ($wagon->is_closed) { +% $extra_class .= ' closed'; +% } +% if ($group->train_no ne $train_no) { +% $extra_class .= ' nondestwagon'; +% } + <div class="wagon <%= $extra_class %>" style=" + top: <%= $wagon->start_percent %>%; bottom: <%= 100 - $wagon->end_percent %>%; <%= $bg %>"> +% if ($wagon->is_locomotive or $wagon->is_powercar) { +% } +% elsif ($wagon->is_closed) { + X +% } +% else { +%= $wagon->number // q{} +% if ($wagon->has_wheelchair_space) { + <i class="material-icons" style="font-size: 20px;">accessible</i> +% } +% if ($wagon->has_bistro) { + <i class="material-icons">restaurant</i> +% } +% if ($wagon->has_quiet_zone) { + <i class="tiny material-icons">volume_off</i> +% } +% if ($wagon->has_family_zone) { + <i class="material-icons">people</i> +% } +% if ($wagon->has_bahn_comfort) { + <i class="material-icons">star</i> +% } +% } + <div class="direction"> +% if (not defined $wr->direction) { +% } +% elsif ($wr->direction == 100) { + <i class="material-icons">arrow_downward</i> +% } +% else { + <i class="material-icons">arrow_upward</i> +% } + </div> + </div> + <div class="details" style=" + top: <%= $wagon->start_percent %>%; bottom: <%= 100 - $wagon->end_percent %>%;"> +% if ($exit_dir ne 'right') { +% if (my $img = wagon_image($wr->train_type // '?', $wagon->type, $wagon->uic_id)) { + <a class="type" href="/w/<%= $img %>?n=<%= $wagon->number // '' %>&s=<%= $wagon->section %>&r=<%= $wref %>"><%= $wagon->type %></a> +% } +% else { + <span class="type"> +%= $wagon->type + </span> +% } +% } +% my $uic_id = $wagon->uic_id; +% if (length($uic_id) != 12 and length($uic_id) != 14) { + <span class="uicunknown"><%= $uic_id %></span> +% } +% elsif (substr($uic_id, 0, 2) >= 90) { + <span class="uicexchange"><%= substr($uic_id, 0, 2) %></span><span class="uiccountry"><%= substr($uic_id, 2, 2) %></span><span class="uic5"><%= substr($uic_id, 4, 1) %></span><span class="uictype"><%= substr($uic_id, 5, 3) %></span><span class="uicno"><%= substr($uic_id, 8, 3) %></span><span class="uiccheck"><%= substr($uic_id, 11) %></span> +% } +% else { + <span class="uicexchange"><%= substr($uic_id, 0, 2) %></span><span class="uiccountry"><%= substr($uic_id, 2, 2) %></span><span class="uic56"><%= substr($uic_id, 4, 2) %></span><span class="uic78"><%= substr($uic_id, 6, 2) %></span><span class="uicno"><%= substr($uic_id, 8, 3) %></span><span class="uiccheck"><%= substr($uic_id, 11) %></span> +% } +% if ($exit_dir eq 'right') { +% if (my $img = wagon_image($wr->train_type // '?', $wagon->type, $wagon->uic_id)) { + <a class="type" href="/w/<%= $img %>?n=<%= $wagon->number // '' %>&s=<%= $wagon->section %>&r=<%= $wref %>"><%= $wagon->type %></a> +% } +% else { + <span class="type"> +%= $wagon->type + </span> +% } +% } +% if ($multi and $first) { + <br/> + <span class="groupno"> +% if (scalar $wr->train_numbers > 1) { + <%= $group->train_type %> <%= $group->train_no %> +% } +% if (scalar $wr->destinations > 1) { + → <%= $group->destination %> +% } + </span> + % if ($multi and $group->desc_short) { + <span class="grouptype"><%= $group->desc_short %></span> +% } +% } + </div> diff --git a/templates/about.html.ep b/templates/about.html.ep index 0c66e25..3bf8295 100644 --- a/templates/about.html.ep +++ b/templates/about.html.ep @@ -1,33 +1,51 @@ <div class="container"> <p> - <a href="https://finalrewind.org/projects/db-fakedisplay/">db-infoscreen</a> - v<%= stash('version') // '???' %><br/> - Entwickelt von <a href="https://twitter.com/derfnull">@derfnull</a><br/> - <br/> - Backends:<br/> - Abfahrtstafel: <a href="https://finalrewind.org/projects/Travel-Status-DE-IRIS/">Travel::Status::DE::IRIS</a> - v<%= $Travel::Status::DE::IRIS::VERSION %><br/> - Abfahrtstafel (Legacy): <a href="https://finalrewind.org/projects/Travel-Status-DE-DeutscheBahn/">Travel::Status::DE::HAFAS</a> - v<%= $Travel::Status::DE::HAFAS::VERSION %><br/> - Meldungen und Ankunft/Abfahrt an Unterwegshalten: DB HAFAS<br/> - Wagenreihung: <a href="https://finalrewind.org/projects/Travel-Status-DE-DBWagenreihung/">Travel::Status::DE::DBWagenreihung</a> - v<%= $Travel::Status::DE::DBWagenreihung::VERSION %><br/> - Karte: <a href="https://2.db.transport.rest/">transport.rest</a> von <a href="https://github.com/derhuerst">@derhuerst</a><br/> - <br/> - Grundlage der <a href="https://data.deutschebahn.com/dataset/zugbildungsplanzugbildungsplan-zpar">Wagengattungsdaten</a> © DB Fernverkehr AG, lizensiert unter CC-BY 4.0 - <br/> - Grundlage der <a href="http://data.deutschebahn.com/dataset/data-haltestellen">Haltestellendaten</a> + DBF ist ein inoffizieller Abfahrtsmonitor für Nah-, Regional- und Fernverkehr in Deutschland und Umgebung. + Die Fahrten in der Übersicht verlinken je eine Detailseite mit Unterwegshalten, Meldungen und Kartendarstellung. + Bei HAFAS-Backends ist zusätzlich die Suche nach spezifischen Fahrten möglich. + </p> + <p> + Der <a href="<%= app->config->{'source_url'} %>">Quelltext</a> steht unter der <a href="https://git.finalrewind.org/db-fakedisplay/tree/COPYING">GNU AGPL v3</a> als Open Source zur Verfügung. © 2011 – 2024 <a href="https://finalrewind.org">derf</a>. + % if (my $issue_url = app->config->{'issue_url'}) { + Fehlermeldungen bitte via + <a href="<%= $issue_url %>">Issue Tracker</a>. + % } + Alle von DBF referenzierten Informationen können auch direkt per CLI im Text- oder JSON-Format abgerufen werden – die unten verlinkten Backends beinhalten entsprechende Anwendungen. + </p> + <p> + Diese Installation nutzt + <strong>DBF v<%= stash('version') // '???' %></strong> mit folgenden Backends: + <ul> + <li>Innerdeutscher Regional- und Fernverkehr: DB IRIS via <a href="https://finalrewind.org/projects/Travel-Status-DE-IRIS/">Travel::Status::DE::IRIS</a> + <strong>v<%= $Travel::Status::DE::IRIS::VERSION %></strong></li> + <li>Nah-, Regional- und Fernverkehr im In- und Ausland: bahn.de via <a href="https://finalrewind.org/projects/Travel-Status-DE-DBRIS/">Travel::Status::DE::DBRIS</a> + <strong>v<%= $Travel::Status::DE::DBRIS::VERSION %></strong></li> + <li>Nah-, Regional- und Fernverkehr im In- und Ausland: EFA via <a href="https://finalrewind.org/projects/Travel-Status-DE-VRR/">Travel::Status::DE::EFA</a> + <strong>v<%= $Travel::Status::DE::EFA::VERSION %></strong></li> + <li>Nah-, Regional- und Fernverkehr im In- und Ausland: HAFAS via <a href="https://finalrewind.org/projects/Travel-Status-DE-DeutscheBahn/">Travel::Status::DE::HAFAS</a> + <strong>v<%= $Travel::Status::DE::HAFAS::VERSION %></strong></li> + <li>Nah-, Regional- und Fernverkehr im In- und Ausland: MOTIS via <a href="https://finalrewind.org/projects/Travel-Status-MOTIS/">Travel::Status::MOTIS</a> + <strong>v<%= $Travel::Status::MOTIS::VERSION %></strong></li> + </ul> + </p> + <p> + Verwendete Ressourcen: + <ul> + <li><a href="/_backend">HAFAS-Backends</a> via <a href="https://github.com/public-transport/transport-apis">transport-apis</a>, CC0</li> + <li><a href="https://data.deutschebahn.com/dataset/zugbildungsplanzugbildungsplan-zpar">Zugbildungsplan</a> © DB Fernverkehr AG, lizensiert unter CC-BY 4.0</li> + <li><a href="http://data.deutschebahn.com/dataset/data-haltestellen">Haltestellenliste</a> © DB Station&Service AG, Europaplatz 1, - 10557 Berlin, lizensiert unter CC-BY 4.0<br/> + 10557 Berlin, lizensiert unter CC-BY 4.0</li> + <li><a href="https://data.deutschebahn.com/dataset/fahrzeuglexikon">Fahrzeuglexikon</a> + © DB Fernverkehr AG, lizensiert unter CC-BY 4.0; Abbildungen © Seemanngrafik d.i.p. im Auftrag der Deutschen Bahn AG, lizensiert unter CC-BY-SA 4.0</li> + </ul> </p> -</div> - -<div class="container"> <p> - <a href="https://twitter.com/derfnull">Kontakt</a> - · - <a href="https://github.com/derf/db-fakedisplay/issues">Bugs?</a> + Trivia: Das Projekt begann als „db-fakedisplay“ (kurz dbf) zur + Nachahmung von Bahnhofs-Abfahrtstafeln. Inzwischen liegt der Fokus auf + der Bereitstellung von Informationen für mobile und Desktop-Anwendungen + und die Bezeichnung DBF wurde zum Eigennamen ohne weitere Bedeutung. </p> </div> diff --git a/templates/app.html.ep b/templates/app.html.ep index 9b7f8ab..8b52c61 100644 --- a/templates/app.html.ep +++ b/templates/app.html.ep @@ -1,7 +1,7 @@ % if (@{$departures}) { % if (not param('ajax')) { -<div class="app"> +<div class="app" data-station="<%= $station %>"> <div class="moreinfo collapsed-moreinfo"> <div class="mheader"> <div> @@ -29,48 +29,48 @@ % $via_cur++; % $route_str .= $stop . ($via_cur < $via_max ? ' - ' : q{}); % } -% my $linetype = 'bahn'; -% if ( $departure->{train_type} eq 'S' ) { -% $linetype = 'sbahn'; -% } -% elsif ( $departure->{train_type} eq 'IC' -% or $departure->{train_type} eq 'ICE' -% or $departure->{train_type} eq 'EC' -% or $departure->{train_type} eq 'ECE' -% or $departure->{train_type} eq 'EN') { -% $linetype = 'fern'; -% } -% elsif ( $departure->{train_type} eq 'THA' -% or $departure->{train_type} eq 'TGV' -% or $departure->{train_type} eq 'FLX' -% or $departure->{train_type} eq 'NJ') { -% $linetype = 'ext'; -% } -% elsif ( $departure->{train_line} and $departure->{train_line} =~ m{^S\d} ) { -% $linetype = 'sbahn'; -% } <li +% if (param('dbris') or param('hafas') or param('efa')) { + data-jid="<%= $departure->{journey_id} =~ s{#}{%23}gr %>" +% } data-train="<%= ($departure->{train_type} // q{}) %> <%= ($departure->{train_no} // $departure->{train} // q{}) %>" data-line="<%= $departure->{train_type} %> <%= $departure->{train_line} // $departure->{train_no} %>" data-no="<%= $departure->{train_line} ? $departure->{train_no} : q{} %>" - data-linetype="<%= $linetype %>" + data-linetype="<%= $departure->{linetype} %>" data-from="<%= $departure->{origin} // q{???} %>" data-to="<%= $departure->{destination} // q{???} %>" + data-station="<%= $departure->{station} // $station %>" data-platform="<%= $departure->{scheduled_platform} // $departure->{platform} // '' %>" data-arrival="<%= $departure->{sched_arrival} // '' %>" data-departure="<%= $departure->{sched_departure} // '' %>" - data-moreinfo="<%= join(q{|}, map { ($_->[0]->isa('DateTime') ? $_->[0]->strftime('%H:%M') : $_->[0]) . ' ' . $_->[1] } @{ $departure->{moreinfo} // [] } ) %>" + data-moreinfo="<%= join(q{|}, map { ($_->[0]->isa('DateTime') ? $_->[0]->strftime('%H:%M') . ' ' . $_->[1] : $_->[0] . ' ' . $_->[1]{text}) } @{ $departure->{moreinfo} // [] } ) %>" data-routeprev="<%= join(q{|}, @{ $departure->{route_pre} // [] } ) %>" data-routenext="<%= join(q{|}, @{ $departure->{route_post} // [] } ) %>" -% my $extraclasses = q{}; % if ($departure->{is_cancelled} or $departure->{departure_is_cancelled}) { -% $extraclasses .= ' cancelled'; class="cancelled"> % } % else { > % } - <div class="line <%= $linetype %>"> +% if (param('hafas')) { + <a href="/z/<%= Mojo::Util::url_escape($departure->{journey_id}) . '?hafas=' . Mojo::Util::url_escape(param('hafas')) . '&highlight=' . Mojo::Util::url_escape($departure->{station} // $station) %>"> +% } +% elsif (param('efa')) { + <a href="/z/<%= Mojo::Util::url_escape($departure->{journey_id}) . '?efa=' . Mojo::Util::url_escape(param('efa')) . '&highlight=' . Mojo::Util::url_escape($departure->{station} // $station) %>"> +% } +% elsif (param('dbris')) { + <a href="/z/<%= Mojo::Util::url_escape($departure->{journey_id}) . '?dbris=' . Mojo::Util::url_escape(param('dbris')) . '&highlight=' . Mojo::Util::url_escape($departure->{station} // $station) %>"> +% } +% else { + <a href="/z/<%= Mojo::Util::url_escape(($departure->{train_type} // q{}) . ' ' . ($departure->{train_no} // $departure->{train} // q{})) . '/' . Mojo::Util::url_escape($departure->{station} // $station) %>"> +% } +% if (param('dbris') or param('hafas')) { + <div class="anchor" id="<%= $departure->{journey_id} =~ s{[ #|]}{x}gr %>"></div> +% } +% else { + <div class="anchor" id="<%= ($departure->{train_type} // q{x}) . ($departure->{train_no} // q{x}) %>"></div> +% } + <div class="line <%= $departure->{linetype} %>"> % if ($departure->{train_type} and $departure->{train_no}) { %= $departure->{train_type} % } @@ -78,9 +78,6 @@ %= $departure->{train_line} % } % elsif ($departure->{train_no}) { -% if (exists $ice_type->{$departure->{train_no}} and $ice_type->{$departure->{train_no}}[1]) { - <span class="trainsubtype" aria-hidden="true"><%= $ice_type->{$departure->{train_no}}[1] %></span> -% } <span class="trainno"><%= $departure->{train_no} %></span> % } % else { @@ -102,71 +99,100 @@ % } </div> % } - <span class="dest <%= $extraclasses %>" aria-label="nach <%= $departure->{destination} %>"> -%= $departure->{destination} - </span> - <span class="time <%= ($show_realtime and $departure->{delay} and not - $departure->{is_cancelled}) ? 'delayed' : q{} %> <%= $extraclasses %>"> -% if (param('detailed')) { -% my $arrow = '→'; -% if (not $departure->{sched_arrival}) { -% $arrow = '↦'; -% } -% elsif (not $departure->{sched_departure}) { -% $arrow = '⇥'; -% } -% if ($show_realtime) { -%= ($departure->{arrival} // q{}) . $arrow . ($departure->{departure} // q{}) -% } -% else { -%= ($departure->{sched_arrival} // q{}) . $arrow . ($departure->{sched_departure} // q{}) -% } +% if ($departure->{sched_departure}) { + <span class="dest"> + <span class="visually-hidden">nach</span> +%= $departure->{destination} + </span> % } % else { -%= $departure->{time} + <span class="origin"> + <span class="visually-hidden">von</span> +%= $departure->{origin} + </span> % } - </span> - <span class="countdown <%= $extraclasses %>"> -% if ($departure->{delay} and not $departure->{is_cancelled}) { -% my $aria_delay = sprintf("Verspätung %d Minuten", $departure->{delay}); -% if ($show_realtime) { -% if ($departure->{delay} > 0) { - <span class="delaynorm" aria-label="<%= $aria_delay %>">(+<%= $departure->{delay} %>)</span> + <span class="time <%= $show_realtime ? get_rt_time_class($departure) : q{} %>"> +% if ($departure->{delay} and not $departure->{is_cancelled} and not $departure->{departure_is_cancelled}) { +% if ($show_realtime and ($departure->{sched_arrival} or $departure->{sched_departure})) { +% if ($departure->{delay} > ($hide_low_delay ? 4 : 0)) { + <span class="delaynorm" aria-hidden="true"><%= $departure->{sched_departure} // $departure->{sched_arrival} %> ⇒</span> +% } +% elsif ($departure->{delay} < 0) { + <span class="undelaynorm" aria-hidden="true"><%= $departure->{sched_departure} // $departure->{sched_arrival} %> ⇒</span> +% } +% } +% else { +% if ($departure->{delay} > ($hide_low_delay ? 4 : 0)) { + <span class="delay" aria-hidden="true">+<%= $departure->{delay} %></span> +% } +% elsif ($departure->{delay} < 0) { + <span class="undelay" aria-hidden="true"><%= $departure->{delay} %></span> +% } +% } +% } +% elsif ($departure->{missing_realtime}) { + <span class="visually-hidden">Echtzeitdaten fehlen</span> + <span class="no-realtime" aria-hidden="true"><i class="material-icons">gps_off</i></span> +% } +% if (param('detailed')) { +% my $arrow = '→'; +% if (not $departure->{sched_arrival}) { +% $arrow = '↦'; +% } +% elsif (not $departure->{sched_departure}) { +% $arrow = '⇥'; +% } +% if ($show_realtime) { +%= ($departure->{arrival} // q{}) . $arrow . ($departure->{departure} // q{}) % } % else { - <span class="undelaynorm" aria-label="<%= $aria_delay %>">(<%= $departure->{delay} %>)</span> +%= ($departure->{sched_arrival} // q{}) . $arrow . ($departure->{sched_departure} // q{}) % } % } % else { -% if ($departure->{delay} > 0) { - <span class="delay" aria-label="<%= $aria_delay %>">(+<%= $departure->{delay} %>)</span> +% if ($departure->{is_cancelled} or $departure->{departure_is_cancelled}) { +%= $departure->{sched_departure} // $departure->{sched_arrival} // $departure->{time} % } % else { - <span class="undelay" aria-label="<%= $aria_delay %>">(<%= $departure->{delay} %>)</span> +%= $departure->{time} % } % } -% } + </span> % if (($departure->{scheduled_platform} and $departure->{platform} and % $departure->{scheduled_platform} ne $departure->{platform}) % or $departure->{changed_platform}) { - <span class="platform changed-platform" aria-label="Gleis <%= $departure->{platform} %>"> + <span class="platform changed-platform"> % } % else { - <span class="platform" aria-label="Gleis <%= $departure->{platform} %>"> + <span class="platform"> % } +% if ($departure->{load}{FIRST} or $departure->{load}{SECOND}) { +% my ($text, $icon1, $icon2) = utilization_icon([$departure->{load}{FIRST}, $departure->{load}{SECOND}]); + <span class="load"> + <i class="material-icons" style="vertical-align: bottom;" aria-hidden="true"><%= $icon2 %></i> + </span> +% } +% elsif (my $o = $departure->{occupancy}) { + <span class="load"> +% my ($text, $icon) = occupancy_icon($o); + <i class="material-icons" style="vertical-align: bottom;" aria-hidden="true"><%= $icon %></i> + </span> +% } + <span class="visually-hidden">Gleis</span> %= $departure->{platform} </span> - </span> % if ($departure->{info} and length $departure->{info}) { <span class="info"> %= $departure->{info} </span> % } % else { - <span class="route" aria-label="Über <%= $route_str %>"> + <span class="route"> + <span class="visually-hidden">über</span> %= $route_str </span> % } + </a> </li> % } diff --git a/templates/coverage_map.html.ep b/templates/coverage_map.html.ep new file mode 100644 index 0000000..bd3d94c --- /dev/null +++ b/templates/coverage_map.html.ep @@ -0,0 +1,22 @@ +<div class="container"> + Das <%= $backend %>-Backend „<%= $service %>“ liefert ungefähr innerhalb + der folgenden grob umrissenen Region voraussichtlich nützliche Echtzeitdaten. +</div> + +<div class="container"> + <div id="map" style="height: 70vh;"> + </div> +</div> + +<script> +const map = L.map('map').setView([51.306, 9.712], 6); + +L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { + attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' +}).addTo(map); + +const coverage = L.geoJSON(<%== $coverage %>); + +coverage.addTo(map); +map.fitBounds(coverage.getBounds()); +</script> diff --git a/templates/exception.html.ep b/templates/exception.html.ep index 2f20bc6..7654c0b 100644 --- a/templates/exception.html.ep +++ b/templates/exception.html.ep @@ -4,9 +4,14 @@ Beim Bearbeiten der Anfrage ist ein Fehler aufgetreten.<br/> <pre> ----------[Debug start]---------- -%= $exception->message +% if ($exception) { +%= ref($exception) ? $exception->message : $exception Stash: %= dumper $snapshot +% } +% else { +%= stash('message') +% } ----------[Debug end]---------- </pre> </div> diff --git a/templates/geolocation.html.ep b/templates/geostop.html.ep index 843892d..843892d 100644 --- a/templates/geolocation.html.ep +++ b/templates/geostop.html.ep diff --git a/templates/landingpage.html.ep b/templates/landingpage.html.ep index b30a358..80fd34f 100644 --- a/templates/landingpage.html.ep +++ b/templates/landingpage.html.ep @@ -1,20 +1,31 @@ % if (stash 'show_intro') { <div class="container"> -<p> - Diese Seite ist ein inoffizielles Frontend zum Abfahrtsmonitor - der DB. In den Standardeinstellungen bietet sie eine Handy- und - Desktop-geeignete Abfahrtstafel. Sie kann ebenfalls für großformatige - Infobildschirme genutzt werden oder die in Schalterhallen und an Gleisen - montierten Anzeigen nachhahmen. -</p> -<p> -Alle Angaben ohne Gewähr. -</p> +% if (0) { + <p> + DBF is an unofficial departure monitor for regional and long-distance trains within Germany, aiming to combine multiple data sources in a useful manner. + It also has limited support for local transit and traffic outside of Germany. + </p> + <p> + This site is operated by a private entity in a not-for-profit manner. + There are no uptime or reliability guarantees whatsoever. + </p> +% } +% else { + <p> + DBF ist ein inoffizieller Abfahrtsmonitor für Nah-, Regional- und Fernverkehr in Deutschland und Umgebung mit dem Ziel, Daten aus verschiedenen Quellen zusammenzutragen. + Es unterstützt neben Fahrten im Netz der DB InfraGO diverse Nah- und Fernverkehrsunternehmen mit EFA- und HAFAS-Backends. + Die Fahrten in der Übersicht verlinken je eine Detailseite mit Unterwegshalten, Meldungen und Kartendarstellung. + </p> + <p> + Diese Seite ist ein kostenfreies, privat betriebenes Projekt ohne Verfügbarkeitsgarantie. + Alle Angaben ohne Gewähr. + </p> +% } <p class="geolink"> -<a class="button" href="<%= url_for('_auto')->to_abs->scheme('https') %>">Bahnhöfe im Umfeld suchen</a> +<a class="button" href="<%= url_for('_autostop')->to_abs->scheme('https')->query({efa => param('efa'), hafas => param('hafas')}) %>">Stationen in der Umgebung suchen</a> </p> <p> -Oder hier angeben: +Oder hier eine Station angeben: </p> </div> % } diff --git a/templates/layouts/app.html.ep b/templates/layouts/app.html.ep index 3c79173..c557bee 100644 --- a/templates/layouts/app.html.ep +++ b/templates/layouts/app.html.ep @@ -4,8 +4,8 @@ <title><%= stash('title') // 'DBF' %></title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <meta name="keywords" content="Abfahrtsmonitor, Bahnhofstafel, Abfahrten, Abfahrtstafel, ICE, IC, RE, RB, S-Bahn"> - <meta name="description" content="Inoffizieller Abfahrtsmonitor für Bahnhöfe der DB"> + <meta name="keywords" content="Abfahrtsmonitor, Bahnhofstafel, Abfahrten, Abfahrtstafel, Nahverkehr, Regionalverkehr, Fernverkehr, ICE, IC, RE, RB, S-Bahn"> + <meta name="description" content="<%= stash('description') // 'Inoffizieller Abfahrtsmonitor für Nah-, Reginol- und Fernverkehr' %>"> <meta name="theme-color" content="#00838f"> <link rel="icon" type="image/png" href="/static/icons/icon-16x16.png" sizes="16x16"> <link rel="icon" type="image/png" href="/static/icons/icon-32x32.png" sizes="32x32"> @@ -18,7 +18,7 @@ <meta http-equiv="refresh" content="<%= $self->stash('refresh_interval') %>"/> % } - % my $av = 'v30'; # asset version + % my $av = 'v110'; # asset version % if (session('theme') and session('theme') eq 'dark' or param('dark')) { %= stylesheet "/static/${av}/css/dark.min.css", id => 'theme' % } @@ -27,14 +27,14 @@ % } <script> function addStyleSheet(name, id) { - var path = '/static/<%=$av%>/css/' + name + '.min.css'; - var old = document.getElementById(id); + const path = '/static/<%=$av%>/css/' + name + '.min.css'; + const old = document.getElementById(id); if (old && (old.href != path)) { old.href = path; - document.cookie = 'theme=' + name; + document.cookie = 'theme=' + name + ';SameSite=None;Secure'; } } - var otherTheme = { + const otherTheme = { 'dark': 'light', 'light': 'dark', }; @@ -43,20 +43,17 @@ currentTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; } addStyleSheet(currentTheme, 'theme'); - - function toggleTheme() { - currentTheme = otherTheme[currentTheme] || 'light'; - localStorage.setItem('theme', currentTheme); - addStyleSheet(currentTheme, 'theme'); - } </script> %= stylesheet "/static/${av}/css/material-icons.css" %= stylesheet "/static/${av}/css/jquery-ui.min.css" %= javascript '/static/js/jquery-3.4.1.min.js', defer => undef %= javascript "/static/${av}/js/jquery-ui.min.js", defer => undef %= javascript "/static/${av}/js/dbf.min.js", defer => undef - % if (stash('with_geolocation')) { - %= javascript "/static/${av}/js/geolocation.min.js", defer => undef + % if (not stash('hide_opts')) { + %= javascript "/dyn/${av}/autocomplete.js", defer => undef + % } + % if (stash('with_geostop')) { + %= javascript "/static/${av}/js/geostop.min.js", defer => undef % } % if (stash('with_map')) { %= stylesheet "/static/${av}/leaflet/leaflet.css" @@ -69,20 +66,28 @@ <div class="navbar-fixed"> <nav style="color: #ffffff; background-color: #00838f;"> <div class="nav-wrapper container"> - <span class="brand-logo"> - %= stash('title') || 'DBF' - </span> + % if (my $nav_link = stash('nav_link')) { + <a class="brand-logo" style="float: left;" href="<%= $nav_link %>"> + %= stash('title') || 'DBF' + </a> + % } + % else { + <span class="brand-logo"> + %= stash('title') || 'DBF' + </span> + % } <ul id="nav-mobile" style="float: right;"> - <li class="waves-effect waves-light"> - <a onClick="javascript:toggleTheme()"><i class="material-icons" aria-label="Farbschema invertieren">invert_colors</i></a> - </li> + % if (stash('api_link')) { + <li class="waves-effect waves-light"> + <a href="<%= stash('api_link') %>"><span class="visually-hidden"><%= stash('api_text') %></span><i class="material-icons" aria-hidden="true"><%= stash('api_icon') %></i></a> + </li> + % } % if (stash('hide_opts')) { - <li><a href="/"><i class="material-icons" aria-label="Hauptseite">edit</i></a></li> + <li><a href="/"><span class="visually-hidden">Hauptseite</span><i class="material-icons" aria-hidden="true">edit</i></a></li> % } % else { - <li><a href="#stationinput"><i class="material-icons" aria-label="Menü">edit</i></a></li> + <li><a href="#stationinput"><span class="visually-hidden">Menü</span><i class="material-icons" aria-hidden="true">edit</i></a></li> % } - <li><a href="/_auto"><i class="material-icons" aria-label="Stationen in der Umgebung suchen">my_location</i></a></li> </ul> </div> </nav> @@ -91,9 +96,9 @@ <div class="container"> % if (my $error = stash 'error') { <div class="error"><strong>Fehler:</strong> -<pre> +<p> %= $error -</pre> +</p> </div> % } % elsif (stash('stationlist')) { @@ -112,62 +117,55 @@ Bitte eine Station aus der Liste auswählen</div> %= form_for _redirect => begin +%= hidden_field efa => param('efa') +%= hidden_field hafas => param('hafas') <div> <div class="field"> - <div class="desc">Bahnhof / Haltestelle</div> - <div> -% if (stash('stationlist')) { - %= select_field station => stash('stationlist') -% } -% elsif (stash('station')) { - %= text_field 'station', class => 'station', placeholder => 'Name oder DS100-Kürzel', id => 'stationinput' -% } -% else { - %= text_field 'station', class => 'station', placeholder => 'Name oder DS100-Kürzel', id => 'stationinput', autofocus => 'autofocus' -% } - </div> +% if (stash('stationlist')) { + %= select_field input => stash('stationlist') +% } +% elsif (stash('input')) { + %= text_field 'input', class => 'station', placeholder => 'Stationsname oder Fahrtnummer', id => 'stationinput' +% } +% else { + %= text_field 'input', class => 'station', placeholder => 'Stationsname oder Fahrtnummer', id => 'stationinput', autofocus => 'autofocus' +% } </div> <div class="field"> - %= submit_button 'Abfahrtsmonitor' + %= submit_button 'Abfahrtstafel' </div> - % if (not stash('show_intro')) { - <div class="break"></div> - <div class="field"> - <a class="button" href="<%= url_for('_auto')->to_abs->scheme('https') %>">Bahnhöfe im Umfeld suchen</a> + % if (stash('input')) { + <div class="geolink"> + <a class="button" href="<%= url_for('_autostop')->to_abs->scheme('https')->query({efa => param('efa'), hafas => param('hafas')}) %>">Stationen in der Umgebung suchen</a> </div> % } + <div class="backendlink"> + <a class="button button-light" href="<%= url_for('_backend')->query({efa => param('efa'), hafas => param('hafas')}) %>">Backend: <%= param('efa') ? param('efa') . ' (EFA)' : param('hafas') ? param('hafas') . ' (HAFAS)' : 'DB (IRIS-TTS)' %></a> + </div> <div class="break"></div> <div class="moresettings-header moresettings-header-collapsed button button-light">Weitere Einstellungen</div> <div class="moresettings moresettings-collapsed"> <div class="field"> <div class="desc"> - Frontend - </div> - <div> - %= select_field mode => [ ['App' => 'app'], ['Infoscreen' => 'infoscreen'], ['Bahnhofstafel' => 'multi'], ['Gleisanzeiger' => 'single'] ] - </div> - </div> - <div class="field"> - <div class="desc"> - Nur Züge über - </div> - <div> - %= text_field 'via', placeholder => 'Bahnhof 1, Bhf2, ... (oder regulärer Ausdruck)', class => 'station' + %= check_box 'hidelowdelay' => 1, id => 'id_hidelowdelay' + <label for="id_hidelowdelay"> + Verspätungen erst ab 5 Minuten anzeigen + </label> </div> </div> <div class="field"> <div class="desc"> - Gleise - </div> - <div> - %= text_field 'platforms', placeholder => '1, 2, 5, ...' + %= check_box 'detailed' => 1, id => 'id_detailed' + <label for="id_detailed"> + Mehr Details + </label> </div> </div> <div class="field"> <div class="desc"> - %= check_box 'hidelowdelay' => 1, id => 'id_hidelowdelay' - <label for="id_hidelowdelay"> - Verspätungen erst ab 5 Minuten anzeigen + %= check_box 'past' => 1, id => 'past' + <label for="past"> + Fahrten der vergangenen 60 Minuten zeigen </label> </div> </div> @@ -175,40 +173,40 @@ Bitte eine Station aus der Liste auswählen</div> <div class="desc"> %= check_box 'hide_opts' => 1, id => 'id_hide_opts' <label for="id_hide_opts"> - Formular verstecken (für Infoscreens) + Formular verstecken </label> </div> </div> <div class="field"> <div class="desc"> - Ankunfts- oder Abfahrtszeit anzeigen? + Nur Fahrten über </div> <div> - %= select_field admode => [['Abfahrt bevorzugen' => 'deparr'], ['Nur Abfahrt' => 'dep'], ['Nur Ankunft' => 'arr']] + %= text_field 'via', placeholder => 'Bahnhof 1, Bhf2, ... (oder regulärer Ausdruck)', class => 'station' </div> </div> <div class="field"> <div class="desc"> - %= check_box 'detailed' => 1, id => 'id_detailed' - <label for="id_detailed"> - Mehr Details (Zugnummern und Ankunftszeiten) anzeigen - </label> + Gleise + </div> + <div> + %= text_field 'platforms', placeholder => '1, 2, 5, ...' </div> </div> <div class="field"> <div class="desc"> - %= check_box 'show_realtime' => 1, id => 'id_show_realtime' - <label for="id_show_realtime"> - Echtzeitangaben statt Fahrplandaten anzeigen - </label> + Ankunfts- oder Abfahrtszeit anzeigen? + </div> + <div> + %= select_field admode => [['Abfahrt bevorzugen' => 'deparr'], ['Nur Abfahrt' => 'dep'], ['Nur Ankunft' => 'arr']] </div> </div> <div class="field"> <div class="desc"> - %= check_box 'no_related' => 1, id => 'id_no_related' - <label for="id_no_related"> - Betriebliche Bahnhofstrennungen berücksichtigen (z.B. "Hbf (Fern+Regio)" vs. "Hbf (S)") - </label> + Frontend + </div> + <div> + %= select_field mode => [ ['App' => 'app'], ['Infoscreen' => 'infoscreen'], ['Bahnhofstafel (legacy)' => 'multi'], ['Gleisanzeiger (legacy)' => 'single'] ] </div> </div> <div class="field"> @@ -221,52 +219,99 @@ Bitte eine Station aus der Liste auswählen</div> </div> <!-- input-field --> <div class="notes"> - <div class="developers-header developers-header-collapsed button button-light">API- und Entwickler-Hinweise</div> + <div class="developers-header developers-header-collapsed button button-light">API</div> <div class="developers developers-collapsed"> <ul> - <li>Diese Seite kann gerne als iframe in eigene Infoscreens o.ä. eingebunden werden. - Für eine kleine Ansicht (z.B. iframe in einer normalen Website) bitte das - "App"-Frontend verwenden. Für eine große Ansicht - (z.B. als alleinstehender Infoscreen) gibt es das "Infoscreen"-Frontend.</li> - <li>Die Parameter <span style="font-family: monospace;">mode=json&version=3</span> - (alternativ auch <span style="font-family: - monospace;">https://dbf.finalrewind.org/Bahnhofsname.json?version=3</span>) - bieten ein JSON-IRIS-Interface. Die route-Elemente können zusätzlich - die Felder "isAdditional" oder "isCancelled" enthalten, der Rest sollte - selbsterklärend sein. Im Fehlerfall fehlt das "departures"-Element, - stattdessen wird ein "error"-Element mit Fehlermeldung zurückgegeben. - Bitte nur eine Anfrage pro Station und Minute - – eine höhere Auflösung haben die Backenddaten ohnehin nicht.</li> - <li>Mit <span style="font-family: monospace;">limit</span> kann die Anzahl der - angezeigten / im JSON enthaltenen Abfahrten eingeschränkt werden, z.B. - <span style="font-family: monospace;">limit=10</span> für die ersten zehn.</li> - <li>Dieser Dienst ist Open Source-Software (Links siehe unten) und kann - mittels carton/cpanminus oder Docker auf eigenen Servern installiert - werden. Automatisierte Crawler, die mehrere Dutzend Stationen pro Minute - abfragen, bitte nur auf eigenen Instanzen betreiben.</li> + % if (0) { + <li>You're welcome to embed DBF departure boards as iframes or use them + in full-screen browser setups. The App frontend works best for + small screens, whereas the legacy Infoscreen mode is better suited + for large displays.</li> + <li>The departure board supports names, EVA IDs, and (in IRIS mode) + DS100/Ril100 codes as station identifiers.</li> + <li>Requests for train details can optionally be suffixed with the + DD.MM.[YYYY] date of the requested trip, e.g. "ICE 921 (1.1.)" or + "ICE 921 @ 1.1.". The date refers to the scheduled departure at the + train's origin station.</li> + <li>A JSON IRIS API is avaliable via + <span style="font-family: monospace;">mode=json&version=3</span> + (or just <span style="font-family: monospace;">https://dbf.finalrewind.org/Station.json?version=3</span>). + Route elements may contain "isAdditional" and "isCancelled"; the rest + should be self-explanatory. Please do not send more than 30 requests + per minute and only one request per station per minute.</li> + <li>There is no JSON API for train details yet.</li> + <li>The optional <span style="font-family: monospace;">limit</span> + parameter limits the number of returnd departures; e.g. + <span style="font-family: monospace;">limit=10</span> will result in no more than ten.</li> + <li>DBF is available as Open Source software + (<a href="https://github.com/derf/db-fakedisplay/blob/master/README.md">installation instructions</a>). + Please use your own installation for automated crawlers that request dozens of stations per minute.</li> + % } + % else { + <li>DBF-Abfahrtstafeln können gerne als iframe eingebunden oder in + fest installierten Vollbild-Browserfenstern verwendet werden. + Für eine kleine Ansicht (z.B. iframe in einer normalen Website) + empfiehlt sich das "App"-Frontend. Für eine große Ansicht + (z.B. als alleinstehender Infoscreen) gibt es den "Infoscreen"-Modus.</li> + <li>Die Abfahrtstafel unterstützt Namen, EVA-IDs, und (im IRIS-Backend) + DS100/Ril100-Codes zur Identifikation von Stationen.</li> + <li>Abfahrten werden mit Echtzeitdaten bzw. Prognosen angegeben und + danach sortiert. Mit dem Parameter + <span style="font-family: monospace;">rt=0</span> wwerden stattdessen + Plandaten angegeben und zur Sortierung genutzt.</li> + <li>Bei HAFAS-Backends können optional Details für spezifische Fahrten im + DD.MM.[YYYY]-Format abgefragt werden, z.B. "ICE 921 (1.1.)" oder + "ICE 921 @ 1.1.". Das Datum bezieht sich auf die geplante + Abfahrtszeit am Startbahnhof der Fahrt.</li> + <li>Viele Seiten sind auch als JSON verfügbar, wahlweise mittels + <span style="font-family: monospace;">Accept: application/json</span> oder + durch <span style="font-family: monospace;">.json</span> in der URL. + HAFAS- und IRIS-Abfahrtstafeln liefern mit dem GET-Parameter <span style="font-family: monospace;">version=3</span> eine stabile JSON-API. + Alle anderen Endpunkte (sowie Abfahrtstafeln mit <span style="font-family: monospace;">version=raw</span>) erlauben direkten Zugriff auf die serialisierten Travel::Status::DE::{EFA,HAFAS,IRIS}-Objekte ohne stabile API.</li> + <li>Bitte maximal 30 Anfragen pro Minute und insbesondere nur eine Anfrage + pro Station und Minute – eine höhere Auflösung haben die Backenddaten + ohnehin nicht.</li> + <li>Mit <span style="font-family: monospace;">limit</span> kann die Anzahl der + angezeigten / im JSON enthaltenen Abfahrten eingeschränkt werden, z.B. + <span style="font-family: monospace;">limit=10</span> für die ersten zehn.</li> + <li>Dieser Dienst ist Open Source-Software und kann leicht auf eigenen Servern + <a href="https://github.com/derf/db-fakedisplay/blob/master/README.md">installiert</a> + werden. Automatisierte Crawler, die mehrere Dutzend Stationen pro Minute + abfragen, bitte nur auf eigenen Instanzen betreiben.</li> + % } </ul> </div> <!-- developers --> </div> <!-- notes --> -<div class="notes"> -<span class="notes">Siehe auch:</span> -<ul> -<li><a href="https://reiseauskunft.bahn.de/bin/bhftafel.exe/dn">DB Abfahrtsmonitor</a> - (<a href="https://mobile.bahn.de/bin/mobil/bhftafel.exe/dox">mobil</a>)</li> -<li>Für Nahverkehr: <a href="https://vrrf.finalrewind.org/">vrr-infoscreen</a></li> -</ul> -</div> <!-- notes --> - </div> <!-- container --> <div class="container"> -<div class="about"> -<a href="_about">db-infoscreen</a> -v<%= stash('version') // '???' %> +<div class="config"> +Farbschema: +<a onClick="javascript:setTheme('light')">hell</a> +· +<a onClick="javascript:setTheme('dark')">dunkel</a> +· +<a onClick="javascript:setTheme('default')">automatisch</a> +<!--Language: <br/> -<a href="_datenschutz" rel="nofollow">Datenschutzerklärung</a> +<a onClick="javascript:setLang('de')">DE</a> +· +<a onClick="javascript:setLang('en')">EN</a> +· +<a onClick="javascript:setLang('default')">system language</a> +--> +</div> <!-- config --> +</div> <!-- container --> +% } +% if (not stash('hide_footer')) { +<div class="container"> +<div class="about"> +<a href="_about">DBF</a> v<%= stash('version') // '???' %> +· +<a href="_datenschutz" rel="nofollow">Datenschutz</a> · -<a href="_impressum" rel="nofollow">Impressum</a><br/> +<a href="_impressum" rel="nofollow">Impressum</a> </div> <!-- about --> </div> <!-- container --> % } diff --git a/templates/layouts/legacy.html.ep b/templates/layouts/legacy.html.ep index 223f07b..e7e59ec 100644 --- a/templates/layouts/legacy.html.ep +++ b/templates/layouts/legacy.html.ep @@ -17,18 +17,21 @@ <meta http-equiv="refresh" content="<%= $self->stash('refresh_interval') %>"/> % } - % my $av = 'v30'; # asset version - %= stylesheet "/static/${av}/css/default.css" + % my $av = 'v110'; # asset version + %= stylesheet "/static/${av}/css/legacy.css" %= stylesheet "/static/${av}/css/material-icons.css" %= stylesheet "/static/${av}/css/jquery-ui.min.css" % my $force_mobile = param('force_mobile') // stash('force_mobile'); % if ($force_mobile) { - %= stylesheet "/static/${av}/css/mobile.css" + %= stylesheet "/static/${av}/css/legacy-mobile.css" % } %if (stash('load_marquee')) { %= javascript '/static/js/jquery-3.4.1.min.js' %= javascript "/static/${av}/js/jquery-ui.min.js" %= javascript "/static/${av}/js/dbf.min.js" + % if (not stash('hide_opts')) { + %= javascript "/dyn/${av}/autocomplete.js", defer => undef + % } %= javascript "/static/${av}/js/marquee.min.js" %= javascript begin $(function () { $('marquee').marquee() }); @@ -38,9 +41,6 @@ %= javascript "/static/${av}/js/jquery-ui.min.js", defer => undef %= javascript "/static/${av}/js/dbf.min.js", defer => undef % } - % if (stash('with_geolocation')) { - %= javascript "/static/${av}/js/geolocation.min.js", defer => undef - % } </head> <body style="<%= (param('dark') ? 'background-color: #000000; color: #ffffff;' : q{}) %>"> @@ -62,178 +62,5 @@ Bitte eine Station aus der Liste auswählen</div> %= content </div> -% if (not stash('hide_opts')) { -<div class="container"> -<div class="input-field"> - - -%= form_for _redirect => begin -<div> - <div class="field"> - <div class="desc">Bahnhof / Haltestelle</div> - <div> -% if (stash('stationlist')) { - %= select_field station => stash('stationlist') -% } -% elsif (stash('station')) { - %= text_field 'station', class => 'station', placeholder => 'Name oder DS100-Kürzel' -% } -% else { - %= text_field 'station', class => 'station', placeholder => 'Name oder DS100-Kürzel', autofocus => 'autofocus' -% } - </div> - </div> - <div class="field"> - %= submit_button 'Abfahrtsmonitor' - </div> - % if (not stash('show_intro')) { - <div class="break"></div> - <div class="field"> - <a class="button" href="<%= url_for('_auto')->to_abs->scheme('https') %>">Bahnhöfe im Umfeld suchen</a> - </div> - % } - <div class="break"></div> - <div class="moresettings-header moresettings-header-collapsed button button-light">Weitere Einstellungen</div> - <div class="moresettings moresettings-collapsed"> - <div class="field"> - <div class="desc"> - Frontend - </div> - <div> - %= select_field mode => [ ['App' => 'app'], ['Infoscreen' => 'infoscreen'], ['Bahnhofstafel' => 'multi'], ['Gleisanzeiger' => 'single'] ] - </div> - </div> - <div class="field"> - <div class="desc"> - Nur Züge über - </div> - <div> - %= text_field 'via', placeholder => 'Bahnhof 1, Bhf2, ... (oder regulärer Ausdruck)', class => 'station' - </div> - </div> - <div class="field"> - <div class="desc"> - Gleise - </div> - <div> - %= text_field 'platforms', placeholder => '1, 2, 5, ...' - </div> - </div> - <div class="field"> - <div class="desc"> - %= check_box 'hidelowdelay' => 1, id => 'id_hidelowdelay' - <label for="id_hidelowdelay"> - Nur Verspätungen >5 Min. anzeigen - </label> - </div> - </div> - <div class="field"> - <div class="desc"> - %= check_box 'dark' => 1, id => 'id_dark' - <label for="id_dark"> - Dunkles Layout (experimentell) - </label> - </div> - </div> - <div class="field"> - <div class="desc"> - %= check_box 'hide_opts' => 1, id => 'id_hide_opts' - <label for="id_hide_opts"> - Formular verstecken (für Infoscreens) - </label> - </div> - </div> - <div class="field"> - <div class="desc"> - Ankunfts- oder Abfahrtszeit anzeigen? - </div> - <div> - %= select_field admode => [['Abfahrt bevorzugen' => 'deparr'], ['Nur Abfahrt' => 'dep'], ['Nur Ankunft' => 'arr']] - </div> - </div> - <div class="field"> - <div class="desc"> - %= check_box 'detailed' => 1, id => 'id_detailed' - <label for="id_detailed"> - Mehr Details (Zugnummern und Ankunftszeiten) anzeigen - </label> - </div> - </div> - <div class="field"> - <div class="desc"> - %= check_box 'show_realtime' => 1, id => 'id_show_realtime' - <label for="id_show_realtime"> - Echtzeitangaben statt Fahrplandaten anzeigen - </label> - </div> - </div> - <div class="field"> - <div class="desc"> - %= check_box 'no_related' => 1, id => 'id_no_related' - <label for="id_no_related"> - Betriebliche Bahnhofstrennungen berücksichtigen (z.B. "Hbf (Fern+Regio)" vs. "Hbf (S)") - </label> - </div> - </div> - <div class="field"> - %= submit_button 'Anzeigen' - </div> - </div> <!-- moresettings --> -</div> -% end - -</div> <!-- input-field --> - -<div class="notes"> - <div class="developers-header developers-header-collapsed button button-light">API- und Entwickler-Hinweise</div> - <div class="developers developers-collapsed"> - <ul> - <li>Diese Seite kann gerne als iframe in eigene Infoscreens o.ä. eingebunden werden. - Für eine kleine Ansicht (z.B. iframe in einer normalen Website) bitte das - "App"-Frontend verwenden. Für eine große Ansicht - (z.B. als alleinstehender Infoscreen) gibt es das "Infoscreen"-Frontend.</li> - <li>Die Parameter <span style="font-family: monospace;">mode=json&version=3</span> - (alternativ auch <span style="font-family: - monospace;">https://dbf.finalrewind.org/Bahnhofsname.json?version=3</span>) - bieten ein JSON-IRIS-Interface. Die route-Elemente können zusätzlich - die Felder "isAdditional" oder "isCancelled" enthalten, der Rest sollte - selbsterklärend sein. Im Fehlerfall fehlt das "departures"-Element, - stattdessen wird ein "error"-Element mit Fehlermeldung zurückgegeben. - Bitte nur eine Anfrage pro Station und Minute - – eine höhere Auflösung haben die Backenddaten ohnehin nicht.</li> - <li>Mit <span style="font-family: monospace;">limit</span> kann die Anzahl der - angezeigten / im JSON enthaltenen Abfahrten eingeschränkt werden, z.B. - <span style="font-family: monospace;">limit=10</span> für die ersten zehn.</li> - <li>Dieser Dienst ist Open Source-Software (Links siehe unten) und kann auch - auf eigenen Servern installiert werden. Automatisierte Crawler, die mehrere - Dutzend Stationen pro Minute abfragen, bitte nur auf eigenen Instanzen - betreiben.</li> - </ul> - </div> <!-- developers --> -</div> <!-- notes --> - -<div class="notes"> -<span class="notes">Siehe auch:</span> -<ul> -<li><a href="https://reiseauskunft.bahn.de/bin/bhftafel.exe/dn">DB Abfahrtsmonitor</a> - (<a href="https://mobile.bahn.de/bin/mobil/bhftafel.exe/dox">mobil</a>)</li> -<li>Für Nahverkehr: <a href="https://vrrf.finalrewind.org/">vrr-infoscreen</a></li> -</ul> -</div> <!-- notes --> - -</div> <!-- container --> - -<div class="container"> -<div class="about"> -<a href="_about">db-infoscreen</a> -v<%= stash('version') // '???' %> -<br/> -<a href="_datenschutz" rel="nofollow">Datenschutzerklärung</a> -· -<a href="_impressum" rel="nofollow">Impressum</a><br/> -</div> <!-- about --> -</div> <!-- container --> -% } - </body> </html> diff --git a/templates/multi.html.ep b/templates/multi.html.ep index 704c589..0095957 100644 --- a/templates/multi.html.ep +++ b/templates/multi.html.ep @@ -48,3 +48,9 @@ </div> <!-- displaymulti --> % } + +<p class="notice"> +<strong>Deprecation Warning.</strong> +Dieses Frontend wird nicht mehr weitergewickelt und möglicherweise in einer +zukünftigen DBF-Version entfernt. +</p> diff --git a/templates/not_found.html.ep b/templates/not_found.html.ep index df583ae..c03d32d 100644 --- a/templates/not_found.html.ep +++ b/templates/not_found.html.ep @@ -1,7 +1,12 @@ <div class="container"> <div class="error"> <strong>404 Page Not Found:</strong> +% if (my $e = stash('message')) { +%= $e +% } +% else { Die aufgerufene URL existiert nicht und ist keine gültige Abbildung auf einen Bahnhofsnamen. +% } </div> </div> diff --git a/templates/route_map.html.ep b/templates/route_map.html.ep index 5bc7fd6..e1c4642 100644 --- a/templates/route_map.html.ep +++ b/templates/route_map.html.ep @@ -1,12 +1,9 @@ % if (stash('origin') and stash('destination')) { %= include '_map_infobox' % } -% elsif (stash('intersection')) { - %= include '_intersection_infobox' -% } <div class="container"> - <div id="map" style="height: 500px;"> + <div id="map" style="height: 70vh;"> </div> </div> @@ -44,7 +41,7 @@ for (var station_id in stations) { opacity: 0.7, fillColor: '#f03', fillOpacity: 0.5, - radius: 250 + radius: <%= stash('station_radius') || 250 %> }).bindPopup(stations[station_id][1].join('<br/>')).addTo(map); } @@ -82,18 +79,20 @@ var marker; </script> <div class="container" style="margin-top: 1ex; margin-bottom: 1ex; color: #555;"> -Die eingezeichnete Route stammt aus dem HAFAS und ist im Detail oft -fehlerbehaftet.<br/> -Die Zugposition auf der Karte ist eine DBF-eigene Schätzung und kann erheblich -von den tatsächlichen Gegebenheiten abweichen. +<p> +Die eingezeichnete Route stammt aus dem angefragten Backend und stimmt nicht +notwendigerweise mit der Realität überein. +Die Fahrzeugposition auf der Karte ist eine DBF-eigene Schätzung und kann +erheblich von den tatsächlichen Gegebenheiten abweichen. % if (stash('intersection')) { <br/>In dieser Ansicht sind Live-Updates der Zug- und Begegnungspositionen noch nicht implementiert. % } +</p> </div> % if (my $op = stash('operator')) { <div class="container" style="margin-top: 1ex; margin-bottom: 1ex; color: #555;"> -Betrieb: <%= $op %> +<p>Betrieb: <%= $op %></p> </div> % } diff --git a/templates/select_backend.html.ep b/templates/select_backend.html.ep new file mode 100644 index 0000000..c6d2a4c --- /dev/null +++ b/templates/select_backend.html.ep @@ -0,0 +1,46 @@ +<div class="container"> + <p> + Das Backend bestimmt die Datenquelle für Stations- und Zuginformationen. + Innerhalb Deutschlands ist <strong>Deutsche Bahn</strong> via IRIS-TTS eine gute Wahl für Schienenverkehr im Bahnnetz. + Die anderen Backends bieten sich für Fahrten im zugehörigen Verkehrsverbund (inklusive Nahverkehr) sowie im Ausland an. + Sofern bekannt sind unterhalb der Backend-Namen Karten verlinkt, die die ungefähre Abdeckung aufzeigen. + Ein Backend, welches Nah- und Fernverkehr in ganz Deutschland abdeckt, ist aktuell leider nicht verfügbar. + </p> + <p> + % my $prev_type = 'IRIS-TTS'; + % for my $backend (@{$backends}) { + <p> + % if ($backend->{type} ne $prev_type) { + % $prev_type = $backend->{type}; + <%= $prev_type %>:<br/> + % } + % my $class = 'button'; + % if (param('efa')) { + % if ($backend->{efa} and $backend->{shortname} eq param('efa')) { + % $class .= ' button-active'; + % } + % } + % elsif (param('hafas')) { + % if ($backend->{hafas} and $backend->{shortname} eq param('hafas')) { + % $class .= ' button-active'; + % } + % } + % else { + % if (not ($backend->{efa} or $backend->{hafas})) { + % $class .= ' button-active'; + % } + % } + <a class="<%= $class %>" href="<%= url_for(q{/})->query({ efa => $backend->{efa} ? $backend->{shortname} : q{}, hafas => $backend->{hafas} ? $backend->{shortname} : q{} }) %>"><%= $backend->{shortname} // 'IRIS-TTS' %> – <%= $backend->{name} %></a> + % if ($backend->{has_area}) { + <a href="/coverage/<%= $backend->{type} %>/<%= $backend->{shortname} %>"><%= join(q{, }, @{$backend->{regions}}) || '[Karte]' %></a> + % } + % else { + %= join(q{, }, @{$backend->{regions} // []}) + % } + % if ($backend->{homepage}) { + (<a href="<%= $backend->{homepage} %>"><%= $backend->{homepage} =~ s{ ^ http s? :// (?: www[.] )? (.*?) (?: / )? $ }{$1}xr %></a>) + % } + </p> + % } + </p> +</div> diff --git a/templates/single.html.ep b/templates/single.html.ep index 681dfee..0156bf4 100644 --- a/templates/single.html.ep +++ b/templates/single.html.ep @@ -1,3 +1,9 @@ +<p class="notice"> +<strong>Deprecation Warning.</strong> +Dieses Frontend wird nicht mehr weitergewickelt und möglicherweise in einer +zukünftigen DBF-Version abgeschaltet. +</p> + % if (@{$departures}) { <div class="displaysingle"> diff --git a/templates/train_details.html.ep b/templates/train_details.html.ep new file mode 100644 index 0000000..7d5ea90 --- /dev/null +++ b/templates/train_details.html.ep @@ -0,0 +1,5 @@ +<div class="app" data-station="<%= stash('station_name') // q{} %>"> +<div class="moreinfo" data-static="1"> + %= include '_train_details' +</div> +</div> diff --git a/templates/trainsearch.html.ep b/templates/trainsearch.html.ep deleted file mode 100644 index 5d6d3f9..0000000 --- a/templates/trainsearch.html.ep +++ /dev/null @@ -1,29 +0,0 @@ -<div class="container"> - <div class="input-field"> - %= form_for _trainsearch => begin - <div> - <div class="field"> - <div class="desc">Zug</div> - <div> - %= text_field 'train1', placeholder => 'RE 1234', id => 'train1_input', autofocus => 'autofocus' - </div> - </div> - <div class="field"> - %= submit_button 'Strecke zeigen' - </div> - <div class="break"></div> - <div class="field"> - <div class="desc"> - Zweiter Zug (optional) - </div> - <div> - %= text_field 'train2', placeholder => 'S 5678', id => 'train2_input' - </div> - </div> - <div class="field"> - %= submit_button 'Begegnungen suchen (beta)' - </div> - </div> - % end - </div> -</div> diff --git a/templates/wagen.html.ep b/templates/wagen.html.ep new file mode 100644 index 0000000..efc2e32 --- /dev/null +++ b/templates/wagen.html.ep @@ -0,0 +1,75 @@ +<div class="container singlewagon"> + % if (not $wref->{e} and $wref->{s} and $wref->{p} and $wref->{ws}) { + <p> + <%= $wref->{s} %> Gleis <%= $wref->{p} %> <%= $wref->{ws} %> + </p> + % } + % if ($wref->{e} eq 'u') { + % if ($wref->{s} and $wref->{p} and $wref->{ws}) { + <div class="platform"> + <%= $wref->{s} %><br/>Gleis <%= $wref->{p} %> <%= $wref->{ws} %> + <div class="sign-left"><i class="material-icons">arrow_upward</i></div> + <div class="sign-right"><i class="material-icons">arrow_upward</i></div> + </div> + % } + % } + % elsif (defined $wref->{d} and $wref->{e} ne 'u') { + % if ($wref->{d} == 0) { + <div class="sign-left"><i class="material-icons">arrow_back</i></div> + <div class="sign-right"><i class="material-icons">arrow_back</i></div> + <div class="sign-center"><i class="material-icons">arrow_back</i></div> + % } + % else { + <div class="sign-left"><i class="material-icons">arrow_forward</i></div> + <div class="sign-right"><i class="material-icons">arrow_forward</i></div> + <div class="sign-center"><i class="material-icons">arrow_forward</i></div> + % } + % } + % for my $wagon_file (@{$wagon_files // [] }) { + % if ($wagon_file ne $wagon_files->[0] and defined $wref->{d}) { + % if ($wref->{d} == 0) { + <div class="sign-left"><i class="material-icons">arrow_back</i></div> + <div class="sign-right"><i class="material-icons">arrow_back</i></div> + <div class="sign-center"><i class="material-icons">arrow_back</i></div> + % } + % else { + <div class="sign-left"><i class="material-icons">arrow_forward</i></div> + <div class="sign-right"><i class="material-icons">arrow_forward</i></div> + <div class="sign-center"><i class="material-icons">arrow_forward</i></div> + % } + % } + <div style="clear: both;"> + <a href="<%= $wagon_file %>"><img class="wagonfile" src="<%= $wagon_file %>"></a> + </div> + % } + % if ($wref->{e} eq 'd') { + <div class="sign-left"><i class="material-icons">arrow_downward</i></div> + <div class="sign-right"><i class="material-icons">arrow_downward</i></div> + % if ($wref->{s} and $wref->{p} and $wref->{ws}) { + <div class="platform"> + <%= $wref->{s} %><br/>Gleis <%= $wref->{p} %> <%= $wref->{ws} %> + </div> + % } + % } + % elsif (defined $wref->{d} and $wref->{e} ne 'd') { + % if ($wref->{d} == 0) { + <div class="sign-left"><i class="material-icons">arrow_back</i></div> + <div class="sign-right"><i class="material-icons">arrow_back</i></div> + <div class="sign-center"><i class="material-icons">arrow_back</i></div> + % } + % else { + <div class="sign-left"><i class="material-icons">arrow_forward</i></div> + <div class="sign-right"><i class="material-icons">arrow_forward</i></div> + <div class="sign-center"><i class="material-icons">arrow_forward</i></div> + % } + % } + % if ($wagon_data->{name}) { + <p> + <%= $wagon_data->{name} %> + </p> + % } + <p class="copyright"> + Abbildung © Seemanngrafik d.i.p. im Auftrag der Deutschen Bahn AG, + lizensiert unter CC-BY-4.0 + </p> +</div> diff --git a/templates/wagenreihung.html.ep b/templates/wagenreihung.html.ep index 1ef0370..19c49ab 100644 --- a/templates/wagenreihung.html.ep +++ b/templates/wagenreihung.html.ep @@ -1,141 +1,57 @@ -% if (not $wr or $wr->errstr) { +% if (not $wr or $wr_error) { <div class="container"> <div class="error"> <strong>Fehler bei der Abfrage der Wagenreihung:</strong> - <%= $wr ? $wr->errstr : $wr_error %> + <%= $wr_error // 'Unbekannter Fehler' %> </div> </div> % } % else { - % my $has_multi_dest = 0; - % if (scalar $wr->destinations > 1) { - % $has_multi_dest = 1; - % } <div class="container"> <div style="text-align: center;"> -%= join( ' / ', $wr->origins ) - → -%= join( ' / ', map { $_->{name} } $wr->destinations ) + Gleis <%= $wr->platform %><br/> </div> - % if ($has_multi_dest) { - <div style="text-align: center;"> - % for my $destination ($wr->destinations) { - Nach <%= $destination->{name} %> in Abschnitt <%= join(q{}, sort @{$destination->{sections} // []}) %><br/> - % } - </div> - % } - <%= $wr->station_name %> Gleis <%= $wr->platform %><br/> - % if ($wr->train_type =~ m{^IC|EC}) { - Zugtyp: <%= $wr->train_subtype // 'IC?' %> - % } - % elsif ($wr->train_powertype) { - %= $wr->train_type - % } - % my %translation = ( - % 90 => 'mit sonstigem Antrieb', - % 91 => 'mit elektrischer Lokomotive', - % 92 => 'mit Diesellokomotive', - % 93 => 'Hochgeschwindigkeitszug', - % 94 => 'Elektrischer Triebzug', - % 95 => 'Diesel-Triebzug', - % 96 => 'mit speziellen Beiwagen', - % 97 => 'mit elektrischer Rangierlok', - % 98 => 'mit Diesel-Rangierlok', - % 99 => 'Sonderfahrzeug', - % ); - % if (not $wr->train_powertype) { - % } - % else { - %= $translation{$wr->train_powertype}; - % } - </div> </div> <div class="container"> - <div class="wagonorder"> -% if (not $wr->has_bad_wagons) { -% for my $section ($wr->sections) { - <div class="section" style=" - top: <%= $section->{start_percent} %>%; bottom: <%= 100 - $section->{end_percent} %>%;"> -%= $section->{name} - </div> -% } + <div class="wagonorder exit-<%= stash('exit_dir') // 'unknown'%>"> +% for my $sector ($wr->sectors) { + <div class="section" style=" + top: <%= $sector->start_percent %>%; bottom: <%= 100 - $sector->end_percent %>%;"> +%= $sector->name + </div> % } -% for my $wagon ($wr->wagons) { -% my $bg = ''; -% my $extra_class = ''; -% if ($wagon->is_first_class) { -% $extra_class .= ' firstclass'; -% } -% if ($wagon->is_locomotive or $wagon->is_powercar) { -% $extra_class .= ' powercar'; -% } -% if ($wagon->train_no ne $train_no) { -% $extra_class .= ' nondestwagon'; +% for my $group ($wr->groups) { +% my $first = 1; +% for my $wagon ($group->carriages) { +%= include '_wagon', wr => $wr, group => $group, wagon => $wagon, first => $first, multi => (scalar $wr->destinations) - 1 + (scalar $wr->train_numbers) - 1, wref => $wref, exit_dir => stash('exit_dir'), train_no => param('number'); +% $first = 0; % } - <div class="wagon <%= $extra_class %>" style=" - top: <%= $wagon->{position}{start_percent} %>%; bottom: <%= 100 - $wagon->{position}{end_percent} %>%; <%= $bg %>"> -% if ($wagon->is_locomotive or $wagon->is_powercar) { -% } -% else { -%= $wagon->number // '?' -% if ($wagon->has_accessibility) { - <i class="material-icons" style="font-size: 20px;">accessible</i> -% } -% if ($wagon->has_bistro) { - <i class="material-icons">restaurant</i> -% } -% if ($wagon->has_compartments) { - <!--<i class="material-icons">folder</i>--> -% } -% if ($wagon->has_quiet_area) { - <i class="tiny material-icons">volume_off</i> -% } -% if ($wagon->has_phone_area) { - <i class="material-icons">smartphone</i> -% } -% if ($wagon->has_family_area) { - <i class="material-icons">people</i> -% } -% if ($wagon->has_bahn_comfort) { - <i class="material-icons">star</i> -% } -% } - <div class="direction"> -% if ($wr->has_bad_wagons or not defined $wr->direction) { -% } -% elsif ($wr->direction == 100) { - <i class="material-icons">arrow_downward</i> -% } -% else { - <i class="material-icons">arrow_upward</i> -% } - </div> - </div> - <div class="details" style=" - top: <%= $wagon->{position}{start_percent} %>%; bottom: <%= 100 - $wagon->{position}{end_percent} %>%;"> - <span class="type"> -%= $wagon->type - </span> -% my $uic_id = $wagon->uic_id; -% if (length($uic_id) != 12) { - <span class="uicunknown"><%= $uic_id %></span> -% } -% elsif (substr($uic_id, 0, 2) >= 90) { - <span class="uicexchange"><%= substr($uic_id, 0, 2) %></span><span class="uiccountry"><%= substr($uic_id, 2, 2) %></span><span class="uic5"><%= substr($uic_id, 4, 1) %></span><span class="uictype"><%= substr($uic_id, 5, 3) %></span><span class="uicno"><%= substr($uic_id, 8, 3) %></span><span class="uiccheck"><%= substr($uic_id, 11) %></span> -% } -% else { - <span class="uicexchange"><%= substr($uic_id, 0, 2) %></span><span class="uiccountry"><%= substr($uic_id, 2, 2) %></span><span class="uic56"><%= substr($uic_id, 4, 2) %></span><span class="uic78"><%= substr($uic_id, 6, 2) %></span><span class="uicno"><%= substr($uic_id, 8, 3) %></span><span class="uiccheck"><%= substr($uic_id, 11) %></span> -% } - </div> % } </div> + % for my $group ($wr->groups) { + % if ($group->description) { + <div style="text-align: center;"> + %= $group->description + % if ($group->designation) { + „<%= $group->designation %>“ + % } + % if (scalar $wr->groups > 1 and $group->has_sectors) { + in Abschnitt <%= join(q{}, sort $group->sectors) %> + % } + </div> + % } + % } + <div style="text-align: center;"> + nach +%= join( ' / ', map { $_->{name} } $wr->destinations ) + </div> <!-- <div> Legende: ♿ Behindertengerechte Ausstattung / 🍴 Bistro/Restaurant / 🚪 Abteile vorhanden </div> --> - <div> - Angaben ohne Gewähr – Echtzeitdaten sind möglicherweise nicht berücksichtigt. - </div> + <p class="copyright"> + Quelle: DB Wagenreihungs-API (<%= stash('ts') // q{} %>). Angaben ohne Gewähr. + </p> </div> % } diff --git a/templates/zugbildung_db.html.ep b/templates/zugbildung_db.html.ep new file mode 100644 index 0000000..45e52aa --- /dev/null +++ b/templates/zugbildung_db.html.ep @@ -0,0 +1,26 @@ +% if ($wr_error) { + <div class="container"> + <div class="error"> + <strong>Fehler bei der Abfrage der Wagenreihung:</strong> + <%= $wr_error %> + </div> + </div> +% } +<div class="container"> + <div style="text-align: center;"><%= $route %></div> + Vorgesehener Zugtyp: <%= $zb->{type} %> +</div> +<div class="container"> + <div class="wagonorder exit-unknown"> +% for my $wagon (@{$wagons // []}) { +%= include '_wagon', direction => undef, wagon => $wagon, type => $zb->{type}, wref => '', exit_dir => 'unknown'; +% } + </div> + <p class="copyright"> + Quelle: <a href="https://data.deutschebahn.com/dataset/zugbildungsplanzugbildungsplan-zpar">DB Zugbildungsplan</a> + mit <a href="https://github.com/derf/db-zugbildung-to-json">automatisierter Nachbearbeitung</a>.<br/> + Nachbearbeitungsbedingte Fehler sind wahrscheinlich.<br/> + Daten © 2020 DB Fernverkehr AG, lizensiert unter CC-BY 4.0. + </p> + + </div> |