diff options
Diffstat (limited to 'templates')
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}}) %>&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} %>&to=<%= $journey->{arr_name} %>&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} %>&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&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') %>&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 80ef49e..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 = 'v71'; # 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> |