From: maxious Date: Sun, 27 Mar 2011 14:55:05 +0000 Subject: Merge branch 'master' of github.com:maxious/ACTBus-ui X-Git-Url: https://maxious.lambdacomplex.org/git/?p=busui.git&a=commitdiff&h=19650b13e4779cd40b6e8a57030e055368422989 --- Merge branch 'master' of github.com:maxious/ACTBus-ui --- --- a/about.php +++ b/about.php @@ -1,11 +1,17 @@

Busness Time - An ACT bus timetable webapp
-Based on the maxious-canberra-transit-feed (download, last updated )
-Source code for the transit feed and this site @ http://maxious.lambdacomplex.org/git
+Based on the maxious-canberra-transit-feed (download, +last updated )
+Source code for the transit +feed and this +site available from github.
Uses jQuery Mobile, PHP, Ruby, Python, Google Transit Feed Specification tools, OpenTripPlanner, OpenLayers, OpenStreetMap, Cloudmade Geocoder and Tile Service

Feedback encouraged; contact maxious@lambdacomplex.org
--- a/aws/awsStartup.sh +++ b/aws/awsStartup.sh @@ -1,20 +1,21 @@ #!/bin/bash #this script should be run from a fresh git checkout from http://maxious.lambdacomplex.org #ami base must have yum install lighttpd-fastcgi, git, tomcat6 -#screen php-cli php-gd tomcat6-webapps tomcat6-admin-webapps +#screen php-cli php-gd tomcat6-webapps tomcat6-admin-webapps svn maven2 #http://www.how2forge.org/installing-lighttpd-with-php5-and-mysql-support-on-fedora-12 -cp -rfv /tmp/busui/* /var/www cp /root/aws.php /tmp/ +mkdir /var/www/lib/staticmaplite/cache chcon -h system_u:object_r:httpd_sys_content_t /var/www chcon -R -h root:object_r:httpd_sys_content_t /var/www/* -chcon -R -t httpd_sys_content_rw_t /var/www/staticmaplite/cache -chmod -R 777 /var/www/staticmaplite/cache +chcon -R -t httpd_sys_content_rw_t /var/www/lib/staticmaplite/cache +chmod -R 777 /var/www/lib/staticmaplite/cache wget http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip \ -O /var/www/cbrfeed.zip easy_install transitfeed easy_install simplejson -screen -d -m /var/www/view.sh +screen -S viewsh -X quit +screen -S viewsh -d -m /var/www/view.sh wget http://s3-ap-southeast-1.amazonaws.com/busresources/Graph.obj \ -O /tmp/Graph.obj --- /dev/null +++ b/aws/compress.conf @@ -1,1 +1,33 @@ +####################################################################### +## +## Output Compression +## -------------------- +## +## see http://www.lighttpd.net/documentation/compress.html +## +server.modules += ( "mod_compress" ) +## +## where should the compressed files be cached? +## see the base config for the declaration of the variable. +## +## This directory should be changed per vhost otherwise you can +## run into trouble with overlapping filenames +## +compress.cache-dir = cache_dir + "/compress" + +## +## FileTypes to compress. +## +#compress.filetype = ("text/plain", "text/html") +compress.filetype = ("text/plain", "text/html", "text/javascript", "text/css", "text/xml") + +## +## Maximum filesize that will be compressed. +## Default is 0, which means unlimited file size. +## +#compress.max-filesize = 0 + +## +####################################################################### + --- /dev/null +++ b/aws/expire.conf @@ -1,1 +1,29 @@ +####################################################################### +## +## Expire Module +## --------------- +## +## See http://www.lighttpd.net/documentation/expire.html +## +server.modules += ( "mod_expire" ) +## +## assignes a expiration to all files below the specified path. The +## specification of the time is made up of: +## +## +## +#expire.url = ( +# "/buggy/" => "access 2 hours", +# "/images/" => "access plus 1 seconds 2 minutes" +#) +etag.use-mtime = "enable" +etag.use-inode = "disable" +static-file.etags = "enable" +$HTTP["url"] =~ "\.(css|js|png|jpg|ico|gif)$" { + expire.url = ( "" => "access 7 days" ) +} + +## +####################################################################### + --- a/aws/modules.conf +++ b/aws/modules.conf @@ -76,7 +76,7 @@ ## ## mod_compress ## -#include "conf.d/compress.conf" +include "conf.d/compress.conf" ## ## mod_userdir @@ -106,7 +106,7 @@ ## ## mod_expire ## -#include "conf.d/expire.conf" +include "conf.d/expire.conf" ## ## mod_secdownload --- a/aws/php.ini +++ b/aws/php.ini @@ -1,4 +1,6 @@ [PHP] + +date.timezone = "Australia/Sydney" ;;;;;;;;;;;;;;;;;;; ; About php.ini ; @@ -288,7 +290,7 @@ ; Note: You need to use zlib.output_handler instead of the standard ; output_handler, or otherwise the output will be corrupted. ; http://www.php.net/manual/en/zlib.configuration.php#ini.zlib.output-compression -zlib.output_compression = Off +zlib.output_compression = on ; http://www.php.net/manual/en/zlib.configuration.php#ini.zlib.output-compression-level ;zlib.output_compression_level = -1 @@ -1264,7 +1266,7 @@ ; where MODE is the octal representation of the mode. Note that this ; does not overwrite the process's umask. ; http://www.php.net/manual/en/session.configuration.php#ini.session.save-path -session.save_path = "/var/lib/php/session" +session.save_path = "/tmp" ; Whether to use cookies. ; http://www.php.net/manual/en/session.configuration.php#ini.session.use-cookies --- a/common.inc.php +++ /dev/null @@ -1,501 +1,1 @@ -centroid)) { - $geocoded = true; - $_SESSION['lat'] = $contents[0]->centroid->coordinates[0]; - $_SESSION['lon'] = $contents[0]->centroid->coordinates[1]; - } - else { - $_SESSION['lat'] = ""; - $_SESSION['lon'] = ""; - } - } - if ($_SESSION['lat'] != "" && isMetricsOn()) { -// Create a new Instance of the tracker -$owa = new owa_php($config); -// Set the ID of the site being tracked -$owa->setSiteId($owaSiteID); -// Create a new event object -$event = $owa->makeEvent(); -// Set the Event Type, in this case a "video_play" -$event->setEventType('geolocate'); -// Set a property -$event->set('lat',$_SESSION['lat']); -$event->set('lon',$_SESSION['lon']); -$event->set('geocoded',$geocoded); -// Track the event -$owa->trackEvent($event); - } - } -debug(print_r($_SESSION,true)); -function isDebug() -{ - return $_SERVER['SERVER_NAME'] == "10.0.1.154" || $_SERVER['SERVER_NAME'] == "localhost" || $_SERVER['SERVER_NAME'] == "127.0.0.1" || !$_SERVER['SERVER_NAME']; -} - -function isMetricsOn() -{ - return !isDebug(); -} - -function debug($msg) { - if (isDebug()) echo "\n\n"; -} -function isFastDevice() { - $ua = $_SERVER['HTTP_USER_AGENT']; - $fastDevices = Array("Mozilla/5.0 (X11;", "Mozilla/5.0 (Windows;", "Mozilla/5.0 (iP", "Mozilla/5.0 (Linux; U; Android", "Mozilla/4.0 (compatible; MSIE"); - - $slowDevices = Array("J2ME","MIDP","Opera/","Mozilla/2.0 (compatible;","Mozilla/3.0 (compatible;"); - return true; -} - -function include_header($pageTitle, $pageType, $opendiv = true, $geolocate = false) { - echo ' - - - - '.$pageTitle.''; - if (isDebug()) echo ' - - '; - else echo ' - - '; -echo ' - - - - - - - - - '; - if ($geolocate) { -echo " "; - } -echo ' - - '; - if (isMetricsOn()) { - require_once('owa/owa_env.php'); - require_once(OWA_DIR.'owa_php.php'); - $owa = new owa_php(); - global $owaSiteID; - $owa->setSiteId($owaSiteID); - $owa->setPageTitle($pageTitle); - $owa->setPageType($pageType); - $owa->trackPageView(); - $owa->placeHelperPageTags(); - } - -if ($opendiv) { - echo '

- -
-

'.$pageTitle.'

-
-
'; -} -} -function include_footer() -{ - if ($geolocate && isset($_SESSION['lat'])) { - echo ""; - } - echo ''; -} - -$service_periods = Array ('sunday','saturday','weekday'); - -function service_period() -{ -if (isset($_SESSION['service_period'])) return $_SESSION['service_period']; - -switch (date('w')){ - -case 0: - return 'sunday'; -case 6: - return 'saturday'; -default: - return 'weekday'; -} -} - -function remove_spaces($string) -{ - return str_replace(' ','',$string); -} - -function midnight_seconds() -{ -// from http://www.perturb.org/display/Perlfunc__Seconds_Since_Midnight.html -if (isset($_SESSION['time'])) { - $time = strtotime($_SESSION['time']); - return (date("G",$time) * 3600) + (date("i",$time) * 60) + date("s",$time); - } - return (date("G") * 3600) + (date("i") * 60) + date("s"); -} - -function midnight_seconds_to_time($seconds) -{ -if ($seconds > 0) { - $midnight = mktime (0, 0, 0, date("n"), date("j"), date("Y")); - return date("h:ia",$midnight+$seconds); -} else { -return ""; -} -} -function getPage($url) -{ - debug($url); - $ch = curl_init($url); -curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ); -curl_setopt( $ch, CURLOPT_HEADER, 0 ); - curl_setopt($ch,CURLOPT_TIMEOUT,30); -$page = curl_exec($ch); - if(curl_errno($ch)) echo " Database temporarily unavailable: ".curl_errno($ch)." ".curl_error($ch)."
"; -curl_close($ch); -return $page; -} -function array_flatten($a,$f=array()){ - if(!$a||!is_array($a))return ''; - foreach($a as $k=>$v){ - if(is_array($v))$f=array_flatten($v,$f); - else $f[$k]=$v; - } - return $f; -} - -function staticmap($mapPoints, $zoom = 0, $markerImage = "iconb") -{ -$width = 300; -$height = 300; -$metersperpixel[9]=305.492*$width; -$metersperpixel[10]=152.746*$width; -$metersperpixel[11]=76.373*$width; -$metersperpixel[12]=38.187*$width; -$metersperpixel[13]=19.093*$width; -$metersperpixel[14]=9.547*$width; -$metersperpixel[15]=4.773*$width; -$metersperpixel[16]=2.387*$width; -// $metersperpixel[17]=1.193*$width; -$center = ""; -$markers = ""; -$minlat = 999; -$minlon = 999; -$maxlat = 0; -$maxlon = 0; - - if (sizeof($mapPoints) < 1) return "map error"; - if (sizeof($mapPoints) === 1) { - if ($zoom == 0) $zoom = 14; - $markers .= "{$mapPoints[0][0]},{$mapPoints[0][1]},$markerimage"; - $center = "{$mapPoints[0][0]},{$mapPoints[0][1]}"; - } else { - foreach ($mapPoints as $index => $mapPoint) { - $markers .= $mapPoint[0].",".$mapPoint[1].",".$markerImage.($index+1); - if ($index+1 != sizeof($mapPoints)) $markers .= "|"; - if ($mapPoint[0] < $minlat) $minlat = $mapPoint[0]; - if ($mapPoint[0] > $maxlat) $maxlat = $mapPoint[0]; - if ($mapPoint[1] < $minlon) $minlon = $mapPoint[1]; - if ($mapPoint[1] > $maxlon) $maxlon = $mapPoint[1]; - $totalLat += $mapPoint[0]; - $totalLon += $mapPoint[1]; - } - if ($zoom == 0) { - $mapwidthinmeters = distance($minlat,$minlon,$minlat,$maxlon); - foreach (array_reverse($metersperpixel,true) as $zoomLevel => $maxdistance) - { - if ($zoom == 0 && $mapwidthinmeters < ($maxdistance + 50)) $zoom = $zoomLevel; - } - } - $center = $totalLat/sizeof($mapPoints).",".$totalLon/sizeof($mapPoints); - } - $output = ""; - if(basename($_SERVER['PHP_SELF']) != "tripPlanner.php") $output .= '

Open Map...

'; - $output .= '
'; - if(basename($_SERVER['PHP_SELF']) != "tripPlanner.php") $output .= '
'; - return $output; -} - -function distance($lat1, $lng1, $lat2, $lng2) -{ - $pi80 = M_PI / 180; - $lat1 *= $pi80; - $lng1 *= $pi80; - $lat2 *= $pi80; - $lng2 *= $pi80; - - $r = 6372.797; // mean radius of Earth in km - $dlat = $lat2 - $lat1; - $dlng = $lng2 - $lng1; - $a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlng / 2) * sin($dlng / 2); - $c = 2 * atan2(sqrt($a), sqrt(1 - $a)); - $km = $r * $c; - - return $km * 1000; -} - -function decodePolylineToArray($encoded) -{ -// source: http://latlongeeks.com/forum/viewtopic.php?f=4&t=5 - $length = strlen($encoded); - $index = 0; - $points = array(); - $lat = 0; - $lng = 0; - - while ($index < $length) - { - // Temporary variable to hold each ASCII byte. - $b = 0; - - // The encoded polyline consists of a latitude value followed by a - // longitude value. They should always come in pairs. Read the - // latitude value first. - $shift = 0; - $result = 0; - do - { - // The `ord(substr($encoded, $index++))` statement returns the ASCII - // code for the character at $index. Subtract 63 to get the original - // value. (63 was added to ensure proper ASCII characters are displayed - // in the encoded polyline string, which is `human` readable) - $b = ord(substr($encoded, $index++)) - 63; - - // AND the bits of the byte with 0x1f to get the original 5-bit `chunk. - // Then left shift the bits by the required amount, which increases - // by 5 bits each time. - // OR the value into $results, which sums up the individual 5-bit chunks - // into the original value. Since the 5-bit chunks were reversed in - // order during encoding, reading them in this way ensures proper - // summation. - $result |= ($b & 0x1f) << $shift; - $shift += 5; - } - // Continue while the read byte is >= 0x20 since the last `chunk` - // was not OR'd with 0x20 during the conversion process. (Signals the end) - while ($b >= 0x20); - - // Check if negative, and convert. (All negative values have the last bit - // set) - $dlat = (($result & 1) ? ~($result >> 1) : ($result >> 1)); - - // Compute actual latitude since value is offset from previous value. - $lat += $dlat; - - // The next values will correspond to the longitude for this point. - $shift = 0; - $result = 0; - do - { - $b = ord(substr($encoded, $index++)) - 63; - $result |= ($b & 0x1f) << $shift; - $shift += 5; - } - while ($b >= 0x20); - - $dlng = (($result & 1) ? ~($result >> 1) : ($result >> 1)); - $lng += $dlng; - - // The actual latitude and longitude values were multiplied by - // 1e5 before encoding so that they could be converted to a 32-bit - // integer representation. (With a decimal accuracy of 5 places) - // Convert back to original values. - $points[] = array($lat * 1e-5, $lng * 1e-5); - } - - return $points; -} - -function object2array($object) { - if (is_object($object)) { - foreach ($object as $key => $value) { - $array[$key] = $value; - } - } - else { - $array = $object; - } - return $array; -} - -function geocode($query, $giveOptions) { - global $cloudmadeAPIkey; - $url = "http://geocoding.cloudmade.com/$cloudmadeAPIkey/geocoding/v2/find.js?query=".urlencode($query)."&bbox=-35.5,149.00,-35.15,149.1930&return_location=true&bbox_only=true"; - $contents = json_decode(getPage($url)); - if ($giveOptions) return $contents->features; - elseif (isset($contents->features[0]->centroid)) return $contents->features[0]->centroid->coordinates[0].",".$contents->features[0]->centroid->coordinates[1]; - else return ""; -} - -function reverseGeocode($lat,$lng) { - global $cloudmadeAPIkey; - $url = "http://geocoding.cloudmade.com/$cloudmadeAPIkey/geocoding/v2/find.js?around=".$lat.",".$lng."&distance=closest&object_type=road"; - $contents = json_decode(getPage($url)); - return $contents->features[0]->properties->name; -} - -function startsWith($haystack,$needle,$case=true) { - if($case){return (strcmp(substr($haystack, 0, strlen($needle)),$needle)===0);} - return (strcasecmp(substr($haystack, 0, strlen($needle)),$needle)===0); -} - -function endsWith($haystack,$needle,$case=true) { - if($case){return (strcmp(substr($haystack, strlen($haystack) - strlen($needle)),$needle)===0);} - return (strcasecmp(substr($haystack, strlen($haystack) - strlen($needle)),$needle)===0); -} -function bracketsMeanNewLine($input) { - return str_replace(")","",str_replace("(","
",$input)); -} - -function viaPoints($tripid,$stopid, $timingPointsOnly = false) { - global $APIurl; - $url = $APIurl."/json/tripstoptimes?trip=".$tripid; - -$json = json_decode(getPage($url)); -debug(print_r($json,true)); -$stops = $json[0]; -$times = $json[1]; -$foundStop = false; -$viaPoints = Array(); -foreach ($stops as $key => $row) -{ - if ($foundStop) { - if (!$timingPointsOnly || !startsWith($row[5],"Wj") ) { - $viaPoints[] = Array("id" => $row[0], "name" => $row[1], "time" => $times[$key]); - } - } else { - if ($row[0] == $stopid) $foundStop = true; - } -} - return $viaPoints; -} - -function viaPointNames($tripid,$stopid) { - $points = viaPoints($tripid,$stopid,true); - $pointNames = Array(); - foreach ($points as $point) { - $pointNames[] = $point['name']; - } - return implode(", ",$pointNames); -} - -function timePlaceSettings($geolocate = false) { - global $service_periods; - $geoerror = false; - if ($geolocate == true) { - $geoerror = !isset($_SESSION['lat']) || !isset($_SESSION['lat']) - || $_SESSION['lat'] == "" || $_SESSION['lon'] == ""; - } - if ($geoerror) { - echo '
Sorry, but your location could not currently be detected. - Please allow location permission, wait for your location to be detected, - or enter an address/co-ordinates in the box below.
'; - } - echo '
-

Change Time/Place...

-
-
-
- - -
-
- - Current Time? -
-
- - - -
- - - -
'; -} -?> - --- a/css/jquery.ui.datepicker.mobile.css +++ b/css/jquery.ui.datepicker.mobile.css @@ -1,30 +1,18 @@ -/* - * jQuery UI Datepicker @VERSION - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Datepicker#theming - */ -div.hasDatepicker{ display: block; padding: 0; overflow: visible; margin: 8px 0; } -.ui-datepicker { overflow: visible; margin: 0; max-width: 500px; } -.ui-datepicker .ui-datepicker-header { position:relative; padding:.4em 0; border-bottom: 0; font-weight: bold; } -.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { padding: 1px 0 1px 2px; position:absolute; top: .5em; margin-top: 0; text-indent: -9999px; } +div.hasDatepicker{display:block;padding:0;overflow:visible;margin:8px 0;} +.ui-datepicker{overflow:visible;margin:0;max-width:500px;} +.ui-datepicker .ui-datepicker-header{position:relative;padding:.4em 0;border-bottom:0;font-weight:bold;} +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next{padding:1px 0 1px 2px;position:absolute;top:.5em;margin-top:0;text-indent:-9999px;} +.ui-datepicker .ui-datepicker-prev{left:6px;} +.ui-datepicker .ui-datepicker-next{right:6px;} +.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center;} +.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0;} +.ui-datepicker select.ui-datepicker-month-year{width:100%;} +.ui-datepicker select.ui-datepicker-month, .ui-datepicker select.ui-datepicker-year{width:49%;} +.ui-datepicker table{width:100%;border-collapse:collapse;margin:0;} +.ui-datepicker td{border-width:1px;padding:0;text-align:center;} +.ui-datepicker td span, .ui-datepicker td a{display:block;padding:.2em 0;font-weight:bold;margin:0;border-width:0;text-align:center;text-decoration:none;} +.ui-datepicker-calendar th{padding-top:.3em;padding-bottom:.3em;} +.ui-datepicker-calendar th span, .ui-datepicker-calendar span.ui-state-default{opacity:.3;} +.ui-datepicker-calendar td a{padding-top:.5em;padding-bottom:.5em;} +.min-width-480px div.hasDatepicker{width:63%;display:inline-block;margin:0;} -.ui-datepicker .ui-datepicker-prev { left:6px; } -.ui-datepicker .ui-datepicker-next { right:6px; } -.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } -.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } -.ui-datepicker select.ui-datepicker-month-year {width: 100%;} -.ui-datepicker select.ui-datepicker-month, -.ui-datepicker select.ui-datepicker-year { width: 49%;} -.ui-datepicker table {width: 100%; border-collapse: collapse; margin:0; } -.ui-datepicker td { border-width: 1px; padding: 0; text-align: center; } -.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em 0; font-weight: bold; margin: 0; border-width: 0; text-align: center; text-decoration: none; } - -.ui-datepicker-calendar th { padding-top: .3em; padding-bottom: .3em; } -.ui-datepicker-calendar th span, .ui-datepicker-calendar span.ui-state-default { opacity: .3; } -.ui-datepicker-calendar td a { padding-top: .5em; padding-bottom: .5em; } - -.min-width-480px div.hasDatepicker { width: 63%; display: inline-block; margin: 0; } --- a/feedback.php +++ b/feedback.php @@ -1,54 +1,71 @@ verifyEmailAddress($address); -//$con->listVerifiedEmailAddresses(); - -$m = new SimpleEmailServiceMessage(); -$m->addTo($address); -$m->setFrom($address); -$m->setSubject($topic); -$m->setMessageFromString($message); -$con->sendEmail($m); -} else { -// In case any of our lines are larger than 70 characters, we should use wordwrap() -$message = wordwrap($message, 70); - -// Send -mail($address, $topic, $message); -} +include ("include/common.inc.php"); +include_header("Feedback", "feedback"); +function sendEmail($topic, $message) +{ + $address = "maxious@lambdacomplex.org"; + if (file_exists("/tmp/aws.php")) { + include_once ("lib/ses.php"); + include_once ("/tmp/aws.php"); + $con = new SimpleEmailService($accessKey, $secretKey); + //$con->verifyEmailAddress($address); + //$con->listVerifiedEmailAddresses(); + $m = new SimpleEmailServiceMessage(); + $m->addTo($address); + $m->setFrom($address); + $m->setSubject($topic); + $m->setMessageFromString($message); + $con->sendEmail($m); + } + else { + // In case any of our lines are larger than 70 characters, we should use wordwrap() + $message = wordwrap($message, 70); + // Send + mail($address, $topic, $message); + } } +$stopid = ""; +$stopcode = ""; +$urlparts = explode("?",$_SERVER["HTTP_REFERER"]); +if (isset($urlparts[1])) { + $getparams = explode("&",$urlparts[1]); + foreach ($getparams as $param) { + $paramparts=explode("=",$param); + if ($paramparts[0] == "stopid") $stopid = $paramparts[1]; + if ($paramparts[0] == "stopcode") $stopcode = $paramparts[1]; + } +} ?>

Add/Move/Delete a Bus Stop Location

-StopID: -or StopCode: - if you click on feedback from a stop page, these will get filled in automatically. else describe the location/street of the stop +StopID:
+or StopCode:
+ if you click on feedback from a stop page, these will get filled in automatically. else describe the location/street of the stop in one of these boxes
-Suggested Stop Location (lat/long or words): - if your device supports javascript, you can pick a location from the map above +Suggested Stop Location (lat/long or words):
+ if your device supports javascript, you can pick a location from the map above
-Submit! +

Bug Report/Feedback

Please leave feedback about bugs/errors or general suggestions about improvements that could be made to the way the data is presented! -Submit! + + + --- /dev/null +++ b/include/common-geo.inc.php @@ -1,1 +1,151 @@ + $mapPoint) { + $markers.= $mapPoint[0] . "," . $mapPoint[1] . "," . $markerImage . ($index + 1); + if ($index + 1 != sizeof($mapPoints)) $markers.= "|"; + if ($mapPoint[0] < $minlat) $minlat = $mapPoint[0]; + if ($mapPoint[0] > $maxlat) $maxlat = $mapPoint[0]; + if ($mapPoint[1] < $minlon) $minlon = $mapPoint[1]; + if ($mapPoint[1] > $maxlon) $maxlon = $mapPoint[1]; + $totalLat+= $mapPoint[0]; + $totalLon+= $mapPoint[1]; + } + if ($zoom == 0) { + $mapwidthinmeters = distance($minlat, $minlon, $minlat, $maxlon); + foreach (array_reverse($metersperpixel, true) as $zoomLevel => $maxdistance) { + if ($zoom == 0 && $mapwidthinmeters < ($maxdistance + 50)) $zoom = $zoomLevel; + } + } + $center = $totalLat / sizeof($mapPoints) . "," . $totalLon / sizeof($mapPoints); + } + $output = ""; + if ($collapsible) $output.= '

Open Map...

'; + $output.= '
'; + if ($collapsible) $output.= '
'; + return $output; +} +function distance($lat1, $lng1, $lat2, $lng2, $roundLargeValues = false) +{ + $pi80 = M_PI / 180; + $lat1*= $pi80; + $lng1*= $pi80; + $lat2*= $pi80; + $lng2*= $pi80; + $r = 6372.797; // mean radius of Earth in km + $dlat = $lat2 - $lat1; + $dlng = $lng2 - $lng1; + $a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlng / 2) * sin($dlng / 2); + $c = 2 * atan2(sqrt($a) , sqrt(1 - $a)); + $km = $r * $c; + if ($roundLargeValues) { + if ($km < 1) return floor($km * 1000); + else return round($km,2)."k"; + } else return floor($km * 1000); +} +function decodePolylineToArray($encoded) +{ + // source: http://latlongeeks.com/forum/viewtopic.php?f=4&t=5 + $length = strlen($encoded); + $index = 0; + $points = array(); + $lat = 0; + $lng = 0; + while ($index < $length) { + // Temporary variable to hold each ASCII byte. + $b = 0; + // The encoded polyline consists of a latitude value followed by a + // longitude value. They should always come in pairs. Read the + // latitude value first. + $shift = 0; + $result = 0; + do { + // The `ord(substr($encoded, $index++))` statement returns the ASCII + // code for the character at $index. Subtract 63 to get the original + // value. (63 was added to ensure proper ASCII characters are displayed + // in the encoded polyline string, which is `human` readable) + $b = ord(substr($encoded, $index++)) - 63; + // AND the bits of the byte with 0x1f to get the original 5-bit `chunk. + // Then left shift the bits by the required amount, which increases + // by 5 bits each time. + // OR the value into $results, which sums up the individual 5-bit chunks + // into the original value. Since the 5-bit chunks were reversed in + // order during encoding, reading them in this way ensures proper + // summation. + $result|= ($b & 0x1f) << $shift; + $shift+= 5; + } + // Continue while the read byte is >= 0x20 since the last `chunk` + // was not OR'd with 0x20 during the conversion process. (Signals the end) + while ($b >= 0x20); + // Check if negative, and convert. (All negative values have the last bit + // set) + $dlat = (($result & 1) ? ~($result >> 1) : ($result >> 1)); + // Compute actual latitude since value is offset from previous value. + $lat+= $dlat; + // The next values will correspond to the longitude for this point. + $shift = 0; + $result = 0; + do { + $b = ord(substr($encoded, $index++)) - 63; + $result|= ($b & 0x1f) << $shift; + $shift+= 5; + } while ($b >= 0x20); + $dlng = (($result & 1) ? ~($result >> 1) : ($result >> 1)); + $lng+= $dlng; + // The actual latitude and longitude values were multiplied by + // 1e5 before encoding so that they could be converted to a 32-bit + // integer representation. (With a decimal accuracy of 5 places) + // Convert back to original values. + $points[] = array( + $lat * 1e-5, + $lng * 1e-5 + ); + } + return $points; +} +function geocode($query, $giveOptions) +{ + global $cloudmadeAPIkey; + $url = "http://geocoding.cloudmade.com/$cloudmadeAPIkey/geocoding/v2/find.js?query=" . urlencode($query) . "&bbox=-35.5,149.00,-35.15,149.1930&return_location=true&bbox_only=true"; + $contents = json_decode(getPage($url)); + if ($giveOptions) return $contents->features; + elseif (isset($contents->features[0]->centroid)) return $contents->features[0]->centroid->coordinates[0] . "," . $contents->features[0]->centroid->coordinates[1]; + else return ""; +} +function reverseGeocode($lat, $lng) +{ + global $cloudmadeAPIkey; + $url = "http://geocoding.cloudmade.com/$cloudmadeAPIkey/geocoding/v2/find.js?around=" . $lat . "," . $lng . "&distance=closest&object_type=road"; + $contents = json_decode(getPage($url)); + return $contents->features[0]->properties->name; +} +?> --- /dev/null +++ b/include/common-net.inc.php @@ -1,1 +1,31 @@ + Database temporarily unavailable: "; + echo curl_errno($ch) . " " . curl_error($ch); + if (isDebug()) { + echo $url; + } + echo "
"; + } + curl_close($ch); + debug(print_r($page,true),"json"); + return $page; +} +function curPageURL() +{ + $isHTTPS = (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on"); + $port = (isset($_SERVER["SERVER_PORT"]) && ((!$isHTTPS && $_SERVER["SERVER_PORT"] != "80") || ($isHTTPS && $_SERVER["SERVER_PORT"] != "443"))); + $port = ($port) ? ':' . $_SERVER["SERVER_PORT"] : ''; + $url = ($isHTTPS ? 'https://' : 'http://') . $_SERVER["SERVER_NAME"] . $port . htmlentities(dirname($_SERVER['PHP_SELF']) , ENT_QUOTES); + return $url; +} +?> --- /dev/null +++ b/include/common-session.inc.php @@ -1,1 +1,57 @@ +centroid)) { + $geocoded = true; + $_SESSION['lat'] = $contents[0]->centroid->coordinates[0]; + $_SESSION['lon'] = $contents[0]->centroid->coordinates[1]; + } + else { + $_SESSION['lat'] = ""; + $_SESSION['lon'] = ""; + } + } + } + if ($_SESSION['lat'] != "" && isAnalyticsOn()) { + trackEvent("Geolocation","Updated Location", "Geocoded - ".($geocoded ? "Yes" : "No")); + } + sessionUpdated(); +} +function sessionUpdated() { + $_SESSION['lastUpdated'] = time(); +} +// timeoutSession +$TIMEOUT_LIMIT = 60*5; // 5 minutes +if (isset($_SESSION['lastUpdated']) && $_SESSION['lastUpdated']+$TIMEOUT_LIMIT < time()) { + debug ("Session timeout ".($_SESSION['lastUpdated']+$TIMEOUT_LIMIT).">".time(),"session"); + session_destroy(); + session_start(); +} +debug(print_r($_SESSION, true) , "session"); +?> --- /dev/null +++ b/include/common-template.inc.php @@ -1,1 +1,242 @@ - + + + + + ' . $pageTitle . ' + '; + if ($datepicker) echo ''; + if (isDebugServer()) echo ' + + + '; + else echo ' + + + '; + if ($datepicker) echo ' + '; + echo ''; + if (strstr($_SERVER['HTTP_USER_AGENT'], 'iPhone') || strstr($_SERVER['HTTP_USER_AGENT'], 'iPod')) { + echo ' + + + '; + } + if ($geolocate) { + echo " "; + } + if (isAnalyticsOn()) echo ' +"; +echo ' + + + '; + if ($opendiv) { + echo '
+ +
+ Back +

' . $pageTitle . '

+
+ +
'; + } +} +function include_footer() +{ + echo ''; + if (isAnalyticsOn()) { + echo ""; + $googleAnalyticsImageUrl = googleAnalyticsGetImageUrl(); + echo ''; + } +} +function timePlaceSettings($geolocate = false) +{ + global $service_periods; + $geoerror = false; + if ($geolocate == true) { + $geoerror = !isset($_SESSION['lat']) || !isset($_SESSION['lat']) || $_SESSION['lat'] == "" || $_SESSION['lon'] == ""; + } + if ($geoerror) { + echo '
Sorry, but your location could not currently be detected. + Please allow location permission, wait for your location to be detected, + or enter an address/co-ordinates in the box below.
'; + } + echo '
+

Change Time/Place (' . (isset($_SESSION['time']) ? $_SESSION['time'] : "Current Time,") . ' ' . ucwords(service_period()) . ')...

+
+
+
+ + +
+
+ + + Current Time? +
+
+ + + +
+ + + +
'; +} +function trackEvent($category, $action, $label = "", $value = -1) { + if (isAnalyticsOn()) { + echo ""; + } +} +?> + --- /dev/null +++ b/include/common-transit.inc.php @@ -1,1 +1,73 @@ - + 0) { + $midnight = mktime(0, 0, 0, date("n") , date("j") , date("Y")); + return date("h:ia", $midnight + $seconds); + } + else { + return ""; + } +} +function viaPoints($tripid, $stopid, $timingPointsOnly = false) +{ + global $APIurl; + $url = $APIurl . "/json/tripstoptimes?trip=" . $tripid; + $json = json_decode(getPage($url)); + debug(print_r($json, true)); + $stops = $json[0]; + $times = $json[1]; + $foundStop = false; + $viaPoints = Array(); + foreach ($stops as $key => $row) { + if ($foundStop) { + if (!$timingPointsOnly || !startsWith($row[5], "Wj")) { + $viaPoints[] = Array( + "id" => $row[0], + "name" => $row[1], + "time" => $times[$key] + ); + } + } + else { + if ($row[0] == $stopid) $foundStop = true; + } + } + return $viaPoints; +} +function viaPointNames($tripid, $stopid) +{ + $points = viaPoints($tripid, $stopid, true); + $pointNames = Array(); + foreach ($points as $point) { + $pointNames[] = $point['name']; + } + return implode(", ", $pointNames); +} +?> --- /dev/null +++ b/include/common.inc.php @@ -1,1 +1,147 @@ +\n"; +} +function isJQueryMobileDevice() +{ + // http://forum.jquery.com/topic/what-is-the-best-way-to-detect-all-useragents-which-can-handle-jquery-mobile#14737000002087897 + $user_agent = $_SERVER['HTTP_USER_AGENT']; + return preg_match('/iphone/i', $user_agent) || preg_match('/android/i', $user_agent) || preg_match('/webos/i', $user_agent) || preg_match('/ios/i', $user_agent) || preg_match('/bada/i', $user_agent) || preg_match('/maemo/i', $user_agent) || preg_match('/meego/i', $user_agent) || preg_match('/fennec/i', $user_agent) || (preg_match('/symbian/i', $user_agent) && preg_match('/s60/i', $user_agent) && $browser['majorver'] >= 5) || (preg_match('/symbian/i', $user_agent) && preg_match('/platform/i', $user_agent) && $browser['majorver'] >= 3) || (preg_match('/blackberry/i', $user_agent) && $browser['majorver'] >= 5) || (preg_match('/opera mobile/i', $user_agent) && $browser['majorver'] >= 10) || (preg_match('/opera mini/i', $user_agent) && $browser['majorver'] >= 5); +} +function isFastDevice() +{ + $ua = $_SERVER['HTTP_USER_AGENT']; + $fastDevices = Array( + "Mozilla/5.0 (X11;", + "Mozilla/5.0 (Windows;", + "Mozilla/5.0 (iP", + "Mozilla/5.0 (Linux; U; Android", + "Mozilla/4.0 (compatible; MSIE" + ); + $slowDevices = Array( + "J2ME", + "MIDP", + "Opera/", + "Mozilla/2.0 (compatible;", + "Mozilla/3.0 (compatible;" + ); + return true; +} +function array_flatten($a, $f = array()) +{ + if (!$a || !is_array($a)) return ''; + foreach ($a as $k => $v) { + if (is_array($v)) $f = array_flatten($v, $f); + else $f[$k] = $v; + } + return $f; +} +function remove_spaces($string) +{ + return str_replace(' ', '', $string); +} +function object2array($object) +{ + if (is_object($object)) { + foreach ($object as $key => $value) { + $array[$key] = $value; + } + } + else { + $array = $object; + } + return $array; +} +function startsWith($haystack, $needle, $case = true) +{ + if ($case) { + return (strcmp(substr($haystack, 0, strlen($needle)) , $needle) === 0); + } + return (strcasecmp(substr($haystack, 0, strlen($needle)) , $needle) === 0); +} + +function endsWith($haystack, $needle, $case = true) +{ + if ($case) { + return (strcmp(substr($haystack, strlen($haystack) - strlen($needle)) , $needle) === 0); + } + return (strcasecmp(substr($haystack, strlen($haystack) - strlen($needle)) , $needle) === 0); +} +function bracketsMeanNewLine($input) +{ + return str_replace(")", "
", str_replace("(", "
", $input)); +} +function sksort(&$array, $subkey = "id", $sort_ascending = false) +{ + if (count($array)) $temp_array[key($array) ] = array_shift($array); + foreach ($array as $key => $val) { + $offset = 0; + $found = false; + foreach ($temp_array as $tmp_key => $tmp_val) { + if (!$found and strtolower($val[$subkey]) > strtolower($tmp_val[$subkey])) { + $temp_array = array_merge((array)array_slice($temp_array, 0, $offset) , array( + $key => $val + ) , array_slice($temp_array, $offset)); + $found = true; + } + $offset++; + } + if (!$found) $temp_array = array_merge($temp_array, array( + $key => $val + )); + } + if ($sort_ascending) $array = array_reverse($temp_array); + else $array = $temp_array; +} +?> + --- a/index.php +++ b/index.php @@ -1,17 +1,18 @@ -
-

busness time


Canberra Bus Timetables and Trip Planner
+

busness time


Canberra Bus Timetables and Trip Planner
- Launch Trip Planner... + + Launch Trip Planner... @@ -19,6 +20,7 @@
  • Timetables - Routes
  • Routes By Final Destination
  • Routes By Number
  • +
  • Routes By Suburb
  • Nearby Routes
  • + --- a/js/jQuery.ui.datepicker.js +++ b/js/jQuery.ui.datepicker.js @@ -95,4 +95,62 @@ "dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker= function(a){if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b)); return this.each(function(){typeof a=="string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new L;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.5";window["DP_jQuery_"+y]=d})(jQuery); -; +;/* +* jQuery Mobile Framework : temporary extension to port jQuery UI's datepicker for mobile +* Copyright (c) jQuery Project +* Dual licensed under the MIT or GPL Version 2 licenses. +* http://jquery.org/license +*/ +(function($, undefined ) { + + //cache previous datepicker ui method + var prevDp = $.fn.datepicker; + + //rewrite datepicker + $.fn.datepicker = function( options ){ + + var dp = this; + + //call cached datepicker plugin + prevDp.call( this, options ); + + //extend with some dom manipulation to update the markup for jQM + //call immediately + function updateDatepicker(){ + $( ".ui-datepicker-header", dp ).addClass("ui-body-c ui-corner-top").removeClass("ui-corner-all"); + $( ".ui-datepicker-prev, .ui-datepicker-next", dp ).attr("href", "#"); + $( ".ui-datepicker-prev", dp ).buttonMarkup({iconpos: "notext", icon: "arrow-l", shadow: true, corners: true}); + $( ".ui-datepicker-next", dp ).buttonMarkup({iconpos: "notext", icon: "arrow-r", shadow: true, corners: true}); + $( ".ui-datepicker-calendar th", dp ).addClass("ui-bar-c"); + $( ".ui-datepicker-calendar td", dp ).addClass("ui-body-c"); + $( ".ui-datepicker-calendar a", dp ).buttonMarkup({corners: false, shadow: false}); + $( ".ui-datepicker-calendar a.ui-state-active", dp ).addClass("ui-btn-active"); // selected date + $( ".ui-datepicker-calendar a.ui-state-highlight", dp ).addClass("ui-btn-up-e"); // today"s date + $( ".ui-datepicker-calendar .ui-btn", dp ).each(function(){ + var el = $(this); + // remove extra button markup - necessary for date value to be interpreted correctly + el.html( el.find( ".ui-btn-text" ).text() ); + }); + }; + + //update now + updateDatepicker(); + + // and on click + $( dp ).click( updateDatepicker ); + + //return jqm obj + return this; + }; + + //bind to pagecreate to automatically enhance date inputs + $( ".ui-page" ).live( "pagecreate", function(){ + $( "#date, input[type='date'], input[data-type='date']" ).each(function(){ + if ($(this).hasClass("hasDatepicker") == false) { + $(this).after( $( "
    " ).datepicker({ altField: "#" + $(this).attr( "id" ), showOtherMonths: true }) ); + $(this).addClass("hasDatepicker"); + } + }); + }); +})( jQuery ); + --- a/js/jquery.ui.datepicker.mobile.js +++ /dev/null @@ -1,59 +1,1 @@ -/* -* jQuery Mobile Framework : temporary extension to port jQuery UI's datepicker for mobile -* Copyright (c) jQuery Project -* Dual licensed under the MIT or GPL Version 2 licenses. -* http://jquery.org/license -*/ -(function($, undefined ) { - //cache previous datepicker ui method - var prevDp = $.fn.datepicker; - - //rewrite datepicker - $.fn.datepicker = function( options ){ - - var dp = this; - - //call cached datepicker plugin - prevDp.call( this, options ); - - //extend with some dom manipulation to update the markup for jQM - //call immediately - function updateDatepicker(){ - $( ".ui-datepicker-header", dp ).addClass("ui-body-c ui-corner-top").removeClass("ui-corner-all"); - $( ".ui-datepicker-prev, .ui-datepicker-next", dp ).attr("href", "#"); - $( ".ui-datepicker-prev", dp ).buttonMarkup({iconpos: "notext", icon: "arrow-l", shadow: true, corners: true}); - $( ".ui-datepicker-next", dp ).buttonMarkup({iconpos: "notext", icon: "arrow-r", shadow: true, corners: true}); - $( ".ui-datepicker-calendar th", dp ).addClass("ui-bar-c"); - $( ".ui-datepicker-calendar td", dp ).addClass("ui-body-c"); - $( ".ui-datepicker-calendar a", dp ).buttonMarkup({corners: false, shadow: false}); - $( ".ui-datepicker-calendar a.ui-state-active", dp ).addClass("ui-btn-active"); // selected date - $( ".ui-datepicker-calendar a.ui-state-highlight", dp ).addClass("ui-btn-up-e"); // today"s date - $( ".ui-datepicker-calendar .ui-btn", dp ).each(function(){ - var el = $(this); - // remove extra button markup - necessary for date value to be interpreted correctly - el.html( el.find( ".ui-btn-text" ).text() ); - }); - }; - - //update now - updateDatepicker(); - - // and on click - $( dp ).click( updateDatepicker ); - - //return jqm obj - return this; - }; - - //bind to pagecreate to automatically enhance date inputs - $( ".ui-page" ).live( "pagecreate", function(){ - $( "#date, input[type='date'], input[data-type='date']" ).each(function(){ - if ($(this).hasClass("hasDatepicker") == false) { - $(this).after( $( "
    " ).datepicker({ altField: "#" + $(this).attr( "id" ), showOtherMonths: true }) ); - $(this).addClass("hasDatepicker"); - } - }); - }); -})( jQuery ); - --- /dev/null +++ b/labs/OpenStreetMap.js @@ -1,1 +1,165 @@ +/** + * Namespace: Util.OSM + */ +OpenLayers.Util.OSM = {}; +/** + * Constant: MISSING_TILE_URL + * {String} URL of image to display for missing tiles + */ +OpenLayers.Util.OSM.MISSING_TILE_URL = "/404.php"; + +/** + * Property: originalOnImageLoadError + * {Function} Original onImageLoadError function. + */ +OpenLayers.Util.OSM.originalOnImageLoadError = OpenLayers.Util.onImageLoadError; + +/** + * Function: onImageLoadError + */ +OpenLayers.Util.onImageLoadError = function() { + if (this.src.match(/^http:\/\/[abc]\.[a-z]+\.openstreetmap\.org\//)) { + this.src = OpenLayers.Util.OSM.MISSING_TILE_URL; + } else if (this.src.match(/^http:\/\/[def]\.tah\.openstreetmap\.org\//)) { + // do nothing - this layer is transparent +