diff options
28 files changed, 652 insertions, 253 deletions
@@ -10,7 +10,7 @@ requires 'List::UtilsBy'; requires 'LWP::UserAgent'; requires 'LWP::Protocol::https'; requires 'Mojolicious'; -requires 'Travel::Status::DE::DBWagenreihung', '0.12'; +requires 'Travel::Status::DE::DBWagenreihung', '== 0.14'; requires 'Travel::Status::DE::HAFAS', '>= 5.06'; requires 'Travel::Status::DE::IRIS'; requires 'XML::LibXML'; diff --git a/cpanfile.snapshot b/cpanfile.snapshot index c93f1c9..3afd2e4 100644 --- a/cpanfile.snapshot +++ b/cpanfile.snapshot @@ -156,6 +156,37 @@ DISTRIBUTIONS perl 5.008001 strict 0 warnings 0 + CPAN-Meta-Requirements-2.143 + pathname: R/RJ/RJBS/CPAN-Meta-Requirements-2.143.tar.gz + provides: + CPAN::Meta::Requirements 2.143 + CPAN::Meta::Requirements::Range 2.143 + requirements: + B 0 + Carp 0 + ExtUtils::MakeMaker 6.17 + perl 5.010000 + strict 0 + version 0.88 + warnings 0 + CPAN-Requirements-Dynamic-0.001 + pathname: L/LE/LEONT/CPAN-Requirements-Dynamic-0.001.tar.gz + provides: + CPAN::Requirements::Dynamic 0.001 + requirements: + CPAN::Meta::Prereqs 0 + CPAN::Meta::Requirements::Range 0 + Carp 0 + ExtUtils::Config 0 + ExtUtils::HasCompiler 0 + ExtUtils::MakeMaker 0 + IPC::Cmd 0 + Module::Metadata 0 + Parse::CPAN::Meta 0 + Perl::OSType 0 + perl 5.006 + strict 0 + warnings 0 Cache-2.11 pathname: S/SH/SHLOMIF/Cache-2.11.tar.gz provides: @@ -354,15 +385,15 @@ DISTRIBUTIONS parent 0 strict 0 warnings 0 - DateTime-Locale-1.40 - pathname: D/DR/DROLSKY/DateTime-Locale-1.40.tar.gz + DateTime-Locale-1.42 + pathname: D/DR/DROLSKY/DateTime-Locale-1.42.tar.gz provides: - DateTime::Locale 1.40 - DateTime::Locale::Base 1.40 - DateTime::Locale::Catalog 1.40 - DateTime::Locale::Data 1.40 - DateTime::Locale::FromData 1.40 - DateTime::Locale::Util 1.40 + DateTime::Locale 1.42 + DateTime::Locale::Base 1.42 + DateTime::Locale::Catalog 1.42 + DateTime::Locale::Data 1.42 + DateTime::Locale::FromData 1.42 + DateTime::Locale::Util 1.42 requirements: Carp 0 Dist::CheckConflicts 0.02 @@ -811,13 +842,16 @@ DISTRIBUTIONS requirements: ExtUtils::MakeMaker 6.17 perl 5.006001 - ExtUtils-Config-0.008 - pathname: L/LE/LEONT/ExtUtils-Config-0.008.tar.gz + ExtUtils-Config-0.009 + pathname: L/LE/LEONT/ExtUtils-Config-0.009.tar.gz provides: - ExtUtils::Config 0.008 + ExtUtils::Config 0.009 + ExtUtils::Config::MakeMaker 0.009 requirements: Data::Dumper 0 - ExtUtils::MakeMaker 6.30 + ExtUtils::MakeMaker 0 + ExtUtils::MakeMaker::Config 0 + perl 5.006 strict 0 warnings 0 ExtUtils-Depends-0.8001 @@ -830,6 +864,23 @@ DISTRIBUTIONS File::Spec 0 IO::File 0 perl 5.006 + ExtUtils-HasCompiler-0.024 + pathname: L/LE/LEONT/ExtUtils-HasCompiler-0.024.tar.gz + provides: + ExtUtils::HasCompiler 0.024 + requirements: + Carp 0 + DynaLoader 0 + Exporter 0 + ExtUtils::MakeMaker 0 + ExtUtils::Mksymlists 0 + File::Basename 0 + File::Spec::Functions 0 + File::Temp 0 + base 0 + perl 5.006 + strict 0 + warnings 0 ExtUtils-Helpers-0.026 pathname: L/LE/LEONT/ExtUtils-Helpers-0.026.tar.gz provides: @@ -848,10 +899,10 @@ DISTRIBUTIONS perl 5.006 strict 0 warnings 0 - ExtUtils-InstallPaths-0.012 - pathname: L/LE/LEONT/ExtUtils-InstallPaths-0.012.tar.gz + ExtUtils-InstallPaths-0.013 + pathname: L/LE/LEONT/ExtUtils-InstallPaths-0.013.tar.gz provides: - ExtUtils::InstallPaths 0.012 + ExtUtils::InstallPaths 0.013 requirements: Carp 0 ExtUtils::Config 0.002 @@ -1286,12 +1337,13 @@ DISTRIBUTIONS Text::ParseWords 0 perl 5.006001 version 0.87 - Module-Build-Tiny-0.047 - pathname: L/LE/LEONT/Module-Build-Tiny-0.047.tar.gz + Module-Build-Tiny-0.048 + pathname: L/LE/LEONT/Module-Build-Tiny-0.048.tar.gz provides: - Module::Build::Tiny 0.047 + Module::Build::Tiny 0.048 requirements: CPAN::Meta 0 + CPAN::Requirements::Dynamic 0 DynaLoader 0 Exporter 5.57 ExtUtils::CBuilder 0 @@ -1450,16 +1502,6 @@ DISTRIBUTIONS IO::Socket::IP 0.37 Sub::Util 1.41 perl 5.016 - Mojolicious-Plugin-I18N-1.6 - pathname: S/SH/SHARIFULN/Mojolicious-Plugin-I18N-1.6.tar.gz - provides: - Mojolicious::Plugin::I18N 1.6 - requirements: - I18N::LangTags 0.35 - Module::Build 0.42 - Mojolicious 5 - Test::More 0 - perl 5.010001 Mozilla-CA-20240313 pathname: L/LW/LWP/Mozilla-CA-20240313.tar.gz provides: @@ -1833,12 +1875,13 @@ DISTRIBUTIONS TimeDate 1.21 requirements: ExtUtils::MakeMaker 0 - Travel-Status-DE-DBWagenreihung-0.11 - pathname: D/DE/DERF/Travel-Status-DE-DBWagenreihung-0.11.tar.gz + Travel-Status-DE-DBWagenreihung-0.14 + pathname: D/DE/DERF/Travel-Status-DE-DBWagenreihung-0.14.tar.gz provides: - Travel::Status::DE::DBWagenreihung 0.11 - Travel::Status::DE::DBWagenreihung::Section 0.11 - Travel::Status::DE::DBWagenreihung::Wagon 0.11 + Travel::Status::DE::DBWagenreihung 0.14 + Travel::Status::DE::DBWagenreihung::Group 0.14 + Travel::Status::DE::DBWagenreihung::Section 0.14 + Travel::Status::DE::DBWagenreihung::Wagon 0.14 requirements: Carp 0 Class::Accessor 0 @@ -1852,18 +1895,18 @@ DISTRIBUTIONS Test::Pod 0 Travel::Status::DE::IRIS 1.2 perl v5.20.0 - Travel-Status-DE-DeutscheBahn-5.06 - pathname: D/DE/DERF/Travel-Status-DE-DeutscheBahn-5.06.tar.gz - provides: - Travel::Status::DE::DeutscheBahn 5.06 - Travel::Status::DE::HAFAS 5.06 - Travel::Status::DE::HAFAS::Journey 5.06 - Travel::Status::DE::HAFAS::Location 5.06 - Travel::Status::DE::HAFAS::Message 5.06 - Travel::Status::DE::HAFAS::Polyline 5.06 - Travel::Status::DE::HAFAS::Product 5.06 - Travel::Status::DE::HAFAS::Stop 5.06 - Travel::Status::DE::HAFAS::StopFinder 5.06 + Travel-Status-DE-DeutscheBahn-6.03 + pathname: D/DE/DERF/Travel-Status-DE-DeutscheBahn-6.03.tar.gz + provides: + Travel::Status::DE::DeutscheBahn 6.03 + Travel::Status::DE::HAFAS 6.03 + Travel::Status::DE::HAFAS::Journey 6.03 + Travel::Status::DE::HAFAS::Location 6.03 + Travel::Status::DE::HAFAS::Message 6.03 + Travel::Status::DE::HAFAS::Polyline 6.03 + Travel::Status::DE::HAFAS::Product 6.03 + Travel::Status::DE::HAFAS::Stop 6.03 + Travel::Status::DE::HAFAS::StopFinder 6.03 requirements: Carp 0 Class::Accessor 0.16 diff --git a/lib/DBInfoscreen.pm b/lib/DBInfoscreen.pm index c33a703..c784e96 100644 --- a/lib/DBInfoscreen.pm +++ b/lib/DBInfoscreen.pm @@ -279,15 +279,18 @@ sub startup { $r->get('/_ajax_mapinfo/:tripid/:lineno')->to('map#ajax_route'); $r->get('/map/:tripid/:lineno')->to('map#route'); - $r->get( '/z/:train/*station' => 'train_at_station' ) - ->to('stationboard#station_train_details'); - $r->get( '/z/:train' => 'train' )->to('stationboard#train_details'); + $r->get( '/z/:train/*station' => [ format => [ 'html', 'json' ] ] ) + ->to( 'stationboard#station_train_details', format => undef ) + ->name('train_at_station'); + $r->get( '/z/:train' => [ format => [ 'html', 'json' ] ] ) + ->to( 'stationboard#train_details', format => undef )->name('train'); $self->defaults( layout => 'app' ); $r->get('/')->to('stationboard#handle_request'); $r->get('/multi/*station')->to('stationboard#handle_request'); - $r->get('/*station')->to('stationboard#handle_request'); + $r->get( '/*station' => [ format => [ 'html', 'json' ] ] ) + ->to( 'stationboard#handle_request', format => undef ); $self->types->type( json => 'application/json; charset=utf-8' ); diff --git a/lib/DBInfoscreen/Controller/Stationboard.pm b/lib/DBInfoscreen/Controller/Stationboard.pm index 305035c..b64c661 100644 --- a/lib/DBInfoscreen/Controller/Stationboard.pm +++ b/lib/DBInfoscreen/Controller/Stationboard.pm @@ -469,7 +469,12 @@ sub handle_request { # (or used by) marudor.de, it was renamed to 'json'. Many clients won't # notice this for year to come, so we make sure mode=marudor still works as # intended. - if ( $template eq 'marudor' ) { + if ( + $template eq 'marudor' + or ( $self->req->headers->accept + and $self->req->headers->accept eq 'application/json' ) + ) + { $template = 'json'; } @@ -518,12 +523,6 @@ sub handle_request { ( $status->station ? $status->station->{name} : $station ), }; - if ( $status->station and $status->station->{names} ) { - $data->{station_name} - = List::Util::reduce { length($a) < length($b) ? $a : $b } - @{ $status->station->{names} }; - } - if ( not @{ $data->{results} } and $template eq 'json' ) { $self->handle_no_results_json( $station, $data, $api_version ); return; @@ -750,8 +749,55 @@ sub render_train { from_json => $wr_json ); $departure->{wr} = $wr; $departure->{wr_text} = join( q{ • }, - map { $_->{short} } - grep { $_->{short} } $wr->train_descriptions ); + map { $_->desc_short } + grep { $_->desc_short } $wr->groups ); + my $first = 0; + for my $group ( $wr->groups ) { + my $had_entry = 0; + for my $wagon ( $group->wagons ) { + if ( + not( $wagon->is_locomotive + or $wagon->is_powercar ) + ) + { + my $class; + if ($first) { + push( + @{ $departure->{wr_preview} }, + [ '•', 'meta' ] + ); + $first = 0; + } + my $entry; + if ( $wagon->is_closed ) { + $entry = 'X'; + $class = 'closed'; + } + else { + $entry = $wagon->number + || ( + $wagon->type =~ m{AB} ? '½' + : $wagon->type =~ m{A} ? '1.' + : $wagon->type =~ m{B} ? '2.' + : $wagon->type + ); + } + if ( + $group->train_no ne $departure->{train_no} ) + { + $class = 'otherno'; + } + push( + @{ $departure->{wr_preview} }, + [ $entry, $class ] + ); + $had_entry = 1; + } + } + if ($had_entry) { + $first = 1; + } + } }; $departure->{wr_text} ||= 'Wagen'; return; @@ -827,10 +873,11 @@ sub render_train { } if ($direction) { - $departure->{direction} = $direction; + $departure->{wr_direction} = $direction; + $departure->{wr_direction_num} = $direction eq 'l' ? 0 : 100; } elsif ( $platform_info->{direction} ) { - $departure->{direction} = 'a' . $platform_info->{direction}; + $departure->{wr_direction} = 'a' . $platform_info->{direction}; } return; @@ -856,9 +903,9 @@ sub render_train { sub { my ( $route, $journey ) = @_; - $departure->{trip_id} = $journey->id; - $departure->{operator} = $journey->operator; - $departure->{date} = $route->[0]{sched_dep} // $route->[0]{dep}; + $departure->{trip_id} = $journey->id; + $departure->{operators} = [ $journey->operators ]; + $departure->{date} = $route->[0]{sched_dep} // $route->[0]{dep}; # Use HAFAS route as source of truth; ignore IRIS data $departure->{route_pre_diff} = []; @@ -874,6 +921,16 @@ sub render_train { = [ $load->{FIRST}, $load->{SECOND} ]; } } + $departure->{tz_offset} = $route->[$i]{tz_offset}; + $departure->{local_dt_da} = $route->[$i]{local_dt_da}; + $departure->{local_sched_arr} + = $route->[$i]{local_sched_arr}; + $departure->{local_sched_dep} + = $route->[$i]{local_sched_dep}; + $departure->{is_annotated} = $route->[$i]{is_annotated}; + $departure->{prod_name} = $route->[$i]{prod_name}; + $departure->{direction} = $route->[$i]{direction}; + $departure->{operator} = $route->[$i]{operator}; last; } } @@ -933,27 +990,36 @@ sub render_train { # Defer rendering until all requests have completed Mojo::Promise->all(@requests)->then( sub { - $self->render( - $template // '_train_details', - description => sprintf( - '%s %s%s%s nach %s', - $departure->{train_type}, - $departure->{train_line} // $departure->{train_no}, - $departure->{origin} ? ' von ' : q{}, - $departure->{origin} // q{}, - $departure->{destination} // 'unbekannt' - ), - departure => $departure, - linetype => $linetype, - dt_now => DateTime->now( time_zone => 'Europe/Berlin' ), - station_name => $station_name, - nav_link => - $self->url_for( 'station', station => $station_name )->query( - { - detailed => $self->param('detailed'), - hafas => $self->param('hafas') - } - ), + $self->respond_to( + json => { + json => { + departure => $departure, + station_name => $station_name, + }, + }, + any => { + template => $template // '_train_details', + description => sprintf( + '%s %s%s%s nach %s', + $departure->{train_type}, + $departure->{train_line} // $departure->{train_no}, + $departure->{origin} ? ' von ' : q{}, + $departure->{origin} // q{}, + $departure->{destination} // 'unbekannt' + ), + departure => $departure, + linetype => $linetype, + dt_now => DateTime->now( time_zone => 'Europe/Berlin' ), + station_name => $station_name, + nav_link => + $self->url_for( 'station', station => $station_name ) + ->query( + { + detailed => $self->param('detailed'), + hafas => $self->param('hafas') + } + ), + }, ); } )->wait; @@ -969,6 +1035,10 @@ sub station_train_details { delete $self->stash->{layout}; } + if ( $station =~ s{ [.] json $ }{}x ) { + $self->stash( format => 'json' ); + } + my %opt = ( cache_iris_main => $self->app->cache_iris_main, cache_iris_rt => $self->app->cache_iris_rt, @@ -1076,11 +1146,20 @@ sub station_train_details { )->catch( sub { my ($errstr) = @_; - $self->render( - 'landingpage', - error => - "Keine Abfahrt von $train_no in $station gefunden: $errstr", - status => 404, + $self->respond_to( + json => { + json => { + error => +"Keine Abfahrt von $train_no in $station gefunden: $errstr", + }, + status => 404, + }, + any => { + template => 'landingpage', + error => +"Keine Abfahrt von $train_no in $station gefunden: $errstr", + status => 404, + }, ); return; } @@ -1099,8 +1178,6 @@ sub train_details { delete $self->stash->{layout}; } - my $api_version = $Travel::Status::DE::IRIS::VERSION; - $self->stash( departures => [] ); $self->stash( title => 'DBF' ); @@ -1130,7 +1207,10 @@ sub train_details { } my $service = 'DB'; - if ( $hafas ne '1' and Travel::Status::DE::HAFAS::get_service($hafas) ) { + if ( $hafas + and $hafas ne '1' + and Travel::Status::DE::HAFAS::get_service($hafas) ) + { $opt{service} = $hafas; } @@ -1166,19 +1246,26 @@ sub train_details { $res->{trip_id} = $journey->id; $res->{date} = $route->[0]{sched_dep} // $route->[0]{dep}; - if ( not $res->{train_type} ) { - my $train_type = $res->{train_type} = $journey->type // q{}; - my $train_no = $res->{train_no} = $journey->number // q{}; - $res->{train_line} = $journey->line_no // q{}; - $self->stash( title => "${train_type} ${train_no}" ); + my $product = $journey->product; + + if ( my $req_name = $self->param('highlight') ) { + if ( my $p = $journey->product_at($req_name) ) { + $product = $p; + } } - if ( not defined $journey->class ) { + my $train_type = $res->{train_type} = $product->type // q{}; + my $train_no = $res->{train_no} = $product->number // q{}; + $res->{train_line} = $product->line_no // q{}; + $self->stash( title => $train_type . ' ' + . ( $train_no || $res->{train_line} ) ); + + if ( not defined $product->class ) { $linetype = 'ext'; } else { my $prod - = $self->class_to_product($hafas_obj)->{ $journey->class } + = $self->class_to_product($hafas_obj)->{ $product->class } // q{}; if ( $prod eq 'ice' or $prod eq 'ic_ec' ) { $linetype = 'fern'; @@ -1199,7 +1286,7 @@ sub train_details { $res->{origin} = $journey->route_start; $res->{destination} = $journey->route_end; - $res->{operator} = $journey->operator; + $res->{operators} = [ $journey->operators ]; $res->{route_post_diff} = $route; @@ -1243,7 +1330,15 @@ sub train_details { = $station_info->{dep_cancelled}; $res->{is_cancelled} = $res->{arrival_is_cancelled} || $res->{arrival_is_cancelled}; - $res->{platform} = $station_info->{platform}; + $res->{tz_offset} = $station_info->{tz_offset}; + $res->{local_dt_da} = $station_info->{local_dt_da}; + $res->{local_sched_arr} = $station_info->{local_sched_arr}; + $res->{local_sched_dep} = $station_info->{local_sched_dep}; + $res->{is_annotated} = $station_info->{is_annotated}; + $res->{prod_name} = $station_info->{prod_name}; + $res->{direction} = $station_info->{direction}; + $res->{operator} = $station_info->{operator}; + $res->{platform} = $station_info->{platform}; $res->{scheduled_platform} = $station_info->{sched_platform}; } @@ -1281,34 +1376,52 @@ sub train_details { $res->{details} = [@him_details]; } - $self->render( - $self->param('ajax') ? '_train_details' : 'train_details', - description => sprintf( - '%s %s%s%s nach %s', - $res->{train_type}, - $res->{train_line} // $res->{train_no}, - $res->{origin} ? ' von ' : q{}, - $res->{origin} // q{}, - $res->{destination} // 'unbekannt' - ), - departure => $res, - linetype => $linetype, - dt_now => DateTime->now( time_zone => 'Europe/Berlin' ), + $self->respond_to( + json => { + json => { + journey => $journey, + }, + }, + any => { + template => $self->param('ajax') + ? '_train_details' + : 'train_details', + description => sprintf( + '%s %s%s%s nach %s', + $res->{train_type}, + $res->{train_line} // $res->{train_no}, + $res->{origin} ? ' von ' : q{}, + $res->{origin} // q{}, + $res->{destination} // 'unbekannt' + ), + departure => $res, + linetype => $linetype, + dt_now => DateTime->now( time_zone => 'Europe/Berlin' ), + }, ); } )->catch( sub { my ($e) = @_; if ($e) { - $self->render( - 'exception', - message => $e, - exception => undef, - snapshot => {} + $self->respond_to( + json => { + json => { + error => $e, + }, + status => 500, + }, + any => { + template => 'exception', + message => $e, + exception => undef, + snapshot => {}, + status => 500, + }, ); } else { - $self->render('not_found'); + $self->render( 'not_found', status => 404 ); } } )->wait; @@ -1818,14 +1931,23 @@ sub handle_result { sub stations_by_coordinates { my $self = shift; - my $lon = $self->param('lon'); - my $lat = $self->param('lat'); + my $lon = $self->param('lon'); + my $lat = $self->param('lat'); + my $hafas = $self->param('hafas'); if ( not $lon or not $lat ) { $self->render( json => { error => 'Invalid lon/lat received' } ); return; } + my $service = 'DB'; + if ( $hafas + and $hafas ne '1' + and Travel::Status::DE::HAFAS::get_service($hafas) ) + { + $service = $hafas; + } + $self->render_later; my @iris = map { @@ -1846,6 +1968,7 @@ sub stations_by_coordinates { Travel::Status::DE::HAFAS->new_p( promise => 'Mojo::Promise', user_agent => $self->ua, + service => $service, geoSearch => { lat => $lat, lon => $lon @@ -1858,7 +1981,7 @@ sub stations_by_coordinates { name => $_->name, eva => $_->eva, distance => $_->distance_m / 1000, - hafas => 1 + hafas => $service, } } $hafas->results; if ( @hafas > 10 ) { diff --git a/lib/DBInfoscreen/Controller/Wagenreihung.pm b/lib/DBInfoscreen/Controller/Wagenreihung.pm index 1708285..03a607d 100644 --- a/lib/DBInfoscreen/Controller/Wagenreihung.pm +++ b/lib/DBInfoscreen/Controller/Wagenreihung.pm @@ -72,7 +72,7 @@ sub wagenreihung { e => $exit_side ? substr( $exit_side, 0, 1 ) : '', tt => $wr->train_type, tn => $train, - s => $wr->station_name, + s => $wr->station->{name}, p => $wr->platform }; @@ -168,7 +168,7 @@ sub wagenreihung { 'wagenreihung', description => sprintf( 'Ist-Wagenreihung %s in %s', - $title, $wr->station_name + $title, $wr->station->{name} ), wr_error => undef, title => $title, @@ -184,7 +184,7 @@ sub wagenreihung { my ($err) = @_; $self->handle_wagenreihung_error( $train, - $err->{error}->{msg} // "Unbekannter Fehler" ); + $err->{error}->{msg} // $err // "Unbekannter Fehler" ); return; } )->wait; diff --git a/lib/DBInfoscreen/Helper/HAFAS.pm b/lib/DBInfoscreen/Helper/HAFAS.pm index 149bfc9..cdb84f0 100644 --- a/lib/DBInfoscreen/Helper/HAFAS.pm +++ b/lib/DBInfoscreen/Helper/HAFAS.pm @@ -105,7 +105,67 @@ sub get_route_p { my $journey = $hafas->result; my @ret; my $station_is_past = 1; + + my $num_names = 0; + my $prev_name = q{}; + my $num_directions = 0; + my $prev_direction = q{}; + my $num_operators = 0; + my $prev_operator = q{}; + for my $stop ( $journey->route ) { + my $prod = $stop->prod_dep // $stop->prod_arr; + if ( $prod and $prod->name and $prod->name ne $prev_name ) { + $num_names++; + $prev_name = $prod->name; + } + if ( $prod + and $prod->operator + and $prod->operator ne $prev_operator ) + { + $num_operators++; + $prev_operator = $prod->operator; + } + if ( $stop->direction and $stop->direction ne $prev_direction ) + { + $num_directions++; + $prev_direction = $stop->direction; + } + } + + $prev_name = q{}; + $prev_direction = q{}; + $prev_operator = q{}; + + for my $stop ( $journey->route ) { + + my $prod = $stop->prod_dep // $stop->prod_arr; + my %annotation; + if ( $num_names > 1 + and $prod + and $prod->name + and $prod->name ne $prev_name ) + { + $prev_name = $annotation{prod_name} = $prod->name; + } + if ( $num_operators > 1 + and $prod + and $prod->operator + and $prod->operator ne $prev_operator ) + { + $prev_operator = $annotation{operator} = $prod->operator; + } + if ( $num_directions > 1 + and $stop->direction + and $stop->direction ne $prev_direction ) + { + $prev_direction = $annotation{direction} = $stop->direction; + } + + if (%annotation) { + $annotation{is_annotated} = 1; + } + push( @ret, { @@ -119,6 +179,7 @@ sub get_route_p { dep_delay => $stop->dep_delay, arr_cancelled => $stop->arr_cancelled, dep_cancelled => $stop->dep_cancelled, + tz_offset => $stop->tz_offset, platform => $stop->platform, sched_platform => $stop->sched_platform, load => $stop->load, @@ -128,6 +189,7 @@ sub get_route_p { and ( $stop->dep_cancelled or not $stop->sched_dep ) ), + %annotation, } ); if ( @@ -142,6 +204,32 @@ sub get_route_p { $station_is_past = 0; } $ret[-1]{isPast} = $station_is_past; + if ( $stop->tz_offset ) { + if ( $stop->sched_arr ) { + $ret[-1]{local_sched_arr} + = $stop->sched_arr->clone->add( + minutes => $stop->tz_offset ); + } + if ( $stop->sched_dep ) { + $ret[-1]{local_sched_dep} + = $stop->sched_dep->clone->add( + minutes => $stop->tz_offset ); + } + if ( $stop->rt_arr ) { + $ret[-1]{local_rt_arr} = $stop->rt_arr->clone->add( + minutes => $stop->tz_offset ); + } + if ( $stop->rt_dep ) { + $ret[-1]{local_rt_dep} = $stop->rt_dep->clone->add( + minutes => $stop->tz_offset ); + } + $ret[-1]{local_dt_ad} = $ret[-1]{local_rt_arr} + // $ret[-1]{local_sched_arr} // $ret[-1]{local_rt_dep} + // $ret[-1]{local_sched_dep}; + $ret[-1]{local_dt_da} = $ret[-1]{local_rt_dep} + // $ret[-1]{local_sched_dep} // $ret[-1]{local_rt_arr} + // $ret[-1]{local_sched_arr}; + } } $promise->resolve( \@ret, $journey, $hafas ); diff --git a/public/static/css/dark.min.css b/public/static/css/dark.min.css index b489a5a..f9b5b35 100644 --- a/public/static/css/dark.min.css +++ b/public/static/css/dark.min.css @@ -1 +1 @@ -body{margin:0;color:#fff;background-color:#101010}html{font-family:"Arimo", "Arial", Sans-Serif}a{color:#99f;text-decoration:none}.visually-hidden{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}p,div.about,div.config,div.input-field,div.notes{max-width:94%;margin-left:auto;margin-right:auto}p{text-align:justify}div.content{width:100%;margin:0}.copyright{margin-top:1em;color:#999;clear:both}.wagonorder{position:relative;width:100%;height:100ex}.wagonorder.exit-unknown .section{left:1em;width:2em}.wagonorder.exit-unknown .wagon{left:3em;min-width:6em}.wagonorder.exit-unknown .details{left:10em;right:0em}.wagonorder.exit-left .section{left:1em;width:2em;background-color:#222}.wagonorder.exit-left .wagon{left:3em;min-width:6em}.wagonorder.exit-left .details{left:10em;right:0em}.wagonorder.exit-right .section{right:1em;width:2em;background-color:#222}.wagonorder.exit-right .wagon{right:3em;min-width:6em}.wagonorder.exit-right .details{right:10em;left:0em;text-align:right}.wagonorder .section{position:absolute;text-align:center}.wagonorder .wagon{position:absolute;border:1px solid #999;padding-left:0.2em;padding-right:0.2em}.wagonorder .wagon .material-icons{color:#bbb}.wagonorder .wagon .direction{position:absolute;left:0.2em;bottom:0;right:0;text-align:center;color:#bbb}.wagonorder .wagon~.wagon{border-top:none}.wagonorder .firstclass{background-color:#330}.wagonorder .powercar{background-color:#222}.wagonorder .closed{background-color:#222}.wagonorder .nondestwagon{border-style:dashed}.wagonorder .details{position:absolute;padding-top:0.5ex}.wagonorder .details .type{display:inline-block;width:5em;color:#bbb}.wagonorder .details a.type{color:#99f}.wagonorder .details .uicunknown{color:#999}.wagonorder .details .uicexchange{margin-right:0.2em;color:#999}.wagonorder .details .uiccountry{margin-right:0.2em;color:#999}.wagonorder .details .uic5{margin-right:0.2em;color:#999}.wagonorder .details .uic56{color:#bbb;font-weight:bold}.wagonorder .details .uic78{margin-right:0.2em;color:#bbb;font-weight:bold}.wagonorder .details .uic78::before{content:"-"}.wagonorder .details .uictype{margin-right:0.2em;color:#bbb;font-weight:bold}.wagonorder .details .uicno{color:#bbb}.wagonorder .details .uiccheck{color:#999}.wagonorder .details .uiccheck::before{content:"-"}.singlewagon .sign-left{float:left;padding-left:5%}.singlewagon .sign-right{float:right;padding-right:5%}.singlewagon .sign-center{text-align:center}.singlewagon .platform{text-align:center;background-color:#444;font-weight:bold;padding-top:0.5em;padding-bottom:0.5em}.singlewagon img.wagonfile{width:100%;margin-top:0.2em;margin-bottom:0.2em}div.app{border-width:1px 2px;width:100%;margin-bottom:5em}div.app>ul{position:relative;width:100%;list-style-type:none;margin:0;padding:0}div.app>ul>li{min-height:7em;display:block;width:100%;position:relative;border-bottom:1px solid #999;background-color:#101010}div.app>ul>li.cancelled{background-color:#512f00}div.app>ul>li.past{opacity:0.8;background-color:#222}div.app>ul>li>a{color:#fff}div.app>ul>li .anchor{position:relative;top:-12em}div.app>ul>li .line{font-size:2.7em;position:absolute;bottom:5px;left:2px;max-width:6em;max-height:3ex;overflow:hidden}div.app>ul>li .line .trainno{font-weight:normal}div.app>ul>li .line .trainno_sub{font-weight:normal;font-size:0.6em;text-align:center;margin-top:-0.2em}div.app>ul>li .sbahn .trainno_sub{font-weight:normal;font-size:0.5em;text-align:center;margin-top:-0.25em}div.app>ul>li .lineinfo{color:#fff;font-size:2em;position:absolute;top:0px;left:2px}div.app>ul>li .route,div.app>ul>li .info{background-color:transparent;font-size:2.1em;position:absolute;top:0;left:7.7em;right:7em;height:1.5em;overflow:hidden;white-space:nowrap}div.app>ul>li .route{color:#ddd}div.app>ul>li .info{color:#f77}div.app>ul>li .dest,div.app>ul>li .origin{background-color:transparent;font-size:4em;position:absolute;bottom:0;left:4em;width:70%;white-space:nowrap;overflow:hidden;color:#fff}div.app>ul>li .dest{background-color:transparent;color:#fff}div.app>ul>li .origin{background-color:transparent;color:#bbb}div.app>ul>li .origin:before{content:"von "}div.app>ul>li .platform{background-color:transparent;font-size:3em;font-weight:bold;position:absolute;right:5px;bottom:0;padding-left:0.2em;color:#fff}div.app>ul>li .changed-platform{color:#f77}div.app>ul>li .time{background-color:transparent;font-size:2.3em;position:absolute;right:5px;top:1px;padding-left:0.2em;color:#fff}div.app>ul>li .time.delayed{color:#f77;background-color:transparent}div.app>ul>li .time .no-realtime{background-color:transparent;padding-right:1ex}div.app>ul>li .time .no-realtime i.material-icons{font-size:12px}div.app>ul>li .time .delay{font-size:1em;color:#f77;background-color:transparent;padding-right:1ex}div.app>ul>li .time .undelay{font-size:1em;color:#7f7;padding-right:1ex}div.app>ul>li .time .delaynorm{font-size:0.9em;color:#d99}div.app>ul>li .time .undelaynorm{font-size:0.9em;color:#9d9}div.app .trainsubtype{font-weight:normal;font-size:70%;position:relative;vertical-align:baseline;top:-0.6ex;left:-0.5ex}div.app .replacement{color:#afa}div.app .replaced{color:#faa}div.app .sbahn{font-weight:bold;border-radius:30px;padding:3px 6px 2px 6px;background-color:#151}div.app .bahn,div.app .fern,div.app .ext{font-weight:bold;border-radius:5px;padding:3px 5px 2px 5px}div.app .bahn{background-color:#333}div.app .fern{background-color:#511}div.app .ext{border:2px solid #333}div.app .tram,div.app .bus,div.app .ubahn{padding:3px 5px 2px 5px}div.app .tram{background-color:#411}div.app .bus{background-color:#515}div.app .ubahn{background-color:#071e62}div.app .moreinfo{font-size:2.1em;position:fixed;left:0;right:0;bottom:0em;z-index:5;overflow:auto;cursor:default;background-color:#101010}div.app .moreinfo .mheader,div.app .moreinfo .mfooter{max-width:50em;margin-left:auto;margin-right:auto}div.app .moreinfo .mheader{text-align:center;font-size:120%;padding-top:0.5em;padding-bottom:0.5em;padding-left:1em;padding-right:1em;border-bottom:0.1em dashed #cccccc}div.app .moreinfo .mfooter{padding-top:0.5em;padding-left:1em;padding-right:1em}div.app .moreinfo .dataline{font-size:120%;width:100%;display:flex;justify-content:space-between;margin-bottom:0.5em}div.app .moreinfo .dataline>div{width:33%}div.app .moreinfo .wagonorder-preview{font-size:110%;width:100%;text-align:center;margin-bottom:1em}div.app .moreinfo .wagonorder-preview a{color:#fff}div.app .moreinfo .departure{text-align:right}div.app .moreinfo .platform{text-align:center}div.app .moreinfo .arrival{display:inline-block;text-align:right}div.app .moreinfo .loading{text-align:center;width:100%;color:#888888}div.app .moreinfo .minfo{color:#f77}div.app .moreinfo .timehidden{color:#bbb}div.app .moreinfo .undelay{color:#7f7}div.app .moreinfo .verbose{margin-bottom:1em}div.app .moreinfo .verbose .no-realtime{color:#f77}div.app .moreinfo .messages i.material-icons{font-size:14px}div.app .moreinfo .details{margin-top:1em}div.app .moreinfo .mroute .important-stop{color:#fff}div.app .moreinfo .mroute .generic-stop{color:#bbb}div.app .moreinfo .mroute .additional-stop{color:#7f7}div.app .moreinfo .mroute .cancelled-stop{color:#f77}div.app .moreinfo .mroute .past-stop{list-style-type:disc}div.app .moreinfo .mroute .future-stop{list-style-type:circle}div.app .moreinfo .mroute i.material-icons{font-size:14px}div.app .moreinfo .db-attr{margin-bottom:1em}div.app .moreinfo .db-attr span{margin-right:0.5em}div.app .collapsed-moreinfo{display:none}div.app .expanded-moreinfo{display:block}ul.ui-autocomplete{max-height:20em;overflow-x:hidden;overflow-y:auto}div.geolocation{text-align:center}div.candidatestatus{text-align:center;color:#999999}div.candidatelist a{display:block;text-decoration:none;font-size:1.4em;padding-top:0.3em;text-align:center;border-bottom:1px solid #999999}div.candidatelist a .distance:after{content:" km"}div.candidatelist a .distance{font-size:0.6em;color:#999999;padding-top:0.2em;padding-bottom:0.3em}div.candidatelist a .traininfo{font-size:0.7em;color:#999999;padding-top:0.2em;padding-bottom:0.3em}div.config{margin-top:2em;font-family:Sans-Serif;color:#bbb}div.config a{color:#99f;cursor:pointer;text-decoration:none}div.about{margin-top:1em;font-family:Sans-Serif;color:#bbb}div.about a{color:#99f;text-decoration:none}.notice{padding:15px;margin-bottom:20px;border:1px solid #bce8f1;border-radius:4px;color:#31708f;background-color:#d9edf7;margin-left:auto;margin-right:auto}.warning{padding:15px;margin-bottom:20px;border:1px solid #faebcc;border-radius:4px;color:#8a6d3b;background-color:#fcf8e3;margin-left:auto;margin-right:auto}.error{padding:15px;margin-bottom:20px;border:1px solid #ebccd1;border-radius:4px;color:#a94442;background-color:#f2dede;margin-left:auto;margin-right:auto}.error .errcode{font-family:Monospace;margin-top:2em;font-size:100%;color:#aaaaaa}.container{max-width:60em;margin-left:auto;margin-right:auto}pre{margin-bottom:2em}span.optional,span.notes{color:#bbb}.moresettings-header{cursor:pointer}.moresettings-header-collapsed:before{content:"▹ "}.moresettings-header-expanded:before{content:"▿ "}.moresettings-collapsed{display:none}.moresettings-expanded{display:block}.developers-header{cursor:pointer}.developers-header-collapsed:before{content:"▹ "}.developers-header-expanded:before{content:"▿ "}.developers-collapsed{display:none}.developers-expanded{display:block}div.break{height:1em}div.field{margin-top:0.3em;margin-bottom:0.6em}.disabledbutton{display:inline-block;vertical-align:baseline;border-radius:4px;border:1px solid #cccccc;box-shadow:none;padding:0.9ex;margin-right:1em}.smallbutton{display:inline-block;vertical-align:baseline;border-radius:4px;border:1px solid #2e6da4;transition:background-color .3s;color:#fff;background-color:#337ab7;cursor:pointer;box-shadow:none;padding:0.9ex;margin-right:1em}.smallbutton .material-icons,.disabledbutton .material-icons{display:block;float:left;margin-right:0.5ex}.smallbutton img{display:block;float:left;margin-right:0.7ex;height:1.2em}input,select,.button{display:inline-block;width:60em;max-width:100%;min-height:1.8em;border-radius:4px;color:#fff;background-color:#101010;border:1px solid #444;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);font-size:90%;text-align:center;vertical-align:middle}input[type="text"]{width:59em;padding-left:0.5em;padding-right:0.5em;text-align:left;box-sizing:border-box}select{min-height:2em}input[type="checkbox"]{width:1.5em;box-shadow:none}input[type="submit"],.button{transition:background-color .3s;color:#fff;background-color:#337ab7;border-color:#2e6da4;cursor:pointer;box-shadow:none;padding-top:0.9ex;padding-bottom:0.9ex}.button{padding-top:1.1ex;padding-bottom:0}input[type="submit"]:active,input[type="submit"]:focus,input[type="submit"]:hover,.button:active,.button:focus,.button:hover,.smallbutton:active,.smallbutton:focus,.smallbutton:hover{color:#fff;background-color:#286090;border-color:#204d74}input[type="submit"]:active,.button:active{box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.button-light{color:#ddd;background-color:#101010;border-color:#444}.button-light:active,.button-light:focus,.button-light:hover{color:#ddd;background-color:#111;border-color:#333}div.notes{margin-top:2em}div.notes ul{margin-top:1em}div.app{max-width:60em;margin-left:auto;margin-right:auto}.navbar-fixed{position:relative;z-index:997}.navbar-fixed nav{position:fixed}nav{box-shadow:0 2px 2px 0 rgba(0,0,0,0.14),0 3px 1px -2px rgba(0,0,0,0.12),0 1px 5px 0 rgba(0,0,0,0.2)}nav{width:100%;overflow:hidden}nav a{color:#fff}nav .nav-wrapper{position:relative;height:100%}nav i,nav i.material-icons{display:block;font-size:24px}nav .brand-logo{position:absolute;display:inline-block;padding-left:0.5rem}nav ul{margin:0;padding-left:0;list-style-type:none}nav ul li{transition:background-color .3s;float:left;padding:0;list-style-type:none;background-color:#00838f}nav ul a{transition:background-color .3s;font-size:1rem;color:#fff;display:block;padding:0 15px;cursor:pointer}@media only screen and (max-width: 600px){div.app>ul>li{font-size:35%}div.navbar-fixed{height:56px}.moreinfo{top:56px}nav{height:56px;line-height:56px}nav .brand-logo{font-size:1.5rem}nav .nav-wrapper i{height:56px;line-height:56px}}@media only screen and (min-width: 600px){div.app>ul>li{font-size:40%}div.navbar-fixed{height:64px}.moreinfo{top:64px}nav{height:64px;line-height:64px}nav .brand-logo{font-size:2.1rem}nav .nav-wrapper i{height:64px;line-height:64px}}div.app .moreinfo{font-size:100%} +body{margin:0;color:#fff;background-color:#101010}html{font-family:"Arimo", "Arial", Sans-Serif}a{color:#99f;text-decoration:none}.visually-hidden{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}p,div.about,div.config,div.input-field,div.notes{max-width:94%;margin-left:auto;margin-right:auto}p{text-align:justify}div.content{width:100%;margin:0}.copyright{margin-top:1em;color:#999;clear:both}.wagonorder{position:relative;width:100%;height:100ex}.wagonorder.exit-unknown .section{left:1em;width:2em}.wagonorder.exit-unknown .wagon{left:3em;min-width:6em}.wagonorder.exit-unknown .details{left:10em;right:0em}.wagonorder.exit-left .section{left:1em;width:2em;background-color:#222}.wagonorder.exit-left .wagon{left:3em;min-width:6em}.wagonorder.exit-left .details{left:10em;right:0em}.wagonorder.exit-right .section{right:1em;width:2em;background-color:#222}.wagonorder.exit-right .wagon{right:3em;min-width:6em}.wagonorder.exit-right .details{right:10em;left:0em;text-align:right}.wagonorder .section{position:absolute;text-align:center}.wagonorder .wagon{position:absolute;border:1px solid #999;padding-left:0.2em;padding-right:0.2em}.wagonorder .wagon .material-icons{color:#bbb}.wagonorder .wagon .direction{position:absolute;left:0.2em;bottom:0;right:0;text-align:center;color:#bbb}.wagonorder .wagon~.wagon{border-top:none}.wagonorder .firstclass{background-color:#330}.wagonorder .powercar{background-color:#222}.wagonorder .closed{background-color:#222}.wagonorder .nondestwagon{border-style:dashed}.wagonorder .details{position:absolute;padding-top:0.5ex}.wagonorder .details .type{display:inline-block;width:5em;color:#fff}.wagonorder .details a.type{color:#99f}.wagonorder .details .groupno{color:#fff}.wagonorder .details .grouptype{color:#bbb}.wagonorder .details .grouptype:before{content:"("}.wagonorder .details .grouptype:after{content:")"}.wagonorder .details .uicunknown{color:#999}.wagonorder .details .uicexchange{margin-right:0.2em;color:#999}.wagonorder .details .uiccountry{margin-right:0.2em;color:#999}.wagonorder .details .uic5{margin-right:0.2em;color:#999}.wagonorder .details .uic56{color:#bbb;font-weight:bold}.wagonorder .details .uic78{margin-right:0.2em;color:#bbb;font-weight:bold}.wagonorder .details .uic78:before{content:"-"}.wagonorder .details .uictype{margin-right:0.2em;color:#bbb;font-weight:bold}.wagonorder .details .uicno{color:#bbb}.wagonorder .details .uiccheck{color:#999}.wagonorder .details .uiccheck:before{content:"-"}.singlewagon .sign-left{float:left;padding-left:5%}.singlewagon .sign-right{float:right;padding-right:5%}.singlewagon .sign-center{text-align:center}.singlewagon .platform{text-align:center;background-color:#444;font-weight:bold;padding-top:0.5em;padding-bottom:0.5em}.singlewagon img.wagonfile{width:100%;margin-top:0.2em;margin-bottom:0.2em}div.app{border-width:1px 2px;width:100%;margin-bottom:5em}div.app>ul{position:relative;width:100%;list-style-type:none;margin:0;padding:0}div.app>ul>li{min-height:7em;display:block;width:100%;position:relative;border-bottom:1px solid #999;background-color:#101010}div.app>ul>li.cancelled{background-color:#512f00}div.app>ul>li.past{opacity:0.8;background-color:#222}div.app>ul>li>a{color:#fff}div.app>ul>li .anchor{position:relative;top:-12em}div.app>ul>li .line{font-size:2.7em;position:absolute;bottom:5px;left:2px;max-width:6em;max-height:3ex;overflow:hidden}div.app>ul>li .line .trainno{font-weight:normal}div.app>ul>li .line .trainno_sub{font-weight:normal;font-size:0.6em;text-align:center;margin-top:-0.2em}div.app>ul>li .sbahn .trainno_sub{font-weight:normal;font-size:0.5em;text-align:center;margin-top:-0.25em}div.app>ul>li .lineinfo{color:#fff;font-size:2em;position:absolute;top:0px;left:2px}div.app>ul>li .route,div.app>ul>li .info{background-color:transparent;font-size:2.1em;position:absolute;top:0;left:7.7em;right:7em;height:1.5em;overflow:hidden;white-space:nowrap}div.app>ul>li .route{color:#ddd}div.app>ul>li .info{color:#f77}div.app>ul>li .dest,div.app>ul>li .origin{background-color:transparent;font-size:4em;position:absolute;bottom:0;left:4em;width:70%;white-space:nowrap;overflow:hidden;color:#fff}div.app>ul>li .dest{background-color:transparent;color:#fff}div.app>ul>li .origin{background-color:transparent;color:#bbb}div.app>ul>li .origin:before{content:"von "}div.app>ul>li .platform{background-color:transparent;font-size:3em;font-weight:bold;position:absolute;right:5px;bottom:0;padding-left:0.2em;color:#fff}div.app>ul>li .changed-platform{color:#f77}div.app>ul>li .time{background-color:transparent;font-size:2.3em;position:absolute;right:5px;top:1px;padding-left:0.2em;color:#fff}div.app>ul>li .time.delayed{color:#f77;background-color:transparent}div.app>ul>li .time .no-realtime{background-color:transparent;padding-right:1ex}div.app>ul>li .time .no-realtime i.material-icons{font-size:12px}div.app>ul>li .time .delay{font-size:1em;color:#f77;background-color:transparent;padding-right:1ex}div.app>ul>li .time .undelay{font-size:1em;color:#7f7;padding-right:1ex}div.app>ul>li .time .delaynorm{font-size:0.9em;color:#d99}div.app>ul>li .time .undelaynorm{font-size:0.9em;color:#9d9}div.app .trainsubtype{font-weight:normal;font-size:70%;position:relative;vertical-align:baseline;top:-0.6ex;left:-0.5ex}div.app .replacement{color:#afa}div.app .replaced{color:#faa}div.app .sbahn{font-weight:bold;border-radius:30px;padding:3px 6px 2px 6px;background-color:#151}div.app .bahn,div.app .fern,div.app .ext{font-weight:bold;border-radius:5px;padding:3px 5px 2px 5px}div.app .bahn{background-color:#333}div.app .fern{background-color:#511}div.app .ext{border:2px solid #333}div.app .tram,div.app .bus,div.app .ubahn{padding:3px 5px 2px 5px}div.app .tram{background-color:#411}div.app .bus{background-color:#515}div.app .ubahn{background-color:#071e62}div.app .moreinfo{font-size:2.1em;position:fixed;left:0;right:0;bottom:0em;z-index:5;overflow:auto;cursor:default;background-color:#101010}div.app .moreinfo .mheader,div.app .moreinfo .mfooter{max-width:50em;margin-left:auto;margin-right:auto}div.app .moreinfo .mheader{text-align:center;font-size:120%;padding-top:0.5em;padding-bottom:0.5em;padding-left:1em;padding-right:1em;border-bottom:0.1em dashed #cccccc}div.app .moreinfo .mfooter{padding-top:0.5em;padding-left:1em;padding-right:1em}div.app .moreinfo .dataline{font-size:120%;width:100%;display:flex;justify-content:space-between;margin-bottom:0.5em}div.app .moreinfo .dataline>div{width:33%}div.app .moreinfo .wagonorder-preview{font-size:110%;width:100%;text-align:center;margin-bottom:1em}div.app .moreinfo .wagonorder-preview a{color:#fff}div.app .moreinfo .wagonorder-preview .otherno{color:#bbb}div.app .moreinfo .wagonorder-preview .meta{color:#ddd}div.app .moreinfo .departure{text-align:right}div.app .moreinfo .platform{text-align:center}div.app .moreinfo .arrival{display:inline-block;text-align:right}div.app .moreinfo .loading{text-align:center;width:100%;color:#888888}div.app .moreinfo .minfo{color:#f77}div.app .moreinfo .timehidden{color:#bbb}div.app .moreinfo .undelay{color:#7f7}div.app .moreinfo .verbose{margin-bottom:1em}div.app .moreinfo .verbose .no-realtime{color:#f77}div.app .moreinfo .messages i.material-icons{font-size:14px}div.app .moreinfo .details{margin-top:1em}div.app .moreinfo .mroute .important-stop{color:#fff}div.app .moreinfo .mroute .generic-stop{color:#bbb}div.app .moreinfo .mroute .additional-stop{color:#7f7}div.app .moreinfo .mroute .cancelled-stop{color:#f77}div.app .moreinfo .mroute .past-stop{list-style-type:disc}div.app .moreinfo .mroute .future-stop{list-style-type:circle}div.app .moreinfo .mroute .time-early{color:#cfc}div.app .moreinfo .mroute .time-delayed{color:#f99}div.app .moreinfo .mroute .time-sched-only{color:#f99}div.app .moreinfo .mroute .time-sched-ontime{color:#cfc}div.app .moreinfo .mroute .annotation{color:#bbb;list-style-type:none;padding-left:3em}div.app .moreinfo .mroute .-sched:before{content:" "}div.app .moreinfo .mroute .time-sched:after{content:" "}div.app .moreinfo .mroute .time-sched-only:before{content:"("}div.app .moreinfo .mroute .time-sched-only:after{content:")"}div.app .moreinfo .mroute i.material-icons{font-size:14px}div.app .moreinfo .db-attr{margin-bottom:1em}div.app .moreinfo .db-attr span{margin-right:0.5em}div.app .collapsed-moreinfo{display:none}div.app .expanded-moreinfo{display:block}ul.ui-autocomplete{max-height:20em;overflow-x:hidden;overflow-y:auto}div.geolocation{text-align:center}div.candidatestatus{text-align:center;color:#999999}div.candidatelist a{display:block;text-decoration:none;font-size:1.4em;padding-top:0.3em;text-align:center;border-bottom:1px solid #999999}div.candidatelist a .distance:after{content:" km"}div.candidatelist a .distance{font-size:0.6em;color:#999999;padding-top:0.2em;padding-bottom:0.3em}div.candidatelist a .traininfo{font-size:0.7em;color:#999999;padding-top:0.2em;padding-bottom:0.3em}div.config{margin-top:2em;font-family:Sans-Serif;color:#bbb}div.config a{color:#99f;cursor:pointer;text-decoration:none}div.about{margin-top:1em;font-family:Sans-Serif;color:#bbb}div.about a{color:#99f;text-decoration:none}.notice{padding:15px;margin-bottom:20px;border:1px solid #bce8f1;border-radius:4px;color:#31708f;background-color:#d9edf7;margin-left:auto;margin-right:auto}.warning{padding:15px;margin-bottom:20px;border:1px solid #faebcc;border-radius:4px;color:#8a6d3b;background-color:#fcf8e3;margin-left:auto;margin-right:auto}.error{padding:15px;margin-bottom:20px;border:1px solid #ebccd1;border-radius:4px;color:#a94442;background-color:#f2dede;margin-left:auto;margin-right:auto}.error .errcode{font-family:Monospace;margin-top:2em;font-size:100%;color:#aaaaaa}.container{max-width:60em;margin-left:auto;margin-right:auto}pre{margin-bottom:2em}span.optional,span.notes{color:#bbb}.moresettings-header{cursor:pointer}.moresettings-header-collapsed:before{content:"▹ "}.moresettings-header-expanded:before{content:"▿ "}.moresettings-collapsed{display:none}.moresettings-expanded{display:block}.developers-header{cursor:pointer}.developers-header-collapsed:before{content:"▹ "}.developers-header-expanded:before{content:"▿ "}.developers-collapsed{display:none}.developers-expanded{display:block}div.break{height:1em}div.field{margin-top:0.3em;margin-bottom:0.6em}.disabledbutton{display:inline-block;vertical-align:baseline;border-radius:4px;border:1px solid #cccccc;box-shadow:none;padding:0.9ex;margin-right:1em}.smallbutton{display:inline-block;vertical-align:baseline;border-radius:4px;border:1px solid #2e6da4;transition:background-color .3s;color:#fff;background-color:#337ab7;cursor:pointer;box-shadow:none;padding:0.9ex;margin-right:1em}.smallbutton .material-icons,.disabledbutton .material-icons{display:block;float:left;margin-right:0.5ex}.smallbutton img{display:block;float:left;margin-right:0.7ex;height:1.2em}input,select,.button{display:inline-block;width:60em;max-width:100%;min-height:1.8em;border-radius:4px;color:#fff;background-color:#101010;border:1px solid #444;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);font-size:90%;text-align:center;vertical-align:middle}input[type="text"]{width:59em;padding-left:0.5em;padding-right:0.5em;text-align:left;box-sizing:border-box}select{min-height:2em}input[type="checkbox"]{width:1.5em;box-shadow:none}input[type="submit"],.button{transition:background-color .3s;color:#fff;background-color:#337ab7;border-color:#2e6da4;cursor:pointer;box-shadow:none;padding-top:0.9ex;padding-bottom:0.9ex}.button{padding-top:1.1ex;padding-bottom:0}input[type="submit"]:active,input[type="submit"]:focus,input[type="submit"]:hover,.button:active,.button:focus,.button:hover,.smallbutton:active,.smallbutton:focus,.smallbutton:hover{color:#fff;background-color:#286090;border-color:#204d74}input[type="submit"]:active,.button:active{box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.button-light{color:#ddd;background-color:#101010;border-color:#444}.button-light:active,.button-light:focus,.button-light:hover{color:#ddd;background-color:#111;border-color:#333}div.notes{margin-top:2em}div.notes ul{margin-top:1em}div.app{max-width:60em;margin-left:auto;margin-right:auto}.navbar-fixed{position:relative;z-index:997}.navbar-fixed nav{position:fixed}nav{box-shadow:0 2px 2px 0 rgba(0,0,0,0.14),0 3px 1px -2px rgba(0,0,0,0.12),0 1px 5px 0 rgba(0,0,0,0.2)}nav{width:100%;overflow:hidden}nav a{color:#fff}nav .nav-wrapper{position:relative;height:100%}nav i,nav i.material-icons{display:block;font-size:24px}nav .brand-logo{position:absolute;display:inline-block;padding-left:0.5rem}nav ul{margin:0;padding-left:0;list-style-type:none}nav ul li{transition:background-color .3s;float:left;padding:0;list-style-type:none;background-color:#00838f}nav ul a{transition:background-color .3s;font-size:1rem;color:#fff;display:block;padding:0 15px;cursor:pointer}@media only screen and (max-width: 600px){div.app>ul>li{font-size:35%}div.navbar-fixed{height:56px}.moreinfo{top:56px}nav{height:56px;line-height:56px}nav .brand-logo{font-size:1.5rem}nav .nav-wrapper i{height:56px;line-height:56px}}@media only screen and (min-width: 600px){div.app>ul>li{font-size:40%}div.navbar-fixed{height:64px}.moreinfo{top:64px}nav{height:64px;line-height:64px}nav .brand-logo{font-size:2.1rem}nav .nav-wrapper i{height:64px;line-height:64px}}div.app .moreinfo{font-size:100%} diff --git a/public/static/css/mobile.css b/public/static/css/legacy-mobile.css index 0bf84d4..0bf84d4 100644 --- a/public/static/css/mobile.css +++ b/public/static/css/legacy-mobile.css diff --git a/public/static/css/default.css b/public/static/css/legacy.css index ac2eb79..ac2eb79 100644 --- a/public/static/css/default.css +++ b/public/static/css/legacy.css diff --git a/public/static/css/light.min.css b/public/static/css/light.min.css index 9b69307..26205dd 100644 --- a/public/static/css/light.min.css +++ b/public/static/css/light.min.css @@ -1 +1 @@ -body{margin:0;color:#000;background-color:#fff}html{font-family:"Arimo", "Arial", Sans-Serif}a{color:#009;text-decoration:none}.visually-hidden{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}p,div.about,div.config,div.input-field,div.notes{max-width:94%;margin-left:auto;margin-right:auto}p{text-align:justify}div.content{width:100%;margin:0}.copyright{margin-top:1em;color:#999;clear:both}.wagonorder{position:relative;width:100%;height:100ex}.wagonorder.exit-unknown .section{left:1em;width:2em}.wagonorder.exit-unknown .wagon{left:3em;min-width:6em}.wagonorder.exit-unknown .details{left:10em;right:0em}.wagonorder.exit-left .section{left:1em;width:2em;background-color:#ddd}.wagonorder.exit-left .wagon{left:3em;min-width:6em}.wagonorder.exit-left .details{left:10em;right:0em}.wagonorder.exit-right .section{right:1em;width:2em;background-color:#ddd}.wagonorder.exit-right .wagon{right:3em;min-width:6em}.wagonorder.exit-right .details{right:10em;left:0em;text-align:right}.wagonorder .section{position:absolute;text-align:center}.wagonorder .wagon{position:absolute;border:1px solid #999;padding-left:0.2em;padding-right:0.2em}.wagonorder .wagon .material-icons{color:#666}.wagonorder .wagon .direction{position:absolute;left:0.2em;bottom:0;right:0;text-align:center;color:#666}.wagonorder .wagon~.wagon{border-top:none}.wagonorder .firstclass{background-color:#ff9}.wagonorder .powercar{background-color:#ccc}.wagonorder .closed{background-color:#ddd}.wagonorder .nondestwagon{border-style:dashed}.wagonorder .details{position:absolute;padding-top:0.5ex}.wagonorder .details .type{display:inline-block;width:5em;color:#666}.wagonorder .details a.type{color:#009}.wagonorder .details .uicunknown{color:#999}.wagonorder .details .uicexchange{margin-right:0.2em;color:#999}.wagonorder .details .uiccountry{margin-right:0.2em;color:#999}.wagonorder .details .uic5{margin-right:0.2em;color:#999}.wagonorder .details .uic56{color:#666;font-weight:bold}.wagonorder .details .uic78{margin-right:0.2em;color:#666;font-weight:bold}.wagonorder .details .uic78::before{content:"-"}.wagonorder .details .uictype{margin-right:0.2em;color:#666;font-weight:bold}.wagonorder .details .uicno{color:#666}.wagonorder .details .uiccheck{color:#999}.wagonorder .details .uiccheck::before{content:"-"}.singlewagon .sign-left{float:left;padding-left:5%}.singlewagon .sign-right{float:right;padding-right:5%}.singlewagon .sign-center{text-align:center}.singlewagon .platform{text-align:center;background-color:#ccc;font-weight:bold;padding-top:0.5em;padding-bottom:0.5em}.singlewagon img.wagonfile{width:100%;margin-top:0.2em;margin-bottom:0.2em}div.app{border-width:1px 2px;width:100%;margin-bottom:5em}div.app>ul{position:relative;width:100%;list-style-type:none;margin:0;padding:0}div.app>ul>li{min-height:7em;display:block;width:100%;position:relative;border-bottom:1px solid #999;background-color:#fff}div.app>ul>li.cancelled{background-color:#ffe7d0}div.app>ul>li.past{opacity:0.8;background-color:#ddd}div.app>ul>li>a{color:#000}div.app>ul>li .anchor{position:relative;top:-12em}div.app>ul>li .line{font-size:2.7em;position:absolute;bottom:5px;left:2px;max-width:6em;max-height:3ex;overflow:hidden}div.app>ul>li .line .trainno{font-weight:normal}div.app>ul>li .line .trainno_sub{font-weight:normal;font-size:0.6em;text-align:center;margin-top:-0.2em}div.app>ul>li .sbahn .trainno_sub{font-weight:normal;font-size:0.5em;text-align:center;margin-top:-0.25em}div.app>ul>li .lineinfo{color:#000;font-size:2em;position:absolute;top:0px;left:2px}div.app>ul>li .route,div.app>ul>li .info{background-color:transparent;font-size:2.1em;position:absolute;top:0;left:7.7em;right:7em;height:1.5em;overflow:hidden;white-space:nowrap}div.app>ul>li .route{color:#444}div.app>ul>li .info{color:red}div.app>ul>li .dest,div.app>ul>li .origin{background-color:transparent;font-size:4em;position:absolute;bottom:0;left:4em;width:70%;white-space:nowrap;overflow:hidden;color:#000}div.app>ul>li .dest{background-color:transparent;color:#000}div.app>ul>li .origin{background-color:transparent;color:#666}div.app>ul>li .origin:before{content:"von "}div.app>ul>li .platform{background-color:transparent;font-size:3em;font-weight:bold;position:absolute;right:5px;bottom:0;padding-left:0.2em;color:#000}div.app>ul>li .changed-platform{color:red}div.app>ul>li .time{background-color:transparent;font-size:2.3em;position:absolute;right:5px;top:1px;padding-left:0.2em;color:#000}div.app>ul>li .time.delayed{color:red;background-color:transparent}div.app>ul>li .time .no-realtime{background-color:transparent;padding-right:1ex}div.app>ul>li .time .no-realtime i.material-icons{font-size:12px}div.app>ul>li .time .delay{font-size:1em;color:red;background-color:transparent;padding-right:1ex}div.app>ul>li .time .undelay{font-size:1em;color:#060;padding-right:1ex}div.app>ul>li .time .delaynorm{font-size:0.9em;color:#b33}div.app>ul>li .time .undelaynorm{font-size:0.9em;color:#383}div.app .trainsubtype{font-weight:normal;font-size:70%;position:relative;vertical-align:baseline;top:-0.6ex;left:-0.5ex}div.app .replacement{color:#060}div.app .replaced{color:#600}div.app .sbahn{font-weight:bold;border-radius:30px;padding:3px 6px 2px 6px;background-color:#95d79f}div.app .bahn,div.app .fern,div.app .ext{font-weight:bold;border-radius:5px;padding:3px 5px 2px 5px}div.app .bahn{background-color:#eee}div.app .fern{background-color:#fdd}div.app .ext{border:2px solid #eee}div.app .tram,div.app .bus,div.app .ubahn{padding:3px 5px 2px 5px}div.app .tram{background-color:#fcc}div.app .bus{background-color:#eae}div.app .ubahn{background-color:#aac0ff}div.app .moreinfo{font-size:2.1em;position:fixed;left:0;right:0;bottom:0em;z-index:5;overflow:auto;cursor:default;background-color:#fff}div.app .moreinfo .mheader,div.app .moreinfo .mfooter{max-width:50em;margin-left:auto;margin-right:auto}div.app .moreinfo .mheader{text-align:center;font-size:120%;padding-top:0.5em;padding-bottom:0.5em;padding-left:1em;padding-right:1em;border-bottom:0.1em dashed #cccccc}div.app .moreinfo .mfooter{padding-top:0.5em;padding-left:1em;padding-right:1em}div.app .moreinfo .dataline{font-size:120%;width:100%;display:flex;justify-content:space-between;margin-bottom:0.5em}div.app .moreinfo .dataline>div{width:33%}div.app .moreinfo .wagonorder-preview{font-size:110%;width:100%;text-align:center;margin-bottom:1em}div.app .moreinfo .wagonorder-preview a{color:#000}div.app .moreinfo .departure{text-align:right}div.app .moreinfo .platform{text-align:center}div.app .moreinfo .arrival{display:inline-block;text-align:right}div.app .moreinfo .loading{text-align:center;width:100%;color:#888888}div.app .moreinfo .minfo{color:red}div.app .moreinfo .timehidden{color:#666}div.app .moreinfo .undelay{color:#060}div.app .moreinfo .verbose{margin-bottom:1em}div.app .moreinfo .verbose .no-realtime{color:#c00}div.app .moreinfo .messages i.material-icons{font-size:14px}div.app .moreinfo .details{margin-top:1em}div.app .moreinfo .mroute .important-stop{color:#000}div.app .moreinfo .mroute .generic-stop{color:#666}div.app .moreinfo .mroute .additional-stop{color:#090}div.app .moreinfo .mroute .cancelled-stop{color:#c00}div.app .moreinfo .mroute .past-stop{list-style-type:disc}div.app .moreinfo .mroute .future-stop{list-style-type:circle}div.app .moreinfo .mroute i.material-icons{font-size:14px}div.app .moreinfo .db-attr{margin-bottom:1em}div.app .moreinfo .db-attr span{margin-right:0.5em}div.app .collapsed-moreinfo{display:none}div.app .expanded-moreinfo{display:block}ul.ui-autocomplete{max-height:20em;overflow-x:hidden;overflow-y:auto}div.geolocation{text-align:center}div.candidatestatus{text-align:center;color:#999999}div.candidatelist a{display:block;text-decoration:none;font-size:1.4em;padding-top:0.3em;text-align:center;border-bottom:1px solid #999999}div.candidatelist a .distance:after{content:" km"}div.candidatelist a .distance{font-size:0.6em;color:#999999;padding-top:0.2em;padding-bottom:0.3em}div.candidatelist a .traininfo{font-size:0.7em;color:#999999;padding-top:0.2em;padding-bottom:0.3em}div.config{margin-top:2em;font-family:Sans-Serif;color:#666}div.config a{color:#009;cursor:pointer;text-decoration:none}div.about{margin-top:1em;font-family:Sans-Serif;color:#666}div.about a{color:#009;text-decoration:none}.notice{padding:15px;margin-bottom:20px;border:1px solid #bce8f1;border-radius:4px;color:#31708f;background-color:#d9edf7;margin-left:auto;margin-right:auto}.warning{padding:15px;margin-bottom:20px;border:1px solid #faebcc;border-radius:4px;color:#8a6d3b;background-color:#fcf8e3;margin-left:auto;margin-right:auto}.error{padding:15px;margin-bottom:20px;border:1px solid #ebccd1;border-radius:4px;color:#a94442;background-color:#f2dede;margin-left:auto;margin-right:auto}.error .errcode{font-family:Monospace;margin-top:2em;font-size:100%;color:#aaaaaa}.container{max-width:60em;margin-left:auto;margin-right:auto}pre{margin-bottom:2em}span.optional,span.notes{color:#666}.moresettings-header{cursor:pointer}.moresettings-header-collapsed:before{content:"▹ "}.moresettings-header-expanded:before{content:"▿ "}.moresettings-collapsed{display:none}.moresettings-expanded{display:block}.developers-header{cursor:pointer}.developers-header-collapsed:before{content:"▹ "}.developers-header-expanded:before{content:"▿ "}.developers-collapsed{display:none}.developers-expanded{display:block}div.break{height:1em}div.field{margin-top:0.3em;margin-bottom:0.6em}.disabledbutton{display:inline-block;vertical-align:baseline;border-radius:4px;border:1px solid #cccccc;box-shadow:none;padding:0.9ex;margin-right:1em}.smallbutton{display:inline-block;vertical-align:baseline;border-radius:4px;border:1px solid #2e6da4;transition:background-color .3s;color:#fff;background-color:#337ab7;cursor:pointer;box-shadow:none;padding:0.9ex;margin-right:1em}.smallbutton .material-icons,.disabledbutton .material-icons{display:block;float:left;margin-right:0.5ex}.smallbutton img{display:block;float:left;margin-right:0.7ex;height:1.2em}input,select,.button{display:inline-block;width:60em;max-width:100%;min-height:1.8em;border-radius:4px;color:#000;background-color:#fff;border:1px solid #ccc;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);font-size:90%;text-align:center;vertical-align:middle}input[type="text"]{width:59em;padding-left:0.5em;padding-right:0.5em;text-align:left;box-sizing:border-box}select{min-height:2em}input[type="checkbox"]{width:1.5em;box-shadow:none}input[type="submit"],.button{transition:background-color .3s;color:#fff;background-color:#337ab7;border-color:#2e6da4;cursor:pointer;box-shadow:none;padding-top:0.9ex;padding-bottom:0.9ex}.button{padding-top:1.1ex;padding-bottom:0}input[type="submit"]:active,input[type="submit"]:focus,input[type="submit"]:hover,.button:active,.button:focus,.button:hover,.smallbutton:active,.smallbutton:focus,.smallbutton:hover{color:#fff;background-color:#286090;border-color:#204d74}input[type="submit"]:active,.button:active{box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.button-light{color:#333;background-color:#fff;border-color:#ccc}.button-light:active,.button-light:focus,.button-light:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}div.notes{margin-top:2em}div.notes ul{margin-top:1em}div.app{max-width:60em;margin-left:auto;margin-right:auto}.navbar-fixed{position:relative;z-index:997}.navbar-fixed nav{position:fixed}nav{box-shadow:0 2px 2px 0 rgba(0,0,0,0.14),0 3px 1px -2px rgba(0,0,0,0.12),0 1px 5px 0 rgba(0,0,0,0.2)}nav{width:100%;overflow:hidden}nav a{color:#fff}nav .nav-wrapper{position:relative;height:100%}nav i,nav i.material-icons{display:block;font-size:24px}nav .brand-logo{position:absolute;display:inline-block;padding-left:0.5rem}nav ul{margin:0;padding-left:0;list-style-type:none}nav ul li{transition:background-color .3s;float:left;padding:0;list-style-type:none;background-color:#00838f}nav ul a{transition:background-color .3s;font-size:1rem;color:#fff;display:block;padding:0 15px;cursor:pointer}@media only screen and (max-width: 600px){div.app>ul>li{font-size:35%}div.navbar-fixed{height:56px}.moreinfo{top:56px}nav{height:56px;line-height:56px}nav .brand-logo{font-size:1.5rem}nav .nav-wrapper i{height:56px;line-height:56px}}@media only screen and (min-width: 600px){div.app>ul>li{font-size:40%}div.navbar-fixed{height:64px}.moreinfo{top:64px}nav{height:64px;line-height:64px}nav .brand-logo{font-size:2.1rem}nav .nav-wrapper i{height:64px;line-height:64px}}div.app .moreinfo{font-size:100%} +body{margin:0;color:#000;background-color:#fff}html{font-family:"Arimo", "Arial", Sans-Serif}a{color:#009;text-decoration:none}.visually-hidden{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}p,div.about,div.config,div.input-field,div.notes{max-width:94%;margin-left:auto;margin-right:auto}p{text-align:justify}div.content{width:100%;margin:0}.copyright{margin-top:1em;color:#999;clear:both}.wagonorder{position:relative;width:100%;height:100ex}.wagonorder.exit-unknown .section{left:1em;width:2em}.wagonorder.exit-unknown .wagon{left:3em;min-width:6em}.wagonorder.exit-unknown .details{left:10em;right:0em}.wagonorder.exit-left .section{left:1em;width:2em;background-color:#ddd}.wagonorder.exit-left .wagon{left:3em;min-width:6em}.wagonorder.exit-left .details{left:10em;right:0em}.wagonorder.exit-right .section{right:1em;width:2em;background-color:#ddd}.wagonorder.exit-right .wagon{right:3em;min-width:6em}.wagonorder.exit-right .details{right:10em;left:0em;text-align:right}.wagonorder .section{position:absolute;text-align:center}.wagonorder .wagon{position:absolute;border:1px solid #999;padding-left:0.2em;padding-right:0.2em}.wagonorder .wagon .material-icons{color:#666}.wagonorder .wagon .direction{position:absolute;left:0.2em;bottom:0;right:0;text-align:center;color:#666}.wagonorder .wagon~.wagon{border-top:none}.wagonorder .firstclass{background-color:#ff9}.wagonorder .powercar{background-color:#ccc}.wagonorder .closed{background-color:#ddd}.wagonorder .nondestwagon{border-style:dashed}.wagonorder .details{position:absolute;padding-top:0.5ex}.wagonorder .details .type{display:inline-block;width:5em;color:#000}.wagonorder .details a.type{color:#009}.wagonorder .details .groupno{color:#000}.wagonorder .details .grouptype{color:#666}.wagonorder .details .grouptype:before{content:"("}.wagonorder .details .grouptype:after{content:")"}.wagonorder .details .uicunknown{color:#999}.wagonorder .details .uicexchange{margin-right:0.2em;color:#999}.wagonorder .details .uiccountry{margin-right:0.2em;color:#999}.wagonorder .details .uic5{margin-right:0.2em;color:#999}.wagonorder .details .uic56{color:#666;font-weight:bold}.wagonorder .details .uic78{margin-right:0.2em;color:#666;font-weight:bold}.wagonorder .details .uic78:before{content:"-"}.wagonorder .details .uictype{margin-right:0.2em;color:#666;font-weight:bold}.wagonorder .details .uicno{color:#666}.wagonorder .details .uiccheck{color:#999}.wagonorder .details .uiccheck:before{content:"-"}.singlewagon .sign-left{float:left;padding-left:5%}.singlewagon .sign-right{float:right;padding-right:5%}.singlewagon .sign-center{text-align:center}.singlewagon .platform{text-align:center;background-color:#ccc;font-weight:bold;padding-top:0.5em;padding-bottom:0.5em}.singlewagon img.wagonfile{width:100%;margin-top:0.2em;margin-bottom:0.2em}div.app{border-width:1px 2px;width:100%;margin-bottom:5em}div.app>ul{position:relative;width:100%;list-style-type:none;margin:0;padding:0}div.app>ul>li{min-height:7em;display:block;width:100%;position:relative;border-bottom:1px solid #999;background-color:#fff}div.app>ul>li.cancelled{background-color:#ffe7d0}div.app>ul>li.past{opacity:0.8;background-color:#ddd}div.app>ul>li>a{color:#000}div.app>ul>li .anchor{position:relative;top:-12em}div.app>ul>li .line{font-size:2.7em;position:absolute;bottom:5px;left:2px;max-width:6em;max-height:3ex;overflow:hidden}div.app>ul>li .line .trainno{font-weight:normal}div.app>ul>li .line .trainno_sub{font-weight:normal;font-size:0.6em;text-align:center;margin-top:-0.2em}div.app>ul>li .sbahn .trainno_sub{font-weight:normal;font-size:0.5em;text-align:center;margin-top:-0.25em}div.app>ul>li .lineinfo{color:#000;font-size:2em;position:absolute;top:0px;left:2px}div.app>ul>li .route,div.app>ul>li .info{background-color:transparent;font-size:2.1em;position:absolute;top:0;left:7.7em;right:7em;height:1.5em;overflow:hidden;white-space:nowrap}div.app>ul>li .route{color:#444}div.app>ul>li .info{color:red}div.app>ul>li .dest,div.app>ul>li .origin{background-color:transparent;font-size:4em;position:absolute;bottom:0;left:4em;width:70%;white-space:nowrap;overflow:hidden;color:#000}div.app>ul>li .dest{background-color:transparent;color:#000}div.app>ul>li .origin{background-color:transparent;color:#666}div.app>ul>li .origin:before{content:"von "}div.app>ul>li .platform{background-color:transparent;font-size:3em;font-weight:bold;position:absolute;right:5px;bottom:0;padding-left:0.2em;color:#000}div.app>ul>li .changed-platform{color:red}div.app>ul>li .time{background-color:transparent;font-size:2.3em;position:absolute;right:5px;top:1px;padding-left:0.2em;color:#000}div.app>ul>li .time.delayed{color:red;background-color:transparent}div.app>ul>li .time .no-realtime{background-color:transparent;padding-right:1ex}div.app>ul>li .time .no-realtime i.material-icons{font-size:12px}div.app>ul>li .time .delay{font-size:1em;color:red;background-color:transparent;padding-right:1ex}div.app>ul>li .time .undelay{font-size:1em;color:#060;padding-right:1ex}div.app>ul>li .time .delaynorm{font-size:0.9em;color:#b33}div.app>ul>li .time .undelaynorm{font-size:0.9em;color:#383}div.app .trainsubtype{font-weight:normal;font-size:70%;position:relative;vertical-align:baseline;top:-0.6ex;left:-0.5ex}div.app .replacement{color:#060}div.app .replaced{color:#600}div.app .sbahn{font-weight:bold;border-radius:30px;padding:3px 6px 2px 6px;background-color:#95d79f}div.app .bahn,div.app .fern,div.app .ext{font-weight:bold;border-radius:5px;padding:3px 5px 2px 5px}div.app .bahn{background-color:#eee}div.app .fern{background-color:#fdd}div.app .ext{border:2px solid #eee}div.app .tram,div.app .bus,div.app .ubahn{padding:3px 5px 2px 5px}div.app .tram{background-color:#fcc}div.app .bus{background-color:#eae}div.app .ubahn{background-color:#aac0ff}div.app .moreinfo{font-size:2.1em;position:fixed;left:0;right:0;bottom:0em;z-index:5;overflow:auto;cursor:default;background-color:#fff}div.app .moreinfo .mheader,div.app .moreinfo .mfooter{max-width:50em;margin-left:auto;margin-right:auto}div.app .moreinfo .mheader{text-align:center;font-size:120%;padding-top:0.5em;padding-bottom:0.5em;padding-left:1em;padding-right:1em;border-bottom:0.1em dashed #cccccc}div.app .moreinfo .mfooter{padding-top:0.5em;padding-left:1em;padding-right:1em}div.app .moreinfo .dataline{font-size:120%;width:100%;display:flex;justify-content:space-between;margin-bottom:0.5em}div.app .moreinfo .dataline>div{width:33%}div.app .moreinfo .wagonorder-preview{font-size:110%;width:100%;text-align:center;margin-bottom:1em}div.app .moreinfo .wagonorder-preview a{color:#000}div.app .moreinfo .wagonorder-preview .otherno{color:#666}div.app .moreinfo .wagonorder-preview .meta{color:#333}div.app .moreinfo .departure{text-align:right}div.app .moreinfo .platform{text-align:center}div.app .moreinfo .arrival{display:inline-block;text-align:right}div.app .moreinfo .loading{text-align:center;width:100%;color:#888888}div.app .moreinfo .minfo{color:red}div.app .moreinfo .timehidden{color:#666}div.app .moreinfo .undelay{color:#060}div.app .moreinfo .verbose{margin-bottom:1em}div.app .moreinfo .verbose .no-realtime{color:#c00}div.app .moreinfo .messages i.material-icons{font-size:14px}div.app .moreinfo .details{margin-top:1em}div.app .moreinfo .mroute .important-stop{color:#000}div.app .moreinfo .mroute .generic-stop{color:#666}div.app .moreinfo .mroute .additional-stop{color:#090}div.app .moreinfo .mroute .cancelled-stop{color:#c00}div.app .moreinfo .mroute .past-stop{list-style-type:disc}div.app .moreinfo .mroute .future-stop{list-style-type:circle}div.app .moreinfo .mroute .time-early{color:#070}div.app .moreinfo .mroute .time-delayed{color:#900}div.app .moreinfo .mroute .time-sched-only{color:#900}div.app .moreinfo .mroute .time-sched-ontime{color:#070}div.app .moreinfo .mroute .annotation{color:#666;list-style-type:none;padding-left:3em}div.app .moreinfo .mroute .-sched:before{content:" "}div.app .moreinfo .mroute .time-sched:after{content:" "}div.app .moreinfo .mroute .time-sched-only:before{content:"("}div.app .moreinfo .mroute .time-sched-only:after{content:")"}div.app .moreinfo .mroute i.material-icons{font-size:14px}div.app .moreinfo .db-attr{margin-bottom:1em}div.app .moreinfo .db-attr span{margin-right:0.5em}div.app .collapsed-moreinfo{display:none}div.app .expanded-moreinfo{display:block}ul.ui-autocomplete{max-height:20em;overflow-x:hidden;overflow-y:auto}div.geolocation{text-align:center}div.candidatestatus{text-align:center;color:#999999}div.candidatelist a{display:block;text-decoration:none;font-size:1.4em;padding-top:0.3em;text-align:center;border-bottom:1px solid #999999}div.candidatelist a .distance:after{content:" km"}div.candidatelist a .distance{font-size:0.6em;color:#999999;padding-top:0.2em;padding-bottom:0.3em}div.candidatelist a .traininfo{font-size:0.7em;color:#999999;padding-top:0.2em;padding-bottom:0.3em}div.config{margin-top:2em;font-family:Sans-Serif;color:#666}div.config a{color:#009;cursor:pointer;text-decoration:none}div.about{margin-top:1em;font-family:Sans-Serif;color:#666}div.about a{color:#009;text-decoration:none}.notice{padding:15px;margin-bottom:20px;border:1px solid #bce8f1;border-radius:4px;color:#31708f;background-color:#d9edf7;margin-left:auto;margin-right:auto}.warning{padding:15px;margin-bottom:20px;border:1px solid #faebcc;border-radius:4px;color:#8a6d3b;background-color:#fcf8e3;margin-left:auto;margin-right:auto}.error{padding:15px;margin-bottom:20px;border:1px solid #ebccd1;border-radius:4px;color:#a94442;background-color:#f2dede;margin-left:auto;margin-right:auto}.error .errcode{font-family:Monospace;margin-top:2em;font-size:100%;color:#aaaaaa}.container{max-width:60em;margin-left:auto;margin-right:auto}pre{margin-bottom:2em}span.optional,span.notes{color:#666}.moresettings-header{cursor:pointer}.moresettings-header-collapsed:before{content:"▹ "}.moresettings-header-expanded:before{content:"▿ "}.moresettings-collapsed{display:none}.moresettings-expanded{display:block}.developers-header{cursor:pointer}.developers-header-collapsed:before{content:"▹ "}.developers-header-expanded:before{content:"▿ "}.developers-collapsed{display:none}.developers-expanded{display:block}div.break{height:1em}div.field{margin-top:0.3em;margin-bottom:0.6em}.disabledbutton{display:inline-block;vertical-align:baseline;border-radius:4px;border:1px solid #cccccc;box-shadow:none;padding:0.9ex;margin-right:1em}.smallbutton{display:inline-block;vertical-align:baseline;border-radius:4px;border:1px solid #2e6da4;transition:background-color .3s;color:#fff;background-color:#337ab7;cursor:pointer;box-shadow:none;padding:0.9ex;margin-right:1em}.smallbutton .material-icons,.disabledbutton .material-icons{display:block;float:left;margin-right:0.5ex}.smallbutton img{display:block;float:left;margin-right:0.7ex;height:1.2em}input,select,.button{display:inline-block;width:60em;max-width:100%;min-height:1.8em;border-radius:4px;color:#000;background-color:#fff;border:1px solid #ccc;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);font-size:90%;text-align:center;vertical-align:middle}input[type="text"]{width:59em;padding-left:0.5em;padding-right:0.5em;text-align:left;box-sizing:border-box}select{min-height:2em}input[type="checkbox"]{width:1.5em;box-shadow:none}input[type="submit"],.button{transition:background-color .3s;color:#fff;background-color:#337ab7;border-color:#2e6da4;cursor:pointer;box-shadow:none;padding-top:0.9ex;padding-bottom:0.9ex}.button{padding-top:1.1ex;padding-bottom:0}input[type="submit"]:active,input[type="submit"]:focus,input[type="submit"]:hover,.button:active,.button:focus,.button:hover,.smallbutton:active,.smallbutton:focus,.smallbutton:hover{color:#fff;background-color:#286090;border-color:#204d74}input[type="submit"]:active,.button:active{box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.button-light{color:#333;background-color:#fff;border-color:#ccc}.button-light:active,.button-light:focus,.button-light:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}div.notes{margin-top:2em}div.notes ul{margin-top:1em}div.app{max-width:60em;margin-left:auto;margin-right:auto}.navbar-fixed{position:relative;z-index:997}.navbar-fixed nav{position:fixed}nav{box-shadow:0 2px 2px 0 rgba(0,0,0,0.14),0 3px 1px -2px rgba(0,0,0,0.12),0 1px 5px 0 rgba(0,0,0,0.2)}nav{width:100%;overflow:hidden}nav a{color:#fff}nav .nav-wrapper{position:relative;height:100%}nav i,nav i.material-icons{display:block;font-size:24px}nav .brand-logo{position:absolute;display:inline-block;padding-left:0.5rem}nav ul{margin:0;padding-left:0;list-style-type:none}nav ul li{transition:background-color .3s;float:left;padding:0;list-style-type:none;background-color:#00838f}nav ul a{transition:background-color .3s;font-size:1rem;color:#fff;display:block;padding:0 15px;cursor:pointer}@media only screen and (max-width: 600px){div.app>ul>li{font-size:35%}div.navbar-fixed{height:56px}.moreinfo{top:56px}nav{height:56px;line-height:56px}nav .brand-logo{font-size:1.5rem}nav .nav-wrapper i{height:56px;line-height:56px}}@media only screen and (min-width: 600px){div.app>ul>li{font-size:40%}div.navbar-fixed{height:64px}.moreinfo{top:64px}nav{height:64px;line-height:64px}nav .brand-logo{font-size:2.1rem}nav .nav-wrapper i{height:64px;line-height:64px}}div.app .moreinfo{font-size:100%} diff --git a/public/static/css/material-icons.css b/public/static/css/material-icons.css index 5aa2994..aa3afa7 100644 --- a/public/static/css/material-icons.css +++ b/public/static/css/material-icons.css @@ -2,12 +2,12 @@ font-family: 'Material Icons'; font-style: normal; font-weight: 400; - src: url(/static/v91/fonts/MaterialIcons-Regular.eot); /* For IE6-8 */ + src: url(/static/v99/fonts/MaterialIcons-Regular.eot); /* For IE6-8 */ src: local('Material Icons'), local('MaterialIcons-Regular'), - url(/static/v91/fonts/MaterialIcons-Regular.woff2) format('woff2'), - url(/static/v91/fonts/MaterialIcons-Regular.woff) format('woff'), - url(/static/v91/fonts/MaterialIcons-Regular.ttf) format('truetype'); + url(/static/v99/fonts/MaterialIcons-Regular.woff2) format('woff2'), + url(/static/v99/fonts/MaterialIcons-Regular.woff) format('woff'), + url(/static/v99/fonts/MaterialIcons-Regular.ttf) format('truetype'); } .material-icons { diff --git a/public/static/js/collapse.js b/public/static/js/collapse.js index 2db1089..d7d1e3b 100644 --- a/public/static/js/collapse.js +++ b/public/static/js/collapse.js @@ -113,7 +113,7 @@ function dbf_reg_handlers() { if (param.get('detailed')) { suffix += '&detailed=1'; } - if (param.get('hafas')) { + if (param.get('hafas') && param.get('hafas') != '0') { suffix += '&hafas=' + param.get('hafas') + '&highlight=' + trainElem.data('station'); } if (param.get('past')) { @@ -122,7 +122,7 @@ function dbf_reg_handlers() { if (param.get('rt') || param.get('show_realtime')) { suffix += '&rt=1'; } - if (param.get('hafas')) { + if (param.get('hafas') && param.get('hafas') != '0') { history.pushState({'page':'traindetail','jid':trainElem.data('jid')}, 'test', '/z/' + trainElem.data('jid') + suffix); } else { history.pushState({'page':'traindetail','station':station,'train':trainElem.data('no')}, 'test', '/z/' + trainElem.data('train') + '/' + trainElem.data('station') + suffix); diff --git a/public/static/js/dbf.min.js b/public/static/js/dbf.min.js index c1f81d4..da4ac90 100644 --- a/public/static/js/dbf.min.js +++ b/public/static/js/dbf.min.js @@ -1 +1 @@ -function setLang(e){document.cookie="lang="+e+";SameSite=None;Secure",location.reload()}function setTheme(e){localStorage.setItem("theme",e),otherTheme.hasOwnProperty(e)||(e=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"),addStyleSheet(e,"theme")}function reload_app(){0==$(".expanded-moreinfo").length?$.get(window.location.href,{ajax:1},function(e){$("div.app > ul").html(e),dbf_reg_handlers(),setTimeout(reload_app,6e4)}).fail(function(){setTimeout(reload_app,1e4)}):setTimeout(reload_app,3e4)}function dbf_show_moreinfo(d,s){const n=d.data("routeprev").split("|"),r=d.data("routenext").split("|"),l=d.data("moreinfo").split("|");$(".moreinfo").each(function(){var e=$(this);if(!s){$(".moreinfo .train-line").removeClass("sbahn fern ext ubahn bus tram").addClass(d.data("linetype")),$(".moreinfo .train-line").text(d.data("line")),$(".moreinfo .train-no").text(d.data("no")),$(".moreinfo .train-origin").text(d.data("from")),$(".moreinfo .train-dest").text(d.data("to")),$(".moreinfo .minfo").text(""),$(".moreinfo .mfooter").html(""),$(".moreinfo .verbose").html(""),$(".moreinfo .mroute").html(""),$(".moreinfo ul").html("");var a="";if(""!=d.data("arrival")?a+='<div><div class="arrival">An: '+d.data("arrival")+"</div></div>":a+='<div><div class="arrival"></div></div>',""!=d.data("platform")?a+='<div><div class="platform">Gleis '+d.data("platform")+"</div></div>":a+='<div><div class="platform"></div></div>',""!=d.data("departure")?a+='<div><div class="departure">Ab: '+d.data("departure")+"</div></div>":a+='<div><div class="departure"></div></div>',$(".moreinfo .mfooter").append('<div class="dataline">'+a+"</div>"),0==$(".moreinfo .loading").length&&$(".moreinfo .mfooter").append('<div class="loading">Lade Daten, bitte warten...</div>'),""!=d.data("moreinfo")){var t="";for(i in l)t+="<li>"+l[i]+"</li>";$(".moreinfo .mfooter").append("Meldungen: <ul>"+t+"</ul>")}var o="";if(""!=d.data("routeprev"))for(var i in n)o+="<li>"+n[i]+"</li>";if(o+="<li><strong>"+document.title+"</strong></li>",""!=d.data("routenext"))for(var i in r)o+="<li>"+r[i]+"</li>";$(".moreinfo .mfooter").append('Fahrtverlauf: <ul class="mroute">'+o+"</ul>")}$.get(window.location.href,{train:d.data("train"),jid:d.data("jid"),ajax:1},function(e){$(".moreinfo").html(e)}).fail(function(){$(".moreinfo .mfooter").append("Der Zug ist abgefahren (Zug nicht gefunden)")}),e.removeClass("collapsed-moreinfo"),e.addClass("expanded-moreinfo")})}function dbf_reg_handlers(){$("div.app > ul > li").click(function(e){var a=$(this),t=$("div.app").data("station"),o=new URLSearchParams(window.location.search),e=(e.preventDefault(),"?");o.get("detailed")&&(e+="&detailed=1"),o.get("hafas")&&(e+="&hafas="+o.get("hafas")+"&highlight="+a.data("station")),o.get("past")&&(e+="&past=1"),(o.get("rt")||o.get("show_realtime"))&&(e+="&rt=1"),o.get("hafas")?history.pushState({page:"traindetail",jid:a.data("jid")},"test","/z/"+a.data("jid")+e):history.pushState({page:"traindetail",station:t,train:a.data("no")},"test","/z/"+a.data("train")+"/"+a.data("station")+e),dbf_show_moreinfo(a,!1)});const a=$(location).attr("hash").substr(1);var t;a&&(t=!1,$("div.app > ul > li").each(function(e){t||$(this).find(".anchor").each(function(){$(this).attr("id")==a&&(t=!0)})}),t)&&(t=!1,$("div.app > ul > li").each(function(e){t||($(this).find(".anchor").each(function(){$(this).attr("id")==a&&(t=!0)}),t?$(this).addClass("selected"):$(this).addClass("past"))}))}$(function(){$(".moresettings-header").each(function(){$(this).click(function(){var e=$(".moresettings");$(this).hasClass("moresettings-header-collapsed")?($(this).removeClass("moresettings-header-collapsed"),$(this).addClass("moresettings-header-expanded"),e.removeClass("moresettings-collapsed"),e.addClass("moresettings-expanded")):($(this).removeClass("moresettings-header-expanded"),$(this).addClass("moresettings-header-collapsed"),e.removeClass("moresettings-expanded"),e.addClass("moresettings-collapsed"))})}),$(".developers-header").each(function(){$(this).click(function(){var e=$(".developers");$(this).hasClass("developers-header-collapsed")?($(this).removeClass("developers-header-collapsed"),$(this).addClass("developers-header-expanded"),e.removeClass("developers-collapsed"),e.addClass("developers-expanded")):($(this).removeClass("developers-header-expanded"),$(this).addClass("developers-header-collapsed"),e.removeClass("developers-expanded"),e.addClass("developers-collapsed"))})}),dbf_reg_handlers(),$(".content .app").length&&(setTimeout(reload_app,3e4),history.replaceState({page:"station"},document.title,"")),window.onpopstate=function(a){var t;null!=a.state?"station"==a.state.page?($(".moreinfo").each(function(){$(this).removeClass("expanded-moreinfo"),$(this).addClass("collapsed-moreinfo")}),$("div.app > ul").length||($("div.app").append("<ul></ul>"),reload_app())):"traindetail"==a.state.page&&(t=!1,$("div.app > ul > li").each(function(){var e=$(this);e.data("no")==a.state.train&&(dbf_show_moreinfo(e,!0),t=!0)}),t||($(".moreinfo").each(function(){$(this).removeClass("collapsed-moreinfo"),$(this).addClass("expanded-moreinfo")}),$(".moreinfo .mfooter").append("Der Zug ist abgefahren (Zug nicht gefunden)"))):console.log("unhandled popstate! "+document.location)}}); +function setLang(e){document.cookie="lang="+e+";SameSite=None;Secure",location.reload()}function setTheme(e){localStorage.setItem("theme",e),otherTheme.hasOwnProperty(e)||(e=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"),addStyleSheet(e,"theme")}function reload_app(){0==$(".expanded-moreinfo").length?$.get(window.location.href,{ajax:1},function(e){$("div.app > ul").html(e),dbf_reg_handlers(),setTimeout(reload_app,6e4)}).fail(function(){setTimeout(reload_app,1e4)}):setTimeout(reload_app,3e4)}function dbf_show_moreinfo(d,s){const n=d.data("routeprev").split("|"),r=d.data("routenext").split("|"),l=d.data("moreinfo").split("|");$(".moreinfo").each(function(){var e=$(this);if(!s){$(".moreinfo .train-line").removeClass("sbahn fern ext ubahn bus tram").addClass(d.data("linetype")),$(".moreinfo .train-line").text(d.data("line")),$(".moreinfo .train-no").text(d.data("no")),$(".moreinfo .train-origin").text(d.data("from")),$(".moreinfo .train-dest").text(d.data("to")),$(".moreinfo .minfo").text(""),$(".moreinfo .mfooter").html(""),$(".moreinfo .verbose").html(""),$(".moreinfo .mroute").html(""),$(".moreinfo ul").html("");var a="";if(""!=d.data("arrival")?a+='<div><div class="arrival">An: '+d.data("arrival")+"</div></div>":a+='<div><div class="arrival"></div></div>',""!=d.data("platform")?a+='<div><div class="platform">Gleis '+d.data("platform")+"</div></div>":a+='<div><div class="platform"></div></div>',""!=d.data("departure")?a+='<div><div class="departure">Ab: '+d.data("departure")+"</div></div>":a+='<div><div class="departure"></div></div>',$(".moreinfo .mfooter").append('<div class="dataline">'+a+"</div>"),0==$(".moreinfo .loading").length&&$(".moreinfo .mfooter").append('<div class="loading">Lade Daten, bitte warten...</div>'),""!=d.data("moreinfo")){var t="";for(i in l)t+="<li>"+l[i]+"</li>";$(".moreinfo .mfooter").append("Meldungen: <ul>"+t+"</ul>")}var o="";if(""!=d.data("routeprev"))for(var i in n)o+="<li>"+n[i]+"</li>";if(o+="<li><strong>"+document.title+"</strong></li>",""!=d.data("routenext"))for(var i in r)o+="<li>"+r[i]+"</li>";$(".moreinfo .mfooter").append('Fahrtverlauf: <ul class="mroute">'+o+"</ul>")}$.get(window.location.href,{train:d.data("train"),jid:d.data("jid"),ajax:1},function(e){$(".moreinfo").html(e)}).fail(function(){$(".moreinfo .mfooter").append("Der Zug ist abgefahren (Zug nicht gefunden)")}),e.removeClass("collapsed-moreinfo"),e.addClass("expanded-moreinfo")})}function dbf_reg_handlers(){$("div.app > ul > li").click(function(e){var a=$(this),t=$("div.app").data("station"),o=new URLSearchParams(window.location.search),e=(e.preventDefault(),"?");o.get("detailed")&&(e+="&detailed=1"),o.get("hafas")&&"0"!=o.get("hafas")&&(e+="&hafas="+o.get("hafas")+"&highlight="+a.data("station")),o.get("past")&&(e+="&past=1"),(o.get("rt")||o.get("show_realtime"))&&(e+="&rt=1"),o.get("hafas")&&"0"!=o.get("hafas")?history.pushState({page:"traindetail",jid:a.data("jid")},"test","/z/"+a.data("jid")+e):history.pushState({page:"traindetail",station:t,train:a.data("no")},"test","/z/"+a.data("train")+"/"+a.data("station")+e),dbf_show_moreinfo(a,!1)});const a=$(location).attr("hash").substr(1);var t;a&&(t=!1,$("div.app > ul > li").each(function(e){t||$(this).find(".anchor").each(function(){$(this).attr("id")==a&&(t=!0)})}),t)&&(t=!1,$("div.app > ul > li").each(function(e){t||($(this).find(".anchor").each(function(){$(this).attr("id")==a&&(t=!0)}),t?$(this).addClass("selected"):$(this).addClass("past"))}))}$(function(){$(".moresettings-header").each(function(){$(this).click(function(){var e=$(".moresettings");$(this).hasClass("moresettings-header-collapsed")?($(this).removeClass("moresettings-header-collapsed"),$(this).addClass("moresettings-header-expanded"),e.removeClass("moresettings-collapsed"),e.addClass("moresettings-expanded")):($(this).removeClass("moresettings-header-expanded"),$(this).addClass("moresettings-header-collapsed"),e.removeClass("moresettings-expanded"),e.addClass("moresettings-collapsed"))})}),$(".developers-header").each(function(){$(this).click(function(){var e=$(".developers");$(this).hasClass("developers-header-collapsed")?($(this).removeClass("developers-header-collapsed"),$(this).addClass("developers-header-expanded"),e.removeClass("developers-collapsed"),e.addClass("developers-expanded")):($(this).removeClass("developers-header-expanded"),$(this).addClass("developers-header-collapsed"),e.removeClass("developers-expanded"),e.addClass("developers-collapsed"))})}),dbf_reg_handlers(),$(".content .app").length&&(setTimeout(reload_app,3e4),history.replaceState({page:"station"},document.title,"")),window.onpopstate=function(a){var t;null!=a.state?"station"==a.state.page?($(".moreinfo").each(function(){$(this).removeClass("expanded-moreinfo"),$(this).addClass("collapsed-moreinfo")}),$("div.app > ul").length||($("div.app").append("<ul></ul>"),reload_app())):"traindetail"==a.state.page&&(t=!1,$("div.app > ul > li").each(function(){var e=$(this);e.data("no")==a.state.train&&(dbf_show_moreinfo(e,!0),t=!0)}),t||($(".moreinfo").each(function(){$(this).removeClass("collapsed-moreinfo"),$(this).addClass("expanded-moreinfo")}),$(".moreinfo .mfooter").append("Der Zug ist abgefahren (Zug nicht gefunden)"))):console.log("unhandled popstate! "+document.location)}}); diff --git a/public/static/js/geostop.js b/public/static/js/geostop.js index 80e8311..fa2d6f1 100644 --- a/public/static/js/geostop.js +++ b/public/static/js/geostop.js @@ -42,7 +42,11 @@ $(function() { hafas = candidate.hafas; const stationlink = $(document.createElement('a')); - stationlink.attr('href', eva + '?hafas=' + hafas); + if (hafas) { + stationlink.attr('href', eva + '?hafas=' + hafas); + } else { + stationlink.attr('href', eva); + } stationlink.text(name + ' '); const distancenode = $(document.createElement('div')); @@ -61,7 +65,8 @@ $(function() { }; const processLocation = function(loc) { - $.post('/_geolocation', {lon: loc.coords.longitude, lat: loc.coords.latitude}, processResult).fail(function(jqXHR, textStatus, errorThrown) { + const param = new URLSearchParams(window.location.search); + $.post('/_geolocation', {lon: loc.coords.longitude, lat: loc.coords.latitude, hafas: param.get('hafas')}, processResult).fail(function(jqXHR, textStatus, errorThrown) { removeStatus(); showError("Netzwerkfehler: ", textStatus, errorThrown); }); diff --git a/public/static/js/geostop.min.js b/public/static/js/geostop.min.js index 8a5db00..41e18e0 100644 --- a/public/static/js/geostop.min.js +++ b/public/static/js/geostop.min.js @@ -1 +1 @@ -$(function(){function t(e){o(),e.error?r("Backend-Fehler:",e.error,null):0==e.candidates.length?r("Keine Stationen in 70km Umkreis gefunden","",null):$.each(e.candidates,function(e,t){var n=t.eva,o=t.name,r=t.distance.toFixed(1),t=t.hafas,a=$(document.createElement("a")),n=(a.attr("href",n+"?hafas="+t),a.text(o+" "),$(document.createElement("div"))),o=(n.attr("class","distance"),n.text(r),$(document.createElement("i")));o.attr("class","material-icons"),o.text(t?"directions":"train"),a.append(o),a.append(n),$("div.candidatelist").append(a)})}const o=function(){$("div.candidatestatus").remove()},r=function(e,t,n){var o=$(document.createElement("div")),t=(o.attr("class","error"),o.text(t),$(document.createElement("strong")));t.text(e),o.prepend(t),n&&((e=$(document.createElement("div"))).attr("class","errcode"),e.text(n),o.append(e)),$("div.candidatelist").append(o)};navigator.geolocation?(navigator.geolocation.getCurrentPosition(function(e){$.post("/_geolocation",{lon:e.coords.longitude,lat:e.coords.latitude},t).fail(function(e,t,n){o(),r("Netzwerkfehler: ",t,n)}),$("div.candidatestatus").text("Suche Stationen…")},function(e){o(),e.code==e.PERMISSION_DENIED?r("Standortanfrage nicht möglich.","Vermutlich fehlen die Rechte im Browser oder der Android Location Service ist deaktiviert.","geolocation.error.PERMISSION_DENIED"):e.code==e.POSITION_UNAVAILABLE?r("Standort konnte nicht ermittelt werden","(Service nicht verfügbar)","geolocation.error.POSITION_UNAVAILABLE"):e.code==e.TIMEOUT?r("Standort konnte nicht ermittelt werden","(Timeout)","geolocation.error.TIMEOUT"):r("Standort konnte nicht ermittelt werden","(unbekannter Fehler)","unknown geolocation.error code")}),$("div.candidatestatus").text("Position wird bestimmt…")):(o(),r("Standortanfragen werden von diesem Browser nicht unterstützt","",null))}); +$(function(){function n(e){a(),e.error?r("Backend-Fehler:",e.error,null):0==e.candidates.length?r("Keine Stationen in 70km Umkreis gefunden","",null):$.each(e.candidates,function(e,t){var n=t.eva,a=t.name,r=t.distance.toFixed(1),t=t.hafas,o=$(document.createElement("a")),n=(t?o.attr("href",n+"?hafas="+t):o.attr("href",n),o.text(a+" "),$(document.createElement("div"))),a=(n.attr("class","distance"),n.text(r),$(document.createElement("i")));a.attr("class","material-icons"),a.text(t?"directions":"train"),o.append(a),o.append(n),$("div.candidatelist").append(o)})}const a=function(){$("div.candidatestatus").remove()},r=function(e,t,n){var a=$(document.createElement("div")),t=(a.attr("class","error"),a.text(t),$(document.createElement("strong")));t.text(e),a.prepend(t),n&&((e=$(document.createElement("div"))).attr("class","errcode"),e.text(n),a.append(e)),$("div.candidatelist").append(a)};navigator.geolocation?(navigator.geolocation.getCurrentPosition(function(e){var t=new URLSearchParams(window.location.search);$.post("/_geolocation",{lon:e.coords.longitude,lat:e.coords.latitude,hafas:t.get("hafas")},n).fail(function(e,t,n){a(),r("Netzwerkfehler: ",t,n)}),$("div.candidatestatus").text("Suche Stationen…")},function(e){a(),e.code==e.PERMISSION_DENIED?r("Standortanfrage nicht möglich.","Vermutlich fehlen die Rechte im Browser oder der Android Location Service ist deaktiviert.","geolocation.error.PERMISSION_DENIED"):e.code==e.POSITION_UNAVAILABLE?r("Standort konnte nicht ermittelt werden","(Service nicht verfügbar)","geolocation.error.POSITION_UNAVAILABLE"):e.code==e.TIMEOUT?r("Standort konnte nicht ermittelt werden","(Timeout)","geolocation.error.TIMEOUT"):r("Standort konnte nicht ermittelt werden","(unbekannter Fehler)","unknown geolocation.error code")}),$("div.candidatestatus").text("Position wird bestimmt…")):(a(),r("Standortanfragen werden von diesem Browser nicht unterstützt","",null))}); diff --git a/public/static/v90 b/public/static/v98 index 945c9b4..945c9b4 120000 --- a/public/static/v90 +++ b/public/static/v98 diff --git a/public/static/v91 b/public/static/v99 index 945c9b4..945c9b4 120000 --- a/public/static/v91 +++ b/public/static/v99 diff --git a/sass/app.scss b/sass/app.scss index d8052f1..fb81921 100644 --- a/sass/app.scss +++ b/sass/app.scss @@ -158,13 +158,29 @@ div.content { .type { display: inline-block; width: 5em; - color: $fg2; + color: $fg; } a.type { color: $link-color; } + .groupno { + color: $fg; + } + + .grouptype { + color: $fg2; + } + + .grouptype:before { + content: "("; + } + + .grouptype:after { + content: ")"; + } + .uicunknown { color: $fg3; } @@ -195,7 +211,7 @@ div.content { font-weight: bold; } - .uic78::before { + .uic78:before { content: "-"; } @@ -213,7 +229,7 @@ div.content { color: $fg3; } - .uiccheck::before { + .uiccheck:before { content: "-"; } } @@ -542,6 +558,14 @@ div.app { a { color: $fg; } + + .otherno { + color: $fg2; + } + + .meta { + color: $fg1; + } } .departure { @@ -618,6 +642,45 @@ div.app { list-style-type: circle; } + .time-early { + color: $early-stop-color; + } + + .time-delayed { + color: $delayed-stop-color; + } + + .time-sched-only { + color: $delayed-stop-color; + } + + .time-sched-ontime { + color: $early-stop-color; + } + + + .annotation { + color: $fg2; + list-style-type: none; + padding-left: 3em; + } + + .-sched:before { + content: " "; + } + + .time-sched:after { + content: " "; + } + + .time-sched-only:before { + content: "("; + } + + .time-sched-only:after { + content: ")"; + } + i.material-icons { font-size: 14px; } diff --git a/sass/dark.scss b/sass/dark.scss index 83cb520..c0e8d2b 100644 --- a/sass/dark.scss +++ b/sass/dark.scss @@ -39,6 +39,9 @@ $undelaynorm-color: #99dd99; $additional-stop-color: #77ff77; $cancelled-stop-color: #ff7777; +$early-stop-color: #ccffcc; +$delayed-stop-color: #ff9999; + $cancelled-bg-color: #512f00; $past-bg-color: $bg05; diff --git a/sass/light.scss b/sass/light.scss index d8f53cb..1dee6a9 100644 --- a/sass/light.scss +++ b/sass/light.scss @@ -39,6 +39,9 @@ $undelaynorm-color: #338833; $additional-stop-color: #009900; $cancelled-stop-color: #cc0000; +$early-stop-color: #007700; +$delayed-stop-color: #990000; + $cancelled-bg-color: #ffe7d0; $past-bg-color: $bg05; diff --git a/templates/_train_details.html.ep b/templates/_train_details.html.ep index 3432c30..f560950 100644 --- a/templates/_train_details.html.ep +++ b/templates/_train_details.html.ep @@ -45,6 +45,9 @@ % elsif ($departure->{prep_time}) { Ein: <%= $departure->{prep_time} %> % } +% if ($departure->{tz_offset} and $departure->{local_sched_arr}) { + <br/>Lokal: <%= $departure->{local_sched_arr}->strftime('%H:%M') %> +% } </div> </div> <div> @@ -65,10 +68,10 @@ % else { % my $left = ''; % my $right = ''; -% if ($departure->{direction} and $departure->{direction} eq 'l') { +% if ($departure->{wr_direction} and $departure->{wr_direction} eq 'l') { % $left = '◀ '; % } -% elsif ($departure->{direction} and $departure->{direction} eq 'r') { +% elsif ($departure->{wr_direction} and $departure->{wr_direction} eq 'r') { % $right = ' ▶'; % } % if ($departure->{scheduled_platform} and $departure->{platform} @@ -107,51 +110,49 @@ % elsif ($departure->{sched_departure}) { Ab: <%= $departure->{sched_departure} %> % } +% if ($departure->{tz_offset} and $departure->{local_sched_dep}) { + <br/>Lokal: <%= $departure->{local_sched_dep}->strftime('%H:%M') %> +% } </div> </div> </div> <!-- dataline --> % if (my $wr = $departure->{wr}) { <div class="wagonorder-preview"> -% my @wagons = $wr->wagons; -% my $direction = $wr->direction ? $wr->direction == 100 ? '→' : '←' : q{}; -% if ($departure->{direction}) { -% $direction = $departure->{direction} eq 'l' ? '◀' : '▶'; -% if (($departure->{direction} eq 'l' ? 0 : 100) != $wr->direction) { -% @wagons = reverse @wagons; -% } +% my $left = defined $wr->direction ? $wr->direction == 100 ? q{} : '←' : q{}; +% my $right = defined $wr->direction ? $wr->direction == 100 ? '→' : q{} : q{}; +% if ($departure->{wr_direction} and $departure->{wr_direction} eq 'l') { +% $left = '◀'; +% $right = q{}; % } - <a href="/_wr/<%= $departure->{train_no} %>/<%= $departure->{wr_link} %>?e=<%= $departure->{direction} // '' %>"> - %= $direction -% my $gi; -% for my $wagon (@wagons) { -% if (not ($wagon->is_locomotive or $wagon->is_powercar)) { -% if (defined $gi and $gi != $wagon->group_index) { - • -% } -% if ($wagon->is_closed) { - X -% } -% else { -%= $wagon->number || ($wagon->type =~ m{AB} ? '½' : $wagon->type =~ m{A} ? '1.' : $wagon->type =~ m{B} ? '2.' : $wagon->type ) -% } -% } -% $gi = $wagon->group_index; +% elsif ($departure->{wr_direction} and $departure->{wr_direction} eq 'r') { +% $left = q{}; +% $right = '▶'; % } - %= $direction + <a href="/_wr/<%= $departure->{train_no} %>/<%= $departure->{wr_link} %>?e=<%= $departure->{wr_direction} // '' %>"> + %= $left + % for my $entry ((defined $departure->{wr_direction_num} and $departure->{wr_direction_num} != $wr->direction) ? reverse @{$departure->{wr_preview} // []} : @{$departure->{wr_preview} // []}) { + % if ($entry->[1]) { + <span class="<%= $entry->[1] %>"><%= $entry->[0] %></span> + % } + % else { + %= $entry->[0] + % } + % } + %= $right </a> </div> % } <div class="verbose"> % if ($departure->{trip_id}) { % if (stash('station_name')) { - <a class="smallbutton" href="/map/<%= $departure->{trip_id} =~ s{#}{%23}gr %>/<%= $departure->{train_line} // 0 %>?from=<%= stash('station_name') %>&hafas=<%= param('hafas') // q{} %>"><i class="material-icons" aria-hidden="true">map</i> Karte</a> + <a class="smallbutton" href="/map/<%= $departure->{trip_id} =~ s{#}{%23}gr %>/<%= $departure->{train_line} || 0 %>?from=<%= stash('station_name') %>&hafas=<%= param('hafas') // q{} %>"><i class="material-icons" aria-hidden="true">map</i> Karte</a> % } % else { - <a class="smallbutton" href="/map/<%= $departure->{trip_id} =~ s{#}{%23}gr %>/<%= $departure->{train_line} // 0 %>?hafas=<%= param('hafas') // q{} %>"><i class="material-icons" aria-hidden="true">map</i> Karte</a> + <a class="smallbutton" href="/map/<%= $departure->{trip_id} =~ s{#}{%23}gr %>/<%= $departure->{train_line} || 0 %>?hafas=<%= param('hafas') // q{} %>"><i class="material-icons" aria-hidden="true">map</i> Karte</a> % } % } % if ($departure->{wr_link}) { - <a class="smallbutton" href="/_wr/<%= $departure->{train_no} %>/<%= $departure->{wr_link} %>?e=<%= $departure->{direction} // '' %>"><i class="material-icons" aria-hidden="true">train</i> <%= $departure->{wr_text} || 'Wagen' %> + <a class="smallbutton" href="/_wr/<%= $departure->{train_no} %>/<%= $departure->{wr_link} %>?e=<%= $departure->{wr_direction} // '' %>"><i class="material-icons" aria-hidden="true">train</i> <%= $departure->{wr_text} || 'Wagen' %> </a> % } % if ($departure->{train_type} and $departure->{train_no}) { @@ -237,6 +238,19 @@ % } <ul class="mroute"> % for my $stop (@{$departure->{route_pre_diff}}) { +% if ($stop->{is_annotated} and $stop->{prod_name}) { + <li class="annotation"> +% if ($stop->{prod_name}) { +%= $stop->{prod_name} +% } +% if ($stop->{direction}) { + → <%= $stop->{direction} %> +% } +% if ($stop->{operator}) { + (<%= $stop->{operator} %>) +% } + </li> +% } <li class="<%= $stop->{isPast} ? 'past-stop' : 'future-stop' %>"> <a href="<%= url_for('station', station => $stop->{eva} // $stop->{name})->query({detailed => param('detailed'), past => param('past'), rt => param('rt'), hafas => param('hafas')}) %>#<%= ($departure->{train_type} // q{x}) . ($departure->{train_no} // q{x}) %>" class=" % if ($stop->{isAdditional}) { @@ -252,13 +266,16 @@ generic-stop % } % if (($stop->{rt_dep} and $stop->{dep_delay}) or (not $stop->{rt_dep} and $stop->{rt_arr} and $stop->{arr_delay})) { - "><%= ($stop->{sched_dep} // $stop->{sched_arr})->strftime('%H:%M') %> (heute <%= ($stop->{rt_dep} // $stop->{rt_arr})->strftime('%H:%M') %>) + "><span class="time-sched-only"><%= ($stop->{sched_dep} // $stop->{sched_arr})->strftime('%H:%M') %></span> <span class="time-delayed"><%= ($stop->{rt_dep} // $stop->{rt_arr})->strftime('%H:%M') %></span> +% } +% elsif (($stop->{rt_dep} and defined $stop->{dep_delay}) or (not $stop->{rt_dep} and $stop->{rt_arr} and defined $stop->{arr_delay})) { + "><span class="time-sched-ontime"><%= ($stop->{sched_dep} // $stop->{sched_arr}) ? ($stop->{sched_dep} // $stop->{sched_arr})->strftime('%H:%M') : q{} %></span> % } % else { - "><%= ($stop->{sched_dep} // $stop->{sched_arr}) ? ($stop->{sched_dep} // $stop->{sched_arr})->strftime('%H:%M') : q{} %> -% if ($stop->{rt_bogus}) { - <i class="material-icons" aria-label="Echtzeitdaten fehlen">gps_off</i> -% } + "><span class="time-sched"><%= ($stop->{sched_dep} // $stop->{sched_arr}) ? ($stop->{sched_dep} // $stop->{sched_arr})->strftime('%H:%M') : q{} %></span> +% } +% if ($stop->{tz_offset} and $stop->{local_dt_da}) { + (lokal <%= $stop->{local_dt_da}->strftime('%H:%M') %>) % } <%= $stop->{name} %></a> % if ($stop->{load}{FIRST} or $stop->{load}{SECOND}) { @@ -269,15 +286,39 @@ </li> % } % if (stash('station_name')) { - <li class="<%= $departure->{is_cancelled} ? 'cancelled-stop' : q{} %> <%= $departure->{isPast} ? 'past-stop' : 'future-stop' %>"><%= $departure->{sched_departure} // $departure->{sched_arrival} // q{} %> +% if ($departure->{is_annotated} and $departure->{prod_name}) { + <li class="annotation"> +% if ($departure->{prod_name}) { +%= $departure->{prod_name} +% } +% if ($departure->{direction}) { + → <%= $departure->{direction} %> +% } +% if ($departure->{operator}) { + (<%= $departure->{operator} %>) +% } + </li> +% } + <li class="<%= $departure->{is_cancelled} ? 'cancelled-stop' : q{} %> <%= $departure->{isPast} ? 'past-stop' : 'future-stop' %>"> % if ($departure->{departure} and $departure->{sched_departure} and $departure->{departure} ne $departure->{sched_departure}) { - (heute <%= $departure->{departure} %>) + <span class="time-sched-only"><%= $departure->{sched_departure} // $departure->{sched_arrival} // q{} %></span><span class="time-delayed"> +% } +% elsif ($departure->{departure} and $departure->{sched_departure} and $departure->{departure} eq $departure->{sched_departure} and not $departure->{no_realtime_yet}) { + <span class="time-sched-ontime"> % } % elsif ($departure->{arrival} and $departure->{sched_arrival} and $departure->{arrival} ne $departure->{sched_arrival}) { - (heute <%= $departure->{arrival} %>) + <span class="time-sched-only"><%= $departure->{sched_departure} // $departure->{sched_arrival} // q{} %></span><span class="time-delayed"> +% } +% elsif ($departure->{arrival} and $departure->{sched_arrival} and $departure->{arrival} eq $departure->{sched_arrival} and not $departure->{no_realtime_yet}) { + <span class="time-sched-ontime"> % } -% if ($departure->{missing_realtime} or $departure->{no_realtime_yet}) { - <i class="material-icons" aria-label="Echtzeitdaten fehlen">gps_off</i> +% else { + <span class="time-sched"> +% } +%= $departure->{departure} // $departure->{arrival} // $departure->{sched_departure} // $departure->{sched_arrival} // q{} + </span> +% if ($departure->{tz_offset} and $departure->{local_dt_da}) { + (lokal <%= $departure->{local_dt_da}->strftime('%H:%M') %>) % } <strong><%= stash('station_name') %></strong> % if (my $u = $departure->{utilization}) { @@ -288,6 +329,19 @@ </li> % } % for my $stop (@{$departure->{route_post_diff}}) { +% if ($stop->{is_annotated} and $stop->{prod_name}) { + <li class="annotation"> +% if ($stop->{prod_name}) { +%= $stop->{prod_name} +% } +% if ($stop->{direction}) { + → <%= $stop->{direction} %> +% } +% if ($stop->{operator}) { + (<%= $stop->{operator} %>) +% } + </li> +% } <li class="<%= $stop->{isPast} ? 'past-stop' : 'future-stop' %>"> <a href="<%= url_for('station', station => $stop->{eva} // $stop->{name})->query({detailed => param('detailed'), past => param('past'), rt => param('rt'), hafas => param('hafas')}) %>#<%= ($departure->{train_type} // q{x}) . ($departure->{train_no} // q{x}) %>" class=" % if ($stop->{isAdditional}) { @@ -303,13 +357,16 @@ generic-stop % } % if (($stop->{rt_arr} and $stop->{arr_delay}) or (not $stop->{rt_arr} and $stop->{rt_dep} and $stop->{dep_delay})) { - "><%= ($stop->{sched_arr} // $stop->{sched_dep})->strftime('%H:%M') %> (heute <%= ($stop->{rt_arr} // $stop->{rt_dep})->strftime('%H:%M') %>) + "><span class="time-sched-only"><%= ($stop->{sched_arr} // $stop->{sched_dep})->strftime('%H:%M') %></span> <span class="time-delayed"><%= ($stop->{rt_arr} // $stop->{rt_dep})->strftime('%H:%M') %></span> +% } +% elsif (($stop->{rt_arr} and defined $stop->{arr_delay}) or (not $stop->{rt_arr} and $stop->{rt_dep} and defined $stop->{dep_delay})) { + "><span class="time-sched-ontime"><%= ($stop->{sched_arr} // $stop->{sched_dep}) ? ($stop->{sched_arr} // $stop->{sched_dep})->strftime('%H:%M') : q{} %></span> % } % else { - "><%= ($stop->{sched_arr} // $stop->{sched_dep}) ? ($stop->{sched_arr} // $stop->{sched_dep})->strftime('%H:%M') : q{} %> -% if ($stop->{rt_bogus}) { - <i class="material-icons" aria-label="Echtzeitdaten fehlen">gps_off</i> -% } + "><span class="time-sched"><%= ($stop->{sched_arr} // $stop->{sched_dep}) ? ($stop->{sched_arr} // $stop->{sched_dep})->strftime('%H:%M') : q{} %></span> +% } +% if ($stop->{tz_offset} and $stop->{local_dt_ad}) { + (lokal <%= $stop->{local_dt_ad}->strftime('%H:%M') %>) % } <%= $stop->{name} %></a> % if ($stop->{load}{FIRST} or $stop->{load}{SECOND}) { @@ -321,8 +378,8 @@ % } </ul> <!-- mroute --> % } -% if ($departure->{operator}) { - <div class="details">Betrieb: <%= $departure->{operator} %></div> +% if ($departure->{operators} and @{$departure->{operators} // []}) { + <div class="details">Betrieb: <%= join(q{, }, @{ $departure->{operators} // [] } ) %></div> % } % if ($departure->{details} and @{$departure->{details}}) { <div class="details">Details: diff --git a/templates/_wagon.html.ep b/templates/_wagon.html.ep index 2f5a0df..59a2ca1 100644 --- a/templates/_wagon.html.ep +++ b/templates/_wagon.html.ep @@ -44,9 +44,9 @@ % } % } <div class="direction"> -% if (not defined $direction) { +% if (not defined $wr->direction) { % } -% elsif ($direction == 100) { +% elsif ($wr->direction == 100) { <i class="material-icons">arrow_downward</i> % } % else { @@ -57,7 +57,7 @@ <div class="details" style=" top: <%= $wagon->{position}{start_percent} %>%; bottom: <%= 100 - $wagon->{position}{end_percent} %>%;"> % if ($exit_dir ne 'right') { -% if (my $img = wagon_image($wagon->train_subtype // $type // '?', $wagon->type, $wagon->uic_id)) { +% if (my $img = wagon_image($wagon->train_subtype // $wr->train_type // '?', $wagon->type, $wagon->uic_id)) { <a class="type" href="/w/<%= $img %>?n=<%= $wagon->number // '' %>&s=<%= $wagon->section %>&r=<%= $wref %>"><%= $wagon->type %></a> % } % else { @@ -77,7 +77,7 @@ <span class="uicexchange"><%= substr($uic_id, 0, 2) %></span><span class="uiccountry"><%= substr($uic_id, 2, 2) %></span><span class="uic56"><%= substr($uic_id, 4, 2) %></span><span class="uic78"><%= substr($uic_id, 6, 2) %></span><span class="uicno"><%= substr($uic_id, 8, 3) %></span><span class="uiccheck"><%= substr($uic_id, 11) %></span> % } % if ($exit_dir eq 'right') { -% if (my $img = wagon_image($wagon->train_subtype // $type // '?', $wagon->type, $wagon->uic_id)) { +% if (my $img = wagon_image($wagon->train_subtype // $wr->train_type // '?', $wagon->type, $wagon->uic_id)) { <a class="type" href="/w/<%= $img %>?n=<%= $wagon->number // '' %>&s=<%= $wagon->section %>&r=<%= $wref %>"><%= $wagon->type %></a> % } % else { @@ -86,4 +86,18 @@ </span> % } % } +% if ($multi and $first) { + <br/> + <span class="groupno"> +% if (scalar $wr->train_nos > 1) { + <%= $wr->train_type %> <%= ($wr->groups)[$wagon->group_index]->train_no %> +% } +% if (scalar $wr->destinations > 1) { + → <%= $wr->{data}{istformation}{allFahrzeuggruppe}[$wagon->group_index]{zielbetriebsstellename} %> +% } + </span> + % if ($multi and ($wr->groups)[$wagon->group_index]->desc_short) { + <span class="grouptype"><%= ($wr->groups)[$wagon->group_index]->desc_short %></span> +% } +% } </div> diff --git a/templates/about.html.ep b/templates/about.html.ep index f299389..b5af92b 100644 --- a/templates/about.html.ep +++ b/templates/about.html.ep @@ -4,7 +4,7 @@ Der Fokus liegt auf Zügen im Netz der Deutschen Bahn; eingeschränkte Unterstützung für Nahverkehr und Züge in anderen Netzen lässt sich optional zuschalten. </p> <p> - Der <a href="<%= app->config->{'source_url'} %>">Quelltext</a> steht unter der <a href="https://git.finalrewind.org/db-fakedisplay/tree/COPYING">GNU AGPL v3</a> als Open Source zur Verfügung. © 2011 – 2023 <a href="https://finalrewind.org">derf</a>. + Der <a href="<%= app->config->{'source_url'} %>">Quelltext</a> steht unter der <a href="https://git.finalrewind.org/db-fakedisplay/tree/COPYING">GNU AGPL v3</a> als Open Source zur Verfügung. © 2011 – 2024 <a href="https://finalrewind.org">derf</a>. % if (my $issue_url = app->config->{'issue_url'}) { Fehlermeldungen bitte via <a href="<%= $issue_url %>">Issue Tracker</a>. @@ -17,32 +17,37 @@ und die Bezeichnung DBF wurde zum Eigennamen ohne weitere Bedeutung. </p> <p> - Diese Installation verwendet die DBF-Version - <b><%= stash('version') // '???' %></b> und greift auf die folgenden Backends - zu:<br/> - • Regional- und Fernverkehr: DB IRIS via <a href="https://finalrewind.org/projects/Travel-Status-DE-IRIS/">Travel::Status::DE::IRIS</a> - v<%= $Travel::Status::DE::IRIS::VERSION %><br/> - • Nahverkehr und Zugdetails: DB HAFAS via <a href="https://finalrewind.org/projects/Travel-Status-DE-DeutscheBahn/">Travel::Status::DE::HAFAS</a> - % if ($Travel::Status::DE::HAFAS::VERSION) { - v<%= $Travel::Status::DE::HAFAS::VERSION %> - % } - <br/> - • Wagenreihung: <a href="https://finalrewind.org/projects/Travel-Status-DE-DBWagenreihung/">Travel::Status::DE::DBWagenreihung</a> - % if ($Travel::Status::DE::DBWagenreihung::VERSION) { - v<%= $Travel::Status::DE::DBWagenreihung::VERSION %> + Diese Installation nutzt + <strong>DBF v<%= stash('version') // '???' %></strong> mit folgenden Backends: + <ul> + <li> Innerdeutscher Regional- und Fernverkehr: DB IRIS via <a href="https://finalrewind.org/projects/Travel-Status-DE-IRIS/">Travel::Status::DE::IRIS</a> + <strong>v<%= $Travel::Status::DE::IRIS::VERSION %></strong></li> + <li> Außerdeutsche Fahrten, Nahverkehr, Details, Karten: HAFAS via <a href="https://finalrewind.org/projects/Travel-Status-DE-DeutscheBahn/">Travel::Status::DE::HAFAS</a> + <strong>v<%= $Travel::Status::DE::HAFAS::VERSION %></strong></li> + <li>Wagenreihung: <a href="https://finalrewind.org/projects/Travel-Status-DE-DBWagenreihung/">Travel::Status::DE::DBWagenreihung</a> + <strong>v<%= $Travel::Status::DE::DBWagenreihung::VERSION %></strong></li> + <li>Zugauslastung Regionalverkehr: VRR EFA via <a href="https://github.com/derf/eva-to-efa-gw">eva-to-efa-gw</a></li> + </ul> + </p> + <p> + Unterstützte HAFAS-Instanzen („hafas=…“): + <ul> + % for my $service (Travel::Status::DE::HAFAS::get_services()) { + <li><%= $service->{shortname} %> (<%= $service->{name} %>)</li> % } - <br/> - • Zugauslastung Regionalverkehr: VRR EFA via <a href="https://github.com/derf/eva-to-efa-gw">eva-to-efa-gw</a><br/> - <br/> - Sie nutzt zusätzlich die folgenden Open Data-Ressourcen:<br/> - • <a href="https://data.deutschebahn.com/dataset/zugbildungsplanzugbildungsplan-zpar">Zugbildungsplan</a> © DB Fernverkehr AG, lizensiert unter CC-BY 4.0 - <br/> - • <a href="http://data.deutschebahn.com/dataset/data-haltestellen">Haltestellenliste</a> + </ul> + </p> + <p> + Verwendete Open Data-Ressourcen: + <ul> + <li><a href="https://data.deutschebahn.com/dataset/zugbildungsplanzugbildungsplan-zpar">Zugbildungsplan</a> © DB Fernverkehr AG, lizensiert unter CC-BY 4.0</li> + <li><a href="http://data.deutschebahn.com/dataset/data-haltestellen">Haltestellenliste</a> © DB Station&Service AG, Europaplatz 1, - 10557 Berlin, lizensiert unter CC-BY 4.0<br/> - • <a href="https://data.deutschebahn.com/dataset/fahrzeuglexikon">Fahrzeuglexikon</a> - © DB Fernverkehr AG, lizensiert unter CC-BY 4.0; Abbildungen © Seemanngrafik d.i.p. im Auftrag der Deutschen Bahn AG, lizensiert unter CC-BY-SA 4.0<br/> + 10557 Berlin, lizensiert unter CC-BY 4.0</li> + <li><a href="https://data.deutschebahn.com/dataset/fahrzeuglexikon">Fahrzeuglexikon</a> + © DB Fernverkehr AG, lizensiert unter CC-BY 4.0; Abbildungen © Seemanngrafik d.i.p. im Auftrag der Deutschen Bahn AG, lizensiert unter CC-BY-SA 4.0</li> + </ul> </p> </div> diff --git a/templates/exception.html.ep b/templates/exception.html.ep index 65ec7ff..7654c0b 100644 --- a/templates/exception.html.ep +++ b/templates/exception.html.ep @@ -5,7 +5,7 @@ Beim Bearbeiten der Anfrage ist ein Fehler aufgetreten.<br/> <pre> ----------[Debug start]---------- % if ($exception) { -%= $exception->message +%= ref($exception) ? $exception->message : $exception Stash: %= dumper $snapshot % } diff --git a/templates/landingpage.html.ep b/templates/landingpage.html.ep index 82128ca..17bb2bb 100644 --- a/templates/landingpage.html.ep +++ b/templates/landingpage.html.ep @@ -21,7 +21,7 @@ </p> % } <p class="geolink"> -<a class="button" href="<%= url_for('_autostop')->to_abs->scheme('https') %>">Stationen in der Umgebung suchen</a> +<a class="button" href="<%= url_for('_autostop')->to_abs->scheme('https')->query({hafas => param('hafas')}) %>">Stationen in der Umgebung suchen</a> </p> <p> Oder hier angeben: diff --git a/templates/layouts/app.html.ep b/templates/layouts/app.html.ep index ae3a7a2..9c39019 100644 --- a/templates/layouts/app.html.ep +++ b/templates/layouts/app.html.ep @@ -18,7 +18,7 @@ <meta http-equiv="refresh" content="<%= $self->stash('refresh_interval') %>"/> % } - % my $av = 'v91'; # asset version + % my $av = 'v99'; # asset version % if (session('theme') and session('theme') eq 'dark' or param('dark')) { %= stylesheet "/static/${av}/css/dark.min.css", id => 'theme' % } @@ -138,7 +138,7 @@ Bitte eine Station aus der Liste auswählen</div> </div> % if (stash('input')) { <div class="geolink"> - <a class="button" href="<%= url_for('_autostop')->to_abs->scheme('https') %>">Stationen in der Umgebung suchen</a> + <a class="button" href="<%= url_for('_autostop')->to_abs->scheme('https')->query({hafas => param('hafas')}) %>">Stationen in der Umgebung suchen</a> </div> % } <div class="break"></div> diff --git a/templates/layouts/legacy.html.ep b/templates/layouts/legacy.html.ep index 3de0374..5389c4b 100644 --- a/templates/layouts/legacy.html.ep +++ b/templates/layouts/legacy.html.ep @@ -17,13 +17,13 @@ <meta http-equiv="refresh" content="<%= $self->stash('refresh_interval') %>"/> % } - % my $av = 'v91'; # asset version - %= stylesheet "/static/${av}/css/default.css" + % my $av = 'v99'; # asset version + %= stylesheet "/static/${av}/css/legacy.css" %= stylesheet "/static/${av}/css/material-icons.css" %= stylesheet "/static/${av}/css/jquery-ui.min.css" % my $force_mobile = param('force_mobile') // stash('force_mobile'); % if ($force_mobile) { - %= stylesheet "/static/${av}/css/mobile.css" + %= stylesheet "/static/${av}/css/legacy-mobile.css" % } %if (stash('load_marquee')) { %= javascript '/static/js/jquery-3.4.1.min.js' diff --git a/templates/wagenreihung.html.ep b/templates/wagenreihung.html.ep index 493d9c6..6781dca 100644 --- a/templates/wagenreihung.html.ep +++ b/templates/wagenreihung.html.ep @@ -7,37 +7,10 @@ </div> % } % else { - % my $has_multi_dest = 0; - % my $has_multi_desc = 0; - % if (scalar $wr->destinations > 1) { - % $has_multi_dest = 1; - % } - % if (scalar $wr->train_descriptions > 1) { - % $has_multi_desc = 1; - % } <div class="container"> <div style="text-align: center;"> -%= join( ' / ', $wr->origins ) - → -%= join( ' / ', map { $_->{name} } $wr->destinations ) + <%= $wr->station->{name} %> Gleis <%= $wr->platform %><br/> </div> - % if ($has_multi_dest) { - <div style="text-align: center;"> - % for my $destination ($wr->destinations) { - Nach <%= $destination->{name} %> in Abschnitt <%= join(q{}, sort @{$destination->{sections} // []}) %><br/> - % } - </div> - % } - <%= $wr->station_name %> Gleis <%= $wr->platform %><br/> - % for my $desc ($wr->train_descriptions) { - % if ($desc->{text}) { - %= $desc->{text} - % if ($has_multi_desc and length(join(q{}, sort @{$desc->{sections}}))) { - in Abschnitt <%= join(q{}, sort @{$desc->{sections}}) %> - % } - <br/> - % } - % } </div> <div class="container"> <div class="wagonorder exit-<%= stash('exit_dir') // 'unknown'%>"> @@ -49,10 +22,29 @@ </div> % } % } -% for my $wagon ($wr->wagons) { -%= include '_wagon', direction => $wr->direction, wagon => $wagon, type => $wr->train_type, wref => $wref, exit_dir => stash('exit_dir'); +% for my $group ($wr->groups) { +% my $first = 1; +% for my $wagon ($group->wagons) { +%= include '_wagon', wr => $wr, wagon => $wagon, first => $first, multi => (scalar $wr->destinations) - 1 + (scalar $wr->train_nos) - 1, wref => $wref, exit_dir => stash('exit_dir'); +% $first = 0; +% } % } </div> + <div style="text-align: center;"> +%= join( ' / ', map { $_->{name} } $wr->origins ) + → +%= join( ' / ', map { $_->{name} } $wr->destinations ) + </div> + % for my $group ($wr->groups) { + % if ($group->description) { + <div style="text-align: center;"> + %= $group->description + % if (scalar $wr->groups > 1 and $group->has_sections) { + in Abschnitt <%= join(q{}, sort $group->sections) %> + % } + </div> + % } + % } <!-- <div> Legende: ♿ Behindertengerechte Ausstattung / 🍴 Bistro/Restaurant / 🚪 Abteile vorhanden </div> |