summaryrefslogtreecommitdiff
path: root/templates
diff options
context:
space:
mode:
Diffstat (limited to 'templates')
-rw-r--r--templates/_backend_line.html.ep25
-rw-r--r--templates/_checked_in.html.ep205
-rw-r--r--templates/_checked_out.html.ep2
-rw-r--r--templates/_connections_hafas.html.ep13
-rw-r--r--templates/_departures_dbris.html.ep55
-rw-r--r--templates/_departures_efa.html.ep57
-rw-r--r--templates/_departures_hafas.html.ep8
-rw-r--r--templates/_departures_motis.html.ep54
-rw-r--r--templates/_format_train.html.ep6
-rw-r--r--templates/_history_trains.html.ep15
-rw-r--r--templates/_map.html.ep20
-rw-r--r--templates/_public_status_card.html.ep164
-rw-r--r--templates/_show_load_icons.html.ep11
-rw-r--r--templates/_timeline_link.html.ep2
-rw-r--r--templates/_wagons.html.ep19
-rw-r--r--templates/about.html.ep30
-rw-r--r--templates/account.html.ep18
-rw-r--r--templates/add_intransit.html.ep93
-rw-r--r--templates/add_journey.html.ep20
-rw-r--r--templates/api_documentation.html.ep15
-rw-r--r--templates/bad_gateway.html.ep27
-rw-r--r--templates/changelog.html.ep253
-rw-r--r--templates/departures.html.ep105
-rw-r--r--templates/disambiguation.html.ep2
-rw-r--r--templates/exception.html.ep11
-rw-r--r--templates/gateway_timeout.html.ep27
-rw-r--r--templates/history_by_month.html.ep6
-rw-r--r--templates/history_map.html.ep4
-rw-r--r--templates/journey.html.ep115
-rw-r--r--templates/landingpage.html.ep66
-rw-r--r--templates/layouts/default.html.ep4
-rw-r--r--templates/legend.html.ep4
-rw-r--r--templates/login.html.ep5
-rw-r--r--templates/passengerrights.html.ep69
-rw-r--r--templates/profile.html.ep2
-rw-r--r--templates/register.html.ep5
-rw-r--r--templates/select_backend.html.ep85
-rw-r--r--templates/traewelling.html.ep51
-rw-r--r--templates/use_external_links.html.ep82
-rw-r--r--templates/use_history.html.ep6
-rw-r--r--templates/user_status.html.ep2
41 files changed, 1363 insertions, 400 deletions
diff --git a/templates/_backend_line.html.ep b/templates/_backend_line.html.ep
new file mode 100644
index 0000000..00496d3
--- /dev/null
+++ b/templates/_backend_line.html.ep
@@ -0,0 +1,25 @@
+<div class="row">
+ <div class="col s8 m6 l6 right-align">
+ %= $backend->{longname}
+ % if ($backend->{id} == $user->{backend_id}) {
+ (aktuell ausgewählt)
+ % }
+ % if ($backend->{has_area}) {
+ <br/>
+ <a href="https://dbf.finalrewind.org/coverage/<%= $backend->{type} %>/<%= $backend->{name} %>"><%= join(q{, }, @{$backend->{regions} // []}) || '[Karte]' %></a>
+ % }
+ % elsif ($backend->{regions}) {
+ <br/>
+ %= join(q{, }, @{$backend->{regions} // []})
+ % }
+ % if ($backend->{homepage}) {
+ <br/>
+ <a href="<%= $backend->{homepage} %>"><%= $backend->{homepage} =~ s{ ^ http s? :// (?: www[.] )? (.*?) (?: / )? $ }{$1}xr %></a>
+ % }
+ </div>
+ <div class="col s4 m6 l6 left-align">
+ <button class="btn waves-effect waves-light <%= $backend->{id} == $user->{backend_id} ? 'disabled' : q{} %>" style="min-width: 6em;" type="submit" name="backend" value="<%= $backend->{id} %>">
+ <%= $backend->{name} %>
+ </button>
+ </div>
+</div>
diff --git a/templates/_checked_in.html.ep b/templates/_checked_in.html.ep
index 7155208..91f1ce7 100644
--- a/templates/_checked_in.html.ep
+++ b/templates/_checked_in.html.ep
@@ -42,13 +42,13 @@
% }
% if ($journey->{arrival_countdown} < (60 * 15) and $journey->{arr_platform}) {
% if ($journey->{arr_direction} and $journey->{arr_direction} eq 'r') {
- <br/>Gleis <%= $journey->{arr_platform} %> ▶
+ <br/><%= $journey->{platform_type} %> <%= $journey->{arr_platform} %> ▶
% }
% elsif ($journey->{arr_direction} and $journey->{arr_direction} eq 'l') {
- <br/>◀ Gleis <%= $journey->{arr_platform} %>
+ <br/>◀ <%= $journey->{platform_type} %> <%= $journey->{arr_platform} %>
% }
% else {
- <br/>auf Gleis <%= $journey->{arr_platform} %>
+ <br/>auf <%= $journey->{platform_type} %> <%= $journey->{arr_platform} %>
% }
% }
% }
@@ -57,43 +57,60 @@
% }
% if ($journey->{departure_countdown} > 0 and $journey->{dep_platform}) {
% if ($journey->{dep_direction} and $journey->{dep_direction} eq 'r') {
- <br/>Gleis <%= $journey->{dep_platform} %> ▶
+ <br/><%= $journey->{platform_type} %> <%= $journey->{dep_platform} %> ▶
% }
% elsif ($journey->{dep_direction} and $journey->{dep_direction} eq 'l') {
- <br/>◀ Gleis <%= $journey->{dep_platform} %>
+ <br/>◀ <%= $journey->{platform_type} %> <%= $journey->{dep_platform} %>
% }
% else {
- <br/>von Gleis <%= $journey->{dep_platform} %>
+ <br/>von <%= $journey->{platform_type} %> <%= $journey->{dep_platform} %>
% }
% }
% if (my $wr = $journey->{wagonorder}) {
<br/>
- % my @wagons = $wr->wagons;
- % my $direction = $wr->direction == 100 ? '→' : '←';
- % if ($journey->{dep_direction}) {
- % $direction = $journey->{dep_direction} eq 'l' ? '◀' : '▶';
- % if (($journey->{dep_direction} eq 'l' ? 0 : 100) != $wr->direction) {
- % @wagons = reverse @wagons;
+ <a href="https://dbf.finalrewind.org/carriage-formation?<%= join('&', map { $_ . '=' . $journey->{extra_data}{wagonorder_param}{$_} } sort keys %{$journey->{extra_data}{wagonorder_param}}) %>&amp;e=<%= $journey->{dep_direction} // q{} %>">
+ % my $direction = $wr->direction == 100 ? '→' : '←';
+ % my $rev = 0;
+ % if ($journey->{dep_direction}) {
+ % $direction = $journey->{dep_direction} eq 'l' ? '◀' : '▶';
+ % $rev = (($journey->{dep_direction} eq 'l' ? 0 : 100) == $wr->direction) ? 0 : 1;
% }
- % }
- <a href="https://dbf.finalrewind.org/_wr/<%= $journey->{train_no} %>/<%= $journey->{sched_departure}->strftime('%Y%m%d%H%M') %>?e=<%= $journey->{dep_direction} // q{} %>">
- %= $direction
- % my $gi;
- % for my $wagon (@wagons) {
- % if (not ($wagon->is_locomotive or $wagon->is_powercar)) {
- % if (defined $gi and $gi != $wagon->group_index) {
+ %= $direction
+ % my $had_entry = 0;
+ % for my $group ($rev ? reverse $wr->groups : $wr->groups) {
+ % if ($had_entry) {
+ % $had_entry = 0;
% }
- % if ($wagon->is_closed) {
- X
- % }
- % else {
- %= $wagon->number || ($wagon->type =~ m{AB} ? '½' : $wagon->type =~ m{A} ? '1.' : $wagon->type =~ m{B} ? '2.' : $wagon->type )
+ % for my $wagon ($rev ? reverse $group->carriages : $group->carriages) {
+ % if (not ($wagon->is_locomotive or $wagon->is_powercar)) {
+ % $had_entry = 1;
+ % if ($wagon->is_closed) {
+ X
+ % }
+ % elsif ( $wagon->number) {
+ %= $wagon->number
+ % }
+ % else {
+ % if ( $wagon->has_first_class ) {
+ % if ( $wagon->has_second_class ) {
+ ½
+ % }
+ % else {
+ 1.
+ % }
+ % }
+ % elsif ( $wagon->has_second_class ) {
+ 2.
+ % }
+ % else {
+ %= $wagon->type;
+ % }
+ % }
+ % }
% }
% }
- % $gi = $wagon->group_index;
- % }
- %= $direction
+ %= $direction
</a>
% }
</div>
@@ -111,12 +128,7 @@
% }
</div>
<div style="float: right; text-align: right;">
- % if ($user->{sb_template}) {
- <b><a href="<%= resolve_sb_template($user->{sb_template}, name => $journey->{arr_name}, eva => $journey->{arr_eva}, tt => $journey->{train_type} // q{x}, tn => $journey->{train_no}, id => $journey->{train_id}) %>" class="unmarked"><%= $journey->{arr_name} %></a></b><br/>
- % }
- % else {
- <b><%= $journey->{arr_name} %></b><br/>
- % }
+ <b><a href="<%= resolve_sb_template($user->{sb_template}, name => $journey->{arr_name}, eva => $journey->{arr_eva}, tt => $journey->{train_type} // q{x}, tn => $journey->{train_no}, id => $journey->{train_id} =~ s{[ #|]}{x}gr, dbris => $journey->{is_dbris} ? $journey->{backend_name} : q{}, efa => $journey->{is_efa} ? $journey->{backend_name} : q{}, hafas => $journey->{is_hafas} ? $journey->{backend_name} : q{}, is_iris => $journey->{is_iris}, motis => $journey->{is_motis} ? $journey->{backend_name} : q{}) %>" class="unmarked"><%= $journey->{arr_name} %></a></b><br/>
% if ($journey->{real_arrival}->epoch) {
<b><%= $journey->{real_arrival}->strftime('%H:%M') %></b>
% if ($journey->{real_arrival}->epoch != $journey->{sched_arrival}->epoch) {
@@ -190,7 +202,10 @@
% if (@{$journey->{messages} // []} or @{$journey->{extra_data}{qos_msg} // []} or not $journey->{extra_data}{rt}) {
<p style="margin-bottom: 2ex;">
<ul>
- % if (not $journey->{extra_data}{rt}) {
+ % if ($journey->{extra_data}{manual}) {
+ <li><i class="material-icons tiny">gps_off</i> Manueller Checkin ohne Echtzeitdaten
+ % }
+ % elsif (not $journey->{extra_data}{rt}) {
<li><i class="material-icons tiny">gps_off</i> Keine Echtzeitdaten vorhanden
% }
% for my $message (reverse @{$journey->{messages} // []}) {
@@ -230,10 +245,7 @@
<a class="tablerow action-checkout" data-station="<%= $station->[1] // $station->[0] %>">
<span><%= $station->[0] %></span>
<span>
- % if ($station->[2]{load}{SECOND}) {
- % my ($first, $second) = load_icon($station->[2]{load});
- <i class="material-icons tiny" aria-hidden="true"><%= $first %></i> <i class="material-icons tiny" aria-hidden="true"><%= $second %></i>
- % }
+ %= include '_show_load_icons', station => $station
% if ($station->[2]{isCancelled}) {
entfällt
% }
@@ -312,15 +324,16 @@
% if (@{stash('timeline') // []}) {
%= include '_timeline_link', timeline => stash('timeline'), from_checkin => 1
% }
- % if ($journey->{arr_name}) {
+ % if ($journey->{arr_name} and @{$journey->{extra_data}{him_msg} // []}) {
<div class="card" style="margin-top: <%= scalar @{stash('timeline') // []} ? '1.5rem' : '3em' %>;">
<div class="card-content">
- <span class="card-title">Details</span>
+ <i class="material-icons small right sync-failed-marker grey-text" style="display: none;">sync_problem</i>
+ <span class="card-title">Meldungen</span>
% if (@{$journey->{extra_data}{him_msg} // []}) {
<p style="margin-bottom: 2ex;">
<ul>
% for my $message (@{$journey->{extra_data}{him_msg} // []}) {
- <li> <i class="material-icons tiny">info</i> <%= $message->{header} %> <%= $message->{lead} %></li>
+ <li> <i class="material-icons tiny"><%= ($message->{prio} and $message->{prio} eq 'HOCH') ? 'warning' : 'info' %></i> <%= $message->{header} %> <%= $message->{lead} %></li>
% }
</ul>
</p>
@@ -340,70 +353,68 @@
</p>
% }
</div>
- <div class="card-action">
- % my $url = 'https://bahn.expert/details/';
- % if ($journey->{train_id} =~ m{[|]}) {
- % $url = $url . '/' . $journey->{sched_departure}->epoch . '000?jid=' . $journey->{train_id};
- % }
- % else {
- % $url = $url . $journey->{train_type} . ' ' . $journey->{train_no} . '/' . $journey->{sched_departure}->epoch . '000?station=' . $journey->{dep_eva};
- % }
- <a style="margin-right: 0;" href="<%= $url %>"><i class="material-icons left" aria-hidden="true">timeline</i> Zuglauf</a>
- % if ($journey->{extra_data}{trip_id}) {
- <a class="right" style="margin-right: 0;" href="https://dbf.finalrewind.org/map/<%= $journey->{extra_data}{trip_id} %>/<%= $journey->{train_line} || 0 %>?from=<%= $journey->{dep_name} %>&amp;to=<%= $journey->{arr_name} %>&amp;dark=<%= (session('theme') and session('theme') eq 'dark') ? 1 : 0 %>"><i class="material-icons left" aria-hidden="true">map</i> Karte</a>
- % }
- </div>
</div>
+ % }
+ % if ($journey->{arr_name}) {
<div class="card" style="margin-top: 3em;">
<div class="card-content">
<i class="material-icons small right sync-failed-marker grey-text" style="display: none;">sync_problem</i>
- <span class="card-title">Ziel ändern?</span>
- % if ($user->{sb_template}) {
- <div class="targetlist">
- % }
- % else {
- <p>
- % }
- % for my $station (@{$journey->{route_after}}) {
- % my $is_dest = ($journey->{arr_name} and $station->[0] eq $journey->{arr_name});
- <a class="action-checkout tablerow" style="<%= $is_dest? 'font-weight: bold;' : '' %>" data-station="<%= $station->[1] // $station->[0] %>">
- <span><%= $station->[0] %></span>
- <span>
- % if ($station->[2]{load}{SECOND}) {
- % my ($first, $second) = load_icon($station->[2]{load});
- <i class="material-icons tiny" aria-hidden="true"><%= $first %></i> <i class="material-icons tiny" aria-hidden="true"><%= $second %></i>
- % }
- % if ($station->[2]{isCancelled}) {
- entfällt
- % }
- % elsif ($station->[2]{rt_arr} or $station->[2]{sched_arr}) {
- %= ($station->[2]{rt_arr} || $station->[2]{sched_arr})->strftime('%H:%M')
- % }
- % elsif ($station->[2]{rt_dep} or $station->[2]{sched_dep}) {
- (<%= ($station->[2]{rt_dep} || $station->[2]{sched_dep})->strftime('%H:%M') %>)
- % }
- % elsif ($station->[2]{isAdditional}) {
- Zusatzhalt
- % }
- </span>
+ <span class="card-title">Karte</span>
+ <div id="map" style="height: 70vh;">
+ </div>
+ %= include '_map', with_map_header => 0, station_coordinates => stash('station_coordinates'), polyline_groups => stash('polyline_groups')
+ </div>
+ </div>
+ % if ($journey->{extra_data}{manual}) {
+ <div class="card" style="margin-top: 3em;">
+ <div class="card-content">
+ <i class="material-icons small right sync-failed-marker grey-text" style="display: none;">sync_problem</i>
+ <span class="card-title">Manueller Checkin</span>
+ </div>
+ <div class="card-action">
+ <a class="action-undo blue-text" data-id="in_transit" data-checkints="<%= $journey->{timestamp}->epoch %>" style="margin-right: 0;">
+ <i class="material-icons left" aria-hidden="true">undo</i> Checkin Rückgängig
</a>
- % if ($user->{sb_template}) {
- <a class="nonflex" href="<%= resolve_sb_template($user->{sb_template}, name => $station->[0], eva => $station->[1], tt => $journey->{train_type} // q{x}, tn => $journey->{train_no}, id => $journey->{train_id}) %>"><i class="material-icons tiny">train</i></a>
+ </div>
+ </div>
+ % }
+ % else {
+ <div class="card" style="margin-top: 3em;">
+ <div class="card-content">
+ <i class="material-icons small right sync-failed-marker grey-text" style="display: none;">sync_problem</i>
+ <span class="card-title">Ziel ändern?</span>
+ <div class="targetlist">
+ % for my $station (@{$journey->{route_after}}) {
+ % my $is_dest = ($journey->{arr_name} and $station->[0] eq $journey->{arr_name});
+ <a class="action-checkout tablerow" style="<%= $is_dest? 'font-weight: bold;' : '' %>" data-station="<%= $station->[1] // $station->[0] %>">
+ <span><%= $station->[0] %></span>
+ <span>
+ %= include '_show_load_icons', station => $station
+ % if ($station->[2]{isCancelled}) {
+ entfällt
+ % }
+ % elsif ($station->[2]{rt_arr} or $station->[2]{sched_arr}) {
+ %= ($station->[2]{rt_arr} || $station->[2]{sched_arr})->strftime('%H:%M')
+ % }
+ % elsif ($station->[2]{rt_dep} or $station->[2]{sched_dep}) {
+ (<%= ($station->[2]{rt_dep} || $station->[2]{sched_dep})->strftime('%H:%M') %>)
+ % }
+ % elsif ($station->[2]{isAdditional}) {
+ Zusatzhalt
+ % }
+ </span>
+ </a>
+ <a class="nonflex" href="<%= resolve_sb_template($user->{sb_template}, name => $station->[0], eva => $station->[1], tt => $journey->{train_type} // q{x}, tn => $journey->{train_no}, id => $journey->{train_id} =~ s{[ #|]}{x}gr, dbris => $journey->{is_dbris} ? $journey->{backend_name} : q{}, efa => $journey->{is_efa} ? $journey->{backend_name} : q{}, hafas => $journey->{is_hafas} ? $journey->{backend_name} : q{}, is_iris => $journey->{is_iris}, motis => $journey->{is_motis} ? $journey->{backend_name} : q{}) %>"><i class="material-icons tiny"><%= $journey->{is_hafas} ? 'directions' : 'train' %></i></a>
% }
- % }
- % if ($user->{sb_template}) {
</div>
- % }
- % else {
- </p>
- % }
- </div>
- <div class="card-action">
- <a class="action-undo blue-text" data-id="in_transit" data-checkints="<%= $journey->{timestamp}->epoch %>" style="margin-right: 0;">
- <i class="material-icons left" aria-hidden="true">undo</i> Checkin Rückgängig
- </a>
+ </div>
+ <div class="card-action">
+ <a class="action-undo blue-text" data-id="in_transit" data-checkints="<%= $journey->{timestamp}->epoch %>" style="margin-right: 0;">
+ <i class="material-icons left" aria-hidden="true">undo</i> Checkin Rückgängig
+ </a>
+ </div>
</div>
- </div>
+ % }
<p>
Falls das Backend ausgefallen ist oder die Fahrt aus anderen
Gründen verloren ging:
diff --git a/templates/_checked_out.html.ep b/templates/_checked_out.html.ep
index 5a944dc..21db335 100644
--- a/templates/_checked_out.html.ep
+++ b/templates/_checked_out.html.ep
@@ -3,7 +3,7 @@
<span class="card-title">Ausgecheckt</span>
<p>Aus
%= include '_format_train', journey => $journey
- bis <a href="/s/<%= $journey->{arr_eva} %>?hafas=<%= $journey->{train_id} =~ m{[|]} ? 1 : 0 %>"><%= $journey->{arr_name} %></a></p>
+ bis <a href="/s/<%= $journey->{arr_eva} %>?hafas=<%= $journey->{is_hafas} ? $journey->{backend_name} : q{} %>"><%= $journey->{arr_name} %></a></p>
% if (@{stash('connections_iris') // [] } or @{stash('connections_hafas') // []}) {
<span class="card-title" style="margin-top: 2ex;">Verbindungen</span>
<p>Fahrt auswählen zum Einchecken mit Zielwahl.</p>
diff --git a/templates/_connections_hafas.html.ep b/templates/_connections_hafas.html.ep
index dcf7ec9..3b995b5 100644
--- a/templates/_connections_hafas.html.ep
+++ b/templates/_connections_hafas.html.ep
@@ -1,6 +1,6 @@
<ul class="collection departures connections">
% for my $res (@{$connections}) {
- % my ($train, $via, $via_arr) = @{$res};
+ % my ($train, $via, $via_arr, $hafas_service) = @{$res};
% $via_arr = $via_arr ? $via_arr->strftime('%H:%M') : q{};
% my $row_class = '';
% my $link_class = 'action-checkin';
@@ -10,6 +10,7 @@
% }
% if ($checkin_from) {
<li class="collection-item <%= $row_class %> <%= $link_class %>"
+ data-hafas="<%= $hafas_service %>"
data-station="<%= $train->station_eva %>"
data-train="<%= $train->id %>"
data-ts="<%= ($train->sched_datetime // $train->datetime)->epoch %>"
@@ -34,7 +35,15 @@
</a>
<span class="connect-platform-wrapper">
% if ($train->platform) {
- <span>Gleis <%= $train->platform %></span>
+ <span>
+ % if (($train->type // q{}) =~ m{ ast | bus | ruf }ix) {
+ Steig
+ % }
+ % else {
+ Gleis
+ % }
+ %= $train->platform
+ </span>
% }
<span class="dep-line <%= $train->type // q{} %>">
%= $train->line
diff --git a/templates/_departures_dbris.html.ep b/templates/_departures_dbris.html.ep
new file mode 100644
index 0000000..dbd1a70
--- /dev/null
+++ b/templates/_departures_dbris.html.ep
@@ -0,0 +1,55 @@
+<ul class="collection departures">
+% my $orientation_bar_shown = param('train');
+% my $now_epoch = now->epoch;
+% for my $result (@{$results}) {
+ % my $row_class = '';
+ % my $link_class = 'action-checkin';
+ % if ($result->is_cancelled) {
+ % $row_class = "cancelled";
+ % $link_class = 'action-cancelled-from';
+ % }
+ % if (not $orientation_bar_shown and $result->dep->epoch < $now_epoch) {
+ % $orientation_bar_shown = 1;
+ <li class="collection-item" id="now">
+ <strong class="dep-time">
+ %= now->strftime('%H:%M')
+ </strong>
+ <strong>— Anfragezeitpunkt —</strong>
+ </li>
+ % }
+ <li class="collection-item <%= $link_class %> <%= $row_class %>"
+ data-dbris="<%= $dbris %>"
+ data-station="<%= $result->stop_eva %>"
+ data-train="<%= $result->id %>"
+ data-suffix="<%= $result->maybe_line_no %>"
+ data-ts="<%= ($result->sched_dep // $result->dep)->epoch %>"
+ >
+ <a class="dep-time" href="#">
+ %= $result->dep->strftime('%H:%M')
+ % if ($result->delay) {
+ (<%= sprintf('%+d', $result->delay) %>)
+ % }
+ % elsif (not defined $result->delay and not $result->is_cancelled) {
+ <i class="material-icons" aria-label="Keine Echtzeitdaten vorhanden" style="font-size: 16px;">gps_off</i>
+ % }
+ </a>
+ <span class="dep-line <%= $result->type // q{} %>">
+ %= $result->line
+ </span>
+ <span class="dep-dest">
+ % if ($result->is_cancelled) {
+ Fahrt nach <%= $result->destination // $result->via_last %> entfällt
+ % }
+ % else {
+ %= $result->destination // $result->via_last
+ % for my $checkin (@{$checkin_by_train->{$result->id} // []}) {
+ <span class="followee-checkin">
+ <i class="material-icons tiny" aria-label="Eine Person, der du folgst, ist hier eingecheckt">people</i>
+ <%= $checkin->{followee_name} %> → <%= $checkin->{arr_name} // '???' %>
+ </span>
+ % }
+ % }
+ </span>
+ </li>
+% }
+</ul>
diff --git a/templates/_departures_efa.html.ep b/templates/_departures_efa.html.ep
new file mode 100644
index 0000000..26af13f
--- /dev/null
+++ b/templates/_departures_efa.html.ep
@@ -0,0 +1,57 @@
+<ul class="collection departures">
+% my $orientation_bar_shown = param('train');
+% my $now_epoch = now->epoch;
+% for my $result (@{$results}) {
+ % my $row_class = '';
+ % my $link_class = 'action-checkin';
+ % if ($result->is_cancelled) {
+ % $row_class = "cancelled";
+ % $link_class = 'action-cancelled-from';
+ % }
+ % if (not $orientation_bar_shown and $result->datetime->epoch < $now_epoch) {
+ % $orientation_bar_shown = 1;
+ <li class="collection-item" id="now">
+ <strong class="dep-time">
+ %= now->strftime('%H:%M')
+ </strong>
+ <strong>— Anfragezeitpunkt —</strong>
+ </li>
+ % }
+ <li class="collection-item <%= $link_class %> <%= $row_class %>"
+ data-efa="<%= $efa %>"
+ data-station="<%= $result->stop_id_num %>"
+ data-train="<%= $result->id %>"
+ data-ts="<%= ($result->sched_datetime // $result->datetime)->epoch %>"
+ >
+ <a class="dep-time" href="#">
+ %= $result->datetime->strftime('%H:%M')
+ % if ($result->delay) {
+ (<%= sprintf('%+d', $result->delay) %>)
+ % }
+ % elsif (not defined $result->delay and not $result->is_cancelled) {
+ <i class="material-icons" aria-label="Keine Echtzeitdaten vorhanden" style="font-size: 16px;">gps_off</i>
+ % }
+ </a>
+ <span class="dep-line <%= ($result->type // q{}) =~ tr{a-zA-Z_-}{}cdr %>">
+ %= $result->line
+ </span>
+ <span class="dep-dest">
+ % if ($result->is_cancelled) {
+ Fahrt nach <%= $result->destination %> entfällt
+ % }
+ % else {
+ %= $result->destination
+ % for my $checkin (@{$checkin_by_train->{$result->id} // []}) {
+ <span class="followee-checkin">
+ <i class="material-icons tiny" aria-label="Eine Person, der du folgst, ist hier eingecheckt">people</i>
+ <%= $checkin->{followee_name} %> → <%= $checkin->{arr_name} // '???' %>
+ </span>
+ % }
+ % if ($result->occupancy) {
+ <i class="material-icons tiny" aria-hidden="true"><%= efa_load_icon($result->occupancy) %></i>
+ % }
+ % }
+ </span>
+ </li>
+% }
+</ul>
diff --git a/templates/_departures_hafas.html.ep b/templates/_departures_hafas.html.ep
index 9e4d7a4..5825ba0 100644
--- a/templates/_departures_hafas.html.ep
+++ b/templates/_departures_hafas.html.ep
@@ -18,6 +18,7 @@
</li>
% }
<li class="collection-item <%= $link_class %> <%= $row_class %>"
+ data-hafas="<%= $hafas %>"
data-station="<%= $result->station_eva %>"
data-train="<%= $result->id %>"
data-ts="<%= ($result->sched_datetime // $result->datetime)->epoch %>"
@@ -40,6 +41,13 @@
% }
% else {
%= $result->destination
+ % if ($result->load and $result->load->{SECOND}) {
+ % my ($first, $second) = load_icon($result->load);
+ % if ($first ne 'help_outline') {
+ <i class="material-icons tiny" aria-hidden="true"><%= $first %></i>
+ % }
+ <i class="material-icons tiny" aria-hidden="true"><%= $second %></i>
+ % }
% for my $checkin (@{$checkin_by_train->{$result->id} // []}) {
<span class="followee-checkin">
<i class="material-icons tiny" aria-label="Eine Person, der du folgst, ist hier eingecheckt">people</i>
diff --git a/templates/_departures_motis.html.ep b/templates/_departures_motis.html.ep
new file mode 100644
index 0000000..2ebc5de
--- /dev/null
+++ b/templates/_departures_motis.html.ep
@@ -0,0 +1,54 @@
+<ul class="collection departures">
+% my $orientation_bar_shown = param('train');
+% my $now_epoch = now->epoch;
+% for my $result (@{$results}) {
+ % my $row_class = '';
+ % my $link_class = 'action-checkin';
+ % if ($result->is_cancelled) {
+ % $row_class = "cancelled";
+ % $link_class = 'action-cancelled-from';
+ % }
+ % if (not $orientation_bar_shown and $result->stopover->departure->epoch < $now_epoch) {
+ % $orientation_bar_shown = 1;
+ <li class="collection-item" id="now">
+ <strong class="dep-time">
+ %= now->strftime('%H:%M')
+ </strong>
+ <strong>— Anfragezeitpunkt —</strong>
+ </li>
+ % }
+ <li class="collection-item <%= $link_class %> <%= $row_class %>"
+ data-motis="<%= $motis %>"
+ data-station="<%= $result->stopover->stop->id %>"
+ data-train="<%= $result->id %>"
+ data-ts="<%= ($result->stopover->departure)->epoch %>"
+ >
+ <a class="dep-time" href="#">
+ %= $result->stopover->departure->strftime('%H:%M')
+ % if ($result->stopover->delay) {
+ (<%= sprintf('%+d', $result->stopover->delay) %>)
+ % }
+ % elsif (not $result->stopover->is_realtime and not $result->stopover->is_cancelled) {
+ <i class="material-icons" aria-label="Keine Echtzeitdaten vorhanden" style="font-size: 16px;">gps_off</i>
+ % }
+ </a>
+ <span class="dep-line <%= $result->mode %>" style="background-color: #<%= $result->route_color // q{} %>;">
+ %= $result->route_name
+ </span>
+ <span class="dep-dest">
+ % if ($result->is_cancelled) {
+ Fahrt nach <%= $result->headsign %> entfällt
+ % }
+ % else {
+ %= $result->headsign
+ % for my $checkin (@{$checkin_by_train->{$result->id} // []}) {
+ <span class="followee-checkin">
+ <i class="material-icons tiny" aria-label="Eine Person, der du folgst, ist hier eingecheckt">people</i>
+ <%= $checkin->{followee_name} %> → <%= $checkin->{arr_name} // '???' %>
+ </span>
+ % }
+ % }
+ </span>
+ </li>
+% }
+</ul>
diff --git a/templates/_format_train.html.ep b/templates/_format_train.html.ep
index 1d6acaa..cb81211 100644
--- a/templates/_format_train.html.ep
+++ b/templates/_format_train.html.ep
@@ -1,8 +1,10 @@
% if ($journey->{extra_data}{wagonorder_pride}) {
🏳️‍🌈
% }
-<span class="dep-line <%= $journey->{train_type} // q{} %>">
- <%= $journey->{train_type} %>
+<span class="dep-line <%= ($journey->{train_type} // q{}) =~ tr{a-zA-Z_-}{}cdr %>">
+ % if (not $journey->{is_motis}) {
+ <%= $journey->{train_type} %>
+ % }
<%= $journey->{train_line} // $journey->{train_no}%>
</span>
% if ($journey->{train_line}) {
diff --git a/templates/_history_trains.html.ep b/templates/_history_trains.html.ep
index cf998ab..166d74d 100644
--- a/templates/_history_trains.html.ep
+++ b/templates/_history_trains.html.ep
@@ -16,8 +16,11 @@
% }
<li class="collection-item">
<a href="<%= $detail_link %>">
- <span class="dep-line <%= $travel->{type} // q{} %>">
- <%= $travel->{type} %> <%= $travel->{line} // $travel->{no}%>
+ <span class="dep-line <%= ($travel->{type} // q{}) =~ tr{a-zA-Z_-}{}cdr %>">
+ % if (length($travel->{type}) < 5 and not $travel->{is_motis}) {
+ <%= $travel->{type} %>
+ % }
+ <%= $travel->{line} // $travel->{no}%>
</span>
</a>
@@ -34,8 +37,8 @@
<i class="material-icons">timer_off</i>
% } else {
%= $travel->{rt_arrival}->strftime('%H:%M');
- % if ($travel->{sched_arrival} != $travel->{rt_arrival}) {
- (<%= sprintf('%+d', ($travel->{rt_arrival}->epoch - $travel->{sched_arrival}->epoch) / 60) %>)
+ % if ($travel->{delay_arr} and int($travel->{delay_arr} / 60)) {
+ (<%= sprintf('%+d', $travel->{delay_arr} / 60) %>)
% }
% }
% }
@@ -52,8 +55,8 @@
% }
% else {
<%= $travel->{rt_departure}->strftime('%H:%M') %>
- % if ($travel->{sched_departure} != $travel->{rt_departure}) {
- (<%= sprintf('%+d', ($travel->{rt_departure}->epoch - $travel->{sched_departure}->epoch) / 60) %>)
+ % if ($travel->{delay_dep} and int($travel->{delay_dep} / 60)) {
+ (<%= sprintf('%+d', $travel->{delay_dep} / 60) %>)
% }
% }
<strong><%= $travel->{from_name} %></strong>
diff --git a/templates/_map.html.ep b/templates/_map.html.ep
index daa16f0..223bd68 100644
--- a/templates/_map.html.ep
+++ b/templates/_map.html.ep
@@ -1,16 +1,18 @@
-<div class="row">
- <div class="col s12">
- <div id="map" style="height: 70vh;">
+% if (stash('with_map_header') // 1) {
+ <div class="row">
+ <div class="col s12">
+ <div id="map" style="height: 70vh;">
+ </div>
</div>
</div>
-</div>
-<div class="row">
- <div class="col s12">
- <span style="color: #f03;">●</span> Ein-/Ausstiegsstation<br/>
- <span style="color: #673ab7;">—</span> Streckenverlauf oder Luftlinie
+ <div class="row">
+ <div class="col s12">
+ <span style="color: #f03;">●</span> Ein-/Ausstiegsstation<br/>
+ <span style="color: #673ab7;">—</span> Streckenverlauf oder Luftlinie
+ </div>
</div>
-</div>
+% }
<script>
var map = L.map('map').setView([51.306, 9.712], 6);
diff --git a/templates/_public_status_card.html.ep b/templates/_public_status_card.html.ep
index b463d15..32b193a 100644
--- a/templates/_public_status_card.html.ep
+++ b/templates/_public_status_card.html.ep
@@ -8,7 +8,7 @@
Unterwegs mit <%= include '_format_train', journey => $journey %>
% }
% elsif (stash('from_timeline')) {
- <a href="/p/<%= $name %>"><%= $name %></a>: <%= include '_format_train', journey => $journey %>
+ <a href="/status/<%= $name %>"><%= $name %></a>: <%= include '_format_train', journey => $journey %>
% }
% else {
<a href="/p/<%= $name %>"><%= $name %></a> ist unterwegs
@@ -19,9 +19,9 @@
% }
</span>
% if ($privacy->{comments_visible} and $journey->{comment}) {
- <p>„<%= $journey->{comment} %>“</p>
+ <div>„<%= $journey->{comment} %>“</div>
% }
- <p>
+ <div>
% if (not stash('from_profile') and not stash('from_timeline')) {
<div class="center-align">
%= include '_format_train', journey => $journey
@@ -60,8 +60,8 @@
<div class="progress" style="height: 1ex;">
<div class="determinate" style="width: <%= sprintf('%.2f', 100 * ($journey->{journey_completion} // 0)); %>%;"></div>
</div>
- </p>
- <p>
+ </div>
+ <div class="status-card-progress-annot">
<div style="float: left;">
<b><%= $journey->{dep_name} %></b><br/>
<b><%= $journey->{real_departure}->strftime('%H:%M') %></b>
@@ -92,20 +92,31 @@
% last;
% }
% if (($station->[2]{arr_countdown} // 0) > 0 and $station->[2]{arr}) {
- <%= $station->[0] %><br/><%= $station->[2]{arr}->strftime('%H:%M') %>
+ %= $station->[0]
+ <br/>
+ %= $station->[2]{arr}->strftime('%H:%M')
% if ($station->[2]{arr_delay}) {
- %= sprintf('(%+d)', $station->[2]{arr_delay} / 60);
+ %= sprintf('(%+d)', $station->[2]{arr_delay} / 60)
+ % }
+ % if ($station->[2]{load}{SECOND}) {
+ <br/>
+ %= include '_show_load_icons', station => $station
% }
% last;
% }
% if (($station->[2]{dep_countdown} // 0) > 0 and $station->[2]{dep}) {
- <%= $station->[0] %><br/>
+ %= $station->[0]
+ <br/>
% if ($station->[2]{arr}) {
<%= $station->[2]{arr}->strftime('%H:%M') %> →
% }
%= $station->[2]{dep}->strftime('%H:%M')
% if ($station->[2]{dep_delay}) {
- %= sprintf('(%+d)', $station->[2]{dep_delay} / 60);
+ %= sprintf('(%+d)', $station->[2]{dep_delay} / 60)
+ % }
+ % if ($station->[2]{load}{SECOND}) {
+ <br/>
+ %= include '_show_load_icons', station => $station
% }
% last;
% }
@@ -120,34 +131,46 @@
% }
% if (($station->[2]{arr_countdown} // 0) > 0 and $station->[2]{arr}) {
Nächster Halt:<br/>
- <%= $station->[0] %><br/><%= $station->[2]{arr}->strftime('%H:%M') %>
+ %= $station->[0]
+ <br/>
+ %= $station->[2]{arr}->strftime('%H:%M')
% if ($station->[2]{arr_delay}) {
- %= sprintf('(%+d)', $station->[2]{arr_delay} / 60);
+ %= sprintf('(%+d)', $station->[2]{arr_delay} / 60)
+ % }
+ % if ($station->[2]{load}{SECOND}) {
+ <br/>
+ %= include '_show_load_icons', station => $station
% }
% last;
% }
% if (($station->[2]{dep_countdown} // 0) > 0 and $station->[2]{arr} and $station->[2]{dep}) {
Aktueller Halt:<br/>
- <%= $station->[0] %><br/>
- <%= $station->[2]{arr}->strftime('%H:%M') %> →
- <%= $station->[2]{dep}->strftime('%H:%M') %>
+ %= $station->[0]
+ <br/>
+ %= $station->[2]{arr}->strftime('%H:%M')
+ →
+ %= $station->[2]{dep}->strftime('%H:%M')
% if ($station->[2]{dep_delay}) {
- %= sprintf('(%+d)', $station->[2]{dep_delay} / 60);
+ %= sprintf('(%+d)', $station->[2]{dep_delay} / 60)
+ % }
+ % if ($station->[2]{load}{SECOND}) {
+ <br/>
+ %= include '_show_load_icons', station => $station
% }
% last;
% }
% }
</div>
- </p>
+ </div>
% if ($journey->{extra_data}{cancelled_destination}) {
- <p style="margin-bottom: 2ex;">
+ <div style="margin-bottom: 2ex;">
<i class="material-icons tiny" aria-hidden="true">error</i>
Der Halt an der Zielstation <b><%=
$journey->{extra_data}{cancelled_destination} %></b> entfällt.
- </p>
+ </div>
% }
% if (@{$journey->{messages} // []} > 0 and $journey->{messages}[0]) {
- <p style="margin-bottom: 2ex;">
+ <div style="margin-top: 2ex;">
<ul>
% for my $message (reverse @{$journey->{messages} // []}) {
% if ($journey->{sched_departure}->epoch - $message->[0]->epoch < 1800) {
@@ -158,22 +181,95 @@
<li> <i class="material-icons tiny">info</i> <%= $message->[0]->strftime('%H:%M') %>: <%= $message->[1] %></li>
% }
</ul>
- </p>
+ </div>
% }
- </div>
- % if (not stash('from_timeline')) {
- <div class="card-action">
- % if ($journey->{traewelling_url}) {
- <a style="margin-right: 0;" href="<%= $journey->{traewelling_url} %>"><i class="material-icons left">timeline</i> Träwelling</a>
- % } else {
- % my $url = 'https://bahn.expert/details/' . $journey->{train_type} . ' ' . $journey->{train_no} . '/' . DateTime->now(time_zone => 'Europe/Berlin')->epoch . '000';
- <a style="margin-right: 0;" href="<%= $url %>"><i class="material-icons left">timeline</i> Zuglauf</a>
+ % if (@{$journey->{extra_data}{him_msg} // []}) {
+ <div style="margin-top: 2ex;">
+ <ul>
+ % for my $message (@{$journey->{extra_data}{him_msg} // []}) {
+ % if (not stash('from_timeline') or $message->{prio} and $message->{prio} eq 'HOCH') {
+ <li> <i class="material-icons tiny"><%= ($message->{prio} and $message->{prio} eq 'HOCH') ? 'warning' : 'info' %></i> <%= $message->{header} %> <%= $message->{lead} %></li>
+ % }
+ % }
+ </ul>
+ </div>
+ % }
+ % if (stash('station_coordinates')) {
+ <div id="map" style="height: 70vh;">
+ </div>
+ %= include '_map', with_map_header => 0, station_coordinates => stash('station_coordinates'), polyline_groups => stash('polyline_groups')
+ % }
+ % if ( @{$journey->{wagongroups} // []} ) {
+ % if (stash('from_timeline')) {
+ <div class="wagons" style="margin-top: 2ex;">
+ % for my $wagongroup (@{$journey->{wagongroups}}) {
+ %= $wagongroup->{desc} // $wagongroup->{name}
+ % if ($wagongroup->{designation}) {
+ „<%= $wagongroup->{designation} %>“
+ % }
+ % if ($wagongroup->{to}) {
+ → <%= $wagongroup->{to} %>
+ % }
+ <br/>
+ % }
+ </div>
% }
- % if ($journey->{extra_data}{trip_id}) {
- <a class="right" style="margin-right: 0;" href="https://dbf.finalrewind.org/map/<%= $journey->{extra_data}{trip_id} %>/<%= $journey->{train_line} || 0 %>?from=<%= $journey->{dep_name} %>&amp;to=<%= $journey->{arr_name} // '' %>"><i class="material-icons left">map</i> Karte</a>
+ % else {
+ <div class="wagons" style="margin-top: 2ex;">
+ Wagen:<br/>
+ %= include '_wagons', wagongroups => $journey->{wagongroups};
+ </div>
% }
- </div>
- % }
+ % }
+ % if (not stash('from_timeline')) {
+ <div style="margin-top: 2ex;">
+ Route:<br/>
+ % my $before = 1;
+ % my $within = 0;
+ % my $at_startstop = 0;
+ % for my $station (@{$journey->{route}}) {
+ % if (($station->[1] and $station->[1] == $journey->{dep_eva}) or $station->[0] eq $journey->{dep_name}) {
+ % $within = 1; $at_startstop = 1;
+ % }
+ % elsif ($journey->{arr_eva} and (($station->[1] and $station->[1] == $journey->{arr_eva}) or $station->[0] eq $journey->{arr_name})) {
+ % $within = 0; $at_startstop = 1;
+ % }
+ % else {
+ % $at_startstop = 0;
+ % }
+ <span style="color: #808080;">
+ % if ($before and $station->[2]{sched_dep}) {
+ %= $station->[2]{sched_dep}->strftime('%H:%M')
+ % }
+ % elsif (not $before and $station->[2]{sched_arr}) {
+ %= $station->[2]{sched_arr}->strftime('%H:%M')
+ % }
+ </span>
+ % if ($at_startstop or $within) {
+ %= $station->[0]
+ % }
+ % else {
+ <span style="color: #808080;"><%= $station->[0] %></span>
+ % }
+ <span>
+ %= include '_show_load_icons', station => $station
+ </span>
+ <span style="color: #808080;">
+ % if ($before and $station->[2]{rt_dep} and $station->[2]{dep_delay}) {
+ %= sprintf('%+d', $station->[2]{dep_delay} / 60)
+ % }
+ % elsif (not $before and $station->[2]{rt_arr} and $station->[2]{arr_delay}) {
+ %= sprintf('%+d', $station->[2]{arr_delay} / 60)
+ % }
+ </span>
+ % if (($station->[1] and $station->[1] == $journey->{dep_eva}) or $station->[0] eq $journey->{dep_name}) {
+ % $before = 0;
+ % }
+ <br/>
+ % }
+ </div>
+ % }
+ </div>
</div>
% }
% else {
@@ -186,7 +282,7 @@
% else {
<span class="card-title"><a href="/p/<%= $name %>"><%= $name %></a> ist gerade nicht eingecheckt</span>
% }
- <p>
+ <div>
% if ($journey->{arr_name}) {
Zuletzt gesehen
% if ($journey->{real_arrival}->epoch) {
@@ -198,7 +294,7 @@
in <b><%= $journey->{arr_name} %></b>
% }
% }
- </p>
+ </div>
</div>
</div>
% }
diff --git a/templates/_show_load_icons.html.ep b/templates/_show_load_icons.html.ep
new file mode 100644
index 0000000..21093b9
--- /dev/null
+++ b/templates/_show_load_icons.html.ep
@@ -0,0 +1,11 @@
+% if ($station->[2]{load}{SECOND}) {
+ % my ($first, $second) = load_icon($station->[2]{load});
+ % if ($first ne 'help_outline') {
+ <i class="material-icons tiny" aria-hidden="true"><%= $first %></i>
+ % }
+ <i class="material-icons tiny" aria-hidden="true"><%= $second %></i>
+% }
+% elsif ($station->[2]{efa_load}) {
+ % my ($icon) = efa_load_icon($station->[2]{efa_load});
+ <i class="material-icons tiny" aria-hidden="true"><%= $icon %></i>
+% }
diff --git a/templates/_timeline_link.html.ep b/templates/_timeline_link.html.ep
index 1a78279..4b9c2a5 100644
--- a/templates/_timeline_link.html.ep
+++ b/templates/_timeline_link.html.ep
@@ -1,5 +1,5 @@
<div>
- <a href="/timeline/in-transit">
+ <a class="timeline-link" href="/timeline/in-transit">
% if (@{$timeline} <= 2) {
<strong><%= $timeline->[0]->{followee_name} %></strong>
% }
diff --git a/templates/_wagons.html.ep b/templates/_wagons.html.ep
index 106709e..4090f11 100644
--- a/templates/_wagons.html.ep
+++ b/templates/_wagons.html.ep
@@ -1,13 +1,22 @@
% for my $wagongroup (@{$wagongroups // []}) {
- <%= $wagongroup->{name} %>
+ %= $wagongroup->{desc} // $wagongroup->{name}
% my ($wagon_number) = ($wagongroup->{name} =~ m{ ^ ICE 0* (\d+) $ }x);
- % if ($wagon_number and my $group_name = app->ice_name->{$wagon_number}) {
+ % if ($wagongroup->{designation}) {
+ „<%= $wagongroup->{designation} %>“
+ % }
+ % elsif ($wagon_number and my $group_name = app->ice_name->{$wagon_number}) {
„<%= $group_name %>“
% }
- als <b><%= $journey->{type} %> <%= $wagongroup->{no} %></b>
- von <b><%= $wagongroup->{from} %></b> nach <b><%= $wagongroup->{to} %></b><br/>
+ als <b><%= $wagongroup->{type} // $journey->{type} %> <%= $wagongroup->{no} %></b>
+ % if ($wagongroup->{from}) {
+ von <b><%= $wagongroup->{from} %></b>
+ % }
+ % if ($wagongroup->{to}) {
+ nach <b><%= $wagongroup->{to} %></b>
+ % }
+ <br/>
% for my $wagon (@{$wagongroup->{wagons}}) {
- % if (length($wagon->{id}) == 12) {
+ % if (length($wagon->{id}) == 12 or length($wagon->{id}) == 14) {
<span><%= substr($wagon->{id}, 0, 2) %></span><span><%= substr($wagon->{id}, 2, 2) %></span><span><%= substr($wagon->{id}, 4, 1) %></span><span class="wagonclass"><%= substr($wagon->{id}, 5, 3) %></span><span class="wagonnum"><%= substr($wagon->{id}, 8, 3) %></span><span class="checksum"><%= substr($wagon->{id}, 11) %></span>
% }
% elsif ($wagon->{id}) {
diff --git a/templates/about.html.ep b/templates/about.html.ep
index ea86bdf..e2b148d 100644
--- a/templates/about.html.ep
+++ b/templates/about.html.ep
@@ -1,14 +1,21 @@
<div class="row">
<div class="col s12">
<a href="https://finalrewind.org/projects/travelynx">travelynx</a> v<%= stash('version') // '???' %><br/>
- Entwickelt von <a href="https://finalrewind.org">derf</a><br/>
- <a href="<%= app->config->{ref}{source} // 'https://github.com/derf/travelynx' %>">Quelltext</a> lizensiert unter AGPL v3<br/><br/>
+ Entwickelt von <a href="https://finalrewind.org">derf</a>
+ und <a href="https://github.com/derf/travelynx/graphs/contributors">weiteren</a><br/>
+ <a href="<%= app->config->{ref}{source} // 'https://git.finalrewind.org/travelynx' %>">Quelltext</a> lizensiert unter AGPL v3<br/><br/>
Backends:
+ <a href="https://finalrewind.org/projects/Travel-Status-DE-DBRIS/">Travel::Status::DE::DBRIS</a>
+ v<%= $Travel::Status::DE::DBRIS::VERSION %>,
+ <a href="https://finalrewind.org/projects/Travel-Status-DE-EFA/">Travel::Status::DE::EFA</a>
+ v<%= $Travel::Status::DE::EFA::VERSION %>,
+ <a href="https://finalrewind.org/projects/Travel-Status-DE-HAFAS/">Travel::Status::DE::HAFAS</a>
+ v<%= $Travel::Status::DE::HAFAS::VERSION %>,
<a href="https://finalrewind.org/projects/Travel-Status-DE-IRIS/">Travel::Status::DE::IRIS</a>
v<%= $Travel::Status::DE::IRIS::VERSION %> und
- <a href="https://finalrewind.org/projects/Travel-Status-DE-DeutscheBahn/">Travel::Status::DE::HAFAS</a>
- v<%= $Travel::Status::DE::HAFAS::VERSION %><br/>
- <a href="http://data.deutschebahn.com/dataset/data-haltestellen">Haltestellendaten</a>
+ <a href="https://finalrewind.org/projects/Travel-Status-MOTIS/">Travel::Status::MOTIS</a>
+ v<%= $Travel::Status::MOTIS::VERSION %><br/>
+ Haltestellendaten
© DB Station&amp;Service AG,
Europaplatz 1,
10557 Berlin, lizensiert unter CC-BY 4.0
@@ -16,6 +23,19 @@
</div>
<div class="row">
+ <div class="col s12">
+ <p>
+ Travelynx ist ein kostenfreies, privat betriebenes Projekt ohne
+ Verfügbarkeitsgarantie. Unangekündigte Downtimes oder eine
+ kurzfristige Einstellung dieser Seite sind nicht vorgesehen, aber
+ möglich. Feature Requests, Bug Reports und sonstige Nachrichten
+ werden je nach Kapazität und Motivation zeitnah, verzögert oder gar
+ nicht bearbeitet / beantwortet.
+ </p>
+ </div>
+</div>
+
+<div class="row">
<div class="col s12 m12 l4 center-align" style="margin-top: 1em;">
<a href="https://social.skyshaper.org/derf" class="waves-effect waves-light btn"><i class="material-icons left">message</i>Kontakt</a>
</div>
diff --git a/templates/account.html.ep b/templates/account.html.ep
index 7f689c2..e4bf38d 100644
--- a/templates/account.html.ep
+++ b/templates/account.html.ep
@@ -28,9 +28,6 @@
% elsif ($success eq 'use_history') {
<span class="card-title">Einstellungen zu vorgeschlagenen Verbindungen geändert</span>
% }
- % elsif ($success eq 'external') {
- <span class="card-title">Einstellungen zu externen Diensten geändert</span>
- % }
% elsif ($success eq 'webhook') {
<span class="card-title">Web Hook aktualisiert</span>
% }
@@ -126,6 +123,8 @@
<tr>
<th scope="row">Träwelling</th>
<td>
+ Wird wegen Inkompatibilität zwischen bahn.de und transitous derzeit nicht unterstützt
+ <!--
<a href="/account/traewelling"><i class="material-icons">edit</i></a>
% if (not ($traewelling->{token})) {
<span style="color: #999999;">Nicht verknüpft</span>
@@ -148,22 +147,11 @@
– Checkins in travelynx werden zu Träwelling weitergereicht
% }
% }
+ -->
</td>
</tr>
% }
<tr>
- <th scope="row">Externe Dienste</th>
- <td>
- <a href="/account/services"><i class="material-icons">edit</i></a>
- % if ($acc->{sb_name}) {
- Abfahrtstafel: <%= $acc->{sb_name} %>
- % }
- % else {
- <span style="color: #999999;">Keine</span>
- % }
- </td>
- </tr>
- <tr>
<th scope="row">Registriert am</th>
<td><%= $acc->{registered_at}->strftime('%d.%m.%Y %H:%M') %></td>
</tr>
diff --git a/templates/add_intransit.html.ep b/templates/add_intransit.html.ep
new file mode 100644
index 0000000..9d711c9
--- /dev/null
+++ b/templates/add_intransit.html.ep
@@ -0,0 +1,93 @@
+<h1>Manuell einchecken</h1>
+% if ($error) {
+ <div class="row">
+ <div class="col s12">
+ <div class="card caution-color">
+ <div class="card-content white-text">
+ <span class="card-title">Ungültige Eingabe</span>
+ <p><%= $error %></p>
+ </div>
+ </div>
+ </div>
+ </div>
+% }
+<div class="row">
+ <div class="col s12">
+ <p>
+ Falls die gesuchte Abfahrt nicht vom ausgewählten Backend verfügbar ist, z.B. da es sich um eine Sonderfahrt handelt, ist hier ein manueller Checkin möglich.
+ Nach dem Checkin werden alle Daten so beibehalten wie sie eingegeben wurden; Änderungen sind erst nach dem Auschecken möglich.
+ </p>
+ <ul>
+ <li>Eingabe der Fahrt als „Typ Linie Nummer“ oder „Typ Nummer“, z.B.
+ „ICE 100“, „S 1 31133“ oder „ABR RE11 26720“</li>
+ <li>Wenn Nummer nicht bekannt oder vorhanden: einen beliebigen Integer eintragen, z.B. „S 5X 0“ oder „U 11 0“</li>
+ <li>Zeitangaben im Format DD.MM.YYYY HH:MM</li>
+ <li>Das ausgewählte Backend bestimmt die verfügbaren Halte für Start, Ziel und Route. Siehe auch <a href="/static/stops.csv">stops.csv</a></li>
+ </ul>
+ </div>
+</div>
+<div class="row">
+ <div class="col s12 center-align">
+ % if (current_user->{backend_id}) {
+ <a href="/account/select_backend?redirect_to=/checkin/add" class="btn-small btn-flat"><i class="material-icons left" aria-hidden="true">directions</i><%= current_user->{backend_name} %></a>
+ % }
+ % else {
+ <a href="/account/select_backend?redirect_to=/checkin/add" class="btn-small btn-flat"><i class="material-icons left" aria-hidden="true">train</i>IRIS</a>
+ % }
+ </div>
+</div>
+%= form_for '/checkin/add' => (method => 'POST') => begin
+ %= csrf_field
+ <div class="row">
+ <div class="input-field col s12">
+ %= text_field 'train', id => 'train', class => 'validate', required => undef, pattern => '[0-9a-zA-Z]+ +[0-9a-zA-Z]* *[0-9]+'
+ <label for="train">Fahrt (Typ Linie Nummer)</label>
+ </div>
+ </div>
+ <div class="row">
+ <div class="input-field col s12">
+ %= text_field 'dep_station', id => 'dep_station', class => 'autocomplete validate', autocomplete => 'off', required => undef
+ <label for="dep_station">Start (Name oder ID)</label>
+ </div>
+ <div class="input-field col s12">
+ %= text_field 'sched_departure', id => 'sched_departure', class => 'validate', required => undef, pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9]'
+ <label for="sched_departure">Geplante Abfahrt</label>
+ </div>
+ </div>
+ <div class="row">
+ <div class="input-field col s12">
+ %= text_field 'arr_station', id => 'arr_station', class => 'autocomplete validate', autocomplete => 'off', required => undef
+ <label for="arr_station">Ziel (Name oder ID)</label>
+ </div>
+ <div class="input-field col s12">
+ %= text_field 'sched_arrival', id => 'sched_arrival', class => 'validate', required => undef, pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9]'
+ <label for="sched_arrival">Geplante Ankunft</label>
+ </div>
+ </div>
+ <div class="row">
+ <div class="input-field col s12">
+ %= text_area 'route', id => 'route', class => 'materialize-textarea'
+ <label for="route">Halte (optional)</label><br/>
+ Eine Station pro Zeile, wahlweise Unterwegshalte oder komplette Route<br/>
+ Format: <i>Name</i> oder <i>Name</i> @ <i>Zeitpunkt</i> (inkl. Datum, siehe oben)
+ </div>
+ </div>
+ <div class="row">
+ <div class="input-field col s12">
+ %= text_field 'comment'
+ <label for="comment">Kommentar</label>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col s3 m3 l3">
+ </div>
+ <div class="col s6 m6 l6 center-align">
+ <button class="btn waves-effect waves-light" type="submit" name="action" value="save">
+ Einchecken
+ <i class="material-icons right">send</i>
+ </button>
+ </div>
+ <div class="col s3 m3 l3">
+ </div>
+ </div>
+%= end
diff --git a/templates/add_journey.html.ep b/templates/add_journey.html.ep
index c543781..cade37e 100644
--- a/templates/add_journey.html.ep
+++ b/templates/add_journey.html.ep
@@ -34,9 +34,21 @@
„ICE 100“, „S 1 31133“ oder „ABR RE11 26720“</li>
<li>Wenn Nummer nicht bekannt oder vorhanden: einen beliebigen Integer eintragen, z.B. „S 5X 0“ oder „U 11 0“</li>
<li>Zeitangaben im Format DD.MM.YYYY HH:MM</li>
+ <li>Das ausgewählte Backend bestimmt die verfügbaren Halte für Start, Ziel und Route. Siehe auch <a href="/static/stops.csv">stops.csv</a></li>
</ul>
</div>
</div>
+<div class="row">
+ <div class="col s12 center-align">
+ % my $self_link = url_for('add_journey');
+ % if (current_user->{backend_id}) {
+ <a href="/account/select_backend?redirect_to=<%= $self_link %>" class="btn-small btn-flat"><i class="material-icons left" aria-hidden="true">directions</i><%= current_user->{backend_name} %></a>
+ % }
+ % else {
+ <a href="/account/select_backend?redirect_to=<%= $self_link %>" class="btn-small btn-flat"><i class="material-icons left" aria-hidden="true">train</i>IRIS</a>
+ % }
+ </div>
+</div>
%= form_for '/journey/add' => (method => 'POST') => begin
%= csrf_field
<div class="row">
@@ -54,7 +66,7 @@
<div class="row">
<div class="input-field col s12">
%= text_field 'dep_station', id => 'dep_station', class => 'autocomplete validate', autocomplete => 'off', required => undef
- <label for="dep_station">Start (Name oder DS100)</label>
+ <label for="dep_station">Start (Name oder ID)</label>
</div>
<div class="input-field col s12">
%= text_field 'sched_departure', id => 'sched_departure', class => 'validate', required => undef, pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9]'
@@ -68,7 +80,7 @@
<div class="row">
<div class="input-field col s12">
%= text_field 'arr_station', id => 'arr_station', class => 'autocomplete validate', autocomplete => 'off', required => undef
- <label for="arr_station">Ziel (Name oder DS100)</label>
+ <label for="arr_station">Ziel (Name oder ID)</label>
</div>
<div class="input-field col s12">
%= text_field 'sched_arrival', id => 'sched_arrival', class => 'validate', required => undef, pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9]'
@@ -82,7 +94,9 @@
<div class="row">
<div class="input-field col s12">
%= text_area 'route', id => 'route', class => 'materialize-textarea'
- <label for="route">Unterwegshalte (optional, eine Station pro Zeile, DS100 möglich)</label>
+ <label for="route">Halte (optional)</label><br/>
+ Eine Station pro Zeile, wahlweise Unterwegshalte oder komplette Route<br/>
+ Format: <i>Name</i> oder <i>Name</i> @ <i>Zeitpunkt</i> (inkl. Datum, siehe oben)
</div>
</div>
<div class="row">
diff --git a/templates/api_documentation.html.ep b/templates/api_documentation.html.ep
index 9c9ee1f..099474c 100644
--- a/templates/api_documentation.html.ep
+++ b/templates/api_documentation.html.ep
@@ -30,12 +30,18 @@
"actionTime" : 1234567, (UNIX-Timestamp des letzten Checkin/Checkout)<br/>
"checkedIn" : true / false,<br/>
"comment": "Kommentar",<br/>
+ "backend": {<br/>
+ "id": 1,<br/>
+ "name": "DB",<br/>
+ "type": "HAFAS",<br/>
+ },<br/>
"fromStation" : { (letzter Checkin)<br/>
"name" : "Essen Hbf",<br/>
"ds100" : "EE", (ggf. null)<br/>
"uic" : 8000098,<br/>
"latitude" : 51.451355,<br/>
"longitude" : 7.014793,<br/>
+ "platform" : "12", (ggf. null)<br/>
"scheduledTime": 1556083680,<br/>
"realTime": 1556083680<br/>
},<br/>
@@ -45,6 +51,7 @@
"uic" : 8001896,<br/>
"latitude" : 51.422853,<br/>
"longitude" : 7.023296,<br/>
+ "platform" : "2", (ggf. null)<br/>
"scheduledTime": 1556083980, (ggf. null)<br/>
"realTime": 1556083980 (ggf. null)<br/>
},<br/>
@@ -122,11 +129,13 @@
{<br/>
"token" : "<%= $uid %>-<%= $token->{travel} // 'TOKEN' %>",<br/>
"action" : "checkin",<br/>
+ "dbris" : "bahn.de", (DBRIS-Instanz – Default: bahn.de)<br/>
+ "hafas" : null, (HAFAS-Instanz, falls verwendet, sonste null)<br/>
"train" : {<br/>
- "journeyID" : "1|1426396|4|80|19082023",<br/>
+ "journeyID" : "2|#VN#1#ST#1742845592#PI#0#ZI#315136#TA#0#DA#270325#1S#8000080#1T#1841#LS#8006486#LT#2024#PU#80#RT#1#CA#RE#ZE#10773#ZB#RE10773#PC#3#FR#8000080#FT#1841#TO#8006486#TT#2024#",<br/>
}<br/>
- "fromStation" : 651806, (Name oder EVA-Nummer)<br/>
- "toStation" : 654645, (optional, Name oder EVA-Nummer)<br/>
+ "fromStation" : 8000080, (Name oder EVA-Nummer – bei bahn.de nur EVA-Nummer)<br/>
+ "toStation" : 8006486, (optional, Name oder EVA-Nummer – bei bahn.de nur EVA-Nummer)<br/>
"comment" : "Beliebiger Text" (optional, überschreibt vorherigen Kommentar)<br/>
}
</p>
diff --git a/templates/bad_gateway.html.ep b/templates/bad_gateway.html.ep
new file mode 100644
index 0000000..07bf29e
--- /dev/null
+++ b/templates/bad_gateway.html.ep
@@ -0,0 +1,27 @@
+<div class="row">
+ <div class="col s12">
+ <div class="card caution-color">
+ <div class="card-content white-text">
+ <span class="card-title">502 Bad Gateway</span>
+ <p>
+ Das von travelynx genutzte Backend hat einen Fehler zurückgegeben.
+ travelynx hat keine Möglichkeiten, diese Situation zu beheben.
+ % if (stash('select_new_backend')) {
+ Versuche es in ein paar Sekunden bis Minuten noch einmal oder <a href="/account/select_backend">wähle ein anderes Backend</a>.
+ % }
+ % else {
+ Versuche es in ein paar Sekunden bis Minuten noch einmal.
+ % }
+ </p>
+ </div>
+ </div>
+ </div>
+</div>
+<div class="row">
+ <div class="col s12">
+ <p>Details:</p>
+ <p style="font-family: monospace;">
+ %= $message
+ </p>
+ </div>
+</div>
diff --git a/templates/changelog.html.ep b/templates/changelog.html.ep
index 09126a8..0d1ecc5 100644
--- a/templates/changelog.html.ep
+++ b/templates/changelog.html.ep
@@ -2,6 +2,259 @@
<div class="row">
<div class="col s12 m1 l1">
+ 2.15
+ </div>
+ <div class="col s12 m11 l11">
+ <p>
+ <i class="material-icons left" aria-label="Neues Feature">add</i>
+ Manuelle Checkins. Diese verhalten sich analog zu manuell
+ eingetragenen Fahrten, werden jedoch bis zur planmäßigen
+ Ankunftszeit als Checkin behandelt. Manuelle Echtzeitdaten-Updates
+ werden nicht unterstützt. Manuelle Checkins sind nur an Halten
+ möglich, die dem ausgewählten Backend bekannt sind. Ggf. wird
+ dieses Feature später um eine Möglichkeit für Echtzeitdaten-Updates
+ und/oder eine API erweitert.
+ </p>
+ <p>
+ <i class="material-icons left" aria-label="Neues Feature">add</i>
+ Erfassung des Betreibers einer Fahrt, sofern verfügbar.
+ </p>
+ <p>
+ <i class="material-icons left" aria-label="Verbesserung">star</i>
+ EFA-Backends werden nun fast vollständig unterstützt und sind nicht
+ mehr experimentell.
+ </p>
+ <p>
+ <i class="material-icons left" aria-label="Bugfix">build</i>
+ Das manuelle Eintragen von Fahrten ist nun wieder möglich. Zudem
+ kann dabei nun ein beliebiges Backend ausgewählt werden; das
+ ausgewählte Backend bestimmt die verfügbaren Halte.
+ </p>
+ </div>
+</div>
+
+<div class="row">
+ <div class="col s12 m1 l1">
+ 2.14
+ </div>
+ <div class="col s12 m11 l11">
+ <p>
+ <i class="material-icons left" aria-label="Neues Feature">add</i>
+ Experimentelle Unterstützung für Checkins via EFA-Backends.
+ Teilweise ist ein Checkin nur bei Fahrten mit Echtzeitdaten
+ möglich. Hierbei handelt es sich nach aktuellem Stand um eine
+ Einschränkung der verwendeten Backends. Unterstützung für
+ ausfallende Fahrten folgt später.
+ </p>
+ </div>
+</div>
+
+<div class="row">
+ <div class="col s12 m1 l1">
+ 2.13
+ </div>
+ <div class="col s12 m11 l11">
+ <p>
+ <i class="material-icons left" aria-label="Neues Feature">add</i>
+ Experimentelle Unterstützung für Checkins via MOTIS-Backends
+ (derzeit transitous und RNV). Vielen Dank an <a href="https://github.com/networkException">networkException</a>
+ für die Implementierung der API und Einbindung in travelynx.
+ Träwelling-Synchronisierung ist noch nicht wiederhergestellt.
+ Time zones are currently somewhat wibbly-wobbly timey-wimey.
+ </p>
+ </div>
+</div>
+
+<div class="row">
+ <div class="col s12 m1 l1">
+ 2.12
+ </div>
+ <div class="col s12 m11 l11">
+ <p>
+ <i class="material-icons left" aria-label="Neues Feature">add</i>
+ Kartografische Visualisierung der Route bei eigenen Checkins und auf
+ der Statusseite sowie Angaben zu Meldungen, Rollmaterial, Route und
+ Auslastung auf der Statusseite. Feinheiten wie die Markierung der
+ geschätzten aktuellen Zugposition oder eine regelmäßige
+ Aktualisierung ohne Zurücksetzen der Kartenansicht folgen später.
+ Die Kartenlinks zu dbf.finalrewind.org entfallen.
+ </p>
+ <p>
+ <i class="material-icons left" aria-label="Ankündigung">announcement</i>
+ Das IRIS-TTS-Backend der Deutschen Bahn wird wegen zunehmend
+ schlechter Datenanreicherunngsmöglichkeiten nicht mehr
+ weiterentwickelt. Bei Checkins per IRIS-TTS stehen regelmäßig keine
+ Echtzeitdaten und insbesondere bei Nebenbahnen auch keine
+ Kartendaten zur Verfügung. In diesem Fall fehlt auch die
+ ersatzwiese Visualisierung der Luftlinie zwischen den
+ Unterwegshalten. Dies betrifft auch die Visualisierung in der
+ Fahrtenkarte.
+ </p>
+ <p>
+ <i class="material-icons left" aria-label="Ankündigung">announcement</i>
+ Derzeit besteht wegen inkompatibler Backends keine
+ Synchronisierungsmöglichkeit zwischen Träwelling (transitous MOTIS)
+ und travelynx (DB IRIS-TTS / DB HAFAS / bahn.de).
+ MOTIS-Unterstützung in travelynx ist in Arbeit.
+ </p>
+ </div>
+</div>
+
+<div class="row">
+ <div class="col s12 m1 l1">
+ 2.11
+ </div>
+ <div class="col s12 m11 l11">
+ <p>
+ <i class="material-icons left" aria-label="Neues Feature">add</i>
+ Neues Backend: bahn.de. Somit steht nach Abschaltung von DB HAFAS
+ und VRN HAFAS wieder ein Backend zur Verfügung, welches für
+ innerdeutschen Nah-, Regional- und Fernverkehr geeignet ist und
+ eine Synchronisierung mit Träwelling unterstützt. Teile der
+ Implementierung können noch unvollständig sein. Ebenso besteht die
+ Möglichkeit, dass es wegen Rate Limits auf Seiten von bahn.de nicht
+ immer zuverlässig nutzbar ist.
+ </p>
+ </div>
+</div>
+
+<div class="row">
+ <div class="col s12 m1 l1">
+ 2.10
+ </div>
+ <div class="col s12 m11 l11">
+ <p>
+ <i class="material-icons left" aria-label="Neues Feature">add</i>
+ Neue HAFAS-Backends: PKP, SaarVV.
+ </p>
+ <p>
+ <i class="material-icons left" aria-label="Bug">warning</i> Das DB
+ HAFAS-Backend wurde am 8. Januar 2025 abgeschaltet und wird von
+ travelynx daher seit v2.9.11 nicht mehr angeboten. Als vorläufiger
+ Ersatz bietet sich das VRN HAFAS-Backend an. Eine Wieder-Anbindung
+ der DB mittels Travel::Status::DE::DBRIS ist in Arbeit. Bis dahin
+ ist keine Synchronisierung mit Traewelling möglich.
+ </p>
+ <p>
+ <i class="material-icons left" aria-label="Administration">announcement</i>
+ Das PKP HAFAS befindet sich hinter einem GeoIP-Filter und wird
+ daher in travelynx-Installationen außerhalb von travelynx.de
+ standardmäßig nicht angeboten. Sofern die travelynx-Instanz auf
+ einer geeigneten IP-Adresse betrieben wird oder eine solche per
+ Proxy erreichbar ist, lässt es sich über einen Eintrag in
+ travelynx.conf aktivieren. Als Nebenwirkung davon kann auch auf
+ beliebige andere HAFAS-Instanzen bei Bedarf über einen
+ Instanz-spezifischen Proxy zugegriffen werden.
+ </p>
+ </div>
+</div>
+
+<div class="row">
+ <div class="col s12 m1 l1">
+ 2.9
+ </div>
+ <div class="col s12 m11 l11">
+ <p>
+ <i class="material-icons left" aria-label="Neues Feature">add</i>
+ Neue HAFAS-Backends: BVG, KVB, mobiliteit, RMV, RSAG, STV, VMT,
+ VOS, VRN, ZVV.
+ </p>
+ <p>
+ <i class="material-icons left" aria-label="Bugfix">build</i>
+ HAFAS-Backends: verbesserte Unterstützung für Ringlinien.
+ </p>
+ <p>
+ <i class="material-icons left" aria-label="Bugfix">build</i>
+ Verbesserte Unterstützung für uneindeutige Stationsnamen. Berlin
+ Hbf ist beispielsweise intern in „Berlin Hbf“ (Gleise 1 bis 8),
+ „Berlin Hbf“ (Gleise 11 bis 14) und „Berlin Hbf (S-Bahn)“ (Gleise
+ 15 und 16) getrennt. Teile von travelynx gingen in der
+ Vergangenheit fälschlich davon aus, dass es keine Stationen mit
+ identischen Namen, aber unterschiedlichen internen IDs gebe.
+ Dies hat u.a. bei Fahrten von/nach Berlin Hbf und innerhalb von
+ Karlsruhe zu interessanten Bugs geführt.
+ </p>
+ <p>
+ <i class="material-icons left" aria-label="Bug">warning</i>
+ Reisen, die in travelynx 2.8.0 bis 2.8.30 mittels IRIS-Backend
+ geloggt wurden, können in Einzelfällen fehlerhafte Stationsangaben
+ enthalten. Der Bug betrifft alle Fahrten von/zu Stationen, die in
+ der von travelynx genutzten Stationsdatenbank zum Checkin-Zeitpunkt
+ nicht bekannt waren. Eine nachträgliche Korrektur dieser Fahrten
+ folgt ggf. in einem späteren Release.
+ </p>
+ <p>
+ <i class="material-icons left" aria-label="Administration">announcement</i>
+ travelynx verlinkt bei Registrierung und Anmeldung nun
+ instanzspezifische <a href="/tos">Nutzungsbedingungen</a>. Admins
+ sollten beim Update auf diese Version
+ templates/terms-of-service.html.ep anlegen. Die Nutzungsbedingungen
+ können beispielsweise Richtlinien für die Freitexte in
+ Checkin-Kommentaren und auf der Profilseite vorgeben oder
+ allgemeine Hinweise und Bedingungen zur Verfügbarkeit der
+ jeweiligen Instanz beinhalten.
+ </p>
+ </div>
+</div>
+
+<div class="row">
+ <div class="col s12 m1 l1">
+ 2.8
+ </div>
+ <div class="col s12 m11 l11">
+ <p>
+ <i class="material-icons left" aria-label="Neues Feature">add</i>
+ Unterstützung von HAFAS-Backends abseits der Deutschen Bahn. Somit
+ sind zumeist akkurate Echtzeit- und Routendaten für Checkins u.a.
+ in Aachen, Berlin/Brandenburg, Hessen, Sachsen-Anhalt,
+ Schleswig-Holstein, Österreich und der Schweiz verfügbar.
+ Das Backend muss vor dem Checkin explizit ausgewählt werden.
+ Eine Synchronisierung mit Traewelling wird nur für DB (IRIS-TTS) –
+ vormals „Schienenverkehr“ – und DB (HAFAS) – vormals „Nahverkehr“ –
+ durchgeführt. Manuell eingetragene Fahrten sind vorerst ebenfalls
+ auf DB (HAFAS) beschränkt.
+ </p>
+ <p>
+ <i class="material-icons left" aria-label="Ankündigung">announcement</i>
+ Stationssuche und Verbindungsvorschläge berücksichtigen nur noch
+ das ausgewählte Backend. Die bisherige Verknüpfung von DB (IRIS-TTS)
+ und DB (HAFAS) entfällt.
+ </p>
+ </div>
+</div>
+
+<div class="row">
+ <div class="col s12 m1 l1">
+ 2.7
+ </div>
+ <div class="col s12 m11 l11">
+ <p>
+ <i class="material-icons left" aria-label="Verbesserung">star</i>
+ Checkins via Nahverkehr (HAFAS) speichern nun Polylines (Routen für
+ die Fahrtenkarte) und Wagenreihungen, sofern verfügbar. Sie sind
+ damit fast identisch zu Checkins via Schienenverkehr (IRIS); es
+ fehlen im Wesentlichen lediglich die mit Zeitstempel versehenen
+ Verspätungs- und Störungsmeldungen.
+ <p/>
+ <p>
+ <i class="material-icons left" aria-label="Bugfix">build</i>
+ Verbesserte (aber weiterhin nicht perfekte) Unterstützung für
+ Ringlinien.
+ </p>
+ <p>
+ <i class="material-icons left" aria-label="Bugfix">build</i>
+ Korrekte Verlinkung von HAFAS-basierten Abfahrtstafeln bei den
+ Unterwegshalten des aktuellen Checkins im Nahverkehrsmodus. Die
+ Konfigurationsmöglichkeit zur Auswahl zwischen bahn.expert und DBF
+ unter Account → Externe Dienste besteht wegen der Abhängigkeit des
+ Diensts vom genutzten Backend und zwecks besserer Wartbarkeit von
+ travelynx nun nicht mehr.
+ </p>
+ </div>
+</div>
+
+<div class="row">
+ <div class="col s12 m1 l1">
2.6
</div>
<div class="col s12 m11 l11">
diff --git a/templates/departures.html.ep b/templates/departures.html.ep
index 6aac482..6df48a8 100644
--- a/templates/departures.html.ep
+++ b/templates/departures.html.ep
@@ -1,26 +1,33 @@
<div class="row">
- <div class="col s12">
- <h2>
- <i class="material-icons " aria-hidden="true"><%= param('hafas') ? 'directions' : 'train' %></i>
+ <div class="col s8">
+ <strong style="font-size: 120%;">
<%= $station %>
- </h2>
+ </strong>
% for my $related_station (sort { $a->{name} cmp $b->{name} } @{$related_stations}) {
+ <%= $related_station->{name} %> <br/>
% }
</div>
-</div>
-% if ($api_link) {
-<div class="row">
- <div class="col s12 center-align">
- % if (param('hafas')) {
- <a href="<%= $api_link %>" class="btn-small"><i class="material-icons left" aria-hidden="true">train</i>zum Schienenverkehr</a>
- % }
- % else {
- <a href="<%= $api_link %>" class="btn-small"><i class="material-icons left" aria-hidden="true">directions</i>zum Nahverkehr</a>
- % }
+ <div class="col s4 center-align">
+ % my $self_link = url_for('sstation', station => $station // param('station'));
+ % if (param('dbris')) {
+ <a href="/account/select_backend?redirect_to=<%= $self_link %>" class="btn-small btn-flat"><i class="material-icons left" aria-hidden="true">directions</i><%= param('dbris') %></a>
+ % }
+ % elsif (param('hafas')) {
+ <a href="/account/select_backend?redirect_to=<%= $self_link %>" class="btn-small btn-flat"><i class="material-icons left" aria-hidden="true">directions</i><%= param('hafas') %></a>
+ % }
+ % elsif (param('motis')) {
+ <a href="/account/select_backend?redirect_to=<%= $self_link %>" class="btn-small btn-flat"><i class="material-icons left" aria-hidden="true">directions</i><%= param('motis') %></a>
+ % }
+ % else {
+ % if ($user->{backend_id}) {
+ <a href="/account/select_backend?redirect_to=<%= $self_link %>" class="btn-small btn-flat"><i class="material-icons left" aria-hidden="true">directions</i><%= $user->{backend_name} %></a>
+ % }
+ % else {
+ <a href="/account/select_backend?redirect_to=<%= $self_link %>" class="btn-small btn-flat"><i class="material-icons left" aria-hidden="true">train</i>IRIS</a>
+ % }
+ % }
</div>
</div>
-% }
% my $have_connections = 0;
% if ($user_status->{checked_in}) {
@@ -29,7 +36,13 @@
<div class="card">
<div class="card-content">
<span class="card-title">Aktuell eingecheckt</span>
- <p>In <%= $user_status->{train_type} %> <%= $user_status->{train_no} %>
+ <p>In
+ % if ( not $user_status->{is_motis} ) {
+ <%= $user_status->{train_type} %>
+ % }
+
+ <%= $user_status->{train_line} // $user_status->{train_no} %>
+
% if ( $user_status->{arr_name}) {
von <%= $user_status->{dep_name} %> nach <%= $user_status->{arr_name} %>
% }
@@ -40,10 +53,10 @@
</div>
<div class="card-action">
% if ($can_check_out) {
- <a class="action-undo" data-id="in_transit" data-checkints="<%= $user_status->{timestamp}->epoch %>" style="margin-right: 0;">
+ <a class="action-undo" data-hafas="<%= param('hafas') // q{} %>" data-id="in_transit" data-checkints="<%= $user_status->{timestamp}->epoch %>" style="margin-right: 0;">
<i class="material-icons left" aria-hidden="true">undo</i> Rückgängig
</a>
- <a class="action-checkout right" data-station="<%= $eva %>" data-force="1">
+ <a class="action-checkout right" data-hafas="<%= param('hafas') // q{} %>" data-station="<%= $eva %>" data-force="1">
Hier auschecken
</a>
% }
@@ -51,7 +64,7 @@
<a class="action-undo" data-id="in_transit" data-checkints="<%= $user_status->{timestamp}->epoch %>" style="margin-right: 0;">
<i class="material-icons left" aria-hidden="true">undo</i> Rückgängig
</a>
- <a class="action-checkout right" data-station="<%= $eva %>" data-force="1">
+ <a class="action-checkout right" data-hafas="<%= param('hafas') // q{} %>" data-station="<%= $eva %>" data-force="1">
<i class="material-icons left" aria-hidden="true">gps_off</i>
Hier auschecken
</a>
@@ -92,8 +105,8 @@
<div class="row">
<div class="col s4 center-align">
- % if ($hafas) {
- <a class="btn-small" href="<%= url_for('sstation', station => param('station'))->query({hafas => 1, timestamp => $datetime->clone->subtract(hours => 1)->epoch}) %>"><i class="material-icons left" aria-hidden="true">chevron_left</i><span class="hide-on-small-only">früher</span></a>
+ % if ($dbris or $efa or $hafas or $motis) {
+ <a class="btn-small" href="<%= url_for('sstation', station => param('station'))->query({dbris => $dbris, hafas => $hafas, timestamp => $datetime->clone->subtract(hours => 1)->epoch}) %>"><i class="material-icons left" aria-hidden="true">chevron_left</i><span class="hide-on-small-only">früher</span></a>
% }
</div>
<div class="col s4 center-align">
@@ -102,8 +115,8 @@
% }
</div>
<div class="col s4 center-align">
- % if ($hafas) {
- <a class="btn-small" href="<%= url_for('sstation', station => param('station'))->query({hafas => 1, timestamp => $datetime->clone->add(hours => 1)->epoch}) %>"><span class="hide-on-small-only">später</span><i class="material-icons right" aria-hidden="true">chevron_right</i></a>
+ % if ($dbris or $efa or $hafas or $motis) {
+ <a class="btn-small" href="<%= url_for('sstation', station => param('station'))->query({dbris => $dbris, hafas => $hafas, timestamp => $datetime->clone->add(hours => 1)->epoch}) %>"><span class="hide-on-small-only">später</span><i class="material-icons right" aria-hidden="true">chevron_right</i></a>
% }
</div>
</div>
@@ -133,13 +146,28 @@
Fahrt auswählen zum Einchecken.
% }
% else {
- Keine Abfahrten gefunden. Ein Checkin ist frühestens 30 Minuten vor
- und maximal 120 Minuten nach Abfahrt möglich.
+ % if ($dbris or $hafas) {
+ Keine Abfahrten im ausgewählten Zeitfenster
+ (<%= $datetime->strftime('%d.%m.%Y %H:%M') %> ± 30min).
+ % }
+ % else {
+ Keine Abfahrten gefunden. Ein Checkin ist frühestens 30 Minuten vor
+ und maximal 120 Minuten nach Abfahrt möglich.
+ % }
% }
</p>
% if (not $user_status->{checked_in} or ($can_check_out and $user_status->{arr_eva} and $user_status->{arrival_countdown} <= 0)) {
- % if ($hafas) {
- %= include '_departures_hafas', results => $results;
+ % if ($dbris) {
+ %= include '_departures_dbris', results => $results, dbris => $dbris;
+ % }
+ % elsif ($efa) {
+ %= include '_departures_efa', results => $results, efa => $efa;
+ % }
+ % elsif ($hafas) {
+ %= include '_departures_hafas', results => $results, hafas => $hafas;
+ % }
+ % elsif ($motis) {
+ %= include '_departures_motis', results => $results, motis => $motis;
% }
% else {
%= include '_departures_iris', results => $results;
@@ -147,3 +175,26 @@
% }
</div>
</div>
+
+<div class="row">
+ <div class="col s4 center-align">
+ % if ($dbris or $efa or $hafas or $motis) {
+ <a class="btn-small" href="<%= url_for('sstation', station => param('station'))->query({dbris => $dbris, hafas => $hafas, timestamp => $datetime->clone->subtract(hours => 1)->epoch}) %>"><i class="material-icons left" aria-hidden="true">chevron_left</i><span class="hide-on-small-only">früher</span></a>
+ % }
+ </div>
+ <div class="col s4 center-align">
+ </div>
+ <div class="col s4 center-align">
+ % if ($dbris or $efa or $hafas or $motis) {
+ <a class="btn-small" href="<%= url_for('sstation', station => param('station'))->query({dbris => $dbris, hafas => $hafas, timestamp => $datetime->clone->add(hours => 1)->epoch}) %>"><span class="hide-on-small-only">später</span><i class="material-icons right" aria-hidden="true">chevron_right</i></a>
+ % }
+ </div>
+</div>
+
+% if (not $user_status->{checked_in}) {
+ <div class="row">
+ <div class="col s12 center-align">
+ <a class="btn-small" href="<%= url_for('checkinadd')->query({dbris => $dbris, efa => $efa, hafas => $hafas, motis => $motis, dep_station => $station}) %>"><i class="material-icons left" aria-hidden="true">add</i><span>manuell einchecken</span></a>
+ </div>
+ </div>
+% }
diff --git a/templates/disambiguation.html.ep b/templates/disambiguation.html.ep
index 270aa99..af7d1dd 100644
--- a/templates/disambiguation.html.ep
+++ b/templates/disambiguation.html.ep
@@ -13,7 +13,7 @@
<div class="col s12">
<ul class="suggestions">
% for my $suggestion (@{$suggestions // []}) {
- <li><a href="<%= url_for('station' => $suggestion->{eva}) . (param('hafas') ? '?hafas=1' : q{}) %>"><%= $suggestion->{name} %></a></li>
+ <li><a href="<%= url_for('station' => $suggestion->{eva}) . (param('hafas') ? '?hafas=' . param('hafas') : q{}) %>"><%= $suggestion->{name} %></a></li>
% }
</ul>
</div>
diff --git a/templates/exception.html.ep b/templates/exception.html.ep
index ec01ad2..9b8697c 100644
--- a/templates/exception.html.ep
+++ b/templates/exception.html.ep
@@ -20,8 +20,15 @@
Timestamp:
%= DateTime->now(time_zone => 'Europe/Berlin')->strftime("%d/%b/%Y:%H:%M:%S %z")
<br/><br/>
- Message:
- %= ref($exception) ? (split(qr{\n}, $exception->message))[0] : $exception
+ % if (ref($exception)) {
+ Trace:<br/>
+ % for my $line (split(qr{\n}, $exception->message)) {
+ <%= $line %><br/>
+ % }
+ % }
+ % else {
+ Message: <%= $exception %>
+ % }
</p>
</div>
</div>
diff --git a/templates/gateway_timeout.html.ep b/templates/gateway_timeout.html.ep
new file mode 100644
index 0000000..9cf8690
--- /dev/null
+++ b/templates/gateway_timeout.html.ep
@@ -0,0 +1,27 @@
+<div class="row">
+ <div class="col s12">
+ <div class="card caution-color">
+ <div class="card-content white-text">
+ <span class="card-title">504 Gateway Timeout</span>
+ <p>
+ Das von travelynx genutzte Backend hat nicht rechtzeitig reagiert.
+ travelynx hat keine Möglichkeiten, diese Situation zu beheben.
+ % if (stash('select_new_backend')) {
+ Versuche es in ein paar Sekunden bis Minuten noch einmal oder <a href="/account/select_backend">wähle ein anderes Backend</a>.
+ % }
+ % else {
+ Versuche es in ein paar Sekunden bis Minuten noch einmal.
+ % }
+ </p>
+ </div>
+ </div>
+ </div>
+</div>
+<div class="row">
+ <div class="col s12">
+ <p>Details:</p>
+ <p style="font-family: monospace;">
+ %= $message
+ </p>
+ </div>
+</div>
diff --git a/templates/history_by_month.html.ep b/templates/history_by_month.html.ep
index 9ad7031..c3b1004 100644
--- a/templates/history_by_month.html.ep
+++ b/templates/history_by_month.html.ep
@@ -4,6 +4,12 @@
%= include '_history_stats', stats => stash('statistics');
% }
+<div class="row">
+ <div class="col s12 m12 l12 center-align">
+ <a href="/history/map?filter_from=<%= $filter_from->strftime('%d.%m.%Y') %>&amp;filter_to=<%= $filter_to->strftime('%d.%m.%Y') %>" class="waves-effect waves-light btn"><i class="material-icons left" aria-hidden="true">map</i> Karte</a>
+ </div>
+</div>
+
% if (stash('journeys')) {
%= include '_history_trains', date_format => '%d.%m.', journeys => stash('journeys');
% }
diff --git a/templates/history_map.html.ep b/templates/history_map.html.ep
index 57ba81f..c2ff9ed 100644
--- a/templates/history_map.html.ep
+++ b/templates/history_map.html.ep
@@ -116,8 +116,8 @@
<div class="row">
<div class="col s12">
<p>
- Die eingezeichneten Routen stammen aus dem HAFAS und sind im Detail
- oft fehlerbehaftet.
+ Die eingezeichneten Routen stammen aus dem Backend, mit dem die Fahrt aufgezeichnet wurde.
+ Die Datenqualität variiert.
</p>
</div>
</div>
diff --git a/templates/journey.html.ep b/templates/journey.html.ep
index f5eebfc..31f9e94 100644
--- a/templates/journey.html.ep
+++ b/templates/journey.html.ep
@@ -15,29 +15,17 @@
<div class="col s12">
<p>
% if (my $name = stash('username')) {
- <b><a href="/p/<%= $name %>"><%= $name %></a></b>s
+ Checkin von <b><a href="/p/<%= $name %>"><%= $name %></a></b>
% }
- % if ($journey->{cancelled}) {
- Ausgefallene Fahrt
+ % elsif ($journey->{cancelled}) {
+ <b>Ausgefallene Fahrt</b> vom <%= $journey->{checkin}->strftime('%d.%m.%Y um %H:%M Uhr') %>
% }
% else {
- Fahrt
+ Checkin vom <%= $journey->{checkin}->strftime('%d.%m.%Y um %H:%M Uhr') %>
% }
% if ($journey->{edited} & 0x0020) {
% }
- von
- <b><%= $journey->{from_name} %></b>
- % if ($journey->{edited} & 0x0004) {
- ∗
- % }
- nach
- <b><%= $journey->{to_name} %></b>
- % if ($journey->{edited} & 0x0400) {
- ∗
- % }
- am
- <b><%= $journey->{sched_departure}->strftime('%d.%m.%Y') %></b>
% if (my $v = stash('journey_visibility')) {
% if (stash('username')) {
<i class="material-icons right"><%= visibility_icon($v) %></i>
@@ -78,19 +66,48 @@
</td>
</tr>
<tr>
+ <th scope="row">Von</th>
+ <td>
+ %= $journey->{from_name}
+ % if ($journey->{from_platform} and $journey->{to_platform}) {
+ (<%= $journey->{from_platform} %>)
+ % }
+ % if ($journey->{edited} & 0x0004) {
+ ∗
+ % }
+ </td>
+ </tr>
+ <tr>
+ <th scope="row">Nach</th>
+ <td>
+ <%= $journey->{to_name} %>
+ % if ($journey->{from_platform} and $journey->{to_platform}) {
+ (<%= $journey->{to_platform} %>)
+ % }
+ % if ($journey->{edited} & 0x0400) {
+ ∗
+ % }
+ </td>
+ </tr>
+ <tr>
<th scope="row">Abfahrt</th>
<td>
% if ($journey->{cancelled}) {
<i class="material-icons">cancel</i>
- (Plan: <%= $journey->{sched_departure}->strftime('%H:%M'); %>)
+ (Plan: <%= $journey->{sched_departure}->strftime('%d.%m.%Y %H:%M'); %>)
% }
- % elsif ($journey->{rt_departure} != $journey->{sched_departure}) {
- %= $journey->{rt_departure}->strftime('%H:%M');
- (<%= sprintf('%+d', ($journey->{rt_departure}->epoch - $journey->{sched_departure}->epoch) / 60) %>,
- Plan: <%= $journey->{sched_departure}->strftime('%H:%M'); %>)
+ % elsif ($journey->{delay_dep}) {
+ %= ($journey->{rt_departure}->epoch % 60) ? $journey->{rt_departure}->strftime('%d.%m.%Y %H:%M:%S') : $journey->{rt_departure}->strftime('%d.%m.%Y %H:%M')
+ % if (int(abs($journey->{delay_dep}) / 60)) {
+ (<%= sprintf('%+d', ($journey->{rt_departure}->epoch - $journey->{sched_departure}->epoch) / 60) %>, Plan:
+ % }
+ % else {
+ (Plan:
+ % }
+ %= ($journey->{sched_departure}->epoch % 60) ? $journey->{sched_departure}->strftime('%H:%M:%S)') : $journey->{sched_departure}->strftime('%H:%M)')
% }
% else {
- %= $journey->{sched_departure}->strftime('%H:%M');
+ %= ($journey->{sched_departure}->epoch % 60) ? $journey->{sched_departure}->strftime('%d.%m.%Y %H:%M:%S') : $journey->{sched_departure}->strftime('%d.%m.%Y %H:%M');
% }
% if ($journey->{edited} & 0x0003) {
@@ -103,19 +120,24 @@
% if ($journey->{cancelled}) {
<i class="material-icons">cancel</i>
% if ($journey->{sched_arrival}->epoch != 0) {
- (Plan: <%= $journey->{sched_arrival}->strftime('%H:%M'); %>)
+ (Plan: <%= $journey->{sched_arrival}->strftime('%d.%m.%Y %H:%M'); %>)
% }
% }
% elsif ($journey->{rt_arrival}->epoch == 0 and $journey->{sched_arrival}->epoch == 0) {
<i class="material-icons">timer_off</i>
% }
- % elsif ($journey->{rt_arrival} != $journey->{sched_arrival}) {
- %= $journey->{rt_arrival}->strftime('%H:%M');
- (<%= sprintf('%+d', ($journey->{rt_arrival}->epoch - $journey->{sched_arrival}->epoch) / 60) %>,
- Plan: <%= $journey->{sched_arrival}->strftime('%H:%M'); %>)
+ % elsif ($journey->{delay_arr}) {
+ %= ($journey->{rt_arrival}->epoch % 60) ? $journey->{rt_arrival}->strftime('%d.%m.%Y %H:%M:%S') : $journey->{rt_arrival}->strftime('%d.%m.%Y %H:%M')
+ % if (int(abs($journey->{delay_arr}) / 60)) {
+ (<%= sprintf('%+d', ($journey->{rt_arrival}->epoch - $journey->{sched_arrival}->epoch) / 60) %>, Plan:
+ % }
+ % else {
+ (Plan:
+ % }
+ %= ($journey->{sched_arrival}->epoch % 60) ? $journey->{sched_arrival}->strftime('%H:%M:%S)') : $journey->{sched_arrival}->strftime('%H:%M)')
% }
% else {
- %= $journey->{sched_arrival}->strftime('%H:%M');
+ %= ($journey->{sched_arrival}->epoch % 60) ? $journey->{sched_arrival}->strftime('%d.%m.%Y %H:%M:%S') : $journey->{sched_arrival}->strftime('%d.%m.%Y %H:%M');
% }
% if ($journey->{edited} & 0x0300) {
@@ -133,6 +155,9 @@
ca. <%= sprintf_km($journey->{km_route}) %>
(Luftlinie: <%= sprintf_km($journey->{km_beeline}) %>)
% }
+ % elsif ($journey->{km_beeline} > 0.1) {
+ (Luftlinie: <%= sprintf_km($journey->{km_beeline}) %>)
+ % }
% else {
?
% }
@@ -155,11 +180,22 @@
% }
% }
+ % elsif ($journey->{km_beeline} > 0.1 and $journey->{kmh_beeline} > 0.01) {
+ (<%= sprintf('%.f', $journey->{kmh_beeline}) %> km/h)
+ % }
% else {
?
% }
</td>
</tr>
+ % if ($journey->{user_data}{operator} or scalar @{ $journey->{user_data}{operators} // [] }) {
+ <tr>
+ <th scope="row">Betrieb</th>
+ <td>
+ %= $journey->{user_data}{operator} // join(q{, }, @{$journey->{user_data}{operators}})
+ </td>
+ </tr>
+ % }
% if ($journey->{messages} and @{$journey->{messages}}) {
<tr>
<th scope="row">Meldungen</th>
@@ -171,6 +207,16 @@
</td>
</tr>
% }
+ % if ($journey->{user_data}{him_msg} and @{$journey->{user_data}{him_msg}}) {
+ <tr>
+ <th scope="row">Meldungen</th>
+ <td>
+ % for my $message (@{$journey->{user_data}{him_msg} // []}) {
+ <i class="material-icons tiny"><%= ($message->{prio} and $message->{prio} eq 'HOCH') ? 'warning' : 'info' %></i> <%= $message->{header} %> <%= $message->{lead} %><br/>
+ % }
+ </td>
+ </tr>
+ % }
% if ($journey->{user_data} and $journey->{user_data}{comment}) {
<tr>
<th scope="row">Kommentar</th>
@@ -212,10 +258,10 @@
% my $within = 0;
% my $at_startstop = 0;
% for my $station (@{$journey->{route}}) {
- % if ($station->[0] eq $journey->{from_name}) {
+ % if (($station->[1] and $station->[1] == $journey->{from_eva}) or $station->[0] eq $journey->{from_name}) {
% $within = 1; $at_startstop = 1;
% }
- % elsif ($station->[0] eq $journey->{to_name}) {
+ % elsif (($station->[1] and $station->[1] == $journey->{to_eva}) or $station->[0] eq $journey->{to_name}) {
% $within = 0; $at_startstop = 1;
% }
% else {
@@ -248,7 +294,7 @@
% }
</span>
% }
- % if ($station->[0] eq $journey->{from_name}) {
+ % if (($station->[1] and $station->[1] == $journey->{from_eva}) or $station->[0] eq $journey->{from_name}) {
% $before = 0;
% }
<br/>
@@ -261,6 +307,13 @@
% if (stash('polyline_groups')) {
%= include '_map', station_coordinates => stash('station_coordinates'), polyline_groups => stash('polyline_groups')
% }
+ <div class="row">
+ <div class="col s12 grey-text">
+ <i class="material-icons tiny" aria-hidden="true"><%= $journey->{is_hafas} ? 'directions' : 'train' %></i>
+ %= $journey->{backend_name} || 'IRIS'
+ #<%= $journey->{id} %>
+ </div>
+ </div>
% if (not stash('readonly')) {
% if (stash('with_share')) {
<div class="row">
diff --git a/templates/landingpage.html.ep b/templates/landingpage.html.ep
index 45bfb21..5ca0e9e 100644
--- a/templates/landingpage.html.ep
+++ b/templates/landingpage.html.ep
@@ -1,5 +1,6 @@
% if (is_user_authenticated()) {
% my $status = stash('user_status');
+ % my $user = stash('user');
% if (stash('error')) {
<div class="row">
<div class="col s12">
@@ -51,40 +52,63 @@
% if ( @{stash('timeline') // [] } ) {
%= include '_timeline_link', timeline => stash('timeline')
% }
- <div class="card">
- <div class="card-content">
- <span class="card-title">Hallo, <%= current_user->{name} %>!</span>
- <p>Du bist gerade nicht eingecheckt.</p>
- <div class="geolocation" data-recent="<%= join('|', map { $_->{eva} . ';' . $_->{name} . ';' . $_->{hafas} } @{stash('recent_targets') // []} ) %>">
- <button class="btn waves-effect waves-light btn-flat">Stationen in der Umgebung abfragen</button>
- </div>
- %= form_for 'list_departures' => begin
+ %= form_for 'list_departures' => begin
+ <div class="card">
+ <div class="card-content">
+ <span class="card-title">Hallo, <%= $user->{name} %>!</span>
+ <p>Du bist gerade nicht eingecheckt.</p>
+ <div class="geolocation" data-recent="<%= join('|', map { $_->{external_id_or_eva} . ';' . $_->{name} . ';' . $_->{dbris} . ';' . $_->{efa} . ';' . $_->{hafas} . ';' . $_->{motis} } @{stash('recent_targets') // []} ) %>" data-backend="<%= $user->{backend_id} %>">
+ <a class="btn waves-effect waves-light btn-flat request">Stationen in der Umgebung abfragen</a>
+ </div>
+ %= hidden_field backend_dbris => $user->{backend_dbris}
<div class="input-field">
%= text_field 'station', id => 'station', class => 'autocomplete contrast-color-text', autocomplete => 'off', required => undef
<label for="station">Manuelle Eingabe</label>
</div>
- <div class="center-align">
- <button class="btn waves-effect waves-light btn-flat" type="submit" name="action" value="departures">
- <i class="material-icons left" aria-hidden="true">send</i>
- Abfahrten
- </button>
- </div>
- %= end
+ </div>
+ <div class="card-action">
+ <a href="/account/select_backend?redirect_to=/" class="btn btn-flat"><i class="material-icons left" aria-hidden="true"><%= $user->{backend_hafas} ? 'directions' : 'train' %></i><%= $user->{backend_name} // 'IRIS' %></a>
+ <button class="btn right waves-effect waves-light btn-flat" type="submit" name="action" value="departures">
+ <i class="material-icons left" aria-hidden="true">send</i>
+ Abfahrten
+ </button>
+ </div>
</div>
- </div>
+ %= end
% }
</div>
</div>
+ % if (not $user->{backend_name}) {
+ <div class="row">
+ <div class="col s12">
+ <div class="card purple white-text">
+ <div class="card-content">
+ <span class="card-title">Legacy-Backend ausgewählt</span>
+ <p>
+ Das aktuell aktive IRIS-Backend wird nicht mehr weiterentwickelt und voraussichtlich bald von der Deutschen Bahn abgeschaltet.
+ Schon jetzt ist die Datenqualität wegen zunehmend schlechter Datenaufbereitungsmöglichkeiten oft unzureichend.
+ Das bahn.de-Backend ist in fast jeder Hinsicht besser geeignet; lediglich bei Verspätungs- und Servicemeldungen ist es geringfügig weniger detailliert und Checkin-Vorschläge werden derzeit nicht unterstützt.
+ </p>
+ </div>
+ <div class="card-action">
+ <a class="btn btn-flat" href="/account/select_backend?redirect_to=/">Backend wechseln</a>
+ </div>
+ </div>
+ </div>
+ </div>
+ % }
<h2 style="margin-left: 0.75rem;">Letzte Fahrten</h2>
- %= include '_history_trains', date_format => '%d.%m.%Y', journeys => [journeys->get(uid => current_user->{id}, limit => 5, with_datetime => 1)];
+ %= include '_history_trains', date_format => '%d.%m.%Y', journeys => [journeys->get(uid => $user->{id}, limit => 5, with_datetime => 1)];
% }
% else {
<div class="row">
<div class="col s12">
<p>
- Travelynx erlaubt das Einchecken in Züge im Netz der Deutschen
- Bahn. So können die eigenen Fahrten später inklusive Echtzeitdaten
- und eingetragenen Servicemeldungen nachvollzogen und brennende
+ Travelynx erlaubt das Einchecken in Verkehrsmittel (Busse,
+ Bahnen, Züge) unter anderem in Deutschland, Österreich, der
+ Schweiz, Luxemburg, Irland, Dänemark und Teilen der USA. So
+ können die eigenen Fahrten später inklusive Echtzeitdaten und
+ eingetragenen Servicemeldungen nachvollzogen und brennende
Fragen wie „Wie viele Stunden war ich letzten Monat unterwegs?“
beantwortet werden.
</p>
@@ -102,7 +126,7 @@
<li>Statistiken über Reisezeiten und Verspätungen</li>
<li>Unterstützung beim Ausfüllen von Fahrgastrechteformularen</li>
<li>Optional: Öffentlicher Reisestatus und öffentliche Angaben zu vergangenen Fahrten</li>
- <li>Optional: Verknüpfung mit Träwelling</li>
+ <!-- <li>Optional: Verknüpfung mit Träwelling</li> -->
</ul>
</p>
<p>
diff --git a/templates/layouts/default.html.ep b/templates/layouts/default.html.ep
index fbb26ef..b275335 100644
--- a/templates/layouts/default.html.ep
+++ b/templates/layouts/default.html.ep
@@ -13,7 +13,7 @@
% while (my ($key, $value) = each %{stash('opengraph') // {}}) {
<meta property="og:<%= $key %>" content="<%= $value %>">
% }
- % my $av = 'v72'; # asset version
+ % my $av = 'v97'; # asset version
<link rel="icon" type="image/png" href="/static/<%= $av %>/icons/icon-16x16.png" sizes="16x16">
<link rel="icon" type="image/png" href="/static/<%= $av %>/icons/icon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="/static/<%= $av %>/icons/icon-96x96.png" sizes="96x96">
@@ -62,7 +62,7 @@
%= javascript "/static/${av}/js/geolocation${min}.js"
% }
% if (stash('with_autocomplete')) {
- %= javascript "/dyn/${av}/autocomplete.js", defer => undef
+ %= javascript "/dyn/${av}/autocomplete.js?backend_id=" . (stash('backend_id') // 1), defer => undef
% }
% if (stash('with_map')) {
%= javascript "/static/${av}/leaflet/leaflet.js"
diff --git a/templates/legend.html.ep b/templates/legend.html.ep
index 73fded9..3dc113a 100644
--- a/templates/legend.html.ep
+++ b/templates/legend.html.ep
@@ -15,11 +15,11 @@
</tr>
<tr>
<td><i class="material-icons">train</i></td>
- <td>Backend: DB IRIS. Bevorzugte Datenquelle für (mindestens teilweise) innerdeutsche Zugfahrten.</td>
+ <td>Backend: Deutsche Bahn (bahn.de oder IRIS-TTS).</td>
</tr>
<tr>
<td><i class="material-icons">directions</i></td>
- <td>Backend: DB HAFAS. Bevorzugte Datenquelle für Nahverkehr und vollständig außerdeutsche Zugfahrten. Weniger detailliert als IRIS.</td>
+ <td>Backend: HAFAS.</td>
</tr>
</tbody>
</table>
diff --git a/templates/login.html.ep b/templates/login.html.ep
index ce89813..3a9cc1f 100644
--- a/templates/login.html.ep
+++ b/templates/login.html.ep
@@ -74,6 +74,11 @@
</div>
</div>
<div class="row">
+ <div class="col s12 m12 l12">
+ Mit der Anmeldung stimmst du den <a href="/tos">Nutzungsbedingungen</a> zu.
+ </div>
+ </div>
+ <div class="row">
<div class="col s3 m3 l3">
</div>
<div class="col s6 m6 l6 center-align">
diff --git a/templates/passengerrights.html.ep b/templates/passengerrights.html.ep
index 3d5d21d..c189657 100644
--- a/templates/passengerrights.html.ep
+++ b/templates/passengerrights.html.ep
@@ -2,10 +2,10 @@
<div class="row">
<div class="col s12">
<p>
- Gemäß der Fahrgastrechte im Eisenbahnverkehr besteht ab 60 Minuten
- Verspätung am Ziel ein Entschädigungsanspruch gegenüber dem
- Eisenbahnverkehrsunternehmen. Dieser kann mit dem
- Fahrgastrechteformular geltend gemacht werden.
+ Ab 60 Minuten Verspätung am Ziel besteht in einigen Fällen ein
+ Entschädigungsanspruch gegenüber dem Eisenbahnverkehrsunternehmen.
+ Dieser kann mit dem Fahrgastrechteformular oder online geltend
+ gemacht werden.
</p>
<p>
Die folgenden Zugfahrten sind wahrscheinliche Kandidaten dafür.
@@ -73,3 +73,64 @@
</table>
</div>
</div>
+
+<div class="row">
+ <div class="col s12">
+ <p>
+ Bei Abo-Tickets besteht teilweise die Möglichkeit, bereits ab 20
+ Minuten Verspätung Fahrten gesammelt zu Entschädigungszwecken
+ einzureichen. Die folgenden Zugfahrten sind Kandidaten dafür.
+ Fahrten mit einer Verspätung von 60 Minuten oder mehr werden hier
+ nicht aufgeführt.
+ </p>
+ </div>
+</div>
+
+<div class="row">
+ <div class="col s12">
+ <table class="striped">
+ <thead>
+ <tr>
+ <th>Datum</th>
+ <th>Zug</th>
+ <th>Verspätung</th>
+ </tr>
+ </thead>
+ <tbody>
+ % for my $journey (@{$abo_journeys}) {
+ % my $detail_link = '/journey/' . $journey->{id};
+ <tr>
+ <td><%= $journey->{sched_departure}->strftime('%d.%m.%Y') %></td>
+ <td><a href="<%= $detail_link %>">
+ <%= $journey->{type} %> <%= $journey->{line} // $journey->{no} %>
+ → <%= $journey->{to_name} %>
+ % if ($journey->{connection}) {
+ % $detail_link = '/journey/' . $journey->{connection}{id};
+ </a><br/><a href="<%= $detail_link %>">
+ <%= $journey->{connection}{type} %> <%= $journey->{connection}{line} // $journey->{connection}{no} %>
+ → <%= $journey->{connection}{to_name} %>
+ % }
+ </a></td>
+ <td>
+ % if ($journey->{cancelled}) {
+ % if ($journey->{has_substitute}) {
+ Ausfall, Ersatzverbindung
+ %= sprintf('%+d', $journey->{substitute_delay})
+ % }
+ % else {
+ Ausfall ohne Ersatzverbindung
+ % }
+ % }
+ % elsif ($journey->{connection}) {
+ %= sprintf('%+d, ggf. Anschluss verpasst', $journey->{delay})
+ % }
+ % else {
+ %= sprintf('%+d', $journey->{delay})
+ % }
+ </td>
+ </tr>
+ % }
+ </tbody>
+ </table>
+ </div>
+</div>
diff --git a/templates/profile.html.ep b/templates/profile.html.ep
index 6f78ea0..a2c965c 100644
--- a/templates/profile.html.ep
+++ b/templates/profile.html.ep
@@ -79,7 +79,7 @@
</div>
<div class="row">
<div class="col s12 publicstatuscol" data-user="<%= $name %>" data-profile="1">
- %= include '_public_status_card', name => $name, privacy => $privacy, journey => $journey, from_profile => 1
+ %= include '_public_status_card', name => $name, privacy => $privacy, journey => $journey, from_profile => 1, station_coordinates => stash('station_coordinates'), polyline_groups => stash('polyline_groups')
</div>
</div>
% if ($journeys and @{$journeys}) {
diff --git a/templates/register.html.ep b/templates/register.html.ep
index ee344f9..f9a486a 100644
--- a/templates/register.html.ep
+++ b/templates/register.html.ep
@@ -27,6 +27,11 @@
</div>
</div>
<div class="row">
+ <div class="col s12 m12 l12">
+ Mit deiner Registrierung stimmst du den <a href="/tos">Nutzungsbedingungen</a> zu.
+ </div>
+ </div>
+ <div class="row">
<div class="col s3 m3 l3">
</div>
<div class="col s6 m6 l6 center-align">
diff --git a/templates/select_backend.html.ep b/templates/select_backend.html.ep
new file mode 100644
index 0000000..e3db44d
--- /dev/null
+++ b/templates/select_backend.html.ep
@@ -0,0 +1,85 @@
+<div class="row">
+ <div class="col s12">
+ <h2>Backend auswählen</h2>
+ <p style="text-align: justify;">
+ Das ausgewählte Backend bestimmt die Datenquelle für Fahrten in travelynx.
+ <a href="#help">Details</a>.
+ </p>
+ </div>
+</div>
+%= form_for '/account/select_backend' => (method => 'POST') => begin
+ % if (stash('redirect_to')) {
+ %= hidden_field 'redirect_to' => stash('redirect_to')
+ % }
+ % if (@{stash('suggestions') // []}) {
+ <div class="row">
+ <div class="col s12">
+ <h3>Vorschläge</h3>
+ <p style="text-align: justify;">
+ Anhand der Zielstation der letzten Fahrt und den
+ empfohlenen Nutzungsbereichen der verfügbaren Backends
+ (soweit bekannt).
+ </p>
+ </div>
+ </div>
+ % for my $backend (@{ stash('suggestions') // [] }) {
+ %= include '_backend_line', user => $user, backend => $backend
+ % }
+ % }
+ <div class="row">
+ <div class="col s12">
+ <h3>Empfohlen</h3>
+ <p style="text-align: justify;">
+ <strong>bahn.de</strong> für Regional- und Fernverkehr in Deutschland.
+ <strong>ÖBB</strong> für Nah-, Regional- und Fernverkehr in Österreich sowie Regional- und Fernverkehr in der EU.
+ </p>
+ </div>
+ </div>
+ % for my $backend (grep { $_->{recommended} } @{ stash('backends') // [] }) {
+ %= include '_backend_line', user => $user, backend => $backend
+ % }
+ <div class="row">
+ <div class="col s12">
+ <h3>Verbünde</h3>
+ <p style="text-align: justify;">
+ Diese Backends sind meist die beste Wahl für
+ Nahverkehrsfahrten in der jeweiligen Region.
+ Backends außerhalb Deutschlands sind im Regelfall auch
+ für dortigen Regional- und Fernverkehr die beste Wahl.
+ </p>
+ </div>
+ </div>
+ % for my $backend (grep { $_->{association} } @{ stash('backends') // [] }) {
+ %= include '_backend_line', user => $user, backend => $backend
+ % }
+ <div class="row">
+ <div class="col s12">
+ <h3>Experimentell oder abgekündigt</h3>
+ <p style="text-align: justify;">
+ Einchecken auf eigene Gefahr.
+ </p>
+ </div>
+ </div>
+ % for my $backend (grep { $_->{experimental} or $_->{legacy} } @{ stash('backends') // [] }) {
+ %= include '_backend_line', user => $user, backend => $backend
+ % }
+%= end
+<div class="row">
+ <div class="col s12">
+ <h2 id="help">Details</h2>
+ <p>
+ <strong>Deutsche Bahn: bahn.de</strong> ist eine gute Wahl für Fahrten des Nah-, Regional- und Fernverkehrs innerhalb Deutschlands.
+ Dieses Backend bietet überwiegend korrekte Echtzeit- und Kartendaten sowie Wagenreihungen.
+ Bei Nahverkehrsfahrten sind die Echtzeit- und Kartendaten meist nicht so gut wie bei den APIs des jeweiligen Verkehrsverbunds.
+ <p>
+ <strong>ÖBB</strong> liefern Kartendaten und Wagenreihungen für Fernverkehr in Deutschland und Umgebung, jedoch keine Meldungen. Echtzeitdaten sind teilweise verfügbar.
+ </p>
+ <p>
+ <strong>Deutsche Bahn: IRIS-TTS</strong> liefert Echtzeitdaten (nur am Start- und Zielbahnhof), Wagenreihungen und Verspätungsmeldungen für Regional- und Fernverkehr in Deutschland. Kartendaten und Angaben zu Unterwegshalten sind nur teilweise verfügbar. Dieses Backend wird nicht mehr weiterentwickelt. Die zugehörige API wird voraussichtlich im Laufe des Jahres 2025 abgeschaltet.
+ </p>
+ <p>
+ <strong>Transitous</strong> ist ein Aggregator für eine Vielzahl von Verkehrsunternehmen.
+ Die Datenqualität variiert.
+ </p>
+ </div>
+</div>
diff --git a/templates/traewelling.html.ep b/templates/traewelling.html.ep
index c1f2b7d..49b5c80 100644
--- a/templates/traewelling.html.ep
+++ b/templates/traewelling.html.ep
@@ -41,30 +41,6 @@
</div>
% }
-<div class="row">
- <div class="col s12">
- <div class="card purple">
- <div class="card-content white-text">
- <span class="card-title">Eingeschränkte Synchronisierung</span>
- <p>
- Träwelling und travelynx setzen unterschiedliche Schwerpunkte und haben unterschiedliche Features.
- Kombiniert mit der Vielzahl an möglichen Randfällen heißt das, dass die Synchronisierung nicht immer funktioniert.
- Diese Einschränkung ist bekannt und wird voraussichtlich bestehen bleiben.
- </p>
- <p>
- Bei hohen Verspätungen, Ausfällen und nachträglichen Checkin-Änderungen ist die Synchronisierung u.U. nicht möglich und muss von Hand vorgenommen werden.
- travelynx-Hooks werden bei via Träwelling vorgenommenen Checkins nicht ausgelöst.
- </p>
- </div>
- <div class="card-action">
- <a href="https://github.com/derf/travelynx/issues" class="waves-effect waves-light btn-flat white-text">
- <i class="material-icons left" aria-hidden="true">bug_report</i>Bug melden
- </a>
- </div>
- </div>
- </div>
-</div>
-
% if ($traewelling->{token} and ($traewelling->{expired} or $traewelling->{expiring})) {
<div class="row">
<div class="col s12">
@@ -157,26 +133,21 @@
<div>
<label>
%= check_box toot => 1
- <span>… Checkin auf Mastodon veröffentlichen</span>
- </label>
- </div>
- <div>
- <label>
- %= check_box tweet => 1
- <span>… Checkin auf Twitter veröffentlichen</span>
+ <span>… Checkin im Fediverse veröffentlichen</span>
</label>
</div>
<p>Die Synchronisierung erfolgt spätestens drei Minuten nach der
- Zielwahl. Beachte, dass die Synchronisierung travelynx
- → Träwelling unabhängig von der eingestellten Sichtbarkeit
- des Checkins erfolgt. travelynx reicht die Sichtbarkeit
- aber an Träwelling weiter.
- Träwelling-Checkins können von travelynx aktuell nicht
- rückgängig gemacht werden. Eine nachträgliche Änderung der
- Zielstation wird nicht übernommen. Mastodon und Twitter beziehen
- sich auf die in den <a
+ Zielwahl. Es werden ausschließlich Checkins mittels
+ DB (IRIS-TTS) und DB (HAFAS) synchornisiert. Beachte, dass
+ die Synchronisierung travelynx → Träwelling unabhängig von
+ der eingestellten Sichtbarkeit des Checkins erfolgt.
+ travelynx reicht die Sichtbarkeit aber an Träwelling
+ weiter. Träwelling-Checkins können von travelynx aktuell
+ nicht rückgängig gemacht werden. Eine nachträgliche
+ Änderung der Zielstation wird nicht übernommen. Fediverse
+ bezieht sich auf den in den <a
href="https://traewelling.de/settings">Träwelling-Einstellungen</a>
- verknüpften Accounts.</p>
+ verknüpften Account.</p>
</div>
<div class="input-field col s12">
<div>
diff --git a/templates/use_external_links.html.ep b/templates/use_external_links.html.ep
deleted file mode 100644
index d7bebd7..0000000
--- a/templates/use_external_links.html.ep
+++ /dev/null
@@ -1,82 +0,0 @@
-<h1>Externe Dienste</h1>
-<div class="row">
- <div class="col s12">
- <p>
- Travelynx kann an geeigneten Stellen Links zu externen Diensten
- (z.B. Abfahrstafeln oder Informationen zum gerade genutzten Zug)
- einbinden. Hier lässt sich konfigurieren, welcher Dienst für welche
- Art von Informationen genutzt wird.
- <p/>
- </div>
-</div>
-<h2>Abfahrtstafel</h2>
-%= form_for '/account/services' => (method => 'POST') => begin
- %= csrf_field
- <div class="row">
- <div class="col s12">
- Angaben zu anderen an einer Station verkehrenden Verkehrsmitteln
- </div>
- </div>
- <div class="row">
- <div class="input-field col s12">
- <div>
- <label>
- %= radio_button stationboard => '0'
- <span>Keine</span>
- </label>
- </div>
- </div>
- </div>
- <div class="row">
- <div class="input-field col s12">
- <div>
- <label>
- %= radio_button stationboard => '1'
- <span><a href="https://dbf.finalrewind.org/">DBF</a> (Schienenverkehr)</span>
- </label>
- </div>
- </div>
- </div>
- <div class="row">
- <div class="input-field col s12">
- <div>
- <label>
- %= radio_button stationboard => '2'
- <span><a href="https://bahn.expert/">bahn.expert</a> (Schienenverkehr)</span>
- </label>
- </div>
- </div>
- </div>
- <div class="row">
- <div class="input-field col s12">
- <div>
- <label>
- %= radio_button stationboard => '3'
- <span><a href="https://dbf.finalrewind.org/?hafas=1">DBF</a> (Nahverkehr)</span>
- </label>
- </div>
- </div>
- </div>
- <div class="row">
- <div class="input-field col s12">
- <div>
- <label>
- %= radio_button stationboard => '4'
- <span><a href="https://bahn.expert/regional">bahn.expert/regional</a> (Nahverkehr)</span>
- </label>
- </div>
- </div>
- </div>
- <div class="row">
- <div class="col s3 m3 l3">
- </div>
- <div class="col s6 m6 l6 center-align">
- <button class="btn waves-effect waves-light" type="submit" name="action" value="save">
- Speichern
- <i class="material-icons right">send</i>
- </button>
- </div>
- <div class="col s3 m3 l3">
- </div>
- </div>
-%= end
diff --git a/templates/use_history.html.ep b/templates/use_history.html.ep
index 9b76e98..f91ca16 100644
--- a/templates/use_history.html.ep
+++ b/templates/use_history.html.ep
@@ -5,9 +5,13 @@
Travelynx kann anhand deiner vergangenen Fahrten Verbindungen zum
Einchecken vorschlagen. Fährst zu z.B regelmäßig von Dortmund Hbf
nach Essen Hbf, werden dir in Dortmund bevorzugt Fahrten angezeigt, die
- Essen passieren. Bei Auswahl dieser wird nicht nur in die Fahrt eingecheckt,
+ Essen passieren. Bei Auswahl dieser wird nicht nur in die Fahrt eingecheckt,
sondern auch direkt Essen Hbf als Ziel eingetragen.
<p/>
+ <p>
+ Beachte, dass nicht alle von travelynx unterstützten Backends die
+ für dieses Feature notwendigen Daten bereitstellen.
+ </p>
<!-- <p>
Falls du das nicht nützlich findest oder nicht möchtest, dass deine
regelmäßigen (Anschluss-)Züge auf deinem Bildschirm sichtbar sind,
diff --git a/templates/user_status.html.ep b/templates/user_status.html.ep
index 45fba54..bf11004 100644
--- a/templates/user_status.html.ep
+++ b/templates/user_status.html.ep
@@ -1,5 +1,5 @@
<div class="row">
<div class="col s12 publicstatuscol" data-user="<%= $name %>">
- %= include '_public_status_card', name => $name, privacy => $privacy, journey => $journey
+ %= include '_public_status_card', name => $name, privacy => $privacy, journey => $journey, station_coordinates => stash('station_coordinates'), polyline_groups => stash('polyline_groups')
</div>
</div>