diff options
Diffstat (limited to 'templates')
31 files changed, 832 insertions, 344 deletions
diff --git a/templates/_cancelled_departure.html.ep b/templates/_cancelled_departure.html.ep index 79492a5..db6cc5c 100644 --- a/templates/_cancelled_departure.html.ep +++ b/templates/_cancelled_departure.html.ep @@ -1,9 +1,9 @@ <div class="card"> <div class="card-content"> - <span class="card-title">Zugausfall</span> + <span class="card-title">Fahrtausfall</span> <p>Die Abfahrt von <%= $journey->{train_type} %> <%= $journey->{train_no} %> in <a href="/s/<%= $journey->{dep_eva} %>"><%= $journey->{dep_name} %></a> - entfällt. Der Zugausfall auf der Fahrt nach <%= $journey->{arr_name} %> wurde bereits dokumentiert. + entfällt. Der Ausfall der Fahrt nach <%= $journey->{arr_name} %> wurde bereits dokumentiert. </p> % if (my @connections = @{stash('connections_iris') // []}) { <p>Alternative Reisemöglichkeiten:</p> diff --git a/templates/_checked_in.html.ep b/templates/_checked_in.html.ep index 988bf39..69754e3 100644 --- a/templates/_checked_in.html.ep +++ b/templates/_checked_in.html.ep @@ -4,7 +4,7 @@ <div class="card-content"> <i class="material-icons right sync-failed-marker grey-text" style="display: none;">sync_problem</i> % if (not $journey->{arr_name}) { - <span class="card-title center-align">Ziel wählen</span> + <span class="card-title center-align"><%= L('status.select-destination') %></span> % } <span class="card-title center-align"> %= include '_format_train', journey => $journey @@ -19,26 +19,26 @@ data-dest="<%= $journey->{arr_name} %>" > % if ($journey->{boarding_countdown} > 60) { - Einfahrt in <%= journeys->min_to_human(int($journey->{boarding_countdown} / 60)) %><br/> + <%= L('status.boarding-in.pre') %> <%= journeys->min_to_human(int($journey->{boarding_countdown} / 60)) %> <%= L('status.boarding-in.post') %><br/> % } % elsif ($journey->{boarding_countdown} > 0) { - Fährt ein<br/> + <%= L('status.boarding-soon') %><br/> % } % if ($journey->{departure_countdown} > 60) { - Abfahrt in <%= journeys->min_to_human(int($journey->{departure_countdown} / 60)) %> + <%= L('status.departure-in.pre') %> <%= journeys->min_to_human(int($journey->{departure_countdown} / 60)) %> <%= L('status.departure-in.post') %> % } % elsif ($journey->{departure_countdown} > 0) { - Abfahrt in weniger als einer Minute + %= L('status.departure-soon') % } % elsif (defined $journey->{arrival_countdown}) { % if ($journey->{arrival_countdown} > 60) { - Ankunft in <%= journeys->min_to_human(int($journey->{arrival_countdown} / 60)) %> + <%= L('status.arrival-in.pre') %> <%= journeys->min_to_human(int($journey->{arrival_countdown} / 60)) %> <%= L('status.arrival-in.post') %> % } % elsif ($journey->{arrival_countdown} > 0) { - Ankunft in weniger als einer Minute + %= L('status.arrival-soon') % } % else { - Ziel erreicht + %= L('status.arrived') % } % if ($journey->{arrival_countdown} < (60 * 15) and $journey->{arr_platform}) { % if ($journey->{arr_direction} and $journey->{arr_direction} eq 'r') { @@ -48,7 +48,7 @@ <br/>◀ <%= $journey->{platform_type} %> <%= $journey->{arr_platform} %> % } % else { - <br/>auf <%= $journey->{platform_type} %> <%= $journey->{arr_platform} %> + <br/><%= L('status.arrive-on.pre') %> <%= $journey->{platform_type} %> <%= $journey->{arr_platform} %> <%= L('status.arrive-on.post') %> % } % } % } @@ -63,7 +63,7 @@ <br/>◀ <%= $journey->{platform_type} %> <%= $journey->{dep_platform} %> % } % else { - <br/>von <%= $journey->{platform_type} %> <%= $journey->{dep_platform} %> + <br/><%= L('status.depart-from.pre') %> <%= $journey->{platform_type} %> <%= $journey->{dep_platform} %> <%= L('status.depart-from.post') %> % } % } % if (my $wr = $journey->{wagonorder}) { @@ -202,8 +202,11 @@ % 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}) { - <li><i class="material-icons tiny">gps_off</i> Keine Echtzeitdaten vorhanden + % 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> <%= L('status.realtime-unavailable') %> % } % for my $message (reverse @{$journey->{messages} // []}) { % if ($journey->{sched_departure}->epoch - $message->[0]->epoch < 1800) { @@ -232,8 +235,7 @@ % } % if (defined $journey->{arrival_countdown} and $journey->{arrival_countdown} <= 0) { <p style="margin-top: 2ex;"> - Der automatische Checkout erfolgt wegen teilweise langsamer - Echtzeitdatenupdates erst etwa zehn Minuten nach der Ankunft. + %= L('status.delayed-auto-checkout') </p> % } % elsif (not $journey->{arr_name}) { @@ -272,7 +274,7 @@ % } % else { <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> Rückgängig + <i class="material-icons left" aria-hidden="true">undo</i> <%= L('status.undo') %> </a> % } % if (defined $journey->{arrival_countdown} and $journey->{arrival_countdown} <= 0) { @@ -281,7 +283,7 @@ style="margin-right: 0;" data-station="<%= $journey->{arr_name}%>"> <i class="material-icons left">done</i> - Auschecken + %= L('status.check-out') </a> % } % elsif ($journey->{arr_name}) { @@ -308,12 +310,12 @@ data-url="<%= url_for('/status')->to_abs->scheme('https') %>/<%= $user->{name} %>/<%= $journey->{sched_departure}->epoch %>?token=<%= $journey->{dep_eva} %>-<%= $journey->{timestamp}->epoch % 337 %>" % } > - <i class="material-icons left" aria-hidden="true">share</i> Teilen + <i class="material-icons left" aria-hidden="true">share</i> <%= L('status.share') %> </a> % } % else { <a class="right" href="/journey/visibility"> - <i class="material-icons left"><%= visibility_icon($journey_visibility) %></i> Sichtbarkeit + <i class="material-icons left"><%= visibility_icon($journey_visibility) %></i> <%= L('status.privacy-level') %> </a> % } </div> @@ -325,7 +327,7 @@ <div class="card" style="margin-top: <%= scalar @{stash('timeline') // []} ? '1.5rem' : '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">Meldungen</span> + <span class="card-title"><%= L('status.messages') %></span> % if (@{$journey->{extra_data}{him_msg} // []}) { <p style="margin-bottom: 2ex;"> <ul> @@ -356,55 +358,69 @@ <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">Karte</span> + <span class="card-title"><%= L('status.map') %></span> <div id="map" style="height: 70vh;"> </div> - %= include '_map', with_map_header => 0, station_coordinates => stash('station_coordinates'), polyline_groups => stash('polyline_groups') + %= include '_map', with_map_header => 0, station_coordinates => stash('station_coordinates'), polyline_groups => stash('polyline_groups'), markers => stash('markers') </div> </div> - <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> + % 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> <%= L('status.undo-checkin') %> </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> - % } </div> </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> + % } + % 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"><%= L('status.change-destination') %></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> + % } + </div> + </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> <%= L('status.undo-checkin') %> + </a> + </div> </div> - </div> + % } <p> - Falls das Backend ausgefallen ist oder die Fahrt aus anderen - Gründen verloren ging: + %= L('status.force-checkout-lead') </p> <p class="center-align"> <a class="action-checkout waves-light btn" data-force="1" data-station="<%= $journey->{arr_name} - %>">Ohne Echtzeitdaten auschecken</a> + %>"><%= L('status.force-checkout') %></a> </p> % } </div> diff --git a/templates/_format_train.html.ep b/templates/_format_train.html.ep index e82f3f9..cb81211 100644 --- a/templates/_format_train.html.ep +++ b/templates/_format_train.html.ep @@ -1,7 +1,7 @@ % if ($journey->{extra_data}{wagonorder_pride}) { 🏳️🌈 % } -<span class="dep-line <%= $journey->{train_type} // q{} %>"> +<span class="dep-line <%= ($journey->{train_type} // q{}) =~ tr{a-zA-Z_-}{}cdr %>"> % if (not $journey->{is_motis}) { <%= $journey->{train_type} %> % } diff --git a/templates/_history_stats.html.ep b/templates/_history_stats.html.ep index cbdbb13..e24e699 100644 --- a/templates/_history_stats.html.ep +++ b/templates/_history_stats.html.ep @@ -2,22 +2,23 @@ <div class="col s12"> <table class="striped"> <tr> - <th scope="row">Fahrten</th> + <th scope="row"><%= L('stats.trips') %></th> <td><%= $stats->{num_trains} %></td> </tr> <tr> - <th scope="row">Entfernung</th> - <td>ca. <%= sprintf('%.f', $stats->{km_route}) %> km - (Luftlinie: <%= sprintf('%.f', $stats->{km_beeline}) %> km)</td> + <th scope="row"><%= L('stats.distance') %></th> + <td>≈ <%= sprintf('%.f', $stats->{km_route}) %> km + <%= L('journey.beeline.pre') %><%= sprintf('%.f', $stats->{km_beeline}) %> km<%= L('journey.beeline.post') %></td> </tr> <tr> - <th scope="row">Fahrtzeit</th> - <td><%= $stats->{min_travel_real_strf} %> Stunden - (nach Fahrplan: <%= $stats->{min_travel_sched_strf} %>)</td> + <th scope="row"><%= L('stats.time') %></th> + <td><%= $stats->{min_travel_real_strf} %> <%= L('stats.hours') %> + (<%= L('stats.per-schedule') %>: <%= $stats->{min_travel_sched_strf} %>)</td> </tr> <tr> - <th scope="row">Wartezeit (nur Umstiege)</th> - <td><%= $stats->{min_interchange_real_strf} %> Stunden + <th scope="row"><%= L('stats.transfer-time') %></th> + <td><%= $stats->{min_interchange_real_strf} %> <%= L('stats.hours') %> + <!-- % if (@{$stats->{inconsistencies}}) { <br/><br/>Für Wartezeitberechnung nicht berücksichtigte Fahrten:<br/> % for my $field (@{$stats->{inconsistencies}}) { @@ -25,12 +26,13 @@ (Konflikt: <a href="/journey/<%= $field->{conflict}{id} %>"><%= $field->{conflict}{train} %> an <%= $field->{conflict}{arr} %></a>)<br/> % } % } + --> </td> </tr> <tr> - <th scope="row">Kumulierte Verspätung</th> - <td>Bei Abfahrt: <%= $stats->{delay_dep_strf} %> Stunden<br/> - Bei Ankunft: <%= $stats->{delay_arr_strf} %> Stunden</td> + <th scope="row"><%= L('stats.total-delay') %></th> + <td><%= L('stats.on-dep') %>: <%= $stats->{delay_dep_strf} %> <%= L('stats.hours') %><br/> + <%= L('stats.on-arr') %>: <%= $stats->{delay_arr_strf} %> <%= L('stats.hours') %></td> </tr> </table> </div> diff --git a/templates/_history_trains.html.ep b/templates/_history_trains.html.ep index 7ae2a1d..166d74d 100644 --- a/templates/_history_trains.html.ep +++ b/templates/_history_trains.html.ep @@ -16,8 +16,8 @@ % } <li class="collection-item"> <a href="<%= $detail_link %>"> - <span class="dep-line <%= $travel->{type} // q{} %>"> - % if (not $travel->{is_motis}) { + <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}%> @@ -37,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) %>) % } % } % } @@ -55,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 223bd68..93f116a 100644 --- a/templates/_map.html.ep +++ b/templates/_map.html.ep @@ -39,6 +39,15 @@ var pl; % } % } +% for my $marker (@{stash('markers') // []}) { + % if ($marker->[0] and $marker->[0][0] and $marker->[1]) { + { + const marker = L.marker([<%= $marker->[0][0] %>, <%= $marker->[0][1] %>]).addTo(map); + marker.bindPopup('<%= $marker->[1] %>'); + } + % } +% } + % if (my $b = stash('bounds')) { map.fitBounds([[<%= $b->[0][0] %>,<%= $b->[0][1] %>],[<%= $b->[1][0] %>,<%= $b->[1][1] %>]]); % } @@ -48,8 +57,8 @@ for (var station_id in stations) { color: '#f03', opacity: 0.7, fillColor: '#f03', - fillOpacity: 0.5, - radius: 250 + fillOpacity: 0.2, + radius: 200 }).bindPopup(stations[station_id][1]).addTo(map); } diff --git a/templates/_public_status_card.html.ep b/templates/_public_status_card.html.ep index 32b193a..ca5ddf8 100644 --- a/templates/_public_status_card.html.ep +++ b/templates/_public_status_card.html.ep @@ -11,7 +11,7 @@ <a href="/status/<%= $name %>"><%= $name %></a>: <%= include '_format_train', journey => $journey %> % } % else { - <a href="/p/<%= $name %>"><%= $name %></a> ist unterwegs + <a href="/p/<%= $name %>"><%= $name %></a> <%= L('status.is-checked-in') %> % } <i class="material-icons right"><%= visibility_icon($journey->{effective_visibility_str}) %></i> % if (not $journey->{extra_data}{rt}) { @@ -41,10 +41,10 @@ % } % elsif (defined $journey->{arrival_countdown}) { % if ($journey->{arrival_countdown} > 60) { - Ankunft in <%= journeys->min_to_human(int($journey->{arrival_countdown} / 60)) %> + <%= L('status.arrival-in.pre') %> <%= journeys->min_to_human(int($journey->{arrival_countdown} / 60)) %> <%= L('status.arrival-in.post') %> % } % elsif ($journey->{arrival_countdown} > 0) { - Ankunft in weniger als einer Minute + %= L('status.arrival-soon') % } % else { Ziel erreicht @@ -54,7 +54,7 @@ % } % } % elsif ($journey->{arr_name}) { - Ankunft in mehr als zwei Stunden + %= L('status.arrival-unknown') % } </div> <div class="progress" style="height: 1ex;"> @@ -216,14 +216,14 @@ % } % else { <div class="wagons" style="margin-top: 2ex;"> - Wagen:<br/> + <%= L('status.carriages') %>:<br/> %= include '_wagons', wagongroups => $journey->{wagongroups}; </div> % } % } % if (not stash('from_timeline')) { <div style="margin-top: 2ex;"> - Route:<br/> + <%= L('status.route') %>:<br/> % my $before = 1; % my $within = 0; % my $at_startstop = 0; @@ -280,7 +280,7 @@ <span class="card-title">Aktuell nicht eingecheckt</span> % } % else { - <span class="card-title"><a href="/p/<%= $name %>"><%= $name %></a> ist gerade nicht eingecheckt</span> + <span class="card-title"><a href="/p/<%= $name %>"><%= $name %></a> <%= L('status.is-not-checked-in') %></span> % } <div> % if ($journey->{arr_name}) { diff --git a/templates/_suggestions_dbris.html.ep b/templates/_suggestions_dbris.html.ep new file mode 100644 index 0000000..175a57b --- /dev/null +++ b/templates/_suggestions_dbris.html.ep @@ -0,0 +1,54 @@ +<ul class="collection departures connections"> + % for my $res (@{$suggestions}) { + % my ($dep, $dest) = @{$res}; + % my $row_class = ''; + % my $link_class = 'action-checkin'; + % if ($dep->is_cancelled) { + % $row_class = 'cancelled'; + % $link_class = 'action-cancelled-from'; + % } + % if ($checkin_from) { + <li class="collection-item <%= $row_class %> <%= $link_class %>" + data-dbris="<%= $dbris %>" + data-station="<%= $dep->stop_eva %>" + data-train="<%= $dep->id %>" + data-suffix="<%= $dep->maybe_line_no %>" + data-ts="<%= ($dep->sched_dep // $dep->dep)->epoch %>" + data-dest="<%= $dest->{name} %>"> + % } + % else { + <li class="collection-item <%= $row_class %>"> + % } + <a class="dep-time" href="#"> + % if ($dep->is_cancelled) { + %= $dep->sched_dep->strftime('%H:%M') + % } + % else { + %= $dep->dep->strftime('%H:%M') + % } + % if ($dep->delay) { + %= sprintf('(%+d)', $dep->delay) + % } + </a> + <span class="connect-platform-wrapper"> + % if ($dep->platform) { + <span> + % if (($dep->type // q{}) =~ m{ ast | bus | ruf }ix) { + Steig + % } + % else { + Gleis + % } + %= $dep->platform + </span> + % } + <span class="dep-line <%= $dep->type // q{} %>"> + %= $dep->line + </span> + </span> + <span class="dep-dest"> + %= $dest->{name} + </span> + </li> + % } +</ul> diff --git a/templates/_suggestions_efa.html.ep b/templates/_suggestions_efa.html.ep new file mode 100644 index 0000000..68fb4a9 --- /dev/null +++ b/templates/_suggestions_efa.html.ep @@ -0,0 +1,53 @@ +<ul class="collection departures connections"> + % for my $res (@{$suggestions}) { + % my ($dep, $dest) = @{$res}; + % my $row_class = ''; + % my $link_class = 'action-checkin'; + % if ($dep->is_cancelled) { + % $row_class = 'cancelled'; + % $link_class = 'action-cancelled-from'; + % } + % if ($checkin_from) { + <li class="collection-item <%= $row_class %> <%= $link_class %>" + data-efa="<%= $efa %>" + data-station="<%= $dep->stop_id_num %>" + data-train="<%= $dep->id %>" + data-ts="<%= ($dep->sched_datetime // $dep->datetime)->epoch %>" + data-dest="<%= $dest->{name} %>"> + % } + % else { + <li class="collection-item <%= $row_class %>"> + % } + <a class="dep-time" href="#"> + % if ($dep->is_cancelled) { + %= $dep->sched_datetime->strftime('%H:%M') + % } + % else { + %= $dep->datetime->strftime('%H:%M') + % } + % if ($dep->delay) { + %= sprintf('(%+d)', $dep->delay) + % } + </a> + <span class="connect-platform-wrapper"> + % if ($dep->platform) { + <span> + % if (($dep->type // q{}) =~ m{ ast | bus | ruf }ix) { + Steig + % } + % else { + Gleis + % } + %= $dep->platform + </span> + % } + <span class="dep-line <%= ($dep->type // q{}) =~ tr{a-zA-Z_-}{}cdr %>"> + %= $dep->line + </span> + </span> + <span class="dep-dest"> + %= $dest->{name} + </span> + </li> + % } +</ul> diff --git a/templates/_wagons.html.ep b/templates/_wagons.html.ep index 4090f11..3f906c0 100644 --- a/templates/_wagons.html.ep +++ b/templates/_wagons.html.ep @@ -7,12 +7,12 @@ % elsif ($wagon_number and my $group_name = app->ice_name->{$wagon_number}) { „<%= $group_name %>“ % } - als <b><%= $wagongroup->{type} // $journey->{type} %> <%= $wagongroup->{no} %></b> + <%= L('wagons.name-as-type') %> <b><%= $wagongroup->{type} // $journey->{type} %> <%= $wagongroup->{no} %></b> % if ($wagongroup->{from}) { - von <b><%= $wagongroup->{from} %></b> + <%= L('wagons.from.pre') %> <b><%= $wagongroup->{from} %></b> <%= L('wagons.from.post') %> % } % if ($wagongroup->{to}) { - nach <b><%= $wagongroup->{to} %></b> + <%= L('wagons.to.pre') %> <b><%= $wagongroup->{to} %></b> <%= L('wagons.to.post') %> % } <br/> % for my $wagon (@{$wagongroup->{wagons}}) { @@ -24,7 +24,7 @@ % } %= $wagon->{type} % if ($wagon->{number}) { - – Wagen <%= $wagon->{number} %> + – <%= L('wagons.carriage') %> <%= $wagon->{number} %> % } <br/> % } diff --git a/templates/about.html.ep b/templates/about.html.ep index e2b148d..a76cb94 100644 --- a/templates/about.html.ep +++ b/templates/about.html.ep @@ -1,10 +1,10 @@ <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> - 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: + <%= L('about.developed-by.lead') %> <a href="https://finalrewind.org">derf</a> + <%= L('about.developed-by.and') %> <a href="https://github.com/derf/travelynx/graphs/contributors"><%= L('about.developed-by.others') %></a> <%= L('about.developed-by.tail') %> <%= L('about.developed-by.tail') %><br/> + <a href="<%= app->config->{ref}{source} // 'https://git.finalrewind.org/travelynx' %>"><%= L('about.source-code') %></a> <%= L('about.licence-agplv3') %><br/><br/> + <%= L('about.data-sources') %>: <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> @@ -12,40 +12,31 @@ <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 + v<%= $Travel::Status::DE::IRIS::VERSION %><%= L('about.data-sources.last-and') %> <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 </div> </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. + %= L('about.disclaimer') </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> + <a href="https://social.skyshaper.org/derf" class="waves-effect waves-light btn"><i class="material-icons left">message</i><%= L('about.contact') %></a> </div> <div class="col s12 m12 l4 center-align" style="margin-top: 1em;"> % if (my $issue_url = app->config->{ref}{issues}) { - <a href="<%= $issue_url %>" class="waves-effect waves-light btn"><i class="material-icons left">bug_report</i>Bugs?</a> + <a href="<%= $issue_url %>" class="waves-effect waves-light btn"><i class="material-icons left">bug_report</i><%= L('about.bugs') %></a> % } </div> <div class="col s12 m12 l4 center-align" style="margin-top: 1em;"> - <a href="/changelog" class="waves-effect waves-light btn"><i class="material-icons left">list</i>Changelog</a> + <a href="/changelog" class="waves-effect waves-light btn"><i class="material-icons left">list</i><%= L('about.changelog') %></a> </div> </div> diff --git a/templates/account.html.ep b/templates/account.html.ep index e4bf38d..17f708f 100644 --- a/templates/account.html.ep +++ b/templates/account.html.ep @@ -8,31 +8,34 @@ <div class="card success-color"> <div class="card-content white-text"> % if ($success eq 'name') { - <span class="card-title">Name geändert</span> + <span class="card-title"><%= L('account.changed-name') %></span> % } % elsif ($success eq 'mail') { - <span class="card-title">Mail-Adresse geändert</span> + <span class="card-title"><%= L('account.changed-mail') %></span> % } % elsif ($success eq 'password') { - <span class="card-title">Passwort geändert</span> + <span class="card-title"><%= L('account.changed-password') %></span> + % } + % elsif ($success eq 'language') { + <span class="card-title"><%= L('account.changed-language') %></span> % } % elsif ($success eq 'privacy') { - <span class="card-title">Einstellungen zu öffentlichen Account-Daten geändert</span> + <span class="card-title"><%= L('account.changed-privacy') %></span> % } % elsif ($success eq 'social') { - <span class="card-title">Einstellungen zur Interaktionen mit anderen Accounts geändert</span> + <span class="card-title"><%= L('account.changed-social') %></span> % } % elsif ($success eq 'traewelling') { - <span class="card-title">Träwelling-Verknüpfung aktualisiert</span> + <span class="card-title"><%= L('account.changed-traewelling') %></span> % } % elsif ($success eq 'use_history') { - <span class="card-title">Einstellungen zu vorgeschlagenen Verbindungen geändert</span> + <span class="card-title"><%= L('account.changed-history') %></span> % } % elsif ($success eq 'webhook') { - <span class="card-title">Web Hook aktualisiert</span> + <span class="card-title"><%= L('account.changed-webhook') %></span> % } % elsif ($success eq 'clear_notifications') { - <span class="card-title">Benachrichtigungen gelesen</span> + <span class="card-title"><%= L('account.cleared-notifications') %></span> % } </div> </div> @@ -46,34 +49,38 @@ % my $use_history = users->use_history(uid => $acc->{id}); <div class="row"> <div class="col s12"> - <h2>Account</h2> + <h2><%= L('account.account') %></h2> <table class="striped"> <tr> - <th scope="row">Name</th> + <th scope="row"><%= L('account.name') %></th> <td><a href="/account/name"><i class="material-icons">edit</i></a><%= $acc->{name} %></td> </tr> <tr> - <th scope="row">Mail</th> + <th scope="row"><%= L('account.mail') %></th> <td><a href="/account/mail"><i class="material-icons">edit</i></a><%= $acc->{email} %></td> </tr> <tr> - <th scope="row">Passwort</th> + <th scope="row"><%= L('account.password') %></th> <td><a href="/account/password"><i class="material-icons">edit</i></a></td> </tr> <tr> - <th scope="row">Verbindungen</th> + <th scope="row"><%= L('account.language') %></th> + <td><a href="/account/language"><i class="material-icons">edit</i></a><%= $acc->{languages}[0] // q{} %></td> + </tr> + <tr> + <th scope="row"><%= L('account.connections') %></th> <td> <a href="/account/insight"><i class="material-icons">edit</i></a> % if ($use_history & 0x03) { - Vorschläge aktiv + %= L('account.connections.enabled') % } % else { - <span style="color: #999999;">Vorschläge deaktiviert</span> + <span style="color: #999999;"><%= L('account.connections.disabled') %></span> % } </td> </tr> <tr> - <th scope="row">Sichtbarkeit</th> + <th scope="row"><%= L('account.visibility') %></th> <td> <a href="/account/privacy"><i class="material-icons">edit</i></a> <i class="material-icons">check</i><i class="material-icons"><%= visibility_icon($acc->{default_visibility_str}) %></i> @@ -81,41 +88,41 @@ </td> </tr> <tr> - <th scope="row">Interaktion</th> + <th scope="row"><%= L('account.interaction') %></th> <td> <a href="/account/social"><i class="material-icons">edit</i></a> % if ($acc->{accept_follows}) { - <span>Accounts können dir direkt folgen</span> + <span><%= L('account.interaction.accept-follows') %></span> % } % elsif ($acc->{accept_follow_requests}) { - <span>Accounts können dir auf Anfrage folgen + <span><%= L('account.interaction.accept-follow-requests') %> % if ($num_rx_follow_requests == 1) { - – <a href="/account/social/follow-requests-received"><strong>eine</strong> offene Anfrage</a> + – <a href="/account/social/follow-requests-received"><strong><%= L('account.interaction.one') %></strong> <%= L('account.interaction.open-request') %></a> % } elsif ($num_rx_follow_requests) { - – <a href="/account/social/follow-requests-received"><strong><%= $num_rx_follow_requests %></strong> offene Anfragen</a> + – <a href="/account/social/follow-requests-received"><strong><%= $num_rx_follow_requests %></strong> <%= L('account.interaction.open-requests') %></a> % } </span> % } % else { - <span style="color: #999999;">Accounts können dir nicht folgen</span> + <span style="color: #999999;"><%= L('account.interaction.disabled') %></span> % } </td> </tr> <tr> - <th scope="row">Web Hook</th> + <th scope="row"><%= L('account.webhook') %></th> <td> <a href="/account/hooks"><i class="material-icons">edit</i></a> % if (not $hook->{enabled}) { - <span style="color: #999999;">Nicht eingerichtet</span> + <span style="color: #999999;"><%= L('account.webhook.disabled') %></span> % } % elsif ($hook->{latest_run}->epoch == 0) { - Aktiv, noch nicht ausgeführt + <%= L('account.webhook.active-pending') %> % } % elsif ($hook->{errored}) { - Aktiv, fehlerhaft <i class="material-icons" aria-hidden="true">error</i> + <%= L('account.webhook.active-error') %> <i class="material-icons" aria-hidden="true">error</i> % } % else { - Aktiv + <%= L('account.webhook.active') %> % } </td> </tr> @@ -123,7 +130,7 @@ <tr> <th scope="row">Träwelling</th> <td> - Wird wegen Inkompatibilität zwischen bahn.de und transitous derzeit nicht unterstützt + <%= L('account.traewelling.unsupported') %> <!-- <a href="/account/traewelling"><i class="material-icons">edit</i></a> % if (not ($traewelling->{token})) { @@ -152,8 +159,8 @@ </tr> % } <tr> - <th scope="row">Registriert am</th> - <td><%= $acc->{registered_at}->strftime('%d.%m.%Y %H:%M') %></td> + <th scope="row"><%= L('account.registration-date') %></th> + <td><%= $acc->{registered_at}->strftime(L('strftime.datetime')) %></td> </tr> </table> </div> @@ -163,7 +170,7 @@ %= form_for 'logout' => begin %= csrf_field <button class="btn waves-effect waves-light" type="submit" name="action" value="logout"> - Abmelden + %= L('button.logout') </button> %= end </div> @@ -172,32 +179,32 @@ % if ($num_rx_follow_requests or $num_tx_follow_requests or $num_followers or $num_following or $num_blocked) { <div class="row"> <div class="col s12"> - <h2>Interaktion</h2> + <h2><%= L('account.interaction') %></h2> <p> - <a href="/p/<%= $acc->{name} %>">Öffentliches Profil</a> + <a href="/p/<%= $acc->{name} %>"><%= L('account.profile') %></a> </p> <table class="striped"> <tr> - <th scope="row">Anfragen</th> + <th scope="row"><%= L('account.interaction.requests') %></th> <td> % if ($num_rx_follow_requests == 0) { - <span style="color: #999999;">keine eingehend</span> + <span style="color: #999999;"><%= L('account.interaction.requests.incoming.none') %></span> % } % elsif ($num_rx_follow_requests == 1) { - <a href="/account/social/follow-requests-received"><strong>eine</strong> eingehend</a> + <a href="/account/social/follow-requests-received"><strong><%= L('account.interaction.one') %></strong> <%= L('account.interaction.requests.incoming.some') %></a> % } % else { - <a href="/account/social/follow-requests-received"><strong><%= $num_rx_follow_requests %></strong> eingehend</a> + <a href="/account/social/follow-requests-received"><strong><%= $num_rx_follow_requests %></strong> <%= L('account.interaction.requests.incoming.some') %></a> % } <br/> % if ($num_tx_follow_requests == 0) { - <span style="color: #999999;">keine ausgehend</span> + <span style="color: #999999;"><%= L('account.interaction.requests.outgoing.none') %></span> % } % elsif ($num_tx_follow_requests == 1) { - <a href="/account/social/follow-requests-sent"><strong>eine</strong> ausgehend</a> + <a href="/account/social/follow-requests-sent"><strong><%= L('account.interaction.one') %></strong> <%= L('account.interaction.requests.outgoing.some') %></a> % } % else { - <a href="/account/social/follow-requests-sent"><strong><%= $num_tx_follow_requests %></strong> ausgehend</a> + <a href="/account/social/follow-requests-sent"><strong><%= $num_tx_follow_requests %></strong> <%= L('account.interaction.requests.outgoing.some') %></a> % } </td> </tr> diff --git a/templates/add_intransit.html.ep b/templates/add_intransit.html.ep new file mode 100644 index 0000000..a044917 --- /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 YYYY-MM-DDTHH:MM. Bei den Zwischenhalten kann auch nur HH:MM angegeben werden</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"> + %= datetime_field 'sched_departure', id => 'sched_departure', class => 'validate', required => undef + <label for="sched_departure" class="active">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"> + %= datetime_field 'sched_arrival', id => 'sched_arrival', class => 'validate', required => undef + <label for="sched_arrival" class="active">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> (Format siehe oben, ein ggf. ausgelassenes Datum wird ergänzt) + </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..94f9270 100644 --- a/templates/add_journey.html.ep +++ b/templates/add_journey.html.ep @@ -33,10 +33,22 @@ <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>Zeitangaben im Format YYYY-MM-DDTHH: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,35 +66,37 @@ <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]' - <label for="sched_departure">Geplante Abfahrt</label> + %= datetime_field 'sched_departure', id => 'sched_departure', class => 'validate', required => undef + <label for="sched_departure" class="active">Geplante Abfahrt</label> </div> <div class="input-field col s12"> - %= text_field 'rt_departure', id => 'rt_departure', class => 'validate', 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="rt_departure">Tatsächliche Abfahrt (wenn leer: pünktlich)</label> + %= datetime_field 'rt_departure', id => 'rt_departure', class => 'validate' + <label for="rt_departure" class="active">Tatsächliche Abfahrt (wenn leer: pünktlich)</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 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]' - <label for="sched_arrival">Geplante Ankunft</label> + %= datetime_field 'sched_arrival', id => 'sched_arrival', class => 'validate', required => undef + <label for="sched_arrival" class="active">Geplante Ankunft</label> </div> <div class="input-field col s12"> - %= text_field 'rt_arrival', id => 'rt_arrival', class => 'validate', 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="rt_arrival">Tatsächliche Ankunft (wenn leer: pünktlich)</label> + %= datetime_field 'rt_arrival', id => 'rt_arrival', class => 'validate' + <label for="rt_arrival" class="active">Tatsächliche Ankunft (wenn leer: pünktlich)</label> </div> </div> <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 099474c..6db9536 100644 --- a/templates/api_documentation.html.ep +++ b/templates/api_documentation.html.ep @@ -89,23 +89,25 @@ <div class="col s12"> <p> Checkin per API. Sobald eine Zielstation bekannt ist, erfolgt der - Checkout wie beim Webinterface automatisch zehn Minuten nach Ankunft. - Bitte beachten: Es wird nicht überprüft, ob die angegebene Zielstation - in der vorgesehenen Route der Fahrt vorkommt oder nicht. + Checkout wie beim Webinterface automatisch spätestens eine halbe + Stunde nach Ankunft. Bitte beachten: Es wird nicht überprüft, ob + die angegebene Zielstation in der vorgesehenen Route der Fahrt + vorkommt oder nicht. </p> <p> - Falls du zum Checkinzeitpunkt bereits in eine andere Fahrt eingecheckt - bist, wirst du zunächst am gewählten Startbahnhof aus diesem ausgecheckt. - Der Checkout erfolgt unabhängig davon, ob die vorherige Fahrt an dieser - Station verkehrt oder nicht. Falls nach einem Checkin ohne Zielwahl - innerhalb von 48 Stunden kein Zielbahnhof nachgetragen wird, wird der - Checkin automatisch rückgängig gemacht. + Falls du zum Checkinzeitpunkt bereits in eine andere Fahrt + eingecheckt bist, wirst du zunächst am gewählten Startbahnhof aus + diesem ausgecheckt. Der Checkout erfolgt unabhängig davon, ob die + vorherige Fahrt an dieser Station verkehrt oder nicht. Falls nach + einem Checkin ohne Zielwahl innerhalb von 48 Stunden kein + Zielbahnhof nachgetragen wird, wird der Checkin automatisch + rückgängig gemacht. </p> <p> Das Verhalten des Checkout-Endpunkts hängt vom Zeitpunkt ab. Wenn die Fahrt den angegebenen Zielbahnhof bereits erreicht hat, wird dort - ausgecheckt. Andernfalls wird das Reiseziel aktualisiert und etwa zehn - Minuten nach Ankunft automatisch ausgecheckt. + ausgecheckt. Andernfalls wird das Reiseziel aktualisiert und + spätestens eine halbe Stunde nach Ankunft automatisch ausgecheckt. </p> <p style="font-family: Monospace;"> curl -X POST -H "Content-Type: application/json" -d '{"token":"<%= $uid %>-<%= $token->{travel} // 'TOKEN' %>"}' <%= $api_root %>/travel diff --git a/templates/cancelled.html.ep b/templates/cancelled.html.ep index 4fab434..fe0b958 100644 --- a/templates/cancelled.html.ep +++ b/templates/cancelled.html.ep @@ -1,7 +1,7 @@ -<h1>Zugausfälle</h1> +<h1>Ausfälle</h1> <div class="row"> <div class="col s12"> - Die folgenden Zugfahrten haben nicht stattgefunden. + Die folgenden Fahrten haben nicht wie geplant stattgefunden. </div> </div> diff --git a/templates/changelog.html.ep b/templates/changelog.html.ep index dc454c5..042a46e 100644 --- a/templates/changelog.html.ep +++ b/templates/changelog.html.ep @@ -2,6 +2,67 @@ <div class="row"> <div class="col s12 m1 l1"> + 2.17 + </div> + <div class="col s12 m11 l11"> + <p> + <i class="material-icons left" aria-label="<%= L('changelog.added') %>">add</i> + %= L('changelog.2-17.1') + </p> + </div> +</div> + +<div class="row"> + <div class="col s12 m1 l1"> + 2.16 + </div> + <div class="col s12 m11 l11"> + <p> + <i class="material-icons left" aria-label="<%= L('changelog.added') %>">add</i> + %= L('changelog.2-16.1') + </p> + <p> + <i class="material-icons left" aria-label="<%= L('changelog.bugfix') %>">build</i> + %= L('changelog.2-16.2') + </p> + </div> +</div> + +<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"> diff --git a/templates/departures.html.ep b/templates/departures.html.ep index 16b5f3c..0d57039 100644 --- a/templates/departures.html.ep +++ b/templates/departures.html.ep @@ -81,14 +81,7 @@ </div> </div> % } -% elsif ($user_status->{timestamp_delta} < 180) { - <div class="row"> - <div class="col s12"> - %= include '_checked_out', journey => $user_status; - </div> - </div> -% } -% elsif (not param('train') and (@{stash('connections_iris') // []} or @{stash('connections_hafas') // []}) ) { +% elsif (not param('train') and (@{stash('connections_iris') // []} or @{stash('connections_hafas') // []} or @{stash('suggestions') // []}) ) { % $have_connections = 1; <div class="row"> <div class="col s12"> @@ -99,6 +92,21 @@ % if (@{stash('connections_hafas') // []}) { %= include '_connections_hafas', connections => stash('connections_hafas'), checkin_from => $eva; % } + % if (@{stash('suggestions') // []}) { + % if ($dbris) { + %= include '_suggestions_dbris', suggestions => stash('suggestions'), checkin_from => $eva; + % } + % elsif ($efa) { + %= include '_suggestions_efa', suggestions => stash('suggestions'), checkin_from => $eva; + % } + % } + </div> + </div> +% } +% if (not $user_status->{checked_in} and $user_status->{timestamp_delta} < 180) { + <div class="row"> + <div class="col s12"> + %= include '_checked_out', journey => $user_status; </div> </div> % } @@ -190,3 +198,11 @@ % } </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/edit_journey.html.ep b/templates/edit_journey.html.ep index cb867e5..57941c0 100644 --- a/templates/edit_journey.html.ep +++ b/templates/edit_journey.html.ep @@ -69,13 +69,13 @@ <tr> <th scope="row">Geplante Abfahrt</th> <td class="input-field"> - %= 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]' + %= 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](:[0-9][0-9])?' </td> </tr> <tr> <th scope="row">Tatsächliche Abfahrt</th> <td class="input-field"> - %= text_field 'rt_departure', id => 'real_departure', class => 'validate', 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]' + %= text_field 'rt_departure', id => 'real_departure', class => 'validate', 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](:[0-9][0-9])?' </td> </tr> <tr> @@ -87,13 +87,13 @@ <tr> <th scope="row">Geplante Ankunft</th> <td class="input-field"> - %= 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]' + %= 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](:[0-9][0-9])?' </td> </tr> <tr> <th scope="row">Tatsächliche Ankunft</th> <td class="input-field"> - %= text_field 'rt_arrival', id => 'real_arrival', class => 'validate', 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]' + %= text_field 'rt_arrival', id => 'real_arrival', class => 'validate', 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](:[0-9][0-9])?' </td> </tr> <tr> diff --git a/templates/history_by_month.html.ep b/templates/history_by_month.html.ep index c3b1004..dec4c8b 100644 --- a/templates/history_by_month.html.ep +++ b/templates/history_by_month.html.ep @@ -6,7 +6,7 @@ <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> + <a href="/history/map?filter_from=<%= $filter_from->strftime('%F') %>&filter_to=<%= $filter_to->strftime('%F') %>" class="waves-effect waves-light btn"><i class="material-icons left" aria-hidden="true">map</i> Karte</a> </div> </div> diff --git a/templates/history_by_year.html.ep b/templates/history_by_year.html.ep index 6aa0c2d..1557b77 100644 --- a/templates/history_by_year.html.ep +++ b/templates/history_by_year.html.ep @@ -7,7 +7,7 @@ <div class="row"> % if (stash('have_review')) { <div class="col s12 m12 l5 center-align"> - <a href="/history/map?filter_from=1.1.<%= $year %>&filter_to=31.12.<%= $year %>" class="waves-effect waves-light btn"><i class="material-icons left" aria-hidden="true">map</i> Karte</a> + <a href="/history/map?filter_from=<%= $year %>-01-01&filter_to=<%= $year %>-12-31" class="waves-effect waves-light btn"><i class="material-icons left" aria-hidden="true">map</i> Karte</a> </div> <div class="col s12 m12 l2"> </div> <div class="col s12 m12 l5 center-align"> @@ -16,7 +16,7 @@ % } % else { <div class="col s12 m12 l12 center-align"> - <a href="/history/map?filter_from=1.1.<%= $year %>&filter_to=31.12.<%= $year %>" class="waves-effect waves-light btn"><i class="material-icons left" aria-hidden="true">map</i> Karte</a> + <a href="/history/map?filter_from=<%= $year %>-01-01&filter_to=<%= $year %>-12-31" class="waves-effect waves-light btn"><i class="material-icons left" aria-hidden="true">map</i> Karte</a> </div> % } </div> diff --git a/templates/history_map.html.ep b/templates/history_map.html.ep index 57ba81f..6620cb2 100644 --- a/templates/history_map.html.ep +++ b/templates/history_map.html.ep @@ -88,14 +88,14 @@ </p> <div class="row"> <div class="input-field col s12"> - %= text_field 'filter_from', id => 'filter_from', class => 'validate', 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="filter_from">Abfahrt ab (DD.MM.YYYY)</label> + %= date_field 'filter_from', id => 'filter_from', class => 'validate' + <label for="filter_from" class="active">Abfahrt ab</label> </div> </div> <div class="row"> <div class="input-field col s12"> - %= text_field 'filter_to', id => 'filter_to', class => 'validate', 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="filter_to">Abfahrt bis (DD.MM.YYYY)</label> + %= date_field 'filter_to', id => 'filter_to', class => 'validate' + <label for="filter_to" class="active">Abfahrt bis</label> </div> </div> <div class="row"> @@ -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 45a1598..09ad76d 100644 --- a/templates/journey.html.ep +++ b/templates/journey.html.ep @@ -3,8 +3,8 @@ <div class="col s12"> <div class="card caution-color"> <div class="card-content white-text"> - <span class="card-title">Fehler</span> - <p>Fahrt nicht gefunden.</p> + <span class="card-title"><%= L('header.error') %></span> + <p><%= L('journey.not-found') %></p> </div> </div> </div> @@ -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> @@ -67,9 +55,9 @@ %= end </div> % } - <table class="striped"> + <table class="striped journey"> <tr> - <th scope="row">Fahrt</th> + <th scope="row"><%= L('journey.trip') %></th> <td> <%= $journey->{type} %> <%= $journey->{no} %> % if ($journey->{line}) { @@ -78,19 +66,48 @@ </td> </tr> <tr> - <th scope="row">Abfahrt</th> + <th scope="row"><%= L('journey.from') %></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"><%= L('journey.to') %></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"><%= L('journey.departure') %></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}->epoch % 60) ? $journey->{rt_departure}->strftime('%H:%M:%S') : $journey->{rt_departure}->strftime('%H:%M'); - (<%= sprintf('%+d', ($journey->{rt_departure}->epoch - $journey->{sched_departure}->epoch) / 60) %>, - Plan: <%= ($journey->{sched_departure}->epoch % 60) ? $journey->{sched_departure}->strftime('%H:%M:%S') : $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}->epoch % 60) ? $journey->{sched_departure}->strftime('%H:%M:%S') : $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) { ∗ @@ -98,24 +115,29 @@ </td> </tr> <tr> - <th scope="row">Ankunft</th> + <th scope="row"><%= L('journey.arrival') %></th> <td> % 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}->epoch % 60) ? $journey->{rt_arrival}->strftime('%H:%M:%S') : $journey->{rt_arrival}->strftime('%H:%M'); - (<%= sprintf('%+d', ($journey->{rt_arrival}->epoch - $journey->{sched_arrival}->epoch) / 60) %>, - Plan: <%= ($journey->{sched_arrival}->epoch % 60) ? $journey->{sched_arrival}->strftime('%H:%M:%S') : $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}->epoch % 60) ? $journey->{sched_arrival}->strftime('%H:%M:%S') : $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) { ∗ @@ -123,7 +145,7 @@ </td> </tr> <tr> - <th scope="row">Strecke</th> + <th scope="row"><%= L('journey.distance') %></th> <td> % if ($journey->{skip_route}) { <i class="material-icons right">location_off</i> @@ -131,10 +153,10 @@ % } % if ($journey->{km_route} > 0.1) { ca. <%= sprintf_km($journey->{km_route}) %> - (Luftlinie: <%= sprintf_km($journey->{km_beeline}) %>) + <%= L('journey.beeline.pre') %><%= sprintf_km($journey->{km_beeline}) %><%= L('journey.beeline.post') %> % } % elsif ($journey->{km_beeline} > 0.1) { - (Luftlinie: <%= sprintf_km($journey->{km_beeline}) %>) + <%= L('journey.beeline.pre') %><%= sprintf_km($journey->{km_beeline}) %><%= L('journey.beeline.post') %> % } % else { ? @@ -145,7 +167,7 @@ </td> </tr> <tr> - <th scope="row">Tempo</th> + <th scope="row"><%= L('journey.speed') %></th> <td> % if ($journey->{skip_route}) { <i class="material-icons right">location_off</i> @@ -168,7 +190,7 @@ </tr> % if ($journey->{user_data}{operator} or scalar @{ $journey->{user_data}{operators} // [] }) { <tr> - <th scope="row">Betrieb</th> + <th scope="row"><%= L('journey.operator') %></th> <td> %= $journey->{user_data}{operator} // join(q{, }, @{$journey->{user_data}{operators}}) </td> @@ -176,7 +198,7 @@ % } % if ($journey->{messages} and @{$journey->{messages}}) { <tr> - <th scope="row">Meldungen</th> + <th scope="row"><%= L('journey.messages') %></th> <td> % for my $message (@{$journey->{messages} // []}) { % my ($ts, $msg) = @{$message}; @@ -187,7 +209,7 @@ % } % if ($journey->{user_data}{him_msg} and @{$journey->{user_data}{him_msg}}) { <tr> - <th scope="row">Meldungen</th> + <th scope="row"><%= L('journey.messages') %></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/> @@ -197,7 +219,7 @@ % } % if ($journey->{user_data} and $journey->{user_data}{comment}) { <tr> - <th scope="row">Kommentar</th> + <th scope="row"><%= L('journey.comment') %></th> <td> <%= $journey->{user_data}{comment} %> </td> @@ -205,7 +227,7 @@ % } % if ($journey->{user_data} and $journey->{user_data}{wagongroups} and not exists $journey->{user_data}{wagons}) { <tr> - <th scope="row">Rollmaterial</th> + <th scope="row"><%= L('journey.carriages') %></th> <td class="wagons"> %= include '_wagons', wagongroups => $journey->{user_data}{wagongroups}; </td> @@ -213,7 +235,7 @@ % } % elsif ($journey->{user_data} and $journey->{user_data}{wagons}) { <tr> - <th scope="row">Rollmaterial</th> + <th scope="row"><%= L('journey.carriages') %></th> <td class="wagons"> % for my $wagongroup (@{$journey->{user_data}{wagongroups} // []}) { Wagenverbund <%= $wagongroup %><br/> @@ -230,16 +252,17 @@ </tr> % } <tr> - <th scope="row">Route</th> - <td> + <th scope="row"><%= L('journey.route') %></th> + <td class="route"> % my $before = 1; % my $within = 0; % my $at_startstop = 0; + % my $i = 0; % for my $station (@{$journey->{route}}) { - % if (($station->[1] and $station->[1] == $journey->{from_eva}) or $station->[0] eq $journey->{from_name}) { + % if ($i == $journey->{route_dep_index}) { % $within = 1; $at_startstop = 1; % } - % elsif (($station->[1] and $station->[1] == $journey->{to_eva}) or $station->[0] eq $journey->{to_name}) { + % elsif ($i == $journey->{route_arr_index}) { % $within = 0; $at_startstop = 1; % } % else { @@ -247,10 +270,10 @@ % } <span style="color: #808080;"> % if ($before and $station->[2]{sched_dep}) { - %= $station->[2]{sched_dep}->strftime('%H:%M') + %= $station->[2]{sched_dep_dt}->strftime('%H:%M') % } % elsif (not $before and $station->[2]{sched_arr}) { - %= $station->[2]{sched_arr}->strftime('%H:%M') + %= $station->[2]{sched_arr_dt}->strftime('%H:%M') % } </span> % if ($at_startstop or $within) { @@ -259,6 +282,12 @@ % else { <span style="color: #808080;"><%= $station->[0] %></span> % } + % if ($station->[2]{isAdditional}) { + <span style="color: #808080;">⊕</span> + % } + % elsif ($station->[2]{isCancelled}) { + <span style="color: #808080;">∅</span> + % } % if ($journey->{edited} & 0x0010) { ∗ % } @@ -276,6 +305,7 @@ % $before = 0; % } <br/> + % $i += 1; % } </td> </tr> @@ -293,62 +323,99 @@ </div> </div> % if (not stash('readonly')) { - % if (stash('with_share')) { - <div class="row"> - <div class="col s12 m6 l6"> - </div> - <div class="col s12 m6 l6 center-align"> + <div class="row"> + <div class="col s12 m6 l4 center-align"> + <a class="btn waves-effect waves-light" href="<%= url_for('journey', id => $journey->{id}, format => 'json' ) %>"> + <i class="material-icons left" aria-hidden="true">file_download</i> + %= L('journey.export') + </a> + </div> + <div class="col s12 m6 l4 center-align"> + %= form_for '/journey/edit' => (method => 'POST') => begin + %= hidden_field 'journey_id' => param('journey_id') + <button class="btn waves-effect waves-light" type="submit" name="action" value="edit"> + <i class="material-icons left" aria-hidden="true">edit</i> + %= L('journey.edit') + </button> + %= end + </div> + <div class="col s12 m6 l4 center-align"> + % if (stash('with_share')) { <a class="btn waves-effect waves-light action-share" % if (stash('journey_visibility') eq 'public') { data-url="<%= url_for('public_journey', name => current_user()->{name}, id => $journey->{id} )->to_abs->scheme('https'); %>" % } % else { - data-url="<%= url_for('public_journey', name => current_user()->{name}, id => $journey->{id} )->to_abs->scheme('https'); %>?token=<%= $journey->{from_eva} %>-<%= $journey->{checkin_ts} % 337 %>-<%= $journey->{sched_dep_ts} %>" + data-url="<%= url_for('public_journey', name => current_user()->{name}, id => $journey->{id} )->to_abs->scheme('https'); %>?token=<%= $journey->{from_eva} %>-<%= $journey->{checkin_ts} % 337 %>-<%= int($journey->{sched_dep_ts}) %>" % } data-text="<%= stash('share_text') %>" > - <i class="material-icons left" aria-hidden="true">share</i> Teilen + <i class="material-icons left" aria-hidden="true">share</i> + %= L('journey.share') </a> - </div> - </div> - % } - <div class="row hide-on-small-only"> - <div class="col s12 m6 l6 center-align"> - <a class="waves-effect waves-light red btn action-delete" - data-id="<%= $journey->{id} %>" - data-checkin="<%= $journey->{checkin}->epoch %>" - data-checkout="<%= $journey->{checkout}->epoch %>"> - <i class="material-icons left">delete_forever</i> - Löschen - </a> - </div> - <div class="col s12 m6 l6 center-align"> - %= form_for '/journey/edit' => (method => 'POST') => begin - %= hidden_field 'journey_id' => param('journey_id') - <button class="btn waves-effect waves-light" type="submit" name="action" value="edit"> - <i class="material-icons left" aria-hidden="true">edit</i> - Bearbeiten - </button> - %= end + % } </div> </div> - <div class="row hide-on-med-and-up"> - <div class="col s12 m6 l6 center-align"> - %= form_for '/journey/edit' => (method => 'POST') => begin - %= hidden_field 'journey_id' => param('journey_id') - <button class="btn waves-effect waves-light" type="submit" name="action" value="edit"> - <i class="material-icons left" aria-hidden="true">edit</i> - Bearbeiten - </button> - %= end + % if ($journey->{polyline} or $journey->{km_route} > 0.1) { + <h2><%= L('journey.map-data') %> + % if ($journey->{edited} & 0x0040) { + ∗ + % } + </h2> + <div class="row"> + <div class="col s12 m6 l6 center-align"> + <a class="btn waves-effect waves-light" href="<%= url_for('polyline_download', id => $journey->{id}, format => 'json' ) %>"> + <i class="material-icons left" aria-label="<%= L('journey.map.download') %>">file_download</i> + JSON + </a> + </div> + <div class="col s12 m6 l6 center-align"> + <a class="btn waves-effect waves-light" href="<%= url_for('polyline_download', id => $journey->{id}, format => 'gpx' ) %>"> + <i class="material-icons left" aria-label="<%= L('journey.map.download') %>">file_download</i> + GPX + </a> + </div> </div> - <div class="col s12 m6 l6 center-align" style="margin-top: 1em;"> + <div class="row"> + <div class="col s12"> + %= L('journey.map.info.download') + %= L('journey.map.info.upload') + </div> + </div> + %= form_for '/polyline/set' => (method => 'post', enctype => 'multipart/form-data') => begin + %= csrf_field + %= hidden_field id => $journey->{id} + <div class="row"> + <div class="col s12"> + <div class="file-field input-field"> + <div class="btn"> + <span><i class="material-icons left" aria-label="<%= L('journey.map.upload') %>">file_upload</i> GPX</span> + <input type="file"> + </div> + <div class="file-path-wrapper"> + <input class="file-path validate" type="text" name="file"> + </div> + %= file_field 'file' + </div> + </div> + <div class="col s12 m6 center-align"> + %= submit_button L('journey.map.upload-full'), class => 'waves-effect waves-light btn', name => 'upload-full' + </div> + <div class="col s12 m6 center-align"> + %= submit_button L('journey.map.upload-partial'), class => 'waves-effect waves-light btn', name => 'upload-partial' + </div> + </div> + %= end + % } + <h2><%= L('journey.danger') %></h2> + <div class="row"> + <div class="col s12 m12 l12 center-align" style="margin-top: 1em;"> <a class="waves-effect waves-light red btn action-delete" data-id="<%= $journey->{id} %>" data-checkin="<%= $journey->{checkin}->epoch %>" data-checkout="<%= $journey->{checkout}->epoch %>"> <i class="material-icons left" aria-hidden="true">delete_forever</i> - Löschen + %= L('journey.delete') </a> </div> </div> diff --git a/templates/landingpage.html.ep b/templates/landingpage.html.ep index 5ca0e9e..ba0433f 100644 --- a/templates/landingpage.html.ep +++ b/templates/landingpage.html.ep @@ -55,22 +55,22 @@ %= 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> + <span class="card-title"><%= L('landingpage.greeting-prefix') %> <%= $user->{name} %><%= L('landingpage.greeting-suffix') %></span> + <p><%= L('landingpage.not-checked-in') %>.</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> + <a class="btn waves-effect waves-light btn-flat request"><%= L('landingpage.stop-geosearch') %></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> + <label for="station"><%= L('landingpage.manual-stop-entry') %></label> </div> </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 + %= L('landingpage.departures') </button> </div> </div> @@ -97,45 +97,36 @@ </div> </div> % } - <h2 style="margin-left: 0.75rem;">Letzte Fahrten</h2> - %= include '_history_trains', date_format => '%d.%m.%Y', journeys => [journeys->get(uid => $user->{id}, limit => 5, with_datetime => 1)]; + <h2 style="margin-left: 0.75rem;"><%= L('landingpage.latest-trips') %></h2> + %= include '_history_trains', date_format => L('landingpage.date-format'), 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 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. + %= L('landingpage.about') </p> <p> - Die Idee dazu kommt von <a - href="https://traewelling.de/">Träwelling</a>. + %= L('landingpage.traewelling.pre') + <a href="https://traewelling.de/">Träwelling</a> + %= L('landingpage.traewelling.post') </p> <p> - Features: + %= L('landingpage.features') <ul> - <li>Protokoll von Fahrplan- und Echtzeitdaten an Start- und - Zielbahnhof</li> - <li>Teilen von aktuellen und vergangenen Fahrten mit anderen Personen</li> - <li>Web-Hooks und <a href="/api">API</a> zum automatisierten Einchecken und Auslesen des aktuellen Status</li> - <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><%= L('landingpage.features.log') %></li> + <li><%= L('landingpage.features.share') %></li> + <li><%= L('landingpage.features.api-pre') %> <a href="/api"><%= L('landingpage.features.api-link') %></a> <%= L('landingpage.features.api-post') %></li> + <li><%= L('landingpage.features.stats') %></li> + <li><%= L('landingpage.features.passenger-rights') %></li> + <li><%= L('landingpage.features.public') %></li> </ul> </p> <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. Wer mag, kann auch den - <a href="https://finalrewind.org/projects/travelynx">Quelltext</a> - laden und eine eigene Instanz aufsetzen. + %= L('landingpage.disclaimer.lead') + %= L('landingpage.disclaimer.source-pre') + <a href="https://finalrewind.org/projects/travelynx"><%= L('landingpage.disclaimer.source-link') %></a> + %= L('landingpage.disclaimer.source-post') </p> </div> </div> @@ -144,9 +135,9 @@ </div> <div class="col s10 m10 l6 center-align"> % if (not app->config->{registration}{disabled}) { - <a href="/register" class="waves-effect waves-light btn"><i class="material-icons left" aria-hidden="true">add</i>Registrieren</a> + <a href="/register" class="waves-effect waves-light btn"><i class="material-icons left" aria-hidden="true">add</i><%= L('button.register') %></a> % } - <a href="/login" class="waves-effect waves-light btn"><i class="material-icons left" aria-hidden="true">account_circle</i>Anmelden</a> + <a href="/login" class="waves-effect waves-light btn"><i class="material-icons left" aria-hidden="true">account_circle</i><%= L('button.login') %></a> </div> <div class="col s1 m1 l3"> </div> diff --git a/templates/language.html.ep b/templates/language.html.ep new file mode 100644 index 0000000..0d14fe6 --- /dev/null +++ b/templates/language.html.ep @@ -0,0 +1,76 @@ +<h1><%= L('language.language') %></h1> +%= form_for '/account/language' => (method => 'POST') => begin + %= csrf_field + <div class="row"> + <div class="input-field col s12"> + <div> + <label> + %= radio_button language => 'none' + <span>–: <%= L('language.browser-default') %></span> + </label> + </div> + </div> + </div> + <div class="row"> + <div class="input-field col s12"> + <div> + <label> + %= radio_button language => 'de-DE' + <span>de-DE: Deutsch (hochdeutsch)</span> + </label> + </div> + </div> + </div> + <div class="row"> + <div class="input-field col s12"> + <div> + <label> + %= radio_button language => 'en-GB' + <span>en-GB: English (Great Britain)</span> + </label> + </div> + </div> + </div> + <div class="row"> + <div class="input-field col s12"> + <div> + <label> + %= radio_button language => 'fr-FR' + <span>fr-FR: français</span> + </label> + </div> + </div> + </div> + <div class="row"> + <div class="input-field col s12"> + <div> + <label> + %= radio_button language => 'hu-HU' + <span>hu-HU: magyar</span> + </label> + </div> + </div> + </div> + <div class="row"> + <div class="input-field col s12"> + <div> + <label> + %= radio_button language => 'pl-PL' + <span>pl-PL: Polski</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/layouts/default.html.ep b/templates/layouts/default.html.ep index e67f99c..81dfea0 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 = 'v92'; # asset version + % my $av = 'v99'; # 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"> @@ -90,7 +90,7 @@ </div> </li> % if ($acc) { - <li class="<%= navbar_class('/history') %>"><a href='/history' title="Vergangene Zugfahrten"><i class="material-icons" aria-label="Vergangene Zugfahrten">history</i></a></li> + <li class="<%= navbar_class('/history') %>"><a href='/history' title="Vergangene Fahrten"><i class="material-icons" aria-label="Vergangene Fahrten">history</i></a></li> <li class="<%= navbar_class('/account') %>"><a href="/account" title="Account"><i class="material-icons" aria-label="Account"><%= $acc->{notifications} ? 'notifications' : 'account_circle' %></i></a></li> % } % else { @@ -131,21 +131,21 @@ <div class="col s12 center-align grey-text"> <a href="/about">travelynx</a> v<%= $version // '???' %> <span style="margin-left: 0.5em; margin-right: 0.5em;">–</span> - <a href="/impressum">Impressum</a> + <a href="/impressum"><%= L('footer.imprint') %></a> <span style="margin-left: 0.5em; margin-right: 0.5em;">–</span> - <a href="/impressum">Datenschutz</a> + <a href="/impressum"><%= L('footer.privacy') %></a> <span style="margin-left: 0.5em; margin-right: 0.5em;">–</span> - <a href="/legend">Legende</a> + <a href="/legend"><%= L('footer.legend') %></a> </div> </div> <div class="row"> <div class="col s12 center-align grey-text config"> - Farbschema: - <a onClick="javascript:setTheme('light')">hell</a> + <%= L('footer.colour-scheme') %>: + <a onClick="javascript:setTheme('light')"><%= L('footer.colour-scheme.light') %></a> · - <a onClick="javascript:setTheme('dark')">dunkel</a> + <a onClick="javascript:setTheme('dark')"><%= L('footer.colour-scheme.dark') %></a> · - <a onClick="javascript:setTheme('default')">automatisch</a> + <a onClick="javascript:setTheme('default')"><%= L('footer.colour-scheme.auto') %></a> </div> </div> </div> diff --git a/templates/login.html.ep b/templates/login.html.ep index 3a9cc1f..21f14d3 100644 --- a/templates/login.html.ep +++ b/templates/login.html.ep @@ -75,7 +75,9 @@ </div> <div class="row"> <div class="col s12 m12 l12"> - Mit der Anmeldung stimmst du den <a href="/tos">Nutzungsbedingungen</a> zu. + %= L('login.accept-tos-pre') + <a href="/tos"><%= L('login.tos') %></a> + %= L('login.accept-tos-post') </div> </div> <div class="row"> @@ -83,7 +85,7 @@ </div> <div class="col s6 m6 l6 center-align"> <button class="btn waves-effect waves-light" type="submit" name="action" value="login"> - Anmelden + %= L('button.login') <i class="material-icons right">send</i> </button> </div> @@ -95,7 +97,7 @@ </div> <div class="col s6 m6 l6 center-align"> <a href="/recover"> - Passwort vergessen + %= L('login.forgot-password') </a> </div> <div class="col s3 m3 l3"> @@ -104,7 +106,7 @@ % if (app->config->{registration}{disabled}) { <div class="row" style="margin-top: 2em;"> <div class="col s12 center-align"> - <em>Diese Instanz erlaubt derzeit keine Registrierung neuer Accounts</em> + <em><%= L('login.registration-disabled') %></em> </div> </div> % } diff --git a/templates/passengerrights.html.ep b/templates/passengerrights.html.ep index c189657..bf9e5de 100644 --- a/templates/passengerrights.html.ep +++ b/templates/passengerrights.html.ep @@ -3,13 +3,13 @@ <div class="col s12"> <p> Ab 60 Minuten Verspätung am Ziel besteht in einigen Fällen ein - Entschädigungsanspruch gegenüber dem Eisenbahnverkehrsunternehmen. + Entschädigungsanspruch gegenüber dem Verkehrsunternehmen. Dieser kann mit dem Fahrgastrechteformular oder online geltend gemacht werden. </p> <p> - Die folgenden Zugfahrten sind wahrscheinliche Kandidaten dafür. - Details zur jeweiligen Zugfahrt sind bereits im Formular eingetragen. + Die folgenden Fahrten sind wahrscheinliche Kandidaten dafür. + Details zur jeweiligen Fahrt sind bereits im Formular eingetragen. </p> </div> </div> @@ -20,7 +20,7 @@ <thead> <tr> <th>Datum</th> - <th>Zug</th> + <th>Fahrt</th> <th>Grund</th> <th>Formular</th> </tr> @@ -79,7 +79,7 @@ <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. + einzureichen. Die folgenden Fahrten sind Kandidaten dafür. Fahrten mit einer Verspätung von 60 Minuten oder mehr werden hier nicht aufgeführt. </p> @@ -92,7 +92,7 @@ <thead> <tr> <th>Datum</th> - <th>Zug</th> + <th>Fahrt</th> <th>Verspätung</th> </tr> </thead> diff --git a/templates/polyline.gpx.ep b/templates/polyline.gpx.ep new file mode 100644 index 0000000..a243926 --- /dev/null +++ b/templates/polyline.gpx.ep @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<gpx + xmlns="http://www.topografix.com/GPX/1/1" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd" + version="1.1" + creator="travelynx <%= $version %>"> + <trk> + <name><%= $name %></name> + <trkseg> + % for my $entry (@{$polyline // []}) { + <trkpt lon="<%= $entry->[0] %>" lat="<%= $entry->[1] %>"> + % if ($entry->[2]) { + <name><%= $entry->[2] %></name> + % } + </trkpt> + % } + </trkseg> + </trk> +</gpx> diff --git a/templates/register.html.ep b/templates/register.html.ep index f9a486a..e7064da 100644 --- a/templates/register.html.ep +++ b/templates/register.html.ep @@ -8,27 +8,29 @@ <div class="input-field col l6 m12 s12"> <i class="material-icons prefix">account_circle</i> %= text_field 'user', id => 'account', class => 'validate', required => undef, pattern => '[0-9a-zA-Z_-]+', maxlength => 60, autocomplete => 'username' - <label for="account">Name (alphanumerisch)</label> + <label for="account"><%= L('register.name') %></label> </div> <div class="input-field col l6 m12 s12"> <i class="material-icons prefix">email</i> %= email_field 'email', id => 'email', class => 'validate', required => undef, maxlength => 250 - <label for="email">Mail-Adresse</label> + <label for="email"><%= L('register.mail') %></label> </div> <div class="input-field col l6 m12 s12"> <i class="material-icons prefix">lock</i> %= password_field 'password', id => 'password', class => 'validate', required => undef, minlength => 8, maxlength => 10000, autocomplete => 'new-password' - <label for="password">Passwort</label> + <label for="password"><%= L('register.password') %></label> </div> <div class="input-field col l6 m12 s12"> <i class="material-icons prefix">lock</i> %= password_field 'password2', id => 'password2', class => 'validate', required => undef, minlength => 8, maxlength => 10000, autocomplete => 'new-password' - <label for="password2">Passwort wiederholen</label> + <label for="password2"><%= L('register.repeat-password') %></label> </div> </div> <div class="row"> <div class="col s12 m12 l12"> - Mit deiner Registrierung stimmst du den <a href="/tos">Nutzungsbedingungen</a> zu. + %= L('register.accept-tos-pre') + <a href="/tos"><%= L('register.tos') %></a> + %= L('register.accept-tos-post') </div> </div> <div class="row"> @@ -36,7 +38,7 @@ </div> <div class="col s6 m6 l6 center-align"> <button class="btn waves-effect waves-light" type="submit" name="action" value="register"> - Registrieren + %= L('button.register') <i class="material-icons right">send</i> </button> </div> @@ -47,9 +49,7 @@ <div class="row"> <div class="col s12"> <p> - Nach der Registrierung wird ein für 48 Stunden gültiger - Bestätigungslink an die angegebene Mail-Adresse geschickt. Eine - Anmeldung ist erst nach Bestätigung der Mail-Adresse möglich. + %= L('register.expect-confirmation-link') </p> <p> Die Mail-Adresse wird ausschließlich zur Bestätigung der Anmeldung, diff --git a/templates/select_backend.html.ep b/templates/select_backend.html.ep index e3db44d..999a689 100644 --- a/templates/select_backend.html.ep +++ b/templates/select_backend.html.ep @@ -11,6 +11,20 @@ % if (stash('redirect_to')) { %= hidden_field 'redirect_to' => stash('redirect_to') % } + % if (@{stash('frequent') // []}) { + <div class="row"> + <div class="col s12"> + <h3>Häufig genutzt</h3> + <p style="text-align: justify;"> + Die folgenden Backends wurden innerhalb der letzten vier + Monate für Checkins verwendet. + </p> + </div> + </div> + % for my $backend (@{ stash('frequent') // [] }) { + %= include '_backend_line', user => $user, backend => $backend + % } + % } % if (@{stash('suggestions') // []}) { <div class="row"> <div class="col s12"> |
