diff options
| -rw-r--r-- | lib/DBInfoscreen.pm | 8 | ||||
| -rw-r--r-- | lib/DBInfoscreen/Controller/Stationboard.pm | 35 | ||||
| -rw-r--r-- | public/static/css/app.css | 736 | ||||
| -rw-r--r-- | public/static/css/default.css | 367 | ||||
| -rw-r--r-- | templates/layouts/app.html.ep | 258 | ||||
| -rw-r--r-- | templates/layouts/legacy.html.ep (renamed from templates/layouts/default.html.ep) | 0 | 
6 files changed, 1015 insertions, 389 deletions
| diff --git a/lib/DBInfoscreen.pm b/lib/DBInfoscreen.pm index d83f58f..44a5520 100644 --- a/lib/DBInfoscreen.pm +++ b/lib/DBInfoscreen.pm @@ -261,7 +261,7 @@ sub startup {  	$r->get('/_wr/:train/:departure')->to('wagenreihung#wagenreihung'); -	$self->defaults( layout => 'default' ); +	$self->defaults( layout => 'app' );  	$self->sessions->default_expiration( 3600 * 24 * 28 );  	$r->get('/')->to('stationboard#handle_request'); @@ -270,12 +270,12 @@ sub startup {  	$self->config(  		hypnotoad => { -			accepts  => $ENV{DBFAKEDISPLAY_ACCEPTS} // 100, -			clients  => $ENV{DBFAKEDISPLAY_CLIENTS} // 10, +			accepts => $ENV{DBFAKEDISPLAY_ACCEPTS} // 100, +			clients => $ENV{DBFAKEDISPLAY_CLIENTS} // 10,  			listen   => [ $ENV{DBFAKEDISPLAY_LISTEN} // 'http://*:8092' ],  			pid_file => $ENV{DBFAKEDISPLAY_PID_FILE}  			  // '/tmp/db-fakedisplay.pid', -			spare   => $ENV{DBFAKEDISPLAY_SPARE} // 2, +			spare   => $ENV{DBFAKEDISPLAY_SPARE}   // 2,  			workers => $ENV{DBFAKEDISPLAY_WORKERS} // 2,  		},  	); diff --git a/lib/DBInfoscreen/Controller/Stationboard.pm b/lib/DBInfoscreen/Controller/Stationboard.pm index 862ba12..e0e778d 100644 --- a/lib/DBInfoscreen/Controller/Stationboard.pm +++ b/lib/DBInfoscreen/Controller/Stationboard.pm @@ -373,22 +373,22 @@ sub handle_request {  	my $via     = $self->param('via');  	my @platforms = split( /,/, $self->param('platforms') // q{} ); -	my @lines     = split( /,/, $self->param('lines') // q{} ); -	my $template  = $self->param('mode') // 'app'; -	my $hide_low_delay = $self->param('hidelowdelay') // 0; -	my $hide_opts      = $self->param('hide_opts') // 0; +	my @lines     = split( /,/, $self->param('lines')     // q{} ); +	my $template       = $self->param('mode')          // 'app'; +	my $hide_low_delay = $self->param('hidelowdelay')  // 0; +	my $hide_opts      = $self->param('hide_opts')     // 0;  	my $show_realtime  = $self->param('show_realtime') // 0; -	my $show_details   = $self->param('detailed') // 0; -	my $backend        = $self->param('backend') // 'iris'; -	my $admode         = $self->param('admode') // 'deparr'; -	my $dark_layout    = $self->param('dark') // 0; -	my $apiver         = $self->param('version') // 0; +	my $show_details   = $self->param('detailed')      // 0; +	my $backend        = $self->param('backend')       // 'iris'; +	my $admode         = $self->param('admode')        // 'deparr'; +	my $dark_layout    = $self->param('dark')          // 0; +	my $apiver         = $self->param('version')       // 0;  	my $callback       = $self->param('callback');  	my $with_related   = !$self->param('no_related');  	my $save_defaults  = $self->param('save_defaults') // 0; -	my $limit          = $self->param('limit') // 0; -	my @train_types    = split( /,/, $self->param('train_types') // q{} ); -	my %opt            = ( +	my $limit          = $self->param('limit')         // 0; +	my @train_types = split( /,/, $self->param('train_types') // q{} ); +	my %opt         = (  		cache_hafas     => $self->app->cache_hafas,  		cache_iris_main => $self->app->cache_iris_main,  		cache_iris_rt   => $self->app->cache_iris_rt, @@ -423,6 +423,9 @@ sub handle_request {  	elsif ( defined $station and $station =~ s{ [.] json $ }{}x ) {  		$template = 'json';  	} +	elsif ( $template ne 'app' ) { +		$self->stash( layout => 'legacy' ); +	}  	# Historically, there were two JSON APIs: 'json' (undocumented, raw  	# passthrough of serialized Travel::Status::DE::IRIS::Result / @@ -452,11 +455,7 @@ sub handle_request {  				$self->param( $param => $self->session($param) );  			}  		} -		$self->render( -			'landingpage', -			hide_opts  => 0, -			show_intro => 1 -		); +		$self->render( 'landingpage', show_intro => 1 );  		return;  	} @@ -554,7 +553,7 @@ sub handle_request {  	for my $result (@results) {  		my $platform = ( split( qr{ }, $result->platform // '' ) )[0]; -		my $delay = $result->delay; +		my $delay    = $result->delay;  		if ( $backend eq 'iris' and $admode eq 'arr' and not $result->arrival )  		{  			next; diff --git a/public/static/css/app.css b/public/static/css/app.css new file mode 100644 index 0000000..9cabc12 --- /dev/null +++ b/public/static/css/app.css @@ -0,0 +1,736 @@ +body { +	margin: 0; +} + +html { +	font-family: Sans-Serif; +} + +a { +	color: #000099; +	text-decoration: none; +} + +p, +div.about, +div.input-field, +div.notes { +	max-width: 94%; +	margin-left: auto; +	margin-right: auto; +} + +p { +	text-align: justify; +} + +div.content { +	width: 100%; +	margin: 0; +} + +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; +	cursor: pointer; +} + +div.appdark > ul > li { +	border-bottom: 1px solid #999999; +	background-color: #000000; +} + +div.applight > ul > li { +	border-bottom: 1px solid #999999; +	background-color: #ffffff; +} + +div.app li .line { +	font-size: 2.7em; +	position:absolute; +	bottom:5px; +	left:2px; +	max-width: 6em; +	max-height: 3ex; +	overflow: hidden; +} + +div.app li .line .trainno { +	font-weight: normal; +} + +div.app li .line .trainno_sub { +	font-weight: normal; +	font-size: 0.6em; +	text-align: center; +	margin-top: -0.2em; +} + +div.app li .sbahn .trainno_sub { +	font-weight: normal; +	font-size: 0.5em; +	text-align: center; +	margin-top: -0.25em; +} + +div.app li .lineinfo { +	color:#000000; +	font-size: 2em; +	position:absolute; +	top:0px; +	left:2px; +} + +div.app .replacement { +	color: #006600; +} + +div.app .replaced { +	color: #660000; +} + +div.app .sbahn { +	font-weight:bold; +	border-radius: 30px; +	padding:3px 6px 2px 6px; +} + +div.applight .sbahn { +	background-color:#95d79f; +} + +div.appdark .sbahn { +	background-color:#115511; +} + +div.app .bahn, +div.app .fern, +div.app .ext { +	font-weight:bold; +	border-radius: 5px; +	padding:3px 5px 2px 5px; +} + +div.applight .bahn { +	background-color: #eeeeee; +} + +div.appdark .bahn { +	background-color: #333333; +} + +div.applight .fern { +	background-color: #ffdddd; +} + +div.appdark .fern { +	background-color: #551111; +} + +div.applight .ext { +	background-color: #ffdddd; +	border: 2px solid #ff6666; +} + +div.appdark .ext { +	background-color: #551111; +	border: 2px solid #993333; +} + +div.app li .route { +	background-color: transparent; +	font-size:2.1em; +	position:absolute; +	top:1px; +	left:7.7em; +	height: 1.2em; +	width: 70%; +	overflow: hidden; +} + +div.applight li .route { +	color:#444444; +} + +div.appdark li .route { +	color:#bbbbbb; +} + +div.app li .info { +	color:#ff0000; +	background-color: transparent; +	font-size:2.1em; +	position:absolute; +	top:1px; +	left:7.7em; +	height: 1.2em; +	width: 70%; +	overflow: hidden; +} + +div.app .moreinfo { +	font-size:2.1em; +	position:fixed; +	top:64px; +	left:0; +	right:0; +	bottom:0em; +	z-index: 5; +	overflow: auto; +	cursor: default; +} + +div.app .moreinfo .mheader, +div.app .moreinfo .mfooter { +	max-width: 50em; +	margin-left: auto; +	margin-right: auto; +} + +div.applight .moreinfo { +	background-color: #ffffff; +} + +div.appdark .moreinfo { +	background-color: #000000; +} + +div.app .collapsed-moreinfo { +	display: none; +} + +div.app .expanded-moreinfo { +	display: block; +} + +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: 1em; +	padding-left: 1em; +	padding-right: 1em; +} + +div.app .moreinfo .reason, +div.app .moreinfo .minfo { +	color: #ff0000; +} + +div.app .moreinfo .verbose { +	margin-bottom: 0.6em; +} + +div.app .moreinfo .timeinfo { +	margin-bottom: 0.6em; +} + +div.applight .moreinfo .mroute .important-stop { +	color: #000000; +} + +div.appdark .moreinfo .mroute .important-stop { +	color: #ffffff; +} + +div.applight .moreinfo .mroute .generic-stop { +	color: #555555; +} + +div.appdark .moreinfo .mroute .generic-stop { +	color: #999999; +} + +div.applight .moreinfo .mroute .additional-stop { +	color: #009900; +} + +div.appdark .moreinfo .mroute .additional-stop { +	color: #009900; +} + +div.applight .moreinfo .mroute .cancelled-stop { +	color: #cc0000; +} + +div.appdark .moreinfo .mroute .cancelled-stop { +	color: #cc0000; +} + +div.app li .dest { +	background-color: transparent; +	font-size:4em; +	position:absolute; +	top:0.62em; +	left:4em; +	bottom:0px; +	width: 70%; +	overflow: hidden; +} + +div.applight li .dest { +	color:#000000; +} + +div.appdark li .dest { +	color:#ffffff; +} + +div.applight li.cancelled { +	background-color: #ffe7d0; +} + +div.appdark li.cancelled { +	background-color: #512f00; +} + +div.app li .countdown { +	background-color: transparent; +	font-size: 3em; +	position: absolute; +	right: 5px; +	bottom: 2px; +	padding-left: 0.2em; +} + +div.applight li .countdown { +	color: #000000; +} + +div.appdark li .countdown { +	color: #ffffff; +} + +div.app li .header { +	color:#000000; +	font-size:2em; +	font-weight:bold; +	padding-top:8px; +	border-width-top:0; +	display:block; +	text-align:center; +} + +div.app li .head { +	border-bottom-width:0; +} + +div.app li .countdown .delay { +	font-size:1em; +	color:#FF0000; +	background-color: transparent; +	padding-right:7px; +} + +div.app li .countdown .undelay { +	font-size:1em; +	color:#006600; +	padding-right:7px; +} + +div.app li .countdown .delaynorm { +	font-size:0.9em; +	color:#BB3333; +	padding-right:7px; +} + +div.app li .countdown .undelaynorm { +	font-size:0.9em; +	color:#338833; +	padding-right:7px; +} + +div.app li .countdown .platform { +	font-weight: bold; +} + +div.app li .countdown .changed-platform { +	color:#ff0000; +} + +div.app li .time { +	background-color: transparent; +	font-size:2.3em; +	position:absolute; +	right:5px; +	top:4px; +	padding-left: 0.2em; +} + +div.applight li .time { +	color:#000000; +} + +div.appdark li .time { +	color:#ffffff; +} + +div.app span.delayed { +	color: #ff0000; +	background-color: transparent; +} + +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.about { +	margin-top: 2em; +	font-family: Sans-Serif; +	color: #666666; +} + +div.about a { +	color: #000066; +	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: #666666; +} + +.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; +} + +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,.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 { +	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 { +	color: #fff; +	background-color: #286090; +	border-color: #204d74; +} + +input[type="submit"]:active, +.button.active { +	box-shadow: inset 0 3px 5px rgba(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,.14), 0 3px 1px -2px rgba(0,0,0,.12), 0 1px 5px 0 rgba(0,0,0,.2); +} + +nav { +	width: 100%; +} + +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; +	font-size: 2.1rem; +	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; +} + +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 .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; +	} +	nav { +		height: 64px; +		line-height: 64px; +	} +	nav .nav-wrapper i { +		height: 64px; +		line-height: 64px; +	} +} + +div.app .moreinfo { +	font-size: 100%; +} + +.content { +} diff --git a/public/static/css/default.css b/public/static/css/default.css index aca2dba..f5cb255 100644 --- a/public/static/css/default.css +++ b/public/static/css/default.css @@ -29,373 +29,6 @@ div.content {  	margin: 0;  } -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; -	cursor: pointer; -} - -div.appdark > ul > li { -	border-bottom: 1px solid #999999; -	background-color: #000000; -} - -div.applight > ul > li { -	border-bottom: 1px solid #999999; -	background-color: #ffffff; -} - -div.app li .line { -	font-size: 2.7em; -	position:absolute; -	bottom:5px; -	left:2px; -	max-width: 6em; -	max-height: 3ex; -	overflow: hidden; -} - -div.app li .line .trainno { -	font-weight: normal; -} - -div.app li .line .trainno_sub { -	font-weight: normal; -	font-size: 0.6em; -	text-align: center; -	margin-top: -0.2em; -} - -div.app li .sbahn .trainno_sub { -	font-weight: normal; -	font-size: 0.5em; -	text-align: center; -	margin-top: -0.25em; -} - -div.app li .lineinfo { -	color:#000000; -	font-size: 2em; -	position:absolute; -	top:0px; -	left:2px; -} - -div.app .replacement { -	color: #006600; -} - -div.app .replaced { -	color: #660000; -} - -div.app .sbahn { -	font-weight:bold; -	border-radius: 30px; -	padding:3px 6px 2px 6px; -} - -div.applight .sbahn { -	background-color:#95d79f; -} - -div.appdark .sbahn { -	background-color:#115511; -} - -div.app .bahn, -div.app .fern, -div.app .ext { -	font-weight:bold; -	border-radius: 5px; -	padding:3px 5px 2px 5px; -} - -div.applight .bahn { -	background-color: #eeeeee; -} - -div.appdark .bahn { -	background-color: #333333; -} - -div.applight .fern { -	background-color: #ffdddd; -} - -div.appdark .fern { -	background-color: #551111; -} - -div.applight .ext { -	background-color: #ffdddd; -	border: 2px solid #ff6666; -} - -div.appdark .ext { -	background-color: #551111; -	border: 2px solid #993333; -} - -div.app li .route { -	background-color: transparent; -	font-size:2.1em; -	position:absolute; -	top:1px; -	left:7.7em; -	height: 1.2em; -	width: 70%; -	overflow: hidden; -} - -div.applight li .route { -	color:#444444; -} - -div.appdark li .route { -	color:#bbbbbb; -} - -div.app li .info { -	color:#ff0000; -	background-color: transparent; -	font-size:2.1em; -	position:absolute; -	top:1px; -	left:7.7em; -	height: 1.2em; -	width: 70%; -	overflow: hidden; -} - -div.app .moreinfo { -	font-size:2.1em; -	position:fixed; -	top:0em; -	left:0; -	right:0; -	bottom:0em; -	z-index: 5; -	overflow: auto; -	cursor: default; -} - -div.app .moreinfo .mheader, -div.app .moreinfo .mfooter { -	max-width: 50em; -	margin-left: auto; -	margin-right: auto; -} - -div.applight .moreinfo { -	background-color: #ffffff; -} - -div.appdark .moreinfo { -	background-color: #000000; -} - -div.app .collapsed-moreinfo { -	display: none; -} - -div.app .expanded-moreinfo { -	display: block; -} - -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: 1em; -	padding-left: 1em; -	padding-right: 1em; -} - -div.app .moreinfo .reason, -div.app .moreinfo .minfo { -	color: #ff0000; -} - -div.app .moreinfo .verbose { -	margin-bottom: 0.6em; -} - -div.app .moreinfo .timeinfo { -	margin-bottom: 0.6em; -} - -div.applight .moreinfo .mroute .important-stop { -	color: #000000; -} - -div.appdark .moreinfo .mroute .important-stop { -	color: #ffffff; -} - -div.applight .moreinfo .mroute .generic-stop { -	color: #555555; -} - -div.appdark .moreinfo .mroute .generic-stop { -	color: #999999; -} - -div.applight .moreinfo .mroute .additional-stop { -	color: #009900; -} - -div.appdark .moreinfo .mroute .additional-stop { -	color: #009900; -} - -div.applight .moreinfo .mroute .cancelled-stop { -	color: #cc0000; -} - -div.appdark .moreinfo .mroute .cancelled-stop { -	color: #cc0000; -} - -div.app li .dest { -	background-color: transparent; -	font-size:4em; -	position:absolute; -	top:0.62em; -	left:4em; -	bottom:0px; -	width: 70%; -	overflow: hidden; -} - -div.applight li .dest { -	color:#000000; -} - -div.appdark li .dest { -	color:#ffffff; -} - -div.applight li.cancelled { -	background-color: #ffe7d0; -} - -div.appdark li.cancelled { -	background-color: #512f00; -} - -div.app li .countdown { -	background-color: transparent; -	font-size: 3em; -	position: absolute; -	right: 5px; -	bottom: 2px; -	padding-left: 0.2em; -} - -div.applight li .countdown { -	color: #000000; -} - -div.appdark li .countdown { -	color: #ffffff; -} - -div.app li .header { -	color:#000000; -	font-size:2em; -	font-weight:bold; -	padding-top:8px; -	border-width-top:0; -	display:block; -	text-align:center; -} - -div.app li .head { -	border-bottom-width:0; -} - -div.app li .countdown .delay { -	font-size:1em; -	color:#FF0000; -	background-color: transparent; -	padding-right:7px; -} - -div.app li .countdown .undelay { -	font-size:1em; -	color:#006600; -	padding-right:7px; -} - -div.app li .countdown .delaynorm { -	font-size:0.9em; -	color:#BB3333; -	padding-right:7px; -} - -div.app li .countdown .undelaynorm { -	font-size:0.9em; -	color:#338833; -	padding-right:7px; -} - -div.app li .countdown .platform { -	font-weight: bold; -} - -div.app li .countdown .changed-platform { -	color:#ff0000; -} - -div.app li .time { -	background-color: transparent; -	font-size:2.3em; -	position:absolute; -	right:5px; -	top:4px; -	padding-left: 0.2em; -} - -div.applight li .time { -	color:#000000; -} - -div.appdark li .time { -	color:#ffffff; -} - -div.app span.delayed { -	color: #ff0000; -	background-color: transparent; -} - -/* ... */ -  div.infoscreen {  	border-width:1px 2px;  	width:100%; diff --git a/templates/layouts/app.html.ep b/templates/layouts/app.html.ep new file mode 100644 index 0000000..6189c9c --- /dev/null +++ b/templates/layouts/app.html.ep @@ -0,0 +1,258 @@ +<!DOCTYPE html> +<html lang="de"> +<head> +	<title><%= stash('title') // 'DBF' %></title> +	<meta charset="utf-8"> +	<meta name="viewport" content="width=device-width, initial-scale=1.0"> +	<meta name="keywords" content="Abfahrtsmonitor, Bahnhofstafel, Abfahrten, Abfahrtstafel, ICE, IC, RE, RB, S-Bahn"> +	<meta name="description" content="Inoffizieller Abfahrtsmonitor für Bahnhöfe der DB"> +	<meta name="theme-color" content="#00838f"> +	<link rel="icon" type="image/png" href="/static/icons/icon-16x16.png" sizes="16x16"> +	<link rel="icon" type="image/png" href="/static/icons/icon-32x32.png" sizes="32x32"> +	<link rel="icon" type="image/png" href="/static/icons/icon-96x96.png" sizes="96x96"> +	<link rel="apple-touch-icon" href="/static/icons/icon-120x120.png"> +	<link rel="apple-touch-icon" sizes="180x180" href="/static/icons/icon-180x180.png"> +	<link rel="apple-touch-icon" sizes="152x152" href="/static/icons/icon-152x152.png"> +	<link rel="apple-touch-icon" sizes="167x167" href="/static/icons/icon-167x167.png"> +% if ($self->stash('refresh_interval')) { +	<meta http-equiv="refresh" content="<%= $self->stash('refresh_interval') %>"/> +% } + +	% my $av = 'v15'; # asset version +	%= stylesheet "/static/${av}/css/app.css" +	%= stylesheet "/static/${av}/css/material-icons.css" +	%= stylesheet "/static/${av}/css/jquery-ui.min.css" +	%= javascript '/static/js/jquery-3.4.1.min.js', defer => undef +	%= javascript "/static/${av}/js/jquery-ui.min.js", defer => undef +	%= javascript "/static/${av}/js/dbf.min.js", defer => undef +	% if (stash('with_geolocation')) { +	%= javascript "/static/${av}/js/geolocation.min.js", defer => undef +	% } +</head> +<body> + +<div class="navbar-fixed"> +	<nav style="color: #ffffff; background-color: #00838f;"> +		<div class="nav-wrapper container"> +			<span class="brand-logo"> +				%= stash('title') || 'DBF' +			</span> +			<ul id="nav-mobile" style="float: right;"> +				<li><a href="#stationinput"><i class="material-icons">edit</i></a></li> +				<li><a href="/_auto"><i class="material-icons">my_location</i></a></li> +			</ul> +		</div> +	</nav> +</div> + +<div class="container"> +% if (my $error = stash 'error') { +<div class="error"><strong>Backend-Fehler:</strong> +<pre> +%= $error +</pre> +</div> +% } +% elsif (stash('stationlist')) { +<div class="error"><strong>Mehrdeutige Eingabe.</strong> +Bitte eine Station aus der Liste auswählen</div> +% } +</div> + +<div class="content"> +%= content +</div> + +% if (not stash('hide_opts')) { +<div class="container"> +<div class="input-field"> + + +%= form_for _redirect => begin +<div> +  <div class="field"> +    <div class="desc">Bahnhof / Haltestelle</div> +    <div> +% if (stash('stationlist')) { +      %= select_field station => stash('stationlist') +% } +% elsif (stash('station')) { +      %= text_field 'station', class => 'station', placeholder => 'Name oder DS100-Kürzel', id => 'stationinput' +% } +% else { +      %= text_field 'station', class => 'station', placeholder => 'Name oder DS100-Kürzel', id => 'stationinput', autofocus => 'autofocus' +% } +    </div> +  </div> +  <div class="field"> +    %= submit_button 'Abfahrtsmonitor' +  </div> +  % if (not stash('show_intro')) { +    <div class="break"></div> +    <div class="field"> +      <a class="button" href="<%= url_for('_auto')->to_abs->scheme('https') %>">Bahnhöfe im Umfeld suchen</a> +    </div> +  % } +  <div class="break"></div> +  <div class="moresettings-header moresettings-header-collapsed button button-light">Weitere Einstellungen</div> +  <div class="moresettings moresettings-collapsed"> +    <div class="field"> +      <div class="desc"> +        Frontend +      </div> +      <div> +        %= select_field mode => [ ['App' => 'app'], ['Infoscreen' => 'infoscreen'], ['Bahnhofstafel' => 'multi'], ['Gleisanzeiger' => 'single'] ] +      </div> +    </div> +    <div class="field"> +      <div class="desc"> +        Backend +      </div> +      <div> +        %= select_field backend => [ ['IRIS' => 'iris'], ['HAFAS' => 'ris'] ] +      </div> +    </div> +    <div class="field"> +      <div class="desc"> +        Nur Züge über +      </div> +      <div> +        %= text_field 'via', placeholder => 'Bahnhof 1, Bhf2, ... (oder regulärer Ausdruck)', class => 'station' +      </div> +    </div> +    <div class="field"> +      <div class="desc"> +        Gleise +      </div> +      <div> +        %= text_field 'platforms', placeholder => '1, 2, 5, ...' +      </div> +    </div> +    <div class="field"> +      <div class="desc"> +        %= check_box 'hidelowdelay' => 1, id => 'id_hidelowdelay' +        <label for="id_hidelowdelay"> +          Nur Verspätungen >5 Min. anzeigen +        </label> +      </div> +    </div> +    <div class="field"> +      <div class="desc"> +        %= check_box 'dark' => 1, id => 'id_dark' +        <label for="id_dark"> +          Dunkles Layout (experimentell) +        </label> +      </div> +    </div> +    <div class="field"> +      <div class="desc"> +        %= check_box 'hide_opts' => 1, id => 'id_hide_opts' +        <label for="id_hide_opts"> +          Formular verstecken (für Infoscreens) +        </label> +      </div> +    </div> +    <div class="break"></div> +    <span class="optional">Nur für IRIS-Backend:</span> +    <div class="field"> +      <div class="desc"> +        Ankunfts- oder Abfahrtszeit anzeigen? +      </div> +      <div> +        %= select_field admode => [['Abfahrt bevorzugen' => 'deparr'], ['Nur Abfahrt' => 'dep'], ['Nur Ankunft' => 'arr']] +      </div> +    </div> +    <div class="field"> +      <div class="desc"> +        %= check_box 'detailed' => 1, id => 'id_detailed' +        <label for="id_detailed"> +          Mehr Details (Zugnummern und Ankunftszeiten) anzeigen +        </label> +      </div> +    </div> +    <div class="field"> +      <div class="desc"> +        %= check_box 'show_realtime' => 1, id => 'id_show_realtime' +        <label for="id_show_realtime"> +          Echtzeitangaben statt Fahrplandaten anzeigen +        </label> +      </div> +    </div> +    <div class="field"> +      <div class="desc"> +        %= check_box 'no_related' => 1, id => 'id_no_related' +        <label for="id_no_related"> +        Betriebliche Bahnhofstrennungen berücksichtigen (z.B. "Hbf (Fern+Regio)" vs. "Hbf (S)") +        </label> +      </div> +    </div> +    <div class="field"> +      <div class="desc"> +        %= check_box 'save_defaults' => 1, id => 'id_save_defaults' +        <label for="id_save_defaults"> +        Ausgewählte Optionen als Default speichern +        </label> +      </div> +    </div> +    <div class="field"> +      %= submit_button 'Anzeigen' +    </div> +  </div> <!-- moresettings --> +</div> +% end + +</div> <!-- input-field --> + +<div class="notes"> +  <div class="developers-header developers-header-collapsed button button-light">API- und Entwickler-Hinweise</div> +  <div class="developers developers-collapsed"> +    <ul> +      <li>Diese Seite kann gerne als iframe in eigene Infoscreens o.ä. eingebunden werden. +	Für eine kleine Ansicht (z.B. iframe in einer normalen Website) bitte das +	"App"-Frontend verwenden. Für eine große Ansicht +	(z.B. als alleinstehender Infoscreen) gibt es das "Infoscreen"-Frontend.</li> +      <li>Die Parameter <span style="font-family: monospace;">mode=json&version=3</span> +	(alternativ auch <span style="font-family: +	monospace;">https://dbf.finalrewind.org/Bahnhofsname.json?version=3</span>) +	bieten ein JSON-IRIS-Interface. Die route-Elemente können zusätzlich +	die Felder "isAdditional" oder "isCancelled" enthalten, der Rest sollte +	selbsterklärend sein. Im Fehlerfall fehlt das "departures"-Element, +	stattdessen wird ein "error"-Element mit Fehlermeldung zurückgegeben. +	Bitte nur eine Anfrage pro Station und Minute +	– eine höhere Auflösung haben die Backenddaten ohnehin nicht.</li> +      <li>Mit <span style="font-family: monospace;">limit</span> kann die Anzahl der +	angezeigten / im JSON enthaltenen Abfahrten eingeschränkt werden, z.B. +	<span style="font-family: monospace;">limit=10</span> für die ersten zehn.</li> +      <li>Dieser Dienst ist Open Source-Software (Links siehe unten) und kann auch +	auf eigenen Servern installiert werden. Automatisierte Crawler, die mehrere +	Dutzend Stationen pro Minute abfragen, bitte nur auf eigenen Instanzen +	betreiben.</li> +    </ul> +  </div> <!-- developers --> +</div> <!-- notes --> + +<div class="notes"> +<span class="notes">Siehe auch:</span> +<ul> +<li><a href="https://reiseauskunft.bahn.de/bin/bhftafel.exe/dn">DB Abfahrtsmonitor</a> +   (<a href="https://mobile.bahn.de/bin/mobil/bhftafel.exe/dox">mobil</a>)</li> +<li>Für Nahverkehr: <a href="https://vrrf.finalrewind.org/">vrr-infoscreen</a></li> +</ul> +</div> <!-- notes --> + +</div> <!-- container --> + +<div class="container"> +<div class="about"> +<a href="_about">db-infoscreen</a> +v<%= stash('version') // '???' %> +<br/> +<a href="_datenschutz" rel="nofollow">Datenschutzerklärung</a> +· +<a href="_impressum" rel="nofollow">Impressum</a><br/> +</div> <!-- about --> +</div> <!-- container --> +% } + +</body> +</html> diff --git a/templates/layouts/default.html.ep b/templates/layouts/legacy.html.ep index 46ce984..46ce984 100644 --- a/templates/layouts/default.html.ep +++ b/templates/layouts/legacy.html.ep | 
