Fix openID auth paths
--- /dev/null
+++ b/.gitignore
@@ -1,1 +1,8 @@
+/labs/tiles/12
+/labs/tiles/13
+/labs/tiles/14
+/labs/tiles/15
+/labs/tiles/16
+/labs/tiles/17
+/labs/tiles/19
--- a/about.php
+++ b/about.php
@@ -1,35 +1,53 @@
<?php
+/*
+ * Copyright 2010,2011 Alexander Sadleir
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
include ('include/common.inc.php');
include_header("About", "about")
?>
<p>
-Busness Time - An ACT bus timetable webapp<br />
-Based on the maxious-canberra-transit-feed (<a
-href="http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip">download</a>,
-last updated <?php
-echo date("F d Y.", @filemtime('cbrfeed.zip')); ?>)<br />
-Source code for the <a
-href="https://github.com/maxious/ACTBus-data">transit
-feed</a> and <a href="https://github.com/maxious/ACTBus-ui">this
-site</a> available from github.<br />
-Uses jQuery Mobile, PHP, PostgreSQL, OpenTripPlanner, OpenLayers, OpenStreetMap, Cloudmade Geocoder and Tile Service<br />
-<br />
-Feedback encouraged; contact maxious@lambdacomplex.org<br />
+ Busness Time - An ACT bus timetable webapp<br />
+ Based on the maxious-canberra-transit-feed (<a
+ href="http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip">download</a>,
+ last updated <?php echo date("F d Y.", @filemtime('cbrfeed.zip')); ?>)<br />
+ Source code for the <a
+ href="https://github.com/maxious/ACTBus-data">transit
+ feed</a> and <a href="https://github.com/maxious/ACTBus-ui">this
+ site</a> available from github.<br />
+ Uses jQuery Mobile, PHP, PostgreSQL, OpenTripPlanner, OpenLayers, OpenStreetMap, Cloudmade Geocoder and Tile Service<br />
<br />
-Some icons by Joseph Wain / glyphish.com<br />
-Native clients also available for iPhone(<a href="http://itunes.apple.com/au/app/cbrtimetable/id444287349?mt=8">cbrTimetable by Sandor Kolotenko</a>
-, <a href="http://itunes.apple.com/au/app/act-buses/id376634797?mt=8">ACT Buses by David Sullivan</a>)
-and Android (<a href="https://market.android.com/details?id=com.action">MyBus 2.0 by Imagine Team</a>)
-<br />
-<br />
-<small>Disclaimer: The content of this website is of a general and informative nature. Please check with printed timetables or those available on http://action.act.gov.au before your trip.
-Whilst every effort has been made to ensure the high quality and accuracy of the Site, the Author makes no warranty,
-express or implied concerning the topicality, correctness, completeness or quality of the information, which is provided
-"as is". The Author expressly disclaims all warranties, including but not limited to warranties of fitness for a particular purpose and warranties of merchantability.
-All offers are not binding and without obligation. The Author expressly reserves the right, in his discretion, to suspend,
-change, modify, add or remove portions of the Site and to restrict or terminate the use and accessibility of the Site
-without prior notice. </small>
-<?php
-include_footer();
-?>
+ Feedback encouraged; contact maxious@lambdacomplex.org<br />
+ <br />
+ Some icons by Joseph Wain / glyphish.com<br />
+ Native clients also available for iPhone(<a href="http://itunes.apple.com/au/app/cbrtimetable/id444287349?mt=8">cbrTimetable by Sandor Kolotenko</a>
+ , <a href="http://itunes.apple.com/au/app/act-buses/id376634797?mt=8">ACT Buses by David Sullivan</a>)
+ and Android (<a href="https://market.android.com/details?id=com.action">MyBus 2.0 by Imagine Team</a>)
+ <br />
+ GTFS-realtime API;
+ Alerts and Trip Updates (but only Cancelled or Stop Skipped)
+ Default format binary but can get JSON by adding ?ascii=yes
+ <br />
+ <br />
+ <small>Disclaimer: The content of this website is of a general and informative nature. Please check with printed timetables or those available on http://action.act.gov.au before your trip.
+ Whilst every effort has been made to ensure the high quality and accuracy of the Site, the Author makes no warranty,
+ express or implied concerning the topicality, correctness, completeness or quality of the information, which is provided
+ "as is". The Author expressly disclaims all warranties, including but not limited to warranties of fitness for a particular purpose and warranties of merchantability.
+ All offers are not binding and without obligation. The Author expressly reserves the right, in his discretion, to suspend,
+ change, modify, add or remove portions of the Site and to restrict or terminate the use and accessibility of the Site
+ without prior notice. </small>
+ <?php
+ include_footer();
+ ?>
--- a/aws/awsStartup.sh
+++ b/aws/awsStartup.sh
@@ -5,38 +5,9 @@
#postgres postgres-server php-pg
#http://www.how2forge.org/installing-lighttpd-with-php5-and-mysql-support-on-fedora-12
-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/lib/staticmaplite/cache
-chmod -R 777 /var/www/lib/staticmaplite/cache
-chcon -R -t httpd_sys_content_rw_t /var/www/labs/tiles
-chmod -R 777 /var/www/labs/tiles
-wget http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip \
--O /var/www/cbrfeed.zip
+sh busuiphp.sh
+sh busuidb.sh
+sh busuiotp.sh
-createdb transitdata
-createlang -d transitdata plpgsql
-psql -d transitdata -f /var/www/lib/postgis.sql
-# curl https://github.com/maxious/ACTBus-ui/raw/master/transitdata.cbrfeed.sql.gz -o transitdata.cbrfeed.sql.gz
-#made with pg_dump transitdata | gzip -c > transitdata.cbrfeed.sql.gz
-gunzip /var/www/transitdata.cbrfeed.sql.gz
-psql -d transitdata -f /var/www/transitdata.cbrfeed.sql
-#createuser transitdata -SDRP
-#password transitdata
-#psql -d transitdata -c \"GRANT SELECT ON TABLE agency,calendar,calendar_dates,routes,stop_times,stops,trips TO transitdata;\"
-#psql -d transitdata -c "GRANT SELECT,INSERT ON TABLE myway_observations,myway_routes,myway_stops,myway_timingdeltas TO transitdata;"
-#psql -d transitdata -c "GRANT SELECT,INSERT,UPDATE ON TABLE myway_routes,myway_stops TO transitdata;"
-##psql -d transitdata -c "GRANT SELECT ON ALL TABLES IN SCHEMA public TO transitdata;"
-php /var/www/updatedb.php
-wget http://s3-ap-southeast-1.amazonaws.com/busresources/Graph.obj \
--O /tmp/Graph.obj
-rm -rfv /usr/share/tomcat6/webapps/opentripplanner*
-wget http://s3-ap-southeast-1.amazonaws.com/busresources/opentripplanner-webapp.war \
--O /usr/share/tomcat6/webapps/opentripplanner-webapp.war
-wget http://s3-ap-southeast-1.amazonaws.com/busresources/opentripplanner-api-webapp.war \
--O /usr/share/tomcat6/webapps/opentripplanner-api-webapp.war
-/etc/init.d/tomcat6 restart
--- /dev/null
+++ b/aws/busuidb.sh
@@ -1,1 +1,14 @@
-
+createdb transitdata
+createlang -d transitdata plpgsql
+psql -d transitdata -f /var/www/lib/postgis.sql
+# curl https://github.com/maxious/ACTBus-ui/raw/master/transitdata.cbrfeed.sql.gz -o transitdata.cbrfeed.sql.gz
+#made with pg_dump transitdata | gzip -c > transitdata.cbrfeed.sql.gz
+gunzip /var/www/transitdata.cbrfeed.sql.gz
+psql -d transitdata -f /var/www/transitdata.cbrfeed.sql
+#createuser transitdata -SDRP
+#password transitdata
+#psql -d transitdata -c "GRANT SELECT ON TABLE agency,calendar,calendar_dates,routes,stop_times,stops,trips TO transitdata;"
+#psql -d transitdata -c "GRANT SELECT,INSERT ON TABLE myway_observations,myway_routes,myway_stops,myway_timingdeltas TO transitdata;"
+#psql -d transitdata -c "GRANT SELECT,INSERT,UPDATE ON TABLE myway_routes,myway_stops TO transitdata;"
+##psql -d transitdata -c "GRANT SELECT ON ALL TABLES IN SCHEMA public TO transitdata;"
+php /var/www/updatedb.php
--- /dev/null
+++ b/aws/busuiotp.sh
@@ -1,1 +1,10 @@
+wget http://s3-ap-southeast-1.amazonaws.com/busresources/Graph.obj \
+-O /tmp/Graph.obj
+/etc/init.d/tomcat6 stop
+rm -rfv /usr/share/tomcat6/webapps/opentripplanner*
+wget http://s3-ap-southeast-1.amazonaws.com/busresources/opentripplanner-webapp.war \
+-O /usr/share/tomcat6/webapps/opentripplanner-webapp.war
+wget http://s3-ap-southeast-1.amazonaws.com/busresources/opentripplanner-api-webapp.war \
+-O /usr/share/tomcat6/webapps/opentripplanner-api-webapp.war
+/etc/init.d/tomcat6 restart
--- /dev/null
+++ b/aws/busuiotp.testing.sh
@@ -1,1 +1,10 @@
+wget http://s3-ap-southeast-1.amazonaws.com/busresources/testing/Graph.obj \
+-O /tmp/Graph.obj
+/etc/init.d/tomcat6 stop
+rm -rfv /usr/share/tomcat6/webapps/opentripplanner*
+wget http://s3-ap-southeast-1.amazonaws.com/busresources/testing/opentripplanner-webapp.war \
+-O /usr/share/tomcat6/webapps/opentripplanner-webapp.war
+wget http://s3-ap-southeast-1.amazonaws.com/busresources/testing/opentripplanner-api-webapp.war \
+-O /usr/share/tomcat6/webapps/opentripplanner-api-webapp.war
+/etc/init.d/tomcat6 restart
--- /dev/null
+++ b/aws/busuiphp.sh
@@ -1,1 +1,16 @@
+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/lib/staticmaplite/cache
+chmod -R 777 /var/www/lib/staticmaplite/cache
+
+chcon -R -t httpd_sys_content_rw_t /var/www/labs/tiles
+chmod -R 777 /var/www/labs/tiles
+
+chcon -R -t httpd_sys_content_rw_t /var/www/lib/openid-php/oid_store
+chmod -R 777 /var/www/lib/openid-php/oid_store
+
+wget http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip \
+-O /var/www/cbrfeed.zip
--- /dev/null
+++ b/aws/data-sources.xml
@@ -1,1 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
+ <!-- Single graph -->
+ <import resource="classpath:org/opentripplanner/api/application-context.xml" />
+
+ <bean id="graphBundle" class="org.opentripplanner.model.GraphBundle">
+ <property name="path" value="/tmp/" />
+ </bean>
+
+</beans>
+
--- a/css/jquery.mobile-1.0b2.css
+++ /dev/null
@@ -1,1641 +1,1 @@
-/*!
- * jQuery Mobile v1.0b2
- * http://jquerymobile.com/
- *
- * Copyright 2010, jQuery Project
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- */
-/*
-* jQuery Mobile Framework
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
-*/
-
-/* A
------------------------------------------------------------------------------------------------------------*/
-
-.ui-bar-a {
- border: 1px solid #2A2A2A;
- background: #111111;
- color: #ffffff;
- font-weight: bold;
- text-shadow: 0 -1px 1px #000000;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#111)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #3c3c3c, #111); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #3c3c3c, #111); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #3c3c3c, #111); /* IE10 */
- background-image: -o-linear-gradient(top, #3c3c3c, #111); /* Opera 11.10+ */
- background-image: linear-gradient(top, #3c3c3c, #111);
-}
-.ui-bar-a,
-.ui-bar-a input,
-.ui-bar-a select,
-.ui-bar-a textarea,
-.ui-bar-a button {
- font-family: Helvetica, Arial, sans-serif;
-}
-.ui-bar-a .ui-link-inherit {
- color: #fff;
-}
-.ui-bar-a .ui-link {
- color: #7cc4e7;
- font-weight: bold;
-}
-.ui-body-a {
- border: 1px solid #2A2A2A;
- background: #222222;
- color: #fff;
- text-shadow: 0 1px 0 #000;
- font-weight: normal;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#666), to(#222)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #666, #222); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #666, #222); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #666, #222); /* IE10 */
- background-image: -o-linear-gradient(top, #666, #222); /* Opera 11.10+ */
- background-image: linear-gradient(top, #666, #222);
-}
-.ui-body-a,
-.ui-body-a input,
-.ui-body-a select,
-.ui-body-a textarea,
-.ui-body-a button {
- font-family: Helvetica, Arial, sans-serif;
-}
-.ui-body-a .ui-link-inherit {
- color: #fff;
-}
-.ui-body-a .ui-link {
- color: #2489CE;
- font-weight: bold;
-}
-.ui-br {
- border-bottom: rgb(130,130,130);
- border-bottom: rgba(130,130,130,.3);
- border-bottom-width: 1px;
- border-bottom-style: solid;
-}
-.ui-btn-up-a {
- border: 1px solid #222;
- background: #333333;
- font-weight: bold;
- color: #fff;
- text-shadow: 0 -1px 1px #000;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#555), to(#333)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #555, #333); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #555, #333); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #555, #333); /* IE10 */
- background-image: -o-linear-gradient(top, #555, #333); /* Opera 11.10+ */
- background-image: linear-gradient(top, #555, #333);
-}
-.ui-btn-up-a a.ui-link-inherit {
- color: #fff;
-}
-.ui-btn-hover-a {
- border: 1px solid #000;
- background: #444444;
- font-weight: bold;
- color: #fff;
- text-shadow: 0 -1px 1px #000;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#666), to(#444)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #666, #444); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #666, #444); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #666, #444); /* IE10 */
- background-image: -o-linear-gradient(top, #666, #444); /* Opera 11.10+ */
- background-image: linear-gradient(top, #666, #444);
-}
-.ui-btn-hover-a a.ui-link-inherit {
- color: #fff;
-}
-.ui-btn-down-a {
- border: 1px solid #000;
- background: #3d3d3d;
- font-weight: bold;
- color: #fff;
- text-shadow: 0 -1px 1px #000;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#333), to(#5a5a5a)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #333, #5a5a5a); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #333, #5a5a5a); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #333, #5a5a5a); /* IE10 */
- background-image: -o-linear-gradient(top, #333, #5a5a5a); /* Opera 11.10+ */
- background-image: linear-gradient(top, #333, #5a5a5a);
-}
-.ui-btn-down-a a.ui-link-inherit {
- color: #fff;
-}
-.ui-btn-up-a,
-.ui-btn-hover-a,
-.ui-btn-down-a {
- font-family: Helvetica, Arial, sans-serif;
- text-decoration: none;
-}
-
-
-/* B
------------------------------------------------------------------------------------------------------------*/
-
-.ui-bar-b {
- border: 1px solid #456f9a;
- background: #5e87b0;
- color: #fff;
- font-weight: bold;
- text-shadow: 0 -1px 1px #254f7a;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#81a8ce), to(#5e87b0)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #81a8ce, #5e87b0); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #81a8ce, #5e87b0); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #81a8ce, #5e87b0); /* IE10 */
- background-image: -o-linear-gradient(top, #81a8ce, #5e87b0); /* Opera 11.10+ */
- background-image: linear-gradient(top, #81a8ce, #5e87b0);
-}
-.ui-bar-b,
-.ui-bar-b input,
-.ui-bar-b select,
-.ui-bar-b textarea,
-.ui-bar-b button {
- font-family: Helvetica, Arial, sans-serif;
-}
-.ui-bar-b .ui-link-inherit {
- color: #fff;
-}
-.ui-bar-b .ui-link {
- color: #7cc4e7;
- font-weight: bold;
-}
-
-.ui-body-b {
- border: 1px solid #C6C6C6;
- background: #cccccc;
- color: #333333;
- text-shadow: 0 1px 0 #fff;
- font-weight: normal;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#e6e6e6), to(#ccc)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #e6e6e6, #ccc); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #e6e6e6, #ccc); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #e6e6e6, #ccc); /* IE10 */
- background-image: -o-linear-gradient(top, #e6e6e6, #ccc); /* Opera 11.10+ */
- background-image: linear-gradient(top, #e6e6e6, #ccc);
-}
-.ui-body-b,
-.ui-body-b input,
-.ui-body-b select,
-.ui-body-b textarea,
-.ui-body-b button {
- font-family: Helvetica, Arial, sans-serif;
-}
-.ui-body-b .ui-link-inherit {
- color: #333333;
-}
-.ui-body-b .ui-link {
- color: #2489CE;
- font-weight: bold;
-}
-.ui-btn-up-b {
- border: 1px solid #145072;
- background: #2567ab;
- font-weight: bold;
- color: #fff;
- text-shadow: 0 -1px 1px #145072;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#5f9cc5), to(#396b9e)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #5f9cc5, #396b9e); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #5f9cc5, #396b9e); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #5f9cc5, #396b9e); /* IE10 */
- background-image: -o-linear-gradient(top, #5f9cc5, #396b9e); /* Opera 11.10+ */
- background-image: linear-gradient(top, #5f9cc5, #396b9e);
-}
-.ui-btn-up-b a.ui-link-inherit {
- color: #fff;
-}
-.ui-btn-hover-b {
- border: 1px solid #00516e;
- background: #4b88b6;
- font-weight: bold;
- color: #fff;
- text-shadow: 0 -1px 1px #014D68;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#72b0d4), to(#4b88b6)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #72b0d4, #4b88b6); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #72b0d4, #4b88b6); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #72b0d4, #4b88b6); /* IE10 */
- background-image: -o-linear-gradient(top, #72b0d4, #4b88b6); /* Opera 11.10+ */
- background-image: linear-gradient(top, #72b0d4, #4b88b6);
-}
-.ui-btn-hover-b a.ui-link-inherit {
- color: #fff;
-}
-.ui-btn-down-b {
- border: 1px solid #225377;
- background: #4e89c5;
- font-weight: bold;
- color: #fff;
- text-shadow: 0 -1px 1px #225377;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#396b9e), to(#4e89c5)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #396b9e, #4e89c5); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #396b9e, #4e89c5); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #396b9e, #4e89c5); /* IE10 */
- background-image: -o-linear-gradient(top, #396b9e, #4e89c5); /* Opera 11.10+ */
- background-image: linear-gradient(top, #396b9e, #4e89c5);
-}
-.ui-btn-down-b a.ui-link-inherit {
- color: #fff;
-}
-.ui-btn-up-b,
-.ui-btn-hover-b,
-.ui-btn-down-b {
- font-family: Helvetica, Arial, sans-serif;
- text-decoration: none;
-}
-
-
-/* C
------------------------------------------------------------------------------------------------------------*/
-
-.ui-bar-c {
- border: 1px solid #B3B3B3;
- background: #e9eaeb;
- color: #3E3E3E;
- font-weight: bold;
- text-shadow: 0 1px 1px #fff;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#f0f0f0), to(#e9eaeb)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #f0f0f0, #e9eaeb); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #f0f0f0, #e9eaeb); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #f0f0f0, #e9eaeb); /* IE10 */
- background-image: -o-linear-gradient(top, #f0f0f0, #e9eaeb); /* Opera 11.10+ */
- background-image: linear-gradient(top, #f0f0f0, #e9eaeb);
-}
-.ui-bar-c,
-.ui-bar-c input,
-.ui-bar-c select,
-.ui-bar-c textarea,
-.ui-bar-c button {
- font-family: Helvetica, Arial, sans-serif;
-}
-.ui-body-c {
- border: 1px solid #B3B3B3;
- color: #333333;
- text-shadow: 0 1px 0 #fff;
- background: #f0f0f0;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#ddd)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #eee, #ddd); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #eee, #ddd); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #eee, #ddd); /* IE10 */
- background-image: -o-linear-gradient(top, #eee, #ddd); /* Opera 11.10+ */
- background-image: linear-gradient(top, #eee, #ddd);
-}
-.ui-body-c,
-.ui-body-c input,
-.ui-body-c select,
-.ui-body-c textarea,
-.ui-body-c button {
- font-family: Helvetica, Arial, sans-serif;
-}
-.ui-body-c .ui-link-inherit {
- color: #333333;
-}
-.ui-body-c .ui-link {
- color: #2489CE;
- font-weight: bold;
-}
-
-.ui-btn-up-c {
- border: 1px solid #ccc;
- background: #eee;
- font-weight: bold;
- color: #444;
- text-shadow: 0 1px 1px #f6f6f6;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#fdfdfd), to(#eee)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #fdfdfd, #eee); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #fdfdfd, #eee); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #fdfdfd, #eee); /* IE10 */
- background-image: -o-linear-gradient(top, #fdfdfd, #eee); /* Opera 11.10+ */
- background-image: linear-gradient(top, #fdfdfd, #eee);
-}
-.ui-btn-up-c a.ui-link-inherit {
- color: #2F3E46;
-}
-
-.ui-btn-hover-c {
- border: 1px solid #bbb;
- background: #dadada;
- font-weight: bold;
- color: #101010;
- text-shadow: 0 1px 1px #fff;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#ededed), to(#dadada)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #ededed, #dadada); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #ededed, #dadada); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #ededed, #dadada); /* IE10 */
- background-image: -o-linear-gradient(top, #ededed, #dadada); /* Opera 11.10+ */
- background-image: linear-gradient(top, #ededed, #dadada);
-}
-.ui-btn-hover-c a.ui-link-inherit {
- color: #2F3E46;
-}
-.ui-btn-down-c {
- border: 1px solid #808080;
- background: #fdfdfd;
- font-weight: bold;
- color: #111111;
- text-shadow: 0 1px 1px #ffffff;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#fdfdfd)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #eee, #fdfdfd); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #eee, #fdfdfd); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #eee, #fdfdfd); /* IE10 */
- background-image: -o-linear-gradient(top, #eee, #fdfdfd); /* Opera 11.10+ */
- background-image: linear-gradient(top, #eee, #fdfdfd);
-}
-.ui-btn-down-c a.ui-link-inherit {
- color: #2F3E46;
-}
-.ui-btn-up-c,
-.ui-btn-hover-c,
-.ui-btn-down-c {
- font-family: Helvetica, Arial, sans-serif;
- text-decoration: none;
-}
-
-
-/* D
------------------------------------------------------------------------------------------------------------*/
-
-.ui-bar-d {
- border: 1px solid #ccc;
- background: #bbb;
- color: #333;
- text-shadow: 0 1px 0 #eee;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#ddd), to(#bbb)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #ddd, #bbb); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #ddd, #bbb); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #ddd, #bbb); /* IE10 */
- background-image: -o-linear-gradient(top, #ddd, #bbb); /* Opera 11.10+ */
- background-image: linear-gradient(top, #ddd, #bbb);
-}
-.ui-bar-d,
-.ui-bar-d input,
-.ui-bar-d select,
-.ui-bar-d textarea,
-.ui-bar-d button {
- font-family: Helvetica, Arial, sans-serif;
-}
-.ui-bar-d .ui-link-inherit {
- color: #333;
-}
-.ui-bar-d .ui-link {
- color: #2489CE;
- font-weight: bold;
-}
-.ui-body-d {
- border: 1px solid #ccc;
- color: #333333;
- text-shadow: 0 1px 0 #fff;
- background: #ffffff;
-}
-.ui-body-d,
-.ui-body-d input,
-.ui-body-d select,
-.ui-body-d textarea,
-.ui-body-d button {
- font-family: Helvetica, Arial, sans-serif;
-}
-.ui-body-d .ui-link-inherit {
- color: #333333;
-}
-.ui-body-d .ui-link {
- color: #2489CE;
- font-weight: bold;
-}
-.ui-btn-up-d {
- border: 1px solid #ccc;
- background: #fff;
- font-weight: bold;
- color: #444;
- text-shadow: 0 1px 1px #fff;
-}
-.ui-btn-up-d a.ui-link-inherit {
- color: #333;
-}
-.ui-btn-hover-d {
- border: 1px solid #aaa;
- background: #eeeeee;
- font-weight: bold;
- color: #222;
- cursor: pointer;
- text-shadow: 0 1px 1px #fff;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#fdfdfd), to(#eee)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #fdfdfd, #eee); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #fdfdfd, #eee); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #fdfdfd, #eee); /* IE10 */
- background-image: -o-linear-gradient(top, #fdfdfd, #eee); /* Opera 11.10+ */
- background-image: linear-gradient(top, #fdfdfd, #eee);
-}
-.ui-btn-hover-d a.ui-link-inherit {
- color: #222;
-}
-.ui-btn-down-d {
- border: 1px solid #aaaaaa;
- background: #ffffff;
- font-weight: bold;
- color: #111;
- text-shadow: 0 1px 1px #ffffff;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#fff)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #eee, #fff); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #eee, #fff); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #eee, #fff); /* IE10 */
- background-image: -o-linear-gradient(top, #eee, #fff); /* Opera 11.10+ */
- background-image: linear-gradient(top, #eee, #fff);
-}
-.ui-btn-down-d a.ui-link-inherit {
- color: #111;
-}
-.ui-btn-up-d,
-.ui-btn-hover-d,
-.ui-btn-down-d {
- font-family: Helvetica, Arial, sans-serif;
- text-decoration: none;
-}
-
-
-/* E
------------------------------------------------------------------------------------------------------------*/
-
-.ui-bar-e {
- border: 1px solid #F7C942;
- background: #fadb4e;
- color: #333;
- text-shadow: 0 1px 0 #fff;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#fceda7), to(#fadb4e)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #fceda7, #fadb4e); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #fceda7, #fadb4e); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #fceda7, #fadb4e); /* IE10 */
- background-image: -o-linear-gradient(top, #fceda7, #fadb4e); /* Opera 11.10+ */
- background-image: linear-gradient(top, #fceda7, #fadb4e);
-}
-.ui-bar-e,
-.ui-bar-e input,
-.ui-bar-e select,
-.ui-bar-e textarea,
-.ui-bar-e button {
- font-family: Helvetica, Arial, sans-serif;
-}
-.ui-bar-e .ui-link-inherit {
- color: #333;
-}
-.ui-bar-e .ui-link {
- color: #2489CE;
- font-weight: bold;
-}
-.ui-body-e {
- border: 1px solid #F7C942;
- color: #333333;
- text-shadow: 0 1px 0 #fff;
- background: #faeb9e;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#faeb9e)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #fff, #faeb9e); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #fff, #faeb9e); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #fff, #faeb9e); /* IE10 */
- background-image: -o-linear-gradient(top, #fff, #faeb9e); /* Opera 11.10+ */
- background-image: linear-gradient(top, #fff, #faeb9e);
-}
-.ui-body-e,
-.ui-body-e input,
-.ui-body-e select,
-.ui-body-e textarea,
-.ui-body-e button {
- font-family: Helvetica, Arial, sans-serif;
-}
-.ui-body-e .ui-link-inherit {
- color: #333333;
-}
-.ui-body-e .ui-link {
- color: #2489CE;
- font-weight: bold;
-}
-.ui-btn-up-e {
- border: 1px solid #F7C942;
- background: #fadb4e;
- font-weight: bold;
- color: #333;
- text-shadow: 0 1px 0 #fff;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#fceda7), to(#fadb4e)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #fceda7, #fadb4e); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #fceda7, #fadb4e); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #fceda7, #fadb4e); /* IE10 */
- background-image: -o-linear-gradient(top, #fceda7, #fadb4e); /* Opera 11.10+ */
- background-image: linear-gradient(top, #fceda7, #fadb4e);
-}
-.ui-btn-up-e a.ui-link-inherit {
- color: #333;
-}
-.ui-btn-hover-e {
- border: 1px solid #e79952;
- background: #fbe26f;
- font-weight: bold;
- color: #111;
- text-shadow: 0 1px 1px #fff;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf0b5), to(#fbe26f)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #fcf0b5, #fbe26f); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #fcf0b5, #fbe26f); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #fcf0b5, #fbe26f); /* IE10 */
- background-image: -o-linear-gradient(top, #fcf0b5, #fbe26f); /* Opera 11.10+ */
- background-image: linear-gradient(top, #fcf0b5, #fbe26f);
-}
-
-.ui-btn-hover-e a.ui-link-inherit {
- color: #333;
-}
-.ui-btn-down-e {
- border: 1px solid #F7C942;
- background: #fceda7;
- font-weight: bold;
- color: #111;
- text-shadow: 0 1px 1px #ffffff;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#fadb4e), to(#fceda7)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #fadb4e, #fceda7); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #fadb4e, #fceda7); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #fadb4e, #fceda7); /* IE10 */
- background-image: -o-linear-gradient(top, #fadb4e, #fceda7); /* Opera 11.10+ */
- background-image: linear-gradient(top, #fadb4e, #fceda7);
-}
-.ui-btn-down-e a.ui-link-inherit {
- color: #333;
-}
-.ui-btn-up-e,
-.ui-btn-hover-e,
-.ui-btn-down-e {
- font-family: Helvetica, Arial, sans-serif;
- text-decoration: none;
-}
-
-
-/* links within "buttons"
------------------------------------------------------------------------------------------------------------*/
-
-a.ui-link-inherit {
- text-decoration: none !important;
-}
-
-
-/* Active class used as the "on" state across all themes
------------------------------------------------------------------------------------------------------------*/
-
-.ui-btn-active {
- border: 1px solid #155678;
- background: #4596ce;
- font-weight: bold;
- color: #fff;
- cursor: pointer;
- text-shadow: 0 -1px 1px #145072;
- text-decoration: none;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#85bae4), to(#5393c5)); /* Saf4+, Chrome */
- background-image: -webkit-linear-gradient(top, #85bae4, #5393c5); /* Chrome 10+, Saf5.1+ */
- background-image: -moz-linear-gradient(top, #85bae4, #5393c5); /* FF3.6 */
- background-image: -ms-linear-gradient(top, #85bae4, #5393c5); /* IE10 */
- background-image: -o-linear-gradient(top, #85bae4, #5393c5); /* Opera 11.10+ */
- background-image: linear-gradient(top, #85bae4, #5393c5);
- outline: none;
-}
-.ui-btn-active a.ui-link-inherit {
- color: #fff;
-}
-
-
-/* button inner top highlight
------------------------------------------------------------------------------------------------------------*/
-
-.ui-btn-inner {
- border-top: 1px solid #fff;
- border-color: rgba(255,255,255,.3);
-}
-
-
-/* corner rounding classes
------------------------------------------------------------------------------------------------------------*/
-
-.ui-corner-tl {
- -moz-border-radius-topleft: .6em;
- -webkit-border-top-left-radius: .6em;
- border-top-left-radius: .6em;
-}
-.ui-corner-tr {
- -moz-border-radius-topright: .6em;
- -webkit-border-top-right-radius: .6em;
- border-top-right-radius: .6em;
-}
-.ui-corner-bl {
- -moz-border-radius-bottomleft: .6em;
- -webkit-border-bottom-left-radius: .6em;
- border-bottom-left-radius: .6em;
-}
-.ui-corner-br {
- -moz-border-radius-bottomright: .6em;
- -webkit-border-bottom-right-radius: .6em;
- border-bottom-right-radius: .6em;
-}
-.ui-corner-top {
- -moz-border-radius-topleft: .6em;
- -webkit-border-top-left-radius: .6em;
- border-top-left-radius: .6em;
- -moz-border-radius-topright: .6em;
- -webkit-border-top-right-radius: .6em;
- border-top-right-radius: .6em;
-}
-.ui-corner-bottom {
- -moz-border-radius-bottomleft: .6em;
- -webkit-border-bottom-left-radius: .6em;
- border-bottom-left-radius: .6em;
- -moz-border-radius-bottomright: .6em;
- -webkit-border-bottom-right-radius: .6em;
- border-bottom-right-radius: .6em;
- }
-.ui-corner-right {
- -moz-border-radius-topright: .6em;
- -webkit-border-top-right-radius: .6em;
- border-top-right-radius: .6em;
- -moz-border-radius-bottomright: .6em;
- -webkit-border-bottom-right-radius: .6em;
- border-bottom-right-radius: .6em;
-}
-.ui-corner-left {
- -moz-border-radius-topleft: .6em;
- -webkit-border-top-left-radius: .6em;
- border-top-left-radius: .6em;
- -moz-border-radius-bottomleft: .6em;
- -webkit-border-bottom-left-radius: .6em;
- border-bottom-left-radius: .6em;
-}
-.ui-corner-all {
- -moz-border-radius: .6em;
- -webkit-border-radius: .6em;
- border-radius: .6em;
-}
-
-
-
-/* Interaction cues
------------------------------------------------------------------------------------------------------------*/
-.ui-disabled {
- opacity: .3;
-}
-.ui-disabled,
-.ui-disabled a {
- cursor: default;
-}
-
-/* Icons
------------------------------------------------------------------------------------------------------------*/
-
-.ui-icon {
- background: #666;
- background: rgba(0,0,0,.4);
- background-image: url(images/icons-18-white.png);
- background-repeat: no-repeat;
- -moz-border-radius: 9px;
- -webkit-border-radius: 9px;
- border-radius: 9px;
-}
-
-
-/* Alt icon color
------------------------------------------------------------------------------------------------------------*/
-
-.ui-icon-alt {
- background: #fff;
- background: rgba(255,255,255,.3);
- background-image: url(images/icons-18-black.png);
- background-repeat: no-repeat;
-}
-
-/* HD/"retina" sprite
------------------------------------------------------------------------------------------------------------*/
-
-@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
- only screen and (min--moz-device-pixel-ratio: 1.5),
- only screen and (min-resolution: 240dpi) {
-
- .ui-icon-plus, .ui-icon-minus, .ui-icon-delete, .ui-icon-arrow-r,
- .ui-icon-arrow-l, .ui-icon-arrow-u, .ui-icon-arrow-d, .ui-icon-check,
- .ui-icon-gear, .ui-icon-refresh, .ui-icon-forward, .ui-icon-back,
- .ui-icon-grid, .ui-icon-star, .ui-icon-alert, .ui-icon-info, .ui-icon-home, .ui-icon-search,
- .ui-icon-checkbox-off, .ui-icon-checkbox-on, .ui-icon-radio-off, .ui-icon-radio-on {
- background-image: url(images/icons-36-white.png);
- -moz-background-size: 776px 18px;
- -o-background-size: 776px 18px;
- -webkit-background-size: 776px 18px;
- background-size: 776px 18px;
- }
- .ui-icon-alt {
- background-image: url(images/icons-36-black.png);
- }
-}
-
-/* plus minus */
-.ui-icon-plus {
- background-position: -0 50%;
-}
-.ui-icon-minus {
- background-position: -36px 50%;
-}
-
-/* delete/close */
-.ui-icon-delete {
- background-position: -72px 50%;
-}
-
-/* arrows */
-.ui-icon-arrow-r {
- background-position: -108px 50%;
-}
-.ui-icon-arrow-l {
- background-position: -144px 50%;
-}
-.ui-icon-arrow-u {
- background-position: -180px 50%;
-}
-.ui-icon-arrow-d {
- background-position: -216px 50%;
-}
-
-/* misc */
-.ui-icon-check {
- background-position: -252px 50%;
-}
-.ui-icon-gear {
- background-position: -288px 50%;
-}
-.ui-icon-refresh {
- background-position: -324px 50%;
-}
-.ui-icon-forward {
- background-position: -360px 50%;
-}
-.ui-icon-back {
- background-position: -396px 50%;
-}
-.ui-icon-grid {
- background-position: -432px 50%;
-}
-.ui-icon-star {
- background-position: -468px 50%;
-}
-.ui-icon-alert {
- background-position: -504px 50%;
-}
-.ui-icon-info {
- background-position: -540px 50%;
-}
-.ui-icon-home {
- background-position: -576px 50%;
-}
-.ui-icon-search {
- background-position: -612px 50%;
-}
-.ui-icon-checkbox-off {
- background-position: -684px 50%;
-}
-.ui-icon-checkbox-on {
- background-position: -648px 50%;
-}
-.ui-icon-radio-off {
- background-position: -756px 50%;
-}
-.ui-icon-radio-on {
- background-position: -720px 50%;
-}
-
-
-/* checks,radios */
-.ui-checkbox .ui-icon {
- -moz-border-radius: 3px;
- -webkit-border-radius: 3px;
- border-radius: 3px;
-}
-.ui-icon-checkbox-off,
-.ui-icon-radio-off {
- background-color: transparent;
-}
-.ui-checkbox-on .ui-icon,
-.ui-radio-on .ui-icon {
- background-color: #4596ce; /* NOTE: this hex should match the active state color. It's repeated here for cascade */
-}
-.ui-icon-searchfield {
- background-image: url(images/icon-search-black.png);
- background-size: 16px 16px;
-}
-
-/* loading icon */
-.ui-icon-loading {
- background-image: url(images/ajax-loader.png);
- width: 40px;
- height: 40px;
- -moz-border-radius: 20px;
- -webkit-border-radius: 20px;
- border-radius: 20px;
- background-size: 35px 35px;
-}
-
-
-/* Button corner classes
------------------------------------------------------------------------------------------------------------*/
-
-.ui-btn-corner-tl {
- -moz-border-radius-topleft: 1em;
- -webkit-border-top-left-radius: 1em;
- border-top-left-radius: 1em;
-}
-.ui-btn-corner-tr {
- -moz-border-radius-topright: 1em;
- -webkit-border-top-right-radius: 1em;
- border-top-right-radius: 1em;
-}
-.ui-btn-corner-bl {
- -moz-border-radius-bottomleft: 1em;
- -webkit-border-bottom-left-radius: 1em;
- border-bottom-left-radius: 1em;
-}
-.ui-btn-corner-br {
- -moz-border-radius-bottomright: 1em;
- -webkit-border-bottom-right-radius: 1em;
- border-bottom-right-radius: 1em;
-}
-.ui-btn-corner-top {
- -moz-border-radius-topleft: 1em;
- -webkit-border-top-left-radius: 1em;
- border-top-left-radius: 1em;
- -moz-border-radius-topright: 1em;
- -webkit-border-top-right-radius: 1em;
- border-top-right-radius: 1em;
-}
-.ui-btn-corner-bottom {
- -moz-border-radius-bottomleft: 1em;
- -webkit-border-bottom-left-radius: 1em;
- border-bottom-left-radius: 1em;
- -moz-border-radius-bottomright: 1em;
- -webkit-border-bottom-right-radius: 1em;
- border-bottom-right-radius: 1em;
-}
-.ui-btn-corner-right {
- -moz-border-radius-topright: 1em;
- -webkit-border-top-right-radius: 1em;
- border-top-right-radius: 1em;
- -moz-border-radius-bottomright: 1em;
- -webkit-border-bottom-right-radius: 1em;
- border-bottom-right-radius: 1em;
-}
-.ui-btn-corner-left {
- -moz-border-radius-topleft: 1em;
- -webkit-border-top-left-radius: 1em;
- border-top-left-radius: 1em;
- -moz-border-radius-bottomleft: 1em;
- -webkit-border-bottom-left-radius: 1em;
- border-bottom-left-radius: 1em;
-}
-.ui-btn-corner-all {
- -moz-border-radius: 1em;
- -webkit-border-radius: 1em;
- border-radius: 1em;
-}
-
-/* radius clip workaround for cleaning up corner trapping */
-.ui-corner-tl,
-.ui-corner-tr,
-.ui-corner-bl,
-.ui-corner-br,
-.ui-corner-top,
-.ui-corner-bottom,
-.ui-corner-right,
-.ui-corner-left,
-.ui-corner-all,
-.ui-btn-corner-tl,
-.ui-btn-corner-tr,
-.ui-btn-corner-bl,
-.ui-btn-corner-br,
-.ui-btn-corner-top,
-.ui-btn-corner-bottom,
-.ui-btn-corner-right,
-.ui-btn-corner-left,
-.ui-btn-corner-all {
- -webkit-background-clip: padding-box;
- -moz-background-clip: padding;
- background-clip: padding-box;
-}
-
-/* Overlay / modal
------------------------------------------------------------------------------------------------------------*/
-
-.ui-overlay {
- background: #666;
- opacity: .5;
- filter: Alpha(Opacity=50);
- position: absolute;
- width: 100%;
- height: 100%;
-}
-.ui-overlay-shadow {
- -moz-box-shadow: 0px 0px 12px rgba(0,0,0,.6);
- -webkit-box-shadow: 0px 0px 12px rgba(0,0,0,.6);
- box-shadow: 0px 0px 12px rgba(0,0,0,.6);
-}
-.ui-shadow {
- -moz-box-shadow: 0px 1px 4px rgba(0,0,0,.3);
- -webkit-box-shadow: 0px 1px 4px rgba(0,0,0,.3);
- box-shadow: 0px 1px 4px rgba(0,0,0,.3);
-}
-.ui-bar-a .ui-shadow,
-.ui-bar-b .ui-shadow ,
-.ui-bar-c .ui-shadow {
- -moz-box-shadow: 0px 1px 0 rgba(255,255,255,.3);
- -webkit-box-shadow: 0px 1px 0 rgba(255,255,255,.3);
- box-shadow: 0px 1px 0 rgba(255,255,255,.3);
-}
-.ui-shadow-inset {
- -moz-box-shadow: inset 0px 1px 4px rgba(0,0,0,.2);
- -webkit-box-shadow: inset 0px 1px 4px rgba(0,0,0,.2);
- box-shadow: inset 0px 1px 4px rgba(0,0,0,.2);
-}
-.ui-icon-shadow {
- -moz-box-shadow: 0px 1px 0 rgba(255,255,255,.4);
- -webkit-box-shadow: 0px 1px 0 rgba(255,255,255,.4);
- box-shadow: 0px 1px 0 rgba(255,255,255,.4);
-}
-
-
-/* Focus state - set here for specificity
------------------------------------------------------------------------------------------------------------*/
-
-.ui-focus {
- -moz-box-shadow: 0px 0px 12px #387bbe;
- -webkit-box-shadow: 0px 0px 12px #387bbe;
- box-shadow: 0px 0px 12px #387bbe;
-}
-
-/* unset box shadow in browsers that don't do it right
------------------------------------------------------------------------------------------------------------*/
-
-.ui-mobile-nosupport-boxshadow * {
- -moz-box-shadow: none !important;
- -webkit-box-shadow: none !important;
- box-shadow: none !important;
-}
-
-/* ...and bring back focus */
-.ui-mobile-nosupport-boxshadow .ui-focus {
- outline-width: 2px;
-}/*
-* jQuery Mobile Framework
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
-*/
-
-/* some unsets - more probably needed */
-.ui-mobile, .ui-mobile body { height: 100%; }
-.ui-mobile fieldset, .ui-page { padding: 0; margin: 0; }
-.ui-mobile a img, .ui-mobile fieldset { border: 0; }
-
-/* responsive page widths */
-.ui-mobile-viewport { margin: 0; overflow-x: hidden; -webkit-text-size-adjust: none; -ms-text-size-adjust:none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); }
-
-/* "page" containers - full-screen views, one should always be in view post-pageload */
-.ui-mobile [data-role=page], .ui-mobile [data-role=dialog], .ui-page { top: 0; left: 0; width: 100%; min-height: 100%; position: absolute; display: none; border: 0; }
-.ui-mobile .ui-page-active { display: block; overflow: visible; }
-
-/*orientations from js are available */
-.portrait,
-.portrait .ui-page { min-height: 420px; }
-.landscape,
-.landscape .ui-page { min-height: 300px; }
-
-/* loading screen */
-.ui-loading .ui-mobile-viewport { overflow: hidden !important; }
-.ui-loading .ui-loader { display: block; }
-.ui-loading .ui-page { overflow: hidden; }
-.ui-loader { display: none; position: absolute; opacity: .85; z-index: 100; left: 50%; width: 200px; margin-left: -130px; margin-top: -35px; padding: 10px 30px; }
-.ui-loader h1 { font-size: 15px; text-align: center; }
-.ui-loader .ui-icon { position: static; display: block; opacity: .9; margin: 0 auto; width: 35px; height: 35px; background-color: transparent; }
-
-/*fouc*/
-.ui-mobile-rendering > * { visibility: hidden; }
-
-/*headers, content panels*/
-.ui-bar, .ui-body { position: relative; padding: .4em 15px; overflow: hidden; display: block; clear:both; }
-.ui-bar { font-size: 16px; margin: 0; }
-.ui-bar h1, .ui-bar h2, .ui-bar h3, .ui-bar h4, .ui-bar h5, .ui-bar h6 { margin: 0; padding: 0; font-size: 16px; display: inline-block; }
-
-.ui-header, .ui-footer { display: block; }
-.ui-page .ui-header, .ui-page .ui-footer { position: relative; }
-.ui-header .ui-btn-left { position: absolute; left: 10px; top: .4em; }
-.ui-header .ui-btn-right { position: absolute; right: 10px; top: .4em; }
-.ui-header .ui-title, .ui-footer .ui-title { min-height: 1.1em; text-align: center; font-size: 16px; display: block; margin: .6em 90px .8em; padding: 0; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; outline: 0 !important; }
-
-/*content area*/
-.ui-content { border-width: 0; overflow: visible; overflow-x: hidden; padding: 15px; }
-.ui-page-fullscreen .ui-content { padding:0; }
-
-/* icons sizing */
-.ui-icon { width: 18px; height: 18px; }
-
-/* fullscreen class on ui-content div */
-.ui-fullscreen { }
-.ui-fullscreen img { max-width: 100%; }
-
-/* non-js content hiding */
-.ui-nojs { position: absolute; left: -9999px; }
-/*
-* jQuery Mobile Framework
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
-*/
-.spin {
- -webkit-transform: rotate(360deg);
- -webkit-animation-name: spin;
- -webkit-animation-duration: 1s;
- -webkit-animation-iteration-count: infinite;
- -webkit-animation-timing-function: linear;
-}
-@-webkit-keyframes spin {
- from {-webkit-transform: rotate(0deg);}
- to {-webkit-transform: rotate(360deg);}
-}
-
-/* Transitions from jQtouch (with small modifications): http://www.jqtouch.com/
-Built by David Kaneda and maintained by Jonathan Stark.
-*/
-.in, .out {
- -webkit-animation-timing-function: ease-in-out;
- -webkit-animation-duration: 350ms;
-}
-
-.slide.in {
- -webkit-transform: translateX(0);
- -webkit-animation-name: slideinfromright;
-}
-
-.slide.out {
- -webkit-transform: translateX(-100%);
- -webkit-animation-name: slideouttoleft;
-}
-
-.slide.in.reverse {
- -webkit-transform: translateX(0);
- -webkit-animation-name: slideinfromleft;
-}
-
-.slide.out.reverse {
- -webkit-transform: translateX(100%);
- -webkit-animation-name: slideouttoright;
-}
-
-.slideup.in {
- -webkit-transform: translateY(0);
- -webkit-animation-name: slideinfrombottom;
- z-index: 10;
-}
-
-.slideup.out {
- -webkit-animation-name: dontmove;
- z-index: 0;
-}
-
-.slideup.out.reverse {
- -webkit-transform: translateY(100%);
- z-index: 10;
- -webkit-animation-name: slideouttobottom;
-}
-
-.slideup.in.reverse {
- z-index: 0;
- -webkit-animation-name: dontmove;
-}
-.slidedown.in {
- -webkit-transform: translateY(0);
- -webkit-animation-name: slideinfromtop;
- z-index: 10;
-}
-
-.slidedown.out {
- -webkit-animation-name: dontmove;
- z-index: 0;
-}
-
-.slidedown.out.reverse {
- -webkit-transform: translateY(-100%);
- z-index: 10;
- -webkit-animation-name: slideouttotop;
-}
-
-.slidedown.in.reverse {
- z-index: 0;
- -webkit-animation-name: dontmove;
-}
-
-@-webkit-keyframes slideinfromright {
- from { -webkit-transform: translateX(100%); }
- to { -webkit-transform: translateX(0); }
-}
-
-@-webkit-keyframes slideinfromleft {
- from { -webkit-transform: translateX(-100%); }
- to { -webkit-transform: translateX(0); }
-}
-
-@-webkit-keyframes slideouttoleft {
- from { -webkit-transform: translateX(0); }
- to { -webkit-transform: translateX(-100%); }
-}
-
-@-webkit-keyframes slideouttoright {
- from { -webkit-transform: translateX(0); }
- to { -webkit-transform: translateX(100%); }
-}
-
-
-@-webkit-keyframes slideinfromtop {
- from { -webkit-transform: translateY(-100%); }
- to { -webkit-transform: translateY(0); }
-}
-
-@-webkit-keyframes slideinfrombottom {
- from { -webkit-transform: translateY(100%); }
- to { -webkit-transform: translateY(0); }
-}
-
-@-webkit-keyframes slideouttobottom {
- from { -webkit-transform: translateY(0); }
- to { -webkit-transform: translateY(100%); }
-}
-
-@-webkit-keyframes slideouttotop {
- from { -webkit-transform: translateY(0); }
- to { -webkit-transform: translateY(-100%); }
-}
-@-webkit-keyframes fadein {
- from { opacity: 0; }
- to { opacity: 1; }
-}
-
-@-webkit-keyframes fadeout {
- from { opacity: 1; }
- to { opacity: 0; }
-}
-
-.fade.in {
- opacity: 1;
- z-index: 10;
- -webkit-animation-name: fadein;
-}
-.fade.out {
- z-index: 0;
- -webkit-animation-name: fadeout;
-}
-
-/* The properties in this rule are only necessary for the 'flip' transition.
- * We need specify the perspective to create a projection matrix. This will add
- * some depth as the element flips. The depth number represents the distance of
- * the viewer from the z-plane. According to the CSS3 spec, 1000 is a moderate
- * value.
- */
-.viewport-flip {
- -webkit-perspective: 1000;
- position: absolute;
-}
-
-.ui-mobile-viewport-transitioning,
-.ui-mobile-viewport-transitioning .ui-page {
- width: 100%;
- height: 100%;
- overflow: hidden;
-}
-
-.flip {
- -webkit-animation-duration: .65s;
- -webkit-backface-visibility:hidden;
- -webkit-transform:translateX(0); /* Needed to work around an iOS 3.1 bug that causes listview thumbs to disappear when -webkit-visibility:hidden is used. */
-}
-
-.flip.in {
- -webkit-transform: rotateY(0) scale(1);
- -webkit-animation-name: flipinfromleft;
-}
-
-.flip.out {
- -webkit-transform: rotateY(-180deg) scale(.8);
- -webkit-animation-name: flipouttoleft;
-}
-
-/* Shake it all about */
-
-.flip.in.reverse {
- -webkit-transform: rotateY(0) scale(1);
- -webkit-animation-name: flipinfromright;
-}
-
-.flip.out.reverse {
- -webkit-transform: rotateY(180deg) scale(.8);
- -webkit-animation-name: flipouttoright;
-}
-
-@-webkit-keyframes flipinfromright {
- from { -webkit-transform: rotateY(-180deg) scale(.8); }
- to { -webkit-transform: rotateY(0) scale(1); }
-}
-
-@-webkit-keyframes flipinfromleft {
- from { -webkit-transform: rotateY(180deg) scale(.8); }
- to { -webkit-transform: rotateY(0) scale(1); }
-}
-
-@-webkit-keyframes flipouttoleft {
- from { -webkit-transform: rotateY(0) scale(1); }
- to { -webkit-transform: rotateY(-180deg) scale(.8); }
-}
-
-@-webkit-keyframes flipouttoright {
- from { -webkit-transform: rotateY(0) scale(1); }
- to { -webkit-transform: rotateY(180deg) scale(.8); }
-}
-
-
-/* Hackish, but reliable. */
-
-@-webkit-keyframes dontmove {
- from { opacity: 1; }
- to { opacity: 1; }
-}
-
-.pop {
- -webkit-transform-origin: 50% 50%;
-}
-
-.pop.in {
- -webkit-transform: scale(1);
- opacity: 1;
- -webkit-animation-name: popin;
- z-index: 10;
-}
-
-.pop.out.reverse {
- -webkit-transform: scale(.2);
- opacity: 0;
- -webkit-animation-name: popout;
- z-index: 10;
-}
-
-.pop.in.reverse {
- z-index: 0;
- -webkit-animation-name: dontmove;
-}
-
-@-webkit-keyframes popin {
- from {
- -webkit-transform: scale(.2);
- opacity: 0;
- }
- to {
- -webkit-transform: scale(1);
- opacity: 1;
- }
-}
-
-@-webkit-keyframes popout {
- from {
- -webkit-transform: scale(1);
- opacity: 1;
- }
- to {
- -webkit-transform: scale(.2);
- opacity: 0;
- }
-}/*
-* jQuery Mobile Framework
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
-*/
-
-/* content configurations. */
-.ui-grid-a, .ui-grid-b, .ui-grid-c, .ui-grid-d { overflow: hidden; }
-.ui-block-a, .ui-block-b, .ui-block-c, .ui-block-d, .ui-block-e { margin: 0; padding: 0; border: 0; float: left; min-height:1px;}
-
-/* grid solo: 100 - single item fallback */
-.ui-grid-solo .ui-block-a { width: 100%; float: none; }
-
-/* grid a: 50/50 */
-.ui-grid-a .ui-block-a, .ui-grid-a .ui-block-b { width: 50%; }
-.ui-grid-a .ui-block-a { clear: left; }
-
-/* grid b: 33/33/33 */
-.ui-grid-b .ui-block-a, .ui-grid-b .ui-block-b, .ui-grid-b .ui-block-c { width: 33.333%; }
-.ui-grid-b .ui-block-a { clear: left; }
-
-/* grid c: 25/25/25/25 */
-.ui-grid-c .ui-block-a, .ui-grid-c .ui-block-b, .ui-grid-c .ui-block-c, .ui-grid-c .ui-block-d { width: 25%; }
-.ui-grid-c .ui-block-a { clear: left; }
-
-/* grid d: 20/20/20/20/20 */
-.ui-grid-d .ui-block-a, .ui-grid-d .ui-block-b, .ui-grid-d .ui-block-c, .ui-grid-d .ui-block-d, .ui-grid-d .ui-block-e { width: 20%; }
-.ui-grid-d .ui-block-a { clear: left; }
-/*
-* jQuery Mobile Framework
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
-*/
-/* fixed page header & footer configuration */
-.ui-header, .ui-footer, .ui-page-fullscreen .ui-header, .ui-page-fullscreen .ui-footer { position: absolute; overflow: hidden; width: 100%; border-left-width: 0; border-right-width: 0; }
-.ui-header-fixed, .ui-footer-fixed {
- z-index: 1000;
- -webkit-transform: translateZ(0); /* Force header/footer rendering to go through the same rendering pipeline as native page scrolling. */
-}
-.ui-footer-duplicate, .ui-page-fullscreen .ui-fixed-inline { display: none; }
-.ui-page-fullscreen .ui-header, .ui-page-fullscreen .ui-footer { opacity: .9; }
-/*
-* jQuery Mobile Framework
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
-*/
-.ui-navbar { overflow: hidden; }
-.ui-navbar ul, .ui-navbar-expanded ul { list-style:none; padding: 0; margin: 0; position: relative; display: block; border: 0;}
-.ui-navbar-collapsed ul { float: left; width: 75%; margin-right: -2px; }
-.ui-navbar-collapsed .ui-navbar-toggle { float: left; width: 25%; }
-.ui-navbar li.ui-navbar-truncate { position: absolute; left: -9999px; top: -9999px; }
-.ui-navbar li .ui-btn, .ui-navbar .ui-navbar-toggle .ui-btn { display: block; font-size: 12px; text-align: center; margin: 0; border-right-width: 0; }
-.ui-navbar li .ui-btn { margin-right: -1px; }
-.ui-navbar li .ui-btn:last-child { margin-right: 0; }
-.ui-header .ui-navbar li .ui-btn, .ui-header .ui-navbar .ui-navbar-toggle .ui-btn,
-.ui-footer .ui-navbar li .ui-btn, .ui-footer .ui-navbar .ui-navbar-toggle .ui-btn { border-top-width: 0; border-bottom-width: 0; }
-.ui-navbar .ui-btn-inner { padding-left: 2px; padding-right: 2px; }
-.ui-navbar-noicons li .ui-btn .ui-btn-inner, .ui-navbar-noicons .ui-navbar-toggle .ui-btn-inner { padding-top: .8em; padding-bottom: .9em; }
-/*expanded page styles*/
-.ui-navbar-expanded .ui-btn { margin: 0; font-size: 14px; }
-.ui-navbar-expanded .ui-btn-inner { padding-left: 5px; padding-right: 5px; }
-.ui-navbar-expanded .ui-btn-icon-top .ui-btn-inner { padding: 45px 5px 15px; text-align: center; }
-.ui-navbar-expanded .ui-btn-icon-top .ui-icon { top: 15px; }
-.ui-navbar-expanded .ui-btn-icon-bottom .ui-btn-inner { padding: 15px 5px 45px; text-align: center; }
-.ui-navbar-expanded .ui-btn-icon-bottom .ui-icon { bottom: 15px; }
-.ui-navbar-expanded li .ui-btn .ui-btn-inner { min-height: 2.5em; }
-.ui-navbar-expanded .ui-navbar-noicons .ui-btn .ui-btn-inner { padding-top: 1.8em; padding-bottom: 1.9em; }
-/*
-* jQuery Mobile Framework
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
-*/
-.ui-btn { display: block; text-align: center; cursor:pointer; position: relative; margin: .5em 5px; padding: 0; }
-.ui-btn:focus, .ui-btn:active { outline: none; }
-.ui-header .ui-btn, .ui-footer .ui-btn, .ui-bar .ui-btn { display: inline-block; font-size: 13px; margin: 0; }
-.ui-btn-inline { display: inline-block; }
-.ui-btn-inner { padding: .6em 25px; display: block; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; position: relative; zoom: 1; }
-.ui-header .ui-btn-inner, .ui-footer .ui-btn-inner, .ui-bar .ui-btn-inner { padding: .4em 8px .5em; }
-.ui-btn-icon-notext { display: inline-block; width: 20px; height: 20px; padding: 2px 1px 2px 3px; text-indent: -9999px; }
-.ui-btn-icon-notext .ui-btn-inner { padding: 0; }
-.ui-btn-icon-notext .ui-btn-text { position: absolute; left: -999px; }
-.ui-btn-icon-left .ui-btn-inner { padding-left: 33px; }
-.ui-header .ui-btn-icon-left .ui-btn-inner,
-.ui-footer .ui-btn-icon-left .ui-btn-inner,
-.ui-bar .ui-btn-icon-left .ui-btn-inner { padding-left: 27px; }
-.ui-btn-icon-right .ui-btn-inner { padding-right: 33px; }
-.ui-header .ui-btn-icon-right .ui-btn-inner,
-.ui-footer .ui-btn-icon-right .ui-btn-inner,
-.ui-bar .ui-btn-icon-right .ui-btn-inner { padding-right: 27px; }
-.ui-btn-icon-top .ui-btn-inner { padding-top: 33px; }
-.ui-header .ui-btn-icon-top .ui-btn-inner,
-.ui-footer .ui-btn-icon-top .ui-btn-inner,
-.ui-bar .ui-btn-icon-top .ui-btn-inner { padding-top: 27px; }
-.ui-btn-icon-bottom .ui-btn-inner { padding-bottom: 33px; }
-.ui-header .ui-btn-icon-bottom .ui-btn-inner,
-.ui-footer .ui-btn-icon-bottom .ui-btn-inner,
-.ui-bar .ui-btn-icon-bottom .ui-btn-inner { padding-bottom: 27px; }
-
-/*btn icon positioning*/
-.ui-btn-icon-notext .ui-icon { display: block; }
-.ui-btn-icon-left .ui-icon, .ui-btn-icon-right .ui-icon { position: absolute; top: 50%; margin-top: -9px; }
-.ui-btn-icon-top .ui-icon, .ui-btn-icon-bottom .ui-icon { position: absolute; left: 50%; margin-left: -9px; }
-.ui-btn-icon-left .ui-icon { left: 10px; }
-.ui-btn-icon-right .ui-icon {right: 10px; }
-.ui-header .ui-btn-icon-left .ui-icon,
-.ui-footer .ui-btn-icon-left .ui-icon,
-.ui-bar .ui-btn-icon-left .ui-icon { left: 4px; }
-.ui-header .ui-btn-icon-right .ui-icon,
-.ui-footer .ui-btn-icon-right .ui-icon,
-.ui-bar .ui-btn-icon-right .ui-icon { right: 4px; }
-.ui-header .ui-btn-icon-top .ui-icon,
-.ui-footer .ui-btn-icon-top .ui-icon,
-.ui-bar .ui-btn-icon-top .ui-icon { top: 4px; }
-.ui-header .ui-btn-icon-bottom .ui-icon,
-.ui-footer .ui-btn-icon-bottom .ui-icon,
-.ui-bar .ui-btn-icon-bottom .ui-icon { bottom: 4px; }
-.ui-btn-icon-top .ui-icon { top: 5px; }
-.ui-btn-icon-bottom .ui-icon { bottom: 5px; }
-/*hiding native button,inputs */
-.ui-btn-hidden { position: absolute; top: 0; left: 0; width: 100%; height: 100%; -webkit-appearance: button; opacity: 0; cursor: pointer; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter: alpha(opacity=0); background: transparent; }
-/*
-* jQuery Mobile Framework
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
-*/
-.ui-collapsible-contain { margin: .5em 0; }
-.ui-collapsible-heading { font-size: 16px; display: block; margin: 0 -8px; padding: 0; border-width: 0 0 1px 0; position: relative; }
-.ui-collapsible-heading a { text-align: left; margin: 0; }
-.ui-collapsible-heading a .ui-btn-inner { padding-left: 40px; }
-.ui-collapsible-heading a span.ui-btn { position: absolute; left: 6px; top: 50%; margin: -12px 0 0 0; width: 20px; height: 20px; padding: 1px 0px 1px 2px; text-indent: -9999px; }
-.ui-collapsible-heading a span.ui-btn .ui-btn-inner { padding: 10px 0; }
-.ui-collapsible-heading a span.ui-btn .ui-icon { left: 0; margin-top: -10px; }
-.ui-collapsible-heading-status { position:absolute; left:-9999px; }
-.ui-collapsible-content { display: block; padding: 10px 0 10px 8px; }
-.ui-collapsible-content-collapsed { display: none; }
-
-.ui-collapsible-set { margin: .5em 0; }
-.ui-collapsible-set .ui-collapsible-contain { margin: -1px 0 0; }
-/*
-* jQuery Mobile Framework
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
-*/
-.ui-controlgroup, fieldset.ui-controlgroup { padding: 0; margin: .5em 0 1em; }
-.ui-bar .ui-controlgroup { margin: 0 .3em; }
-.ui-controlgroup-label { font-size: 16px; line-height: 1.4; font-weight: normal; margin: 0 0 .3em; }
-.ui-controlgroup-controls { display: block; width: 95%;}
-.ui-controlgroup li { list-style: none; }
-.ui-controlgroup-vertical .ui-btn,
-.ui-controlgroup-vertical .ui-checkbox, .ui-controlgroup-vertical .ui-radio { margin: 0; border-bottom-width: 0; }
-.ui-controlgroup-vertical .ui-controlgroup-last { border-bottom-width: 1px; }
-.ui-controlgroup-horizontal { padding: 0; }
-.ui-controlgroup-horizontal .ui-btn,
-.ui-controlgroup-horizontal .ui-checkbox, .ui-controlgroup-horizontal .ui-radio { display: inline-block; margin: 0 -5px 0 0; }
-.ui-controlgroup-horizontal .ui-checkbox, .ui-controlgroup-horizontal .ui-radio { display: inline; }
-.ui-controlgroup-horizontal .ui-checkbox .ui-btn, .ui-controlgroup-horizontal .ui-radio .ui-btn,
-.ui-controlgroup-horizontal .ui-checkbox:last-child, .ui-controlgroup-horizontal .ui-radio:last-child { margin-right: 0; }
-.ui-controlgroup-horizontal .ui-controlgroup-last { margin-right: 0; }
-.ui-controlgroup .ui-checkbox label, .ui-controlgroup .ui-radio label { font-size: 16px; }
-/* conflicts with listview..
-.ui-controlgroup .ui-btn-icon-notext { width: 30px; height: 30px; text-indent: -9999px; }
-.ui-controlgroup .ui-btn-icon-notext .ui-btn-inner { padding: 5px 6px 5px 5px; }
-*/
-
-@media all and (min-width: 450px){
- .ui-controlgroup-label { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0; }
- .ui-controlgroup-controls { width: 60%; display: inline-block; }
-} /*
-* jQuery Mobile Framework
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
-*/
-.ui-dialog { min-height: 480px; }
-.ui-dialog .ui-header, .ui-dialog .ui-content, .ui-dialog .ui-footer { margin: 15px; position: relative; }
-.ui-dialog .ui-header, .ui-dialog .ui-footer { z-index: 10; width: auto; }
-.ui-dialog .ui-content, .ui-dialog .ui-footer { margin-top: -15px; }/*
-* jQuery Mobile Framework
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
-*/
-.ui-checkbox, .ui-radio { position:relative; margin: .2em 0 .5em; z-index: 1; }
-.ui-checkbox .ui-btn, .ui-radio .ui-btn { margin: 0; text-align: left; z-index: 2; }
-.ui-checkbox .ui-btn-inner, .ui-radio .ui-btn-inner { white-space: normal; }
-.ui-checkbox .ui-btn-icon-left .ui-btn-inner,.ui-radio .ui-btn-icon-left .ui-btn-inner { padding-left: 45px; }
-.ui-checkbox .ui-btn-icon-right .ui-btn-inner, .ui-radio .ui-btn-icon-right .ui-btn-inner { padding-right: 45px; }
-.ui-checkbox .ui-icon, .ui-radio .ui-icon { top: 1.1em; }
-.ui-checkbox .ui-btn-icon-left .ui-icon, .ui-radio .ui-btn-icon-left .ui-icon {left: 15px; }
-.ui-checkbox .ui-btn-icon-right .ui-icon, .ui-radio .ui-btn-icon-right .ui-icon {right: 15px; }
-/* input, label positioning */
-.ui-checkbox input,.ui-radio input { position:absolute; left:20px; top:50%; width: 10px; height: 10px; margin:-5px 0 0 0; outline: 0 !important; z-index: 1; }/*
-* jQuery Mobile Framework
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
-*/
-.ui-field-contain { padding: 1.5em 0; margin: 0; border-bottom-width: 1px; overflow: visible; }
-.ui-field-contain:first-child { border-top-width: 0; }
-@media all and (min-width: 450px){
- .ui-field-contain { border-width: 0; padding: 0; margin: 1em 0; }
-} /*
-* jQuery Mobile Framework
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
-*/
-.ui-select { display: block; position: relative; }
-.ui-select select { position: absolute; left: -9999px; top: -9999px; }
-.ui-select .ui-btn { overflow: hidden; }
-.ui-select .ui-btn select { cursor: pointer; -webkit-appearance: button; left: 0; top:0; width: 100%; height: 100%; opacity: 0; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter: alpha(opacity=0); }
-@-moz-document url-prefix() {.ui-select .ui-btn select { opacity: 0.0001; }}
-.ui-select .ui-btn select.ui-select-nativeonly { opacity: 1; text-indent: 0; }
-
-.ui-select .ui-btn-icon-right .ui-btn-inner { padding-right: 45px; }
-.ui-select .ui-btn-icon-right .ui-icon { right: 15px; }
-
-/* labels */
-label.ui-select { font-size: 16px; line-height: 1.4; font-weight: normal; margin: 0 0 .3em; display: block; }
-
-/*listbox*/
-.ui-select .ui-btn-text, .ui-selectmenu .ui-btn-text { display: block; min-height: 1em; }
-.ui-select .ui-btn-text { text-overflow: ellipsis; overflow: hidden;}
-
-.ui-selectmenu { position: absolute; padding: 0; z-index: 100 !important; width: 80%; max-width: 350px; padding: 6px; }
-.ui-selectmenu .ui-listview { margin: 0; }
-.ui-selectmenu .ui-btn.ui-li-divider { cursor: default; }
-.ui-selectmenu-hidden { top: -9999px; left: -9999px; }
-.ui-selectmenu-screen { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 99; }
-.ui-screen-hidden, .ui-selectmenu-list .ui-li .ui-icon { display: none; }
-.ui-selectmenu-list .ui-li .ui-icon { display: block; }
-.ui-li.ui-selectmenu-placeholder { display: none; }
-.ui-selectmenu .ui-header .ui-title { margin: 0.6em 46px 0.8em; }
-
-@media all and (min-width: 450px){
- label.ui-select { display: inline-block; width: 20%; margin: 0 2% 0 0; }
- .ui-select { width: 60%; display: inline-block; }
-}
-
-/* when no placeholder is defined in a multiple select, the header height doesn't even extend past the close button. this shim's content in there */
-.ui-selectmenu .ui-header h1:after { content: '.'; visibility: hidden; }/*
-* jQuery Mobile Framework
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
-*/
-label.ui-input-text { font-size: 16px; line-height: 1.4; display: block; font-weight: normal; margin: 0 0 .3em; }
-input.ui-input-text, textarea.ui-input-text { background-image: none; padding: .4em; line-height: 1.4; font-size: 16px; display: block; width: 95%; }
-input.ui-input-text { -webkit-appearance: none; }
-textarea.ui-input-text { height: 50px; -webkit-transition: height 200ms linear; -moz-transition: height 200ms linear; -o-transition: height 200ms linear; transition: height 200ms linear; }
-.ui-input-search { padding: 0 30px; width: 77%; background-position: 8px 50%; background-repeat: no-repeat; position: relative; }
-.ui-input-search input.ui-input-text { border: none; width: 98%; padding: .4em 0; margin: 0; display: block; background: transparent none; outline: 0 !important; }
-.ui-input-search .ui-input-clear { position: absolute; right: 0; top: 50%; margin-top: -14px; }
-.ui-input-search .ui-input-clear-hidden { display: none; }
-
-/* orientation adjustments - incomplete!*/
-@media all and (min-width: 450px){
- label.ui-input-text { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0 }
- input.ui-input-text,
- textarea.ui-input-text,
- .ui-input-search { width: 60%; display: inline-block; }
- .ui-input-search { width: 50%; }
- .ui-input-search input.ui-input-text { width: 98%; /*echos rule from above*/ }
-}/*
-* jQuery Mobile Framework
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
-*/
-.ui-listview { margin: 0; counter-reset: listnumbering; }
-.ui-content .ui-listview { margin: -15px; }
-.ui-content .ui-listview-inset { margin: 1em 0; }
-.ui-listview, .ui-li { list-style:none; padding:0; }
-.ui-li, .ui-li.ui-field-contain { display: block; margin:0; position: relative; overflow: visible; text-align: left; border-width: 0; border-top-width: 1px; }
-.ui-li .ui-btn-text a.ui-link-inherit { text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }
-.ui-li-divider, .ui-li-static { padding: .5em 15px; font-size: 14px; font-weight: bold; }
-.ui-li-divider { counter-reset: listnumbering; }
-ol.ui-listview .ui-link-inherit:before, ol.ui-listview .ui-li-static:before, .ui-li-dec { font-size: .8em; display: inline-block; padding-right: .3em; font-weight: normal;counter-increment: listnumbering; content: counter(listnumbering) ". "; }
-ol.ui-listview .ui-li-jsnumbering:before { content: "" !important; } /* to avoid chance of duplication */
-.ui-listview-inset .ui-li { border-right-width: 1px; border-left-width: 1px; }
-.ui-li:last-child, .ui-li.ui-field-contain:last-child { border-bottom-width: 1px; }
-.ui-li>.ui-btn-inner { display: block; position: relative; padding: 0; }
-.ui-li .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li { padding: .7em 75px .7em 15px; display: block; }
-.ui-li-has-thumb .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-thumb { min-height: 60px; padding-left: 100px; }
-.ui-li-has-icon .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-icon { min-height: 20px; padding-left: 40px; }
-.ui-li-heading { font-size: 16px; font-weight: bold; display: block; margin: .6em 0; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }
-.ui-li-desc { font-size: 12px; font-weight: normal; display: block; margin: -.5em 0 .6em; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }
-.ui-li-thumb, .ui-li-icon { position: absolute; left: 1px; top: 0; max-height: 80px; max-width: 80px; }
-.ui-li-icon { max-height: 40px; max-width: 40px; left: 10px; top: .9em; }
-.ui-li-thumb, .ui-li-icon, .ui-li-content { float: left; margin-right: 10px; }
-
-.ui-li-aside { float: right; width: 50%; text-align: right; margin: .3em 0; }
-@media all and (min-width: 480px){
- .ui-li-aside { width: 45%; }
-}
-.ui-li-divider { cursor: default; }
-.ui-li-has-alt .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-alt { padding-right: 95px; }
-.ui-li-count { position: absolute; font-size: 11px; font-weight: bold; padding: .2em .5em; top: 50%; margin-top: -.9em; right: 38px; }
-.ui-li-divider .ui-li-count, .ui-li-static .ui-li-count { right: 10px; }
-.ui-li-has-alt .ui-li-count { right: 55px; }
-.ui-li-link-alt { position: absolute; width: 40px; height: 100%; border-width: 0; border-left-width: 1px; top: 0; right: 0; margin: 0; padding: 0; }
-.ui-li-link-alt .ui-btn { overflow: hidden; position: absolute; right: 8px; top: 50%; margin: -11px 0 0 0; border-bottom-width: 1px; }
-.ui-li-link-alt .ui-btn-inner { padding: 0; position: static; }
-.ui-li-link-alt .ui-btn .ui-icon { right: 50%; margin-right: -9px; }
-
-.ui-listview-filter { border-width: 0; overflow: hidden; margin: -15px -15px 15px -15px }
-.ui-listview-filter .ui-input-search { margin: 5px; width: auto; display: block; }
-
-.ui-listview-filter-inset { margin: -15px -5px -15px -5px; background: transparent; }
-.ui-li.ui-screen-hidden{display:none;}
-/* Odd iPad positioning issue. */
-@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) {
- .ui-li .ui-btn-text { overflow: visible; }
-}/*
-* jQuery Mobile Framework
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
-*/
-label.ui-slider { display: block; }
-input.ui-slider-input { display: inline-block; width: 50px; }
-select.ui-slider-switch { display: none; }
-div.ui-slider { position: relative; display: inline-block; overflow: visible; height: 15px; padding: 0; margin: 0 2% 0 20px; top: 4px; width: 66%; }
-a.ui-slider-handle { position: absolute; z-index: 10; top: 50%; width: 28px; height: 28px; margin-top: -15px; margin-left: -15px; }
-a.ui-slider-handle .ui-btn-inner { padding-left: 0; padding-right: 0; }
-@media all and (min-width: 480px){
- label.ui-slider { display: inline-block; width: 20%; margin: 0 2% 0 0; }
- div.ui-slider { width: 45%; }
-}
-
-div.ui-slider-switch { height: 32px; overflow: hidden; margin-left: 0; }
-div.ui-slider-inneroffset { margin-left: 50%; position: absolute; top: 1px; height: 100%; width: 50%; }
-div.ui-slider-handle-snapping { -webkit-transition: left 100ms linear; }
-div.ui-slider-labelbg { position: absolute; top:0; margin: 0; border-width: 0; }
-div.ui-slider-switch div.ui-slider-labelbg-a { width: 60%; height: 100%; left: 0; }
-div.ui-slider-switch div.ui-slider-labelbg-b { width: 60%; height: 100%; right: 0; }
-.ui-slider-switch-a div.ui-slider-labelbg-a, .ui-slider-switch-b div.ui-slider-labelbg-b { z-index: -1; }
-.ui-slider-switch-a div.ui-slider-labelbg-b, .ui-slider-switch-b div.ui-slider-labelbg-a { z-index: 0; }
-
-div.ui-slider-switch a.ui-slider-handle { z-index: 20; width: 101%; height: 32px; margin-top: -18px; margin-left: -101%; }
-span.ui-slider-label { width: 100%; position: absolute;height: 32px; font-size: 16px; text-align: center; line-height: 2; background: none; border-color: transparent; }
-span.ui-slider-label-a { left: -100%; margin-right: -1px }
-span.ui-slider-label-b { right: -100%; margin-left: -1px }
-
--- /dev/null
+++ b/css/jquery.mobile-1.0b3.css
@@ -1,1 +1,1700 @@
-
+/*!
+ * jQuery Mobile v1.0b3
+ * http://jquerymobile.com/
+ *
+ * Copyright 2010, jQuery Project
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ */
+/*
+* jQuery Mobile Framework
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
+*/
+
+
+/* A
+-----------------------------------------------------------------------------------------------------------*/
+
+.ui-bar-a {
+ border: 1px solid #2A2A2A;
+ background: #111111;
+ color: #ffffff;
+ font-weight: bold;
+ text-shadow: 0 -1px 1px #000000;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#111)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #3c3c3c, #111); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #3c3c3c, #111); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #3c3c3c, #111); /* IE10 */
+ background-image: -o-linear-gradient(top, #3c3c3c, #111); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #3c3c3c, #111);
+}
+.ui-bar-a,
+.ui-bar-a input,
+.ui-bar-a select,
+.ui-bar-a textarea,
+.ui-bar-a button {
+ font-family: Helvetica, Arial, sans-serif;
+}
+.ui-bar-a .ui-link-inherit {
+ color: #fff;
+}
+.ui-bar-a .ui-link {
+ color: #7cc4e7;
+ font-weight: bold;
+}
+.ui-body-a {
+ border: 1px solid #2A2A2A;
+ background: #222222;
+ color: #fff;
+ text-shadow: 0 1px 0 #000;
+ font-weight: normal;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#666), to(#222)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #666, #222); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #666, #222); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #666, #222); /* IE10 */
+ background-image: -o-linear-gradient(top, #666, #222); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #666, #222);
+}
+.ui-body-a,
+.ui-body-a input,
+.ui-body-a select,
+.ui-body-a textarea,
+.ui-body-a button {
+ font-family: Helvetica, Arial, sans-serif;
+}
+.ui-body-a .ui-link-inherit {
+ color: #fff;
+}
+.ui-body-a .ui-link {
+ color: #2489CE;
+ font-weight: bold;
+}
+.ui-br {
+ border-bottom: rgb(130,130,130);
+ border-bottom: rgba(130,130,130,.3);
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+}
+.ui-btn-up-a {
+ border: 1px solid #222;
+ background: #333333;
+ font-weight: bold;
+ color: #fff;
+ text-shadow: 0 -1px 1px #000;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#555), to(#333)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #555, #333); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #555, #333); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #555, #333); /* IE10 */
+ background-image: -o-linear-gradient(top, #555, #333); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #555, #333);
+}
+.ui-btn-up-a a.ui-link-inherit {
+ color: #fff;
+}
+.ui-btn-hover-a {
+ border: 1px solid #000;
+ background: #444444;
+ font-weight: bold;
+ color: #fff;
+ text-shadow: 0 -1px 1px #000;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#666), to(#444)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #666, #444); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #666, #444); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #666, #444); /* IE10 */
+ background-image: -o-linear-gradient(top, #666, #444); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #666, #444);
+}
+.ui-btn-hover-a a.ui-link-inherit {
+ color: #fff;
+}
+.ui-btn-down-a {
+ border: 1px solid #000;
+ background: #3d3d3d;
+ font-weight: bold;
+ color: #fff;
+ text-shadow: 0 -1px 1px #000;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#333), to(#5a5a5a)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #333, #5a5a5a); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #333, #5a5a5a); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #333, #5a5a5a); /* IE10 */
+ background-image: -o-linear-gradient(top, #333, #5a5a5a); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #333, #5a5a5a);
+}
+.ui-btn-down-a a.ui-link-inherit {
+ color: #fff;
+}
+.ui-btn-up-a,
+.ui-btn-hover-a,
+.ui-btn-down-a {
+ font-family: Helvetica, Arial, sans-serif;
+ text-decoration: none;
+}
+
+
+/* B
+-----------------------------------------------------------------------------------------------------------*/
+
+.ui-bar-b {
+ border: 1px solid #456f9a;
+ background: #5e87b0;
+ color: #fff;
+ font-weight: bold;
+ text-shadow: 0 -1px 1px #254f7a;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#81a8ce), to(#5e87b0)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #81a8ce, #5e87b0); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #81a8ce, #5e87b0); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #81a8ce, #5e87b0); /* IE10 */
+ background-image: -o-linear-gradient(top, #81a8ce, #5e87b0); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #81a8ce, #5e87b0);
+}
+.ui-bar-b,
+.ui-bar-b input,
+.ui-bar-b select,
+.ui-bar-b textarea,
+.ui-bar-b button {
+ font-family: Helvetica, Arial, sans-serif;
+}
+.ui-bar-b .ui-link-inherit {
+ color: #fff;
+}
+.ui-bar-b .ui-link {
+ color: #7cc4e7;
+ font-weight: bold;
+}
+
+.ui-body-b {
+ border: 1px solid #C6C6C6;
+ background: #cccccc;
+ color: #333333;
+ text-shadow: 0 1px 0 #fff;
+ font-weight: normal;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#e6e6e6), to(#ccc)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #e6e6e6, #ccc); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #e6e6e6, #ccc); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #e6e6e6, #ccc); /* IE10 */
+ background-image: -o-linear-gradient(top, #e6e6e6, #ccc); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #e6e6e6, #ccc);
+}
+.ui-body-b,
+.ui-body-b input,
+.ui-body-b select,
+.ui-body-b textarea,
+.ui-body-b button {
+ font-family: Helvetica, Arial, sans-serif;
+}
+.ui-body-b .ui-link-inherit {
+ color: #333333;
+}
+.ui-body-b .ui-link {
+ color: #2489CE;
+ font-weight: bold;
+}
+.ui-btn-up-b {
+ border: 1px solid #145072;
+ background: #2567ab;
+ font-weight: bold;
+ color: #fff;
+ text-shadow: 0 -1px 1px #145072;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#5f9cc5), to(#396b9e)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #5f9cc5, #396b9e); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #5f9cc5, #396b9e); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #5f9cc5, #396b9e); /* IE10 */
+ background-image: -o-linear-gradient(top, #5f9cc5, #396b9e); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #5f9cc5, #396b9e);
+}
+.ui-btn-up-b a.ui-link-inherit {
+ color: #fff;
+}
+.ui-btn-hover-b {
+ border: 1px solid #00516e;
+ background: #4b88b6;
+ font-weight: bold;
+ color: #fff;
+ text-shadow: 0 -1px 1px #014D68;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#72b0d4), to(#4b88b6)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #72b0d4, #4b88b6); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #72b0d4, #4b88b6); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #72b0d4, #4b88b6); /* IE10 */
+ background-image: -o-linear-gradient(top, #72b0d4, #4b88b6); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #72b0d4, #4b88b6);
+}
+.ui-btn-hover-b a.ui-link-inherit {
+ color: #fff;
+}
+.ui-btn-down-b {
+ border: 1px solid #225377;
+ background: #4e89c5;
+ font-weight: bold;
+ color: #fff;
+ text-shadow: 0 -1px 1px #225377;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#396b9e), to(#4e89c5)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #396b9e, #4e89c5); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #396b9e, #4e89c5); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #396b9e, #4e89c5); /* IE10 */
+ background-image: -o-linear-gradient(top, #396b9e, #4e89c5); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #396b9e, #4e89c5);
+}
+.ui-btn-down-b a.ui-link-inherit {
+ color: #fff;
+}
+.ui-btn-up-b,
+.ui-btn-hover-b,
+.ui-btn-down-b {
+ font-family: Helvetica, Arial, sans-serif;
+ text-decoration: none;
+}
+
+
+/* C
+-----------------------------------------------------------------------------------------------------------*/
+
+.ui-bar-c {
+ border: 1px solid #B3B3B3;
+ background: #e9eaeb;
+ color: #3E3E3E;
+ font-weight: bold;
+ text-shadow: 0 1px 1px #fff;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f0f0f0), to(#e9eaeb)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #f0f0f0, #e9eaeb); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #f0f0f0, #e9eaeb); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #f0f0f0, #e9eaeb); /* IE10 */
+ background-image: -o-linear-gradient(top, #f0f0f0, #e9eaeb); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #f0f0f0, #e9eaeb);
+}
+.ui-bar-c,
+.ui-bar-c input,
+.ui-bar-c select,
+.ui-bar-c textarea,
+.ui-bar-c button {
+ font-family: Helvetica, Arial, sans-serif;
+}
+.ui-body-c {
+ border: 1px solid #B3B3B3;
+ color: #333333;
+ text-shadow: 0 1px 0 #fff;
+ background: #f0f0f0;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#ddd)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #eee, #ddd); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #eee, #ddd); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #eee, #ddd); /* IE10 */
+ background-image: -o-linear-gradient(top, #eee, #ddd); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #eee, #ddd);
+}
+.ui-body-c,
+.ui-body-c input,
+.ui-body-c select,
+.ui-body-c textarea,
+.ui-body-c button {
+ font-family: Helvetica, Arial, sans-serif;
+}
+.ui-body-c .ui-link-inherit {
+ color: #333333;
+}
+.ui-body-c .ui-link {
+ color: #2489CE;
+ font-weight: bold;
+}
+
+.ui-btn-up-c {
+ border: 1px solid #ccc;
+ background: #eee;
+ font-weight: bold;
+ color: #444;
+ text-shadow: 0 1px 1px #f6f6f6;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fdfdfd), to(#eee)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #fdfdfd, #eee); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #fdfdfd, #eee); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #fdfdfd, #eee); /* IE10 */
+ background-image: -o-linear-gradient(top, #fdfdfd, #eee); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #fdfdfd, #eee);
+}
+.ui-btn-up-c a.ui-link-inherit {
+ color: #2F3E46;
+}
+
+.ui-btn-hover-c {
+ border: 1px solid #bbb;
+ background: #dadada;
+ font-weight: bold;
+ color: #101010;
+ text-shadow: 0 1px 1px #fff;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#ededed), to(#dadada)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #ededed, #dadada); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #ededed, #dadada); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #ededed, #dadada); /* IE10 */
+ background-image: -o-linear-gradient(top, #ededed, #dadada); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #ededed, #dadada);
+}
+.ui-btn-hover-c a.ui-link-inherit {
+ color: #2F3E46;
+}
+.ui-btn-down-c {
+ border: 1px solid #808080;
+ background: #fdfdfd;
+ font-weight: bold;
+ color: #111111;
+ text-shadow: 0 1px 1px #ffffff;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#fdfdfd)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #eee, #fdfdfd); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #eee, #fdfdfd); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #eee, #fdfdfd); /* IE10 */
+ background-image: -o-linear-gradient(top, #eee, #fdfdfd); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #eee, #fdfdfd);
+}
+.ui-btn-down-c a.ui-link-inherit {
+ color: #2F3E46;
+}
+.ui-btn-up-c,
+.ui-btn-hover-c,
+.ui-btn-down-c {
+ font-family: Helvetica, Arial, sans-serif;
+ text-decoration: none;
+}
+
+
+/* D
+-----------------------------------------------------------------------------------------------------------*/
+
+.ui-bar-d {
+ border: 1px solid #ccc;
+ background: #bbb;
+ color: #333;
+ text-shadow: 0 1px 0 #eee;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#ddd), to(#bbb)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #ddd, #bbb); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #ddd, #bbb); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #ddd, #bbb); /* IE10 */
+ background-image: -o-linear-gradient(top, #ddd, #bbb); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #ddd, #bbb);
+}
+.ui-bar-d,
+.ui-bar-d input,
+.ui-bar-d select,
+.ui-bar-d textarea,
+.ui-bar-d button {
+ font-family: Helvetica, Arial, sans-serif;
+}
+.ui-bar-d .ui-link-inherit {
+ color: #333;
+}
+.ui-bar-d .ui-link {
+ color: #2489CE;
+ font-weight: bold;
+}
+.ui-body-d {
+ border: 1px solid #ccc;
+ color: #333333;
+ text-shadow: 0 1px 0 #fff;
+ background: #ffffff;
+}
+.ui-body-d,
+.ui-body-d input,
+.ui-body-d select,
+.ui-body-d textarea,
+.ui-body-d button {
+ font-family: Helvetica, Arial, sans-serif;
+}
+.ui-body-d .ui-link-inherit {
+ color: #333333;
+}
+.ui-body-d .ui-link {
+ color: #2489CE;
+ font-weight: bold;
+}
+.ui-btn-up-d {
+ border: 1px solid #ccc;
+ background: #fff;
+ font-weight: bold;
+ color: #444;
+ text-shadow: 0 1px 1px #fff;
+}
+.ui-btn-up-d a.ui-link-inherit {
+ color: #333;
+}
+.ui-btn-hover-d {
+ border: 1px solid #aaa;
+ background: #eeeeee;
+ font-weight: bold;
+ color: #222;
+ cursor: pointer;
+ text-shadow: 0 1px 1px #fff;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fdfdfd), to(#eee)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #fdfdfd, #eee); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #fdfdfd, #eee); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #fdfdfd, #eee); /* IE10 */
+ background-image: -o-linear-gradient(top, #fdfdfd, #eee); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #fdfdfd, #eee);
+}
+.ui-btn-hover-d a.ui-link-inherit {
+ color: #222;
+}
+.ui-btn-down-d {
+ border: 1px solid #aaaaaa;
+ background: #ffffff;
+ font-weight: bold;
+ color: #111;
+ text-shadow: 0 1px 1px #ffffff;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#fff)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #eee, #fff); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #eee, #fff); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #eee, #fff); /* IE10 */
+ background-image: -o-linear-gradient(top, #eee, #fff); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #eee, #fff);
+}
+.ui-btn-down-d a.ui-link-inherit {
+ color: #111;
+}
+.ui-btn-up-d,
+.ui-btn-hover-d,
+.ui-btn-down-d {
+ font-family: Helvetica, Arial, sans-serif;
+ text-decoration: none;
+}
+
+
+/* E
+-----------------------------------------------------------------------------------------------------------*/
+
+.ui-bar-e {
+ border: 1px solid #F7C942;
+ background: #fadb4e;
+ color: #333;
+ text-shadow: 0 1px 0 #fff;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fceda7), to(#fadb4e)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #fceda7, #fadb4e); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #fceda7, #fadb4e); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #fceda7, #fadb4e); /* IE10 */
+ background-image: -o-linear-gradient(top, #fceda7, #fadb4e); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #fceda7, #fadb4e);
+}
+.ui-bar-e,
+.ui-bar-e input,
+.ui-bar-e select,
+.ui-bar-e textarea,
+.ui-bar-e button {
+ font-family: Helvetica, Arial, sans-serif;
+}
+.ui-bar-e .ui-link-inherit {
+ color: #333;
+}
+.ui-bar-e .ui-link {
+ color: #2489CE;
+ font-weight: bold;
+}
+.ui-body-e {
+ border: 1px solid #F7C942;
+ color: #333333;
+ text-shadow: 0 1px 0 #fff;
+ background: #faeb9e;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#faeb9e)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #fff, #faeb9e); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #fff, #faeb9e); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #fff, #faeb9e); /* IE10 */
+ background-image: -o-linear-gradient(top, #fff, #faeb9e); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #fff, #faeb9e);
+}
+.ui-body-e,
+.ui-body-e input,
+.ui-body-e select,
+.ui-body-e textarea,
+.ui-body-e button {
+ font-family: Helvetica, Arial, sans-serif;
+}
+.ui-body-e .ui-link-inherit {
+ color: #333333;
+}
+.ui-body-e .ui-link {
+ color: #2489CE;
+ font-weight: bold;
+}
+.ui-btn-up-e {
+ border: 1px solid #F7C942;
+ background: #fadb4e;
+ font-weight: bold;
+ color: #333;
+ text-shadow: 0 1px 0 #fff;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fceda7), to(#fadb4e)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #fceda7, #fadb4e); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #fceda7, #fadb4e); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #fceda7, #fadb4e); /* IE10 */
+ background-image: -o-linear-gradient(top, #fceda7, #fadb4e); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #fceda7, #fadb4e);
+}
+.ui-btn-up-e a.ui-link-inherit {
+ color: #333;
+}
+.ui-btn-hover-e {
+ border: 1px solid #e79952;
+ background: #fbe26f;
+ font-weight: bold;
+ color: #111;
+ text-shadow: 0 1px 1px #fff;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf0b5), to(#fbe26f)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #fcf0b5, #fbe26f); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #fcf0b5, #fbe26f); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #fcf0b5, #fbe26f); /* IE10 */
+ background-image: -o-linear-gradient(top, #fcf0b5, #fbe26f); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #fcf0b5, #fbe26f);
+}
+
+.ui-btn-hover-e a.ui-link-inherit {
+ color: #333;
+}
+.ui-btn-down-e {
+ border: 1px solid #F7C942;
+ background: #fceda7;
+ font-weight: bold;
+ color: #111;
+ text-shadow: 0 1px 1px #ffffff;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fadb4e), to(#fceda7)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #fadb4e, #fceda7); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #fadb4e, #fceda7); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #fadb4e, #fceda7); /* IE10 */
+ background-image: -o-linear-gradient(top, #fadb4e, #fceda7); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #fadb4e, #fceda7);
+}
+.ui-btn-down-e a.ui-link-inherit {
+ color: #333;
+}
+.ui-btn-up-e,
+.ui-btn-hover-e,
+.ui-btn-down-e {
+ font-family: Helvetica, Arial, sans-serif;
+ text-decoration: none;
+}
+
+
+/* links within "buttons"
+-----------------------------------------------------------------------------------------------------------*/
+
+a.ui-link-inherit {
+ text-decoration: none !important;
+}
+
+
+/* Active class used as the "on" state across all themes
+-----------------------------------------------------------------------------------------------------------*/
+
+.ui-btn-active {
+ border: 1px solid #155678;
+ background: #4596ce;
+ font-weight: bold;
+ color: #fff;
+ cursor: pointer;
+ text-shadow: 0 -1px 1px #145072;
+ text-decoration: none;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#85bae4), to(#5393c5)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient(top, #85bae4, #5393c5); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient(top, #85bae4, #5393c5); /* FF3.6 */
+ background-image: -ms-linear-gradient(top, #85bae4, #5393c5); /* IE10 */
+ background-image: -o-linear-gradient(top, #85bae4, #5393c5); /* Opera 11.10+ */
+ background-image: linear-gradient(top, #85bae4, #5393c5);
+ outline: none;
+}
+.ui-btn-active a.ui-link-inherit {
+ color: #fff;
+}
+
+
+/* button inner top highlight
+-----------------------------------------------------------------------------------------------------------*/
+
+.ui-btn-inner {
+ border-top: 1px solid #fff;
+ border-color: rgba(255,255,255,.3);
+}
+
+
+/* corner rounding classes
+-----------------------------------------------------------------------------------------------------------*/
+
+.ui-corner-tl {
+ -moz-border-radius-topleft: .6em;
+ -webkit-border-top-left-radius: .6em;
+ border-top-left-radius: .6em;
+}
+.ui-corner-tr {
+ -moz-border-radius-topright: .6em;
+ -webkit-border-top-right-radius: .6em;
+ border-top-right-radius: .6em;
+}
+.ui-corner-bl {
+ -moz-border-radius-bottomleft: .6em;
+ -webkit-border-bottom-left-radius: .6em;
+ border-bottom-left-radius: .6em;
+}
+.ui-corner-br {
+ -moz-border-radius-bottomright: .6em;
+ -webkit-border-bottom-right-radius: .6em;
+ border-bottom-right-radius: .6em;
+}
+.ui-corner-top {
+ -moz-border-radius-topleft: .6em;
+ -webkit-border-top-left-radius: .6em;
+ border-top-left-radius: .6em;
+ -moz-border-radius-topright: .6em;
+ -webkit-border-top-right-radius: .6em;
+ border-top-right-radius: .6em;
+}
+.ui-corner-bottom {
+ -moz-border-radius-bottomleft: .6em;
+ -webkit-border-bottom-left-radius: .6em;
+ border-bottom-left-radius: .6em;
+ -moz-border-radius-bottomright: .6em;
+ -webkit-border-bottom-right-radius: .6em;
+ border-bottom-right-radius: .6em;
+ }
+.ui-corner-right {
+ -moz-border-radius-topright: .6em;
+ -webkit-border-top-right-radius: .6em;
+ border-top-right-radius: .6em;
+ -moz-border-radius-bottomright: .6em;
+ -webkit-border-bottom-right-radius: .6em;
+ border-bottom-right-radius: .6em;
+}
+.ui-corner-left {
+ -moz-border-radius-topleft: .6em;
+ -webkit-border-top-left-radius: .6em;
+ border-top-left-radius: .6em;
+ -moz-border-radius-bottomleft: .6em;
+ -webkit-border-bottom-left-radius: .6em;
+ border-bottom-left-radius: .6em;
+}
+.ui-corner-all {
+ -moz-border-radius: .6em;
+ -webkit-border-radius: .6em;
+ border-radius: .6em;
+}
+.ui-corner-none {
+ -moz-border-radius: 0;
+ -webkit-border-radius: 0;
+ border-radius: 0;
+}
+
+/* Interaction cues
+-----------------------------------------------------------------------------------------------------------*/
+.ui-disabled {
+ opacity: .3;
+}
+.ui-disabled,
+.ui-disabled a {
+ cursor: default;
+}
+
+/* Icons
+-----------------------------------------------------------------------------------------------------------*/
+
+.ui-icon {
+ background: #666;
+ background: rgba(0,0,0,.4);
+ background-image: url(images/icons-18-white.png);
+ background-repeat: no-repeat;
+ -moz-border-radius: 9px;
+ -webkit-border-radius: 9px;
+ border-radius: 9px;
+}
+
+
+/* Alt icon color
+-----------------------------------------------------------------------------------------------------------*/
+
+.ui-icon-alt {
+ background: #fff;
+ background: rgba(255,255,255,.3);
+ background-image: url(images/icons-18-black.png);
+ background-repeat: no-repeat;
+}
+
+/* HD/"retina" sprite
+-----------------------------------------------------------------------------------------------------------*/
+
+@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
+ only screen and (min--moz-device-pixel-ratio: 1.5),
+ only screen and (min-resolution: 240dpi) {
+
+ .ui-icon-plus, .ui-icon-minus, .ui-icon-delete, .ui-icon-arrow-r,
+ .ui-icon-arrow-l, .ui-icon-arrow-u, .ui-icon-arrow-d, .ui-icon-check,
+ .ui-icon-gear, .ui-icon-refresh, .ui-icon-forward, .ui-icon-back,
+ .ui-icon-grid, .ui-icon-star, .ui-icon-alert, .ui-icon-info, .ui-icon-home, .ui-icon-search,
+ .ui-icon-checkbox-off, .ui-icon-checkbox-on, .ui-icon-radio-off, .ui-icon-radio-on {
+ background-image: url(images/icons-36-white.png);
+ -moz-background-size: 776px 18px;
+ -o-background-size: 776px 18px;
+ -webkit-background-size: 776px 18px;
+ background-size: 776px 18px;
+ }
+ .ui-icon-alt {
+ background-image: url(images/icons-36-black.png);
+ }
+}
+
+/* plus minus */
+.ui-icon-plus {
+ background-position: -0 50%;
+}
+.ui-icon-minus {
+ background-position: -36px 50%;
+}
+
+/* delete/close */
+.ui-icon-delete {
+ background-position: -72px 50%;
+}
+
+/* arrows */
+.ui-icon-arrow-r {
+ background-position: -108px 50%;
+}
+.ui-icon-arrow-l {
+ background-position: -144px 50%;
+}
+.ui-icon-arrow-u {
+ background-position: -180px 50%;
+}
+.ui-icon-arrow-d {
+ background-position: -216px 50%;
+}
+
+/* misc */
+.ui-icon-check {
+ background-position: -252px 50%;
+}
+.ui-icon-gear {
+ background-position: -288px 50%;
+}
+.ui-icon-refresh {
+ background-position: -324px 50%;
+}
+.ui-icon-forward {
+ background-position: -360px 50%;
+}
+.ui-icon-back {
+ background-position: -396px 50%;
+}
+.ui-icon-grid {
+ background-position: -432px 50%;
+}
+.ui-icon-star {
+ background-position: -468px 50%;
+}
+.ui-icon-alert {
+ background-position: -504px 50%;
+}
+.ui-icon-info {
+ background-position: -540px 50%;
+}
+.ui-icon-home {
+ background-position: -576px 50%;
+}
+.ui-icon-search {
+ background-position: -612px 50%;
+}
+.ui-icon-checkbox-off {
+ background-position: -684px 50%;
+}
+.ui-icon-checkbox-on {
+ background-position: -648px 50%;
+}
+.ui-icon-radio-off {
+ background-position: -756px 50%;
+}
+.ui-icon-radio-on {
+ background-position: -720px 50%;
+}
+
+
+/* checks,radios */
+.ui-checkbox .ui-icon {
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+}
+.ui-icon-checkbox-off,
+.ui-icon-radio-off {
+ background-color: transparent;
+}
+.ui-icon-checkbox-on,
+.ui-checkbox-on .ui-icon,
+.ui-radio-on .ui-icon {
+ background-color: #4596ce; /* NOTE: this hex should match the active state color. It's repeated here for cascade */
+}
+.ui-icon-searchfield {
+ background-image: url(images/icon-search-black.png);
+ background-size: 16px 16px;
+}
+
+/* loading icon */
+.ui-icon-loading {
+ background-image: url(images/ajax-loader.png);
+ width: 40px;
+ height: 40px;
+ -moz-border-radius: 20px;
+ -webkit-border-radius: 20px;
+ border-radius: 20px;
+ background-size: 35px 35px;
+}
+
+
+/* Button corner classes
+-----------------------------------------------------------------------------------------------------------*/
+
+.ui-btn-corner-tl {
+ -moz-border-radius-topleft: 1em;
+ -webkit-border-top-left-radius: 1em;
+ border-top-left-radius: 1em;
+}
+.ui-btn-corner-tr {
+ -moz-border-radius-topright: 1em;
+ -webkit-border-top-right-radius: 1em;
+ border-top-right-radius: 1em;
+}
+.ui-btn-corner-bl {
+ -moz-border-radius-bottomleft: 1em;
+ -webkit-border-bottom-left-radius: 1em;
+ border-bottom-left-radius: 1em;
+}
+.ui-btn-corner-br {
+ -moz-border-radius-bottomright: 1em;
+ -webkit-border-bottom-right-radius: 1em;
+ border-bottom-right-radius: 1em;
+}
+.ui-btn-corner-top {
+ -moz-border-radius-topleft: 1em;
+ -webkit-border-top-left-radius: 1em;
+ border-top-left-radius: 1em;
+ -moz-border-radius-topright: 1em;
+ -webkit-border-top-right-radius: 1em;
+ border-top-right-radius: 1em;
+}
+.ui-btn-corner-bottom {
+ -moz-border-radius-bottomleft: 1em;
+ -webkit-border-bottom-left-radius: 1em;
+ border-bottom-left-radius: 1em;
+ -moz-border-radius-bottomright: 1em;
+ -webkit-border-bottom-right-radius: 1em;
+ border-bottom-right-radius: 1em;
+}
+.ui-btn-corner-right {
+ -moz-border-radius-topright: 1em;
+ -webkit-border-top-right-radius: 1em;
+ border-top-right-radius: 1em;
+ -moz-border-radius-bottomright: 1em;
+ -webkit-border-bottom-right-radius: 1em;
+ border-bottom-right-radius: 1em;
+}
+.ui-btn-corner-left {
+ -moz-border-radius-topleft: 1em;
+ -webkit-border-top-left-radius: 1em;
+ border-top-left-radius: 1em;
+ -moz-border-radius-bottomleft: 1em;
+ -webkit-border-bottom-left-radius: 1em;
+ border-bottom-left-radius: 1em;
+}
+.ui-btn-corner-all {
+ -moz-border-radius: 1em;
+ -webkit-border-radius: 1em;
+ border-radius: 1em;
+}
+
+/* radius clip workaround for cleaning up corner trapping */
+.ui-corner-tl,
+.ui-corner-tr,
+.ui-corner-bl,
+.ui-corner-br,
+.ui-corner-top,
+.ui-corner-bottom,
+.ui-corner-right,
+.ui-corner-left,
+.ui-corner-all,
+.ui-btn-corner-tl,
+.ui-btn-corner-tr,
+.ui-btn-corner-bl,
+.ui-btn-corner-br,
+.ui-btn-corner-top,
+.ui-btn-corner-bottom,
+.ui-btn-corner-right,
+.ui-btn-corner-left,
+.ui-btn-corner-all {
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding;
+ background-clip: padding-box;
+}
+
+/* Overlay / modal
+-----------------------------------------------------------------------------------------------------------*/
+
+.ui-overlay {
+ background: #666;
+ opacity: .5;
+ filter: Alpha(Opacity=50);
+ position: absolute;
+ width: 100%;
+ height: 100%;
+}
+.ui-overlay-shadow {
+ -moz-box-shadow: 0px 0px 12px rgba(0,0,0,.6);
+ -webkit-box-shadow: 0px 0px 12px rgba(0,0,0,.6);
+ box-shadow: 0px 0px 12px rgba(0,0,0,.6);
+}
+.ui-shadow {
+ -moz-box-shadow: 0px 1px 4px rgba(0,0,0,.3);
+ -webkit-box-shadow: 0px 1px 4px rgba(0,0,0,.3);
+ box-shadow: 0px 1px 4px rgba(0,0,0,.3);
+}
+.ui-bar-a .ui-shadow,
+.ui-bar-b .ui-shadow ,
+.ui-bar-c .ui-shadow {
+ -moz-box-shadow: 0px 1px 0 rgba(255,255,255,.3);
+ -webkit-box-shadow: 0px 1px 0 rgba(255,255,255,.3);
+ box-shadow: 0px 1px 0 rgba(255,255,255,.3);
+}
+.ui-shadow-inset {
+ -moz-box-shadow: inset 0px 1px 4px rgba(0,0,0,.2);
+ -webkit-box-shadow: inset 0px 1px 4px rgba(0,0,0,.2);
+ box-shadow: inset 0px 1px 4px rgba(0,0,0,.2);
+}
+.ui-icon-shadow {
+ -moz-box-shadow: 0px 1px 0 rgba(255,255,255,.4);
+ -webkit-box-shadow: 0px 1px 0 rgba(255,255,255,.4);
+ box-shadow: 0px 1px 0 rgba(255,255,255,.4);
+}
+
+
+/* Focus state - set here for specificity
+-----------------------------------------------------------------------------------------------------------*/
+
+.ui-focus {
+ -moz-box-shadow: 0px 0px 12px #387bbe;
+ -webkit-box-shadow: 0px 0px 12px #387bbe;
+ box-shadow: 0px 0px 12px #387bbe;
+}
+
+/* unset box shadow in browsers that don't do it right
+-----------------------------------------------------------------------------------------------------------*/
+
+.ui-mobile-nosupport-boxshadow * {
+ -moz-box-shadow: none !important;
+ -webkit-box-shadow: none !important;
+ box-shadow: none !important;
+}
+
+/* ...and bring back focus */
+.ui-mobile-nosupport-boxshadow .ui-focus {
+ outline-width: 2px;
+}/*
+* jQuery Mobile Framework
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
+*/
+
+/* some unsets - more probably needed */
+.ui-mobile, .ui-mobile body { height: 100%; }
+.ui-mobile fieldset, .ui-page { padding: 0; margin: 0; }
+.ui-mobile a img, .ui-mobile fieldset { border: 0; }
+
+/* responsive page widths */
+.ui-mobile-viewport { margin: 0; overflow-x: hidden; -webkit-text-size-adjust: none; -ms-text-size-adjust:none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); }
+
+/* "page" containers - full-screen views, one should always be in view post-pageload */
+.ui-mobile [data-role=page], .ui-mobile [data-role=dialog], .ui-page { top: 0; left: 0; width: 100%; min-height: 100%; position: absolute; display: none; border: 0; }
+.ui-mobile .ui-page-active { display: block; overflow: visible; }
+
+/*orientations from js are available */
+.portrait,
+.portrait .ui-page { min-height: 420px; }
+.landscape,
+.landscape .ui-page { min-height: 300px; }
+
+/* native overflow scrolling */
+.ui-page.ui-mobile-touch-overflow,
+.ui-mobile-touch-overflow.ui-native-fixed .ui-content {
+ overflow: auto;
+ height: 100%;
+ -webkit-overflow-scrolling: touch;
+ -moz-overflow-scrolling: touch;
+ -o-overflow-scrolling: touch;
+ -ms-overflow-scrolling: touch;
+ overflow-scrolling: touch;
+}
+.ui-page.ui-mobile-pre-transition {
+ display: block;
+}
+
+/* loading screen */
+.ui-loading .ui-mobile-viewport { overflow: hidden !important; }
+.ui-loading .ui-loader { display: block; }
+.ui-loading .ui-page { overflow: hidden; }
+.ui-loader { display: none; position: absolute; opacity: .85; z-index: 100; left: 50%; width: 200px; margin-left: -130px; margin-top: -35px; padding: 10px 30px; }
+.ui-loader h1 { font-size: 15px; text-align: center; }
+.ui-loader .ui-icon { position: static; display: block; opacity: .9; margin: 0 auto; width: 35px; height: 35px; background-color: transparent; }
+
+/*fouc*/
+.ui-mobile-rendering > * { visibility: hidden; }
+
+/*headers, content panels*/
+.ui-bar, .ui-body { position: relative; padding: .4em 15px; overflow: hidden; display: block; clear:both; }
+.ui-bar { font-size: 16px; margin: 0; }
+.ui-bar h1, .ui-bar h2, .ui-bar h3, .ui-bar h4, .ui-bar h5, .ui-bar h6 { margin: 0; padding: 0; font-size: 16px; display: inline-block; }
+
+.ui-header, .ui-footer { display: block; }
+.ui-page .ui-header, .ui-page .ui-footer { position: relative; }
+.ui-header .ui-btn-left { position: absolute; left: 10px; top: .4em; }
+.ui-header .ui-btn-right { position: absolute; right: 10px; top: .4em; }
+.ui-header .ui-title, .ui-footer .ui-title { min-height: 1.1em; text-align: center; font-size: 16px; display: block; margin: .6em 90px .8em; padding: 0; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; outline: 0 !important; }
+
+/*content area*/
+.ui-content { border-width: 0; overflow: visible; overflow-x: hidden; padding: 15px; }
+.ui-page-fullscreen .ui-content { padding:0; }
+
+/* native fixed headers and footers */
+.ui-mobile-touch-overflow.ui-page.ui-native-fixed,
+.ui-mobile-touch-overflow.ui-page.ui-native-fullscreen {
+ overflow: visible;
+}
+.ui-mobile-touch-overflow.ui-native-fixed .ui-header,
+.ui-mobile-touch-overflow.ui-native-fixed .ui-footer {
+ position: fixed;
+ left: 0;
+ right: 0;
+ top: 0;
+ z-index: 200;
+}
+.ui-mobile-touch-overflow.ui-page.ui-native-fixed .ui-footer {
+ top: auto;
+ bottom: 0;
+}
+.ui-mobile-touch-overflow.ui-native-fixed .ui-content {
+ padding-top: 2.5em;
+ padding-bottom: 3em;
+ top: 0;
+ bottom: 0;
+ height: auto;
+ position: absolute;
+}
+.ui-mobile-touch-overflow.ui-native-fullscreen .ui-content {
+ padding-top: 0;
+ padding-bottom: 0;
+}
+.ui-mobile-touch-overflow.ui-native-fullscreen .ui-header,
+.ui-mobile-touch-overflow.ui-native-fullscreen .ui-footer {
+ opacity: .9;
+}
+.ui-native-bars-hidden {
+ display: none;
+}
+
+/* icons sizing */
+.ui-icon { width: 18px; height: 18px; }
+
+/* fullscreen class on ui-content div */
+.ui-fullscreen { }
+.ui-fullscreen img { max-width: 100%; }
+
+/* non-js content hiding */
+.ui-nojs { position: absolute; left: -9999px; }
+/*
+* jQuery Mobile Framework
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
+*/
+.spin {
+ -webkit-transform: rotate(360deg);
+ -webkit-animation-name: spin;
+ -webkit-animation-duration: 1s;
+ -webkit-animation-iteration-count: infinite;
+ -webkit-animation-timing-function: linear;
+}
+@-webkit-keyframes spin {
+ from {-webkit-transform: rotate(0deg);}
+ to {-webkit-transform: rotate(360deg);}
+}
+
+/* Transitions from jQtouch (with small modifications): http://www.jqtouch.com/
+Built by David Kaneda and maintained by Jonathan Stark.
+*/
+.in, .out {
+ -webkit-animation-timing-function: ease-in-out;
+ -webkit-animation-duration: 350ms;
+}
+
+.slide.in {
+ -webkit-transform: translateX(0);
+ -webkit-animation-name: slideinfromright;
+}
+
+.slide.out {
+ -webkit-transform: translateX(-100%);
+ -webkit-animation-name: slideouttoleft;
+}
+
+.slide.in.reverse {
+ -webkit-transform: translateX(0);
+ -webkit-animation-name: slideinfromleft;
+}
+
+.slide.out.reverse {
+ -webkit-transform: translateX(100%);
+ -webkit-animation-name: slideouttoright;
+}
+
+.slideup.in {
+ -webkit-transform: translateY(0);
+ -webkit-animation-name: slideinfrombottom;
+ z-index: 10;
+}
+
+.slideup.out {
+ -webkit-animation-name: dontmove;
+ z-index: 0;
+}
+
+.slideup.out.reverse {
+ -webkit-transform: translateY(100%);
+ z-index: 10;
+ -webkit-animation-name: slideouttobottom;
+}
+
+.slideup.in.reverse {
+ z-index: 0;
+ -webkit-animation-name: dontmove;
+}
+.slidedown.in {
+ -webkit-transform: translateY(0);
+ -webkit-animation-name: slideinfromtop;
+ z-index: 10;
+}
+
+.slidedown.out {
+ -webkit-animation-name: dontmove;
+ z-index: 0;
+}
+
+.slidedown.out.reverse {
+ -webkit-transform: translateY(-100%);
+ z-index: 10;
+ -webkit-animation-name: slideouttotop;
+}
+
+.slidedown.in.reverse {
+ z-index: 0;
+ -webkit-animation-name: dontmove;
+}
+
+@-webkit-keyframes slideinfromright {
+ from { -webkit-transform: translateX(100%); }
+ to { -webkit-transform: translateX(0); }
+}
+
+@-webkit-keyframes slideinfromleft {
+ from { -webkit-transform: translateX(-100%); }
+ to { -webkit-transform: translateX(0); }
+}
+
+@-webkit-keyframes slideouttoleft {
+ from { -webkit-transform: translateX(0); }
+ to { -webkit-transform: translateX(-100%); }
+}
+
+@-webkit-keyframes slideouttoright {
+ from { -webkit-transform: translateX(0); }
+ to { -webkit-transform: translateX(100%); }
+}
+
+
+@-webkit-keyframes slideinfromtop {
+ from { -webkit-transform: translateY(-100%); }
+ to { -webkit-transform: translateY(0); }
+}
+
+@-webkit-keyframes slideinfrombottom {
+ from { -webkit-transform: translateY(100%); }
+ to { -webkit-transform: translateY(0); }
+}
+
+@-webkit-keyframes slideouttobottom {
+ from { -webkit-transform: translateY(0); }
+ to { -webkit-transform: translateY(100%); }
+}
+
+@-webkit-keyframes slideouttotop {
+ from { -webkit-transform: translateY(0); }
+ to { -webkit-transform: translateY(-100%); }
+}
+@-webkit-keyframes fadein {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+
+@-webkit-keyframes fadeout {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+
+.fade.in {
+ opacity: 1;
+ z-index: 10;
+ -webkit-animation-name: fadein;
+}
+.fade.out {
+ z-index: 0;
+ -webkit-animation-name: fadeout;
+}
+
+/* The properties in this rule are only necessary for the 'flip' transition.
+ * We need specify the perspective to create a projection matrix. This will add
+ * some depth as the element flips. The depth number represents the distance of
+ * the viewer from the z-plane. According to the CSS3 spec, 1000 is a moderate
+ * value.
+ */
+.viewport-flip {
+ -webkit-perspective: 1000;
+ position: absolute;
+}
+
+.ui-mobile-viewport-transitioning,
+.ui-mobile-viewport-transitioning .ui-page {
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+}
+
+.flip {
+ -webkit-animation-duration: .65s;
+ -webkit-backface-visibility:hidden;
+ -webkit-transform:translateX(0); /* Needed to work around an iOS 3.1 bug that causes listview thumbs to disappear when -webkit-visibility:hidden is used. */
+}
+
+.flip.in {
+ -webkit-transform: rotateY(0) scale(1);
+ -webkit-animation-name: flipinfromleft;
+}
+
+.flip.out {
+ -webkit-transform: rotateY(-180deg) scale(.8);
+ -webkit-animation-name: flipouttoleft;
+}
+
+/* Shake it all about */
+
+.flip.in.reverse {
+ -webkit-transform: rotateY(0) scale(1);
+ -webkit-animation-name: flipinfromright;
+}
+
+.flip.out.reverse {
+ -webkit-transform: rotateY(180deg) scale(.8);
+ -webkit-animation-name: flipouttoright;
+}
+
+@-webkit-keyframes flipinfromright {
+ from { -webkit-transform: rotateY(-180deg) scale(.8); }
+ to { -webkit-transform: rotateY(0) scale(1); }
+}
+
+@-webkit-keyframes flipinfromleft {
+ from { -webkit-transform: rotateY(180deg) scale(.8); }
+ to { -webkit-transform: rotateY(0) scale(1); }
+}
+
+@-webkit-keyframes flipouttoleft {
+ from { -webkit-transform: rotateY(0) scale(1); }
+ to { -webkit-transform: rotateY(-180deg) scale(.8); }
+}
+
+@-webkit-keyframes flipouttoright {
+ from { -webkit-transform: rotateY(0) scale(1); }
+ to { -webkit-transform: rotateY(180deg) scale(.8); }
+}
+
+
+/* Hackish, but reliable. */
+
+@-webkit-keyframes dontmove {
+ from { opacity: 1; }
+ to { opacity: 1; }
+}
+
+.pop {
+ -webkit-transform-origin: 50% 50%;
+}
+
+.pop.in {
+ -webkit-transform: scale(1);
+ opacity: 1;
+ -webkit-animation-name: popin;
+ z-index: 10;
+}
+
+.pop.out.reverse {
+ -webkit-transform: scale(.2);
+ opacity: 0;
+ -webkit-animation-name: popout;
+ z-index: 10;
+}
+
+.pop.in.reverse {
+ z-index: 0;
+ -webkit-animation-name: dontmove;
+}
+
+@-webkit-keyframes popin {
+ from {
+ -webkit-transform: scale(.2);
+ opacity: 0;
+ }
+ to {
+ -webkit-transform: scale(1);
+ opacity: 1;
+ }
+}
+
+@-webkit-keyframes popout {
+ from {
+ -webkit-transform: scale(1);
+ opacity: 1;
+ }
+ to {
+ -webkit-transform: scale(.2);
+ opacity: 0;
+ }
+}/*
+* jQuery Mobile Framework
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
+*/
+
+/* content configurations. */
+.ui-grid-a, .ui-grid-b, .ui-grid-c, .ui-grid-d { overflow: hidden; }
+.ui-block-a, .ui-block-b, .ui-block-c, .ui-block-d, .ui-block-e { margin: 0; padding: 0; border: 0; float: left; min-height:1px;}
+
+/* grid solo: 100 - single item fallback */
+.ui-grid-solo .ui-block-a { width: 100%; float: none; }
+
+/* grid a: 50/50 */
+.ui-grid-a .ui-block-a, .ui-grid-a .ui-block-b { width: 50%; }
+.ui-grid-a .ui-block-a { clear: left; }
+
+/* grid b: 33/33/33 */
+.ui-grid-b .ui-block-a, .ui-grid-b .ui-block-b, .ui-grid-b .ui-block-c { width: 33.333%; }
+.ui-grid-b .ui-block-a { clear: left; }
+
+/* grid c: 25/25/25/25 */
+.ui-grid-c .ui-block-a, .ui-grid-c .ui-block-b, .ui-grid-c .ui-block-c, .ui-grid-c .ui-block-d { width: 25%; }
+.ui-grid-c .ui-block-a { clear: left; }
+
+/* grid d: 20/20/20/20/20 */
+.ui-grid-d .ui-block-a, .ui-grid-d .ui-block-b, .ui-grid-d .ui-block-c, .ui-grid-d .ui-block-d, .ui-grid-d .ui-block-e { width: 20%; }
+.ui-grid-d .ui-block-a { clear: left; }
+/*
+* jQuery Mobile Framework
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
+*/
+/* fixed page header & footer configuration */
+.ui-header, .ui-footer, .ui-page-fullscreen .ui-header, .ui-page-fullscreen .ui-footer { position: absolute; overflow: hidden; width: 100%; border-left-width: 0; border-right-width: 0; }
+.ui-header-fixed, .ui-footer-fixed {
+ z-index: 1000;
+ -webkit-transform: translateZ(0); /* Force header/footer rendering to go through the same rendering pipeline as native page scrolling. */
+}
+.ui-footer-duplicate, .ui-page-fullscreen .ui-fixed-inline { display: none; }
+.ui-page-fullscreen .ui-header, .ui-page-fullscreen .ui-footer { opacity: .9; }
+/*
+* jQuery Mobile Framework
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
+*/
+.ui-navbar { overflow: hidden; }
+.ui-navbar ul, .ui-navbar-expanded ul { list-style:none; padding: 0; margin: 0; position: relative; display: block; border: 0;}
+.ui-navbar-collapsed ul { float: left; width: 75%; margin-right: -2px; }
+.ui-navbar-collapsed .ui-navbar-toggle { float: left; width: 25%; }
+.ui-navbar li.ui-navbar-truncate { position: absolute; left: -9999px; top: -9999px; }
+.ui-navbar li .ui-btn, .ui-navbar .ui-navbar-toggle .ui-btn { display: block; font-size: 12px; text-align: center; margin: 0; border-right-width: 0; }
+.ui-navbar li .ui-btn { margin-right: -1px; }
+.ui-navbar li .ui-btn:last-child { margin-right: 0; }
+.ui-header .ui-navbar li .ui-btn, .ui-header .ui-navbar .ui-navbar-toggle .ui-btn,
+.ui-footer .ui-navbar li .ui-btn, .ui-footer .ui-navbar .ui-navbar-toggle .ui-btn { border-top-width: 0; border-bottom-width: 0; }
+.ui-navbar .ui-btn-inner { padding-left: 2px; padding-right: 2px; }
+.ui-navbar-noicons li .ui-btn .ui-btn-inner, .ui-navbar-noicons .ui-navbar-toggle .ui-btn-inner { padding-top: .8em; padding-bottom: .9em; }
+/*expanded page styles*/
+.ui-navbar-expanded .ui-btn { margin: 0; font-size: 14px; }
+.ui-navbar-expanded .ui-btn-inner { padding-left: 5px; padding-right: 5px; }
+.ui-navbar-expanded .ui-btn-icon-top .ui-btn-inner { padding: 45px 5px 15px; text-align: center; }
+.ui-navbar-expanded .ui-btn-icon-top .ui-icon { top: 15px; }
+.ui-navbar-expanded .ui-btn-icon-bottom .ui-btn-inner { padding: 15px 5px 45px; text-align: center; }
+.ui-navbar-expanded .ui-btn-icon-bottom .ui-icon { bottom: 15px; }
+.ui-navbar-expanded li .ui-btn .ui-btn-inner { min-height: 2.5em; }
+.ui-navbar-expanded .ui-navbar-noicons .ui-btn .ui-btn-inner { padding-top: 1.8em; padding-bottom: 1.9em; }
+/*
+* jQuery Mobile Framework
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
+*/
+.ui-btn { display: block; text-align: center; cursor:pointer; position: relative; margin: .5em 5px; padding: 0; }
+.ui-btn:focus, .ui-btn:active { outline: none; }
+.ui-header .ui-btn, .ui-footer .ui-btn, .ui-bar .ui-btn { display: inline-block; font-size: 13px; margin: 0; }
+.ui-btn-inline { display: inline-block; }
+.ui-btn-inner { padding: .6em 25px; display: block; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; position: relative; zoom: 1; }
+.ui-header .ui-btn-inner, .ui-footer .ui-btn-inner, .ui-bar .ui-btn-inner { padding: .4em 8px .5em; }
+.ui-btn-icon-notext { display: inline-block; width: 20px; height: 20px; padding: 2px 1px 2px 3px; text-indent: -9999px; }
+.ui-btn-icon-notext .ui-btn-inner { padding: 0; }
+.ui-btn-icon-notext .ui-btn-text { position: absolute; left: -999px; }
+.ui-btn-icon-left .ui-btn-inner { padding-left: 33px; }
+.ui-header .ui-btn-icon-left .ui-btn-inner,
+.ui-footer .ui-btn-icon-left .ui-btn-inner,
+.ui-bar .ui-btn-icon-left .ui-btn-inner { padding-left: 27px; }
+.ui-btn-icon-right .ui-btn-inner { padding-right: 33px; }
+.ui-header .ui-btn-icon-right .ui-btn-inner,
+.ui-footer .ui-btn-icon-right .ui-btn-inner,
+.ui-bar .ui-btn-icon-right .ui-btn-inner { padding-right: 27px; }
+.ui-btn-icon-top .ui-btn-inner { padding-top: 33px; }
+.ui-header .ui-btn-icon-top .ui-btn-inner,
+.ui-footer .ui-btn-icon-top .ui-btn-inner,
+.ui-bar .ui-btn-icon-top .ui-btn-inner { padding-top: 27px; }
+.ui-btn-icon-bottom .ui-btn-inner { padding-bottom: 33px; }
+.ui-header .ui-btn-icon-bottom .ui-btn-inner,
+.ui-footer .ui-btn-icon-bottom .ui-btn-inner,
+.ui-bar .ui-btn-icon-bottom .ui-btn-inner { padding-bottom: 27px; }
+
+/*btn icon positioning*/
+.ui-btn-icon-notext .ui-icon { display: block; }
+.ui-btn-icon-left .ui-icon, .ui-btn-icon-right .ui-icon { position: absolute; top: 50%; margin-top: -9px; }
+.ui-btn-icon-top .ui-icon, .ui-btn-icon-bottom .ui-icon { position: absolute; left: 50%; margin-left: -9px; }
+.ui-btn-icon-left .ui-icon { left: 10px; }
+.ui-btn-icon-right .ui-icon {right: 10px; }
+.ui-header .ui-btn-icon-left .ui-icon,
+.ui-footer .ui-btn-icon-left .ui-icon,
+.ui-bar .ui-btn-icon-left .ui-icon { left: 4px; }
+.ui-header .ui-btn-icon-right .ui-icon,
+.ui-footer .ui-btn-icon-right .ui-icon,
+.ui-bar .ui-btn-icon-right .ui-icon { right: 4px; }
+.ui-header .ui-btn-icon-top .ui-icon,
+.ui-footer .ui-btn-icon-top .ui-icon,
+.ui-bar .ui-btn-icon-top .ui-icon { top: 4px; }
+.ui-header .ui-btn-icon-bottom .ui-icon,
+.ui-footer .ui-btn-icon-bottom .ui-icon,
+.ui-bar .ui-btn-icon-bottom .ui-icon { bottom: 4px; }
+.ui-btn-icon-top .ui-icon { top: 5px; }
+.ui-btn-icon-bottom .ui-icon { bottom: 5px; }
+/*hiding native button,inputs */
+.ui-btn-hidden { position: absolute; top: 0; left: 0; width: 100%; height: 100%; -webkit-appearance: button; opacity: 0; cursor: pointer; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter: alpha(opacity=0); background: transparent; }
+/*
+* jQuery Mobile Framework
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
+*/
+.ui-collapsible-contain { margin: .5em 0; }
+.ui-collapsible-heading { font-size: 16px; display: block; margin: 0 -8px; padding: 0; border-width: 0 0 1px 0; position: relative; }
+.ui-collapsible-heading a { text-align: left; margin: 0; }
+.ui-collapsible-heading a .ui-btn-inner { padding-left: 40px; }
+.ui-collapsible-heading a span.ui-btn { position: absolute; left: 6px; top: 50%; margin: -12px 0 0 0; width: 20px; height: 20px; padding: 1px 0px 1px 2px; text-indent: -9999px; }
+.ui-collapsible-heading a span.ui-btn .ui-btn-inner { padding: 10px 0; }
+.ui-collapsible-heading a span.ui-btn .ui-icon { left: 0; margin-top: -10px; }
+.ui-collapsible-heading-status { position:absolute; left:-9999px; }
+.ui-collapsible-content { display: block; padding: 10px 0 10px 8px; }
+.ui-collapsible-content-collapsed { display: none; }
+
+.ui-collapsible-set { margin: .5em 0; }
+.ui-collapsible-set .ui-collapsible-contain { margin: -1px 0 0; }
+/*
+* jQuery Mobile Framework
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
+*/
+.ui-controlgroup, fieldset.ui-controlgroup { padding: 0; margin: .5em 0 1em; }
+.ui-bar .ui-controlgroup { margin: 0 .3em; }
+.ui-controlgroup-label { font-size: 16px; line-height: 1.4; font-weight: normal; margin: 0 0 .3em; }
+.ui-controlgroup-controls { display: block; width: 95%;}
+.ui-controlgroup li { list-style: none; }
+.ui-controlgroup-vertical .ui-btn,
+.ui-controlgroup-vertical .ui-checkbox, .ui-controlgroup-vertical .ui-radio { margin: 0; border-bottom-width: 0; }
+.ui-controlgroup-vertical .ui-controlgroup-last { border-bottom-width: 1px; }
+.ui-controlgroup-horizontal { padding: 0; }
+.ui-controlgroup-horizontal .ui-btn,
+.ui-controlgroup-horizontal .ui-checkbox, .ui-controlgroup-horizontal .ui-radio { display: inline-block; margin: 0 -5px 0 0; }
+.ui-controlgroup-horizontal .ui-checkbox, .ui-controlgroup-horizontal .ui-radio { display: inline; }
+.ui-controlgroup-horizontal .ui-checkbox .ui-btn, .ui-controlgroup-horizontal .ui-radio .ui-btn,
+.ui-controlgroup-horizontal .ui-checkbox:last-child, .ui-controlgroup-horizontal .ui-radio:last-child { margin-right: 0; }
+.ui-controlgroup-horizontal .ui-controlgroup-last { margin-right: 0; }
+.ui-controlgroup .ui-checkbox label, .ui-controlgroup .ui-radio label { font-size: 16px; }
+/* conflicts with listview..
+.ui-controlgroup .ui-btn-icon-notext { width: 30px; height: 30px; text-indent: -9999px; }
+.ui-controlgroup .ui-btn-icon-notext .ui-btn-inner { padding: 5px 6px 5px 5px; }
+*/
+
+@media all and (min-width: 450px){
+ .ui-controlgroup-label { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0; }
+ .ui-controlgroup-controls { width: 60%; display: inline-block; }
+} /*
+* jQuery Mobile Framework
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
+*/
+.ui-dialog { min-height: 480px; }
+.ui-dialog .ui-header, .ui-dialog .ui-content, .ui-dialog .ui-footer { margin: 15px; position: relative; }
+.ui-dialog .ui-header, .ui-dialog .ui-footer { z-index: 10; width: auto; }
+.ui-dialog .ui-content, .ui-dialog .ui-footer { margin-top: -15px; }/*
+* jQuery Mobile Framework
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
+*/
+.ui-checkbox, .ui-radio { position:relative; margin: .2em 0 .5em; z-index: 1; }
+.ui-checkbox .ui-btn, .ui-radio .ui-btn { margin: 0; text-align: left; z-index: 2; }
+.ui-checkbox .ui-btn-inner, .ui-radio .ui-btn-inner { white-space: normal; }
+.ui-checkbox .ui-btn-icon-left .ui-btn-inner,.ui-radio .ui-btn-icon-left .ui-btn-inner { padding-left: 45px; }
+.ui-checkbox .ui-btn-icon-right .ui-btn-inner, .ui-radio .ui-btn-icon-right .ui-btn-inner { padding-right: 45px; }
+.ui-checkbox .ui-icon, .ui-radio .ui-icon { top: 1.1em; }
+.ui-checkbox .ui-btn-icon-left .ui-icon, .ui-radio .ui-btn-icon-left .ui-icon {left: 15px; }
+.ui-checkbox .ui-btn-icon-right .ui-icon, .ui-radio .ui-btn-icon-right .ui-icon {right: 15px; }
+/* input, label positioning */
+.ui-checkbox input,.ui-radio input { position:absolute; left:20px; top:50%; width: 10px; height: 10px; margin:-5px 0 0 0; outline: 0 !important; z-index: 1; }/*
+* jQuery Mobile Framework
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
+*/
+.ui-field-contain { padding: 1.5em 0; margin: 0; border-bottom-width: 1px; overflow: visible; }
+.ui-field-contain:first-child { border-top-width: 0; }
+@media all and (min-width: 450px){
+ .ui-field-contain { border-width: 0; padding: 0; margin: 1em 0; }
+} /*
+* jQuery Mobile Framework
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
+*/
+.ui-select { display: block; position: relative; }
+.ui-select select { position: absolute; left: -9999px; top: -9999px; }
+.ui-select .ui-btn { overflow: hidden; }
+.ui-select .ui-btn select { cursor: pointer; -webkit-appearance: button; left: 0; top:0; width: 100%; height: 100%; opacity: 0; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter: alpha(opacity=0); }
+@-moz-document url-prefix() {.ui-select .ui-btn select { opacity: 0.0001; }}
+.ui-select .ui-btn select.ui-select-nativeonly { opacity: 1; text-indent: 0; }
+
+.ui-select .ui-btn-icon-right .ui-btn-inner { padding-right: 45px; }
+.ui-select .ui-btn-icon-right .ui-icon { right: 15px; }
+
+/* labels */
+label.ui-select { font-size: 16px; line-height: 1.4; font-weight: normal; margin: 0 0 .3em; display: block; }
+
+/*listbox*/
+.ui-select .ui-btn-text, .ui-selectmenu .ui-btn-text { display: block; min-height: 1em; }
+.ui-select .ui-btn-text { text-overflow: ellipsis; overflow: hidden;}
+
+.ui-selectmenu { position: absolute; padding: 0; z-index: 100 !important; width: 80%; max-width: 350px; padding: 6px; }
+.ui-selectmenu .ui-listview { margin: 0; }
+.ui-selectmenu .ui-btn.ui-li-divider { cursor: default; }
+.ui-selectmenu-hidden { top: -9999px; left: -9999px; }
+.ui-selectmenu-screen { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 99; }
+.ui-screen-hidden, .ui-selectmenu-list .ui-li .ui-icon { display: none; }
+.ui-selectmenu-list .ui-li .ui-icon { display: block; }
+.ui-li.ui-selectmenu-placeholder { display: none; }
+.ui-selectmenu .ui-header .ui-title { margin: 0.6em 46px 0.8em; }
+
+@media all and (min-width: 450px){
+ label.ui-select { display: inline-block; width: 20%; margin: 0 2% 0 0; }
+ .ui-select { width: 60%; display: inline-block; }
+}
+
+/* when no placeholder is defined in a multiple select, the header height doesn't even extend past the close button. this shim's content in there */
+.ui-selectmenu .ui-header h1:after { content: '.'; visibility: hidden; }/*
+* jQuery Mobile Framework
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
+*/
+label.ui-input-text { font-size: 16px; line-height: 1.4; display: block; font-weight: normal; margin: 0 0 .3em; }
+input.ui-input-text, textarea.ui-input-text { background-image: none; padding: .4em; line-height: 1.4; font-size: 16px; display: block; width: 95%; }
+input.ui-input-text { -webkit-appearance: none; }
+textarea.ui-input-text { height: 50px; -webkit-transition: height 200ms linear; -moz-transition: height 200ms linear; -o-transition: height 200ms linear; transition: height 200ms linear; }
+.ui-input-search { padding: 0 30px; width: 77%; background-position: 8px 50%; background-repeat: no-repeat; position: relative; }
+.ui-input-search input.ui-input-text { border: none; width: 98%; padding: .4em 0; margin: 0; display: block; background: transparent none; outline: 0 !important; }
+.ui-input-search .ui-input-clear { position: absolute; right: 0; top: 50%; margin-top: -14px; }
+.ui-input-search .ui-input-clear-hidden { display: none; }
+
+/* orientation adjustments - incomplete!*/
+@media all and (min-width: 450px){
+ label.ui-input-text { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0 }
+ input.ui-input-text,
+ textarea.ui-input-text,
+ .ui-input-search { width: 60%; display: inline-block; }
+ .ui-input-search { width: 50%; }
+ .ui-input-search input.ui-input-text { width: 98%; /*echos rule from above*/ }
+}/*
+* jQuery Mobile Framework
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
+*/
+.ui-listview { margin: 0; counter-reset: listnumbering; }
+.ui-content .ui-listview { margin: -15px; }
+.ui-content .ui-listview-inset { margin: 1em 0; }
+.ui-listview, .ui-li { list-style:none; padding:0; }
+.ui-li, .ui-li.ui-field-contain { display: block; margin:0; position: relative; overflow: visible; text-align: left; border-width: 0; border-top-width: 1px; }
+.ui-li .ui-btn-text a.ui-link-inherit { text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }
+.ui-li-divider, .ui-li-static { padding: .5em 15px; font-size: 14px; font-weight: bold; }
+.ui-li-divider { counter-reset: listnumbering; }
+ol.ui-listview .ui-link-inherit:before, ol.ui-listview .ui-li-static:before, .ui-li-dec { font-size: .8em; display: inline-block; padding-right: .3em; font-weight: normal;counter-increment: listnumbering; content: counter(listnumbering) ". "; }
+ol.ui-listview .ui-li-jsnumbering:before { content: "" !important; } /* to avoid chance of duplication */
+.ui-listview-inset .ui-li { border-right-width: 1px; border-left-width: 1px; }
+.ui-li:last-child, .ui-li.ui-field-contain:last-child { border-bottom-width: 1px; }
+.ui-li>.ui-btn-inner { display: block; position: relative; padding: 0; }
+.ui-li .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li { padding: .7em 15px .7em 15px; display: block; }
+.ui-li-has-thumb .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-thumb { min-height: 60px; padding-left: 100px; }
+.ui-li-has-icon .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-icon { min-height: 20px; padding-left: 40px; }
+.ui-li-has-count .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-count { padding-right: 45px; }
+.ui-li-has-arrow .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-arrow { padding-right: 30px; }
+.ui-li-has-arrow.ui-li-has-count .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-arrow.ui-li-has-count { padding-right: 75px; }
+.ui-li-heading { font-size: 16px; font-weight: bold; display: block; margin: .6em 0; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }
+.ui-li-desc { font-size: 12px; font-weight: normal; display: block; margin: -.5em 0 .6em; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }
+.ui-li-thumb, .ui-li-icon { position: absolute; left: 1px; top: 0; max-height: 80px; max-width: 80px; }
+.ui-li-icon { max-height: 40px; max-width: 40px; left: 10px; top: .9em; }
+.ui-li-thumb, .ui-li-icon, .ui-li-content { float: left; margin-right: 10px; }
+
+.ui-li-aside { float: right; width: 50%; text-align: right; margin: .3em 0; }
+@media all and (min-width: 480px){
+ .ui-li-aside { width: 45%; }
+}
+.ui-li-divider { cursor: default; }
+.ui-li-has-alt .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-alt { padding-right: 95px; }
+.ui-li-count { position: absolute; font-size: 11px; font-weight: bold; padding: .2em .5em; top: 50%; margin-top: -.9em; right: 38px; }
+.ui-li-divider .ui-li-count, .ui-li-static .ui-li-count { right: 10px; }
+.ui-li-has-alt .ui-li-count { right: 55px; }
+.ui-li-link-alt { position: absolute; width: 40px; height: 100%; border-width: 0; border-left-width: 1px; top: 0; right: 0; margin: 0; padding: 0; }
+.ui-li-link-alt .ui-btn { overflow: hidden; position: absolute; right: 8px; top: 50%; margin: -11px 0 0 0; border-bottom-width: 1px; }
+.ui-li-link-alt .ui-btn-inner { padding: 0; position: static; }
+.ui-li-link-alt .ui-btn .ui-icon { right: 50%; margin-right: -9px; }
+
+.ui-listview-filter { border-width: 0; overflow: hidden; margin: -15px -15px 15px -15px }
+.ui-listview-filter .ui-input-search { margin: 5px; width: auto; display: block; }
+
+.ui-listview-filter-inset { margin: -15px -5px -15px -5px; background: transparent; }
+.ui-li.ui-screen-hidden{display:none;}
+/* Odd iPad positioning issue. */
+@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) {
+ .ui-li .ui-btn-text { overflow: visible; }
+}/*
+* jQuery Mobile Framework
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.
+*/
+label.ui-slider { display: block; }
+input.ui-slider-input { display: inline-block; width: 50px; }
+select.ui-slider-switch { display: none; }
+div.ui-slider { position: relative; display: inline-block; overflow: visible; height: 15px; padding: 0; margin: 0 2% 0 20px; top: 4px; width: 66%; }
+a.ui-slider-handle { position: absolute; z-index: 10; top: 50%; width: 28px; height: 28px; margin-top: -15px; margin-left: -15px; }
+a.ui-slider-handle .ui-btn-inner { padding-left: 0; padding-right: 0; }
+@media all and (min-width: 480px){
+ label.ui-slider { display: inline-block; width: 20%; margin: 0 2% 0 0; }
+ div.ui-slider { width: 45%; }
+}
+
+div.ui-slider-switch { height: 32px; overflow: hidden; margin-left: 0; }
+div.ui-slider-inneroffset { margin-left: 50%; position: absolute; top: 1px; height: 100%; width: 50%; }
+a.ui-slider-handle-snapping { -webkit-transition: left 100ms linear; }
+div.ui-slider-labelbg { position: absolute; top:0; margin: 0; border-width: 0; }
+div.ui-slider-switch div.ui-slider-labelbg-a { width: 60%; height: 100%; left: 0; }
+div.ui-slider-switch div.ui-slider-labelbg-b { width: 60%; height: 100%; right: 0; }
+.ui-slider-switch-a div.ui-slider-labelbg-a, .ui-slider-switch-b div.ui-slider-labelbg-b { z-index: -1; }
+.ui-slider-switch-a div.ui-slider-labelbg-b, .ui-slider-switch-b div.ui-slider-labelbg-a { z-index: 0; }
+
+div.ui-slider-switch a.ui-slider-handle { z-index: 20; width: 101%; height: 32px; margin-top: -18px; margin-left: -101%; }
+span.ui-slider-label { width: 100%; position: absolute;height: 32px; font-size: 16px; text-align: center; line-height: 2; background: none; border-color: transparent; }
+span.ui-slider-label-a { left: -100%; margin-right: -1px }
+span.ui-slider-label-b { right: -100%; margin-left: -1px }
+
--- /dev/null
+++ b/include/common-auth.inc.php
@@ -1,1 +1,101 @@
+<?php
+/*
+ * Copyright 2010,2011 Alexander Sadleir
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+function getScheme() {
+ $scheme = 'http';
+ if (isset($_SERVER['HTTPS']) and $_SERVER['HTTPS'] == 'on') {
+ $scheme .= 's';
+ }
+ return $scheme;
+}
+
+function getTrustRoot() {
+ return sprintf("%s://%s:%s%s/", getScheme(), $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], dirname($_SERVER['PHP_SELF']));
+}
+
+// Includes required files
+set_include_path(get_include_path() . PATH_SEPARATOR . $basePath . "lib/openid-php/");
+require_once "Auth/OpenID/Consumer.php";
+require_once "Auth/OpenID/FileStore.php";
+require_once "Auth/OpenID/AX.php";
+
+function login() {
+ global $basePath;
+ // Just tested this with/for Google, needs trying with others ...
+ $oid_identifier = 'https://www.google.com/accounts/o8/id';
+ // Create file storage area for OpenID data
+ $store = new Auth_OpenID_FileStore(realpath($basePath) . '/lib/openid-php/oid_store');
+ // Create OpenID consumer
+ $consumer = new Auth_OpenID_Consumer($store);
+ // Create an authentication request to the OpenID provider
+ $auth = $consumer->begin($oid_identifier);
+
+ // Create attribute request object
+ // See http://code.google.com/apis/accounts/docs/OpenID.html#Parameters for parameters
+ // Usage: make($type_uri, $count=1, $required=false, $alias=null)
+ $attribute[] = Auth_OpenID_AX_AttrInfo :: make('http://axschema.org/contact/email', 2, 1, 'email');
+ $attribute[] = Auth_OpenID_AX_AttrInfo :: make('http://axschema.org/namePerson/first', 1, 1, 'firstname');
+ $attribute[] = Auth_OpenID_AX_AttrInfo :: make('http://axschema.org/namePerson/last', 1, 1, 'lastname');
+
+ // Create AX fetch request
+ $ax = new Auth_OpenID_AX_FetchRequest;
+
+ // Add attributes to AX fetch request
+ foreach ($attribute as $attr) {
+ $ax->add($attr);
+ }
+
+ // Add AX fetch request to authentication request
+ $auth->addExtension($ax);
+ $_SESSION['returnURL'] = curPageURL();
+ // Redirect to OpenID provider for authentication
+ $url = $auth->redirectURL(getTrustRoot(), $_SESSION['returnURL']);
+ header('Location: ' . $url);
+}
+
+function auth() {
+ global $basePath;
+ if ($_SESSION['authed'] == true)
+ return true;
+
+ // Create file storage area for OpenID data
+ $store = new Auth_OpenID_FileStore(realpath($basePath) . '/lib/openid-php/oid_store');
+ // Create OpenID consumer
+ $consumer = new Auth_OpenID_Consumer($store);
+ // Create an authentication request to the OpenID provider
+ $response = $consumer->complete($_SESSION['returnURL']);
+
+ if ($response->status == Auth_OpenID_SUCCESS) {
+ // Get registration informations
+ $ax = new Auth_OpenID_AX_FetchResponse();
+ $obj = $ax->fromSuccessResponse($response);
+ $email = $obj->data['http://axschema.org/contact/email'][0];
+ var_dump($email);
+ if ($email != "maxious@gmail.com") {
+ die("Access Denied");
+ } else {
+ $_SESSION['authed'] = true;
+ }
+ } else {
+ login();
+ }
+}
+
+if ($_REQUEST['janrain_nonce'])
+ auth();
+?>
--- a/include/common-db.inc.php
+++ b/include/common-db.inc.php
@@ -1,20 +1,35 @@
<?php
+
+/*
+ * Copyright 2010,2011 Alexander Sadleir
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
if (php_uname('n') == "actbus-www") {
- $conn = new PDO("pgsql:dbname=transitdata;user=transitdata;password=transitdata;host=bus-main.lambdacomplex.org");
-}
-else if (isDebugServer()) {
- $conn = new PDO("pgsql:dbname=transitdata;user=postgres;password=snmc;host=localhost");
-}
-else {
- $conn = new PDO("pgsql:dbname=transitdata;user=transitdata;password=transitdata;host=localhost");
+ $conn = new PDO("pgsql:dbname=transitdata;user=transitdata;password=transitdata;host=bus-main.lambdacomplex.org");
+} else if (isDebugServer()) {
+ $conn = new PDO("pgsql:dbname=transitdata;user=postgres;password=snmc;host=localhost");
+} else {
+ $conn = new PDO("pgsql:dbname=transitdata;user=transitdata;password=transitdata;host=localhost");
}
if (!$conn) {
- die("A database error occurred.\n");
+ die("A database error occurred.\n");
}
-function databaseError($errMsg)
-{
- die($errMsg);
+
+function databaseError($errMsg) {
+ die($errMsg);
}
+
include ('db/route-dao.inc.php');
include ('db/trip-dao.inc.php');
include ('db/stop-dao.inc.php');
--- a/include/common-geo.inc.php
+++ b/include/common-geo.inc.php
@@ -1,153 +1,181 @@
<?php
+
+/*
+ * Copyright 2010,2011 Alexander Sadleir
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
// SELECT array_to_string(array(SELECT REPLACE(name_2006, ',', '\,') as name FROM suburbs order by name), ',')
$suburbs = explode(",", "Acton,Ainslie,Amaroo,Aranda,Banks,Barton,Belconnen,Bonner,Bonython,Braddon,Bruce,Calwell,Campbell,Chapman,Charnwood,Chifley,Chisholm,City,Conder,Cook,Curtin,Deakin,Dickson,Downer,Duffy,Dunlop,Evatt,Fadden,Farrer,Fisher,Florey,Flynn,Forrest,Franklin,Fraser,Fyshwick,Garran,Gilmore,Giralang,Gordon,Gowrie,Greenway,Griffith,Gungahlin,Hackett,Hall,Harrison,Hawker,Higgins,Holder,Holt,Hughes,Hume,Isaacs,Isabella Plains,Kaleen,Kambah,Kingston,Latham,Lawson,Lyneham,Lyons,Macarthur,Macgregor,Macquarie,Mawson,McKellar,Melba,Mitchell,Monash,Narrabundah,Ngunnawal,Nicholls,Oaks Estate,O'Connor,O'Malley,Oxley,Page,Palmerston,Parkes,Pearce,Phillip,Pialligo,Red Hill,Reid,Richardson,Rivett,Russell,Scullin,Spence,Stirling,Symonston,Tharwa,Theodore,Torrens,Turner,Wanniassa,Waramanga,Watson,Weetangera,Weston,Yarralumla");
-function staticmap($mapPoints, $zoom = 0, $markerImage = "iconb", $collapsible = true, $twotone = false)
-{
- global $labsPath;
- $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 = "";
- $mapwidthinmeters = 50;
- 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) {
- if ($twotone && $index == 0) {
- $markers.= $mapPoint[0] . "," . $mapPoint[1] . "," . "iconr" . ($index + 1);
- $center = "{$mapPoints[0][0]},{$mapPoints[0][1]}";
- }
- else {
- $markers.= $mapPoint[0] . "," . $mapPoint[1] . "," . $markerImage . ($index + 1);
- }
- if ($index + 1 != sizeof($mapPoints)) $markers.= "|";
- $dist = distance($mapPoints[0][0], $mapPoint[0][1], $mapPoint[0], $mapPoint[1]);
- $mapwidthinmeters = ($dist > $mapwidthinmeters ? $dist : $mapwidthinmeters);
- $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 * 1.5 < ($maxdistance)) $zoom = $zoomLevel;
- }
- }
- $center = $totalLat / sizeof($mapPoints) . "," . $totalLon / sizeof($mapPoints);
- }
- $output = "";
- if ($collapsible) $output.= '<div class="map" data-role="collapsible" data-collapsed="true"><h3>Open Map...</h3>';
- $output.= '<img class="map" src="' . curPageURL() . '/' . $labsPath . '/lib/staticmaplite/staticmap.php?center=' . $center . '&zoom=' . $zoom . '&size=' . $width . 'x' . $height . '&markers=' . $markers . '" width=' . $width . ' height=' . $height . '>';
- if ($collapsible) $output.= '</div>';
- return $output;
+
+function staticmap($mapPoints, $zoom = 0, $markerImage = "iconb", $collapsible = true, $twotone = false) {
+ global $basePath;
+ $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 = "";
+ $mapwidthinmeters = 50;
+ 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) {
+ if ($twotone && $index == 0) {
+ $markers.= $mapPoint[0] . "," . $mapPoint[1] . "," . "iconr" . ($index + 1);
+ $center = "{$mapPoints[0][0]},{$mapPoints[0][1]}";
+ } else {
+ $markers.= $mapPoint[0] . "," . $mapPoint[1] . "," . $markerImage . ($index + 1);
+ }
+ if ($index + 1 != sizeof($mapPoints))
+ $markers.= "|";
+ $dist = distance($mapPoints[0][0], $mapPoint[0][1], $mapPoint[0], $mapPoint[1]);
+ $mapwidthinmeters = ($dist > $mapwidthinmeters ? $dist : $mapwidthinmeters);
+ $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 * 1.5 < ($maxdistance))
+ $zoom = $zoomLevel;
+ }
+ }
+ $center = $totalLat / sizeof($mapPoints) . "," . $totalLon / sizeof($mapPoints);
+ }
+ $output = "";
+ if ($collapsible)
+ $output.= '<div class="map" data-role="collapsible" data-collapsed="true"><h3>Open Map...</h3>';
+ $output.= '<img class="map" src="' . curPageURL() . '/' . $basePath . '/lib/staticmaplite/staticmap.php?center=' . $center . '&zoom=' . $zoom . '&size=' . $width . 'x' . $height . '&markers=' . $markers . '" width=' . $width . ' height=' . $height . '>';
+ if ($collapsible)
+ $output.= '</div>';
+ 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 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 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 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 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;
}
+
?>
--- a/include/common-net.inc.php
+++ b/include/common-net.inc.php
@@ -1,31 +1,48 @@
<?php
-function getPage($url)
-{
- debug($url, "json");
- $ch = curl_init($url);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
- curl_setopt($ch, CURLOPT_HEADER, 0);
- curl_setopt($ch, CURLOPT_TIMEOUT, 45);
- $page = curl_exec($ch);
- if (curl_errno($ch)) {
- echo "<font color=red> Database temporarily unavailable: ";
- echo curl_errno($ch) . " " . curl_error($ch);
- if (isDebug()) {
- echo $url;
- }
- echo "</font><br>";
- }
- curl_close($ch);
- debug(print_r($page,true),"json");
- return $page;
+
+/*
+ * Copyright 2010,2011 Alexander Sadleir
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+function getPage($url) {
+ debug($url, "json");
+ $ch = curl_init($url);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ch, CURLOPT_HEADER, 0);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 45);
+ $page = curl_exec($ch);
+ if (curl_errno($ch)) {
+ echo "<font color=red> Database temporarily unavailable: ";
+ echo curl_errno($ch) . " " . curl_error($ch);
+ if (isDebug()) {
+ echo $url;
+ }
+ echo "</font><br>";
+ }
+ 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;
+
+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;
}
+
?>
--- a/include/common-request.inc.php
+++ b/include/common-request.inc.php
@@ -1,48 +1,64 @@
<?php
+
+/*
+ * Copyright 2010,2011 Alexander Sadleir
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
if (isset($_REQUEST['firstLetter'])) {
- $firstLetter = filter_var($_REQUEST['firstLetter'], FILTER_SANITIZE_STRING);
+ $firstLetter = filter_var($_REQUEST['firstLetter'], FILTER_SANITIZE_STRING);
}
if (isset($_REQUEST['bysuburbs'])) {
- $bysuburbs = true;
+ $bysuburbs = true;
}
if (isset($_REQUEST['bynumber'])) {
- $bynumber = true;
+ $bynumber = true;
}
if (isset($_REQUEST['allstops'])) {
- $allstops = true;
+ $allstops = true;
}
if (isset($_REQUEST['nearby'])) {
- $nearby = true;
+ $nearby = true;
}
if (isset($_REQUEST['suburb'])) {
- $suburb = $_REQUEST['suburb'];
+ $suburb = $_REQUEST['suburb'];
}
$pageKey = filter_var($_REQUEST['pageKey'], FILTER_SANITIZE_NUMBER_INT);
$lat = filter_var($_REQUEST['lat'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
$lon = filter_var($_REQUEST['lon'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
$max_distance = filter_var($_REQUEST['radius'], FILTER_SANITIZE_NUMBER_INT);
if (isset($_REQUEST['numberSeries'])) {
- $numberSeries = filter_var($_REQUEST['numberSeries'], FILTER_SANITIZE_NUMBER_INT);
+ $numberSeries = filter_var($_REQUEST['numberSeries'], FILTER_SANITIZE_NUMBER_INT);
}
if (isset($_REQUEST['routeDestination'])) {
- $routeDestination = urldecode(filter_var($_REQUEST['routeDestination'], FILTER_SANITIZE_ENCODED));
+ $routeDestination = urldecode(filter_var($_REQUEST['routeDestination'], FILTER_SANITIZE_ENCODED));
}
if (isset($_REQUEST['stopcode'])) {
- $stopcode = filter_var($_REQUEST['stopcode'], FILTER_SANITIZE_STRING);
+ $stopcode = filter_var($_REQUEST['stopcode'], FILTER_SANITIZE_STRING);
}
if (isset($_REQUEST['stopids'])) {
- $stopids = explode(",", filter_var($_REQUEST['stopids'], FILTER_SANITIZE_STRING));
+ $stopids = explode(",", filter_var($_REQUEST['stopids'], FILTER_SANITIZE_STRING));
}
if (isset($_REQUEST['tripid'])) {
- $tripid = filter_var($_REQUEST['tripid'], FILTER_SANITIZE_NUMBER_INT);
+ $tripid = filter_var($_REQUEST['tripid'], FILTER_SANITIZE_NUMBER_INT);
}
if (isset($_REQUEST['stopid'])) {
- $stopid = filter_var($_REQUEST['stopid'], FILTER_SANITIZE_NUMBER_INT);
+ $stopid = filter_var($_REQUEST['stopid'], FILTER_SANITIZE_NUMBER_INT);
}
if (isset($_REQUEST['routeid'])) {
- $routeid = filter_var($_REQUEST['routeid'], FILTER_SANITIZE_NUMBER_INT);
+ $routeid = filter_var($_REQUEST['routeid'], FILTER_SANITIZE_NUMBER_INT);
}
if (isset($_REQUEST['geolocate'])) {
-$geolocate = filter_var($_REQUEST['geolocate'], FILTER_SANITIZE_URL);
+ $geolocate = filter_var($_REQUEST['geolocate'], FILTER_SANITIZE_URL);
}
?>
--- a/include/common-session.inc.php
+++ b/include/common-session.inc.php
@@ -1,63 +1,77 @@
<?php
+
+/*
+ * Copyright 2010,2011 Alexander Sadleir
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
// you have to open the session to be able to modify or remove it
session_start();
if (isset($_REQUEST['service_period'])) {
- $_SESSION['service_period'] = filter_var($_REQUEST['service_period'], FILTER_SANITIZE_STRING);
- sessionUpdated();
+ $_SESSION['service_period'] = filter_var($_REQUEST['service_period'], FILTER_SANITIZE_STRING);
+ sessionUpdated();
}
if (isset($_REQUEST['time'])) {
- $_SESSION['time'] = filter_var($_REQUEST['time'], FILTER_SANITIZE_STRING);
- sessionUpdated();
+ $_SESSION['time'] = filter_var($_REQUEST['time'], FILTER_SANITIZE_STRING);
+ sessionUpdated();
}
if (isset($_REQUEST['geolocate']) && $_REQUEST['geolocate'] != "Enter co-ordinates or address here") {
- $geocoded = false;
- if (isset($_REQUEST['lat']) && isset($_REQUEST['lon'])) {
- $_SESSION['lat'] = trim(filter_var($_REQUEST['lat'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
- $_SESSION['lon'] = trim(filter_var($_REQUEST['lon'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
- }
- else {
- if (startsWith($geolocate, "-")) {
- $locateparts = explode(",", $geolocate);
- $_SESSION['lat'] = $locateparts[0];
- $_SESSION['lon'] = $locateparts[1];
- }
- else if (strpos($geolocate, "(") !== false) {
- $geoParts = explode("(", $geolocate);
- $locateparts = explode(",", str_replace(")", "",$geoParts[1]));
- $_SESSION['lat'] = $locateparts[0];
- $_SESSION['lon'] = $locateparts[1];
- }
- else {
- $contents = geocode($geolocate, true);
- print_r($contents);
- if (isset($contents[0]->centroid)) {
- $geocoded = true;
- $_SESSION['lat'] = $contents[0]->centroid->coordinates[0];
- $_SESSION['lon'] = $contents[0]->centroid->coordinates[1];
- }
- else {
- $_SESSION['lat'] = "";
- $_SESSION['lon'] = "";
- }
- }
- }
- sessionUpdated();
+ $geocoded = false;
+ if (isset($_REQUEST['lat']) && isset($_REQUEST['lon'])) {
+ $_SESSION['lat'] = trim(filter_var($_REQUEST['lat'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
+ $_SESSION['lon'] = trim(filter_var($_REQUEST['lon'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
+ } else {
+ if (startsWith($geolocate, "-")) {
+ $locateparts = explode(",", $geolocate);
+ $_SESSION['lat'] = $locateparts[0];
+ $_SESSION['lon'] = $locateparts[1];
+ } else if (strpos($geolocate, "(") !== false) {
+ $geoParts = explode("(", $geolocate);
+ $locateparts = explode(",", str_replace(")", "", $geoParts[1]));
+ $_SESSION['lat'] = $locateparts[0];
+ $_SESSION['lon'] = $locateparts[1];
+ } else {
+ $contents = geocode($geolocate, true);
+ print_r($contents);
+ if (isset($contents[0]->centroid)) {
+ $geocoded = true;
+ $_SESSION['lat'] = $contents[0]->centroid->coordinates[0];
+ $_SESSION['lon'] = $contents[0]->centroid->coordinates[1];
+ } else {
+ $_SESSION['lat'] = "";
+ $_SESSION['lon'] = "";
+ }
+ }
+ }
+ sessionUpdated();
}
-function sessionUpdated()
-{
- $_SESSION['lastUpdated'] = time();
+
+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("Session timeout " . ($_SESSION['lastUpdated'] + $TIMEOUT_LIMIT) . ">" . time(), "session");
+ session_destroy();
+ session_start();
}
+
//debug(print_r($_SESSION, true) , "session");
-function current_time()
-{
- return ($_SESSION['time'] ? $_SESSION['time'] : date("H:i:s"));
+function current_time() {
+ return ($_SESSION['time'] ? $_SESSION['time'] : date("H:i:s"));
}
+
?>
--- a/include/common-template.inc.php
+++ b/include/common-template.inc.php
@@ -1,64 +1,80 @@
<?php
+
+/*
+ * Copyright 2010,2011 Alexander Sadleir
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
// Copyright 2009 Google Inc. All Rights Reserved.
$GA_ACCOUNT = "MO-22173039-1";
$GA_PIXEL = "/lib/ga.php";
-function googleAnalyticsGetImageUrl()
-{
- global $GA_ACCOUNT, $GA_PIXEL;
- //if (stristr($_SERVER['HTTP_USER_AGENT'], 'Googlebot') return "";
- $url = "";
- $url.= $GA_PIXEL . "?";
- $url.= "utmac=" . $GA_ACCOUNT;
- $url.= "&utmn=" . rand(0, 0x7fffffff);
- $referer = $_SERVER["HTTP_REFERER"];
- $query = $_SERVER["QUERY_STRING"];
- $path = $_SERVER["REQUEST_URI"];
- if (empty($referer)) {
- $referer = "-";
- }
- $url.= "&utmr=" . urlencode($referer);
- if (!empty($path)) {
- $url.= "&utmp=" . urlencode($path);
- }
- $url.= "&guid=ON";
- return str_replace("&", "&", $url);
-}
-function include_header($pageTitle, $pageType, $opendiv = true, $geolocate = false, $datepicker = false)
-{
- global $labsPath;
- echo '
+
+function googleAnalyticsGetImageUrl() {
+ global $GA_ACCOUNT, $GA_PIXEL;
+ //if (stristr($_SERVER['HTTP_USER_AGENT'], 'Googlebot') return "";
+ $url = "";
+ $url.= $GA_PIXEL . "?";
+ $url.= "utmac=" . $GA_ACCOUNT;
+ $url.= "&utmn=" . rand(0, 0x7fffffff);
+ $referer = $_SERVER["HTTP_REFERER"];
+ $query = $_SERVER["QUERY_STRING"];
+ $path = $_SERVER["REQUEST_URI"];
+ if (empty($referer)) {
+ $referer = "-";
+ }
+ $url.= "&utmr=" . urlencode($referer);
+ if (!empty($path)) {
+ $url.= "&utmp=" . urlencode($path);
+ }
+ $url.= "&guid=ON";
+ return str_replace("&", "&", $url);
+}
+
+function include_header($pageTitle, $pageType, $opendiv = true, $geolocate = false, $datepicker = false) {
+ global $basePath, $serviceAlertsEnabled;
+ echo '
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>' . $pageTitle . '</title>
+<title>' . $pageTitle . ' - Canberra Bus Timetable</title>
<meta name="google-site-verification" content="-53T5Qn4TB_de1NyfR_ZZkEVdUNcNFSaYKSFkWKx-sY" />
<link rel="dns-prefetch" href="//code.jquery.com">
<link rel="dns-prefetch" href="//ajax.googleapis.com">
- <link rel="stylesheet" href="' . $labsPath . 'css/jquery-ui-1.8.12.custom.css" />';
- if (isDebugServer()) {
- $jqmcss = $labsPath . 'css/jquery.mobile-1.0b2.css';
- $jqjs = $labsPath . 'js/jquery-1.6.2.min.js';
- $jqmjs = $labsPath . 'js/jquery.mobile-1.0b2.js';
- }
- else {
- $jqmcss = "//code.jquery.com/mobile/1.0b2/jquery.mobile-1.0b2.min.css";
- $jqjs = "//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js";
- $jqmjs = "//code.jquery.com/mobile/1.0b2/jquery.mobile-1.0b2.min.js";
- }
- echo '<link rel="stylesheet" href="' . $jqmcss . '" />
- <script src="'.$jqjs.'"></script>
+ <link rel="stylesheet" href="' . $basePath . 'css/jquery-ui-1.8.12.custom.css" />';
+ if (isDebugServer()) {
+ $jqmcss = $basePath . 'css/jquery.mobile-1.0b3.css';
+ $jqjs = $basePath . 'js/jquery-1.6.2.min.js';
+ $jqmjs = $basePath . 'js/jquery.mobile-1.0b3.js';
+ } else {
+ $jqmcss = "//code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.css";
+ $jqjs = "//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js";
+ $jqmjs = "//code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.js";
+ }
+ echo '<link rel="stylesheet" href="' . $jqmcss . '" />
+ <script src="' . $jqjs . '"></script>
<script>$(document).bind("mobileinit", function(){
$.mobile.ajaxEnabled = false;
});
</script>
- <script src="'.$jqmjs.'"></script>
-
-<script src="' . $labsPath . 'js/jquery.ui.core.min.js"></script>
-<script src="' . $labsPath . 'js/jquery.ui.position.min.js"></script>
-<script src="' . $labsPath . 'js/jquery.ui.widget.min.js"></script>
- <script src="' . $labsPath . 'js/jquery.ui.autocomplete.min.js"></script>
+ <script src="' . $jqmjs . '"></script>
+
+<script src="' . $basePath . 'js/jquery.ui.core.min.js"></script>
+<script src="' . $basePath . 'js/jquery.ui.position.min.js"></script>
+<script src="' . $basePath . 'js/jquery.ui.widget.min.js"></script>
+ <script src="' . $basePath . 'js/jquery.ui.autocomplete.min.js"></script>
<script>
$(function() {
$( "#geolocate" ).autocomplete({
@@ -75,8 +91,9 @@
});
});
</script>';
- echo '<style type="text/css">';
- if (strstr($_SERVER['HTTP_USER_AGENT'], 'Android')) echo '.ui-shadow,.ui-btn-up-a,.ui-btn-hover-a,.ui-btn-down-a,.ui-body-b,.ui-btn-up-b,.ui-btn-hover-b,
+ echo '<style type="text/css">';
+ if (strstr($_SERVER['HTTP_USER_AGENT'], 'Android'))
+ echo '.ui-shadow,.ui-btn-up-a,.ui-btn-hover-a,.ui-btn-down-a,.ui-body-b,.ui-btn-up-b,.ui-btn-hover-b,
.ui-btn-down-b,.ui-bar-c,.ui-body-c,.ui-btn-up-c,.ui-btn-hover-c,.ui-btn-down-c,.ui-bar-c,.ui-body-d,
.ui-btn-up-d,.ui-btn-hover-d,.ui-btn-down-d,.ui-bar-d,.ui-body-e,.ui-btn-up-e,.ui-btn-hover-e,
.ui-btn-down-e,.ui-bar-e,.ui-overlay-shadow,.ui-shadow,.ui-btn-active,.ui-body-a,.ui-bar-a {
@@ -84,22 +101,25 @@
box-shadow: none;
-webkit-box-shadow: none;
}';
- echo '</style>';
- echo '<link rel="stylesheet" href="' . $labsPath . 'css/local.css.php" />';
- if (strstr($_SERVER['HTTP_USER_AGENT'], 'iPhone') || strstr($_SERVER['HTTP_USER_AGENT'], 'iPod') || strstr($_SERVER['HTTP_USER_AGENT'], 'iPad')) {
- echo '<meta name="apple-mobile-web-app-capable" content="yes" />
+ echo '</style>';
+ echo '<link rel="stylesheet" href="' . $basePath . 'css/local.css.php" />';
+ if (strstr($_SERVER['HTTP_USER_AGENT'], 'iPhone') || strstr($_SERVER['HTTP_USER_AGENT'], 'iPod') || strstr($_SERVER['HTTP_USER_AGENT'], 'iPad')) {
+ echo '<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<link rel="apple-touch-startup-image" href="startup.png" />
<link rel="apple-touch-icon" href="apple-touch-icon.png" />';
- }
- if ($geolocate) {
- echo "<script>
+ }
+ if ($geolocate) {
+ echo "<script>
function success(position) {
$('#error').val('Location now detected. Please wait for data to load.');
$('#geolocate').val(position.coords.latitude+','+position.coords.longitude);
-$.ajax({ url: \"include/common.inc.php?geolocate=yes&lat=\"+position.coords.latitude+\"&lon=\"+position.coords.longitude });
-location.reload(true);
+$.ajax({ async: false,
+success: function(){
+ location.reload(true);
+ },
+url: \"include/common.inc.php?geolocate=yes&lat=\"+position.coords.latitude+\"&lon=\"+position.coords.longitude });
}
function error(msg) {
$('#error').val('Error: '+msg);
@@ -120,10 +140,12 @@
$('#here').show();
});
";
- if (!isset($_SESSION['lat']) || $_SESSION['lat'] == "") echo "geolocate();";
- echo "</script> ";
- }
- if (isAnalyticsOn()) echo '
+ if (!isset($_SESSION['lat']) || $_SESSION['lat'] == "")
+ echo "geolocate();";
+ echo "</script> ";
+ }
+ if (isAnalyticsOn())
+ echo '
<script type="text/javascript">' . "
var _gaq = _gaq || [];
@@ -131,40 +153,46 @@
_gaq.push(['_trackPageview']);
_gaq.push(['_trackPageLoadTime']);
</script>";
- echo '</head>
+ echo '</head>
<body>
<div id="skip">
<a href="#maincontent">Skip to content</a>
</div>
';
- if ($opendiv) {
- echo '<div data-role="page">
+ if ($opendiv) {
+ echo '<div data-role="page">
<div data-role="header" data-position="inline">
<a href="' . (isset($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : "javascript:history.go(-1)") . '" data-icon="arrow-l" data-rel="back" class="ui-btn-left">Back</a>
<h1>' . $pageTitle . '</h1>
- <a href="' . $labsPath . '/index.php" data-icon="home" class="ui-btn-right">Home</a>
+ <a href="' . $basePath . '/index.php" data-icon="home" class="ui-btn-right">Home</a>
</div><!-- /header -->
<a name="maincontent" id="maincontent"></a>
<div data-role="content"> ';
- $overrides = getServiceOverride();
- if ($overrides['service_id']) {
- if ($overrides['service_id'] == "noservice") {
- echo '<div id="servicewarning">Buses are <strong>not running today</strong> due to industrial action/public holiday. See <a
+ $overrides = getServiceOverride();
+ if ($overrides['service_id']) {
+ if ($overrides['service_id'] == "noservice") {
+ echo '<div id="servicewarning">Buses are <strong>not running today</strong> due to industrial action/public holiday. See <a
href="http://www.action.act.gov.au">http://www.action.act.gov.au</a> for details.</div>';
- }
- else {
- echo '<div id="servicewarning">Buses are running on an altered timetable today due to industrial action/public holiday. See <a href="http://www.action.act.gov.au">http://www.action.act.gov.au</a> for details.</div>';
- }
- }
- }
-}
-function include_footer()
-{
- global $labsPath;
- echo '<div id="footer"><a href="' . $labsPath . 'about.php">About/Contact Us</a> <a href="' . $labsPath . 'feedback.php">Feedback/Bug Report</a> <a href="' . $labsPath . 'privacy.php">Privacy Policy</a>';
- echo '</div>';
- if (isAnalyticsOn()) {
- echo "<script> (function() {
+ } else {
+ echo '<div id="servicewarning">Buses are running on an altered timetable today due to industrial action/public holiday. See <a href="http://www.action.act.gov.au">http://www.action.act.gov.au</a> for details.</div>';
+ }
+ }
+ if ($GTFSREnabled) {
+ $serviceAlerts = getServiceAlertsAsArray("agency", "0");
+ foreach ($serviceAlerts['entity'] as $entity) {
+ echo "<div id='servicewarning'>" . date("F j, g:i a", strtotime($entity['alert']['active_period'][0]['start'])) . " to " . date("F j, g:i a", strtotime($entity['alert']['active_period'][0]['end'])) . "{$entity['alert']['header_text']['translation'][0]['text']}<br>Warning: {$entity['alert']['description_text']['translation'][0]['text']}
+ <br><a href='{$entity['alert']['url']['translation'][0]['text']}'>Source</a> </div>";
+ }
+ }
+ }
+}
+
+function include_footer() {
+ global $basePath;
+ echo '<div id="footer"><a href="' . $basePath . 'about.php">About/Contact Us</a> <a href="' . $basePath . 'feedback.php">Feedback/Bug Report</a> <a href="' . $basePath . 'privacy.php">Privacy Policy</a>';
+ echo '</div>';
+ if (isAnalyticsOn()) {
+ echo "<script> (function() {
var ga = document.createElement('script'); ga.type =
'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
@@ -172,25 +200,25 @@
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();</script>";
- $googleAnalyticsImageUrl = googleAnalyticsGetImageUrl();
- echo '<noscript><img src="' . $googleAnalyticsImageUrl . '" /></noscript>';
- }
- echo "\n</div></div></body></html>";
-}
-function placeSettings()
-{
- global $service_periods;
- $geoerror = false;
- $geoerror = !isset($_SESSION['lat']) || !isset($_SESSION['lat']) || $_SESSION['lat'] == "" || $_SESSION['lon'] == "";
-
- echo '<div id="error">';
- if ($geoerror) {
- echo 'Sorry, but your location could not currently be detected.
+ $googleAnalyticsImageUrl = googleAnalyticsGetImageUrl();
+ echo '<noscript><img src="' . $googleAnalyticsImageUrl . '" /></noscript>';
+ }
+ echo "\n</div></div></body></html>";
+}
+
+function placeSettings() {
+ global $service_periods;
+ $geoerror = false;
+ $geoerror = !isset($_SESSION['lat']) || !isset($_SESSION['lat']) || $_SESSION['lat'] == "" || $_SESSION['lon'] == "";
+
+ echo '<div id="error">';
+ 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 '</div>';
- echo '<div id="settings" data-role="collapsible" data-collapsed="' . !$geoerror . '">
+ }
+ echo '</div>';
+ echo '<div id="settings" data-role="collapsible" data-collapsed="' . !$geoerror . '">
<h3>Change Location...</h3>
<form action="' . basename($_SERVER['PHP_SELF']) . "?" . $_SERVER['QUERY_STRING'] . '" method="post">
<div class="ui-body">
@@ -203,11 +231,12 @@
</div></form>
</div>';
}
-function trackEvent($category, $action, $label = "", $value = - 1)
-{
- if (isAnalyticsOn()) {
- echo "\n<script> _gaq.push(['_trackEvent', '$category', '$action'" . ($label != "" ? ", '$label'" : "") . ($value != - 1 ? ", $value" : "") . "]);</script>";
- }
-}
+
+function trackEvent($category, $action, $label = "", $value = - 1) {
+ if (isAnalyticsOn()) {
+ echo "\n<script> _gaq.push(['_trackEvent', '$category', '$action'" . ($label != "" ? ", '$label'" : "") . ($value != - 1 ? ", $value" : "") . "]);</script>";
+ }
+}
+
?>
--- a/include/common-transit.inc.php
+++ b/include/common-transit.inc.php
@@ -1,49 +1,278 @@
<?php
+
+/*
+ * Copyright 2010,2011 Alexander Sadleir
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
$service_periods = Array(
- 'sunday',
- 'saturday',
- 'weekday'
+ 'sunday',
+ 'saturday',
+ 'weekday'
);
-function service_period($date = "")
-{
-
- if (isset($_SESSION['service_period'])) return $_SESSION['service_period'];
- $override = getServiceOverride($date);
- if ($override['service_id']){
- return $override['service_id'];
- }
-
- switch (date('w',($date != "" ? $date : time()))) {
- case 0:
- return 'sunday';
- case 6:
- return 'saturday';
- default:
- return 'weekday';
- }
-}
-function midnight_seconds($time = "")
-{
- // from http://www.perturb.org/display/Perlfunc__Seconds_Since_Midnight.html
- if ($time != "") {
- return (date("G", $time) * 3600) + (date("i", $time) * 60) + date("s", $time);
- }
- 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 service_period($date = "") {
+
+ if (isset($_SESSION['service_period']))
+ return $_SESSION['service_period'];
+ $override = getServiceOverride($date);
+ if ($override['service_id']) {
+ return $override['service_id'];
+ }
+
+ switch (date('w', ($date != "" ? $date : time()))) {
+ case 0:
+ return 'sunday';
+ case 6:
+ return 'saturday';
+ default:
+ return 'weekday';
+ }
+}
+
+function midnight_seconds($time = "") {
+ // from http://www.perturb.org/display/Perlfunc__Seconds_Since_Midnight.html
+ if ($time != "") {
+ return (date("G", $time) * 3600) + (date("i", $time) * 60) + date("s", $time);
+ }
+ 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 "";
+ }
+}
+
+if ($GTFSREnabled) {
+ $serviceAlertCause = Array(
+ "UNKNOWN_CAUSE" => "Unknown cause",
+ "OTHER_CAUSE" => "Other cause",
+ "TECHNICAL_PROBLEM" => "Technical problem",
+ "STRIKE" => "Strike",
+ "DEMONSTRATION" => "Demonstration",
+ "ACCIDENT" => "Accident",
+ "HOLIDAY" => "Holiday",
+ "WEATHER" => "Weather",
+ "MAINTENANCE" => "Maintenance",
+ "CONSTRUCTION" => "Construction",
+ "POLICE_ACTIVITY" => "Police activity",
+ "MEDICAL_EMERGENCY" => "Medical emergency"
+ );
+ $serviceAlertEffect = Array(
+ "NO_SERVICE" => "No service",
+ "REDUCED_SERVICE" => "Reduced service",
+ "SIGNIFICANT_DELAYS" => "Significant delays",
+ "DETOUR" => "Detour",
+ "ADDITIONAL_SERVICE" => "Additional service",
+ "MODIFIED_SERVICE" => "Modified service",
+ "OTHER_EFFECT" => "Other effect",
+ "UNKNOWN_EFFECT" => "Unknown effect",
+ "STOP_MOVED" => "Stop moved");
+
+ set_include_path(get_include_path() . PATH_SEPARATOR . ($basePath . "lib/Protobuf-PHP/library/DrSlump/"));
+
+ include_once("Protobuf.php");
+ include_once("Protobuf/Message.php");
+ include_once("Protobuf/Registry.php");
+ include_once("Protobuf/Descriptor.php");
+ include_once("Protobuf/Field.php");
+
+ include_once($basePath . "lib/Protobuf-PHP/gtfs-realtime.php");
+ include_once("Protobuf/CodecInterface.php");
+ include_once("Protobuf/Codec/PhpArray.php");
+ include_once("Protobuf/Codec/Binary.php");
+ include_once("Protobuf/Codec/Binary/Writer.php");
+ include_once("Protobuf/Codec/Json.php");
+
+ function getServiceAlerts($filter_class = "", $filter_id = "") {
+ /*
+
+ also need last modified epoch of client gtfs
+
+ - add,remove,patch,inform (null)
+ - stop
+ - trip
+ - network
+ - classes (WHERE=)
+ - route (short_name or route_id)
+ - street
+ - stop
+ - trip
+ Currently support:
+ network inform
+ trip patch: stop remove
+ street inform: route inform, trip inform, stop inform
+ route patch: trip remove
+ */
+ $fm = new transit_realtime\FeedMessage();
+ $fh = new transit_realtime\FeedHeader();
+ $fh->setGtfsRealtimeVersion(1);
+ $fh->setTimestamp(time());
+ $fm->setHeader($fh);
+ foreach (getCurrentAlerts() as $alert) {
+ $fe = new transit_realtime\FeedEntity();
+ $fe->setId($alert['id']);
+ $fe->setIsDeleted(false);
+ $alert = new transit_realtime\Alert();
+ $tr = new transit_realtime\TimeRange();
+ $tr->setStart($alert['start']);
+ $tr->setEnd($alert['end']);
+ $alert->addActivePeriod($tr);
+ $informedEntities = getInformedAlerts($alert['id'], $_REQUEST['filter_class'], $_REQUEST['filter_id']);
+ if (sizeof($informedEntities) > 0) {
+ $informed = Array();
+ $es = new transit_realtime\EntitySelector();
+ if ($informedEntity['informed_class'] == "agency") {
+ $es->setAgencyId($informedEntity['informed_id']);
+ }
+ if ($informedEntity['informed_class'] == "stop") {
+ $es->setStopId($informedEntity['informed_id']);
+ }
+ if ($informedEntity['informed_class'] == "route") {
+ $es->setRouteId($informedEntity['informed_id']);
+ }
+ if ($informedEntity['informed_class'] == "trip") {
+ $td = new transit_realtime\TripDescriptor();
+ $td->setTripId($informedEntity['informed_id']);
+ $es->setTrip($td);
+ }
+ $alert->addInformedEntity($es);
+ }
+ $alert->setCause(constant("transit_realtime\Alert\Cause::" . $alert['cause']));
+ $alert->setEffect(constant("transit_realtime\Alert\Effect::" . $alert['effect']));
+ $tsUrl = new transit_realtime\TranslatedString();
+ $tUrl = new transit_realtime\TranslatedString\Translation();
+ $tUrl->setText($alert['url']);
+ $tUrl->setLanguage("en");
+ $tsUrl->addTranslation($tUrl);
+ $alert->setUrl($tsUrl);
+ $tsHeaderText = new transit_realtime\TranslatedString();
+ $tHeaderText = new transit_realtime\TranslatedString\Translation();
+ $tHeaderText->setText($alert['header']);
+ $tHeaderText->setLanguage("en");
+ $tsHeaderText->addTranslation($tHeaderText);
+ $alert->setHeaderText($tsHeaderText);
+ $tsDescriptionText = new transit_realtime\TranslatedString();
+ $tDescriptionText = new transit_realtime\TranslatedString\Translation();
+ $tDescriptionText->setText($alert['description']);
+ $tDescriptionText->setLanguage("en");
+ $tsDescriptionText->addTranslation($tDescriptionText);
+ $alert->setDescriptionText($tsDescriptionText);
+ $fe->setAlert($alert);
+ $fm->addEntity($fe);
+ }
+ return $fm;
+ }
+
+ function getServiceAlertsAsArray($filter_class = "", $filter_id = "") {
+ $codec = new DrSlump\Protobuf\Codec\PhpArray();
+ return $codec->encode(getServiceAlerts($filter_class, $filter_id));
+ }
+
+ function getServiceAlertsAsBinary($filter_class = "", $filter_id = "") {
+ $codec = new DrSlump\Protobuf\Codec\Binary();
+ return $codec->encode(getServiceAlerts($filter_class, $filter_id));
+ }
+
+ function getServiceAlertsAsJSON($filter_class = "", $filter_id = "") {
+ $codec = new DrSlump\Protobuf\Codec\Json();
+ return $codec->encode(getServiceAlerts($filter_class, $filter_id));
+ }
+
+ function getServiceAlertsByClass() {
+ $return = Array();
+ $alerts = getServiceAlertsAsArray("", "");
+ foreach ($alerts['entities'] as $entity) {
+ foreach ($entity['informed'] as $informed) {
+ foreach ($informed as $key => $value) {
+ if (strpos("_id", $key) > 0) {
+ $parts = explode($key);
+ $class = $parts[0];
+ $id = $value;
+ }
+ }
+ $return[$class][$id][] = $entity;
+ }
+ }
+ }
+
+ function getTripUpdates($filter_class = "", $filter_id = "") {
+ $fm = new transit_realtime\FeedMessage();
+ $fh = new transit_realtime\FeedHeader();
+ $fh->setGtfsRealtimeVersion(1);
+ $fh->setTimestamp(time());
+ $fm->setHeader($fh);
+ foreach (getCurrentAlerts() as $alert) {
+ $informedEntities = getInformedAlerts($alert['id'], $_REQUEST['filter_class'], $_REQUEST['filter_id']);
+ $stops = Array();
+ $routestrips = Array();
+ if (sizeof($informedEntities) > 0) {
+ if ($informedEntity['informed_class'] == "stop" && $informed["x-action"] == "remove") {
+ $stops[] = $informedEntity['informed_id'];
+ }
+ if (($informedEntity['informed_class'] == "route" || $informedEntity['informed_class'] == "trip") && $informed["x-action"] == "patch") {
+ $routestrips[] = Array("id" => $informedEntity['informed_id'],
+ "type" => $informedEntity['informed_class']);
+ }
+ }
+ foreach ($routestrips as $routetrip) {
+ $fe = new transit_realtime\FeedEntity();
+ $fe->setId($alert['id'] . $routetrip['id']);
+ $fe->setIsDeleted(false);
+ $tu = new transit_realtime\TripUpdate();
+ $td = new transit_realtime\TripDescriptor();
+ if ($routetrip['type'] == "route") {
+ $td->setRouteId($routetrip['id']);
+ } else if ($routetrip['type'] == "trip") {
+ $td->setTripId($routetrip['id']);
+ }
+ $tu->setTrip($td);
+ foreach ($stops as $stop) {
+ $stu = new transit_realtime\TripUpdate\StopTimeUpdate();
+ $stu->setStopId($stop);
+ $stu->setScheduleRelationship(transit_realtime\TripUpdate\StopTimeUpdate\ScheduleRelationship::SKIPPED);
+ $tu->addStopTimeUpdate($stu);
+ }
+ $fe->setTripUpdate($tu);
+ $fm->addEntity($fe);
+ }
+ }
+ return $fm;
+ }
+
+ function getTripUpdatesAsArray($filter_class = "", $filter_id = "") {
+ $codec = new DrSlump\Protobuf\Codec\PhpArray();
+ return $codec->encode(getTripUpdates($filter_class, $filter_id));
+ }
+
+ function getTripUpdatesAsBinary($filter_class = "", $filter_id = "") {
+ $codec = new DrSlump\Protobuf\Codec\Binary();
+ return $codec->encode(getTripUpdates($filter_class, $filter_id));
+ }
+
+ function getTripUpdatesAsJSON($filter_class = "", $filter_id = "") {
+ $codec = new DrSlump\Protobuf\Codec\Json();
+ return $codec->encode(getTripUpdates($filter_class, $filter_id));
+ }
+
}
?>
--- a/include/common.inc.php
+++ b/include/common.inc.php
@@ -1,38 +1,59 @@
<?php
+
+/*
+ * Copyright 2010,2011 Alexander Sadleir
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
date_default_timezone_set('Australia/ACT');
$debugOkay = Array(
- "session",
- "json",
- "phperror",
- "awsotp",
- //"squallotp",
- //"vanilleotp",
- "database",
- "other"
+ "session",
+ "json",
+ "phperror",
+ "awsotp",
+ //"squallotp",
+ //"vanilleotp",
+ "database",
+ "other"
);
+$GTFSREnabled = true;
$cloudmadeAPIkey = "daa03470bb8740298d4b10e3f03d63e6";
$googleMapsAPIkey = "ABQIAAAA95XYXN0cki3Yj_Sb71CFvBTPaLd08ONybQDjcH_VdYtHHLgZvRTw2INzI_m17_IoOUqH3RNNmlTk1Q";
$otpAPIurl = 'http://localhost:8080/opentripplanner-api-webapp/';
if (isDebug("awsotp") || php_uname('n') == "maxious.xen.prgmr.com") {
- $otpAPIurl = 'http://bus-main.lambdacomplex.org:8080/opentripplanner-api-webapp/';
+ $otpAPIurl = 'http://bus-main.lambdacomplex.org:8080/opentripplanner-api-webapp/';
}
if (isDebug("dotcloudotp") || php_uname('n') == "actbus-www") {
- $otpAPIurl = 'http://otp.actbus.dotcloud.com/opentripplanner-api-webapp/';
+ $otpAPIurl = 'http://otp.actbus.dotcloud.com/opentripplanner-api-webapp/';
}
if (isDebug("squallotp")) {
- $otpAPIurl = 'http://10.0.1.108:5080/opentripplanner-api-webapp/';
+ $otpAPIurl = 'http://10.0.1.108:5080/opentripplanner-api-webapp/';
}
if (isDebug("vanilleotp")) {
- $otpAPIurl = 'http://10.0.1.135:8080/opentripplanner-api-webapp/';
-}
-if (isDebug("phperror")) error_reporting(E_ALL ^ E_NOTICE);
-$labsPath = "";
-if (strstr($_SERVER['PHP_SELF'],"labs")) $labsPath = "../";
-
-function isDebugServer()
-{
- return php_sapi_name() == "cli" || isset($_SERVER['SERVER_NAME']) && ( $_SERVER['SERVER_NAME'] == "10.0.1.154" || $_SERVER['SERVER_NAME'] == "10.1.0.4" || $_SERVER['SERVER_NAME'] ==
-"localhost" || $_SERVER['SERVER_NAME'] == "127.0.0.1") ;
+ $otpAPIurl = 'http://10.0.1.135:8080/opentripplanner-api-webapp/';
+}
+if (isDebug("phperror"))
+ error_reporting(E_ALL ^ E_NOTICE);
+$basePath = "";
+if (strstr($_SERVER['PHP_SELF'], "labs/")
+ || strstr($_SERVER['PHP_SELF'], "myway/")
+ || strstr($_SERVER['PHP_SELF'], "servicealerts/"))
+ $basePath = "../";
+
+function isDebugServer() {
+ return php_sapi_name() == "cli" || isset($_SERVER['SERVER_NAME']) && ( $_SERVER['SERVER_NAME'] == "azusa" || $_SERVER['SERVER_NAME'] == "vanille"
+ || $_SERVER['SERVER_NAME'] == "localhost" || $_SERVER['SERVER_NAME'] == "127.0.0.1");
}
include_once ("common-geo.inc.php");
@@ -42,149 +63,157 @@
include_once ("common-request.inc.php");
include_once ("common-session.inc.php");
+include_once ("common-auth.inc.php");
include_once ("common-template.inc.php");
-
-function isAnalyticsOn()
-{
- return !isDebugServer();
-}
-function isDebug($debugReason = "other")
-{
- global $debugOkay;
- return in_array($debugReason, $debugOkay, false) && isDebugServer();
-}
-function debug($msg, $debugReason = "other")
-{
- if (isDebug($debugReason)) echo "\n<!-- " . date(DATE_RFC822) . "\n $msg -->\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(")", "</small>", str_replace("(", "<br><small>", $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;
-}
-function sktimesort(&$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 strtotime($val[$subkey]) > strtotime($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 && isset($temp_array)) $array = array_reverse($temp_array);
- else $array = $temp_array;
-}
-function r_implode( $glue, $pieces )
-{
- foreach( $pieces as $r_pieces )
- {
- if( is_array( $r_pieces ) )
- {
- $retVal[] = r_implode( $glue, $r_pieces );
- }
- else
- {
- $retVal[] = $r_pieces;
- }
- }
- return implode( $glue, $retVal );
-}
+function isAnalyticsOn() {
+ $user_agent = $_SERVER['HTTP_USER_AGENT'];
+ return!isDebugServer() && !preg_match('/cloudkick/i', $user_agent) && !preg_match('/googlebot/i', $user_agent) &&
+ !preg_match('/baidu/i', $user_agent);
+}
+
+function isDebug($debugReason = "other") {
+ global $debugOkay;
+ return in_array($debugReason, $debugOkay, false) && isDebugServer();
+}
+
+function debug($msg, $debugReason = "other") {
+ if (isDebug($debugReason))
+ echo "\n<!-- " . date(DATE_RFC822) . "\n $msg -->\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(")", "</small>", str_replace("(", "<br><small>", $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;
+}
+
+function sktimesort(&$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 strtotime($val[$subkey]) > strtotime($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 && isset($temp_array))
+ $array = array_reverse($temp_array);
+ else
+ $array = $temp_array;
+}
+
+function r_implode($glue, $pieces) {
+ foreach ($pieces as $r_pieces) {
+ if (is_array($r_pieces)) {
+ $retVal[] = r_implode($glue, $r_pieces);
+ } else {
+ $retVal[] = $r_pieces;
+ }
+ }
+ return implode($glue, $retVal);
+}
+
?>
--- a/include/db/route-dao.inc.php
+++ b/include/db/route-dao.inc.php
@@ -1,211 +1,229 @@
<?php
-function getRoute($routeID)
-{
- global $conn;
- $query = "Select * from routes where route_id = :routeID LIMIT 1";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":routeID", $routeID);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetch(PDO::FETCH_ASSOC);
-}
-
-function getRouteByFullName($routeFullName)
-{
- global $conn;
- $query = "Select * from routes where route_short_name||route_long_name = :routeFullName LIMIT 1";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":routeFullName", $routeFullName);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetch(PDO::FETCH_ASSOC);
-}
-
-function getRoutes()
-{
- global $conn;
- $query = "Select * from routes order by route_short_name;";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetchAll();
-}
-function getRoutesByNumber($routeNumber = "")
-{
- global $conn;
- if ($routeNumber != "") {
- $query = "Select distinct routes.route_id,routes.route_short_name,routes.route_long_name,service_id from routes join trips on trips.route_id =
+
+/*
+ * Copyright 2010,2011 Alexander Sadleir
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+function getRoute($routeID) {
+ global $conn;
+ $query = "Select * from routes where route_id = :routeID LIMIT 1";
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":routeID", $routeID);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetch(PDO :: FETCH_ASSOC);
+}
+
+function getRouteByFullName($routeFullName) {
+ global $conn;
+ $query = "Select * from routes where route_short_name||route_long_name = :routeFullName LIMIT 1";
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":routeFullName", $routeFullName);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetch(PDO :: FETCH_ASSOC);
+}
+
+function getRoutes() {
+ global $conn;
+ $query = "Select * from routes order by route_short_name;";
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetchAll();
+}
+
+function getRoutesByNumber($routeNumber = "") {
+ global $conn;
+ if ($routeNumber != "") {
+ $query = "Select distinct routes.route_id,routes.route_short_name,routes.route_long_name,service_id from routes join trips on trips.route_id =
routes.route_id join stop_times on stop_times.trip_id = trips.trip_id
where route_short_name = :routeNumber OR route_short_name LIKE :routeNumber2 order by route_short_name;";
- }
- else {
- $query = "SELECT DISTINCT route_short_name from routes order by route_short_name";
- }
- debug($query, "database");
- $query = $conn->prepare($query);
- if ($routeNumber != "") {
- $query->bindParam(":routeNumber", $routeNumber);
- $routeNumber2 = "% ".$routeNumber;
- $query->bindParam(":routeNumber2", $routeNumber2);
- }
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetchAll();
-}
-function getRoutesByNumberSeries($routeNumberSeries = "")
-{
- global $conn;
- if (strlen($routeNumberSeries) == 1) {
- return getRoutesByNumber($routeNumberSeries);
- }
- $seriesMin = substr($routeNumberSeries, 0, -1) . "0";
- $seriesMax = substr($routeNumberSeries, 0, -1) . "9";
- $query = "Select distinct routes.route_id,routes.route_short_name,routes.route_long_name,service_id from routes join trips on trips.route_id =
+ } else {
+ $query = "SELECT DISTINCT route_short_name from routes order by route_short_name";
+ }
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ if ($routeNumber != "") {
+ $query->bindParam(":routeNumber", $routeNumber);
+ $routeNumber2 = "% " . $routeNumber;
+ $query->bindParam(":routeNumber2", $routeNumber2);
+ }
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetchAll();
+}
+
+function getRoutesByNumberSeries($routeNumberSeries = "") {
+ global $conn;
+ if (strlen($routeNumberSeries) == 1) {
+ return getRoutesByNumber($routeNumberSeries);
+ }
+ $seriesMin = substr($routeNumberSeries, 0, -1) . "0";
+ $seriesMax = substr($routeNumberSeries, 0, -1) . "9";
+ $query = "Select distinct routes.route_id,routes.route_short_name,routes.route_long_name,service_id from routes join trips on trips.route_id =
routes.route_id join stop_times on stop_times.trip_id = trips.trip_id where to_number(route_short_name, 'FM999') between :seriesMin and :seriesMax OR route_short_name LIKE :routeNumberSeries order by route_short_name;";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":seriesMin", $seriesMin);
- $query->bindParam(":seriesMax", $seriesMax);
- $routeNumberSeries = "% ".substr($routeNumberSeries, 0, -1)."%";
- $query->bindParam(":routeNumberSeries", $routeNumberSeries);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetchAll();
-}
-function getRouteNextTrip($routeID)
-{
- global $conn;
- $query = "select * from routes join trips on trips.route_id = routes.route_id
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":seriesMin", $seriesMin);
+ $query->bindParam(":seriesMax", $seriesMax);
+ $routeNumberSeries = "% " . substr($routeNumberSeries, 0, -1) . "%";
+ $query->bindParam(":routeNumberSeries", $routeNumberSeries);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetchAll();
+}
+
+function getRouteNextTrip($routeID) {
+ global $conn;
+ $query = "select * from routes join trips on trips.route_id = routes.route_id
join stop_times on stop_times.trip_id = trips.trip_id where
arrival_time > :currentTime and routes.route_id = :routeID order by
arrival_time limit 1";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":currentTime", current_time());
- $query->bindParam(":routeID", $routeID);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- $r = $query->fetch(PDO::FETCH_ASSOC);
-
- // past last trip of the day special case
- if (sizeof($r) < 16) {
- $query = "select * from routes join trips on trips.route_id = routes.route_id
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":currentTime", current_time());
+ $query->bindParam(":routeID", $routeID);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ $r = $query->fetch(PDO :: FETCH_ASSOC);
+
+ // past last trip of the day special case
+ if (sizeof($r) < 16) {
+ $query = "select * from routes join trips on trips.route_id = routes.route_id
join stop_times on stop_times.trip_id = trips.trip_id where routes.route_id = :routeID order by
arrival_time DESC limit 1";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":routeID", $routeID);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
-
- $r = $query->fetch(PDO::FETCH_ASSOC);
- }
- return $r;
-}
-function getTimeInterpolatedRouteAtStop($routeID, $stop_id)
-{
- $nextTrip = getRouteNextTrip($routeID);
- if ($nextTrip['trip_id']) {
- foreach (getTimeInterpolatedTrip($nextTrip['trip_id']) as $tripStop) {
- if ($tripStop['stop_id'] == $stop_id) return $tripStop;
- }
- }
- return Array();
-}
-function getRouteTrips($routeID)
-{
- global $conn;
- $query = "select routes.route_id,trips.trip_id,service_id,arrival_time, stop_id, stop_sequence from routes join trips on trips.route_id = routes.route_id
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":routeID", $routeID);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+
+ $r = $query->fetch(PDO :: FETCH_ASSOC);
+ }
+ return $r;
+}
+
+function getTimeInterpolatedRouteAtStop($routeID, $stop_id) {
+ $nextTrip = getRouteNextTrip($routeID);
+ if ($nextTrip['trip_id']) {
+ foreach (getTimeInterpolatedTrip($nextTrip['trip_id']) as $tripStop) {
+ if ($tripStop['stop_id'] == $stop_id)
+ return $tripStop;
+ }
+ }
+ return Array();
+}
+
+function getRouteTrips($routeID) {
+ global $conn;
+ $query = "select routes.route_id,trips.trip_id,service_id,arrival_time, stop_id, stop_sequence from routes join trips on trips.route_id = routes.route_id
join stop_times on stop_times.trip_id = trips.trip_id where routes.route_id = :routeID and stop_sequence = '1' order by
arrival_time ";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":routeID", $routeID);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetchAll();
-}
-function getRoutesByDestination($destination = "", $service_period = "")
-{
- global $conn;
- if ($service_period == "") $service_period = service_period();
- if ($destination != "") {
- $query = "SELECT DISTINCT trips.route_id,route_short_name,route_long_name, service_id
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":routeID", $routeID);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetchAll();
+}
+
+function getRoutesByDestination($destination = "", $service_period = "") {
+ global $conn;
+ if ($service_period == "")
+ $service_period = service_period();
+ if ($destination != "") {
+ $query = "SELECT DISTINCT trips.route_id,route_short_name,route_long_name, service_id
FROM stop_times join trips on trips.trip_id =
stop_times.trip_id join routes on trips.route_id = routes.route_id
WHERE route_long_name = :destination AND service_id=:service_period order by route_short_name";
- }
- else {
- $query = "SELECT DISTINCT route_long_name
+ } else {
+ $query = "SELECT DISTINCT route_long_name
FROM stop_times join trips on trips.trip_id =
stop_times.trip_id join routes on trips.route_id = routes.route_id
WHERE service_id= :service_period order by route_long_name";
- }
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":service_period", $service_period);
- if ($destination != "") $query->bindParam(":destination", $destination);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetchAll();
-}
-function getRoutesBySuburb($suburb, $service_period = "")
-{
- if ($service_period == "") $service_period = service_period();
- global $conn;
- $query = "SELECT DISTINCT service_id,trips.route_id,route_short_name,route_long_name
+ }
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":service_period", $service_period);
+ if ($destination != "")
+ $query->bindParam(":destination", $destination);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetchAll();
+}
+
+function getRoutesBySuburb($suburb, $service_period = "") {
+ if ($service_period == "")
+ $service_period = service_period();
+ global $conn;
+ $query = "SELECT DISTINCT service_id,trips.route_id,route_short_name,route_long_name
FROM stop_times join trips on trips.trip_id = stop_times.trip_id
join routes on trips.route_id = routes.route_id
join stops on stops.stop_id = stop_times.stop_id
WHERE zone_id LIKE ':suburb AND service_id=:service_period ORDER BY route_short_name";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":service_period", $service_period);
- $suburb = "%" . $suburb . ";%";
- $query->bindParam(":suburb", $suburb);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetchAll();
-}
-function getRoutesNearby($lat, $lng, $limit = "", $distance = 500)
-{
- if ($service_period == "") $service_period = service_period();
- if ($limit != "") $limitSQL = " LIMIT :limit ";
- global $conn;
- $query = "SELECT service_id,trips.route_id,route_short_name,route_long_name,min(stops.stop_id) as stop_id,
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":service_period", $service_period);
+ $suburb = "%" . $suburb . ";%";
+ $query->bindParam(":suburb", $suburb);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetchAll();
+}
+
+function getRoutesNearby($lat, $lng, $limit = "", $distance = 500) {
+ if ($service_period == "")
+ $service_period = service_period();
+ if ($limit != "")
+ $limitSQL = " LIMIT :limit ";
+ global $conn;
+ $query = "SELECT service_id,trips.route_id,route_short_name,route_long_name,min(stops.stop_id) as stop_id,
min(ST_Distance(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), FALSE)) as distance
FROM stop_times
join trips on trips.trip_id = stop_times.trip_id
@@ -215,16 +233,18 @@
AND ST_DWithin(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), :distance, FALSE)
group by service_id,trips.route_id,route_short_name,route_long_name
order by distance $limitSQL";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":service_period", $service_period);
- $query->bindParam(":distance", $distance);
- if ($limit != "") $query->bindParam(":limit", $limit);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetchAll();
-}
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":service_period", $service_period);
+ $query->bindParam(":distance", $distance);
+ if ($limit != "")
+ $query->bindParam(":limit", $limit);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetchAll();
+}
+
?>
--- a/include/db/servicealert-dao.inc.php
+++ b/include/db/servicealert-dao.inc.php
@@ -1,53 +1,177 @@
<?php
-function getServiceOverride($date="") {
- global $conn;
- $query = "Select * from calendar_dates where date = :date and exception_type = '1' LIMIT 1";
- // debug($query,"database");
- $query = $conn->prepare($query); // Create a prepared statement
- $query->bindParam(":date", date("Ymd",($date != "" ? $date : time())));
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetch(PDO::FETCH_ASSOC);
+
+/*
+ * Copyright 2010,2011 Alexander Sadleir
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+function getServiceOverride($date = "") {
+ global $conn;
+ $query = "Select * from calendar_dates where date = :date and exception_type = '1' LIMIT 1";
+ // debug($query,"database");
+ $query = $conn->prepare($query); // Create a prepared statement
+ $query->bindParam(":date", date("Ymd", ($date != "" ? $date : time())));
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetch(PDO :: FETCH_ASSOC);
+}
+
+function getServiceAlert($alertID) {
+ global $conn;
+ $query = "SELECT id,extract('epoch', start) as start, extract('epoch', end) as end,cause,effect,header,description,url from servicealerts_alerts where id = :servicealert_id";
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":servicealert_id", $alertID);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetch(PDO :: FETCH_ASSOC);
+}
+
+function updateServiceAlert($alertID, $start, $end, $header, $description, $url) {
+ global $conn;
+ $query = 'update servicealerts_alerts set start=:start, "end"=:end, header=:header, description=:description, url=:url where id = :servicealert_id';
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":servicealert_id", $alertID);
+ $query->bindParam(":start", $start);
+ $query->bindParam(":end", $end);
+ $query->bindParam(":header", $header);
+ $query->bindParam(":description", $description);
+ $query->bindParam(":url", $url);
+ $query->execute();
+
+ print_r($conn->errorInfo());
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetch(PDO :: FETCH_ASSOC);
+}
+
+function addServiceAlert($start, $end, $header, $description, $url) {
+ global $conn;
+ $query = 'INSERT INTO servicealerts_alerts (start, "end", header, description, url) VALUES (:start, :end, :header, :description, :url) ';
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":start", $start);
+ $query->bindParam(":end", $end);
+ $query->bindParam(":header", $header);
+ $query->bindParam(":description", $description);
+ $query->bindParam(":url", $url);
+ $query->execute();
+
+ print_r($conn->errorInfo());
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetch(PDO :: FETCH_ASSOC);
}
function getCurrentAlerts() {
- global $conn;
- $query = "SELECT * from servicealerts_alerts";
- //debug($query, "database");
- $query = $conn->prepare($query);
- //if ($stop_sequence != "") $query->bindParam(":stop_sequence", $stop_sequence);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetchAll();
+ global $conn;
+ $query = "SELECT id,extract('epoch', start) as start, extract('epoch', end) as end,cause,effect,header,description,url from servicealerts_alerts where NOW() > start and NOW() < \"end\"";
+ // debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetchAll();
}
-function getInformedAlerts($id,$filter_class,$filter_id) {
-
- global $conn;
- $query = "SELECT * from servicealerts_informed where servicealert_id = :servicealert_id";
-
- if ($filter_class != "" && $filter_id != "") {
- $query .= " AND (informed_class = :informed_class OR informed_class = 'network') AND informed_id = :informed_id";
-
- }
- //debug($query, "database");
- $query = $conn->prepare($query);
- if ($filter_class != "" && $filter_id != "") {
- $query->bindParam(":informed_class", $filter_class);
- $query->bindParam(":informed_id", $filter_id);
- }
- $query->bindParam(":servicealert_id", $id);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetchAll();
+
+function getFutureAlerts() {
+ global $conn;
+ $query = "SELECT id,extract('epoch', start) as start, extract('epoch', end) as end,cause,effect,header,description,url from servicealerts_alerts where NOW() > start or NOW() < \"end\"";
+ // debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetchAll();
+}
+
+function getInformedAlerts($id, $filter_class, $filter_id) {
+
+ global $conn;
+ $query = "SELECT * from servicealerts_informed where servicealert_id = :servicealert_id";
+
+ if ($filter_class != "") {
+ $query .= " AND informed_class = :informed_class ";
+ }
+ if ($filter_id != "") {
+ $query .= " AND informed_id = :informed_id ";
+ }
+ // debug($query, "database");
+ $query = $conn->prepare($query);
+ if ($filter_class != "") {
+ $query->bindParam(":informed_class", $filter_class);
+ }
+ if ($filter_id != "") {
+ $query->bindParam(":informed_id", $filter_id);
+ }
+ $query->bindParam(":servicealert_id", $id);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetchAll();
+}
+
+function deleteInformedAlert($serviceAlertID, $class, $id) {
+ global $conn;
+ $query = 'DELETE from servicealerts_informed where servicealert_id = :servicealert_id and informed_class = :informed_class AND informed_id = :informed_id';
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":servicealert_id", $serviceAlertID);
+ $query->bindParam(":informed_class", $class);
+ $query->bindParam(":informed_id", $id);
+ $query->execute();
+ print_r($conn->errorInfo());
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return null;
+}
+
+function addInformedAlert($serviceAlertID, $class, $id, $action) {
+ global $conn;
+ $query = 'INSERT INTO servicealerts_informed (servicealert_id , informed_class , informed_id) VALUES(:servicealert_id ,:informed_class, :informed_id)';
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":servicealert_id", $serviceAlertID);
+ $query->bindParam(":informed_class", $class);
+ $query->bindParam(":informed_id", $id);
+ $query->execute();
+
+ print_r($conn->errorInfo());
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return null;
}
?>
--- a/include/db/stop-dao.inc.php
+++ b/include/db/stop-dao.inc.php
@@ -1,131 +1,171 @@
<?php
-function getStop($stopID)
-{
- global $conn;
- $query = "Select * from stops where stop_id = :stopID LIMIT 1";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":stopID", $stopID);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetch(PDO::FETCH_ASSOC);
-}
-function getStops($timingPointsOnly = false, $firstLetter = "", $startsWith = "")
-{
- global $conn;
- $conditions = Array();
- if ($timingPointsOnly) $conditions[] = "substr(stop_code,1,2) != 'Wj'";
- if ($firstLetter != "") $conditions[] = "substr(stop_name,1,1) = :firstLetter";
- if ($startsWith != "") $conditions[] = "stop_name like :startsWith";
- $query = "Select * from stops";
- if (sizeof($conditions) > 0) {
- if (sizeof($conditions) > 1) {
- $query.= " Where " . implode(" AND ", $conditions) . " ";
- }
- else {
- $query.= " Where " . $conditions[0] . " ";
- }
- }
- $query.= " order by stop_name;";
- $query = $conn->prepare($query);
- if ($firstLetter != "") $query->bindParam(":firstLetter", $firstLetter);
-
- if ($startsWith != "") {
- $startsWith = $startsWith."%";
- $query->bindParam(":startsWith", $startsWith);
+
+/*
+ * Copyright 2010,2011 Alexander Sadleir
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+function getStop($stopID) {
+ global $conn;
+ $query = "Select * from stops where stop_id = :stopID LIMIT 1";
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":stopID", $stopID);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetch(PDO :: FETCH_ASSOC);
+}
+
+function getStops($timingPointsOnly = false, $firstLetter = "", $startsWith = "") {
+ global $conn;
+ $conditions = Array();
+ if ($timingPointsOnly)
+ $conditions[] = "substr(stop_code,1,2) != 'Wj'";
+ if ($firstLetter != "")
+ $conditions[] = "substr(stop_name,1,1) = :firstLetter";
+ if ($startsWith != "")
+ $conditions[] = "stop_name like :startsWith";
+ $query = "Select * from stops";
+ if (sizeof($conditions) > 0) {
+ if (sizeof($conditions) > 1) {
+ $query .= " Where " . implode(" AND ", $conditions) . " ";
+ } else {
+ $query .= " Where " . $conditions[0] . " ";
}
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetchAll();
-}
-function getNearbyStops($lat, $lng, $limit = "", $distance = 1000)
-{
- if ($lat == null || $lng == null) return Array();
- if ($limit != "") $limitSQL = " LIMIT :limit ";
- global $conn;
- $query = "Select *, ST_Distance(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), FALSE) as distance
+ }
+ $query .= " order by stop_name;";
+ $query = $conn->prepare($query);
+ if ($firstLetter != "")
+ $query->bindParam(":firstLetter", $firstLetter);
+
+ if ($startsWith != "") {
+ $startsWith = $startsWith . "%";
+ $query->bindParam(":startsWith", $startsWith);
+ }
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetchAll();
+}
+
+function getNearbyStops($lat, $lng, $limit = "", $distance = 1000) {
+ if ($lat == null || $lng == null)
+ return Array();
+ if ($limit != "")
+ $limitSQL = " LIMIT :limit ";
+ global $conn;
+ $query = "Select *, ST_Distance(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), FALSE) as distance
from stops WHERE ST_DWithin(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), :distance, FALSE)
order by distance $limitSQL;";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":distance", $distance);
- $query->bindParam(":limit", $limit);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetchAll();
-}
-function getStopsBySuburb($suburb)
-{
- global $conn;
- $query = "Select * from stops where zone_id LIKE :suburb order by stop_name;";
- debug($query, "database");
- $query = $conn->prepare($query);
- $suburb = "%" . $suburb . ";%";
- $query->bindParam(":suburb", $suburb);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetchAll();
-}
-function getStopsByStopCode($stop_code,$startsWith = "")
-{
- global $conn;
- $query = "Select * from stops where (stop_code = :stop_code OR stop_code LIKE :stop_code2)";
- if ($startsWith != "") $query .= " AND stop_name like :startsWith";
-
- debug($query, "database");
- $query = $conn->prepare($query);
-
- $query->bindParam(":stop_code", $stop_code);
- $stop_code2 = $stop_code . "%";
- $query->bindParam(":stop_code2", $stop_code2);
- if ($startsWith != "") {
- $startsWith = $startsWith."%";
- $query->bindParam(":startsWith", $startsWith);
- }
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetchAll();
-}
-function getStopRoutes($stopID, $service_period)
-{
- if ($service_period == "") $service_period = service_period();
- global $conn;
- $query = "SELECT distinct service_id,trips.route_id,route_short_name,route_long_name
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":distance", $distance);
+ $query->bindParam(":limit", $limit);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetchAll();
+}
+
+function getStopsByName($name) {
+ global $conn;
+ $query = "Select * from stops where stop_name LIKE :name;";
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $name = "%" . $name . ";%";
+ $query->bindParam(":name", $name);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetchAll();
+}
+
+function getStopsBySuburb($suburb) {
+ global $conn;
+ $query = "Select * from stops where zone_id LIKE :suburb order by stop_name;";
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $suburb = "%" . $suburb . ";%";
+ $query->bindParam(":suburb", $suburb);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetchAll();
+}
+
+function getStopsByStopCode($stop_code, $startsWith = "") {
+ global $conn;
+ $query = "Select * from stops where (stop_code = :stop_code OR stop_code LIKE :stop_code2)";
+ if ($startsWith != "")
+ $query .= " AND stop_name like :startsWith";
+
+ debug($query, "database");
+ $query = $conn->prepare($query);
+
+ $query->bindParam(":stop_code", $stop_code);
+ $stop_code2 = $stop_code . "%";
+ $query->bindParam(":stop_code2", $stop_code2);
+ if ($startsWith != "") {
+ $startsWith = $startsWith . "%";
+ $query->bindParam(":startsWith", $startsWith);
+ }
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetchAll();
+}
+
+function getStopRoutes($stopID, $service_period) {
+ if ($service_period == "")
+ $service_period = service_period();
+ global $conn;
+ $query = "SELECT distinct service_id,trips.route_id,route_short_name,route_long_name
FROM stop_times join trips on trips.trip_id =
stop_times.trip_id join routes on trips.route_id = routes.route_id WHERE stop_id = :stopID AND service_id=:service_period";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":service_period", $service_period);
- $query->bindParam(":stopID", $stopID);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetchAll();
-}
-function getStopTrips($stopID, $service_period = "", $afterTime = "", $limit = "")
-{
- if ($service_period == "") $service_period = service_period();
- if ($limit != "") $limitSQL = " LIMIT :limit ";
- global $conn;
- if ($afterTime != "") {
- $query = " SELECT stop_times.trip_id,stop_times.arrival_time,stop_times.stop_id,stop_sequence,service_id,trips.route_id,route_short_name,route_long_name, end_times.arrival_time as end_time
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":service_period", $service_period);
+ $query->bindParam(":stopID", $stopID);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetchAll();
+}
+
+function getStopTrips($stopID, $service_period = "", $afterTime = "", $limit = "") {
+ if ($service_period == "")
+ $service_period = service_period();
+ if ($limit != "")
+ $limitSQL = " LIMIT :limit ";
+ global $conn;
+ if ($afterTime != "") {
+ $query = " SELECT stop_times.trip_id,stop_times.arrival_time,stop_times.stop_id,stop_sequence,service_id,trips.route_id,route_short_name,route_long_name, end_times.arrival_time as end_time
FROM stop_times
join trips on trips.trip_id =
stop_times.trip_id
@@ -136,9 +176,8 @@
AND service_id=:service_period
AND end_times.arrival_time > :afterTime
ORDER BY end_time $limitSQL";
- }
- else {
- $query = "SELECT stop_times.trip_id,arrival_time,stop_times.stop_id,stop_sequence,service_id,trips.route_id,route_short_name,route_long_name
+ } else {
+ $query = "SELECT stop_times.trip_id,arrival_time,stop_times.stop_id,stop_sequence,service_id,trips.route_id,route_short_name,route_long_name
FROM stop_times
join trips on trips.trip_id =
stop_times.trip_id
@@ -146,45 +185,52 @@
WHERE stop_times.stop_id = :stopID
AND service_id=:service_period
ORDER BY arrival_time $limitSQL";
- }
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":service_period", $service_period);
- $query->bindParam(":stopID", $stopID);
- if ($limit != "") $query->bindParam(":limit", $limit);
- if ($afterTime != "") $query->bindParam(":afterTime", $afterTime);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetchAll();
-}
-function getStopTripsWithTimes($stopID, $time = "", $service_period = "", $time_range = "", $limit = "")
-{
- if ($service_period == "") $service_period = service_period();
- if ($time_range == "") $time_range = (24 * 60 * 60);
- if ($time == "") $time = current_time();
- if ($limit == "") $limit = 10;
- $trips = getStopTrips($stopID, $service_period, $time);
- $timedTrips = Array();
- if ($trips && sizeof($trips) > 0) {
- foreach ($trips as $trip) {
- if ($trip['arrival_time'] != "") {
- if (strtotime($trip['arrival_time']) > strtotime($time) and strtotime($trip['arrival_time']) < (strtotime($time) + $time_range)) {
- $timedTrips[] = $trip;
- }
- }
- else {
- $timedTrip = getTimeInterpolatedTripAtStop($trip['trip_id'], $trip['stop_sequence']);
- if ($timedTrip['arrival_time'] > $time and strtotime($timedTrip['arrival_time']) < (strtotime($time) + $time_range)) {
- $timedTrips[] = $timedTrip;
- }
- }
- if (sizeof($timedTrips) > $limit) break;
- }
- sktimesort($timedTrips, "arrival_time", true);
+ }
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":service_period", $service_period);
+ $query->bindParam(":stopID", $stopID);
+ if ($limit != "")
+ $query->bindParam(":limit", $limit);
+ if ($afterTime != "")
+ $query->bindParam(":afterTime", $afterTime);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetchAll();
+}
+
+function getStopTripsWithTimes($stopID, $time = "", $service_period = "", $time_range = "", $limit = "") {
+ if ($service_period == "")
+ $service_period = service_period();
+ if ($time_range == "")
+ $time_range = (24 * 60 * 60);
+ if ($time == "")
+ $time = current_time();
+ if ($limit == "")
+ $limit = 10;
+ $trips = getStopTrips($stopID, $service_period, $time);
+ $timedTrips = Array();
+ if ($trips && sizeof($trips) > 0) {
+ foreach ($trips as $trip) {
+ if ($trip['arrival_time'] != "") {
+ if (strtotime($trip['arrival_time']) > strtotime($time) and strtotime($trip['arrival_time']) < (strtotime($time) + $time_range)) {
+ $timedTrips[] = $trip;
+ }
+ } else {
+ $timedTrip = getTimeInterpolatedTripAtStop($trip['trip_id'], $trip['stop_sequence']);
+ if ($timedTrip['arrival_time'] > $time and strtotime($timedTrip['arrival_time']) < (strtotime($time) + $time_range)) {
+ $timedTrips[] = $timedTrip;
+ }
+ }
+ if (sizeof($timedTrips) > $limit)
+ break;
}
- return $timedTrips;
-}
+ sktimesort($timedTrips, "arrival_time", true);
+ }
+ return $timedTrips;
+}
+
?>
--- a/include/db/trip-dao.inc.php
+++ b/include/db/trip-dao.inc.php
@@ -1,240 +1,256 @@
<?php
-function getTrip($tripID)
-{
- global $conn;
- $query = "Select * from trips
+
+/*
+ * Copyright 2010,2011 Alexander Sadleir
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+function getTrip($tripID) {
+ global $conn;
+ $query = "Select * from trips
join routes on trips.route_id = routes.route_id
where trip_id = :tripID
LIMIT 1";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":tripID", $tripID);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetch(PDO::FETCH_ASSOC);
-}
-function getTripShape($tripID)
-{
- global $conn;
- $query = "SELECT ST_AsKML(ST_MakeLine(geometry(a.position))) as the_route
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":tripID", $tripID);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetch(PDO :: FETCH_ASSOC);
+}
+
+function getTripShape($tripID) {
+ global $conn;
+ $query = "SELECT ST_AsKML(ST_MakeLine(geometry(a.position))) as the_route
FROM (SELECT position,
stop_sequence, trips.trip_id
FROM stop_times
join trips on trips.trip_id = stop_times.trip_id
join stops on stops.stop_id = stop_times.stop_id
WHERE trips.trip_id = :tripID ORDER BY stop_sequence) as a group by a.trip_id";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":tripID", $tripID);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetchColumn(0);
-}
-function getTimeInterpolatedTrip($tripID, $range = "")
-{
- global $conn;
- $query = "SELECT stop_times.trip_id,arrival_time,stop_times.stop_id,stop_lat,stop_lon,stop_name,stop_code,
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":tripID", $tripID);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetchColumn(0);
+}
+
+function getTimeInterpolatedTrip($tripID, $range = "") {
+ global $conn;
+ $query = "SELECT stop_times.trip_id,arrival_time,stop_times.stop_id,stop_lat,stop_lon,stop_name,stop_code,
stop_sequence,service_id,trips.route_id,route_short_name,route_long_name
FROM stop_times
join trips on trips.trip_id = stop_times.trip_id
join routes on trips.route_id = routes.route_id
join stops on stops.stop_id = stop_times.stop_id
WHERE trips.trip_id = :tripID $range ORDER BY stop_sequence";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":tripID", $tripID);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- $stopTimes = $query->fetchAll();
- $cur_timepoint = Array();
- $next_timepoint = Array();
- $distance_between_timepoints = 0.0;
- $distance_traveled_between_timepoints = 0.0;
- $rv = Array();
- foreach ($stopTimes as $i => $stopTime) {
- if ($stopTime['arrival_time'] != "") {
- // is timepoint
- $cur_timepoint = $stopTime;
- $distance_between_timepoints = 0.0;
- $distance_traveled_between_timepoints = 0.0;
- if ($i + 1 < sizeof($stopTimes)) {
- $k = $i + 1;
- $distance_between_timepoints+= distance($stopTimes[$k - 1]["stop_lat"], $stopTimes[$k - 1]["stop_lon"], $stopTimes[$k]["stop_lat"], $stopTimes[$k]["stop_lon"]);
- while ($stopTimes[$k]["arrival_time"] == "" && $k + 1 < sizeof($stopTimes)) {
- $k+= 1;
- //echo "k".$k;
- $distance_between_timepoints+= distance($stopTimes[$k - 1]["stop_lat"], $stopTimes[$k - 1]["stop_lon"], $stopTimes[$k]["stop_lat"], $stopTimes[$k]["stop_lon"]);
- }
- $next_timepoint = $stopTimes[$k];
-
- }
- $rv[] = $stopTime;
- }
- else {
- // is untimed point
- //echo "i".$i;
- $distance_traveled_between_timepoints+= distance($stopTimes[$i - 1]["stop_lat"], $stopTimes[$i - 1]["stop_lon"], $stopTimes[$i]["stop_lat"], $stopTimes[$i]["stop_lon"]);
- //echo "$distance_traveled_between_timepoints / $distance_between_timepoints<br>";
- $distance_percent = $distance_traveled_between_timepoints / $distance_between_timepoints;
- if ($next_timepoint["arrival_time"] != "") {
- $total_time = strtotime($next_timepoint["arrival_time"]) - strtotime($cur_timepoint["arrival_time"]);
- //echo strtotime($next_timepoint["arrival_time"])." - ".strtotime($cur_timepoint["arrival_time"])."<br>";
- $time_estimate = ($distance_percent * $total_time) + strtotime($cur_timepoint["arrival_time"]);
- $stopTime["arrival_time"] = date("H:i:s", $time_estimate);
- }
- else {
- $stopTime["arrival_time"] = $cur_timepoint["arrival_time"];
- }
- $rv[] = $stopTime;
-
-
- }
- }
- //var_dump($rv);
- return $rv;
-}
-function getTripPreviousTimePoint($tripID, $stop_sequence)
-{
- global $conn;
- $query = " SELECT trip_id,stop_id,
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":tripID", $tripID);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ $stopTimes = $query->fetchAll();
+ $cur_timepoint = Array();
+ $next_timepoint = Array();
+ $distance_between_timepoints = 0.0;
+ $distance_traveled_between_timepoints = 0.0;
+ $rv = Array();
+ foreach ($stopTimes as $i => $stopTime) {
+ if ($stopTime['arrival_time'] != "") {
+ // is timepoint
+ $cur_timepoint = $stopTime;
+ $distance_between_timepoints = 0.0;
+ $distance_traveled_between_timepoints = 0.0;
+ if ($i + 1 < sizeof($stopTimes)) {
+ $k = $i + 1;
+ $distance_between_timepoints += distance($stopTimes[$k - 1]["stop_lat"], $stopTimes[$k - 1]["stop_lon"], $stopTimes[$k]["stop_lat"], $stopTimes[$k]["stop_lon"]);
+ while ($stopTimes[$k]["arrival_time"] == "" && $k + 1 < sizeof($stopTimes)) {
+ $k += 1;
+ // echo "k".$k;
+ $distance_between_timepoints += distance($stopTimes[$k - 1]["stop_lat"], $stopTimes[$k - 1]["stop_lon"], $stopTimes[$k]["stop_lat"], $stopTimes[$k]["stop_lon"]);
+ }
+ $next_timepoint = $stopTimes[$k];
+ }
+ $rv[] = $stopTime;
+ } else {
+ // is untimed point
+ // echo "i".$i;
+ $distance_traveled_between_timepoints += distance($stopTimes[$i - 1]["stop_lat"], $stopTimes[$i - 1]["stop_lon"], $stopTimes[$i]["stop_lat"], $stopTimes[$i]["stop_lon"]);
+ // echo "$distance_traveled_between_timepoints / $distance_between_timepoints<br>";
+ $distance_percent = $distance_traveled_between_timepoints / $distance_between_timepoints;
+ if ($next_timepoint["arrival_time"] != "") {
+ $total_time = strtotime($next_timepoint["arrival_time"]) - strtotime($cur_timepoint["arrival_time"]);
+ // echo strtotime($next_timepoint["arrival_time"])." - ".strtotime($cur_timepoint["arrival_time"])."<br>";
+ $time_estimate = ($distance_percent * $total_time) + strtotime($cur_timepoint["arrival_time"]);
+ $stopTime["arrival_time"] = date("H:i:s", $time_estimate);
+ } else {
+ $stopTime["arrival_time"] = $cur_timepoint["arrival_time"];
+ }
+ $rv[] = $stopTime;
+ }
+ }
+ // var_dump($rv);
+ return $rv;
+}
+
+function getTripPreviousTimePoint($tripID, $stop_sequence) {
+ global $conn;
+ $query = " SELECT trip_id,stop_id,
stop_sequence
FROM stop_times
WHERE trip_id = :tripID and stop_sequence < :stop_sequence
and stop_times.arrival_time IS NOT NULL ORDER BY stop_sequence DESC LIMIT 1";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":tripID", $tripID);
- $query->bindParam(":stop_sequence", $stop_sequence);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetch(PDO::FETCH_ASSOC);
-}
-function getTripNextTimePoint($tripID, $stop_sequence)
-{
- global $conn;
- $query = " SELECT trip_id,stop_id,
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":tripID", $tripID);
+ $query->bindParam(":stop_sequence", $stop_sequence);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetch(PDO :: FETCH_ASSOC);
+}
+
+function getTripNextTimePoint($tripID, $stop_sequence) {
+ global $conn;
+ $query = " SELECT trip_id,stop_id,
stop_sequence
FROM stop_times
WHERE trip_id = :tripID and stop_sequence > :stop_sequence
and stop_times.arrival_time IS NOT NULL ORDER BY stop_sequence LIMIT 1";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":tripID", $tripID);
- $query->bindParam(":stop_sequence", $stop_sequence);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetch(PDO::FETCH_ASSOC);
-}
-function getTimeInterpolatedTripAtStop($tripID, $stop_sequence)
-{
- global $conn;
- // limit interpolation to between nearest actual points.
- $prevTimePoint = getTripPreviousTimePoint($tripID, $stop_sequence);
- $nextTimePoint = getTripNextTimePoint($tripID, $stop_sequence);
- //echo " prev {$lowestDelta['stop_sequence']} next {$nextTimePoint['stop_sequence']} ";
- $range = "";
- if ($prevTimePoint != "") $range .= " AND stop_sequence >= '{$prevTimePoint['stop_sequence']}'";
- if ($nextTimePoint != "") $range .= " AND stop_sequence <= '{$nextTimePoint['stop_sequence']}'";
- foreach (getTimeInterpolatedTrip($tripID, $range) as $tripStop) {
- if ($tripStop['stop_sequence'] == $stop_sequence) return $tripStop;
- }
- return Array();
-}
-function getTripStartTime($tripID)
-{
- global $conn;
- $query = "Select * from stop_times
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":tripID", $tripID);
+ $query->bindParam(":stop_sequence", $stop_sequence);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetch(PDO :: FETCH_ASSOC);
+}
+
+function getTimeInterpolatedTripAtStop($tripID, $stop_sequence) {
+ global $conn;
+ // limit interpolation to between nearest actual points.
+ $prevTimePoint = getTripPreviousTimePoint($tripID, $stop_sequence);
+ $nextTimePoint = getTripNextTimePoint($tripID, $stop_sequence);
+ // echo " prev {$lowestDelta['stop_sequence']} next {$nextTimePoint['stop_sequence']} ";
+ $range = "";
+ if ($prevTimePoint != "")
+ $range .= " AND stop_sequence >= '{$prevTimePoint['stop_sequence']}'";
+ if ($nextTimePoint != "")
+ $range .= " AND stop_sequence <= '{$nextTimePoint['stop_sequence']}'";
+ foreach (getTimeInterpolatedTrip($tripID, $range) as $tripStop) {
+ if ($tripStop['stop_sequence'] == $stop_sequence)
+ return $tripStop;
+ }
+ return Array();
+}
+
+function getTripStartTime($tripID) {
+ global $conn;
+ $query = "Select * from stop_times
where trip_id = :tripID
AND arrival_time IS NOT NULL
AND stop_sequence = '1'";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":tripID", $tripID);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- $r = $query->fetch(PDO::FETCH_ASSOC);
- return $r['arrival_time'];
-}
-function getTripEndTime($tripID)
-{
- global $conn;
- $query = "SELECT trip_id,max(arrival_time) as arrival_time from stop_times
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":tripID", $tripID);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ $r = $query->fetch(PDO :: FETCH_ASSOC);
+ return $r['arrival_time'];
+}
+
+function getTripEndTime($tripID) {
+ global $conn;
+ $query = "SELECT trip_id,max(arrival_time) as arrival_time from stop_times
WHERE stop_times.arrival_time IS NOT NULL and trip_id = :tripID group by trip_id";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":tripID", $tripID);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- $r = $query->fetch(PDO::FETCH_ASSOC);
- return $r['arrival_time'];
-}
-function getActiveTrips($time)
-{
- global $conn;
- if ($time == "") $time = current_time();
- $query = "Select distinct stop_times.trip_id, start_times.arrival_time as start_time, end_times.arrival_time as end_time from stop_times, (SELECT trip_id,arrival_time from stop_times WHERE stop_times.arrival_time IS NOT NULL
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":tripID", $tripID);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ $r = $query->fetch(PDO :: FETCH_ASSOC);
+ return $r['arrival_time'];
+}
+
+function getActiveTrips($time) {
+ global $conn;
+ if ($time == "")
+ $time = current_time();
+ $query = "Select distinct stop_times.trip_id, start_times.arrival_time as start_time, end_times.arrival_time as end_time from stop_times, (SELECT trip_id,arrival_time from stop_times WHERE stop_times.arrival_time IS NOT NULL
AND stop_sequence = '1') as start_times, (SELECT trip_id,max(arrival_time) as arrival_time from stop_times WHERE stop_times.arrival_time IS NOT NULL group by trip_id) as end_times
WHERE start_times.trip_id = end_times.trip_id AND stop_times.trip_id = end_times.trip_id AND :time > start_times.arrival_time AND :time < end_times.arrival_time";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":time", $time);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetchAll();
-}
-function viaPoints($tripID, $stop_sequence = "")
-{
- global $conn;
- $query = "SELECT stops.stop_id, stop_name, arrival_time
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ $query->bindParam(":time", $time);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetchAll();
+}
+
+function viaPoints($tripID, $stop_sequence = "", $timing_points_only = true) {
+ global $conn;
+ $query = "SELECT stops.stop_id, stop_name, arrival_time
FROM stop_times join stops on stops.stop_id = stop_times.stop_id
WHERE stop_times.trip_id = :tripID
-" . ($stop_sequence != "" ? " AND stop_sequence > :stop_sequence " : "") . "AND substr(stop_code,1,2) != 'Wj' ORDER BY stop_sequence";
- debug($query, "database");
- $query = $conn->prepare($query);
- if ($stop_sequence != "") $query->bindParam(":stop_sequence", $stop_sequence);
- $query->bindParam(":tripID", $tripID);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- return $query->fetchAll();
-}
-function viaPointNames($tripid, $stop_sequence = "")
-{
- $viaPointNames = Array();
- foreach (viaPoints($tripid, $stop_sequence) as $point) {
- $viaPointNames[] = $point['stop_name'];
- }
- if (sizeof($viaPointNames) > 0) {
- return r_implode(", ", $viaPointNames);
- }
- else {
- return "";
- }
-}
+" . ($stop_sequence != "" ? " AND stop_sequence > :stop_sequence " : "") . ($timing_points_only ? "AND substr(stop_code,1,2) != 'Wj' " : "") . " ORDER BY stop_sequence";
+ debug($query, "database");
+ $query = $conn->prepare($query);
+ if ($stop_sequence != "")
+ $query->bindParam(":stop_sequence", $stop_sequence);
+ $query->bindParam(":tripID", $tripID);
+ $query->execute();
+ if (!$query) {
+ databaseError($conn->errorInfo());
+ return Array();
+ }
+ return $query->fetchAll();
+}
+
+function viaPointNames($tripid, $stop_sequence = "") {
+ $viaPointNames = Array();
+ foreach (viaPoints($tripid, $stop_sequence) as $point) {
+ $viaPointNames[] = $point['stop_name'];
+ }
+ if (sizeof($viaPointNames) > 0) {
+ return r_implode(", ", $viaPointNames);
+ } else {
+ return "";
+ }
+}
+
?>
--- a/index.php
+++ b/index.php
@@ -1,30 +1,46 @@
<?php
+/*
+ * Copyright 2010,2011 Alexander Sadleir
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
include ('include/common.inc.php');
include_header("bus.lambdacomplex.org", "index", false)
?>
<div data-role="page">
- <div data-role="content">
- <div id="jqm-homeheader">
- <h1>busness time</h1><br><small>Canberra Bus Timetables and Trip Planner</small>
- </div>
- <a name="maincontent" id="maincontent"></a>
- <a href="tripPlanner.php" data-role="button" data-icon="navigation">Launch Trip Planner...</a>
- <ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b">
- <li data-role="list-divider">Timetables - Stops</li>
- <li><a href="stopList.php">Major (Timing Point) Stops</a></li>
- <li><a href="stopList.php?allstops=yes">All Stops</a></li>
- <li><a href="stopList.php?bysuburbs=yes">Stops By Suburb</a></li>
- <li><a class="nearby" href="stopList.php?nearby=yes">Nearby Stops</a></li>
- </ul>
- <ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b">
- <li data-role="list-divider">Timetables - Routes</li>
- <li><a href="routeList.php">Routes By Final Destination</a></li>
- <li><a href="routeList.php?bynumber=yes">Routes By Number</a></li>
- <li><a href="routeList.php?bysuburbs=yes">Routes By Suburb</a></li>
- <li><a class="nearby" href="routeList.php?nearby=yes">Nearby Routes</a></li>
- </ul>
-<?php
-echo ' <a href="labs/index.php" data-role="button" data-icon="beaker">Busness R&D</a>';
-include_footer(true)
-?>
+ <div data-role="content">
+ <div id="jqm-homeheader">
+ <h1>busness time</h1><br><small>Canberra Bus Timetables and Trip Planner</small>
+ </div>
+ <a name="maincontent" id="maincontent"></a>
+ <a href="tripPlanner.php" data-role="button" data-icon="navigation">Launch Trip Planner...</a>
+ <ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b">
+ <li data-role="list-divider">Timetables - Stops</li>
+ <li><a href="stopList.php">Major (Timing Point) Stops</a></li>
+ <li><a href="stopList.php?allstops=yes">All Stops</a></li>
+ <li><a href="stopList.php?bysuburbs=yes">Stops By Suburb</a></li>
+ <li><a class="nearby" href="stopList.php?nearby=yes">Nearby Stops</a></li>
+ </ul>
+ <ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b">
+ <li data-role="list-divider">Timetables - Routes</li>
+ <li><a href="routeList.php">Routes By Final Destination</a></li>
+ <li><a href="routeList.php?bynumber=yes">Routes By Number</a></li>
+ <li><a href="routeList.php?bysuburbs=yes">Routes By Suburb</a></li>
+ <li><a class="nearby" href="routeList.php?nearby=yes">Nearby Routes</a></li>
+ </ul>
+ <?php
+ echo ' <a href="labs/index.php" data-role="button" data-icon="beaker">Busness R&D</a>';
+ echo ' <a href="myway/index.php" data-role="button">MyWay Balance and Timeliness Survey Results</a>';
+ include_footer(true)
+ ?>
--- a/js/jquery.mobile-1.0b2.js
+++ /dev/null
@@ -1,6260 +1,1 @@
-/*!
- * jQuery Mobile v1.0b2
- * http://jquerymobile.com/
- *
- * Copyright 2010, jQuery Project
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- */
-/*!
- * jQuery UI Widget @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/Widget
- */
-(function( $, undefined ) {
-// jQuery 1.4+
-if ( $.cleanData ) {
- var _cleanData = $.cleanData;
- $.cleanData = function( elems ) {
- for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
- $( elem ).triggerHandler( "remove" );
- }
- _cleanData( elems );
- };
-} else {
- var _remove = $.fn.remove;
- $.fn.remove = function( selector, keepData ) {
- return this.each(function() {
- if ( !keepData ) {
- if ( !selector || $.filter( selector, [ this ] ).length ) {
- $( "*", this ).add( [ this ] ).each(function() {
- $( this ).triggerHandler( "remove" );
- });
- }
- }
- return _remove.call( $(this), selector, keepData );
- });
- };
-}
-
-$.widget = function( name, base, prototype ) {
- var namespace = name.split( "." )[ 0 ],
- fullName;
- name = name.split( "." )[ 1 ];
- fullName = namespace + "-" + name;
-
- if ( !prototype ) {
- prototype = base;
- base = $.Widget;
- }
-
- // create selector for plugin
- $.expr[ ":" ][ fullName ] = function( elem ) {
- return !!$.data( elem, name );
- };
-
- $[ namespace ] = $[ namespace ] || {};
- $[ namespace ][ name ] = function( options, element ) {
- // allow instantiation without initializing for simple inheritance
- if ( arguments.length ) {
- this._createWidget( options, element );
- }
- };
-
- var basePrototype = new base();
- // we need to make the options hash a property directly on the new instance
- // otherwise we'll modify the options hash on the prototype that we're
- // inheriting from
-// $.each( basePrototype, function( key, val ) {
-// if ( $.isPlainObject(val) ) {
-// basePrototype[ key ] = $.extend( {}, val );
-// }
-// });
- basePrototype.options = $.extend( true, {}, basePrototype.options );
- $[ namespace ][ name ].prototype = $.extend( true, basePrototype, {
- namespace: namespace,
- widgetName: name,
- widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name,
- widgetBaseClass: fullName
- }, prototype );
-
- $.widget.bridge( name, $[ namespace ][ name ] );
-};
-
-$.widget.bridge = function( name, object ) {
- $.fn[ name ] = function( options ) {
- var isMethodCall = typeof options === "string",
- args = Array.prototype.slice.call( arguments, 1 ),
- returnValue = this;
-
- // allow multiple hashes to be passed on init
- options = !isMethodCall && args.length ?
- $.extend.apply( null, [ true, options ].concat(args) ) :
- options;
-
- // prevent calls to internal methods
- if ( isMethodCall && options.charAt( 0 ) === "_" ) {
- return returnValue;
- }
-
- if ( isMethodCall ) {
- this.each(function() {
- var instance = $.data( this, name );
- if ( !instance ) {
- throw "cannot call methods on " + name + " prior to initialization; " +
- "attempted to call method '" + options + "'";
- }
- if ( !$.isFunction( instance[options] ) ) {
- throw "no such method '" + options + "' for " + name + " widget instance";
- }
- var methodValue = instance[ options ].apply( instance, args );
- if ( methodValue !== instance && methodValue !== undefined ) {
- returnValue = methodValue;
- return false;
- }
- });
- } else {
- this.each(function() {
- var instance = $.data( this, name );
- if ( instance ) {
- instance.option( options || {} )._init();
- } else {
- $.data( this, name, new object( options, this ) );
- }
- });
- }
-
- return returnValue;
- };
-};
-
-$.Widget = function( options, element ) {
- // allow instantiation without initializing for simple inheritance
- if ( arguments.length ) {
- this._createWidget( options, element );
- }
-};
-
-$.Widget.prototype = {
- widgetName: "widget",
- widgetEventPrefix: "",
- options: {
- disabled: false
- },
- _createWidget: function( options, element ) {
- // $.widget.bridge stores the plugin instance, but we do it anyway
- // so that it's stored even before the _create function runs
- $.data( element, this.widgetName, this );
- this.element = $( element );
- this.options = $.extend( true, {},
- this.options,
- this._getCreateOptions(),
- options );
-
- var self = this;
- this.element.bind( "remove." + this.widgetName, function() {
- self.destroy();
- });
-
- this._create();
- this._trigger( "create" );
- this._init();
- },
- _getCreateOptions: function() {
- var options = {};
- if ( $.metadata ) {
- options = $.metadata.get( element )[ this.widgetName ];
- }
- return options;
- },
- _create: function() {},
- _init: function() {},
-
- destroy: function() {
- this.element
- .unbind( "." + this.widgetName )
- .removeData( this.widgetName );
- this.widget()
- .unbind( "." + this.widgetName )
- .removeAttr( "aria-disabled" )
- .removeClass(
- this.widgetBaseClass + "-disabled " +
- "ui-state-disabled" );
- },
-
- widget: function() {
- return this.element;
- },
-
- option: function( key, value ) {
- var options = key;
-
- if ( arguments.length === 0 ) {
- // don't return a reference to the internal hash
- return $.extend( {}, this.options );
- }
-
- if (typeof key === "string" ) {
- if ( value === undefined ) {
- return this.options[ key ];
- }
- options = {};
- options[ key ] = value;
- }
-
- this._setOptions( options );
-
- return this;
- },
- _setOptions: function( options ) {
- var self = this;
- $.each( options, function( key, value ) {
- self._setOption( key, value );
- });
-
- return this;
- },
- _setOption: function( key, value ) {
- this.options[ key ] = value;
-
- if ( key === "disabled" ) {
- this.widget()
- [ value ? "addClass" : "removeClass"](
- this.widgetBaseClass + "-disabled" + " " +
- "ui-state-disabled" )
- .attr( "aria-disabled", value );
- }
-
- return this;
- },
-
- enable: function() {
- return this._setOption( "disabled", false );
- },
- disable: function() {
- return this._setOption( "disabled", true );
- },
-
- _trigger: function( type, event, data ) {
- var callback = this.options[ type ];
-
- event = $.Event( event );
- event.type = ( type === this.widgetEventPrefix ?
- type :
- this.widgetEventPrefix + type ).toLowerCase();
- data = data || {};
-
- // copy original event properties over to the new event
- // this would happen if we could call $.event.fix instead of $.Event
- // but we don't have a way to force an event to be fixed multiple times
- if ( event.originalEvent ) {
- for ( var i = $.event.props.length, prop; i; ) {
- prop = $.event.props[ --i ];
- event[ prop ] = event.originalEvent[ prop ];
- }
- }
-
- this.element.trigger( event, data );
-
- return !( $.isFunction(callback) &&
- callback.call( this.element[0], event, data ) === false ||
- event.isDefaultPrevented() );
- }
-};
-
-})( jQuery );
-/*
-* jQuery Mobile Framework : widget factory extentions for mobile
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-
-(function( $, undefined ) {
-
-$.widget( "mobile.widget", {
- _getCreateOptions: function() {
-
- var elem = this.element,
- options = {};
-
- $.each( this.options, function( option ) {
-
- var value = elem.jqmData( option.replace( /[A-Z]/g, function( c ) {
- return "-" + c.toLowerCase();
- })
- );
-
- if ( value !== undefined ) {
- options[ option ] = value;
- }
- });
-
- return options;
- }
-});
-
-})( jQuery );
-/*
-* jQuery Mobile Framework : resolution and CSS media query related helpers and behavior
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-(function( $, undefined ) {
-
-var $window = $( window ),
- $html = $( "html" );
-
-/* $.mobile.media method: pass a CSS media type or query and get a bool return
- note: this feature relies on actual media query support for media queries, though types will work most anywhere
- examples:
- $.mobile.media('screen') //>> tests for screen media type
- $.mobile.media('screen and (min-width: 480px)') //>> tests for screen media type with window width > 480px
- $.mobile.media('@media screen and (-webkit-min-device-pixel-ratio: 2)') //>> tests for webkit 2x pixel ratio (iPhone 4)
-*/
-$.mobile.media = (function() {
- // TODO: use window.matchMedia once at least one UA implements it
- var cache = {},
- testDiv = $( "<div id='jquery-mediatest'>" ),
- fakeBody = $( "<body>" ).append( testDiv );
-
- return function( query ) {
- if ( !( query in cache ) ) {
- var styleBlock = document.createElement( "style" ),
- cssrule = "@media " + query + " { #jquery-mediatest { position:absolute; } }";
-
- //must set type for IE!
- styleBlock.type = "text/css";
-
- if ( styleBlock.styleSheet ){
- styleBlock.styleSheet.cssText = cssrule;
- } else {
- styleBlock.appendChild( document.createTextNode(cssrule) );
- }
-
- $html.prepend( fakeBody ).prepend( styleBlock );
- cache[ query ] = testDiv.css( "position" ) === "absolute";
- fakeBody.add( styleBlock ).remove();
- }
- return cache[ query ];
- };
-})();
-
-})(jQuery);/*
-* jQuery Mobile Framework : support tests
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
-*/
-
-(function( $, undefined ) {
-
-var fakeBody = $( "<body>" ).prependTo( "html" ),
- fbCSS = fakeBody[ 0 ].style,
- vendors = [ "webkit", "moz", "o" ],
- webos = "palmGetResource" in window, //only used to rule out scrollTop
- bb = window.blackberry; //only used to rule out box shadow, as it's filled opaque on BB
-
-// thx Modernizr
-function propExists( prop ) {
- var uc_prop = prop.charAt( 0 ).toUpperCase() + prop.substr( 1 ),
- props = ( prop + " " + vendors.join( uc_prop + " " ) + uc_prop ).split( " " );
-
- for ( var v in props ){
- if ( fbCSS[ v ] !== undefined ) {
- return true;
- }
- }
-}
-
-// Test for dynamic-updating base tag support ( allows us to avoid href,src attr rewriting )
-function baseTagTest() {
- var fauxBase = location.protocol + "//" + location.host + location.pathname + "ui-dir/",
- base = $( "head base" ),
- fauxEle = null,
- href = "",
- link, rebase;
-
- if ( !base.length ) {
- base = fauxEle = $( "<base>", { "href": fauxBase }).appendTo( "head" );
- } else {
- href = base.attr( "href" );
- }
-
- link = $( "<a href='testurl'></a>" ).prependTo( fakeBody );
- rebase = link[ 0 ].href;
- base[ 0 ].href = href ? href : location.pathname;
-
- if ( fauxEle ) {
- fauxEle.remove();
- }
- return rebase.indexOf( fauxBase ) === 0;
-}
-
-
-// non-UA-based IE version check by James Padolsey, modified by jdalton - from http://gist.github.com/527683
-// allows for inclusion of IE 6+, including Windows Mobile 7
-$.mobile.browser = {};
-$.mobile.browser.ie = (function() {
- var v = 3,
- div = document.createElement( "div" ),
- a = div.all || [];
-
- while ( div.innerHTML = "<!--[if gt IE " + ( ++v ) + "]><br><![endif]-->", a[ 0 ] );
-
- return v > 4 ? v : !v;
-})();
-
-
-$.extend( $.support, {
- orientation: "orientation" in window,
- touch: "ontouchend" in document,
- cssTransitions: "WebKitTransitionEvent" in window,
- pushState: !!history.pushState,
- mediaquery: $.mobile.media( "only all" ),
- cssPseudoElement: !!propExists( "content" ),
- boxShadow: !!propExists( "boxShadow" ) && !bb,
- scrollTop: ( "pageXOffset" in window || "scrollTop" in document.documentElement || "scrollTop" in fakeBody[ 0 ] ) && !webos,
- dynamicBaseTag: baseTagTest(),
- // TODO: This is a weak test. We may want to beef this up later.
- eventCapture: "addEventListener" in document
-});
-
-fakeBody.remove();
-
-
-// $.mobile.ajaxBlacklist is used to override ajaxEnabled on platforms that have known conflicts with hash history updates (BB5, Symbian)
-// or that generally work better browsing in regular http for full page refreshes (Opera Mini)
-// Note: This detection below is used as a last resort.
-// We recommend only using these detection methods when all other more reliable/forward-looking approaches are not possible
-var nokiaLTE7_3 = (function(){
-
- var ua = window.navigator.userAgent;
-
- //The following is an attempt to match Nokia browsers that are running Symbian/s60, with webkit, version 7.3 or older
- return ua.indexOf( "Nokia" ) > -1 &&
- ( ua.indexOf( "Symbian/3" ) > -1 || ua.indexOf( "Series60/5" ) > -1 ) &&
- ua.indexOf( "AppleWebKit" ) > -1 &&
- ua.match( /(BrowserNG|NokiaBrowser)\/7\.[0-3]/ );
-})();
-
-$.mobile.ajaxBlacklist =
- // BlackBerry browsers, pre-webkit
- window.blackberry && !window.WebKitPoint ||
- // Opera Mini
- window.operamini && Object.prototype.toString.call( window.operamini ) === "[object OperaMini]" ||
- // Symbian webkits pre 7.3
- nokiaLTE7_3;
-
-// Lastly, this workaround is the only way we've found so far to get pre 7.3 Symbian webkit devices
-// to render the stylesheets when they're referenced before this script, as we'd recommend doing.
-// This simply reappends the CSS in place, which for some reason makes it apply
-if ( nokiaLTE7_3 ) {
- $(function() {
- $( "head link[rel=stylesheet]" ).attr( "rel", "alternate stylesheet" ).attr( "rel", "stylesheet" );
- });
-}
-
-// For ruling out shadows via css
-if ( !$.support.boxShadow ) {
- $( "html" ).addClass( "ui-mobile-nosupport-boxshadow" );
-}
-
-})( jQuery );/*
-* jQuery Mobile Framework : "mouse" plugin
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-
-// This plugin is an experiment for abstracting away the touch and mouse
-// events so that developers don't have to worry about which method of input
-// the device their document is loaded on supports.
-//
-// The idea here is to allow the developer to register listeners for the
-// basic mouse events, such as mousedown, mousemove, mouseup, and click,
-// and the plugin will take care of registering the correct listeners
-// behind the scenes to invoke the listener at the fastest possible time
-// for that device, while still retaining the order of event firing in
-// the traditional mouse environment, should multiple handlers be registered
-// on the same element for different events.
-//
-// The current version exposes the following virtual events to jQuery bind methods:
-// "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel"
-
-(function( $, window, document, undefined ) {
-
-var dataPropertyName = "virtualMouseBindings",
- touchTargetPropertyName = "virtualTouchID",
- virtualEventNames = "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split( " " ),
- touchEventProps = "clientX clientY pageX pageY screenX screenY".split( " " ),
- activeDocHandlers = {},
- resetTimerID = 0,
- startX = 0,
- startY = 0,
- didScroll = false,
- clickBlockList = [],
- blockMouseTriggers = false,
- blockTouchTriggers = false,
- eventCaptureSupported = $.support.eventCapture,
- $document = $( document ),
- nextTouchID = 1,
- lastTouchID = 0;
-
-$.vmouse = {
- moveDistanceThreshold: 10,
- clickDistanceThreshold: 10,
- resetTimerDuration: 1500
-};
-
-function getNativeEvent( event ) {
-
- while ( event && typeof event.originalEvent !== "undefined" ) {
- event = event.originalEvent;
- }
- return event;
-}
-
-function createVirtualEvent( event, eventType ) {
-
- var t = event.type,
- oe, props, ne, prop, ct, touch, i, j;
-
- event = $.Event(event);
- event.type = eventType;
-
- oe = event.originalEvent;
- props = $.event.props;
-
- // copy original event properties over to the new event
- // this would happen if we could call $.event.fix instead of $.Event
- // but we don't have a way to force an event to be fixed multiple times
- if ( oe ) {
- for ( i = props.length, prop; i; ) {
- prop = props[ --i ];
- event[ prop ] = oe[ prop ];
- }
- }
-
- if ( t.search(/^touch/) !== -1 ) {
- ne = getNativeEvent( oe );
- t = ne.touches;
- ct = ne.changedTouches;
- touch = ( t && t.length ) ? t[0] : ( (ct && ct.length) ? ct[ 0 ] : undefined );
-
- if ( touch ) {
- for ( j = 0, len = touchEventProps.length; j < len; j++){
- prop = touchEventProps[ j ];
- event[ prop ] = touch[ prop ];
- }
- }
- }
-
- return event;
-}
-
-function getVirtualBindingFlags( element ) {
-
- var flags = {},
- b, k;
-
- while ( element ) {
-
- b = $.data( element, dataPropertyName );
-
- for ( k in b ) {
- if ( b[ k ] ) {
- flags[ k ] = flags.hasVirtualBinding = true;
- }
- }
- element = element.parentNode;
- }
- return flags;
-}
-
-function getClosestElementWithVirtualBinding( element, eventType ) {
- var b;
- while ( element ) {
-
- b = $.data( element, dataPropertyName );
-
- if ( b && ( !eventType || b[ eventType ] ) ) {
- return element;
- }
- element = element.parentNode;
- }
- return null;
-}
-
-function enableTouchBindings() {
- blockTouchTriggers = false;
-}
-
-function disableTouchBindings() {
- blockTouchTriggers = true;
-}
-
-function enableMouseBindings() {
- lastTouchID = 0;
- clickBlockList.length = 0;
- blockMouseTriggers = false;
-
- // When mouse bindings are enabled, our
- // touch bindings are disabled.
- disableTouchBindings();
-}
-
-function disableMouseBindings() {
- // When mouse bindings are disabled, our
- // touch bindings are enabled.
- enableTouchBindings();
-}
-
-function startResetTimer() {
- clearResetTimer();
- resetTimerID = setTimeout(function(){
- resetTimerID = 0;
- enableMouseBindings();
- }, $.vmouse.resetTimerDuration );
-}
-
-function clearResetTimer() {
- if ( resetTimerID ){
- clearTimeout( resetTimerID );
- resetTimerID = 0;
- }
-}
-
-function triggerVirtualEvent( eventType, event, flags ) {
- var defaultPrevented = false,
- ve;
-
- if ( ( flags && flags[ eventType ] ) ||
- ( !flags && getClosestElementWithVirtualBinding( event.target, eventType ) ) ) {
-
- ve = createVirtualEvent( event, eventType );
-
- $( event.target).trigger( ve );
-
- defaultPrevented = ve.isDefaultPrevented();
- }
-
- return defaultPrevented;
-}
-
-function mouseEventCallback( event ) {
- var touchID = $.data(event.target, touchTargetPropertyName);
-
- if ( !blockMouseTriggers && ( !lastTouchID || lastTouchID !== touchID ) ){
- triggerVirtualEvent( "v" + event.type, event );
- }
-}
-
-function handleTouchStart( event ) {
-
- var touches = getNativeEvent( event ).touches,
- target, flags;
-
- if ( touches && touches.length === 1 ) {
-
- target = event.target;
- flags = getVirtualBindingFlags( target );
-
- if ( flags.hasVirtualBinding ) {
-
- lastTouchID = nextTouchID++;
- $.data( target, touchTargetPropertyName, lastTouchID );
-
- clearResetTimer();
-
- disableMouseBindings();
- didScroll = false;
-
- var t = getNativeEvent( event ).touches[ 0 ];
- startX = t.pageX;
- startY = t.pageY;
-
- triggerVirtualEvent( "vmouseover", event, flags );
- triggerVirtualEvent( "vmousedown", event, flags );
- }
- }
-}
-
-function handleScroll( event ) {
- if ( blockTouchTriggers ) {
- return;
- }
-
- if ( !didScroll ) {
- triggerVirtualEvent( "vmousecancel", event, getVirtualBindingFlags( event.target ) );
- }
-
- didScroll = true;
- startResetTimer();
-}
-
-function handleTouchMove( event ) {
- if ( blockTouchTriggers ) {
- return;
- }
-
- var t = getNativeEvent( event ).touches[ 0 ],
- didCancel = didScroll,
- moveThreshold = $.vmouse.moveDistanceThreshold;
- didScroll = didScroll ||
- ( Math.abs(t.pageX - startX) > moveThreshold ||
- Math.abs(t.pageY - startY) > moveThreshold ),
- flags = getVirtualBindingFlags( event.target );
-
- if ( didScroll && !didCancel ) {
- triggerVirtualEvent( "vmousecancel", event, flags );
- }
-
- triggerVirtualEvent( "vmousemove", event, flags );
- startResetTimer();
-}
-
-function handleTouchEnd( event ) {
- if ( blockTouchTriggers ) {
- return;
- }
-
- disableTouchBindings();
-
- var flags = getVirtualBindingFlags( event.target ),
- t;
- triggerVirtualEvent( "vmouseup", event, flags );
-
- if ( !didScroll ) {
- if ( triggerVirtualEvent( "vclick", event, flags ) ) {
- // The target of the mouse events that follow the touchend
- // event don't necessarily match the target used during the
- // touch. This means we need to rely on coordinates for blocking
- // any click that is generated.
- t = getNativeEvent( event ).changedTouches[ 0 ];
- clickBlockList.push({
- touchID: lastTouchID,
- x: t.clientX,
- y: t.clientY
- });
-
- // Prevent any mouse events that follow from triggering
- // virtual event notifications.
- blockMouseTriggers = true;
- }
- }
- triggerVirtualEvent( "vmouseout", event, flags);
- didScroll = false;
-
- startResetTimer();
-}
-
-function hasVirtualBindings( ele ) {
- var bindings = $.data( ele, dataPropertyName ),
- k;
-
- if ( bindings ) {
- for ( k in bindings ) {
- if ( bindings[ k ] ) {
- return true;
- }
- }
- }
- return false;
-}
-
-function dummyMouseHandler(){}
-
-function getSpecialEventObject( eventType ) {
- var realType = eventType.substr( 1 );
-
- return {
- setup: function( data, namespace ) {
- // If this is the first virtual mouse binding for this element,
- // add a bindings object to its data.
-
- if ( !hasVirtualBindings( this ) ) {
- $.data( this, dataPropertyName, {});
- }
-
- // If setup is called, we know it is the first binding for this
- // eventType, so initialize the count for the eventType to zero.
- var bindings = $.data( this, dataPropertyName );
- bindings[ eventType ] = true;
-
- // If this is the first virtual mouse event for this type,
- // register a global handler on the document.
-
- activeDocHandlers[ eventType ] = ( activeDocHandlers[ eventType ] || 0 ) + 1;
-
- if ( activeDocHandlers[ eventType ] === 1 ) {
- $document.bind( realType, mouseEventCallback );
- }
-
- // Some browsers, like Opera Mini, won't dispatch mouse/click events
- // for elements unless they actually have handlers registered on them.
- // To get around this, we register dummy handlers on the elements.
-
- $( this ).bind( realType, dummyMouseHandler );
-
- // For now, if event capture is not supported, we rely on mouse handlers.
- if ( eventCaptureSupported ) {
- // If this is the first virtual mouse binding for the document,
- // register our touchstart handler on the document.
-
- activeDocHandlers[ "touchstart" ] = ( activeDocHandlers[ "touchstart" ] || 0) + 1;
-
- if (activeDocHandlers[ "touchstart" ] === 1) {
- $document.bind( "touchstart", handleTouchStart )
- .bind( "touchend", handleTouchEnd )
-
- // On touch platforms, touching the screen and then dragging your finger
- // causes the window content to scroll after some distance threshold is
- // exceeded. On these platforms, a scroll prevents a click event from being
- // dispatched, and on some platforms, even the touchend is suppressed. To
- // mimic the suppression of the click event, we need to watch for a scroll
- // event. Unfortunately, some platforms like iOS don't dispatch scroll
- // events until *AFTER* the user lifts their finger (touchend). This means
- // we need to watch both scroll and touchmove events to figure out whether
- // or not a scroll happenens before the touchend event is fired.
-
- .bind( "touchmove", handleTouchMove )
- .bind( "scroll", handleScroll );
- }
- }
- },
-
- teardown: function( data, namespace ) {
- // If this is the last virtual binding for this eventType,
- // remove its global handler from the document.
-
- --activeDocHandlers[ eventType ];
-
- if ( !activeDocHandlers[ eventType ] ) {
- $document.unbind( realType, mouseEventCallback );
- }
-
- if ( eventCaptureSupported ) {
- // If this is the last virtual mouse binding in existence,
- // remove our document touchstart listener.
-
- --activeDocHandlers[ "touchstart" ];
-
- if ( !activeDocHandlers[ "touchstart" ] ) {
- $document.unbind( "touchstart", handleTouchStart )
- .unbind( "touchmove", handleTouchMove )
- .unbind( "touchend", handleTouchEnd )
- .unbind( "scroll", handleScroll );
- }
- }
-
- var $this = $( this ),
- bindings = $.data( this, dataPropertyName );
-
- // teardown may be called when an element was
- // removed from the DOM. If this is the case,
- // jQuery core may have already stripped the element
- // of any data bindings so we need to check it before
- // using it.
- if ( bindings ) {
- bindings[ eventType ] = false;
- }
-
- // Unregister the dummy event handler.
-
- $this.unbind( realType, dummyMouseHandler );
-
- // If this is the last virtual mouse binding on the
- // element, remove the binding data from the element.
-
- if ( !hasVirtualBindings( this ) ) {
- $this.removeData( dataPropertyName );
- }
- }
- };
-}
-
-// Expose our custom events to the jQuery bind/unbind mechanism.
-
-for ( var i = 0; i < virtualEventNames.length; i++ ){
- $.event.special[ virtualEventNames[ i ] ] = getSpecialEventObject( virtualEventNames[ i ] );
-}
-
-// Add a capture click handler to block clicks.
-// Note that we require event capture support for this so if the device
-// doesn't support it, we punt for now and rely solely on mouse events.
-if ( eventCaptureSupported ) {
- document.addEventListener( "click", function( e ){
- var cnt = clickBlockList.length,
- target = e.target,
- x, y, ele, i, o, touchID;
-
- if ( cnt ) {
- x = e.clientX;
- y = e.clientY;
- threshold = $.vmouse.clickDistanceThreshold;
-
- // The idea here is to run through the clickBlockList to see if
- // the current click event is in the proximity of one of our
- // vclick events that had preventDefault() called on it. If we find
- // one, then we block the click.
- //
- // Why do we have to rely on proximity?
- //
- // Because the target of the touch event that triggered the vclick
- // can be different from the target of the click event synthesized
- // by the browser. The target of a mouse/click event that is syntehsized
- // from a touch event seems to be implementation specific. For example,
- // some browsers will fire mouse/click events for a link that is near
- // a touch event, even though the target of the touchstart/touchend event
- // says the user touched outside the link. Also, it seems that with most
- // browsers, the target of the mouse/click event is not calculated until the
- // time it is dispatched, so if you replace an element that you touched
- // with another element, the target of the mouse/click will be the new
- // element underneath that point.
- //
- // Aside from proximity, we also check to see if the target and any
- // of its ancestors were the ones that blocked a click. This is necessary
- // because of the strange mouse/click target calculation done in the
- // Android 2.1 browser, where if you click on an element, and there is a
- // mouse/click handler on one of its ancestors, the target will be the
- // innermost child of the touched element, even if that child is no where
- // near the point of touch.
-
- ele = target;
-
- while ( ele ) {
- for ( i = 0; i < cnt; i++ ) {
- o = clickBlockList[ i ];
- touchID = 0;
-
- if ( ( ele === target && Math.abs( o.x - x ) < threshold && Math.abs( o.y - y ) < threshold ) ||
- $.data( ele, touchTargetPropertyName ) === o.touchID ) {
- // XXX: We may want to consider removing matches from the block list
- // instead of waiting for the reset timer to fire.
- e.preventDefault();
- e.stopPropagation();
- return;
- }
- }
- ele = ele.parentNode;
- }
- }
- }, true);
-}
-})( jQuery, window, document );
-/*
-* jQuery Mobile Framework : events
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-(function( $, window, undefined ) {
-
-// add new event shortcuts
-$.each( ( "touchstart touchmove touchend orientationchange throttledresize " +
- "tap taphold swipe swipeleft swiperight scrollstart scrollstop" ).split( " " ), function( i, name ) {
-
- $.fn[ name ] = function( fn ) {
- return fn ? this.bind( name, fn ) : this.trigger( name );
- };
-
- $.attrFn[ name ] = true;
-});
-
-var supportTouch = $.support.touch,
- scrollEvent = "touchmove scroll",
- touchStartEvent = supportTouch ? "touchstart" : "mousedown",
- touchStopEvent = supportTouch ? "touchend" : "mouseup",
- touchMoveEvent = supportTouch ? "touchmove" : "mousemove";
-
-function triggerCustomEvent( obj, eventType, event ) {
- var originalType = event.type;
- event.type = eventType;
- $.event.handle.call( obj, event );
- event.type = originalType;
-}
-
-// also handles scrollstop
-$.event.special.scrollstart = {
-
- enabled: true,
-
- setup: function() {
-
- var thisObject = this,
- $this = $( thisObject ),
- scrolling,
- timer;
-
- function trigger( event, state ) {
- scrolling = state;
- triggerCustomEvent( thisObject, scrolling ? "scrollstart" : "scrollstop", event );
- }
-
- // iPhone triggers scroll after a small delay; use touchmove instead
- $this.bind( scrollEvent, function( event ) {
-
- if ( !$.event.special.scrollstart.enabled ) {
- return;
- }
-
- if ( !scrolling ) {
- trigger( event, true );
- }
-
- clearTimeout( timer );
- timer = setTimeout(function() {
- trigger( event, false );
- }, 50 );
- });
- }
-};
-
-// also handles taphold
-$.event.special.tap = {
- setup: function() {
- var thisObject = this,
- $this = $( thisObject );
-
- $this.bind( "vmousedown", function( event ) {
-
- if ( event.which && event.which !== 1 ) {
- return false;
- }
-
- var touching = true,
- origTarget = event.target,
- origEvent = event.originalEvent,
- timer;
-
- function clearTapHandlers() {
- touching = false;
- clearTimeout(timer);
-
- $this.unbind( "vclick", clickHandler )
- .unbind( "vmousecancel", clearTapHandlers );
- }
-
- function clickHandler(event) {
- clearTapHandlers();
-
- // ONLY trigger a 'tap' event if the start target is
- // the same as the stop target.
- if ( origTarget == event.target ) {
- triggerCustomEvent( thisObject, "tap", event );
- }
- }
-
- $this.bind( "vmousecancel", clearTapHandlers )
- .bind( "vclick", clickHandler );
-
- timer = setTimeout(function() {
- if ( touching ) {
- triggerCustomEvent( thisObject, "taphold", event );
- }
- }, 750 );
- });
- }
-};
-
-// also handles swipeleft, swiperight
-$.event.special.swipe = {
- scrollSupressionThreshold: 10, // More than this horizontal displacement, and we will suppress scrolling.
-
- durationThreshold: 1000, // More time than this, and it isn't a swipe.
-
- horizontalDistanceThreshold: 30, // Swipe horizontal displacement must be more than this.
-
- verticalDistanceThreshold: 75, // Swipe vertical displacement must be less than this.
-
- setup: function() {
- var thisObject = this,
- $this = $( thisObject );
-
- $this.bind( touchStartEvent, function( event ) {
- var data = event.originalEvent.touches ?
- event.originalEvent.touches[ 0 ] : event,
- start = {
- time: ( new Date() ).getTime(),
- coords: [ data.pageX, data.pageY ],
- origin: $( event.target )
- },
- stop;
-
- function moveHandler( event ) {
-
- if ( !start ) {
- return;
- }
-
- var data = event.originalEvent.touches ?
- event.originalEvent.touches[ 0 ] : event;
-
- stop = {
- time: ( new Date() ).getTime(),
- coords: [ data.pageX, data.pageY ]
- };
-
- // prevent scrolling
- if ( Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.scrollSupressionThreshold ) {
- event.preventDefault();
- }
- }
-
- $this.bind( touchMoveEvent, moveHandler )
- .one( touchStopEvent, function( event ) {
- $this.unbind( touchMoveEvent, moveHandler );
-
- if ( start && stop ) {
- if ( stop.time - start.time < $.event.special.swipe.durationThreshold &&
- Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.horizontalDistanceThreshold &&
- Math.abs( start.coords[ 1 ] - stop.coords[ 1 ] ) < $.event.special.swipe.verticalDistanceThreshold ) {
-
- start.origin.trigger( "swipe" )
- .trigger( start.coords[0] > stop.coords[ 0 ] ? "swipeleft" : "swiperight" );
- }
- }
- start = stop = undefined;
- });
- });
- }
-};
-
-(function( $, window ) {
- // "Cowboy" Ben Alman
-
- var win = $( window ),
- special_event,
- get_orientation,
- last_orientation;
-
- $.event.special.orientationchange = special_event = {
- setup: function() {
- // If the event is supported natively, return false so that jQuery
- // will bind to the event using DOM methods.
- if ( $.support.orientation ) {
- return false;
- }
-
- // Get the current orientation to avoid initial double-triggering.
- last_orientation = get_orientation();
-
- // Because the orientationchange event doesn't exist, simulate the
- // event by testing window dimensions on resize.
- win.bind( "throttledresize", handler );
- },
- teardown: function(){
- // If the event is not supported natively, return false so that
- // jQuery will unbind the event using DOM methods.
- if ( $.support.orientation ) {
- return false;
- }
-
- // Because the orientationchange event doesn't exist, unbind the
- // resize event handler.
- win.unbind( "throttledresize", handler );
- },
- add: function( handleObj ) {
- // Save a reference to the bound event handler.
- var old_handler = handleObj.handler;
-
- handleObj.handler = function( event ) {
- // Modify event object, adding the .orientation property.
- event.orientation = get_orientation();
-
- // Call the originally-bound event handler and return its result.
- return old_handler.apply( this, arguments );
- };
- }
- };
-
- // If the event is not supported natively, this handler will be bound to
- // the window resize event to simulate the orientationchange event.
- function handler() {
- // Get the current orientation.
- var orientation = get_orientation();
-
- if ( orientation !== last_orientation ) {
- // The orientation has changed, so trigger the orientationchange event.
- last_orientation = orientation;
- win.trigger( "orientationchange" );
- }
- };
-
- // Get the current page orientation. This method is exposed publicly, should it
- // be needed, as jQuery.event.special.orientationchange.orientation()
- $.event.special.orientationchange.orientation = get_orientation = function() {
- var elem = document.documentElement;
- return elem && elem.clientWidth / elem.clientHeight < 1.1 ? "portrait" : "landscape";
- };
-
-})( jQuery, window );
-
-
-// throttled resize event
-(function() {
-
- $.event.special.throttledresize = {
- setup: function() {
- $( this ).bind( "resize", handler );
- },
- teardown: function(){
- $( this ).unbind( "resize", handler );
- }
- };
-
- var throttle = 250,
- handler = function() {
- curr = ( new Date() ).getTime();
- diff = curr - lastCall;
-
- if ( diff >= throttle ) {
-
- lastCall = curr;
- $( this ).trigger( "throttledresize" );
-
- } else {
-
- if ( heldCall ) {
- clearTimeout( heldCall );
- }
-
- // Promise a held call will still execute
- heldCall = setTimeout( handler, throttle - diff );
- }
- },
- lastCall = 0,
- heldCall,
- curr,
- diff;
-})();
-
-
-$.each({
- scrollstop: "scrollstart",
- taphold: "tap",
- swipeleft: "swipe",
- swiperight: "swipe"
-}, function( event, sourceEvent ) {
-
- $.event.special[ event ] = {
- setup: function() {
- $( this ).bind( sourceEvent, $.noop );
- }
- };
-});
-
-})( jQuery, this );
-/*!
- * jQuery hashchange event - v1.3 - 7/21/2010
- * http://benalman.com/projects/jquery-hashchange-plugin/
- *
- * Copyright (c) 2010 "Cowboy" Ben Alman
- * Dual licensed under the MIT and GPL licenses.
- * http://benalman.com/about/license/
- */
-
-// Script: jQuery hashchange event
-//
-// *Version: 1.3, Last updated: 7/21/2010*
-//
-// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
-// GitHub - http://github.com/cowboy/jquery-hashchange/
-// Source - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
-// (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
-//
-// About: License
-//
-// Copyright (c) 2010 "Cowboy" Ben Alman,
-// Dual licensed under the MIT and GPL licenses.
-// http://benalman.com/about/license/
-//
-// About: Examples
-//
-// These working examples, complete with fully commented code, illustrate a few
-// ways in which this plugin can be used.
-//
-// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
-// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
-//
-// About: Support and Testing
-//
-// Information about what version or versions of jQuery this plugin has been
-// tested with, what browsers it has been tested in, and where the unit tests
-// reside (so you can test it yourself).
-//
-// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
-// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
-// Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
-// Unit Tests - http://benalman.com/code/projects/jquery-hashchange/unit/
-//
-// About: Known issues
-//
-// While this jQuery hashchange event implementation is quite stable and
-// robust, there are a few unfortunate browser bugs surrounding expected
-// hashchange event-based behaviors, independent of any JavaScript
-// window.onhashchange abstraction. See the following examples for more
-// information:
-//
-// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
-// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
-// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
-// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
-//
-// Also note that should a browser natively support the window.onhashchange
-// event, but not report that it does, the fallback polling loop will be used.
-//
-// About: Release History
-//
-// 1.3 - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
-// "removable" for mobile-only development. Added IE6/7 document.title
-// support. Attempted to make Iframe as hidden as possible by using
-// techniques from http://www.paciellogroup.com/blog/?p=604. Added
-// support for the "shortcut" format $(window).hashchange( fn ) and
-// $(window).hashchange() like jQuery provides for built-in events.
-// Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
-// lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
-// and <jQuery.fn.hashchange.src> properties plus document-domain.html
-// file to address access denied issues when setting document.domain in
-// IE6/7.
-// 1.2 - (2/11/2010) Fixed a bug where coming back to a page using this plugin
-// from a page on another domain would cause an error in Safari 4. Also,
-// IE6/7 Iframe is now inserted after the body (this actually works),
-// which prevents the page from scrolling when the event is first bound.
-// Event can also now be bound before DOM ready, but it won't be usable
-// before then in IE6/7.
-// 1.1 - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
-// where browser version is incorrectly reported as 8.0, despite
-// inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
-// 1.0 - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
-// window.onhashchange functionality into a separate plugin for users
-// who want just the basic event & back button support, without all the
-// extra awesomeness that BBQ provides. This plugin will be included as
-// part of jQuery BBQ, but also be available separately.
-
-(function($,window,undefined){
- '$:nomunge'; // Used by YUI compressor.
-
- // Reused string.
- var str_hashchange = 'hashchange',
-
- // Method / object references.
- doc = document,
- fake_onhashchange,
- special = $.event.special,
-
- // Does the browser support window.onhashchange? Note that IE8 running in
- // IE7 compatibility mode reports true for 'onhashchange' in window, even
- // though the event isn't supported, so also test document.documentMode.
- doc_mode = doc.documentMode,
- supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );
-
- // Get location.hash (or what you'd expect location.hash to be) sans any
- // leading #. Thanks for making this necessary, Firefox!
- function get_fragment( url ) {
- url = url || location.href;
- return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
- };
-
- // Method: jQuery.fn.hashchange
- //
- // Bind a handler to the window.onhashchange event or trigger all bound
- // window.onhashchange event handlers. This behavior is consistent with
- // jQuery's built-in event handlers.
- //
- // Usage:
- //
- // > jQuery(window).hashchange( [ handler ] );
- //
- // Arguments:
- //
- // handler - (Function) Optional handler to be bound to the hashchange
- // event. This is a "shortcut" for the more verbose form:
- // jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
- // all bound window.onhashchange event handlers will be triggered. This
- // is a shortcut for the more verbose
- // jQuery(window).trigger( 'hashchange' ). These forms are described in
- // the <hashchange event> section.
- //
- // Returns:
- //
- // (jQuery) The initial jQuery collection of elements.
-
- // Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
- // $(elem).hashchange() for triggering, like jQuery does for built-in events.
- $.fn[ str_hashchange ] = function( fn ) {
- return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange );
- };
-
- // Property: jQuery.fn.hashchange.delay
- //
- // The numeric interval (in milliseconds) at which the <hashchange event>
- // polling loop executes. Defaults to 50.
-
- // Property: jQuery.fn.hashchange.domain
- //
- // If you're setting document.domain in your JavaScript, and you want hash
- // history to work in IE6/7, not only must this property be set, but you must
- // also set document.domain BEFORE jQuery is loaded into the page. This
- // property is only applicable if you are supporting IE6/7 (or IE8 operating
- // in "IE7 compatibility" mode).
- //
- // In addition, the <jQuery.fn.hashchange.src> property must be set to the
- // path of the included "document-domain.html" file, which can be renamed or
- // modified if necessary (note that the document.domain specified must be the
- // same in both your main JavaScript as well as in this file).
- //
- // Usage:
- //
- // jQuery.fn.hashchange.domain = document.domain;
-
- // Property: jQuery.fn.hashchange.src
- //
- // If, for some reason, you need to specify an Iframe src file (for example,
- // when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
- // do so using this property. Note that when using this property, history
- // won't be recorded in IE6/7 until the Iframe src file loads. This property
- // is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
- // compatibility" mode).
- //
- // Usage:
- //
- // jQuery.fn.hashchange.src = 'path/to/file.html';
-
- $.fn[ str_hashchange ].delay = 50;
- /*
- $.fn[ str_hashchange ].domain = null;
- $.fn[ str_hashchange ].src = null;
- */
-
- // Event: hashchange event
- //
- // Fired when location.hash changes. In browsers that support it, the native
- // HTML5 window.onhashchange event is used, otherwise a polling loop is
- // initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
- // see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
- // compatibility" mode), a hidden Iframe is created to allow the back button
- // and hash-based history to work.
- //
- // Usage as described in <jQuery.fn.hashchange>:
- //
- // > // Bind an event handler.
- // > jQuery(window).hashchange( function(e) {
- // > var hash = location.hash;
- // > ...
- // > });
- // >
- // > // Manually trigger the event handler.
- // > jQuery(window).hashchange();
- //
- // A more verbose usage that allows for event namespacing:
- //
- // > // Bind an event handler.
- // > jQuery(window).bind( 'hashchange', function(e) {
- // > var hash = location.hash;
- // > ...
- // > });
- // >
- // > // Manually trigger the event handler.
- // > jQuery(window).trigger( 'hashchange' );
- //
- // Additional Notes:
- //
- // * The polling loop and Iframe are not created until at least one handler
- // is actually bound to the 'hashchange' event.
- // * If you need the bound handler(s) to execute immediately, in cases where
- // a location.hash exists on page load, via bookmark or page refresh for
- // example, use jQuery(window).hashchange() or the more verbose
- // jQuery(window).trigger( 'hashchange' ).
- // * The event can be bound before DOM ready, but since it won't be usable
- // before then in IE6/7 (due to the necessary Iframe), recommended usage is
- // to bind it inside a DOM ready handler.
-
- // Override existing $.event.special.hashchange methods (allowing this plugin
- // to be defined after jQuery BBQ in BBQ's source code).
- special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
-
- // Called only when the first 'hashchange' event is bound to window.
- setup: function() {
- // If window.onhashchange is supported natively, there's nothing to do..
- if ( supports_onhashchange ) { return false; }
-
- // Otherwise, we need to create our own. And we don't want to call this
- // until the user binds to the event, just in case they never do, since it
- // will create a polling loop and possibly even a hidden Iframe.
- $( fake_onhashchange.start );
- },
-
- // Called only when the last 'hashchange' event is unbound from window.
- teardown: function() {
- // If window.onhashchange is supported natively, there's nothing to do..
- if ( supports_onhashchange ) { return false; }
-
- // Otherwise, we need to stop ours (if possible).
- $( fake_onhashchange.stop );
- }
-
- });
-
- // fake_onhashchange does all the work of triggering the window.onhashchange
- // event for browsers that don't natively support it, including creating a
- // polling loop to watch for hash changes and in IE 6/7 creating a hidden
- // Iframe to enable back and forward.
- fake_onhashchange = (function(){
- var self = {},
- timeout_id,
-
- // Remember the initial hash so it doesn't get triggered immediately.
- last_hash = get_fragment(),
-
- fn_retval = function(val){ return val; },
- history_set = fn_retval,
- history_get = fn_retval;
-
- // Start the polling loop.
- self.start = function() {
- timeout_id || poll();
- };
-
- // Stop the polling loop.
- self.stop = function() {
- timeout_id && clearTimeout( timeout_id );
- timeout_id = undefined;
- };
-
- // This polling loop checks every $.fn.hashchange.delay milliseconds to see
- // if location.hash has changed, and triggers the 'hashchange' event on
- // window when necessary.
- function poll() {
- var hash = get_fragment(),
- history_hash = history_get( last_hash );
-
- if ( hash !== last_hash ) {
- history_set( last_hash = hash, history_hash );
-
- $(window).trigger( str_hashchange );
-
- } else if ( history_hash !== last_hash ) {
- location.href = location.href.replace( /#.*/, '' ) + history_hash;
- }
-
- timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
- };
-
- // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
- // vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv
- // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
- $.browser.msie && !supports_onhashchange && (function(){
- // Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8
- // when running in "IE7 compatibility" mode.
-
- var iframe,
- iframe_src;
-
- // When the event is bound and polling starts in IE 6/7, create a hidden
- // Iframe for history handling.
- self.start = function(){
- if ( !iframe ) {
- iframe_src = $.fn[ str_hashchange ].src;
- iframe_src = iframe_src && iframe_src + get_fragment();
-
- // Create hidden Iframe. Attempt to make Iframe as hidden as possible
- // by using techniques from http://www.paciellogroup.com/blog/?p=604.
- iframe = $('<iframe tabindex="-1" title="empty"/>').hide()
-
- // When Iframe has completely loaded, initialize the history and
- // start polling.
- .one( 'load', function(){
- iframe_src || history_set( get_fragment() );
- poll();
- })
-
- // Load Iframe src if specified, otherwise nothing.
- .attr( 'src', iframe_src || 'javascript:0' )
-
- // Append Iframe after the end of the body to prevent unnecessary
- // initial page scrolling (yes, this works).
- .insertAfter( 'body' )[0].contentWindow;
-
- // Whenever `document.title` changes, update the Iframe's title to
- // prettify the back/next history menu entries. Since IE sometimes
- // errors with "Unspecified error" the very first time this is set
- // (yes, very useful) wrap this with a try/catch block.
- doc.onpropertychange = function(){
- try {
- if ( event.propertyName === 'title' ) {
- iframe.document.title = doc.title;
- }
- } catch(e) {}
- };
-
- }
- };
-
- // Override the "stop" method since an IE6/7 Iframe was created. Even
- // if there are no longer any bound event handlers, the polling loop
- // is still necessary for back/next to work at all!
- self.stop = fn_retval;
-
- // Get history by looking at the hidden Iframe's location.hash.
- history_get = function() {
- return get_fragment( iframe.location.href );
- };
-
- // Set a new history item by opening and then closing the Iframe
- // document, *then* setting its location.hash. If document.domain has
- // been set, update that as well.
- history_set = function( hash, history_hash ) {
- var iframe_doc = iframe.document,
- domain = $.fn[ str_hashchange ].domain;
-
- if ( hash !== history_hash ) {
- // Update Iframe with any initial `document.title` that might be set.
- iframe_doc.title = doc.title;
-
- // Opening the Iframe's document after it has been closed is what
- // actually adds a history entry.
- iframe_doc.open();
-
- // Set document.domain for the Iframe document as well, if necessary.
- domain && iframe_doc.write( '<script>document.domain="' + domain + '"</script>' );
-
- iframe_doc.close();
-
- // Update the Iframe's hash, for great justice.
- iframe.location.hash = hash;
- }
- };
-
- })();
- // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- // ^^^^^^^^^^^^^^^^^^^ REMOVE IF NOT SUPPORTING IE6/7/8 ^^^^^^^^^^^^^^^^^^^
- // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
- return self;
- })();
-
-})(jQuery,this);
-/*
-* jQuery Mobile Framework : "page" plugin
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-
-(function( $, undefined ) {
-
-$.widget( "mobile.page", $.mobile.widget, {
- options: {
- theme: "c",
- domCache: false
- },
-
- _create: function() {
- var $elem = this.element,
- o = this.options;
-
- if ( this._trigger( "beforeCreate" ) === false ) {
- return;
- }
-
- $elem.addClass( "ui-page ui-body-" + o.theme );
- }
-});
-
-})( jQuery );
-/*!
- * jQuery Mobile v@VERSION
- * http://jquerymobile.com/
- *
- * Copyright 2010, jQuery Project
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- */
-
-(function( $, window, undefined ) {
-
- // jQuery.mobile configurable options
- $.extend( $.mobile, {
-
- // Namespace used framework-wide for data-attrs. Default is no namespace
- ns: "",
-
- // Define the url parameter used for referencing widget-generated sub-pages.
- // Translates to to example.html&ui-page=subpageIdentifier
- // hash segment before &ui-page= is used to make Ajax request
- subPageUrlKey: "ui-page",
-
- // Class assigned to page currently in view, and during transitions
- activePageClass: "ui-page-active",
-
- // Class used for "active" button state, from CSS framework
- activeBtnClass: "ui-btn-active",
-
- // Automatically handle clicks and form submissions through Ajax, when same-domain
- ajaxEnabled: true,
-
- // Automatically load and show pages based on location.hash
- hashListeningEnabled: true,
-
- // Set default page transition - 'none' for no transitions
- defaultPageTransition: "slide",
-
- // Minimum scroll distance that will be remembered when returning to a page
- minScrollBack: screen.height / 2,
-
- // Set default dialog transition - 'none' for no transitions
- defaultDialogTransition: "pop",
-
- // Show loading message during Ajax requests
- // if false, message will not appear, but loading classes will still be toggled on html el
- loadingMessage: "loading",
-
- // Error response message - appears when an Ajax page request fails
- pageLoadErrorMessage: "Error Loading Page",
-
- //automatically initialize the DOM when it's ready
- autoInitializePage: true,
-
- // Support conditions that must be met in order to proceed
- // default enhanced qualifications are media query support OR IE 7+
- gradeA: function(){
- return $.support.mediaquery || $.mobile.browser.ie && $.mobile.browser.ie >= 7;
- },
-
- // TODO might be useful upstream in jquery itself ?
- keyCode: {
- ALT: 18,
- BACKSPACE: 8,
- CAPS_LOCK: 20,
- COMMA: 188,
- COMMAND: 91,
- COMMAND_LEFT: 91, // COMMAND
- COMMAND_RIGHT: 93,
- CONTROL: 17,
- DELETE: 46,
- DOWN: 40,
- END: 35,
- ENTER: 13,
- ESCAPE: 27,
- HOME: 36,
- INSERT: 45,
- LEFT: 37,
- MENU: 93, // COMMAND_RIGHT
- NUMPAD_ADD: 107,
- NUMPAD_DECIMAL: 110,
- NUMPAD_DIVIDE: 111,
- NUMPAD_ENTER: 108,
- NUMPAD_MULTIPLY: 106,
- NUMPAD_SUBTRACT: 109,
- PAGE_DOWN: 34,
- PAGE_UP: 33,
- PERIOD: 190,
- RIGHT: 39,
- SHIFT: 16,
- SPACE: 32,
- TAB: 9,
- UP: 38,
- WINDOWS: 91 // COMMAND
- },
-
- // Scroll page vertically: scroll to 0 to hide iOS address bar, or pass a Y value
- silentScroll: function( ypos ) {
- if ( $.type( ypos ) !== "number" ) {
- ypos = $.mobile.defaultHomeScroll;
- }
-
- // prevent scrollstart and scrollstop events
- $.event.special.scrollstart.enabled = false;
-
- setTimeout(function() {
- window.scrollTo( 0, ypos );
- $( document ).trigger( "silentscroll", { x: 0, y: ypos });
- }, 20 );
-
- setTimeout(function() {
- $.event.special.scrollstart.enabled = true;
- }, 150 );
- },
-
- // Take a data attribute property, prepend the namespace
- // and then camel case the attribute string
- nsNormalize: function( prop ) {
- if ( !prop ) {
- return;
- }
-
- return $.camelCase( $.mobile.ns + prop );
- }
- });
-
- // Mobile version of data and removeData and hasData methods
- // ensures all data is set and retrieved using jQuery Mobile's data namespace
- $.fn.jqmData = function( prop, value ) {
- return this.data( prop ? $.mobile.nsNormalize( prop ) : prop, value );
- };
-
- $.jqmData = function( elem, prop, value ) {
- return $.data( elem, $.mobile.nsNormalize( prop ), value );
- };
-
- $.fn.jqmRemoveData = function( prop ) {
- return this.removeData( $.mobile.nsNormalize( prop ) );
- };
-
- $.jqmRemoveData = function( elem, prop ) {
- return $.removeData( elem, $.mobile.nsNormalize( prop ) );
- };
-
- $.jqmHasData = function( elem, prop ) {
- return $.hasData( elem, $.mobile.nsNormalize( prop ) );
- };
-
- // Monkey-patching Sizzle to filter the :jqmData selector
- var oldFind = $.find;
-
- $.find = function( selector, context, ret, extra ) {
- selector = selector.replace(/:jqmData\(([^)]*)\)/g, "[data-" + ( $.mobile.ns || "" ) + "$1]");
-
- return oldFind.call( this, selector, context, ret, extra );
- };
-
- $.extend( $.find, oldFind );
-
- $.find.matches = function( expr, set ) {
- return $.find( expr, null, null, set );
- };
-
- $.find.matchesSelector = function( node, expr ) {
- return $.find( expr, null, null, [ node ] ).length > 0;
- };
-})( jQuery, this );
-/*
-* jQuery Mobile Framework : core utilities for auto ajax navigation, base tag mgmt,
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-( function( $, undefined ) {
-
- //define vars for interal use
- var $window = $( window ),
- $html = $( 'html' ),
- $head = $( 'head' ),
-
- //url path helpers for use in relative url management
- path = {
-
- // This scary looking regular expression parses an absolute URL or its relative
- // variants (protocol, site, document, query, and hash), into the various
- // components (protocol, host, path, query, fragment, etc that make up the
- // URL as well as some other commonly used sub-parts. When used with RegExp.exec()
- // or String.match, it parses the URL into a results array that looks like this:
- //
- // [0]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread#msg-content
- // [1]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread
- // [2]: http://jblas:password@mycompany.com:8080/mail/inbox
- // [3]: http://jblas:password@mycompany.com:8080
- // [4]: http:
- // [5]: jblas:password@mycompany.com:8080
- // [6]: jblas:password
- // [7]: jblas
- // [8]: password
- // [9]: mycompany.com:8080
- // [10]: mycompany.com
- // [11]: 8080
- // [12]: /mail/inbox
- // [13]: /mail/
- // [14]: inbox
- // [15]: ?msg=1234&type=unread
- // [16]: #msg-content
- //
- urlParseRE: /^(((([^:\/#\?]+:)?(?:\/\/((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?]+)(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,
-
- //Parse a URL into a structure that allows easy access to
- //all of the URL components by name.
- parseUrl: function( url ) {
- // If we're passed an object, we'll assume that it is
- // a parsed url object and just return it back to the caller.
- if ( $.type( url ) === "object" ) {
- return url;
- }
-
- var u = url || "",
- matches = path.urlParseRE.exec( url ),
- results;
- if ( matches ) {
- // Create an object that allows the caller to access the sub-matches
- // by name. Note that IE returns an empty string instead of undefined,
- // like all other browsers do, so we normalize everything so its consistent
- // no matter what browser we're running on.
- results = {
- href: matches[0] || "",
- hrefNoHash: matches[1] || "",
- hrefNoSearch: matches[2] || "",
- domain: matches[3] || "",
- protocol: matches[4] || "",
- authority: matches[5] || "",
- username: matches[7] || "",
- password: matches[8] || "",
- host: matches[9] || "",
- hostname: matches[10] || "",
- port: matches[11] || "",
- pathname: matches[12] || "",
- directory: matches[13] || "",
- filename: matches[14] || "",
- search: matches[15] || "",
- hash: matches[16] || ""
- };
- }
- return results || {};
- },
-
- //Turn relPath into an asbolute path. absPath is
- //an optional absolute path which describes what
- //relPath is relative to.
- makePathAbsolute: function( relPath, absPath ) {
- if ( relPath && relPath.charAt( 0 ) === "/" ) {
- return relPath;
- }
-
- relPath = relPath || "";
- absPath = absPath ? absPath.replace( /^\/|(\/[^\/]*|[^\/]+)$/g, "" ) : "";
-
- var absStack = absPath ? absPath.split( "/" ) : [],
- relStack = relPath.split( "/" );
- for ( var i = 0; i < relStack.length; i++ ) {
- var d = relStack[ i ];
- switch ( d ) {
- case ".":
- break;
- case "..":
- if ( absStack.length ) {
- absStack.pop();
- }
- break;
- default:
- absStack.push( d );
- break;
- }
- }
- return "/" + absStack.join( "/" );
- },
-
- //Returns true if both urls have the same domain.
- isSameDomain: function( absUrl1, absUrl2 ) {
- return path.parseUrl( absUrl1 ).domain === path.parseUrl( absUrl2 ).domain;
- },
-
- //Returns true for any relative variant.
- isRelativeUrl: function( url ) {
- // All relative Url variants have one thing in common, no protocol.
- return path.parseUrl( url ).protocol === "";
- },
-
- //Returns true for an absolute url.
- isAbsoluteUrl: function( url ) {
- return path.parseUrl( url ).protocol !== "";
- },
-
- //Turn the specified realtive URL into an absolute one. This function
- //can handle all relative variants (protocol, site, document, query, fragment).
- makeUrlAbsolute: function( relUrl, absUrl ) {
- if ( !path.isRelativeUrl( relUrl ) ) {
- return relUrl;
- }
-
- var relObj = path.parseUrl( relUrl ),
- absObj = path.parseUrl( absUrl ),
- protocol = relObj.protocol || absObj.protocol,
- authority = relObj.authority || absObj.authority,
- hasPath = relObj.pathname !== "",
- pathname = path.makePathAbsolute( relObj.pathname || absObj.filename, absObj.pathname ),
- search = relObj.search || ( !hasPath && absObj.search ) || "",
- hash = relObj.hash;
-
- return protocol + "//" + authority + pathname + search + hash;
- },
-
- //Add search (aka query) params to the specified url.
- addSearchParams: function( url, params ) {
- var u = path.parseUrl( url ),
- p = ( typeof params === "object" ) ? $.param( params ) : params,
- s = u.search || "?";
- return u.hrefNoSearch + s + ( s.charAt( s.length - 1 ) !== "?" ? "&" : "" ) + p + ( u.hash || "" );
- },
-
- convertUrlToDataUrl: function( absUrl ) {
- var u = path.parseUrl( absUrl );
- if ( path.isEmbeddedPage( u ) ) {
- // For embedded pages, remove the dialog hash key as in getFilePath(),
- // otherwise the Data Url won't match the id of the embedded Page.
- return u.hash.split( dialogHashKey )[0].replace( /^#/, "" );
- } else if ( path.isSameDomain( u, documentBase ) ) {
- return u.hrefNoHash.replace( documentBase.domain, "" );
- }
- return absUrl;
- },
-
- //get path from current hash, or from a file path
- get: function( newPath ) {
- if( newPath === undefined ) {
- newPath = location.hash;
- }
- return path.stripHash( newPath ).replace( /[^\/]*\.[^\/*]+$/, '' );
- },
-
- //return the substring of a filepath before the sub-page key, for making a server request
- getFilePath: function( path ) {
- var splitkey = '&' + $.mobile.subPageUrlKey;
- return path && path.split( splitkey )[0].split( dialogHashKey )[0];
- },
-
- //set location hash to path
- set: function( path ) {
- location.hash = path;
- },
-
- //test if a given url (string) is a path
- //NOTE might be exceptionally naive
- isPath: function( url ) {
- return ( /\// ).test( url );
- },
-
- //return a url path with the window's location protocol/hostname/pathname removed
- clean: function( url ) {
- return url.replace( documentBase.domain, "" );
- },
-
- //just return the url without an initial #
- stripHash: function( url ) {
- return url.replace( /^#/, "" );
- },
-
- //remove the preceding hash, any query params, and dialog notations
- cleanHash: function( hash ) {
- return path.stripHash( hash.replace( /\?.*$/, "" ).replace( dialogHashKey, "" ) );
- },
-
- //check whether a url is referencing the same domain, or an external domain or different protocol
- //could be mailto, etc
- isExternal: function( url ) {
- var u = path.parseUrl( url );
- return u.protocol && u.domain !== documentUrl.domain ? true : false;
- },
-
- hasProtocol: function( url ) {
- return ( /^(:?\w+:)/ ).test( url );
- },
-
- isEmbeddedPage: function( url ) {
- var u = path.parseUrl( url );
-
- //if the path is absolute, then we need to compare the url against
- //both the documentUrl and the documentBase. The main reason for this
- //is that links embedded within external documents will refer to the
- //application document, whereas links embedded within the application
- //document will be resolved against the document base.
- if ( u.protocol !== "" ) {
- return ( u.hash && ( u.hrefNoHash === documentUrl.hrefNoHash || ( documentBaseDiffers && u.hrefNoHash === documentBase.hrefNoHash ) ) );
- }
- return (/^#/).test( u.href );
- }
- },
-
- //will be defined when a link is clicked and given an active class
- $activeClickedLink = null,
-
- //urlHistory is purely here to make guesses at whether the back or forward button was clicked
- //and provide an appropriate transition
- urlHistory = {
- // Array of pages that are visited during a single page load.
- // Each has a url and optional transition, title, and pageUrl (which represents the file path, in cases where URL is obscured, such as dialogs)
- stack: [],
-
- //maintain an index number for the active page in the stack
- activeIndex: 0,
-
- //get active
- getActive: function() {
- return urlHistory.stack[ urlHistory.activeIndex ];
- },
-
- getPrev: function() {
- return urlHistory.stack[ urlHistory.activeIndex - 1 ];
- },
-
- getNext: function() {
- return urlHistory.stack[ urlHistory.activeIndex + 1 ];
- },
-
- // addNew is used whenever a new page is added
- addNew: function( url, transition, title, pageUrl ) {
- //if there's forward history, wipe it
- if( urlHistory.getNext() ) {
- urlHistory.clearForward();
- }
-
- urlHistory.stack.push( {url : url, transition: transition, title: title, pageUrl: pageUrl } );
-
- urlHistory.activeIndex = urlHistory.stack.length - 1;
- },
-
- //wipe urls ahead of active index
- clearForward: function() {
- urlHistory.stack = urlHistory.stack.slice( 0, urlHistory.activeIndex + 1 );
- },
-
- directHashChange: function( opts ) {
- var back , forward, newActiveIndex;
-
- // check if url isp in history and if it's ahead or behind current page
- $.each( urlHistory.stack, function( i, historyEntry ) {
-
- //if the url is in the stack, it's a forward or a back
- if( opts.currentUrl === historyEntry.url ) {
- //define back and forward by whether url is older or newer than current page
- back = i < urlHistory.activeIndex;
- forward = !back;
- newActiveIndex = i;
- }
- });
-
- // save new page index, null check to prevent falsey 0 result
- this.activeIndex = newActiveIndex !== undefined ? newActiveIndex : this.activeIndex;
-
- if( back ) {
- opts.isBack();
- } else if( forward ) {
- opts.isForward();
- }
- },
-
- //disable hashchange event listener internally to ignore one change
- //toggled internally when location.hash is updated to match the url of a successful page load
- ignoreNextHashChange: false
- },
-
- //define first selector to receive focus when a page is shown
- focusable = "[tabindex],a,button:visible,select:visible,input",
-
- //queue to hold simultanious page transitions
- pageTransitionQueue = [],
-
- //indicates whether or not page is in process of transitioning
- isPageTransitioning = false,
-
- //nonsense hash change key for dialogs, so they create a history entry
- dialogHashKey = "&ui-state=dialog",
-
- //existing base tag?
- $base = $head.children( "base" ),
-
- //tuck away the original document URL minus any fragment.
- documentUrl = path.parseUrl( location.href ),
-
- //if the document has an embedded base tag, documentBase is set to its
- //initial value. If a base tag does not exist, then we default to the documentUrl.
- documentBase = $base.length ? path.parseUrl( path.makeUrlAbsolute( $base.attr( "href" ), documentUrl.href ) ) : documentUrl,
-
- //cache the comparison once.
- documentBaseDiffers = ( documentUrl.hrefNoHash !== documentBase.hrefNoHash );
-
- //base element management, defined depending on dynamic base tag support
- var base = $.support.dynamicBaseTag ? {
-
- //define base element, for use in routing asset urls that are referenced in Ajax-requested markup
- element: ( $base.length ? $base : $( "<base>", { href: documentBase.hrefNoHash } ).prependTo( $head ) ),
-
- //set the generated BASE element's href attribute to a new page's base path
- set: function( href ) {
- base.element.attr( "href", path.makeUrlAbsolute( href, documentBase ) );
- },
-
- //set the generated BASE element's href attribute to a new page's base path
- reset: function() {
- base.element.attr( "href", documentBase.hrefNoHash );
- }
-
- } : undefined;
-
-/*
- internal utility functions
---------------------------------------*/
-
-
- //direct focus to the page title, or otherwise first focusable element
- function reFocus( page ) {
- var lastClicked = page.jqmData( "lastClicked" );
-
- if( lastClicked && lastClicked.length ) {
- lastClicked.focus();
- }
- else {
- var pageTitle = page.find( ".ui-title:eq(0)" );
-
- if( pageTitle.length ) {
- pageTitle.focus();
- }
- else{
- page.find( focusable ).eq( 0 ).focus();
- }
- }
- }
-
- //remove active classes after page transition or error
- function removeActiveLinkClass( forceRemoval ) {
- if( !!$activeClickedLink && ( !$activeClickedLink.closest( '.ui-page-active' ).length || forceRemoval ) ) {
- $activeClickedLink.removeClass( $.mobile.activeBtnClass );
- }
- $activeClickedLink = null;
- }
-
- function releasePageTransitionLock() {
- isPageTransitioning = false;
- if( pageTransitionQueue.length > 0 ) {
- $.mobile.changePage.apply( null, pageTransitionQueue.pop() );
- }
- }
-
- //function for transitioning between two existing pages
- function transitionPages( toPage, fromPage, transition, reverse ) {
-
- //get current scroll distance
- var currScroll = $.support.scrollTop ? $window.scrollTop() : true,
- toScroll = toPage.data( "lastScroll" ) || $.mobile.defaultHomeScroll,
- screenHeight = getScreenHeight();
-
- //if scrolled down, scroll to top
- if( currScroll ){
- window.scrollTo( 0, $.mobile.defaultHomeScroll );
- }
-
- //if the Y location we're scrolling to is less than 10px, let it go for sake of smoothness
- if( toScroll < $.mobile.minScrollBack ){
- toScroll = 0;
- }
-
- if( fromPage ) {
- //set as data for returning to that spot
- fromPage
- .height( screenHeight + currScroll )
- .jqmData( "lastScroll", currScroll )
- .jqmData( "lastClicked", $activeClickedLink );
-
- //trigger before show/hide events
- fromPage.data( "page" )._trigger( "beforehide", null, { nextPage: toPage } );
- }
- toPage
- .height( screenHeight + toScroll )
- .data( "page" )._trigger( "beforeshow", null, { prevPage: fromPage || $( "" ) } );
-
- //clear page loader
- $.mobile.hidePageLoadingMsg();
-
- //find the transition handler for the specified transition. If there
- //isn't one in our transitionHandlers dictionary, use the default one.
- //call the handler immediately to kick-off the transition.
- var th = $.mobile.transitionHandlers[transition || "none"] || $.mobile.defaultTransitionHandler,
- promise = th( transition, reverse, toPage, fromPage );
-
- promise.done(function() {
- //reset toPage height bac
- toPage.height( "" );
-
- //jump to top or prev scroll, sometimes on iOS the page has not rendered yet.
- if( toScroll ){
- $.mobile.silentScroll( toScroll );
- $( document ).one( "silentscroll", function() { reFocus( toPage ); } );
- }
- else{
- reFocus( toPage );
- }
-
- //trigger show/hide events
- if( fromPage ) {
- fromPage.height("").data( "page" )._trigger( "hide", null, { nextPage: toPage } );
- }
-
- //trigger pageshow, define prevPage as either fromPage or empty jQuery obj
- toPage.data( "page" )._trigger( "show", null, { prevPage: fromPage || $( "" ) } );
- });
-
- return promise;
- }
-
- //simply set the active page's minimum height to screen height, depending on orientation
- function getScreenHeight(){
- var orientation = jQuery.event.special.orientationchange.orientation(),
- port = orientation === "portrait",
- winMin = port ? 480 : 320,
- screenHeight = port ? screen.availHeight : screen.availWidth,
- winHeight = Math.max( winMin, $( window ).height() ),
- pageMin = Math.min( screenHeight, winHeight );
-
- return pageMin;
- }
-
- //simply set the active page's minimum height to screen height, depending on orientation
- function resetActivePageHeight(){
- $( "." + $.mobile.activePageClass ).css( "min-height", getScreenHeight() );
- }
-
- //shared page enhancements
- function enhancePage( $page, role ) {
- // If a role was specified, make sure the data-role attribute
- // on the page element is in sync.
- if( role ) {
- $page.attr( "data-" + $.mobile.ns + "role", role );
- }
-
- //run page plugin
- $page.page();
- }
-
-/* exposed $.mobile methods */
-
- //animation complete callback
- $.fn.animationComplete = function( callback ) {
- if( $.support.cssTransitions ) {
- return $( this ).one( 'webkitAnimationEnd', callback );
- }
- else{
- // defer execution for consistency between webkit/non webkit
- setTimeout( callback, 0 );
- return $( this );
- }
- };
-
- //update location.hash, with or without triggering hashchange event
- //TODO - deprecate this one at 1.0
- $.mobile.updateHash = path.set;
-
- //expose path object on $.mobile
- $.mobile.path = path;
-
- //expose base object on $.mobile
- $.mobile.base = base;
-
- //url stack, useful when plugins need to be aware of previous pages viewed
- //TODO: deprecate this one at 1.0
- $.mobile.urlstack = urlHistory.stack;
-
- //history stack
- $.mobile.urlHistory = urlHistory;
-
- //default non-animation transition handler
- $.mobile.noneTransitionHandler = function( name, reverse, $toPage, $fromPage ) {
- if ( $fromPage ) {
- $fromPage.removeClass( $.mobile.activePageClass );
- }
- $toPage.addClass( $.mobile.activePageClass );
-
- return $.Deferred().resolve( name, reverse, $toPage, $fromPage ).promise();
- };
-
- //default handler for unknown transitions
- $.mobile.defaultTransitionHandler = $.mobile.noneTransitionHandler;
-
- //transition handler dictionary for 3rd party transitions
- $.mobile.transitionHandlers = {
- none: $.mobile.defaultTransitionHandler
- };
-
- //enable cross-domain page support
- $.mobile.allowCrossDomainPages = false;
-
- //return the original document url
- $.mobile.getDocumentUrl = function(asParsedObject) {
- return asParsedObject ? $.extend( {}, documentUrl ) : documentUrl.href;
- };
-
- //return the original document base url
- $.mobile.getDocumentBase = function(asParsedObject) {
- return asParsedObject ? $.extend( {}, documentBase ) : documentBase.href;
- };
-
- // Load a page into the DOM.
- $.mobile.loadPage = function( url, options ) {
- // This function uses deferred notifications to let callers
- // know when the page is done loading, or if an error has occurred.
- var deferred = $.Deferred(),
-
- // The default loadPage options with overrides specified by
- // the caller.
- settings = $.extend( {}, $.mobile.loadPage.defaults, options ),
-
- // The DOM element for the page after it has been loaded.
- page = null,
-
- // If the reloadPage option is true, and the page is already
- // in the DOM, dupCachedPage will be set to the page element
- // so that it can be removed after the new version of the
- // page is loaded off the network.
- dupCachedPage = null,
-
- // determine the current base url
- findBaseWithDefault = function(){
- var closestBase = ( $.mobile.activePage && getClosestBaseUrl( $.mobile.activePage ) );
- return closestBase || documentBase.hrefNoHash;
- },
-
- // The absolute version of the URL passed into the function. This
- // version of the URL may contain dialog/subpage params in it.
- absUrl = path.makeUrlAbsolute( url, findBaseWithDefault() );
-
-
- // If the caller provided data, and we're using "get" request,
- // append the data to the URL.
- if ( settings.data && settings.type === "get" ) {
- absUrl = path.addSearchParams( absUrl, settings.data );
- settings.data = undefined;
- }
-
- // The absolute version of the URL minus any dialog/subpage params.
- // In otherwords the real URL of the page to be loaded.
- var fileUrl = path.getFilePath( absUrl ),
-
- // The version of the Url actually stored in the data-url attribute of
- // the page. For embedded pages, it is just the id of the page. For pages
- // within the same domain as the document base, it is the site relative
- // path. For cross-domain pages (Phone Gap only) the entire absolute Url
- // used to load the page.
- dataUrl = path.convertUrlToDataUrl( absUrl );
-
- // Make sure we have a pageContainer to work with.
- settings.pageContainer = settings.pageContainer || $.mobile.pageContainer;
-
- // Check to see if the page already exists in the DOM.
- page = settings.pageContainer.children( ":jqmData(url='" + dataUrl + "')" );
-
- // Reset base to the default document base.
- if ( base ) {
- base.reset();
- }
-
- // If the page we are interested in is already in the DOM,
- // and the caller did not indicate that we should force a
- // reload of the file, we are done. Otherwise, track the
- // existing page as a duplicated.
- if ( page.length ) {
- if ( !settings.reloadPage ) {
- enhancePage( page, settings.role );
- deferred.resolve( absUrl, options, page );
- return deferred.promise();
- }
- dupCachedPage = page;
- }
-
- if ( settings.showLoadMsg ) {
-
- // This configurable timeout allows cached pages a brief delay to load without showing a message
- var loadMsgDelay = setTimeout(function(){
- $.mobile.showPageLoadingMsg();
- }, settings.loadMsgDelay ),
-
- // Shared logic for clearing timeout and removing message.
- hideMsg = function(){
-
- // Stop message show timer
- clearTimeout( loadMsgDelay );
-
- // Hide loading message
- $.mobile.hidePageLoadingMsg();
- };
- }
-
- if ( !( $.mobile.allowCrossDomainPages || path.isSameDomain( documentUrl, absUrl ) ) ) {
- deferred.reject( absUrl, options );
- } else {
- // Load the new page.
- $.ajax({
- url: fileUrl,
- type: settings.type,
- data: settings.data,
- dataType: "html",
- success: function( html ) {
- //pre-parse html to check for a data-url,
- //use it as the new fileUrl, base path, etc
- var all = $( "<div></div>" ),
-
- //page title regexp
- newPageTitle = html.match( /<title[^>]*>([^<]*)/ ) && RegExp.$1,
-
- // TODO handle dialogs again
- pageElemRegex = new RegExp( ".*(<[^>]+\\bdata-" + $.mobile.ns + "role=[\"']?page[\"']?[^>]*>).*" ),
- dataUrlRegex = new RegExp( "\\bdata-" + $.mobile.ns + "url=[\"']?([^\"'>]*)[\"']?" );
-
-
- // data-url must be provided for the base tag so resource requests can be directed to the
- // correct url. loading into a temprorary element makes these requests immediately
- if( pageElemRegex.test( html )
- && RegExp.$1
- && dataUrlRegex.test( RegExp.$1 )
- && RegExp.$1 ) {
- url = fileUrl = path.getFilePath( RegExp.$1 );
- }
- else{
-
- }
-
- if ( base ) {
- base.set( fileUrl );
- }
-
- //workaround to allow scripts to execute when included in page divs
- all.get( 0 ).innerHTML = html;
- page = all.find( ":jqmData(role='page'), :jqmData(role='dialog')" ).first();
-
- //if page elem couldn't be found, create one and insert the body element's contents
- if( !page.length ){
- page = $( "<div data-" + $.mobile.ns + "role='page'>" + html.split( /<\/?body[^>]*>/gmi )[1] + "</div>" );
- }
-
- if ( newPageTitle && !page.jqmData( "title" ) ) {
- page.jqmData( "title", newPageTitle );
- }
-
- //rewrite src and href attrs to use a base url
- if( !$.support.dynamicBaseTag ) {
- var newPath = path.get( fileUrl );
- page.find( "[src], link[href], a[rel='external'], :jqmData(ajax='false'), a[target]" ).each(function() {
- var thisAttr = $( this ).is( '[href]' ) ? 'href' :
- $(this).is('[src]') ? 'src' : 'action',
- thisUrl = $( this ).attr( thisAttr );
-
- // XXX_jblas: We need to fix this so that it removes the document
- // base URL, and then prepends with the new page URL.
- //if full path exists and is same, chop it - helps IE out
- thisUrl = thisUrl.replace( location.protocol + '//' + location.host + location.pathname, '' );
-
- if( !/^(\w+:|#|\/)/.test( thisUrl ) ) {
- $( this ).attr( thisAttr, newPath + thisUrl );
- }
- });
- }
-
- //append to page and enhance
- page
- .attr( "data-" + $.mobile.ns + "url", path.convertUrlToDataUrl( fileUrl ) )
- .appendTo( settings.pageContainer );
-
- // wait for page creation to leverage options defined on widget
- page.one('pagecreate', function(){
-
- // when dom caching is not enabled bind to remove the page on hide
- if( !page.data("page").options.domCache ){
- page.bind( "pagehide.remove", function(){
- $(this).remove();
- });
- }
- });
-
- enhancePage( page, settings.role );
-
- // Enhancing the page may result in new dialogs/sub pages being inserted
- // into the DOM. If the original absUrl refers to a sub-page, that is the
- // real page we are interested in.
- if ( absUrl.indexOf( "&" + $.mobile.subPageUrlKey ) > -1 ) {
- page = settings.pageContainer.children( ":jqmData(url='" + dataUrl + "')" );
- }
-
- //bind pageHide to removePage after it's hidden, if the page options specify to do so
-
- // Remove loading message.
- if ( settings.showLoadMsg ) {
- hideMsg();
- }
-
- deferred.resolve( absUrl, options, page, dupCachedPage );
- },
- error: function() {
- //set base back to current path
- if( base ) {
- base.set( path.get() );
- }
-
- // Remove loading message.
- if ( settings.showLoadMsg ) {
-
- // Remove loading message.
- hideMsg();
-
- //show error message
- $( "<div class='ui-loader ui-overlay-shadow ui-body-e ui-corner-all'><h1>"+ $.mobile.pageLoadErrorMessage +"</h1></div>" )
- .css({ "display": "block", "opacity": 0.96, "top": $window.scrollTop() + 100 })
- .appendTo( settings.pageContainer )
- .delay( 800 )
- .fadeOut( 400, function() {
- $( this ).remove();
- });
- }
-
- deferred.reject( absUrl, options );
- }
- });
- }
-
- return deferred.promise();
- };
-
- $.mobile.loadPage.defaults = {
- type: "get",
- data: undefined,
- reloadPage: false,
- role: undefined, // By default we rely on the role defined by the @data-role attribute.
- showLoadMsg: false,
- pageContainer: undefined,
- loadMsgDelay: 50 // This delay allows loads that pull from browser cache to occur without showing the loading message.
- };
-
- // Show a specific page in the page container.
- $.mobile.changePage = function( toPage, options ) {
- // XXX: REMOVE_BEFORE_SHIPPING_1.0
- // This is temporary code that makes changePage() compatible with previous alpha versions.
- if ( typeof options !== "object" ) {
- var opts = null;
-
- // Map old-style call signature for form submit to the new options object format.
- if ( typeof toPage === "object" && toPage.url && toPage.type ) {
- opts = {
- type: toPage.type,
- data: toPage.data,
- forcePageLoad: true
- };
- toPage = toPage.url;
- }
-
- // The arguments passed into the function need to be re-mapped
- // to the new options object format.
- var len = arguments.length;
- if ( len > 1 ) {
- var argNames = [ "transition", "reverse", "changeHash", "fromHashChange" ], i;
- for ( i = 1; i < len; i++ ) {
- var a = arguments[ i ];
- if ( typeof a !== "undefined" ) {
- opts = opts || {};
- opts[ argNames[ i - 1 ] ] = a;
- }
- }
- }
-
- // If an options object was created, then we know changePage() was called
- // with an old signature.
- if ( opts ) {
- return $.mobile.changePage( toPage, opts );
- }
- }
- // XXX: REMOVE_BEFORE_SHIPPING_1.0
-
- // If we are in the midst of a transition, queue the current request.
- // We'll call changePage() once we're done with the current transition to
- // service the request.
- if( isPageTransitioning ) {
- pageTransitionQueue.unshift( arguments );
- return;
- }
-
- // Set the isPageTransitioning flag to prevent any requests from
- // entering this method while we are in the midst of loading a page
- // or transitioning.
-
- isPageTransitioning = true;
-
- var settings = $.extend( {}, $.mobile.changePage.defaults, options );
-
- // Make sure we have a pageContainer to work with.
- settings.pageContainer = settings.pageContainer || $.mobile.pageContainer;
-
- // If the caller passed us a url, call loadPage()
- // to make sure it is loaded into the DOM. We'll listen
- // to the promise object it returns so we know when
- // it is done loading or if an error ocurred.
- if ( typeof toPage == "string" ) {
- $.mobile.loadPage( toPage, settings )
- .done(function( url, options, newPage, dupCachedPage ) {
- isPageTransitioning = false;
- options.duplicateCachedPage = dupCachedPage;
- $.mobile.changePage( newPage, options );
- })
- .fail(function( url, options ) {
- // XXX_jblas: Fire off changepagefailed notificaiton.
- isPageTransitioning = false;
-
- //clear out the active button state
- removeActiveLinkClass( true );
-
- //release transition lock so navigation is free again
- releasePageTransitionLock();
- settings.pageContainer.trigger("changepagefailed");
- });
- return;
- }
-
- // The caller passed us a real page DOM element. Update our
- // internal state and then trigger a transition to the page.
- var mpc = settings.pageContainer,
- fromPage = $.mobile.activePage,
- url = toPage.jqmData( "url" ),
- // The pageUrl var is usually the same as url, except when url is obscured as a dialog url. pageUrl always contains the file path
- pageUrl = url,
- fileUrl = path.getFilePath( url ),
- active = urlHistory.getActive(),
- activeIsInitialPage = urlHistory.activeIndex === 0,
- historyDir = 0,
- pageTitle = document.title,
- isDialog = settings.role === "dialog" || toPage.jqmData( "role" ) === "dialog";
-
- // Let listeners know we're about to change the current page.
- mpc.trigger( "beforechangepage" );
-
- // If we are trying to transition to the same page that we are currently on ignore the request.
- // an illegal same page request is defined by the current page being the same as the url, as long as there's history
- // and toPage is not an array or object (those are allowed to be "same")
- //
- // XXX_jblas: We need to remove this at some point when we allow for transitions
- // to the same page.
- if( fromPage && fromPage[0] === toPage[0] ) {
- isPageTransitioning = false;
- mpc.trigger( "changepage" );
- return;
- }
-
- // We need to make sure the page we are given has already been enhanced.
- enhancePage( toPage, settings.role );
-
- // If the changePage request was sent from a hashChange event, check to see if the
- // page is already within the urlHistory stack. If so, we'll assume the user hit
- // the forward/back button and will try to match the transition accordingly.
- if( settings.fromHashChange ) {
- urlHistory.directHashChange({
- currentUrl: url,
- isBack: function() { historyDir = -1; },
- isForward: function() { historyDir = 1; }
- });
- }
-
- // Kill the keyboard.
- // XXX_jblas: We need to stop crawling the entire document to kill focus. Instead,
- // we should be tracking focus with a live() handler so we already have
- // the element in hand at this point.
- // Wrap this in a try/catch block since IE9 throw "Unspecified error" if document.activeElement
- // is undefined when we are in an IFrame.
- try {
- $( document.activeElement || "" ).add( "input:focus, textarea:focus, select:focus" ).blur();
- } catch(e) {}
-
- // If we're displaying the page as a dialog, we don't want the url
- // for the dialog content to be used in the hash. Instead, we want
- // to append the dialogHashKey to the url of the current page.
- if ( isDialog && active ) {
- url = active.url + dialogHashKey;
- }
-
- // Set the location hash.
- if( settings.changeHash !== false && url ) {
- //disable hash listening temporarily
- urlHistory.ignoreNextHashChange = true;
- //update hash and history
- path.set( url );
- }
-
- //if title element wasn't found, try the page div data attr too
- var newPageTitle = toPage.jqmData( "title" ) || toPage.children(":jqmData(role='header')").find(".ui-title" ).text();
- if( !!newPageTitle && pageTitle == document.title ) {
- pageTitle = newPageTitle;
- }
-
- //add page to history stack if it's not back or forward
- if( !historyDir ) {
- urlHistory.addNew( url, settings.transition, pageTitle, pageUrl );
- }
-
- //set page title
- document.title = urlHistory.getActive().title;
-
- //set "toPage" as activePage
- $.mobile.activePage = toPage;
-
- // Make sure we have a transition defined.
- settings.transition = settings.transition
- || ( ( historyDir && !activeIsInitialPage ) ? active.transition : undefined )
- || ( isDialog ? $.mobile.defaultDialogTransition : $.mobile.defaultPageTransition );
-
- // If we're navigating back in the URL history, set reverse accordingly.
- settings.reverse = settings.reverse || historyDir < 0;
-
- transitionPages( toPage, fromPage, settings.transition, settings.reverse )
- .done(function() {
- removeActiveLinkClass();
-
- //if there's a duplicateCachedPage, remove it from the DOM now that it's hidden
- if ( settings.duplicateCachedPage ) {
- settings.duplicateCachedPage.remove();
- }
-
- //remove initial build class (only present on first pageshow)
- $html.removeClass( "ui-mobile-rendering" );
-
- releasePageTransitionLock();
-
- // Let listeners know we're all done changing the current page.
- mpc.trigger( "changepage" );
- });
- };
-
- $.mobile.changePage.defaults = {
- transition: undefined,
- reverse: false,
- changeHash: true,
- fromHashChange: false,
- role: undefined, // By default we rely on the role defined by the @data-role attribute.
- duplicateCachedPage: undefined,
- pageContainer: undefined,
- showLoadMsg: true //loading message shows by default when pages are being fetched during changePage
- };
-
-/* Event Bindings - hashchange, submit, and click */
- function findClosestLink( ele )
- {
- while ( ele ) {
- if ( ele.nodeName.toLowerCase() == "a" ) {
- break;
- }
- ele = ele.parentNode;
- }
- return ele;
- }
-
- // The base URL for any given element depends on the page it resides in.
- function getClosestBaseUrl( ele )
- {
- // Find the closest page and extract out its url.
- var url = $( ele ).closest( ".ui-page" ).jqmData( "url" ),
- base = documentBase.hrefNoHash;
-
- if ( !url || !path.isPath( url ) ) {
- url = base;
- }
-
- return path.makeUrlAbsolute( url, base);
- }
-
-
- //The following event bindings should be bound after mobileinit has been triggered
- //the following function is called in the init file
- $.mobile._registerInternalEvents = function(){
-
- //bind to form submit events, handle with Ajax
- $( "form" ).live('submit', function( event ) {
- var $this = $( this );
- if( !$.mobile.ajaxEnabled ||
- $this.is( ":jqmData(ajax='false')" ) ) {
- return;
- }
-
- var type = $this.attr( "method" ),
- target = $this.attr( "target" ),
- url = $this.attr( "action" );
-
- // If no action is specified, browsers default to using the
- // URL of the document containing the form. Since we dynamically
- // pull in pages from external documents, the form should submit
- // to the URL for the source document of the page containing
- // the form.
- if ( !url ) {
- // Get the @data-url for the page containing the form.
- url = getClosestBaseUrl( $this );
- if ( url === documentBase.hrefNoHash ) {
- // The url we got back matches the document base,
- // which means the page must be an internal/embedded page,
- // so default to using the actual document url as a browser
- // would.
- url = documentUrl.hrefNoSearch;
- }
- }
-
- url = path.makeUrlAbsolute( url, getClosestBaseUrl($this) );
-
- //external submits use regular HTTP
- if( path.isExternal( url ) || target ) {
- return;
- }
-
- $.mobile.changePage(
- url,
- {
- type: type && type.length && type.toLowerCase() || "get",
- data: $this.serialize(),
- transition: $this.jqmData( "transition" ),
- direction: $this.jqmData( "direction" ),
- reloadPage: true
- }
- );
- event.preventDefault();
- });
-
- //add active state on vclick
- $( document ).bind( "vclick", function( event ) {
- var link = findClosestLink( event.target );
- if ( link ) {
- if ( path.parseUrl( link.getAttribute( "href" ) || "#" ).hash !== "#" ) {
- $( link ).closest( ".ui-btn" ).not( ".ui-disabled" ).addClass( $.mobile.activeBtnClass );
- $( "." + $.mobile.activePageClass + " .ui-btn" ).not( link ).blur();
- }
- }
- });
-
- // click routing - direct to HTTP or Ajax, accordingly
- $( document ).bind( "click", function( event ) {
- var link = findClosestLink( event.target );
- if ( !link ) {
- return;
- }
-
- var $link = $( link ),
- //remove active link class if external (then it won't be there if you come back)
- httpCleanup = function(){
- window.setTimeout( function() { removeActiveLinkClass( true ); }, 200 );
- };
-
- //if there's a data-rel=back attr, go back in history
- if( $link.is( ":jqmData(rel='back')" ) ) {
- window.history.back();
- return false;
- }
-
- //if ajax is disabled, exit early
- if( !$.mobile.ajaxEnabled ){
- httpCleanup();
- //use default click handling
- return;
- }
-
- var baseUrl = getClosestBaseUrl( $link ),
-
- //get href, if defined, otherwise default to empty hash
- href = path.makeUrlAbsolute( $link.attr( "href" ) || "#", baseUrl );
-
- // XXX_jblas: Ideally links to application pages should be specified as
- // an url to the application document with a hash that is either
- // the site relative path or id to the page. But some of the
- // internal code that dynamically generates sub-pages for nested
- // lists and select dialogs, just write a hash in the link they
- // create. This means the actual URL path is based on whatever
- // the current value of the base tag is at the time this code
- // is called. For now we are just assuming that any url with a
- // hash in it is an application page reference.
- if ( href.search( "#" ) != -1 ) {
- href = href.replace( /[^#]*#/, "" );
- if ( !href ) {
- //link was an empty hash meant purely
- //for interaction, so we ignore it.
- event.preventDefault();
- return;
- } else if ( path.isPath( href ) ) {
- //we have apath so make it the href we want to load.
- href = path.makeUrlAbsolute( href, baseUrl );
- } else {
- //we have a simple id so use the documentUrl as its base.
- href = path.makeUrlAbsolute( "#" + href, documentUrl.hrefNoHash );
- }
- }
-
- // Should we handle this link, or let the browser deal with it?
- var useDefaultUrlHandling = $link.is( "[rel='external']" ) || $link.is( ":jqmData(ajax='false')" ) || $link.is( "[target]" ),
-
- // Some embedded browsers, like the web view in Phone Gap, allow cross-domain XHR
- // requests if the document doing the request was loaded via the file:// protocol.
- // This is usually to allow the application to "phone home" and fetch app specific
- // data. We normally let the browser handle external/cross-domain urls, but if the
- // allowCrossDomainPages option is true, we will allow cross-domain http/https
- // requests to go through our page loading logic.
- isCrossDomainPageLoad = ( $.mobile.allowCrossDomainPages && documentUrl.protocol === "file:" && href.search( /^https?:/ ) != -1 ),
-
- //check for protocol or rel and its not an embedded page
- //TODO overlap in logic from isExternal, rel=external check should be
- // moved into more comprehensive isExternalLink
- isExternal = useDefaultUrlHandling || ( path.isExternal( href ) && !isCrossDomainPageLoad );
-
- $activeClickedLink = $link.closest( ".ui-btn" );
-
- if( isExternal ) {
- httpCleanup();
- //use default click handling
- return;
- }
-
- //use ajax
- var transition = $link.jqmData( "transition" ),
- direction = $link.jqmData( "direction" ),
- reverse = ( direction && direction === "reverse" ) ||
- // deprecated - remove by 1.0
- $link.jqmData( "back" ),
-
- //this may need to be more specific as we use data-rel more
- role = $link.attr( "data-" + $.mobile.ns + "rel" ) || undefined;
-
- $.mobile.changePage( href, { transition: transition, reverse: reverse, role: role } );
- event.preventDefault();
- });
-
- //prefetch pages when anchors with data-prefetch are encountered
- $( ".ui-page" ).live( "pageshow.prefetch", function(){
- var urls = [];
- $( this ).find( "a:jqmData(prefetch)" ).each(function(){
- var url = $( this ).attr( "href" );
- if ( url && $.inArray( url, urls ) === -1 ) {
- urls.push( url );
- $.mobile.loadPage( url );
- }
- });
- } );
-
- //hashchange event handler
- $window.bind( "hashchange", function( e, triggered ) {
- //find first page via hash
- var to = path.stripHash( location.hash ),
- //transition is false if it's the first page, undefined otherwise (and may be overridden by default)
- transition = $.mobile.urlHistory.stack.length === 0 ? "none" : undefined;
-
- //if listening is disabled (either globally or temporarily), or it's a dialog hash
- if( !$.mobile.hashListeningEnabled || urlHistory.ignoreNextHashChange ) {
- urlHistory.ignoreNextHashChange = false;
- return;
- }
-
- // special case for dialogs
- if( urlHistory.stack.length > 1 &&
- to.indexOf( dialogHashKey ) > -1 ) {
-
- // If current active page is not a dialog skip the dialog and continue
- // in the same direction
- if(!$.mobile.activePage.is( ".ui-dialog" )) {
- //determine if we're heading forward or backward and continue accordingly past
- //the current dialog
- urlHistory.directHashChange({
- currentUrl: to,
- isBack: function() { window.history.back(); },
- isForward: function() { window.history.forward(); }
- });
-
- // prevent changepage
- return;
- } else {
- var setTo = function() { to = $.mobile.urlHistory.getActive().pageUrl; };
- // if the current active page is a dialog and we're navigating
- // to a dialog use the dialog objected saved in the stack
- urlHistory.directHashChange({ currentUrl: to, isBack: setTo, isForward: setTo });
- }
- }
-
- //if to is defined, load it
- if ( to ) {
- to = ( typeof to === "string" && !path.isPath( to ) ) ? ( '#' + to ) : to;
- $.mobile.changePage( to, { transition: transition, changeHash: false, fromHashChange: true } );
- }
- //there's no hash, go to the first page in the dom
- else {
- $.mobile.changePage( $.mobile.firstPage, { transition: transition, changeHash: false, fromHashChange: true } );
- }
- });
-
- //set page min-heights to be device specific
- $( document ).bind( "pageshow", resetActivePageHeight );
- $( window ).bind( "throttledresize", resetActivePageHeight );
-
- };//_registerInternalEvents callback
-
-})( jQuery );
-/*!
- * jQuery Mobile v@VERSION
- * http://jquerymobile.com/
- *
- * Copyright 2010, jQuery Project
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- */
-
-(function( $, window, undefined ) {
-
-function css3TransitionHandler( name, reverse, $to, $from ) {
-
- var deferred = new $.Deferred(),
- reverseClass = reverse ? " reverse" : "",
- viewportClass = "ui-mobile-viewport-transitioning viewport-" + name,
- doneFunc = function() {
-
- $to.add( $from ).removeClass( "out in reverse " + name );
-
- if ( $from ) {
- $from.removeClass( $.mobile.activePageClass );
- }
-
- $to.parent().removeClass( viewportClass );
-
- deferred.resolve( name, reverse, $to, $from );
- };
-
- $to.animationComplete( doneFunc );
-
- $to.parent().addClass( viewportClass );
-
- if ( $from ) {
- $from.addClass( name + " out" + reverseClass );
- }
- $to.addClass( $.mobile.activePageClass + " " + name + " in" + reverseClass );
-
- return deferred.promise();
-}
-
-// Make our transition handler public.
-$.mobile.css3TransitionHandler = css3TransitionHandler;
-
-// If the default transition handler is the 'none' handler, replace it with our handler.
-if ( $.mobile.defaultTransitionHandler === $.mobile.noneTransitionHandler ) {
- $.mobile.defaultTransitionHandler = css3TransitionHandler;
-}
-
-})( jQuery, this );
-/*
-* jQuery Mobile Framework : "degradeInputs" plugin - degrades inputs to another type after custom enhancements are made.
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-
-(function( $, undefined ) {
-
-$.mobile.page.prototype.options.degradeInputs = {
- color: false,
- date: false,
- datetime: false,
- "datetime-local": false,
- email: false,
- month: false,
- number: false,
- range: "number",
- search: true,
- tel: false,
- time: false,
- url: false,
- week: false
-};
-
-$.mobile.page.prototype.options.keepNative = ":jqmData(role='none'), :jqmData(role='nojs')";
-
-
-//auto self-init widgets
-$( document ).bind( "pagecreate enhance", function( e ){
-
- var page = $( e.target ).data( "page" ),
- o = page.options;
-
- // degrade inputs to avoid poorly implemented native functionality
- $( e.target ).find( "input" ).not( o.keepNative ).each(function() {
- var $this = $( this ),
- type = this.getAttribute( "type" ),
- optType = o.degradeInputs[ type ] || "text";
-
- if ( o.degradeInputs[ type ] ) {
- $this.replaceWith(
- $( "<div>" ).html( $this.clone() ).html()
- .replace( /\s+type=["']?\w+['"]?/, " type=\"" + optType + "\" data-" + $.mobile.ns + "type=\"" + type + "\" " )
- );
- }
- });
-
-});
-
-})( jQuery );/*
-* jQuery Mobile Framework : "dialog" plugin.
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
-*/
-
-(function( $, window, undefined ) {
-
-$.widget( "mobile.dialog", $.mobile.widget, {
- options: {
- closeBtnText : "Close",
- theme : "a",
- initSelector : ":jqmData(role='dialog')"
- },
- _create: function() {
- var $el = this.element,
- pageTheme = $el.attr( "class" ).match( /ui-body-[a-z]/ );
-
- if( pageTheme.length ){
- $el.removeClass( pageTheme[ 0 ] );
- }
-
- $el.addClass( "ui-body-" + this.options.theme );
-
- // Class the markup for dialog styling
- // Set aria role
- $el.attr( "role", "dialog" )
- .addClass( "ui-dialog" )
- .find( ":jqmData(role='header')" )
- .addClass( "ui-corner-top ui-overlay-shadow" )
- .prepend( "<a href='#' data-" + $.mobile.ns + "icon='delete' data-" + $.mobile.ns + "rel='back' data-" + $.mobile.ns + "iconpos='notext'>"+ this.options.closeBtnText + "</a>" )
- .end()
- .find( ":jqmData(role='content'),:jqmData(role='footer')" )
- .last()
- .addClass( "ui-corner-bottom ui-overlay-shadow" );
-
- /* bind events
- - clicks and submits should use the closing transition that the dialog opened with
- unless a data-transition is specified on the link/form
- - if the click was on the close button, or the link has a data-rel="back" it'll go back in history naturally
- */
- $el.bind( "vclick submit", function( event ) {
- var $target = $( event.target ).closest( event.type === "vclick" ? "a" : "form" ),
- active;
-
- if ( $target.length && !$target.jqmData( "transition" ) ) {
-
- active = $.mobile.urlHistory.getActive() || {};
-
- $target.attr( "data-" + $.mobile.ns + "transition", ( active.transition || $.mobile.defaultDialogTransition ) )
- .attr( "data-" + $.mobile.ns + "direction", "reverse" );
- }
- })
- .bind( "pagehide", function() {
- $( this ).find( "." + $.mobile.activeBtnClass ).removeClass( $.mobile.activeBtnClass );
- });
- },
-
- // Close method goes back in history
- close: function() {
- window.history.back();
- }
-});
-
-//auto self-init widgets
-$( $.mobile.dialog.prototype.options.initSelector ).live( "pagecreate", function(){
- $( this ).dialog();
-});
-
-})( jQuery, this );
-/*
-* jQuery Mobile Framework : This plugin handles theming and layout of headers, footers, and content areas
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-
-(function( $, undefined ) {
-
-$.mobile.page.prototype.options.backBtnText = "Back";
-$.mobile.page.prototype.options.addBackBtn = false;
-$.mobile.page.prototype.options.backBtnTheme = null;
-$.mobile.page.prototype.options.headerTheme = "a";
-$.mobile.page.prototype.options.footerTheme = "a";
-$.mobile.page.prototype.options.contentTheme = null;
-
-$( ":jqmData(role='page'), :jqmData(role='dialog')" ).live( "pagecreate", function( e ) {
-
- var $page = $( this ),
- o = $page.data( "page" ).options,
- pageTheme = o.theme;
-
- $( ":jqmData(role='header'), :jqmData(role='footer'), :jqmData(role='content')", this ).each(function() {
- var $this = $( this ),
- role = $this.jqmData( "role" ),
- theme = $this.jqmData( "theme" ),
- $headeranchors,
- leftbtn,
- rightbtn,
- backBtn;
-
- $this.addClass( "ui-" + role );
-
- //apply theming and markup modifications to page,header,content,footer
- if ( role === "header" || role === "footer" ) {
-
- var thisTheme = theme || ( role === "header" ? o.headerTheme : o.footerTheme ) || pageTheme;
-
- //add theme class
- $this.addClass( "ui-bar-" + thisTheme );
-
- // Add ARIA role
- $this.attr( "role", role === "header" ? "banner" : "contentinfo" );
-
- // Right,left buttons
- $headeranchors = $this.children( "a" );
- leftbtn = $headeranchors.hasClass( "ui-btn-left" );
- rightbtn = $headeranchors.hasClass( "ui-btn-right" );
-
- if ( !leftbtn ) {
- leftbtn = $headeranchors.eq( 0 ).not( ".ui-btn-right" ).addClass( "ui-btn-left" ).length;
- }
-
- if ( !rightbtn ) {
- rightbtn = $headeranchors.eq( 1 ).addClass( "ui-btn-right" ).length;
- }
-
- // Auto-add back btn on pages beyond first view
- if ( o.addBackBtn && role === "header" &&
- $( ".ui-page" ).length > 1 &&
- $this.jqmData( "url" ) !== $.mobile.path.stripHash( location.hash ) &&
- !leftbtn ) {
-
- backBtn = $( "<a href='#' class='ui-btn-left' data-"+ $.mobile.ns +"rel='back' data-"+ $.mobile.ns +"icon='arrow-l'>"+ o.backBtnText +"</a>" ).prependTo( $this );
-
- // If theme is provided, override default inheritance
- backBtn.attr( "data-"+ $.mobile.ns +"theme", o.backBtnTheme || thisTheme );
- }
-
- // Page title
- $this.children( "h1, h2, h3, h4, h5, h6" )
- .addClass( "ui-title" )
- // Regardless of h element number in src, it becomes h1 for the enhanced page
- .attr({
- "tabindex": "0",
- "role": "heading",
- "aria-level": "1"
- });
-
- } else if ( role === "content" ) {
-
- $this.addClass( "ui-body-" + ( theme || pageTheme || o.contentTheme ) );
-
- // Add ARIA role
- $this.attr( "role", "main" );
-
- }
- });
-});
-
-})( jQuery );/*
-* jQuery Mobile Framework : "collapsible" plugin
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-(function( $, undefined ) {
-
-$.widget( "mobile.collapsible", $.mobile.widget, {
- options: {
- expandCueText: " click to expand contents",
- collapseCueText: " click to collapse contents",
- collapsed: false,
- heading: ">:header,>legend",
- theme: null,
- iconTheme: "d",
- initSelector: ":jqmData(role='collapsible')"
- },
- _create: function() {
-
- var $el = this.element,
- o = this.options,
- collapsibleContain = $el.addClass( "ui-collapsible-contain" ),
- collapsibleHeading = $el.find( o.heading ).eq( 0 ),
- collapsibleContent = collapsibleContain.wrapInner( "<div class='ui-collapsible-content'></div>" ).find( ".ui-collapsible-content" ),
- collapsibleParent = $el.closest( ":jqmData(role='collapsible-set')" ).addClass( "ui-collapsible-set" );
-
- // Replace collapsibleHeading if it's a legend
- if ( collapsibleHeading.is( "legend" ) ) {
- collapsibleHeading = $( "<div role='heading'>"+ collapsibleHeading.html() +"</div>" ).insertBefore( collapsibleHeading );
- collapsibleHeading.next().remove();
- }
-
- collapsibleHeading
- //drop heading in before content
- .insertBefore( collapsibleContent )
- //modify markup & attributes
- .addClass( "ui-collapsible-heading" )
- .append( "<span class='ui-collapsible-heading-status'></span>" )
- .wrapInner( "<a href='#' class='ui-collapsible-heading-toggle'></a>" )
- .find( "a:eq(0)" )
- .buttonMarkup({
- shadow: !collapsibleParent.length,
- corners: false,
- iconPos: "left",
- icon: "plus",
- theme: o.theme
- })
- .find( ".ui-icon" )
- .removeAttr( "class" )
- .buttonMarkup({
- shadow: true,
- corners: true,
- iconPos: "notext",
- icon: "plus",
- theme: o.iconTheme
- });
-
- if ( !collapsibleParent.length ) {
- collapsibleHeading
- .find( "a:eq(0)" )
- .addClass( "ui-corner-all" )
- .find( ".ui-btn-inner" )
- .addClass( "ui-corner-all" );
- } else {
- if ( collapsibleContain.jqmData( "collapsible-last" ) ) {
- collapsibleHeading
- .find( "a:eq(0), .ui-btn-inner" )
- .addClass( "ui-corner-bottom" );
- }
- }
-
- //events
- collapsibleContain
- .bind( "collapse", function( event ) {
- if ( ! event.isDefaultPrevented() &&
- $( event.target ).closest( ".ui-collapsible-contain" ).is( collapsibleContain ) ) {
-
- event.preventDefault();
-
- collapsibleHeading
- .addClass( "ui-collapsible-heading-collapsed" )
- .find( ".ui-collapsible-heading-status" )
- .text( o.expandCueText )
- .end()
- .find( ".ui-icon" )
- .removeClass( "ui-icon-minus" )
- .addClass( "ui-icon-plus" );
-
- collapsibleContent.addClass( "ui-collapsible-content-collapsed" ).attr( "aria-hidden", true );
-
- if ( collapsibleContain.jqmData( "collapsible-last" ) ) {
- collapsibleHeading
- .find( "a:eq(0), .ui-btn-inner" )
- .addClass( "ui-corner-bottom" );
- }
- }
- })
- .bind( "expand", function( event ) {
- if ( !event.isDefaultPrevented() ) {
-
- event.preventDefault();
-
- collapsibleHeading
- .removeClass( "ui-collapsible-heading-collapsed" )
- .find( ".ui-collapsible-heading-status" ).text( o.collapseCueText );
-
- collapsibleHeading.find( ".ui-icon" ).removeClass( "ui-icon-plus" ).addClass( "ui-icon-minus" );
-
- collapsibleContent.removeClass( "ui-collapsible-content-collapsed" ).attr( "aria-hidden", false );
-
- if ( collapsibleContain.jqmData( "collapsible-last" ) ) {
-
- collapsibleHeading
- .find( "a:eq(0), .ui-btn-inner" )
- .removeClass( "ui-corner-bottom" );
- }
- }
- })
- .trigger( o.collapsed ? "collapse" : "expand" );
-
- // Close others in a set
- if ( collapsibleParent.length && !collapsibleParent.jqmData( "collapsiblebound" ) ) {
-
- collapsibleParent
- .jqmData( "collapsiblebound", true )
- .bind( "expand", function( event ) {
-
- $( event.target )
- .closest( ".ui-collapsible-contain" )
- .siblings( ".ui-collapsible-contain" )
- .trigger( "collapse" );
-
- });
-
- var set = collapsibleParent.children( ":jqmData(role='collapsible')" );
-
- set.first()
- .find( "a:eq(0)" )
- .addClass( "ui-corner-top" )
- .find( ".ui-btn-inner" )
- .addClass( "ui-corner-top" );
-
- set.last().jqmData( "collapsible-last", true );
- }
-
- collapsibleHeading
- .bind( "vclick", function( event ) {
-
- var type = collapsibleHeading.is( ".ui-collapsible-heading-collapsed" ) ?
- "expand" : "collapse";
-
- collapsibleContain.trigger( type );
-
- event.preventDefault();
- });
- }
-});
-
-//auto self-init widgets
-$( document ).bind( "pagecreate create", function( e ){
- $( $.mobile.collapsible.prototype.options.initSelector, e.target ).collapsible();
-});
-
-})( jQuery );
-/*
-* jQuery Mobile Framework : "fieldcontain" plugin - simple class additions to make form row separators
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-
-(function( $, undefined ) {
-
-$.fn.fieldcontain = function( options ) {
- return this.addClass( "ui-field-contain ui-body ui-br" );
-};
-
-//auto self-init widgets
-$( document ).bind( "pagecreate create", function( e ){
- $( ":jqmData(role='fieldcontain')", e.target ).fieldcontain();
-});
-
-})( jQuery );/*
-* jQuery Mobile Framework : plugin for creating CSS grids
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-
-(function( $, undefined ) {
-
-$.fn.grid = function( options ) {
- return this.each(function() {
-
- var $this = $( this ),
- o = $.extend({
- grid: null
- },options),
- $kids = $this.children(),
- gridCols = {solo:1, a:2, b:3, c:4, d:5},
- grid = o.grid,
- iterator;
-
- if ( !grid ) {
- if ( $kids.length <= 5 ) {
- for ( var letter in gridCols ) {
- if ( gridCols[ letter ] === $kids.length ) {
- grid = letter;
- }
- }
- } else {
- grid = "a";
- }
- }
- iterator = gridCols[grid];
-
- $this.addClass( "ui-grid-" + grid );
-
- $kids.filter( ":nth-child(" + iterator + "n+1)" ).addClass( "ui-block-a" );
-
- if ( iterator > 1 ) {
- $kids.filter( ":nth-child(" + iterator + "n+2)" ).addClass( "ui-block-b" );
- }
- if ( iterator > 2 ) {
- $kids.filter( ":nth-child(3n+3)" ).addClass( "ui-block-c" );
- }
- if ( iterator > 3 ) {
- $kids.filter( ":nth-child(4n+4)" ).addClass( "ui-block-d" );
- }
- if ( iterator > 4 ) {
- $kids.filter( ":nth-child(5n+5)" ).addClass( "ui-block-e" );
- }
- });
-};
-})( jQuery );/*
-* jQuery Mobile Framework : "navbar" plugin
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-
-(function( $, undefined ) {
-
-$.widget( "mobile.navbar", $.mobile.widget, {
- options: {
- iconpos: "top",
- grid: null,
- initSelector: ":jqmData(role='navbar')"
- },
-
- _create: function(){
-
- var $navbar = this.element,
- $navbtns = $navbar.find( "a" ),
- iconpos = $navbtns.filter( ":jqmData(icon)" ).length ?
- this.options.iconpos : undefined;
-
- $navbar.addClass( "ui-navbar" )
- .attr( "role","navigation" )
- .find( "ul" )
- .grid({ grid: this.options.grid });
-
- if ( !iconpos ) {
- $navbar.addClass( "ui-navbar-noicons" );
- }
-
- $navbtns.buttonMarkup({
- corners: false,
- shadow: false,
- iconpos: iconpos
- });
-
- $navbar.delegate( "a", "vclick", function( event ) {
- $navbtns.not( ".ui-state-persist" ).removeClass( $.mobile.activeBtnClass );
- $( this ).addClass( $.mobile.activeBtnClass );
- });
- }
-});
-
-//auto self-init widgets
-$( document ).bind( "pagecreate create", function( e ){
- $( $.mobile.navbar.prototype.options.initSelector, e.target ).navbar();
-});
-
-})( jQuery );
-/*
-* jQuery Mobile Framework : "listview" plugin
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-
-(function( $, undefined ) {
-
-//Keeps track of the number of lists per page UID
-//This allows support for multiple nested list in the same page
-//https://github.com/jquery/jquery-mobile/issues/1617
-var listCountPerPage = {};
-
-$.widget( "mobile.listview", $.mobile.widget, {
- options: {
- theme: "c",
- countTheme: "c",
- headerTheme: "b",
- dividerTheme: "b",
- splitIcon: "arrow-r",
- splitTheme: "b",
- inset: false,
- initSelector: ":jqmData(role='listview')"
- },
-
- _create: function() {
- var t = this;
-
- // create listview markup
- t.element.addClass(function( i, orig ) {
- return orig + " ui-listview " + ( t.options.inset ? " ui-listview-inset ui-corner-all ui-shadow " : "" );
- });
-
- t.refresh();
- },
-
- _itemApply: function( $list, item ) {
- // TODO class has to be defined in markup
- item.find( ".ui-li-count" )
- .addClass( "ui-btn-up-" + ( $list.jqmData( "counttheme" ) || this.options.countTheme ) + " ui-btn-corner-all" ).end()
- .find( "h1, h2, h3, h4, h5, h6" ).addClass( "ui-li-heading" ).end()
- .find( "p, dl" ).addClass( "ui-li-desc" ).end()
- .find( ">img:eq(0), .ui-link-inherit>img:eq(0)" ).addClass( "ui-li-thumb" ).each(function() {
- item.addClass( $(this).is( ".ui-li-icon" ) ? "ui-li-has-icon" : "ui-li-has-thumb" );
- }).end()
- .find( ".ui-li-aside" ).each(function() {
- var $this = $(this);
- $this.prependTo( $this.parent() ); //shift aside to front for css float
- });
- },
-
- _removeCorners: function( li, which ) {
- var top = "ui-corner-top ui-corner-tr ui-corner-tl",
- bot = "ui-corner-bottom ui-corner-br ui-corner-bl";
-
- li = li.add( li.find( ".ui-btn-inner, .ui-li-link-alt, .ui-li-thumb" ) );
-
- if ( which === "top" ) {
- li.removeClass( top );
- } else if ( which === "bottom" ) {
- li.removeClass( bot );
- } else {
- li.removeClass( top + " " + bot );
- }
- },
-
- refresh: function( create ) {
- this.parentPage = this.element.closest( ".ui-page" );
- this._createSubPages();
-
- var o = this.options,
- $list = this.element,
- self = this,
- dividertheme = $list.jqmData( "dividertheme" ) || o.dividerTheme,
- listsplittheme = $list.jqmData( "splittheme" ),
- listspliticon = $list.jqmData( "spliticon" ),
- li = $list.children( "li" ),
- counter = $.support.cssPseudoElement || !$.nodeName( $list[ 0 ], "ol" ) ? 0 : 1,
- item, itemClass, itemTheme,
- a, last, splittheme, countParent, icon;
-
- if ( counter ) {
- $list.find( ".ui-li-dec" ).remove();
- }
-
- for ( var pos = 0, numli = li.length; pos < numli; pos++ ) {
- item = li.eq( pos );
- itemClass = "ui-li";
-
- // If we're creating the element, we update it regardless
- if ( create || !item.hasClass( "ui-li" ) ) {
- itemTheme = item.jqmData("theme") || o.theme;
- a = item.children( "a" );
-
- if ( a.length ) {
- icon = item.jqmData("icon");
-
- item.buttonMarkup({
- wrapperEls: "div",
- shadow: false,
- corners: false,
- iconpos: "right",
- icon: a.length > 1 || icon === false ? false : icon || "arrow-r",
- theme: itemTheme
- });
-
- a.first().addClass( "ui-link-inherit" );
-
- if ( a.length > 1 ) {
- itemClass += " ui-li-has-alt";
-
- last = a.last();
- splittheme = listsplittheme || last.jqmData( "theme" ) || o.splitTheme;
-
- last.appendTo(item)
- .attr( "title", last.text() )
- .addClass( "ui-li-link-alt" )
- .empty()
- .buttonMarkup({
- shadow: false,
- corners: false,
- theme: itemTheme,
- icon: false,
- iconpos: false
- })
- .find( ".ui-btn-inner" )
- .append(
- $( "<span />" ).buttonMarkup({
- shadow: true,
- corners: true,
- theme: splittheme,
- iconpos: "notext",
- icon: listspliticon || last.jqmData( "icon" ) || o.splitIcon
- })
- );
- }
- } else if ( item.jqmData( "role" ) === "list-divider" ) {
-
- itemClass += " ui-li-divider ui-btn ui-bar-" + dividertheme;
- item.attr( "role", "heading" );
-
- //reset counter when a divider heading is encountered
- if ( counter ) {
- counter = 1;
- }
-
- } else {
- itemClass += " ui-li-static ui-body-" + itemTheme;
- }
- }
-
- if ( o.inset ) {
- if ( pos === 0 ) {
- itemClass += " ui-corner-top";
-
- item.add( item.find( ".ui-btn-inner" ) )
- .find( ".ui-li-link-alt" )
- .addClass( "ui-corner-tr" )
- .end()
- .find( ".ui-li-thumb" )
- .addClass( "ui-corner-tl" );
-
- if ( item.next().next().length ) {
- self._removeCorners( item.next() );
- }
- }
-
- if ( pos === li.length - 1 ) {
- itemClass += " ui-corner-bottom";
-
- item.add( item.find( ".ui-btn-inner" ) )
- .find( ".ui-li-link-alt" )
- .addClass( "ui-corner-br" )
- .end()
- .find( ".ui-li-thumb" )
- .addClass( "ui-corner-bl" );
-
- if ( item.prev().prev().length ) {
- self._removeCorners( item.prev() );
- } else if ( item.prev().length ) {
- self._removeCorners( item.prev(), "bottom" );
- }
- }
- }
-
- if ( counter && itemClass.indexOf( "ui-li-divider" ) < 0 ) {
- countParent = item.is( ".ui-li-static:first" ) ? item : item.find( ".ui-link-inherit" );
-
- countParent.addClass( "ui-li-jsnumbering" )
- .prepend( "<span class='ui-li-dec'>" + (counter++) + ". </span>" );
- }
-
- item.add( item.children( ".ui-btn-inner" ) ).addClass( itemClass );
-
- if ( !create ) {
- self._itemApply( $list, item );
- }
- }
- },
-
- //create a string for ID/subpage url creation
- _idStringEscape: function( str ) {
- return str.replace(/[^a-zA-Z0-9]/g, '-');
- },
-
- _createSubPages: function() {
- var parentList = this.element,
- parentPage = parentList.closest( ".ui-page" ),
- parentUrl = parentPage.jqmData( "url" ),
- parentId = parentUrl || parentPage[ 0 ][ $.expando ],
- parentListId = parentList.attr( "id" ),
- o = this.options,
- dns = "data-" + $.mobile.ns,
- self = this,
- persistentFooterID = parentPage.find( ":jqmData(role='footer')" ).jqmData( "id" ),
- hasSubPages;
-
- if ( typeof listCountPerPage[ parentId ] === "undefined" ) {
- listCountPerPage[ parentId ] = -1;
- }
-
- parentListId = parentListId || ++listCountPerPage[ parentId ];
-
- $( parentList.find( "li>ul, li>ol" ).toArray().reverse() ).each(function( i ) {
- var self = this,
- list = $( this ),
- listId = list.attr( "id" ) || parentListId + "-" + i,
- parent = list.parent(),
- nodeEls = $( list.prevAll().toArray().reverse() ),
- nodeEls = nodeEls.length ? nodeEls : $( "<span>" + $.trim(parent.contents()[ 0 ].nodeValue) + "</span>" ),
- title = nodeEls.first().text(),//url limits to first 30 chars of text
- id = ( parentUrl || "" ) + "&" + $.mobile.subPageUrlKey + "=" + listId,
- theme = list.jqmData( "theme" ) || o.theme,
- countTheme = list.jqmData( "counttheme" ) || parentList.jqmData( "counttheme" ) || o.countTheme,
- newPage, anchor;
-
- //define hasSubPages for use in later removal
- hasSubPages = true;
-
- newPage = list.detach()
- .wrap( "<div " + dns + "role='page' " + dns + "url='" + id + "' " + dns + "theme='" + theme + "' " + dns + "count-theme='" + countTheme + "'><div " + dns + "role='content'></div></div>" )
- .parent()
- .before( "<div " + dns + "role='header' " + dns + "theme='" + o.headerTheme + "'><div class='ui-title'>" + title + "</div></div>" )
- .after( persistentFooterID ? $( "<div " + dns + "role='footer' " + dns + "id='"+ persistentFooterID +"'>") : "" )
- .parent()
- .appendTo( $.mobile.pageContainer );
-
- newPage.page();
-
- anchor = parent.find('a:first');
-
- if ( !anchor.length ) {
- anchor = $( "<a/>" ).html( nodeEls || title ).prependTo( parent.empty() );
- }
-
- anchor.attr( "href", "#" + id );
-
- }).listview();
-
- //on pagehide, remove any nested pages along with the parent page, as long as they aren't active
- if( hasSubPages && parentPage.data("page").options.domCache === false ){
- var newRemove = function( e, ui ){
- var nextPage = ui.nextPage, npURL;
-
- if( ui.nextPage ){
- npURL = nextPage.jqmData( "url" );
- if( npURL.indexOf( parentUrl + "&" + $.mobile.subPageUrlKey ) !== 0 ){
- self.childPages().remove();
- parentPage.remove();
- }
- }
- };
-
- // unbind the original page remove and replace with our specialized version
- parentPage
- .unbind( "pagehide.remove" )
- .bind( "pagehide.remove", newRemove);
- }
- },
-
- // TODO sort out a better way to track sub pages of the listview this is brittle
- childPages: function(){
- var parentUrl = this.parentPage.jqmData( "url" );
-
- return $( ":jqmData(url^='"+ parentUrl + "&" + $.mobile.subPageUrlKey +"')");
- }
-});
-
-//auto self-init widgets
-$( document ).bind( "pagecreate create", function( e ){
- $( $.mobile.listview.prototype.options.initSelector, e.target ).listview();
-});
-
-})( jQuery );
-/*
-* jQuery Mobile Framework : "listview" filter extension
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-
-(function( $, undefined ) {
-
-$.mobile.listview.prototype.options.filter = false;
-$.mobile.listview.prototype.options.filterPlaceholder = "Filter items...";
-$.mobile.listview.prototype.options.filterTheme = "c";
-
-$( ":jqmData(role='listview')" ).live( "listviewcreate", function() {
-
- var list = $( this ),
- listview = list.data( "listview" );
-
- if ( !listview.options.filter ) {
- return;
- }
-
- var wrapper = $( "<form>", {
- "class": "ui-listview-filter ui-bar-" + listview.options.filterTheme,
- "role": "search"
- }),
- search = $( "<input>", {
- placeholder: listview.options.filterPlaceholder
- })
- .attr( "data-" + $.mobile.ns + "type", "search" )
- .jqmData( "lastval", "" )
- .bind( "keyup change", function() {
-
- var $this = $(this),
- val = this.value.toLowerCase(),
- listItems = null,
- lastval = $this.jqmData( "lastval" ) + "",
- childItems = false,
- itemtext = "",
- item;
-
- // Change val as lastval for next execution
- $this.jqmData( "lastval" , val );
-
- change = val.replace( new RegExp( "^" + lastval ) , "" );
-
- if ( val.length < lastval.length || change.length != ( val.length - lastval.length ) ) {
-
- // Removed chars or pasted something totaly different, check all items
- listItems = list.children();
- } else {
-
- // Only chars added, not removed, only use visible subset
- listItems = list.children( ":not(.ui-screen-hidden)" );
- }
-
- if ( val ) {
-
- // This handles hiding regular rows without the text we search for
- // and any list dividers without regular rows shown under it
-
- for ( var i = listItems.length - 1; i >= 0; i-- ) {
- item = $( listItems[ i ] );
- itemtext = item.jqmData( "filtertext" ) || item.text();
-
- if ( item.is( "li:jqmData(role=list-divider)" ) ) {
-
- item.toggleClass( "ui-filter-hidequeue" , !childItems );
-
- // New bucket!
- childItems = false;
-
- } else if ( itemtext.toLowerCase().indexOf( val ) === -1 ) {
-
- //mark to be hidden
- item.toggleClass( "ui-filter-hidequeue" , true );
- } else {
-
- // There"s a shown item in the bucket
- childItems = true;
- }
- }
-
- // Show items, not marked to be hidden
- listItems
- .filter( ":not(.ui-filter-hidequeue)" )
- .toggleClass( "ui-screen-hidden", false );
-
- // Hide items, marked to be hidden
- listItems
- .filter( ".ui-filter-hidequeue" )
- .toggleClass( "ui-screen-hidden", true )
- .toggleClass( "ui-filter-hidequeue", false );
-
- } else {
-
- //filtervalue is empty => show all
- listItems.toggleClass( "ui-screen-hidden", false );
- }
- })
- .appendTo( wrapper )
- .textinput();
-
- if ( $( this ).jqmData( "inset" ) ) {
- wrapper.addClass( "ui-listview-filter-inset" );
- }
-
- wrapper.bind( "submit", function() {
- return false;
- })
- .insertBefore( list );
-});
-
-})( jQuery );/*
-* jQuery Mobile Framework : "fieldcontain" plugin - simple class additions to make form row separators
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-
-(function( $, undefined ) {
-
-$( document ).bind( "pagecreate create", function( e ){
- $( ":jqmData(role='nojs')", e.target ).addClass( "ui-nojs" );
-
-});
-
-})( jQuery );/*
-* jQuery Mobile Framework : "checkboxradio" plugin
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-
-(function( $, undefined ) {
-
-$.widget( "mobile.checkboxradio", $.mobile.widget, {
- options: {
- theme: null,
- initSelector: "input[type='checkbox'],input[type='radio']"
- },
- _create: function() {
- var self = this,
- input = this.element,
- // NOTE: Windows Phone could not find the label through a selector
- // filter works though.
- label = input.closest( "form,fieldset,:jqmData(role='page')" ).find( "label" ).filter( "[for='" + input[ 0 ].id + "']"),
- inputtype = input.attr( "type" ),
- checkedState = inputtype + "-on",
- uncheckedState = inputtype + "-off",
- icon = input.parents( ":jqmData(type='horizontal')" ).length ? undefined : uncheckedState,
- activeBtn = icon ? "" : " " + $.mobile.activeBtnClass,
- checkedClass = "ui-" + checkedState + activeBtn,
- uncheckedClass = "ui-" + uncheckedState,
- checkedicon = "ui-icon-" + checkedState,
- uncheckedicon = "ui-icon-" + uncheckedState;
-
- if ( inputtype !== "checkbox" && inputtype !== "radio" ) {
- return;
- }
-
- // Expose for other methods
- $.extend( this, {
- label: label,
- inputtype: inputtype,
- checkedClass: checkedClass,
- uncheckedClass: uncheckedClass,
- checkedicon: checkedicon,
- uncheckedicon: uncheckedicon
- });
-
- // If there's no selected theme...
- if( !this.options.theme ) {
- this.options.theme = this.element.jqmData( "theme" );
- }
-
- label.buttonMarkup({
- theme: this.options.theme,
- icon: icon,
- shadow: false
- });
-
- // Wrap the input + label in a div
- input.add( label )
- .wrapAll( "<div class='ui-" + inputtype + "'></div>" );
-
- label.bind({
- vmouseover: function() {
- if ( $( this ).parent().is( ".ui-disabled" ) ) {
- return false;
- }
- },
-
- vclick: function( event ) {
- if ( input.is( ":disabled" ) ) {
- event.preventDefault();
- return;
- }
-
- self._cacheVals();
-
- input.prop( "checked", inputtype === "radio" && true || !input.prop( "checked" ) );
-
- // Input set for common radio buttons will contain all the radio
- // buttons, but will not for checkboxes. clearing the checked status
- // of other radios ensures the active button state is applied properly
- self._getInputSet().not( input ).prop( "checked", false );
-
- self._updateAll();
- return false;
- }
-
- });
-
- input
- .bind({
- vmousedown: function() {
- this._cacheVals();
- },
-
- vclick: function() {
-
- var $this = $(this);
-
- // Adds checked attribute to checked input when keyboard is used
- if ( $this.is( ":checked" ) ) {
-
- $this.prop( "checked", true);
- self._getInputSet().not($this).prop( "checked", false );
- } else {
-
- $this.prop( "checked", false );
- }
-
- self._updateAll();
- },
-
- focus: function() {
- label.addClass( "ui-focus" );
- },
-
- blur: function() {
- label.removeClass( "ui-focus" );
- }
- });
-
- this.refresh();
- },
-
- _cacheVals: function() {
- this._getInputSet().each(function() {
- var $this = $(this);
-
- $this.jqmData( "cacheVal", $this.is( ":checked" ) );
- });
- },
-
- //returns either a set of radios with the same name attribute, or a single checkbox
- _getInputSet: function(){
- if(this.inputtype == "checkbox") {
- return this.element;
- }
- return this.element.closest( "form,fieldset,:jqmData(role='page')" )
- .find( "input[name='"+ this.element.attr( "name" ) +"'][type='"+ this.inputtype +"']" );
- },
-
- _updateAll: function() {
- var self = this;
-
- this._getInputSet().each(function() {
- var $this = $(this);
-
- if ( $this.is( ":checked" ) || self.inputtype === "checkbox" ) {
- $this.trigger( "change" );
- }
- })
- .checkboxradio( "refresh" );
- },
-
- refresh: function() {
- var input = this.element,
- label = this.label,
- icon = label.find( ".ui-icon" );
-
- // input[0].checked expando doesn't always report the proper value
- // for checked='checked'
- if ( $( input[ 0 ] ).prop( "checked" ) ) {
-
- label.addClass( this.checkedClass ).removeClass( this.uncheckedClass );
- icon.addClass( this.checkedicon ).removeClass( this.uncheckedicon );
-
- } else {
-
- label.removeClass( this.checkedClass ).addClass( this.uncheckedClass );
- icon.removeClass( this.checkedicon ).addClass( this.uncheckedicon );
- }
-
- if ( input.is( ":disabled" ) ) {
- this.disable();
- } else {
- this.enable();
- }
- },
-
- disable: function() {
- this.element.prop( "disabled", true ).parent().addClass( "ui-disabled" );
- },
-
- enable: function() {
- this.element.prop( "disabled", false ).parent().removeClass( "ui-disabled" );
- }
-});
-
-//auto self-init widgets
-$( document ).bind( "pagecreate create", function( e ){
- $( $.mobile.checkboxradio.prototype.options.initSelector, e.target )
- .not( ":jqmData(role='none'), :jqmData(role='nojs')" )
- .checkboxradio();
-});
-
-})( jQuery );
-/*
-* jQuery Mobile Framework : "button" plugin - links that proxy to native input/buttons
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-
-(function( $, undefined ) {
-
-$.widget( "mobile.button", $.mobile.widget, {
- options: {
- theme: null,
- icon: null,
- iconpos: null,
- inline: null,
- corners: true,
- shadow: true,
- iconshadow: true,
- initSelector: "button, [type='button'], [type='submit'], [type='reset'], [type='image']"
- },
- _create: function() {
- var $el = this.element,
- o = this.options,
- type;
-
- // Add ARIA role
- this.button = $( "<div></div>" )
- .text( $el.text() || $el.val() )
- .buttonMarkup({
- theme: o.theme,
- icon: o.icon,
- iconpos: o.iconpos,
- inline: o.inline,
- corners: o.corners,
- shadow: o.shadow,
- iconshadow: o.iconshadow
- })
- .insertBefore( $el )
- .append( $el.addClass( "ui-btn-hidden" ) );
-
- // Add hidden input during submit
- type = $el.attr( "type" );
-
- if ( type !== "button" && type !== "reset" ) {
-
- $el.bind( "vclick", function() {
-
- var $buttonPlaceholder = $( "<input>", {
- type: "hidden",
- name: $el.attr( "name" ),
- value: $el.attr( "value" )
- })
- .insertBefore( $el );
-
- // Bind to doc to remove after submit handling
- $( document ).submit(function(){
- $buttonPlaceholder.remove();
- });
- });
- }
-
- this.refresh();
- },
-
- enable: function() {
- this.element.attr( "disabled", false );
- this.button.removeClass( "ui-disabled" ).attr( "aria-disabled", false );
- return this._setOption( "disabled", false );
- },
-
- disable: function() {
- this.element.attr( "disabled", true );
- this.button.addClass( "ui-disabled" ).attr( "aria-disabled", true );
- return this._setOption( "disabled", true );
- },
-
- refresh: function() {
- if ( this.element.attr( "disabled" ) ) {
- this.disable();
- } else {
- this.enable();
- }
- }
-});
-
-//auto self-init widgets
-$( document ).bind( "pagecreate create", function( e ){
- $( $.mobile.button.prototype.options.initSelector, e.target )
- .not( ":jqmData(role='none'), :jqmData(role='nojs')" )
- .button();
-});
-
-})( jQuery );/*
-* jQuery Mobile Framework : "slider" plugin
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-
-( function( $, undefined ) {
-
-$.widget( "mobile.slider", $.mobile.widget, {
- options: {
- theme: null,
- trackTheme: null,
- disabled: false,
- initSelector: "input[type='range'], :jqmData(type='range'), :jqmData(role='slider')"
- },
-
- _create: function() {
-
- // TODO: Each of these should have comments explain what they're for
- var self = this,
-
- control = this.element,
-
- parentTheme = control.parents( "[class*='ui-bar-'],[class*='ui-body-']" ).eq( 0 ),
-
- parentTheme = parentTheme.length ? parentTheme.attr( "class" ).match( /ui-(bar|body)-([a-z])/ )[ 2 ] : "c",
-
- theme = this.options.theme ? this.options.theme : parentTheme,
-
- trackTheme = this.options.trackTheme ? this.options.trackTheme : parentTheme,
-
- cType = control[ 0 ].nodeName.toLowerCase(),
-
- selectClass = ( cType == "select" ) ? "ui-slider-switch" : "",
-
- controlID = control.attr( "id" ),
-
- labelID = controlID + "-label",
-
- label = $( "[for='"+ controlID +"']" ).attr( "id", labelID ),
-
- val = function() {
- return cType == "input" ? parseFloat( control.val() ) : control[0].selectedIndex;
- },
-
- min = cType == "input" ? parseFloat( control.attr( "min" ) ) : 0,
-
- max = cType == "input" ? parseFloat( control.attr( "max" ) ) : control.find( "option" ).length-1,
-
- step = window.parseFloat( control.attr( "step" ) || 1 ),
-
- slider = $( "<div class='ui-slider " + selectClass + " ui-btn-down-" + trackTheme +
- " ui-btn-corner-all' role='application'></div>" ),
-
- handle = $( "<a href='#' class='ui-slider-handle'></a>" )
- .appendTo( slider )
- .buttonMarkup({ corners: true, theme: theme, shadow: true })
- .attr({
- "role": "slider",
- "aria-valuemin": min,
- "aria-valuemax": max,
- "aria-valuenow": val(),
- "aria-valuetext": val(),
- "title": val(),
- "aria-labelledby": labelID
- }),
- options;
-
- $.extend( this, {
- slider: slider,
- handle: handle,
- dragging: false,
- beforeStart: null
- });
-
- if ( cType == "select" ) {
-
- slider.wrapInner( "<div class='ui-slider-inneroffset'></div>" );
-
- options = control.find( "option" );
-
- control.find( "option" ).each(function( i ) {
-
- var side = !i ? "b":"a",
- corners = !i ? "right" :"left",
- theme = !i ? " ui-btn-down-" + trackTheme :" ui-btn-active";
-
- $( "<div class='ui-slider-labelbg ui-slider-labelbg-" + side + theme + " ui-btn-corner-" + corners + "'></div>" )
- .prependTo( slider );
-
- $( "<span class='ui-slider-label ui-slider-label-" + side + theme + " ui-btn-corner-" + corners + "' role='img'>" + $( this ).text() + "</span>" )
- .prependTo( handle );
- });
-
- }
-
- label.addClass( "ui-slider" );
-
- // monitor the input for updated values
- control.addClass( cType === "input" ? "ui-slider-input" : "ui-slider-switch" )
- .change( function() {
- self.refresh( val(), true );
- })
- .keyup( function() { // necessary?
- self.refresh( val(), true, true );
- })
- .blur( function() {
- self.refresh( val(), true );
- });
-
- // prevent screen drag when slider activated
- $( document ).bind( "vmousemove", function( event ) {
- if ( self.dragging ) {
- self.refresh( event );
- return false;
- }
- });
-
- slider.bind( "vmousedown", function( event ) {
- self.dragging = true;
-
- if ( cType === "select" ) {
- self.beforeStart = control[0].selectedIndex;
- }
- self.refresh( event );
- return false;
- });
-
- slider.add( document )
- .bind( "vmouseup", function() {
- if ( self.dragging ) {
-
- self.dragging = false;
-
- if ( cType === "select" ) {
-
- if ( self.beforeStart === control[ 0 ].selectedIndex ) {
- //tap occurred, but value didn't change. flip it!
- self.refresh( !self.beforeStart ? 1 : 0 );
- }
- var curval = val();
- var snapped = Math.round( curval / ( max - min ) * 100 );
- handle
- .addClass( "ui-slider-handle-snapping" )
- .css( "left", snapped + "%" )
- .animationComplete( function() {
- handle.removeClass( "ui-slider-handle-snapping" );
- });
- }
- return false;
- }
- });
-
- slider.insertAfter( control );
-
- // NOTE force focus on handle
- this.handle
- .bind( "vmousedown", function() {
- $( this ).focus();
- })
- .bind( "vclick", false );
-
- this.handle
- .bind( "keydown", function( event ) {
- var index = val();
-
- if ( self.options.disabled ) {
- return;
- }
-
- // In all cases prevent the default and mark the handle as active
- switch ( event.keyCode ) {
- case $.mobile.keyCode.HOME:
- case $.mobile.keyCode.END:
- case $.mobile.keyCode.PAGE_UP:
- case $.mobile.keyCode.PAGE_DOWN:
- case $.mobile.keyCode.UP:
- case $.mobile.keyCode.RIGHT:
- case $.mobile.keyCode.DOWN:
- case $.mobile.keyCode.LEFT:
- event.preventDefault();
-
- if ( !self._keySliding ) {
- self._keySliding = true;
- $( this ).addClass( "ui-state-active" );
- }
- break;
- }
-
- // move the slider according to the keypress
- switch ( event.keyCode ) {
- case $.mobile.keyCode.HOME:
- self.refresh( min );
- break;
- case $.mobile.keyCode.END:
- self.refresh( max );
- break;
- case $.mobile.keyCode.PAGE_UP:
- case $.mobile.keyCode.UP:
- case $.mobile.keyCode.RIGHT:
- self.refresh( index + step );
- break;
- case $.mobile.keyCode.PAGE_DOWN:
- case $.mobile.keyCode.DOWN:
- case $.mobile.keyCode.LEFT:
- self.refresh( index - step );
- break;
- }
- }) // remove active mark
- .keyup( function( event ) {
- if ( self._keySliding ) {
- self._keySliding = false;
- $( this ).removeClass( "ui-state-active" );
- }
- });
-
- this.refresh(undefined, undefined, true);
- },
-
- refresh: function( val, isfromControl, preventInputUpdate ) {
- if ( this.options.disabled ) { return; }
-
- var control = this.element, percent,
- cType = control[0].nodeName.toLowerCase(),
- min = cType === "input" ? parseFloat( control.attr( "min" ) ) : 0,
- max = cType === "input" ? parseFloat( control.attr( "max" ) ) : control.find( "option" ).length - 1;
-
- if ( typeof val === "object" ) {
- var data = val,
- // a slight tolerance helped get to the ends of the slider
- tol = 8;
- if ( !this.dragging ||
- data.pageX < this.slider.offset().left - tol ||
- data.pageX > this.slider.offset().left + this.slider.width() + tol ) {
- return;
- }
- percent = Math.round( ( ( data.pageX - this.slider.offset().left ) / this.slider.width() ) * 100 );
- } else {
- if ( val == null ) {
- val = cType === "input" ? parseFloat( control.val() ) : control[0].selectedIndex;
- }
- percent = ( parseFloat( val ) - min ) / ( max - min ) * 100;
- }
-
- if ( isNaN( percent ) ) {
- return;
- }
-
- if ( percent < 0 ) {
- percent = 0;
- }
-
- if ( percent > 100 ) {
- percent = 100;
- }
-
- var newval = Math.round( ( percent / 100 ) * ( max - min ) ) + min;
-
- if ( newval < min ) {
- newval = min;
- }
-
- if ( newval > max ) {
- newval = max;
- }
-
- // Flip the stack of the bg colors
- if ( percent > 60 && cType === "select" ) {
- // TODO: Dead path?
- }
- this.handle.css( "left", percent + "%" );
- this.handle.attr( {
- "aria-valuenow": cType === "input" ? newval : control.find( "option" ).eq( newval ).attr( "value" ),
- "aria-valuetext": cType === "input" ? newval : control.find( "option" ).eq( newval ).text(),
- title: newval
- });
-
- // add/remove classes for flip toggle switch
- if ( cType === "select" ) {
- if ( newval === 0 ) {
- this.slider.addClass( "ui-slider-switch-a" )
- .removeClass( "ui-slider-switch-b" );
- } else {
- this.slider.addClass( "ui-slider-switch-b" )
- .removeClass( "ui-slider-switch-a" );
- }
- }
-
- if ( !preventInputUpdate ) {
- // update control"s value
- if ( cType === "input" ) {
- control.val( newval );
- } else {
- control[ 0 ].selectedIndex = newval;
- }
- if ( !isfromControl ) {
- control.trigger( "change" );
- }
- }
- },
-
- enable: function() {
- this.element.attr( "disabled", false );
- this.slider.removeClass( "ui-disabled" ).attr( "aria-disabled", false );
- return this._setOption( "disabled", false );
- },
-
- disable: function() {
- this.element.attr( "disabled", true );
- this.slider.addClass( "ui-disabled" ).attr( "aria-disabled", true );
- return this._setOption( "disabled", true );
- }
-
-});
-
-//auto self-init widgets
-$( document ).bind( "pagecreate create", function( e ){
-
- $( $.mobile.slider.prototype.options.initSelector, e.target )
- .not( ":jqmData(role='none'), :jqmData(role='nojs')" )
- .slider();
-
-});
-
-})( jQuery );/*
-* jQuery Mobile Framework : "textinput" plugin for text inputs, textareas
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-
-(function( $, undefined ) {
-
-$.widget( "mobile.textinput", $.mobile.widget, {
- options: {
- theme: null,
- initSelector: "input[type='text'], input[type='search'], :jqmData(type='search'), input[type='number'], :jqmData(type='number'), input[type='password'], input[type='email'], input[type='url'], input[type='tel'], textarea"
- },
-
- _create: function() {
-
- var input = this.element,
- o = this.options,
- theme = o.theme,
- themedParent, themeclass, themeLetter, focusedEl, clearbtn;
-
- if ( !theme ) {
- themedParent = this.element.closest( "[class*='ui-bar-'],[class*='ui-body-']" );
- themeLetter = themedParent.length && /ui-(bar|body)-([a-z])/.exec( themedParent.attr( "class" ) );
- theme = themeLetter && themeLetter[2] || "c";
- }
-
- themeclass = " ui-body-" + theme;
-
- $( "label[for='" + input.attr( "id" ) + "']" ).addClass( "ui-input-text" );
-
- input.addClass("ui-input-text ui-body-"+ o.theme );
-
- focusedEl = input;
-
- // XXX: Temporary workaround for issue 785. Turn off autocorrect and
- // autocomplete since the popup they use can't be dismissed by
- // the user. Note that we test for the presence of the feature
- // by looking for the autocorrect property on the input element.
- if ( typeof input[0].autocorrect !== "undefined" ) {
- // Set the attribute instead of the property just in case there
- // is code that attempts to make modifications via HTML.
- input[0].setAttribute( "autocorrect", "off" );
- input[0].setAttribute( "autocomplete", "off" );
- }
-
-
- //"search" input widget
- if ( input.is( "[type='search'],:jqmData(type='search')" ) ) {
-
- focusedEl = input.wrap( "<div class='ui-input-search ui-shadow-inset ui-btn-corner-all ui-btn-shadow ui-icon-searchfield" + themeclass + "'></div>" ).parent();
- clearbtn = $( "<a href='#' class='ui-input-clear' title='clear text'>clear text</a>" )
- .tap(function( event ) {
- input.val( "" ).focus();
- input.trigger( "change" );
- clearbtn.addClass( "ui-input-clear-hidden" );
- event.preventDefault();
- })
- .appendTo( focusedEl )
- .buttonMarkup({
- icon: "delete",
- iconpos: "notext",
- corners: true,
- shadow: true
- });
-
- function toggleClear() {
- if ( !input.val() ) {
- clearbtn.addClass( "ui-input-clear-hidden" );
- } else {
- clearbtn.removeClass( "ui-input-clear-hidden" );
- }
- }
-
- toggleClear();
-
- input.keyup( toggleClear )
- .focus( toggleClear );
-
- } else {
- input.addClass( "ui-corner-all ui-shadow-inset" + themeclass );
- }
-
- input.focus(function() {
- focusedEl.addClass( "ui-focus" );
- })
- .blur(function(){
- focusedEl.removeClass( "ui-focus" );
- });
-
- // Autogrow
- if ( input.is( "textarea" ) ) {
- var extraLineHeight = 15,
- keyupTimeoutBuffer = 100,
- keyup = function() {
- var scrollHeight = input[ 0 ].scrollHeight,
- clientHeight = input[ 0 ].clientHeight;
-
- if ( clientHeight < scrollHeight ) {
- input.css({
- height: (scrollHeight + extraLineHeight)
- });
- }
- },
- keyupTimeout;
-
- input.keyup(function() {
- clearTimeout( keyupTimeout );
- keyupTimeout = setTimeout( keyup, keyupTimeoutBuffer );
- });
- }
- },
-
- disable: function(){
- ( this.element.attr( "disabled", true ).is( "[type='search'],:jqmData(type='search')" ) ?
- this.element.parent() : this.element ).addClass( "ui-disabled" );
- },
-
- enable: function(){
- ( this.element.attr( "disabled", false).is( "[type='search'],:jqmData(type='search')" ) ?
- this.element.parent() : this.element ).removeClass( "ui-disabled" );
- }
-});
-
-//auto self-init widgets
-$( document ).bind( "pagecreate create", function( e ){
-
- $( $.mobile.textinput.prototype.options.initSelector, e.target )
- .not( ":jqmData(role='none'), :jqmData(role='nojs')" )
- .textinput();
-
-});
-
-})( jQuery );
-/*
-* jQuery Mobile Framework : "selectmenu" plugin
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-
-(function( $, undefined ) {
-
-$.widget( "mobile.selectmenu", $.mobile.widget, {
- options: {
- theme: null,
- disabled: false,
- icon: "arrow-d",
- iconpos: "right",
- inline: null,
- corners: true,
- shadow: true,
- iconshadow: true,
- menuPageTheme: "b",
- overlayTheme: "a",
- hidePlaceholderMenuItems: true,
- closeText: "Close",
- nativeMenu: true,
- initSelector: "select:not(:jqmData(role='slider'))"
- },
- _create: function() {
-
- var self = this,
-
- o = this.options,
-
- select = this.element
- .wrap( "<div class='ui-select'>" ),
-
- selectID = select.attr( "id" ),
-
- label = $( "label[for='"+ selectID +"']" ).addClass( "ui-select" ),
-
- // IE throws an exception at options.item() function when
- // there is no selected item
- // select first in this case
- selectedIndex = select[ 0 ].selectedIndex == -1 ? 0 : select[ 0 ].selectedIndex,
-
- button = ( self.options.nativeMenu ? $( "<div/>" ) : $( "<a>", {
- "href": "#",
- "role": "button",
- "id": buttonId,
- "aria-haspopup": "true",
- "aria-owns": menuId
- }) )
- .text( $( select[ 0 ].options.item( selectedIndex ) ).text() )
- .insertBefore( select )
- .buttonMarkup({
- theme: o.theme,
- icon: o.icon,
- iconpos: o.iconpos,
- inline: o.inline,
- corners: o.corners,
- shadow: o.shadow,
- iconshadow: o.iconshadow
- }),
-
- // Multi select or not
- isMultiple = self.isMultiple = select[ 0 ].multiple;
-
- // Opera does not properly support opacity on select elements
- // In Mini, it hides the element, but not its text
- // On the desktop,it seems to do the opposite
- // for these reasons, using the nativeMenu option results in a full native select in Opera
- if ( o.nativeMenu && window.opera && window.opera.version ) {
- select.addClass( "ui-select-nativeonly" );
- }
-
- //vars for non-native menus
- if ( !o.nativeMenu ) {
- var options = select.find("option"),
-
- buttonId = selectID + "-button",
-
- menuId = selectID + "-menu",
-
- thisPage = select.closest( ".ui-page" ),
-
- //button theme
- theme = /ui-btn-up-([a-z])/.exec( button.attr( "class" ) )[1],
-
- menuPage = $( "<div data-" + $.mobile.ns + "role='dialog' data-" +$.mobile.ns + "theme='"+ o.menuPageTheme +"'>" +
- "<div data-" + $.mobile.ns + "role='header'>" +
- "<div class='ui-title'>" + label.text() + "</div>"+
- "</div>"+
- "<div data-" + $.mobile.ns + "role='content'></div>"+
- "</div>" )
- .appendTo( $.mobile.pageContainer )
- .page(),
-
- menuPageContent = menuPage.find( ".ui-content" ),
-
- menuPageClose = menuPage.find( ".ui-header a" ),
-
- screen = $( "<div>", {"class": "ui-selectmenu-screen ui-screen-hidden"})
- .appendTo( thisPage ),
-
- listbox = $("<div>", { "class": "ui-selectmenu ui-selectmenu-hidden ui-overlay-shadow ui-corner-all ui-body-" + o.overlayTheme + " " + $.mobile.defaultDialogTransition })
- .insertAfter(screen),
-
- list = $( "<ul>", {
- "class": "ui-selectmenu-list",
- "id": menuId,
- "role": "listbox",
- "aria-labelledby": buttonId
- })
- .attr( "data-" + $.mobile.ns + "theme", theme )
- .appendTo( listbox ),
-
- header = $( "<div>", {
- "class": "ui-header ui-bar-" + theme
- })
- .prependTo( listbox ),
-
- headerTitle = $( "<h1>", {
- "class": "ui-title"
- })
- .appendTo( header ),
-
- headerClose = $( "<a>", {
- "text": o.closeText,
- "href": "#",
- "class": "ui-btn-left"
- })
- .attr( "data-" + $.mobile.ns + "iconpos", "notext" )
- .attr( "data-" + $.mobile.ns + "icon", "delete" )
- .appendTo( header )
- .buttonMarkup(),
-
- menuType;
- } // End non native vars
-
- // Add counter for multi selects
- if ( isMultiple ) {
- self.buttonCount = $( "<span>" )
- .addClass( "ui-li-count ui-btn-up-c ui-btn-corner-all" )
- .hide()
- .appendTo( button );
- }
-
- // Disable if specified
- if ( o.disabled ) {
- this.disable();
- }
-
- // Events on native select
- select.change(function() {
- self.refresh();
- });
-
- // Expose to other methods
- $.extend( self, {
- select: select,
- optionElems: options,
- selectID: selectID,
- label: label,
- buttonId: buttonId,
- menuId: menuId,
- thisPage: thisPage,
- button: button,
- menuPage: menuPage,
- menuPageContent: menuPageContent,
- screen: screen,
- listbox: listbox,
- list: list,
- menuType: menuType,
- header: header,
- headerClose: headerClose,
- headerTitle: headerTitle,
- placeholder: ""
- });
-
- // Support for using the native select menu with a custom button
- if ( o.nativeMenu ) {
-
- select.appendTo( button )
- .bind( "vmousedown", function() {
- // Add active class to button
- button.addClass( $.mobile.activeBtnClass );
- })
- .bind( "focus vmouseover", function() {
- button.trigger( "vmouseover" );
- })
- .bind( "vmousemove", function() {
- // Remove active class on scroll/touchmove
- button.removeClass( $.mobile.activeBtnClass );
- })
- .bind( "change blur vmouseout", function() {
-
- button.trigger( "vmouseout" )
- .removeClass( $.mobile.activeBtnClass );
- });
-
-
- } else {
-
- // Create list from select, update state
- self.refresh();
-
- select.attr( "tabindex", "-1" )
- .focus(function() {
- $(this).blur();
- button.focus();
- });
-
- // Button events
- button.bind( "vclick keydown" , function( event ) {
- if ( event.type == "vclick" ||
- event.keyCode && ( event.keyCode === $.mobile.keyCode.ENTER ||
- event.keyCode === $.mobile.keyCode.SPACE ) ) {
-
- self.open();
- event.preventDefault();
- }
- });
-
- // Events for list items
- list.attr( "role", "listbox" )
- .delegate( ".ui-li>a", "focusin", function() {
- $( this ).attr( "tabindex", "0" );
- })
- .delegate( ".ui-li>a", "focusout", function() {
- $( this ).attr( "tabindex", "-1" );
- })
- .delegate( "li:not(.ui-disabled, .ui-li-divider)", "vclick", function( event ) {
-
- var $this = $( this ),
- // index of option tag to be selected
- oldIndex = select[ 0 ].selectedIndex,
- newIndex = $this.jqmData( "option-index" ),
- option = self.optionElems[ newIndex ];
-
- // toggle selected status on the tag for multi selects
- option.selected = isMultiple ? !option.selected : true;
-
- // toggle checkbox class for multiple selects
- if ( isMultiple ) {
- $this.find( ".ui-icon" )
- .toggleClass( "ui-icon-checkbox-on", option.selected )
- .toggleClass( "ui-icon-checkbox-off", !option.selected );
- }
-
- // trigger change if value changed
- if ( isMultiple || oldIndex !== newIndex ) {
- select.trigger( "change" );
- }
-
- //hide custom select for single selects only
- if ( !isMultiple ) {
- self.close();
- }
-
- event.preventDefault();
- })
- //keyboard events for menu items
- .keydown(function( event ) {
- var target = $( event.target ),
- li = target.closest( "li" ),
- prev, next;
-
- // switch logic based on which key was pressed
- switch ( event.keyCode ) {
- // up or left arrow keys
- case 38:
- prev = li.prev();
-
- // if there's a previous option, focus it
- if ( prev.length ) {
- target
- .blur()
- .attr( "tabindex", "-1" );
-
- prev.find( "a" ).first().focus();
- }
-
- return false;
- break;
-
- // down or right arrow keys
- case 40:
- next = li.next();
-
- // if there's a next option, focus it
- if ( next.length ) {
- target
- .blur()
- .attr( "tabindex", "-1" );
-
- next.find( "a" ).first().focus();
- }
-
- return false;
- break;
-
- // If enter or space is pressed, trigger click
- case 13:
- case 32:
- target.trigger( "vclick" );
-
- return false;
- break;
- }
- });
-
- // button refocus ensures proper height calculation
- // by removing the inline style and ensuring page inclusion
- self.menuPage.bind( "pagehide", function(){
- self.list.appendTo( self.listbox );
- self._focusButton();
- });
-
- // Events on "screen" overlay
- screen.bind( "vclick", function( event ) {
- self.close();
- });
-
- // Close button on small overlays
- self.headerClose.click(function() {
- if ( self.menuType == "overlay" ) {
- self.close();
- return false;
- }
- });
- }
- },
-
- _buildList: function() {
- var self = this,
- o = this.options,
- placeholder = this.placeholder,
- optgroups = [],
- lis = [],
- dataIcon = self.isMultiple ? "checkbox-off" : "false";
-
- self.list.empty().filter( ".ui-listview" ).listview( "destroy" );
-
- // Populate menu with options from select element
- self.select.find( "option" ).each(function( i ) {
- var $this = $( this ),
- $parent = $this.parent(),
- text = $this.text(),
- anchor = "<a href='#'>"+ text +"</a>",
- classes = [],
- extraAttrs = [];
-
- // Are we inside an optgroup?
- if ( $parent.is( "optgroup" ) ) {
- var optLabel = $parent.attr( "label" );
-
- // has this optgroup already been built yet?
- if ( $.inArray( optLabel, optgroups ) === -1 ) {
- lis.push( "<li data-" + $.mobile.ns + "role='list-divider'>"+ optLabel +"</li>" );
- optgroups.push( optLabel );
- }
- }
-
- // Find placeholder text
- // TODO: Are you sure you want to use getAttribute? ^RW
- if ( !this.getAttribute( "value" ) || text.length == 0 || $this.jqmData( "placeholder" ) ) {
- if ( o.hidePlaceholderMenuItems ) {
- classes.push( "ui-selectmenu-placeholder" );
- }
- placeholder = self.placeholder = text;
- }
-
- // support disabled option tags
- if ( this.disabled ) {
- classes.push( "ui-disabled" );
- extraAttrs.push( "aria-disabled='true'" );
- }
-
- lis.push( "<li data-" + $.mobile.ns + "option-index='" + i + "' data-" + $.mobile.ns + "icon='"+ dataIcon +"' class='"+ classes.join(" ") + "' " + extraAttrs.join(" ") +">"+ anchor +"</li>" )
- });
-
- self.list.html( lis.join(" ") );
-
- self.list.find( "li" )
- .attr({ "role": "option", "tabindex": "-1" })
- .first().attr( "tabindex", "0" );
-
- // Hide header close link for single selects
- if ( !this.isMultiple ) {
- this.headerClose.hide();
- }
-
- // Hide header if it's not a multiselect and there's no placeholder
- if ( !this.isMultiple && !placeholder.length ) {
- this.header.hide();
- } else {
- this.headerTitle.text( this.placeholder );
- }
-
- // Now populated, create listview
- self.list.listview();
- },
-
- refresh: function( forceRebuild ) {
- var self = this,
- select = this.element,
- isMultiple = this.isMultiple,
- options = this.optionElems = select.find( "option" ),
- selected = options.filter( ":selected" ),
-
- // return an array of all selected index's
- indicies = selected.map(function() {
- return options.index( this );
- }).get();
-
- if ( !self.options.nativeMenu &&
- ( forceRebuild || select[0].options.length != self.list.find( "li" ).length ) ) {
-
- self._buildList();
- }
-
- self.button.find( ".ui-btn-text" )
- .text(function() {
-
- if ( !isMultiple ) {
- return selected.text();
- }
-
- return selected.length ? selected.map(function() {
- return $( this ).text();
- }).get().join( ", " ) : self.placeholder;
- });
-
- // multiple count inside button
- if ( isMultiple ) {
- self.buttonCount[ selected.length > 1 ? "show" : "hide" ]().text( selected.length );
- }
-
- if ( !self.options.nativeMenu ) {
-
- self.list.find( "li:not(.ui-li-divider)" )
- .removeClass( $.mobile.activeBtnClass )
- .attr( "aria-selected", false )
- .each(function( i ) {
-
- if ( $.inArray( i, indicies ) > -1 ) {
- var item = $( this ).addClass( $.mobile.activeBtnClass );
-
- // Aria selected attr
- item.find( "a" ).attr( "aria-selected", true );
-
- // Multiple selects: add the "on" checkbox state to the icon
- if ( isMultiple ) {
- item.find( ".ui-icon" ).removeClass( "ui-icon-checkbox-off" ).addClass( "ui-icon-checkbox-on" );
- }
- }
- });
- }
- },
-
- open: function() {
- if ( this.options.disabled || this.options.nativeMenu ) {
- return;
- }
-
- var self = this,
- menuHeight = self.list.parent().outerHeight(),
- menuWidth = self.list.parent().outerWidth(),
- scrollTop = $( window ).scrollTop(),
- btnOffset = self.button.offset().top,
- screenHeight = window.innerHeight,
- screenWidth = window.innerWidth;
-
- //add active class to button
- self.button.addClass( $.mobile.activeBtnClass );
-
- //remove after delay
- setTimeout(function() {
- self.button.removeClass( $.mobile.activeBtnClass );
- }, 300);
-
- function focusMenuItem() {
- self.list.find( ".ui-btn-active" ).focus();
- }
-
- if ( menuHeight > screenHeight - 80 || !$.support.scrollTop ) {
- // prevent the parent page from being removed from the DOM,
- // otherwise the results of selecting a list item in the dialog
- // fall into a black hole
- self.thisPage.unbind( "pagehide.remove" );
-
- //for webos (set lastscroll using button offset)
- if ( scrollTop == 0 && btnOffset > screenHeight ) {
- self.thisPage.one( "pagehide", function() {
- $( this ).jqmData( "lastScroll", btnOffset );
- });
- }
-
- self.menuPage.one( "pageshow", function() {
- // silentScroll() is called whenever a page is shown to restore
- // any previous scroll position the page may have had. We need to
- // wait for the "silentscroll" event before setting focus to avoid
- // the browser"s "feature" which offsets rendering to make sure
- // whatever has focus is in view.
- $( window ).one( "silentscroll", function() {
- focusMenuItem();
- });
-
- self.isOpen = true;
- });
-
- self.menuType = "page";
- self.menuPageContent.append( self.list );
- $.mobile.changePage( self.menuPage, {
- transition: $.mobile.defaultDialogTransition
- });
- } else {
-
- self.menuType = "overlay";
-
- self.screen.height( $(document).height() )
- .removeClass( "ui-screen-hidden" );
-
- // Try and center the overlay over the button
- var roomtop = btnOffset - scrollTop,
- roombot = scrollTop + screenHeight - btnOffset,
- halfheight = menuHeight / 2,
- maxwidth = parseFloat( self.list.parent().css( "max-width" ) ),
- newtop, newleft;
-
- if ( roomtop > menuHeight / 2 && roombot > menuHeight / 2 ) {
- newtop = btnOffset + ( self.button.outerHeight() / 2 ) - halfheight;
- } else {
- // 30px tolerance off the edges
- newtop = roomtop > roombot ? scrollTop + screenHeight - menuHeight - 30 : scrollTop + 30;
- }
-
- // If the menuwidth is smaller than the screen center is
- if ( menuWidth < maxwidth ) {
- newleft = ( screenWidth - menuWidth ) / 2;
- } else {
-
- //otherwise insure a >= 30px offset from the left
- newleft = self.button.offset().left + self.button.outerWidth() / 2 - menuWidth / 2;
-
- // 30px tolerance off the edges
- if ( newleft < 30 ) {
- newleft = 30;
- } else if ( ( newleft + menuWidth ) > screenWidth ) {
- newleft = screenWidth - menuWidth - 30;
- }
- }
-
- self.listbox.append( self.list )
- .removeClass( "ui-selectmenu-hidden" )
- .css({
- top: newtop,
- left: newleft
- })
- .addClass( "in" );
-
- focusMenuItem();
-
- // duplicate with value set in page show for dialog sized selects
- self.isOpen = true;
- }
- },
-
- _focusButton : function(){
- var self = this;
- setTimeout(function() {
- self.button.focus();
- }, 40);
- },
-
- close: function() {
- if ( this.options.disabled || !this.isOpen || this.options.nativeMenu ) {
- return;
- }
-
- var self = this;
-
- if ( self.menuType == "page" ) {
- // rebind the page remove that was unbound in the open function
- // to allow for the parent page removal from actions other than the use
- // of a dialog sized custom select
- self.thisPage.bind( "pagehide.remove", function(){
- $(this).remove();
- });
-
- // doesn't solve the possible issue with calling change page
- // where the objects don't define data urls which prevents dialog key
- // stripping - changePage has incoming refactor
- window.history.back();
- } else{
- self.screen.addClass( "ui-screen-hidden" );
- self.listbox.addClass( "ui-selectmenu-hidden" ).removeAttr( "style" ).removeClass( "in" );
- self.list.appendTo( self.listbox );
- self._focusButton();
- }
-
- // allow the dialog to be closed again
- this.isOpen = false;
- },
-
- disable: function() {
- this.element.attr( "disabled", true );
- this.button.addClass( "ui-disabled" ).attr( "aria-disabled", true );
- return this._setOption( "disabled", true );
- },
-
- enable: function() {
- this.element.attr( "disabled", false );
- this.button.removeClass( "ui-disabled" ).attr( "aria-disabled", false );
- return this._setOption( "disabled", false );
- }
-});
-
-//auto self-init widgets
-$( document ).bind( "pagecreate create", function( e ){
- $( $.mobile.selectmenu.prototype.options.initSelector, e.target )
- .not( ":jqmData(role='none'), :jqmData(role='nojs')" )
- .selectmenu();
-});
-
-})( jQuery );
-
-/*
-* jQuery Mobile Framework : plugin for making button-like links
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-( function( $, undefined ) {
-
-$.fn.buttonMarkup = function( options ) {
- return this.each( function() {
- var el = $( this ),
- o = $.extend( {}, $.fn.buttonMarkup.defaults, el.jqmData(), options ),
-
- // Classes Defined
- innerClass = "ui-btn-inner",
- buttonClass, iconClass,
- themedParent, wrap;
-
- if ( attachEvents ) {
- attachEvents();
- }
-
- // if not, try to find closest theme container
- if ( !o.theme ) {
- themedParent = el.closest( "[class*='ui-bar-'],[class*='ui-body-']" );
- o.theme = themedParent.length ?
- /ui-(bar|body)-([a-z])/.exec( themedParent.attr( "class" ) )[2] :
- "c";
- }
-
- buttonClass = "ui-btn ui-btn-up-" + o.theme;
-
- if ( o.inline ) {
- buttonClass += " ui-btn-inline";
- }
-
- if ( o.icon ) {
- o.icon = "ui-icon-" + o.icon;
- o.iconpos = o.iconpos || "left";
-
- iconClass = "ui-icon " + o.icon;
-
- if ( o.iconshadow ) {
- iconClass += " ui-icon-shadow";
- }
- }
-
- if ( o.iconpos ) {
- buttonClass += " ui-btn-icon-" + o.iconpos;
-
- if ( o.iconpos == "notext" && !el.attr( "title" ) ) {
- el.attr( "title", el.text() );
- }
- }
-
- if ( o.corners ) {
- buttonClass += " ui-btn-corner-all";
- innerClass += " ui-btn-corner-all";
- }
-
- if ( o.shadow ) {
- buttonClass += " ui-shadow";
- }
-
- el.attr( "data-" + $.mobile.ns + "theme", o.theme )
- .addClass( buttonClass );
-
- wrap = ( "<D class='" + innerClass + "'><D class='ui-btn-text'></D>" +
- ( o.icon ? "<span class='" + iconClass + "'></span>" : "" ) +
- "</D>" ).replace( /D/g, o.wrapperEls );
-
- el.wrapInner( wrap );
- });
-};
-
-$.fn.buttonMarkup.defaults = {
- corners: true,
- shadow: true,
- iconshadow: true,
- wrapperEls: "span"
-};
-
-function closestEnabledButton( element ) {
- while ( element ) {
- var $ele = $( element );
- if ( $ele.hasClass( "ui-btn" ) && !$ele.hasClass( "ui-disabled" ) ) {
- break;
- }
- element = element.parentNode;
- }
- return element;
-}
-
-var attachEvents = function() {
- $( document ).bind( {
- "vmousedown": function( event ) {
- var btn = closestEnabledButton( event.target ),
- $btn, theme;
-
- if ( btn ) {
- $btn = $( btn );
- theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
- $btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-down-" + theme );
- }
- },
- "vmousecancel vmouseup": function( event ) {
- var btn = closestEnabledButton( event.target ),
- $btn, theme;
-
- if ( btn ) {
- $btn = $( btn );
- theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
- $btn.removeClass( "ui-btn-down-" + theme ).addClass( "ui-btn-up-" + theme );
- }
- },
- "vmouseover focus": function( event ) {
- var btn = closestEnabledButton( event.target ),
- $btn, theme;
-
- if ( btn ) {
- $btn = $( btn );
- theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
- $btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-hover-" + theme );
- }
- },
- "vmouseout blur": function( event ) {
- var btn = closestEnabledButton( event.target ),
- $btn, theme;
-
- if ( btn ) {
- $btn = $( btn );
- theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
- $btn.removeClass( "ui-btn-hover-" + theme ).addClass( "ui-btn-up-" + theme );
- }
- }
- });
-
- attachEvents = null;
-};
-
-//links in bars, or those with data-role become buttons
-//auto self-init widgets
-$( document ).bind( "pagecreate create", function( e ){
-
- $( ":jqmData(role='button'), .ui-bar > a, .ui-header > a, .ui-footer > a, .ui-bar > :jqmData(role='controlgroup') > a", e.target )
- .not( ".ui-btn, :jqmData(role='none'), :jqmData(role='nojs')" )
- .buttonMarkup();
-});
-
-})( jQuery );
-/*
-* jQuery Mobile Framework: "controlgroup" plugin - corner-rounding for groups of buttons, checks, radios, etc
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-(function( $, undefined ) {
-
-$.fn.controlgroup = function( options ) {
-
- return this.each(function() {
-
- var $el = $( this ),
- o = $.extend({
- direction: $el.jqmData( "type" ) || "vertical",
- shadow: false,
- excludeInvisible: true
- }, options ),
- groupheading = $el.find( ">legend" ),
- flCorners = o.direction == "horizontal" ? [ "ui-corner-left", "ui-corner-right" ] : [ "ui-corner-top", "ui-corner-bottom" ],
- type = $el.find( "input:eq(0)" ).attr( "type" );
-
- // Replace legend with more stylable replacement div
- if ( groupheading.length ) {
- $el.wrapInner( "<div class='ui-controlgroup-controls'></div>" );
- $( "<div role='heading' class='ui-controlgroup-label'>" + groupheading.html() + "</div>" ).insertBefore( $el.children(0) );
- groupheading.remove();
- }
-
- $el.addClass( "ui-corner-all ui-controlgroup ui-controlgroup-" + o.direction );
-
- // TODO: This should be moved out to the closure
- // otherwise it is redefined each time controlgroup() is called
- function flipClasses( els ) {
- els.removeClass( "ui-btn-corner-all ui-shadow" )
- .eq( 0 ).addClass( flCorners[ 0 ] )
- .end()
- .filter( ":last" ).addClass( flCorners[ 1 ] ).addClass( "ui-controlgroup-last" );
- }
-
- flipClasses( $el.find( ".ui-btn" + ( o.excludeInvisible ? ":visible" : "" ) ) );
- flipClasses( $el.find( ".ui-btn-inner" ) );
-
- if ( o.shadow ) {
- $el.addClass( "ui-shadow" );
- }
- });
-};
-
-//auto self-init widgets
-$( document ).bind( "pagecreate create", function( e ){
- $( ":jqmData(role='controlgroup')", e.target ).controlgroup({ excludeInvisible: false });
-});
-
-})(jQuery);/*
-* jQuery Mobile Framework : "fieldcontain" plugin - simple class additions to make form row separators
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-
-(function( $, undefined ) {
-
-$( document ).bind( "pagecreate create", function( e ){
-
- //links within content areas
- $( e.target )
- .find( "a" )
- .not( ".ui-btn, .ui-link-inherit, :jqmData(role='none'), :jqmData(role='nojs')" )
- .addClass( "ui-link" );
-
-});
-
-})( jQuery );/*
-* jQuery Mobile Framework : "fixHeaderFooter" plugin - on-demand positioning for headers,footers
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-
-(function( $, undefined ) {
-
-var slideDownClass = "ui-header-fixed ui-fixed-inline fade",
- slideUpClass = "ui-footer-fixed ui-fixed-inline fade",
-
- slideDownSelector = ".ui-header:jqmData(position='fixed')",
- slideUpSelector = ".ui-footer:jqmData(position='fixed')";
-
-$.fn.fixHeaderFooter = function( options ) {
-
- if ( !$.support.scrollTop ) {
- return this;
- }
-
- return this.each(function() {
- var $this = $( this );
-
- if ( $this.jqmData( "fullscreen" ) ) {
- $this.addClass( "ui-page-fullscreen" );
- }
-
- // Should be slidedown
- $this.find( slideDownSelector ).addClass( slideDownClass );
-
- // Should be slideup
- $this.find( slideUpSelector ).addClass( slideUpClass );
- });
-};
-
-// single controller for all showing,hiding,toggling
-$.mobile.fixedToolbars = (function() {
-
- if ( !$.support.scrollTop ) {
- return;
- }
-
- var stickyFooter, delayTimer,
- currentstate = "inline",
- autoHideMode = false,
- showDelay = 100,
- ignoreTargets = "a,input,textarea,select,button,label,.ui-header-fixed,.ui-footer-fixed",
- toolbarSelector = ".ui-header-fixed:first, .ui-footer-fixed:not(.ui-footer-duplicate):last",
- // for storing quick references to duplicate footers
- supportTouch = $.support.touch,
- touchStartEvent = supportTouch ? "touchstart" : "mousedown",
- touchStopEvent = supportTouch ? "touchend" : "mouseup",
- stateBefore = null,
- scrollTriggered = false,
- touchToggleEnabled = true;
-
- function showEventCallback( event ) {
- // An event that affects the dimensions of the visual viewport has
- // been triggered. If the header and/or footer for the current page are in overlay
- // mode, we want to hide them, and then fire off a timer to show them at a later
- // point. Events like a resize can be triggered continuously during a scroll, on
- // some platforms, so the timer is used to delay the actual positioning until the
- // flood of events have subsided.
- //
- // If we are in autoHideMode, we don't do anything because we know the scroll
- // callbacks for the plugin will fire off a show when the scrolling has stopped.
- if ( !autoHideMode && currentstate === "overlay" ) {
- if ( !delayTimer ) {
- $.mobile.fixedToolbars.hide( true );
- }
-
- $.mobile.fixedToolbars.startShowTimer();
- }
- }
-
- $(function() {
- var $document = $( document ),
- $window = $( window );
-
- $document
- .bind( "vmousedown", function( event ) {
- if ( touchToggleEnabled ) {
- stateBefore = currentstate;
- }
- })
- .bind( "vclick", function( event ) {
- if ( touchToggleEnabled ) {
-
- if ( $(event.target).closest( ignoreTargets ).length ) {
- return;
- }
-
- if ( !scrollTriggered ) {
- $.mobile.fixedToolbars.toggle( stateBefore );
- stateBefore = null;
- }
- }
- })
- .bind( "silentscroll", showEventCallback );
-
-
- // The below checks first for a $(document).scrollTop() value, and if zero, binds scroll events to $(window) instead.
- // If the scrollTop value is actually zero, both will return zero anyway.
- //
- // Works with $(document), not $(window) : Opera Mobile (WinMO phone; kinda broken anyway)
- // Works with $(window), not $(document) : IE 7/8
- // Works with either $(window) or $(document) : Chrome, FF 3.6/4, Android 1.6/2.1, iOS
- // Needs work either way : BB5, Opera Mobile (iOS)
-
- ( ( $document.scrollTop() === 0 ) ? $window : $document )
- .bind( "scrollstart", function( event ) {
-
- scrollTriggered = true;
-
- if ( stateBefore === null ) {
- stateBefore = currentstate;
- }
-
- // We only enter autoHideMode if the headers/footers are in
- // an overlay state or the show timer was started. If the
- // show timer is set, clear it so the headers/footers don't
- // show up until after we're done scrolling.
- var isOverlayState = stateBefore == "overlay";
-
- autoHideMode = isOverlayState || !!delayTimer;
-
- if ( autoHideMode ) {
- $.mobile.fixedToolbars.clearShowTimer();
-
- if ( isOverlayState ) {
- $.mobile.fixedToolbars.hide( true );
- }
- }
- })
- .bind( "scrollstop", function( event ) {
-
- if ( $( event.target ).closest( ignoreTargets ).length ) {
- return;
- }
-
- scrollTriggered = false;
-
- if ( autoHideMode ) {
- $.mobile.fixedToolbars.startShowTimer();
- autoHideMode = false;
- }
- stateBefore = null;
- });
-
- $window.bind( "resize", showEventCallback );
- });
-
- // 1. Before page is shown, check for duplicate footer
- // 2. After page is shown, append footer to new page
- $( ".ui-page" )
- .live( "pagebeforeshow", function( event, ui ) {
-
- var page = $( event.target ),
- footer = page.find( ":jqmData(role='footer')" ),
- id = footer.data( "id" ),
- prevPage = ui.prevPage,
- prevFooter = prevPage && prevPage.find( ":jqmData(role='footer')" ),
- prevFooterMatches = prevFooter.length && prevFooter.jqmData( "id" ) === id;
-
- if ( id && prevFooterMatches ) {
- stickyFooter = footer;
- setTop( stickyFooter.removeClass( "fade in out" ).appendTo( $.mobile.pageContainer ) );
- }
- })
- .live( "pageshow", function( event, ui ) {
-
- var $this = $( this );
-
- if ( stickyFooter && stickyFooter.length ) {
-
- setTimeout(function() {
- setTop( stickyFooter.appendTo( $this ).addClass( "fade" ) );
- stickyFooter = null;
- }, 500);
- }
-
- $.mobile.fixedToolbars.show( true, this );
- });
-
- // When a collapsiable is hidden or shown we need to trigger the fixed toolbar to reposition itself (#1635)
- $( ".ui-collapsible-contain" ).live( "collapse expand", showEventCallback );
-
- // element.getBoundingClientRect() is broken in iOS 3.2.1 on the iPad. The
- // coordinates inside of the rect it returns don't have the page scroll position
- // factored out of it like the other platforms do. To get around this,
- // we'll just calculate the top offset the old fashioned way until core has
- // a chance to figure out how to handle this situation.
- //
- // TODO: We'll need to get rid of getOffsetTop() once a fix gets folded into core.
-
- function getOffsetTop( ele ) {
- var top = 0,
- op, body;
-
- if ( ele ) {
- body = document.body;
- op = ele.offsetParent;
- top = ele.offsetTop;
-
- while ( ele && ele != body ) {
- top += ele.scrollTop || 0;
-
- if ( ele == op ) {
- top += op.offsetTop;
- op = ele.offsetParent;
- }
-
- ele = ele.parentNode;
- }
- }
- return top;
- }
-
- function setTop( el ) {
- var fromTop = $(window).scrollTop(),
- thisTop = getOffsetTop( el[ 0 ] ), // el.offset().top returns the wrong value on iPad iOS 3.2.1, call our workaround instead.
- thisCSStop = el.css( "top" ) == "auto" ? 0 : parseFloat(el.css( "top" )),
- screenHeight = window.innerHeight,
- thisHeight = el.outerHeight(),
- useRelative = el.parents( ".ui-page:not(.ui-page-fullscreen)" ).length,
- relval;
-
- if ( el.is( ".ui-header-fixed" ) ) {
-
- relval = fromTop - thisTop + thisCSStop;
-
- if ( relval < thisTop ) {
- relval = 0;
- }
-
- return el.css( "top", useRelative ? relval : fromTop );
- } else {
- // relval = -1 * (thisTop - (fromTop + screenHeight) + thisCSStop + thisHeight);
- // if ( relval > thisTop ) { relval = 0; }
- relval = fromTop + screenHeight - thisHeight - (thisTop - thisCSStop );
-
- return el.css( "top", useRelative ? relval : fromTop + screenHeight - thisHeight );
- }
- }
-
- // Exposed methods
- return {
-
- show: function( immediately, page ) {
-
- $.mobile.fixedToolbars.clearShowTimer();
-
- currentstate = "overlay";
-
- var $ap = page ? $( page ) :
- ( $.mobile.activePage ? $.mobile.activePage :
- $( ".ui-page-active" ) );
-
- return $ap.children( toolbarSelector ).each(function() {
-
- var el = $( this ),
- fromTop = $( window ).scrollTop(),
- // el.offset().top returns the wrong value on iPad iOS 3.2.1, call our workaround instead.
- thisTop = getOffsetTop( el[ 0 ] ),
- screenHeight = window.innerHeight,
- thisHeight = el.outerHeight(),
- alreadyVisible = ( el.is( ".ui-header-fixed" ) && fromTop <= thisTop + thisHeight ) ||
- ( el.is( ".ui-footer-fixed" ) && thisTop <= fromTop + screenHeight );
-
- // Add state class
- el.addClass( "ui-fixed-overlay" ).removeClass( "ui-fixed-inline" );
-
- if ( !alreadyVisible && !immediately ) {
- el.animationComplete(function() {
- el.removeClass( "in" );
- }).addClass( "in" );
- }
- setTop(el);
- });
- },
-
- hide: function( immediately ) {
-
- currentstate = "inline";
-
- var $ap = $.mobile.activePage ? $.mobile.activePage :
- $( ".ui-page-active" );
-
- return $ap.children( toolbarSelector ).each(function() {
-
- var el = $(this),
- thisCSStop = el.css( "top" ),
- classes;
-
- thisCSStop = thisCSStop == "auto" ? 0 :
- parseFloat(thisCSStop);
-
- // Add state class
- el.addClass( "ui-fixed-inline" ).removeClass( "ui-fixed-overlay" );
-
- if ( thisCSStop < 0 || ( el.is( ".ui-header-fixed" ) && thisCSStop !== 0 ) ) {
-
- if ( immediately ) {
- el.css( "top", 0);
- } else {
-
- if ( el.css( "top" ) !== "auto" && parseFloat( el.css( "top" ) ) !== 0 ) {
-
- classes = "out reverse";
-
- el.animationComplete(function() {
- el.removeClass( classes ).css( "top", 0 );
- }).addClass( classes );
- }
- }
- }
- });
- },
-
- startShowTimer: function() {
-
- $.mobile.fixedToolbars.clearShowTimer();
-
- var args = [].slice.call( arguments );
-
- delayTimer = setTimeout(function() {
- delayTimer = undefined;
- $.mobile.fixedToolbars.show.apply( null, args );
- }, showDelay);
- },
-
- clearShowTimer: function() {
- if ( delayTimer ) {
- clearTimeout( delayTimer );
- }
- delayTimer = undefined;
- },
-
- toggle: function( from ) {
- if ( from ) {
- currentstate = from;
- }
- return ( currentstate === "overlay" ) ? $.mobile.fixedToolbars.hide() :
- $.mobile.fixedToolbars.show();
- },
-
- setTouchToggleEnabled: function( enabled ) {
- touchToggleEnabled = enabled;
- }
- };
-})();
-
-// TODO - Deprecated namepace on $. Remove in a later release
-$.fixedToolbars = $.mobile.fixedToolbars;
-
-//auto self-init widgets
-$( document ).bind( "pagecreate create", function( event ) {
-
- if ( $( ":jqmData(position='fixed')", event.target ).length ) {
-
- $( event.target ).each(function() {
-
- if ( !$.support.scrollTop ) {
- return this;
- }
-
- var $this = $( this );
-
- if ( $this.jqmData( "fullscreen" ) ) {
- $this.addClass( "ui-page-fullscreen" );
- }
-
- // Should be slidedown
- $this.find( slideDownSelector ).addClass( slideDownClass );
-
- // Should be slideup
- $this.find( slideUpSelector ).addClass( slideUpClass );
-
- })
-
- }
-});
-
-})( jQuery );
-/*
-* jQuery Mobile Framework : resolution and CSS media query related helpers and behavior
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-(function( $, undefined ) {
-
-var $window = $( window ),
- $html = $( "html" ),
-
- //media-query-like width breakpoints, which are translated to classes on the html element
- resolutionBreakpoints = [ 320, 480, 768, 1024 ];
-
-/*
- private function for adding/removing breakpoint classes to HTML element for faux media-query support
- It does not require media query support, instead using JS to detect screen width > cross-browser support
- This function is called on orientationchange, resize, and mobileinit, and is bound via the 'htmlclass' event namespace
-*/
-function detectResolutionBreakpoints() {
- var currWidth = $window.width(),
- minPrefix = "min-width-",
- maxPrefix = "max-width-",
- minBreakpoints = [],
- maxBreakpoints = [],
- unit = "px",
- breakpointClasses;
-
- $html.removeClass( minPrefix + resolutionBreakpoints.join(unit + " " + minPrefix) + unit + " " +
- maxPrefix + resolutionBreakpoints.join( unit + " " + maxPrefix) + unit );
-
- $.each( resolutionBreakpoints, function( i, breakPoint ) {
- if( currWidth >= breakPoint ) {
- minBreakpoints.push( minPrefix + breakPoint + unit );
- }
- if( currWidth <= breakPoint ) {
- maxBreakpoints.push( maxPrefix + breakPoint + unit );
- }
- });
-
- if ( minBreakpoints.length ) {
- breakpointClasses = minBreakpoints.join(" ");
- }
- if ( maxBreakpoints.length ) {
- breakpointClasses += " " + maxBreakpoints.join(" ");
- }
-
- $html.addClass( breakpointClasses );
-};
-
-/* $.mobile.addResolutionBreakpoints method:
- pass either a number or an array of numbers and they'll be added to the min/max breakpoint classes
- Examples:
- $.mobile.addResolutionBreakpoints( 500 );
- $.mobile.addResolutionBreakpoints( [500, 1200] );
-*/
-$.mobile.addResolutionBreakpoints = function( newbps ) {
- if( $.type( newbps ) === "array" ){
- resolutionBreakpoints = resolutionBreakpoints.concat( newbps );
- } else {
- resolutionBreakpoints.push( newbps );
- }
-
- resolutionBreakpoints.sort(function( a, b ) {
- return a - b;
- });
-
- detectResolutionBreakpoints();
-};
-
-/* on mobileinit, add classes to HTML element
- and set handlers to update those on orientationchange and resize
-*/
-$( document ).bind( "mobileinit.htmlclass", function() {
- // bind to orientationchange and resize
- // to add classes to HTML element for min/max breakpoints and orientation
-
- var ev = $.support.orientation;
-
- $window.bind( "orientationchange.htmlclass throttledResize.htmlclass", function( event ) {
-
- // add orientation class to HTML element on flip/resize.
- if ( event.orientation ) {
- $html.removeClass( "portrait landscape" ).addClass( event.orientation );
- }
-
- // add classes to HTML element for min/max breakpoints
- detectResolutionBreakpoints();
- });
-});
-
-/* Manually trigger an orientationchange event when the dom ready event fires.
- This will ensure that any viewport meta tag that may have been injected
- has taken effect already, allowing us to properly calculate the width of the
- document.
-*/
-$(function() {
- //trigger event manually
- $window.trigger( "orientationchange.htmlclass" );
-});
-
-})(jQuery);/*!
- * jQuery Mobile v@VERSION
- * http://jquerymobile.com/
- *
- * Copyright 2010, jQuery Project
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- */
-
-(function( $, window, undefined ) {
- var $html = $( "html" ),
- $head = $( "head" ),
- $window = $( window );
-
- //trigger mobileinit event - useful hook for configuring $.mobile settings before they're used
- $( window.document ).trigger( "mobileinit" );
-
- //support conditions
- //if device support condition(s) aren't met, leave things as they are -> a basic, usable experience,
- //otherwise, proceed with the enhancements
- if ( !$.mobile.gradeA() ) {
- return;
- }
-
- // override ajaxEnabled on platforms that have known conflicts with hash history updates
- // or generally work better browsing in regular http for full page refreshes (BB5, Opera Mini)
- if( $.mobile.ajaxBlacklist ){
- $.mobile.ajaxEnabled = false;
- }
-
- //add mobile, initial load "rendering" classes to docEl
- $html.addClass( "ui-mobile ui-mobile-rendering" );
-
- //loading div which appears during Ajax requests
- //will not appear if $.mobile.loadingMessage is false
- var $loader = $( "<div class='ui-loader ui-body-a ui-corner-all'><span class='ui-icon ui-icon-loading spin'></span><h1></h1></div>" );
-
- $.extend($.mobile, {
- // turn on/off page loading message.
- showPageLoadingMsg: function() {
- if( $.mobile.loadingMessage ){
- var activeBtn = $( "." + $.mobile.activeBtnClass ).first();
-
- $loader
- .find( "h1" )
- .text( $.mobile.loadingMessage )
- .end()
- .appendTo( $.mobile.pageContainer )
- //position at y center (if scrollTop supported), above the activeBtn (if defined), or just 100px from top
- .css( {
- top: $.support.scrollTop && $(window).scrollTop() + $(window).height() / 2 ||
- activeBtn.length && activeBtn.offset().top || 100
- } );
- }
-
- $html.addClass( "ui-loading" );
- },
-
- hidePageLoadingMsg: function() {
- $html.removeClass( "ui-loading" );
- },
-
- // XXX: deprecate for 1.0
- pageLoading: function ( done ) {
- if ( done ) {
- $.mobile.hidePageLoadingMsg();
- } else {
- $.mobile.showPageLoadingMsg();
- }
- },
-
- // find and enhance the pages in the dom and transition to the first page.
- initializePage: function(){
- //find present pages
- var $pages = $( ":jqmData(role='page')" );
-
- //if no pages are found, create one with body's inner html
- if( !$pages.length ){
- $pages = $( "body" ).wrapInner( "<div data-" + $.mobile.ns + "role='page'></div>" ).children( 0 );
- }
-
- //add dialogs, set data-url attrs
- $pages.add( ":jqmData(role='dialog')" ).each(function(){
- var $this = $(this);
-
- // unless the data url is already set set it to the id
- if( !$this.jqmData('url') ){
- $this.attr( "data-" + $.mobile.ns + "url", $this.attr( "id" ) );
- }
- });
-
- //define first page in dom case one backs out to the directory root (not always the first page visited, but defined as fallback)
- $.mobile.firstPage = $pages.first();
-
- //define page container
- $.mobile.pageContainer = $pages.first().parent().addClass( "ui-mobile-viewport" );
-
- //cue page loading message
- $.mobile.showPageLoadingMsg();
-
- // if hashchange listening is disabled or there's no hash deeplink, change to the first page in the DOM
- if( !$.mobile.hashListeningEnabled || !$.mobile.path.stripHash( location.hash ) ){
- $.mobile.changePage( $.mobile.firstPage, { transition: "none", reverse: true, changeHash: false, fromHashChange: true } );
- }
- // otherwise, trigger a hashchange to load a deeplink
- else {
- $window.trigger( "hashchange", [ true ] );
- }
- }
- });
-
- //initialize events now, after mobileinit has occurred
- $.mobile._registerInternalEvents();
-
- //check which scrollTop value should be used by scrolling to 1 immediately at domready
- //then check what the scroll top is. Android will report 0... others 1
- //note that this initial scroll won't hide the address bar. It's just for the check.
- $(function(){
- window.scrollTo( 0, 1 );
-
- //if defaultHomeScroll hasn't been set yet, see if scrollTop is 1
- //it should be 1 in most browsers, but android treats 1 as 0 (for hiding addr bar)
- //so if it's 1, use 0 from now on
- $.mobile.defaultHomeScroll = ( !$.support.scrollTop || $(window).scrollTop() === 1 ) ? 0 : 1;
-
- //dom-ready inits
- if( $.mobile.autoInitializePage ){
- $( $.mobile.initializePage );
- }
-
- //window load event
- //hide iOS browser chrome on load
- $window.load( $.mobile.silentScroll );
- });
-})( jQuery, this );
-
--- /dev/null
+++ b/js/jquery.mobile-1.0b3.js
@@ -1,1 +1,6658 @@
-
+/*!
+ * jQuery Mobile v1.0b3
+ * http://jquerymobile.com/
+ *
+ * Copyright 2010, jQuery Project
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ */
+/*!
+ * jQuery UI Widget @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/Widget
+ */
+(function( $, undefined ) {
+
+// jQuery 1.4+
+if ( $.cleanData ) {
+ var _cleanData = $.cleanData;
+ $.cleanData = function( elems ) {
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ $( elem ).triggerHandler( "remove" );
+ }
+ _cleanData( elems );
+ };
+} else {
+ var _remove = $.fn.remove;
+ $.fn.remove = function( selector, keepData ) {
+ return this.each(function() {
+ if ( !keepData ) {
+ if ( !selector || $.filter( selector, [ this ] ).length ) {
+ $( "*", this ).add( [ this ] ).each(function() {
+ $( this ).triggerHandler( "remove" );
+ });
+ }
+ }
+ return _remove.call( $(this), selector, keepData );
+ });
+ };
+}
+
+$.widget = function( name, base, prototype ) {
+ var namespace = name.split( "." )[ 0 ],
+ fullName;
+ name = name.split( "." )[ 1 ];
+ fullName = namespace + "-" + name;
+
+ if ( !prototype ) {
+ prototype = base;
+ base = $.Widget;
+ }
+
+ // create selector for plugin
+ $.expr[ ":" ][ fullName ] = function( elem ) {
+ return !!$.data( elem, name );
+ };
+
+ $[ namespace ] = $[ namespace ] || {};
+ $[ namespace ][ name ] = function( options, element ) {
+ // allow instantiation without initializing for simple inheritance
+ if ( arguments.length ) {
+ this._createWidget( options, element );
+ }
+ };
+
+ var basePrototype = new base();
+ // we need to make the options hash a property directly on the new instance
+ // otherwise we'll modify the options hash on the prototype that we're
+ // inheriting from
+// $.each( basePrototype, function( key, val ) {
+// if ( $.isPlainObject(val) ) {
+// basePrototype[ key ] = $.extend( {}, val );
+// }
+// });
+ basePrototype.options = $.extend( true, {}, basePrototype.options );
+ $[ namespace ][ name ].prototype = $.extend( true, basePrototype, {
+ namespace: namespace,
+ widgetName: name,
+ widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name,
+ widgetBaseClass: fullName
+ }, prototype );
+
+ $.widget.bridge( name, $[ namespace ][ name ] );
+};
+
+$.widget.bridge = function( name, object ) {
+ $.fn[ name ] = function( options ) {
+ var isMethodCall = typeof options === "string",
+ args = Array.prototype.slice.call( arguments, 1 ),
+ returnValue = this;
+
+ // allow multiple hashes to be passed on init
+ options = !isMethodCall && args.length ?
+ $.extend.apply( null, [ true, options ].concat(args) ) :
+ options;
+
+ // prevent calls to internal methods
+ if ( isMethodCall && options.charAt( 0 ) === "_" ) {
+ return returnValue;
+ }
+
+ if ( isMethodCall ) {
+ this.each(function() {
+ var instance = $.data( this, name );
+ if ( !instance ) {
+ throw "cannot call methods on " + name + " prior to initialization; " +
+ "attempted to call method '" + options + "'";
+ }
+ if ( !$.isFunction( instance[options] ) ) {
+ throw "no such method '" + options + "' for " + name + " widget instance";
+ }
+ var methodValue = instance[ options ].apply( instance, args );
+ if ( methodValue !== instance && methodValue !== undefined ) {
+ returnValue = methodValue;
+ return false;
+ }
+ });
+ } else {
+ this.each(function() {
+ var instance = $.data( this, name );
+ if ( instance ) {
+ instance.option( options || {} )._init();
+ } else {
+ $.data( this, name, new object( options, this ) );
+ }
+ });
+ }
+
+ return returnValue;
+ };
+};
+
+$.Widget = function( options, element ) {
+ // allow instantiation without initializing for simple inheritance
+ if ( arguments.length ) {
+ this._createWidget( options, element );
+ }
+};
+
+$.Widget.prototype = {
+ widgetName: "widget",
+ widgetEventPrefix: "",
+ options: {
+ disabled: false
+ },
+ _createWidget: function( options, element ) {
+ // $.widget.bridge stores the plugin instance, but we do it anyway
+ // so that it's stored even before the _create function runs
+ $.data( element, this.widgetName, this );
+ this.element = $( element );
+ this.options = $.extend( true, {},
+ this.options,
+ this._getCreateOptions(),
+ options );
+
+ var self = this;
+ this.element.bind( "remove." + this.widgetName, function() {
+ self.destroy();
+ });
+
+ this._create();
+ this._trigger( "create" );
+ this._init();
+ },
+ _getCreateOptions: function() {
+ var options = {};
+ if ( $.metadata ) {
+ options = $.metadata.get( element )[ this.widgetName ];
+ }
+ return options;
+ },
+ _create: function() {},
+ _init: function() {},
+
+ destroy: function() {
+ this.element
+ .unbind( "." + this.widgetName )
+ .removeData( this.widgetName );
+ this.widget()
+ .unbind( "." + this.widgetName )
+ .removeAttr( "aria-disabled" )
+ .removeClass(
+ this.widgetBaseClass + "-disabled " +
+ "ui-state-disabled" );
+ },
+
+ widget: function() {
+ return this.element;
+ },
+
+ option: function( key, value ) {
+ var options = key;
+
+ if ( arguments.length === 0 ) {
+ // don't return a reference to the internal hash
+ return $.extend( {}, this.options );
+ }
+
+ if (typeof key === "string" ) {
+ if ( value === undefined ) {
+ return this.options[ key ];
+ }
+ options = {};
+ options[ key ] = value;
+ }
+
+ this._setOptions( options );
+
+ return this;
+ },
+ _setOptions: function( options ) {
+ var self = this;
+ $.each( options, function( key, value ) {
+ self._setOption( key, value );
+ });
+
+ return this;
+ },
+ _setOption: function( key, value ) {
+ this.options[ key ] = value;
+
+ if ( key === "disabled" ) {
+ this.widget()
+ [ value ? "addClass" : "removeClass"](
+ this.widgetBaseClass + "-disabled" + " " +
+ "ui-state-disabled" )
+ .attr( "aria-disabled", value );
+ }
+
+ return this;
+ },
+
+ enable: function() {
+ return this._setOption( "disabled", false );
+ },
+ disable: function() {
+ return this._setOption( "disabled", true );
+ },
+
+ _trigger: function( type, event, data ) {
+ var callback = this.options[ type ];
+
+ event = $.Event( event );
+ event.type = ( type === this.widgetEventPrefix ?
+ type :
+ this.widgetEventPrefix + type ).toLowerCase();
+ data = data || {};
+
+ // copy original event properties over to the new event
+ // this would happen if we could call $.event.fix instead of $.Event
+ // but we don't have a way to force an event to be fixed multiple times
+ if ( event.originalEvent ) {
+ for ( var i = $.event.props.length, prop; i; ) {
+ prop = $.event.props[ --i ];
+ event[ prop ] = event.originalEvent[ prop ];
+ }
+ }
+
+ this.element.trigger( event, data );
+
+ return !( $.isFunction(callback) &&
+ callback.call( this.element[0], event, data ) === false ||
+ event.isDefaultPrevented() );
+ }
+};
+
+})( jQuery );
+/*
+* jQuery Mobile Framework : widget factory extentions for mobile
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+(function( $, undefined ) {
+
+$.widget( "mobile.widget", {
+ _getCreateOptions: function() {
+
+ var elem = this.element,
+ options = {};
+
+ $.each( this.options, function( option ) {
+
+ var value = elem.jqmData( option.replace( /[A-Z]/g, function( c ) {
+ return "-" + c.toLowerCase();
+ })
+ );
+
+ if ( value !== undefined ) {
+ options[ option ] = value;
+ }
+ });
+
+ return options;
+ }
+});
+
+})( jQuery );
+/*
+* jQuery Mobile Framework : resolution and CSS media query related helpers and behavior
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function( $, undefined ) {
+
+var $window = $( window ),
+ $html = $( "html" );
+
+/* $.mobile.media method: pass a CSS media type or query and get a bool return
+ note: this feature relies on actual media query support for media queries, though types will work most anywhere
+ examples:
+ $.mobile.media('screen') //>> tests for screen media type
+ $.mobile.media('screen and (min-width: 480px)') //>> tests for screen media type with window width > 480px
+ $.mobile.media('@media screen and (-webkit-min-device-pixel-ratio: 2)') //>> tests for webkit 2x pixel ratio (iPhone 4)
+*/
+$.mobile.media = (function() {
+ // TODO: use window.matchMedia once at least one UA implements it
+ var cache = {},
+ testDiv = $( "<div id='jquery-mediatest'>" ),
+ fakeBody = $( "<body>" ).append( testDiv );
+
+ return function( query ) {
+ if ( !( query in cache ) ) {
+ var styleBlock = document.createElement( "style" ),
+ cssrule = "@media " + query + " { #jquery-mediatest { position:absolute; } }";
+
+ //must set type for IE!
+ styleBlock.type = "text/css";
+
+ if ( styleBlock.styleSheet ){
+ styleBlock.styleSheet.cssText = cssrule;
+ } else {
+ styleBlock.appendChild( document.createTextNode(cssrule) );
+ }
+
+ $html.prepend( fakeBody ).prepend( styleBlock );
+ cache[ query ] = testDiv.css( "position" ) === "absolute";
+ fakeBody.add( styleBlock ).remove();
+ }
+ return cache[ query ];
+ };
+})();
+
+})(jQuery);/*
+* jQuery Mobile Framework : support tests
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
+*/
+
+(function( $, undefined ) {
+
+var fakeBody = $( "<body>" ).prependTo( "html" ),
+ fbCSS = fakeBody[ 0 ].style,
+ vendors = [ "Webkit", "Moz", "O" ],
+ webos = "palmGetResource" in window, //only used to rule out scrollTop
+ bb = window.blackberry; //only used to rule out box shadow, as it's filled opaque on BB
+
+// thx Modernizr
+function propExists( prop ) {
+ var uc_prop = prop.charAt( 0 ).toUpperCase() + prop.substr( 1 ),
+ props = ( prop + " " + vendors.join( uc_prop + " " ) + uc_prop ).split( " " );
+
+ for ( var v in props ){
+ if ( fbCSS[ props[ v ] ] !== undefined ) {
+ return true;
+ }
+ }
+}
+
+// Test for dynamic-updating base tag support ( allows us to avoid href,src attr rewriting )
+function baseTagTest() {
+ var fauxBase = location.protocol + "//" + location.host + location.pathname + "ui-dir/",
+ base = $( "head base" ),
+ fauxEle = null,
+ href = "",
+ link, rebase;
+
+ if ( !base.length ) {
+ base = fauxEle = $( "<base>", { "href": fauxBase }).appendTo( "head" );
+ } else {
+ href = base.attr( "href" );
+ }
+
+ link = $( "<a href='testurl'></a>" ).prependTo( fakeBody );
+ rebase = link[ 0 ].href;
+ base[ 0 ].href = href ? href : location.pathname;
+
+ if ( fauxEle ) {
+ fauxEle.remove();
+ }
+ return rebase.indexOf( fauxBase ) === 0;
+}
+
+
+// non-UA-based IE version check by James Padolsey, modified by jdalton - from http://gist.github.com/527683
+// allows for inclusion of IE 6+, including Windows Mobile 7
+$.mobile.browser = {};
+$.mobile.browser.ie = (function() {
+ var v = 3,
+ div = document.createElement( "div" ),
+ a = div.all || [];
+
+ while ( div.innerHTML = "<!--[if gt IE " + ( ++v ) + "]><br><![endif]-->", a[ 0 ] );
+
+ return v > 4 ? v : !v;
+})();
+
+
+$.extend( $.support, {
+ orientation: "orientation" in window,
+ touch: "ontouchend" in document,
+ cssTransitions: "WebKitTransitionEvent" in window,
+ pushState: "pushState" in history && "replaceState" in history,
+ mediaquery: $.mobile.media( "only all" ),
+ cssPseudoElement: !!propExists( "content" ),
+ touchOverflow: !!propExists( "overflowScrolling" ),
+ boxShadow: !!propExists( "boxShadow" ) && !bb,
+ scrollTop: ( "pageXOffset" in window || "scrollTop" in document.documentElement || "scrollTop" in fakeBody[ 0 ] ) && !webos,
+ dynamicBaseTag: baseTagTest(),
+ // TODO: This is a weak test. We may want to beef this up later.
+ eventCapture: "addEventListener" in document
+});
+
+fakeBody.remove();
+
+
+// $.mobile.ajaxBlacklist is used to override ajaxEnabled on platforms that have known conflicts with hash history updates (BB5, Symbian)
+// or that generally work better browsing in regular http for full page refreshes (Opera Mini)
+// Note: This detection below is used as a last resort.
+// We recommend only using these detection methods when all other more reliable/forward-looking approaches are not possible
+var nokiaLTE7_3 = (function(){
+
+ var ua = window.navigator.userAgent;
+
+ //The following is an attempt to match Nokia browsers that are running Symbian/s60, with webkit, version 7.3 or older
+ return ua.indexOf( "Nokia" ) > -1 &&
+ ( ua.indexOf( "Symbian/3" ) > -1 || ua.indexOf( "Series60/5" ) > -1 ) &&
+ ua.indexOf( "AppleWebKit" ) > -1 &&
+ ua.match( /(BrowserNG|NokiaBrowser)\/7\.[0-3]/ );
+})();
+
+$.mobile.ajaxBlacklist =
+ // BlackBerry browsers, pre-webkit
+ window.blackberry && !window.WebKitPoint ||
+ // Opera Mini
+ window.operamini && Object.prototype.toString.call( window.operamini ) === "[object OperaMini]" ||
+ // Symbian webkits pre 7.3
+ nokiaLTE7_3;
+
+// Lastly, this workaround is the only way we've found so far to get pre 7.3 Symbian webkit devices
+// to render the stylesheets when they're referenced before this script, as we'd recommend doing.
+// This simply reappends the CSS in place, which for some reason makes it apply
+if ( nokiaLTE7_3 ) {
+ $(function() {
+ $( "head link[rel=stylesheet]" ).attr( "rel", "alternate stylesheet" ).attr( "rel", "stylesheet" );
+ });
+}
+
+// For ruling out shadows via css
+if ( !$.support.boxShadow ) {
+ $( "html" ).addClass( "ui-mobile-nosupport-boxshadow" );
+}
+
+})( jQuery );/*
+* jQuery Mobile Framework : "mouse" plugin
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+// This plugin is an experiment for abstracting away the touch and mouse
+// events so that developers don't have to worry about which method of input
+// the device their document is loaded on supports.
+//
+// The idea here is to allow the developer to register listeners for the
+// basic mouse events, such as mousedown, mousemove, mouseup, and click,
+// and the plugin will take care of registering the correct listeners
+// behind the scenes to invoke the listener at the fastest possible time
+// for that device, while still retaining the order of event firing in
+// the traditional mouse environment, should multiple handlers be registered
+// on the same element for different events.
+//
+// The current version exposes the following virtual events to jQuery bind methods:
+// "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel"
+
+(function( $, window, document, undefined ) {
+
+var dataPropertyName = "virtualMouseBindings",
+ touchTargetPropertyName = "virtualTouchID",
+ virtualEventNames = "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split( " " ),
+ touchEventProps = "clientX clientY pageX pageY screenX screenY".split( " " ),
+ activeDocHandlers = {},
+ resetTimerID = 0,
+ startX = 0,
+ startY = 0,
+ didScroll = false,
+ clickBlockList = [],
+ blockMouseTriggers = false,
+ blockTouchTriggers = false,
+ eventCaptureSupported = $.support.eventCapture,
+ $document = $( document ),
+ nextTouchID = 1,
+ lastTouchID = 0;
+
+$.vmouse = {
+ moveDistanceThreshold: 10,
+ clickDistanceThreshold: 10,
+ resetTimerDuration: 1500
+};
+
+function getNativeEvent( event ) {
+
+ while ( event && typeof event.originalEvent !== "undefined" ) {
+ event = event.originalEvent;
+ }
+ return event;
+}
+
+function createVirtualEvent( event, eventType ) {
+
+ var t = event.type,
+ oe, props, ne, prop, ct, touch, i, j;
+
+ event = $.Event(event);
+ event.type = eventType;
+
+ oe = event.originalEvent;
+ props = $.event.props;
+
+ // copy original event properties over to the new event
+ // this would happen if we could call $.event.fix instead of $.Event
+ // but we don't have a way to force an event to be fixed multiple times
+ if ( oe ) {
+ for ( i = props.length, prop; i; ) {
+ prop = props[ --i ];
+ event[ prop ] = oe[ prop ];
+ }
+ }
+
+ if ( t.search(/^touch/) !== -1 ) {
+ ne = getNativeEvent( oe );
+ t = ne.touches;
+ ct = ne.changedTouches;
+ touch = ( t && t.length ) ? t[0] : ( (ct && ct.length) ? ct[ 0 ] : undefined );
+
+ if ( touch ) {
+ for ( j = 0, len = touchEventProps.length; j < len; j++){
+ prop = touchEventProps[ j ];
+ event[ prop ] = touch[ prop ];
+ }
+ }
+ }
+
+ return event;
+}
+
+function getVirtualBindingFlags( element ) {
+
+ var flags = {},
+ b, k;
+
+ while ( element ) {
+
+ b = $.data( element, dataPropertyName );
+
+ for ( k in b ) {
+ if ( b[ k ] ) {
+ flags[ k ] = flags.hasVirtualBinding = true;
+ }
+ }
+ element = element.parentNode;
+ }
+ return flags;
+}
+
+function getClosestElementWithVirtualBinding( element, eventType ) {
+ var b;
+ while ( element ) {
+
+ b = $.data( element, dataPropertyName );
+
+ if ( b && ( !eventType || b[ eventType ] ) ) {
+ return element;
+ }
+ element = element.parentNode;
+ }
+ return null;
+}
+
+function enableTouchBindings() {
+ blockTouchTriggers = false;
+}
+
+function disableTouchBindings() {
+ blockTouchTriggers = true;
+}
+
+function enableMouseBindings() {
+ lastTouchID = 0;
+ clickBlockList.length = 0;
+ blockMouseTriggers = false;
+
+ // When mouse bindings are enabled, our
+ // touch bindings are disabled.
+ disableTouchBindings();
+}
+
+function disableMouseBindings() {
+ // When mouse bindings are disabled, our
+ // touch bindings are enabled.
+ enableTouchBindings();
+}
+
+function startResetTimer() {
+ clearResetTimer();
+ resetTimerID = setTimeout(function(){
+ resetTimerID = 0;
+ enableMouseBindings();
+ }, $.vmouse.resetTimerDuration );
+}
+
+function clearResetTimer() {
+ if ( resetTimerID ){
+ clearTimeout( resetTimerID );
+ resetTimerID = 0;
+ }
+}
+
+function triggerVirtualEvent( eventType, event, flags ) {
+ var ve;
+
+ if ( ( flags && flags[ eventType ] ) ||
+ ( !flags && getClosestElementWithVirtualBinding( event.target, eventType ) ) ) {
+
+ ve = createVirtualEvent( event, eventType );
+
+ $( event.target).trigger( ve );
+ }
+
+ return ve;
+}
+
+function mouseEventCallback( event ) {
+ var touchID = $.data(event.target, touchTargetPropertyName);
+
+ if ( !blockMouseTriggers && ( !lastTouchID || lastTouchID !== touchID ) ){
+ var ve = triggerVirtualEvent( "v" + event.type, event );
+ if ( ve ) {
+ if ( ve.isDefaultPrevented() ) {
+ event.preventDefault();
+ }
+ if ( ve.isPropagationStopped() ) {
+ event.stopPropagation();
+ }
+ if ( ve.isImmediatePropagationStopped() ) {
+ event.stopImmediatePropagation();
+ }
+ }
+ }
+}
+
+function handleTouchStart( event ) {
+
+ var touches = getNativeEvent( event ).touches,
+ target, flags;
+
+ if ( touches && touches.length === 1 ) {
+
+ target = event.target;
+ flags = getVirtualBindingFlags( target );
+
+ if ( flags.hasVirtualBinding ) {
+
+ lastTouchID = nextTouchID++;
+ $.data( target, touchTargetPropertyName, lastTouchID );
+
+ clearResetTimer();
+
+ disableMouseBindings();
+ didScroll = false;
+
+ var t = getNativeEvent( event ).touches[ 0 ];
+ startX = t.pageX;
+ startY = t.pageY;
+
+ triggerVirtualEvent( "vmouseover", event, flags );
+ triggerVirtualEvent( "vmousedown", event, flags );
+ }
+ }
+}
+
+function handleScroll( event ) {
+ if ( blockTouchTriggers ) {
+ return;
+ }
+
+ if ( !didScroll ) {
+ triggerVirtualEvent( "vmousecancel", event, getVirtualBindingFlags( event.target ) );
+ }
+
+ didScroll = true;
+ startResetTimer();
+}
+
+function handleTouchMove( event ) {
+ if ( blockTouchTriggers ) {
+ return;
+ }
+
+ var t = getNativeEvent( event ).touches[ 0 ],
+ didCancel = didScroll,
+ moveThreshold = $.vmouse.moveDistanceThreshold;
+ didScroll = didScroll ||
+ ( Math.abs(t.pageX - startX) > moveThreshold ||
+ Math.abs(t.pageY - startY) > moveThreshold ),
+ flags = getVirtualBindingFlags( event.target );
+
+ if ( didScroll && !didCancel ) {
+ triggerVirtualEvent( "vmousecancel", event, flags );
+ }
+
+ triggerVirtualEvent( "vmousemove", event, flags );
+ startResetTimer();
+}
+
+function handleTouchEnd( event ) {
+ if ( blockTouchTriggers ) {
+ return;
+ }
+
+ disableTouchBindings();
+
+ var flags = getVirtualBindingFlags( event.target ),
+ t;
+ triggerVirtualEvent( "vmouseup", event, flags );
+
+ if ( !didScroll ) {
+ var ve = triggerVirtualEvent( "vclick", event, flags );
+ if ( ve && ve.isDefaultPrevented() ) {
+ // The target of the mouse events that follow the touchend
+ // event don't necessarily match the target used during the
+ // touch. This means we need to rely on coordinates for blocking
+ // any click that is generated.
+ t = getNativeEvent( event ).changedTouches[ 0 ];
+ clickBlockList.push({
+ touchID: lastTouchID,
+ x: t.clientX,
+ y: t.clientY
+ });
+
+ // Prevent any mouse events that follow from triggering
+ // virtual event notifications.
+ blockMouseTriggers = true;
+ }
+ }
+ triggerVirtualEvent( "vmouseout", event, flags);
+ didScroll = false;
+
+ startResetTimer();
+}
+
+function hasVirtualBindings( ele ) {
+ var bindings = $.data( ele, dataPropertyName ),
+ k;
+
+ if ( bindings ) {
+ for ( k in bindings ) {
+ if ( bindings[ k ] ) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+function dummyMouseHandler(){}
+
+function getSpecialEventObject( eventType ) {
+ var realType = eventType.substr( 1 );
+
+ return {
+ setup: function( data, namespace ) {
+ // If this is the first virtual mouse binding for this element,
+ // add a bindings object to its data.
+
+ if ( !hasVirtualBindings( this ) ) {
+ $.data( this, dataPropertyName, {});
+ }
+
+ // If setup is called, we know it is the first binding for this
+ // eventType, so initialize the count for the eventType to zero.
+ var bindings = $.data( this, dataPropertyName );
+ bindings[ eventType ] = true;
+
+ // If this is the first virtual mouse event for this type,
+ // register a global handler on the document.
+
+ activeDocHandlers[ eventType ] = ( activeDocHandlers[ eventType ] || 0 ) + 1;
+
+ if ( activeDocHandlers[ eventType ] === 1 ) {
+ $document.bind( realType, mouseEventCallback );
+ }
+
+ // Some browsers, like Opera Mini, won't dispatch mouse/click events
+ // for elements unless they actually have handlers registered on them.
+ // To get around this, we register dummy handlers on the elements.
+
+ $( this ).bind( realType, dummyMouseHandler );
+
+ // For now, if event capture is not supported, we rely on mouse handlers.
+ if ( eventCaptureSupported ) {
+ // If this is the first virtual mouse binding for the document,
+ // register our touchstart handler on the document.
+
+ activeDocHandlers[ "touchstart" ] = ( activeDocHandlers[ "touchstart" ] || 0) + 1;
+
+ if (activeDocHandlers[ "touchstart" ] === 1) {
+ $document.bind( "touchstart", handleTouchStart )
+ .bind( "touchend", handleTouchEnd )
+
+ // On touch platforms, touching the screen and then dragging your finger
+ // causes the window content to scroll after some distance threshold is
+ // exceeded. On these platforms, a scroll prevents a click event from being
+ // dispatched, and on some platforms, even the touchend is suppressed. To
+ // mimic the suppression of the click event, we need to watch for a scroll
+ // event. Unfortunately, some platforms like iOS don't dispatch scroll
+ // events until *AFTER* the user lifts their finger (touchend). This means
+ // we need to watch both scroll and touchmove events to figure out whether
+ // or not a scroll happenens before the touchend event is fired.
+
+ .bind( "touchmove", handleTouchMove )
+ .bind( "scroll", handleScroll );
+ }
+ }
+ },
+
+ teardown: function( data, namespace ) {
+ // If this is the last virtual binding for this eventType,
+ // remove its global handler from the document.
+
+ --activeDocHandlers[ eventType ];
+
+ if ( !activeDocHandlers[ eventType ] ) {
+ $document.unbind( realType, mouseEventCallback );
+ }
+
+ if ( eventCaptureSupported ) {
+ // If this is the last virtual mouse binding in existence,
+ // remove our document touchstart listener.
+
+ --activeDocHandlers[ "touchstart" ];
+
+ if ( !activeDocHandlers[ "touchstart" ] ) {
+ $document.unbind( "touchstart", handleTouchStart )
+ .unbind( "touchmove", handleTouchMove )
+ .unbind( "touchend", handleTouchEnd )
+ .unbind( "scroll", handleScroll );
+ }
+ }
+
+ var $this = $( this ),
+ bindings = $.data( this, dataPropertyName );
+
+ // teardown may be called when an element was
+ // removed from the DOM. If this is the case,
+ // jQuery core may have already stripped the element
+ // of any data bindings so we need to check it before
+ // using it.
+ if ( bindings ) {
+ bindings[ eventType ] = false;
+ }
+
+ // Unregister the dummy event handler.
+
+ $this.unbind( realType, dummyMouseHandler );
+
+ // If this is the last virtual mouse binding on the
+ // element, remove the binding data from the element.
+
+ if ( !hasVirtualBindings( this ) ) {
+ $this.removeData( dataPropertyName );
+ }
+ }
+ };
+}
+
+// Expose our custom events to the jQuery bind/unbind mechanism.
+
+for ( var i = 0; i < virtualEventNames.length; i++ ){
+ $.event.special[ virtualEventNames[ i ] ] = getSpecialEventObject( virtualEventNames[ i ] );
+}
+
+// Add a capture click handler to block clicks.
+// Note that we require event capture support for this so if the device
+// doesn't support it, we punt for now and rely solely on mouse events.
+if ( eventCaptureSupported ) {
+ document.addEventListener( "click", function( e ){
+ var cnt = clickBlockList.length,
+ target = e.target,
+ x, y, ele, i, o, touchID;
+
+ if ( cnt ) {
+ x = e.clientX;
+ y = e.clientY;
+ threshold = $.vmouse.clickDistanceThreshold;
+
+ // The idea here is to run through the clickBlockList to see if
+ // the current click event is in the proximity of one of our
+ // vclick events that had preventDefault() called on it. If we find
+ // one, then we block the click.
+ //
+ // Why do we have to rely on proximity?
+ //
+ // Because the target of the touch event that triggered the vclick
+ // can be different from the target of the click event synthesized
+ // by the browser. The target of a mouse/click event that is syntehsized
+ // from a touch event seems to be implementation specific. For example,
+ // some browsers will fire mouse/click events for a link that is near
+ // a touch event, even though the target of the touchstart/touchend event
+ // says the user touched outside the link. Also, it seems that with most
+ // browsers, the target of the mouse/click event is not calculated until the
+ // time it is dispatched, so if you replace an element that you touched
+ // with another element, the target of the mouse/click will be the new
+ // element underneath that point.
+ //
+ // Aside from proximity, we also check to see if the target and any
+ // of its ancestors were the ones that blocked a click. This is necessary
+ // because of the strange mouse/click target calculation done in the
+ // Android 2.1 browser, where if you click on an element, and there is a
+ // mouse/click handler on one of its ancestors, the target will be the
+ // innermost child of the touched element, even if that child is no where
+ // near the point of touch.
+
+ ele = target;
+
+ while ( ele ) {
+ for ( i = 0; i < cnt; i++ ) {
+ o = clickBlockList[ i ];
+ touchID = 0;
+
+ if ( ( ele === target && Math.abs( o.x - x ) < threshold && Math.abs( o.y - y ) < threshold ) ||
+ $.data( ele, touchTargetPropertyName ) === o.touchID ) {
+ // XXX: We may want to consider removing matches from the block list
+ // instead of waiting for the reset timer to fire.
+ e.preventDefault();
+ e.stopPropagation();
+ return;
+ }
+ }
+ ele = ele.parentNode;
+ }
+ }
+ }, true);
+}
+})( jQuery, window, document );
+/*
+* jQuery Mobile Framework : events
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function( $, window, undefined ) {
+
+// add new event shortcuts
+$.each( ( "touchstart touchmove touchend orientationchange throttledresize " +
+ "tap taphold swipe swipeleft swiperight scrollstart scrollstop" ).split( " " ), function( i, name ) {
+
+ $.fn[ name ] = function( fn ) {
+ return fn ? this.bind( name, fn ) : this.trigger( name );
+ };
+
+ $.attrFn[ name ] = true;
+});
+
+var supportTouch = $.support.touch,
+ scrollEvent = "touchmove scroll",
+ touchStartEvent = supportTouch ? "touchstart" : "mousedown",
+ touchStopEvent = supportTouch ? "touchend" : "mouseup",
+ touchMoveEvent = supportTouch ? "touchmove" : "mousemove";
+
+function triggerCustomEvent( obj, eventType, event ) {
+ var originalType = event.type;
+ event.type = eventType;
+ $.event.handle.call( obj, event );
+ event.type = originalType;
+}
+
+// also handles scrollstop
+$.event.special.scrollstart = {
+
+ enabled: true,
+
+ setup: function() {
+
+ var thisObject = this,
+ $this = $( thisObject ),
+ scrolling,
+ timer;
+
+ function trigger( event, state ) {
+ scrolling = state;
+ triggerCustomEvent( thisObject, scrolling ? "scrollstart" : "scrollstop", event );
+ }
+
+ // iPhone triggers scroll after a small delay; use touchmove instead
+ $this.bind( scrollEvent, function( event ) {
+
+ if ( !$.event.special.scrollstart.enabled ) {
+ return;
+ }
+
+ if ( !scrolling ) {
+ trigger( event, true );
+ }
+
+ clearTimeout( timer );
+ timer = setTimeout(function() {
+ trigger( event, false );
+ }, 50 );
+ });
+ }
+};
+
+// also handles taphold
+$.event.special.tap = {
+ setup: function() {
+ var thisObject = this,
+ $this = $( thisObject );
+
+ $this.bind( "vmousedown", function( event ) {
+
+ if ( event.which && event.which !== 1 ) {
+ return false;
+ }
+
+ var origTarget = event.target,
+ origEvent = event.originalEvent,
+ timer;
+
+ function clearTapTimer() {
+ clearTimeout( timer );
+ }
+
+ function clearTapHandlers() {
+ clearTapTimer();
+
+ $this.unbind( "vclick", clickHandler )
+ .unbind( "vmouseup", clearTapTimer )
+ .unbind( "vmousecancel", clearTapHandlers );
+ }
+
+ function clickHandler(event) {
+ clearTapHandlers();
+
+ // ONLY trigger a 'tap' event if the start target is
+ // the same as the stop target.
+ if ( origTarget == event.target ) {
+ triggerCustomEvent( thisObject, "tap", event );
+ }
+ }
+
+ $this.bind( "vmousecancel", clearTapHandlers )
+ .bind( "vmouseup", clearTapTimer )
+ .bind( "vclick", clickHandler );
+
+ timer = setTimeout(function() {
+ triggerCustomEvent( thisObject, "taphold", $.Event( "taphold" ) );
+ }, 750 );
+ });
+ }
+};
+
+// also handles swipeleft, swiperight
+$.event.special.swipe = {
+ scrollSupressionThreshold: 10, // More than this horizontal displacement, and we will suppress scrolling.
+
+ durationThreshold: 1000, // More time than this, and it isn't a swipe.
+
+ horizontalDistanceThreshold: 30, // Swipe horizontal displacement must be more than this.
+
+ verticalDistanceThreshold: 75, // Swipe vertical displacement must be less than this.
+
+ setup: function() {
+ var thisObject = this,
+ $this = $( thisObject );
+
+ $this.bind( touchStartEvent, function( event ) {
+ var data = event.originalEvent.touches ?
+ event.originalEvent.touches[ 0 ] : event,
+ start = {
+ time: ( new Date() ).getTime(),
+ coords: [ data.pageX, data.pageY ],
+ origin: $( event.target )
+ },
+ stop;
+
+ function moveHandler( event ) {
+
+ if ( !start ) {
+ return;
+ }
+
+ var data = event.originalEvent.touches ?
+ event.originalEvent.touches[ 0 ] : event;
+
+ stop = {
+ time: ( new Date() ).getTime(),
+ coords: [ data.pageX, data.pageY ]
+ };
+
+ // prevent scrolling
+ if ( Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.scrollSupressionThreshold ) {
+ event.preventDefault();
+ }
+ }
+
+ $this.bind( touchMoveEvent, moveHandler )
+ .one( touchStopEvent, function( event ) {
+ $this.unbind( touchMoveEvent, moveHandler );
+
+ if ( start && stop ) {
+ if ( stop.time - start.time < $.event.special.swipe.durationThreshold &&
+ Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.horizontalDistanceThreshold &&
+ Math.abs( start.coords[ 1 ] - stop.coords[ 1 ] ) < $.event.special.swipe.verticalDistanceThreshold ) {
+
+ start.origin.trigger( "swipe" )
+ .trigger( start.coords[0] > stop.coords[ 0 ] ? "swipeleft" : "swiperight" );
+ }
+ }
+ start = stop = undefined;
+ });
+ });
+ }
+};
+
+(function( $, window ) {
+ // "Cowboy" Ben Alman
+
+ var win = $( window ),
+ special_event,
+ get_orientation,
+ last_orientation;
+
+ $.event.special.orientationchange = special_event = {
+ setup: function() {
+ // If the event is supported natively, return false so that jQuery
+ // will bind to the event using DOM methods.
+ if ( $.support.orientation ) {
+ return false;
+ }
+
+ // Get the current orientation to avoid initial double-triggering.
+ last_orientation = get_orientation();
+
+ // Because the orientationchange event doesn't exist, simulate the
+ // event by testing window dimensions on resize.
+ win.bind( "throttledresize", handler );
+ },
+ teardown: function(){
+ // If the event is not supported natively, return false so that
+ // jQuery will unbind the event using DOM methods.
+ if ( $.support.orientation ) {
+ return false;
+ }
+
+ // Because the orientationchange event doesn't exist, unbind the
+ // resize event handler.
+ win.unbind( "throttledresize", handler );
+ },
+ add: function( handleObj ) {
+ // Save a reference to the bound event handler.
+ var old_handler = handleObj.handler;
+
+ handleObj.handler = function( event ) {
+ // Modify event object, adding the .orientation property.
+ event.orientation = get_orientation();
+
+ // Call the originally-bound event handler and return its result.
+ return old_handler.apply( this, arguments );
+ };
+ }
+ };
+
+ // If the event is not supported natively, this handler will be bound to
+ // the window resize event to simulate the orientationchange event.
+ function handler() {
+ // Get the current orientation.
+ var orientation = get_orientation();
+
+ if ( orientation !== last_orientation ) {
+ // The orientation has changed, so trigger the orientationchange event.
+ last_orientation = orientation;
+ win.trigger( "orientationchange" );
+ }
+ };
+
+ // Get the current page orientation. This method is exposed publicly, should it
+ // be needed, as jQuery.event.special.orientationchange.orientation()
+ $.event.special.orientationchange.orientation = get_orientation = function() {
+ var elem = document.documentElement;
+ return elem && elem.clientWidth / elem.clientHeight < 1.1 ? "portrait" : "landscape";
+ };
+
+})( jQuery, window );
+
+
+// throttled resize event
+(function() {
+
+ $.event.special.throttledresize = {
+ setup: function() {
+ $( this ).bind( "resize", handler );
+ },
+ teardown: function(){
+ $( this ).unbind( "resize", handler );
+ }
+ };
+
+ var throttle = 250,
+ handler = function() {
+ curr = ( new Date() ).getTime();
+ diff = curr - lastCall;
+
+ if ( diff >= throttle ) {
+
+ lastCall = curr;
+ $( this ).trigger( "throttledresize" );
+
+ } else {
+
+ if ( heldCall ) {
+ clearTimeout( heldCall );
+ }
+
+ // Promise a held call will still execute
+ heldCall = setTimeout( handler, throttle - diff );
+ }
+ },
+ lastCall = 0,
+ heldCall,
+ curr,
+ diff;
+})();
+
+
+$.each({
+ scrollstop: "scrollstart",
+ taphold: "tap",
+ swipeleft: "swipe",
+ swiperight: "swipe"
+}, function( event, sourceEvent ) {
+
+ $.event.special[ event ] = {
+ setup: function() {
+ $( this ).bind( sourceEvent, $.noop );
+ }
+ };
+});
+
+})( jQuery, this );
+/*!
+ * jQuery hashchange event - v1.3 - 7/21/2010
+ * http://benalman.com/projects/jquery-hashchange-plugin/
+ *
+ * Copyright (c) 2010 "Cowboy" Ben Alman
+ * Dual licensed under the MIT and GPL licenses.
+ * http://benalman.com/about/license/
+ */
+
+// Script: jQuery hashchange event
+//
+// *Version: 1.3, Last updated: 7/21/2010*
+//
+// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
+// GitHub - http://github.com/cowboy/jquery-hashchange/
+// Source - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
+// (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
+//
+// About: License
+//
+// Copyright (c) 2010 "Cowboy" Ben Alman,
+// Dual licensed under the MIT and GPL licenses.
+// http://benalman.com/about/license/
+//
+// About: Examples
+//
+// These working examples, complete with fully commented code, illustrate a few
+// ways in which this plugin can be used.
+//
+// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
+// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
+//
+// About: Support and Testing
+//
+// Information about what version or versions of jQuery this plugin has been
+// tested with, what browsers it has been tested in, and where the unit tests
+// reside (so you can test it yourself).
+//
+// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
+// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
+// Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
+// Unit Tests - http://benalman.com/code/projects/jquery-hashchange/unit/
+//
+// About: Known issues
+//
+// While this jQuery hashchange event implementation is quite stable and
+// robust, there are a few unfortunate browser bugs surrounding expected
+// hashchange event-based behaviors, independent of any JavaScript
+// window.onhashchange abstraction. See the following examples for more
+// information:
+//
+// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
+// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
+// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
+// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
+//
+// Also note that should a browser natively support the window.onhashchange
+// event, but not report that it does, the fallback polling loop will be used.
+//
+// About: Release History
+//
+// 1.3 - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
+// "removable" for mobile-only development. Added IE6/7 document.title
+// support. Attempted to make Iframe as hidden as possible by using
+// techniques from http://www.paciellogroup.com/blog/?p=604. Added
+// support for the "shortcut" format $(window).hashchange( fn ) and
+// $(window).hashchange() like jQuery provides for built-in events.
+// Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
+// lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
+// and <jQuery.fn.hashchange.src> properties plus document-domain.html
+// file to address access denied issues when setting document.domain in
+// IE6/7.
+// 1.2 - (2/11/2010) Fixed a bug where coming back to a page using this plugin
+// from a page on another domain would cause an error in Safari 4. Also,
+// IE6/7 Iframe is now inserted after the body (this actually works),
+// which prevents the page from scrolling when the event is first bound.
+// Event can also now be bound before DOM ready, but it won't be usable
+// before then in IE6/7.
+// 1.1 - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
+// where browser version is incorrectly reported as 8.0, despite
+// inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
+// 1.0 - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
+// window.onhashchange functionality into a separate plugin for users
+// who want just the basic event & back button support, without all the
+// extra awesomeness that BBQ provides. This plugin will be included as
+// part of jQuery BBQ, but also be available separately.
+
+(function($,window,undefined){
+ '$:nomunge'; // Used by YUI compressor.
+
+ // Reused string.
+ var str_hashchange = 'hashchange',
+
+ // Method / object references.
+ doc = document,
+ fake_onhashchange,
+ special = $.event.special,
+
+ // Does the browser support window.onhashchange? Note that IE8 running in
+ // IE7 compatibility mode reports true for 'onhashchange' in window, even
+ // though the event isn't supported, so also test document.documentMode.
+ doc_mode = doc.documentMode,
+ supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );
+
+ // Get location.hash (or what you'd expect location.hash to be) sans any
+ // leading #. Thanks for making this necessary, Firefox!
+ function get_fragment( url ) {
+ url = url || location.href;
+ return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
+ };
+
+ // Method: jQuery.fn.hashchange
+ //
+ // Bind a handler to the window.onhashchange event or trigger all bound
+ // window.onhashchange event handlers. This behavior is consistent with
+ // jQuery's built-in event handlers.
+ //
+ // Usage:
+ //
+ // > jQuery(window).hashchange( [ handler ] );
+ //
+ // Arguments:
+ //
+ // handler - (Function) Optional handler to be bound to the hashchange
+ // event. This is a "shortcut" for the more verbose form:
+ // jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
+ // all bound window.onhashchange event handlers will be triggered. This
+ // is a shortcut for the more verbose
+ // jQuery(window).trigger( 'hashchange' ). These forms are described in
+ // the <hashchange event> section.
+ //
+ // Returns:
+ //
+ // (jQuery) The initial jQuery collection of elements.
+
+ // Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
+ // $(elem).hashchange() for triggering, like jQuery does for built-in events.
+ $.fn[ str_hashchange ] = function( fn ) {
+ return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange );
+ };
+
+ // Property: jQuery.fn.hashchange.delay
+ //
+ // The numeric interval (in milliseconds) at which the <hashchange event>
+ // polling loop executes. Defaults to 50.
+
+ // Property: jQuery.fn.hashchange.domain
+ //
+ // If you're setting document.domain in your JavaScript, and you want hash
+ // history to work in IE6/7, not only must this property be set, but you must
+ // also set document.domain BEFORE jQuery is loaded into the page. This
+ // property is only applicable if you are supporting IE6/7 (or IE8 operating
+ // in "IE7 compatibility" mode).
+ //
+ // In addition, the <jQuery.fn.hashchange.src> property must be set to the
+ // path of the included "document-domain.html" file, which can be renamed or
+ // modified if necessary (note that the document.domain specified must be the
+ // same in both your main JavaScript as well as in this file).
+ //
+ // Usage:
+ //
+ // jQuery.fn.hashchange.domain = document.domain;
+
+ // Property: jQuery.fn.hashchange.src
+ //
+ // If, for some reason, you need to specify an Iframe src file (for example,
+ // when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
+ // do so using this property. Note that when using this property, history
+ // won't be recorded in IE6/7 until the Iframe src file loads. This property
+ // is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
+ // compatibility" mode).
+ //
+ // Usage:
+ //
+ // jQuery.fn.hashchange.src = 'path/to/file.html';
+
+ $.fn[ str_hashchange ].delay = 50;
+ /*
+ $.fn[ str_hashchange ].domain = null;
+ $.fn[ str_hashchange ].src = null;
+ */
+
+ // Event: hashchange event
+ //
+ // Fired when location.hash changes. In browsers that support it, the native
+ // HTML5 window.onhashchange event is used, otherwise a polling loop is
+ // initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
+ // see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
+ // compatibility" mode), a hidden Iframe is created to allow the back button
+ // and hash-based history to work.
+ //
+ // Usage as described in <jQuery.fn.hashchange>:
+ //
+ // > // Bind an event handler.
+ // > jQuery(window).hashchange( function(e) {
+ // > var hash = location.hash;
+ // > ...
+ // > });
+ // >
+ // > // Manually trigger the event handler.
+ // > jQuery(window).hashchange();
+ //
+ // A more verbose usage that allows for event namespacing:
+ //
+ // > // Bind an event handler.
+ // > jQuery(window).bind( 'hashchange', function(e) {
+ // > var hash = location.hash;
+ // > ...
+ // > });
+ // >
+ // > // Manually trigger the event handler.
+ // > jQuery(window).trigger( 'hashchange' );
+ //
+ // Additional Notes:
+ //
+ // * The polling loop and Iframe are not created until at least one handler
+ // is actually bound to the 'hashchange' event.
+ // * If you need the bound handler(s) to execute immediately, in cases where
+ // a location.hash exists on page load, via bookmark or page refresh for
+ // example, use jQuery(window).hashchange() or the more verbose
+ // jQuery(window).trigger( 'hashchange' ).
+ // * The event can be bound before DOM ready, but since it won't be usable
+ // before then in IE6/7 (due to the necessary Iframe), recommended usage is
+ // to bind it inside a DOM ready handler.
+
+ // Override existing $.event.special.hashchange methods (allowing this plugin
+ // to be defined after jQuery BBQ in BBQ's source code).
+ special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
+
+ // Called only when the first 'hashchange' event is bound to window.
+ setup: function() {
+ // If window.onhashchange is supported natively, there's nothing to do..
+ if ( supports_onhashchange ) { return false; }
+
+ // Otherwise, we need to create our own. And we don't want to call this
+ // until the user binds to the event, just in case they never do, since it
+ // will create a polling loop and possibly even a hidden Iframe.
+ $( fake_onhashchange.start );
+ },
+
+ // Called only when the last 'hashchange' event is unbound from window.
+ teardown: function() {
+ // If window.onhashchange is supported natively, there's nothing to do..
+ if ( supports_onhashchange ) { return false; }
+
+ // Otherwise, we need to stop ours (if possible).
+ $( fake_onhashchange.stop );
+ }
+
+ });
+
+ // fake_onhashchange does all the work of triggering the window.onhashchange
+ // event for browsers that don't natively support it, including creating a
+ // polling loop to watch for hash changes and in IE 6/7 creating a hidden
+ // Iframe to enable back and forward.
+ fake_onhashchange = (function(){
+ var self = {},
+ timeout_id,
+
+ // Remember the initial hash so it doesn't get triggered immediately.
+ last_hash = get_fragment(),
+
+ fn_retval = function(val){ return val; },
+ history_set = fn_retval,
+ history_get = fn_retval;
+
+ // Start the polling loop.
+ self.start = function() {
+ timeout_id || poll();
+ };
+
+ // Stop the polling loop.
+ self.stop = function() {
+ timeout_id && clearTimeout( timeout_id );
+ timeout_id = undefined;
+ };
+
+ // This polling loop checks every $.fn.hashchange.delay milliseconds to see
+ // if location.hash has changed, and triggers the 'hashchange' event on
+ // window when necessary.
+ function poll() {
+ var hash = get_fragment(),
+ history_hash = history_get( last_hash );
+
+ if ( hash !== last_hash ) {
+ history_set( last_hash = hash, history_hash );
+
+ $(window).trigger( str_hashchange );
+
+ } else if ( history_hash !== last_hash ) {
+ location.href = location.href.replace( /#.*/, '' ) + history_hash;
+ }
+
+ timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
+ };
+
+ // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+ // vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv
+ // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+ $.browser.msie && !supports_onhashchange && (function(){
+ // Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8
+ // when running in "IE7 compatibility" mode.
+
+ var iframe,
+ iframe_src;
+
+ // When the event is bound and polling starts in IE 6/7, create a hidden
+ // Iframe for history handling.
+ self.start = function(){
+ if ( !iframe ) {
+ iframe_src = $.fn[ str_hashchange ].src;
+ iframe_src = iframe_src && iframe_src + get_fragment();
+
+ // Create hidden Iframe. Attempt to make Iframe as hidden as possible
+ // by using techniques from http://www.paciellogroup.com/blog/?p=604.
+ iframe = $('<iframe tabindex="-1" title="empty"/>').hide()
+
+ // When Iframe has completely loaded, initialize the history and
+ // start polling.
+ .one( 'load', function(){
+ iframe_src || history_set( get_fragment() );
+ poll();
+ })
+
+ // Load Iframe src if specified, otherwise nothing.
+ .attr( 'src', iframe_src || 'javascript:0' )
+
+ // Append Iframe after the end of the body to prevent unnecessary
+ // initial page scrolling (yes, this works).
+ .insertAfter( 'body' )[0].contentWindow;
+
+ // Whenever `document.title` changes, update the Iframe's title to
+ // prettify the back/next history menu entries. Since IE sometimes
+ // errors with "Unspecified error" the very first time this is set
+ // (yes, very useful) wrap this with a try/catch block.
+ doc.onpropertychange = function(){
+ try {
+ if ( event.propertyName === 'title' ) {
+ iframe.document.title = doc.title;
+ }
+ } catch(e) {}
+ };
+
+ }
+ };
+
+ // Override the "stop" method since an IE6/7 Iframe was created. Even
+ // if there are no longer any bound event handlers, the polling loop
+ // is still necessary for back/next to work at all!
+ self.stop = fn_retval;
+
+ // Get history by looking at the hidden Iframe's location.hash.
+ history_get = function() {
+ return get_fragment( iframe.location.href );
+ };
+
+ // Set a new history item by opening and then closing the Iframe
+ // document, *then* setting its location.hash. If document.domain has
+ // been set, update that as well.
+ history_set = function( hash, history_hash ) {
+ var iframe_doc = iframe.document,
+ domain = $.fn[ str_hashchange ].domain;
+
+ if ( hash !== history_hash ) {
+ // Update Iframe with any initial `document.title` that might be set.
+ iframe_doc.title = doc.title;
+
+ // Opening the Iframe's document after it has been closed is what
+ // actually adds a history entry.
+ iframe_doc.open();
+
+ // Set document.domain for the Iframe document as well, if necessary.
+ domain && iframe_doc.write( '<script>document.domain="' + domain + '"</script>' );
+
+ iframe_doc.close();
+
+ // Update the Iframe's hash, for great justice.
+ iframe.location.hash = hash;
+ }
+ };
+
+ })();
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ // ^^^^^^^^^^^^^^^^^^^ REMOVE IF NOT SUPPORTING IE6/7/8 ^^^^^^^^^^^^^^^^^^^
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ return self;
+ })();
+
+})(jQuery,this);
+/*
+* jQuery Mobile Framework : "page" plugin
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+(function( $, undefined ) {
+
+$.widget( "mobile.page", $.mobile.widget, {
+ options: {
+ theme: "c",
+ domCache: false
+ },
+
+ _create: function() {
+
+ this._trigger( "beforecreate" );
+
+ this.element
+ .attr( "tabindex", "0" )
+ .addClass( "ui-page ui-body-" + this.options.theme );
+ }
+});
+
+})( jQuery );
+/*!
+ * jQuery Mobile v@VERSION
+ * http://jquerymobile.com/
+ *
+ * Copyright 2010, jQuery Project
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ */
+
+(function( $, window, undefined ) {
+
+ // jQuery.mobile configurable options
+ $.extend( $.mobile, {
+
+ // Namespace used framework-wide for data-attrs. Default is no namespace
+ ns: "",
+
+ // Define the url parameter used for referencing widget-generated sub-pages.
+ // Translates to to example.html&ui-page=subpageIdentifier
+ // hash segment before &ui-page= is used to make Ajax request
+ subPageUrlKey: "ui-page",
+
+ // Class assigned to page currently in view, and during transitions
+ activePageClass: "ui-page-active",
+
+ // Class used for "active" button state, from CSS framework
+ activeBtnClass: "ui-btn-active",
+
+ // Automatically handle clicks and form submissions through Ajax, when same-domain
+ ajaxEnabled: true,
+
+ // Automatically load and show pages based on location.hash
+ hashListeningEnabled: true,
+
+ // Set default page transition - 'none' for no transitions
+ defaultPageTransition: "slide",
+
+ // Minimum scroll distance that will be remembered when returning to a page
+ minScrollBack: 250,
+
+ // Set default dialog transition - 'none' for no transitions
+ defaultDialogTransition: "pop",
+
+ // Show loading message during Ajax requests
+ // if false, message will not appear, but loading classes will still be toggled on html el
+ loadingMessage: "loading",
+
+ // Error response message - appears when an Ajax page request fails
+ pageLoadErrorMessage: "Error Loading Page",
+
+ //automatically initialize the DOM when it's ready
+ autoInitializePage: true,
+
+ pushStateEnabled: true,
+
+ // Support conditions that must be met in order to proceed
+ // default enhanced qualifications are media query support OR IE 7+
+ gradeA: function(){
+ return $.support.mediaquery || $.mobile.browser.ie && $.mobile.browser.ie >= 7;
+ },
+
+ // TODO might be useful upstream in jquery itself ?
+ keyCode: {
+ ALT: 18,
+ BACKSPACE: 8,
+ CAPS_LOCK: 20,
+ COMMA: 188,
+ COMMAND: 91,
+ COMMAND_LEFT: 91, // COMMAND
+ COMMAND_RIGHT: 93,
+ CONTROL: 17,
+ DELETE: 46,
+ DOWN: 40,
+ END: 35,
+ ENTER: 13,
+ ESCAPE: 27,
+ HOME: 36,
+ INSERT: 45,
+ LEFT: 37,
+ MENU: 93, // COMMAND_RIGHT
+ NUMPAD_ADD: 107,
+ NUMPAD_DECIMAL: 110,
+ NUMPAD_DIVIDE: 111,
+ NUMPAD_ENTER: 108,
+ NUMPAD_MULTIPLY: 106,
+ NUMPAD_SUBTRACT: 109,
+ PAGE_DOWN: 34,
+ PAGE_UP: 33,
+ PERIOD: 190,
+ RIGHT: 39,
+ SHIFT: 16,
+ SPACE: 32,
+ TAB: 9,
+ UP: 38,
+ WINDOWS: 91 // COMMAND
+ },
+
+ // Scroll page vertically: scroll to 0 to hide iOS address bar, or pass a Y value
+ silentScroll: function( ypos ) {
+ if ( $.type( ypos ) !== "number" ) {
+ ypos = $.mobile.defaultHomeScroll;
+ }
+
+ // prevent scrollstart and scrollstop events
+ $.event.special.scrollstart.enabled = false;
+
+ setTimeout(function() {
+ window.scrollTo( 0, ypos );
+ $( document ).trigger( "silentscroll", { x: 0, y: ypos });
+ }, 20 );
+
+ setTimeout(function() {
+ $.event.special.scrollstart.enabled = true;
+ }, 150 );
+ },
+
+ // Take a data attribute property, prepend the namespace
+ // and then camel case the attribute string
+ nsNormalize: function( prop ) {
+ if ( !prop ) {
+ return;
+ }
+
+ return $.camelCase( $.mobile.ns + prop );
+ }
+ });
+
+ // Mobile version of data and removeData and hasData methods
+ // ensures all data is set and retrieved using jQuery Mobile's data namespace
+ $.fn.jqmData = function( prop, value ) {
+ return this.data( prop ? $.mobile.nsNormalize( prop ) : prop, value );
+ };
+
+ $.jqmData = function( elem, prop, value ) {
+ return $.data( elem, $.mobile.nsNormalize( prop ), value );
+ };
+
+ $.fn.jqmRemoveData = function( prop ) {
+ return this.removeData( $.mobile.nsNormalize( prop ) );
+ };
+
+ $.jqmRemoveData = function( elem, prop ) {
+ return $.removeData( elem, $.mobile.nsNormalize( prop ) );
+ };
+
+ $.jqmHasData = function( elem, prop ) {
+ return $.hasData( elem, $.mobile.nsNormalize( prop ) );
+ };
+
+ // Monkey-patching Sizzle to filter the :jqmData selector
+ var oldFind = $.find;
+
+ $.find = function( selector, context, ret, extra ) {
+ selector = selector.replace(/:jqmData\(([^)]*)\)/g, "[data-" + ( $.mobile.ns || "" ) + "$1]");
+
+ return oldFind.call( this, selector, context, ret, extra );
+ };
+
+ $.extend( $.find, oldFind );
+
+ $.find.matches = function( expr, set ) {
+ return $.find( expr, null, null, set );
+ };
+
+ $.find.matchesSelector = function( node, expr ) {
+ return $.find( expr, null, null, [ node ] ).length > 0;
+ };
+})( jQuery, this );
+
+/*
+* jQuery Mobile Framework : core utilities for auto ajax navigation, base tag mgmt,
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+( function( $, undefined ) {
+
+ //define vars for interal use
+ var $window = $( window ),
+ $html = $( 'html' ),
+ $head = $( 'head' ),
+
+ //url path helpers for use in relative url management
+ path = {
+
+ // This scary looking regular expression parses an absolute URL or its relative
+ // variants (protocol, site, document, query, and hash), into the various
+ // components (protocol, host, path, query, fragment, etc that make up the
+ // URL as well as some other commonly used sub-parts. When used with RegExp.exec()
+ // or String.match, it parses the URL into a results array that looks like this:
+ //
+ // [0]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread#msg-content
+ // [1]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread
+ // [2]: http://jblas:password@mycompany.com:8080/mail/inbox
+ // [3]: http://jblas:password@mycompany.com:8080
+ // [4]: http:
+ // [5]: jblas:password@mycompany.com:8080
+ // [6]: jblas:password
+ // [7]: jblas
+ // [8]: password
+ // [9]: mycompany.com:8080
+ // [10]: mycompany.com
+ // [11]: 8080
+ // [12]: /mail/inbox
+ // [13]: /mail/
+ // [14]: inbox
+ // [15]: ?msg=1234&type=unread
+ // [16]: #msg-content
+ //
+ urlParseRE: /^(((([^:\/#\?]+:)?(?:\/\/((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,
+
+ //Parse a URL into a structure that allows easy access to
+ //all of the URL components by name.
+ parseUrl: function( url ) {
+ // If we're passed an object, we'll assume that it is
+ // a parsed url object and just return it back to the caller.
+ if ( $.type( url ) === "object" ) {
+ return url;
+ }
+
+ var u = url || "",
+ matches = path.urlParseRE.exec( url ),
+ results;
+ if ( matches ) {
+ // Create an object that allows the caller to access the sub-matches
+ // by name. Note that IE returns an empty string instead of undefined,
+ // like all other browsers do, so we normalize everything so its consistent
+ // no matter what browser we're running on.
+ results = {
+ href: matches[0] || "",
+ hrefNoHash: matches[1] || "",
+ hrefNoSearch: matches[2] || "",
+ domain: matches[3] || "",
+ protocol: matches[4] || "",
+ authority: matches[5] || "",
+ username: matches[7] || "",
+ password: matches[8] || "",
+ host: matches[9] || "",
+ hostname: matches[10] || "",
+ port: matches[11] || "",
+ pathname: matches[12] || "",
+ directory: matches[13] || "",
+ filename: matches[14] || "",
+ search: matches[15] || "",
+ hash: matches[16] || ""
+ };
+ }
+ return results || {};
+ },
+
+ //Turn relPath into an asbolute path. absPath is
+ //an optional absolute path which describes what
+ //relPath is relative to.
+ makePathAbsolute: function( relPath, absPath ) {
+ if ( relPath && relPath.charAt( 0 ) === "/" ) {
+ return relPath;
+ }
+
+ relPath = relPath || "";
+ absPath = absPath ? absPath.replace( /^\/|(\/[^\/]*|[^\/]+)$/g, "" ) : "";
+
+ var absStack = absPath ? absPath.split( "/" ) : [],
+ relStack = relPath.split( "/" );
+ for ( var i = 0; i < relStack.length; i++ ) {
+ var d = relStack[ i ];
+ switch ( d ) {
+ case ".":
+ break;
+ case "..":
+ if ( absStack.length ) {
+ absStack.pop();
+ }
+ break;
+ default:
+ absStack.push( d );
+ break;
+ }
+ }
+ return "/" + absStack.join( "/" );
+ },
+
+ //Returns true if both urls have the same domain.
+ isSameDomain: function( absUrl1, absUrl2 ) {
+ return path.parseUrl( absUrl1 ).domain === path.parseUrl( absUrl2 ).domain;
+ },
+
+ //Returns true for any relative variant.
+ isRelativeUrl: function( url ) {
+ // All relative Url variants have one thing in common, no protocol.
+ return path.parseUrl( url ).protocol === "";
+ },
+
+ //Returns true for an absolute url.
+ isAbsoluteUrl: function( url ) {
+ return path.parseUrl( url ).protocol !== "";
+ },
+
+ //Turn the specified realtive URL into an absolute one. This function
+ //can handle all relative variants (protocol, site, document, query, fragment).
+ makeUrlAbsolute: function( relUrl, absUrl ) {
+ if ( !path.isRelativeUrl( relUrl ) ) {
+ return relUrl;
+ }
+
+ var relObj = path.parseUrl( relUrl ),
+ absObj = path.parseUrl( absUrl ),
+ protocol = relObj.protocol || absObj.protocol,
+ authority = relObj.authority || absObj.authority,
+ hasPath = relObj.pathname !== "",
+ pathname = path.makePathAbsolute( relObj.pathname || absObj.filename, absObj.pathname ),
+ search = relObj.search || ( !hasPath && absObj.search ) || "",
+ hash = relObj.hash;
+
+ return protocol + "//" + authority + pathname + search + hash;
+ },
+
+ //Add search (aka query) params to the specified url.
+ addSearchParams: function( url, params ) {
+ var u = path.parseUrl( url ),
+ p = ( typeof params === "object" ) ? $.param( params ) : params,
+ s = u.search || "?";
+ return u.hrefNoSearch + s + ( s.charAt( s.length - 1 ) !== "?" ? "&" : "" ) + p + ( u.hash || "" );
+ },
+
+ convertUrlToDataUrl: function( absUrl ) {
+ var u = path.parseUrl( absUrl );
+ if ( path.isEmbeddedPage( u ) ) {
+ // For embedded pages, remove the dialog hash key as in getFilePath(),
+ // otherwise the Data Url won't match the id of the embedded Page.
+ return u.hash.split( dialogHashKey )[0].replace( /^#/, "" );
+ } else if ( path.isSameDomain( u, documentBase ) ) {
+ return u.hrefNoHash.replace( documentBase.domain, "" );
+ }
+ return absUrl;
+ },
+
+ //get path from current hash, or from a file path
+ get: function( newPath ) {
+ if( newPath === undefined ) {
+ newPath = location.hash;
+ }
+ return path.stripHash( newPath ).replace( /[^\/]*\.[^\/*]+$/, '' );
+ },
+
+ //return the substring of a filepath before the sub-page key, for making a server request
+ getFilePath: function( path ) {
+ var splitkey = '&' + $.mobile.subPageUrlKey;
+ return path && path.split( splitkey )[0].split( dialogHashKey )[0];
+ },
+
+ //set location hash to path
+ set: function( path ) {
+ location.hash = path;
+ },
+
+ //test if a given url (string) is a path
+ //NOTE might be exceptionally naive
+ isPath: function( url ) {
+ return ( /\// ).test( url );
+ },
+
+ //return a url path with the window's location protocol/hostname/pathname removed
+ clean: function( url ) {
+ return url.replace( documentBase.domain, "" );
+ },
+
+ //just return the url without an initial #
+ stripHash: function( url ) {
+ return url.replace( /^#/, "" );
+ },
+
+ //remove the preceding hash, any query params, and dialog notations
+ cleanHash: function( hash ) {
+ return path.stripHash( hash.replace( /\?.*$/, "" ).replace( dialogHashKey, "" ) );
+ },
+
+ //check whether a url is referencing the same domain, or an external domain or different protocol
+ //could be mailto, etc
+ isExternal: function( url ) {
+ var u = path.parseUrl( url );
+ return u.protocol && u.domain !== documentUrl.domain ? true : false;
+ },
+
+ hasProtocol: function( url ) {
+ return ( /^(:?\w+:)/ ).test( url );
+ },
+
+ //check if the specified url refers to the first page in the main application document.
+ isFirstPageUrl: function( url ) {
+ // We only deal with absolute paths.
+ var u = path.parseUrl( path.makeUrlAbsolute( url, documentBase ) ),
+
+ // Does the url have the same path as the document?
+ samePath = u.hrefNoHash === documentUrl.hrefNoHash || ( documentBaseDiffers && u.hrefNoHash === documentBase.hrefNoHash ),
+
+ // Get the first page element.
+ fp = $.mobile.firstPage,
+
+ // Get the id of the first page element if it has one.
+ fpId = fp && fp[0] ? fp[0].id : undefined;
+
+ // The url refers to the first page if the path matches the document and
+ // it either has no hash value, or the hash is exactly equal to the id of the
+ // first page element.
+ return samePath && ( !u.hash || u.hash === "#" || ( fpId && u.hash.replace( /^#/, "" ) === fpId ) );
+ },
+
+ isEmbeddedPage: function( url ) {
+ var u = path.parseUrl( url );
+
+ //if the path is absolute, then we need to compare the url against
+ //both the documentUrl and the documentBase. The main reason for this
+ //is that links embedded within external documents will refer to the
+ //application document, whereas links embedded within the application
+ //document will be resolved against the document base.
+ if ( u.protocol !== "" ) {
+ return ( u.hash && ( u.hrefNoHash === documentUrl.hrefNoHash || ( documentBaseDiffers && u.hrefNoHash === documentBase.hrefNoHash ) ) );
+ }
+ return (/^#/).test( u.href );
+ }
+ },
+
+ //will be defined when a link is clicked and given an active class
+ $activeClickedLink = null,
+
+ //urlHistory is purely here to make guesses at whether the back or forward button was clicked
+ //and provide an appropriate transition
+ urlHistory = {
+ // Array of pages that are visited during a single page load.
+ // Each has a url and optional transition, title, and pageUrl (which represents the file path, in cases where URL is obscured, such as dialogs)
+ stack: [],
+
+ //maintain an index number for the active page in the stack
+ activeIndex: 0,
+
+ //get active
+ getActive: function() {
+ return urlHistory.stack[ urlHistory.activeIndex ];
+ },
+
+ getPrev: function() {
+ return urlHistory.stack[ urlHistory.activeIndex - 1 ];
+ },
+
+ getNext: function() {
+ return urlHistory.stack[ urlHistory.activeIndex + 1 ];
+ },
+
+ // addNew is used whenever a new page is added
+ addNew: function( url, transition, title, pageUrl, role ) {
+ //if there's forward history, wipe it
+ if( urlHistory.getNext() ) {
+ urlHistory.clearForward();
+ }
+
+ urlHistory.stack.push( {url : url, transition: transition, title: title, pageUrl: pageUrl, role: role } );
+
+ urlHistory.activeIndex = urlHistory.stack.length - 1;
+ },
+
+ //wipe urls ahead of active index
+ clearForward: function() {
+ urlHistory.stack = urlHistory.stack.slice( 0, urlHistory.activeIndex + 1 );
+ },
+
+ directHashChange: function( opts ) {
+ var back , forward, newActiveIndex, prev = this.getActive();
+
+ // check if url isp in history and if it's ahead or behind current page
+ $.each( urlHistory.stack, function( i, historyEntry ) {
+
+ //if the url is in the stack, it's a forward or a back
+ if( opts.currentUrl === historyEntry.url ) {
+ //define back and forward by whether url is older or newer than current page
+ back = i < urlHistory.activeIndex;
+ forward = !back;
+ newActiveIndex = i;
+ }
+ });
+
+ // save new page index, null check to prevent falsey 0 result
+ this.activeIndex = newActiveIndex !== undefined ? newActiveIndex : this.activeIndex;
+
+ if( back ) {
+ ( opts.either || opts.isBack )( true );
+ } else if( forward ) {
+ ( opts.either || opts.isForward )( false );
+ }
+ },
+
+ //disable hashchange event listener internally to ignore one change
+ //toggled internally when location.hash is updated to match the url of a successful page load
+ ignoreNextHashChange: false
+ },
+
+ //define first selector to receive focus when a page is shown
+ focusable = "[tabindex],a,button:visible,select:visible,input",
+
+ //queue to hold simultanious page transitions
+ pageTransitionQueue = [],
+
+ //indicates whether or not page is in process of transitioning
+ isPageTransitioning = false,
+
+ //nonsense hash change key for dialogs, so they create a history entry
+ dialogHashKey = "&ui-state=dialog",
+
+ //existing base tag?
+ $base = $head.children( "base" ),
+
+ //tuck away the original document URL minus any fragment.
+ documentUrl = path.parseUrl( location.href ),
+
+ //if the document has an embedded base tag, documentBase is set to its
+ //initial value. If a base tag does not exist, then we default to the documentUrl.
+ documentBase = $base.length ? path.parseUrl( path.makeUrlAbsolute( $base.attr( "href" ), documentUrl.href ) ) : documentUrl,
+
+ //cache the comparison once.
+ documentBaseDiffers = ( documentUrl.hrefNoHash !== documentBase.hrefNoHash );
+
+ //base element management, defined depending on dynamic base tag support
+ var base = $.support.dynamicBaseTag ? {
+
+ //define base element, for use in routing asset urls that are referenced in Ajax-requested markup
+ element: ( $base.length ? $base : $( "<base>", { href: documentBase.hrefNoHash } ).prependTo( $head ) ),
+
+ //set the generated BASE element's href attribute to a new page's base path
+ set: function( href ) {
+ base.element.attr( "href", path.makeUrlAbsolute( href, documentBase ) );
+ },
+
+ //set the generated BASE element's href attribute to a new page's base path
+ reset: function() {
+ base.element.attr( "href", documentBase.hrefNoHash );
+ }
+
+ } : undefined;
+
+/*
+ internal utility functions
+--------------------------------------*/
+
+
+ //direct focus to the page title, or otherwise first focusable element
+ function reFocus( page ) {
+ var pageTitle = page.find( ".ui-title:eq(0)" );
+
+ if( pageTitle.length ) {
+ pageTitle.focus();
+ }
+ else{
+ page.focus();
+ }
+ }
+
+ //remove active classes after page transition or error
+ function removeActiveLinkClass( forceRemoval ) {
+ if( !!$activeClickedLink && ( !$activeClickedLink.closest( '.ui-page-active' ).length || forceRemoval ) ) {
+ $activeClickedLink.removeClass( $.mobile.activeBtnClass );
+ }
+ $activeClickedLink = null;
+ }
+
+ function releasePageTransitionLock() {
+ isPageTransitioning = false;
+ if( pageTransitionQueue.length > 0 ) {
+ $.mobile.changePage.apply( null, pageTransitionQueue.pop() );
+ }
+ }
+
+ // Save the last scroll distance per page, before it is hidden
+ var getLastScroll = (function( lastScrollEnabled ){
+ return function(){
+ if( !lastScrollEnabled ){
+ lastScrollEnabled = true;
+ return;
+ }
+
+ lastScrollEnabled = false;
+
+ var active = $.mobile.urlHistory.getActive(),
+ activePage = $( ".ui-page-active" ),
+ scrollElem = $( window ),
+ touchOverflow = $.support.touchOverflow && $.mobile.touchOverflowEnabled;
+
+ if( touchOverflow ){
+ scrollElem = activePage.is( ".ui-native-fixed" ) ? activePage.find( ".ui-content" ) : activePage;
+ }
+
+ if( active ){
+ var lastScroll = scrollElem.scrollTop();
+
+ // Set active page's lastScroll prop.
+ // If the Y location we're scrolling to is less than minScrollBack, let it go.
+ active.lastScroll = lastScroll < $.mobile.minScrollBack ? $.mobile.defaultHomeScroll : lastScroll;
+ }
+ };
+ })( true );
+
+ // to get last scroll, we need to get scrolltop before the page change
+ // using beforechangepage or popstate/hashchange (whichever comes first)
+ $( document ).bind( "beforechangepage", getLastScroll );
+ $( window ).bind( $.support.pushState ? "popstate" : "hashchange", getLastScroll );
+
+ // Make the iOS clock quick-scroll work again if we're using native overflow scrolling
+ /*
+ if( $.support.touchOverflow ){
+ if( $.mobile.touchOverflowEnabled ){
+ $( window ).bind( "scrollstop", function(){
+ if( $( this ).scrollTop() === 0 ){
+ $.mobile.activePage.scrollTop( 0 );
+ }
+ });
+ }
+ }
+ */
+
+ //function for transitioning between two existing pages
+ function transitionPages( toPage, fromPage, transition, reverse ) {
+
+ //get current scroll distance
+ var active = $.mobile.urlHistory.getActive(),
+ touchOverflow = $.support.touchOverflow && $.mobile.touchOverflowEnabled,
+ toScroll = active.lastScroll || ( touchOverflow ? 0 : $.mobile.defaultHomeScroll ),
+ screenHeight = getScreenHeight();
+
+ // Scroll to top, hide addr bar
+ window.scrollTo( 0, $.mobile.defaultHomeScroll );
+
+ if( fromPage ) {
+ //trigger before show/hide events
+ fromPage.data( "page" )._trigger( "beforehide", null, { nextPage: toPage } );
+ }
+
+ if( !touchOverflow){
+ toPage.height( screenHeight + toScroll );
+ }
+
+ toPage.data( "page" )._trigger( "beforeshow", null, { prevPage: fromPage || $( "" ) } );
+
+ //clear page loader
+ $.mobile.hidePageLoadingMsg();
+
+ if( touchOverflow && toScroll ){
+
+ toPage.addClass( "ui-mobile-pre-transition" );
+ // Send focus to page as it is now display: block
+ reFocus( toPage );
+
+ //set page's scrollTop to remembered distance
+ if( toPage.is( ".ui-native-fixed" ) ){
+ toPage.find( ".ui-content" ).scrollTop( toScroll );
+ }
+ else{
+ toPage.scrollTop( toScroll );
+ }
+ }
+
+ //find the transition handler for the specified transition. If there
+ //isn't one in our transitionHandlers dictionary, use the default one.
+ //call the handler immediately to kick-off the transition.
+ var th = $.mobile.transitionHandlers[transition || "none"] || $.mobile.defaultTransitionHandler,
+ promise = th( transition, reverse, toPage, fromPage );
+
+ promise.done(function() {
+ //reset toPage height back
+ if( !touchOverflow ){
+ toPage.height( "" );
+ // Send focus to the newly shown page
+ reFocus( toPage );
+ }
+
+ // Jump to top or prev scroll, sometimes on iOS the page has not rendered yet.
+ if( !touchOverflow ){
+ $.mobile.silentScroll( toScroll );
+ }
+
+ //trigger show/hide events
+ if( fromPage ) {
+ if( !touchOverflow ){
+ fromPage.height( "" );
+ }
+
+ fromPage.data( "page" )._trigger( "hide", null, { nextPage: toPage } );
+ }
+
+ //trigger pageshow, define prevPage as either fromPage or empty jQuery obj
+ toPage.data( "page" )._trigger( "show", null, { prevPage: fromPage || $( "" ) } );
+ });
+
+ return promise;
+ }
+
+ //simply set the active page's minimum height to screen height, depending on orientation
+ function getScreenHeight(){
+ var orientation = jQuery.event.special.orientationchange.orientation(),
+ port = orientation === "portrait",
+ winMin = port ? 480 : 320,
+ screenHeight = port ? screen.availHeight : screen.availWidth,
+ winHeight = Math.max( winMin, $( window ).height() ),
+ pageMin = Math.min( screenHeight, winHeight );
+
+ return pageMin;
+ }
+
+ $.mobile.getScreenHeight = getScreenHeight;
+
+ //simply set the active page's minimum height to screen height, depending on orientation
+ function resetActivePageHeight(){
+ $( "." + $.mobile.activePageClass ).css( "min-height", getScreenHeight() );
+ }
+
+ //shared page enhancements
+ function enhancePage( $page, role ) {
+ // If a role was specified, make sure the data-role attribute
+ // on the page element is in sync.
+ if( role ) {
+ $page.attr( "data-" + $.mobile.ns + "role", role );
+ }
+
+ //run page plugin
+ $page.page();
+ }
+
+/* exposed $.mobile methods */
+
+ //animation complete callback
+ $.fn.animationComplete = function( callback ) {
+ if( $.support.cssTransitions ) {
+ return $( this ).one( 'webkitAnimationEnd', callback );
+ }
+ else{
+ // defer execution for consistency between webkit/non webkit
+ setTimeout( callback, 0 );
+ return $( this );
+ }
+ };
+
+ //update location.hash, with or without triggering hashchange event
+ //TODO - deprecate this one at 1.0
+ $.mobile.updateHash = path.set;
+
+ //expose path object on $.mobile
+ $.mobile.path = path;
+
+ //expose base object on $.mobile
+ $.mobile.base = base;
+
+ //url stack, useful when plugins need to be aware of previous pages viewed
+ //TODO: deprecate this one at 1.0
+ $.mobile.urlstack = urlHistory.stack;
+
+ //history stack
+ $.mobile.urlHistory = urlHistory;
+
+ $.mobile.dialogHashKey = dialogHashKey;
+
+ //default non-animation transition handler
+ $.mobile.noneTransitionHandler = function( name, reverse, $toPage, $fromPage ) {
+ if ( $fromPage ) {
+ $fromPage.removeClass( $.mobile.activePageClass );
+ }
+ $toPage.addClass( $.mobile.activePageClass );
+
+ return $.Deferred().resolve( name, reverse, $toPage, $fromPage ).promise();
+ };
+
+ //default handler for unknown transitions
+ $.mobile.defaultTransitionHandler = $.mobile.noneTransitionHandler;
+
+ //transition handler dictionary for 3rd party transitions
+ $.mobile.transitionHandlers = {
+ none: $.mobile.defaultTransitionHandler
+ };
+
+ //enable cross-domain page support
+ $.mobile.allowCrossDomainPages = false;
+
+ //return the original document url
+ $.mobile.getDocumentUrl = function(asParsedObject) {
+ return asParsedObject ? $.extend( {}, documentUrl ) : documentUrl.href;
+ };
+
+ //return the original document base url
+ $.mobile.getDocumentBase = function(asParsedObject) {
+ return asParsedObject ? $.extend( {}, documentBase ) : documentBase.href;
+ };
+
+ // Load a page into the DOM.
+ $.mobile.loadPage = function( url, options ) {
+ // This function uses deferred notifications to let callers
+ // know when the page is done loading, or if an error has occurred.
+ var deferred = $.Deferred(),
+
+ // The default loadPage options with overrides specified by
+ // the caller.
+ settings = $.extend( {}, $.mobile.loadPage.defaults, options ),
+
+ // The DOM element for the page after it has been loaded.
+ page = null,
+
+ // If the reloadPage option is true, and the page is already
+ // in the DOM, dupCachedPage will be set to the page element
+ // so that it can be removed after the new version of the
+ // page is loaded off the network.
+ dupCachedPage = null,
+
+ // determine the current base url
+ findBaseWithDefault = function(){
+ var closestBase = ( $.mobile.activePage && getClosestBaseUrl( $.mobile.activePage ) );
+ return closestBase || documentBase.hrefNoHash;
+ },
+
+ // The absolute version of the URL passed into the function. This
+ // version of the URL may contain dialog/subpage params in it.
+ absUrl = path.makeUrlAbsolute( url, findBaseWithDefault() );
+
+
+ // If the caller provided data, and we're using "get" request,
+ // append the data to the URL.
+ if ( settings.data && settings.type === "get" ) {
+ absUrl = path.addSearchParams( absUrl, settings.data );
+ settings.data = undefined;
+ }
+
+ // The absolute version of the URL minus any dialog/subpage params.
+ // In otherwords the real URL of the page to be loaded.
+ var fileUrl = path.getFilePath( absUrl ),
+
+ // The version of the Url actually stored in the data-url attribute of
+ // the page. For embedded pages, it is just the id of the page. For pages
+ // within the same domain as the document base, it is the site relative
+ // path. For cross-domain pages (Phone Gap only) the entire absolute Url
+ // used to load the page.
+ dataUrl = path.convertUrlToDataUrl( absUrl );
+
+ // Make sure we have a pageContainer to work with.
+ settings.pageContainer = settings.pageContainer || $.mobile.pageContainer;
+
+ // Check to see if the page already exists in the DOM.
+ page = settings.pageContainer.children( ":jqmData(url='" + dataUrl + "')" );
+
+ // If we failed to find a page in the DOM, check the URL to see if it
+ // refers to the first page in the application.
+ if ( page.length === 0 && $.mobile.firstPage && path.isFirstPageUrl( absUrl ) ) {
+ page = $( $.mobile.firstPage );
+ }
+
+ // Reset base to the default document base.
+ if ( base ) {
+ base.reset();
+ }
+
+ // If the page we are interested in is already in the DOM,
+ // and the caller did not indicate that we should force a
+ // reload of the file, we are done. Otherwise, track the
+ // existing page as a duplicated.
+ if ( page.length ) {
+ if ( !settings.reloadPage ) {
+ enhancePage( page, settings.role );
+ deferred.resolve( absUrl, options, page );
+ return deferred.promise();
+ }
+ dupCachedPage = page;
+ }
+
+ if ( settings.showLoadMsg ) {
+
+ // This configurable timeout allows cached pages a brief delay to load without showing a message
+ var loadMsgDelay = setTimeout(function(){
+ $.mobile.showPageLoadingMsg();
+ }, settings.loadMsgDelay ),
+
+ // Shared logic for clearing timeout and removing message.
+ hideMsg = function(){
+
+ // Stop message show timer
+ clearTimeout( loadMsgDelay );
+
+ // Hide loading message
+ $.mobile.hidePageLoadingMsg();
+ };
+ }
+
+ if ( !( $.mobile.allowCrossDomainPages || path.isSameDomain( documentUrl, absUrl ) ) ) {
+ deferred.reject( absUrl, options );
+ } else {
+ // Load the new page.
+ $.ajax({
+ url: fileUrl,
+ type: settings.type,
+ data: settings.data,
+ dataType: "html",
+ success: function( html ) {
+ //pre-parse html to check for a data-url,
+ //use it as the new fileUrl, base path, etc
+ var all = $( "<div></div>" ),
+
+ //page title regexp
+ newPageTitle = html.match( /<title[^>]*>([^<]*)/ ) && RegExp.$1,
+
+ // TODO handle dialogs again
+ pageElemRegex = new RegExp( ".*(<[^>]+\\bdata-" + $.mobile.ns + "role=[\"']?page[\"']?[^>]*>).*" ),
+ dataUrlRegex = new RegExp( "\\bdata-" + $.mobile.ns + "url=[\"']?([^\"'>]*)[\"']?" );
+
+
+ // data-url must be provided for the base tag so resource requests can be directed to the
+ // correct url. loading into a temprorary element makes these requests immediately
+ if( pageElemRegex.test( html )
+ && RegExp.$1
+ && dataUrlRegex.test( RegExp.$1 )
+ && RegExp.$1 ) {
+ url = fileUrl = path.getFilePath( RegExp.$1 );
+ }
+ else{
+
+ }
+
+ if ( base ) {
+ base.set( fileUrl );
+ }
+
+ //workaround to allow scripts to execute when included in page divs
+ all.get( 0 ).innerHTML = html;
+ page = all.find( ":jqmData(role='page'), :jqmData(role='dialog')" ).first();
+
+ //if page elem couldn't be found, create one and insert the body element's contents
+ if( !page.length ){
+ page = $( "<div data-" + $.mobile.ns + "role='page'>" + html.split( /<\/?body[^>]*>/gmi )[1] + "</div>" );
+ }
+
+ if ( newPageTitle && !page.jqmData( "title" ) ) {
+ page.jqmData( "title", newPageTitle );
+ }
+
+ //rewrite src and href attrs to use a base url
+ if( !$.support.dynamicBaseTag ) {
+ var newPath = path.get( fileUrl );
+ page.find( "[src], link[href], a[rel='external'], :jqmData(ajax='false'), a[target]" ).each(function() {
+ var thisAttr = $( this ).is( '[href]' ) ? 'href' :
+ $(this).is('[src]') ? 'src' : 'action',
+ thisUrl = $( this ).attr( thisAttr );
+
+ // XXX_jblas: We need to fix this so that it removes the document
+ // base URL, and then prepends with the new page URL.
+ //if full path exists and is same, chop it - helps IE out
+ thisUrl = thisUrl.replace( location.protocol + '//' + location.host + location.pathname, '' );
+
+ if( !/^(\w+:|#|\/)/.test( thisUrl ) ) {
+ $( this ).attr( thisAttr, newPath + thisUrl );
+ }
+ });
+ }
+
+ //append to page and enhance
+ page
+ .attr( "data-" + $.mobile.ns + "url", path.convertUrlToDataUrl( fileUrl ) )
+ .appendTo( settings.pageContainer );
+
+ // wait for page creation to leverage options defined on widget
+ page.one('pagecreate', function(){
+
+ // when dom caching is not enabled bind to remove the page on hide
+ if( !page.data("page").options.domCache ){
+ page.bind( "pagehide.remove", function(){
+ $(this).remove();
+ });
+ }
+ });
+
+ enhancePage( page, settings.role );
+
+ // Enhancing the page may result in new dialogs/sub pages being inserted
+ // into the DOM. If the original absUrl refers to a sub-page, that is the
+ // real page we are interested in.
+ if ( absUrl.indexOf( "&" + $.mobile.subPageUrlKey ) > -1 ) {
+ page = settings.pageContainer.children( ":jqmData(url='" + dataUrl + "')" );
+ }
+
+ //bind pageHide to removePage after it's hidden, if the page options specify to do so
+
+ // Remove loading message.
+ if ( settings.showLoadMsg ) {
+ hideMsg();
+ }
+
+ deferred.resolve( absUrl, options, page, dupCachedPage );
+ },
+ error: function() {
+ //set base back to current path
+ if( base ) {
+ base.set( path.get() );
+ }
+
+ // Remove loading message.
+ if ( settings.showLoadMsg ) {
+
+ // Remove loading message.
+ hideMsg();
+
+ //show error message
+ $( "<div class='ui-loader ui-overlay-shadow ui-body-e ui-corner-all'><h1>"+ $.mobile.pageLoadErrorMessage +"</h1></div>" )
+ .css({ "display": "block", "opacity": 0.96, "top": $window.scrollTop() + 100 })
+ .appendTo( settings.pageContainer )
+ .delay( 800 )
+ .fadeOut( 400, function() {
+ $( this ).remove();
+ });
+ }
+
+ deferred.reject( absUrl, options );
+ }
+ });
+ }
+
+ return deferred.promise();
+ };
+
+ $.mobile.loadPage.defaults = {
+ type: "get",
+ data: undefined,
+ reloadPage: false,
+ role: undefined, // By default we rely on the role defined by the @data-role attribute.
+ showLoadMsg: false,
+ pageContainer: undefined,
+ loadMsgDelay: 50 // This delay allows loads that pull from browser cache to occur without showing the loading message.
+ };
+
+ // Show a specific page in the page container.
+ $.mobile.changePage = function( toPage, options ) {
+ // XXX: REMOVE_BEFORE_SHIPPING_1.0
+ // This is temporary code that makes changePage() compatible with previous alpha versions.
+ if ( typeof options !== "object" ) {
+ var opts = null;
+
+ // Map old-style call signature for form submit to the new options object format.
+ if ( typeof toPage === "object" && toPage.url && toPage.type ) {
+ opts = {
+ type: toPage.type,
+ data: toPage.data,
+ forcePageLoad: true
+ };
+ toPage = toPage.url;
+ }
+
+ // The arguments passed into the function need to be re-mapped
+ // to the new options object format.
+ var len = arguments.length;
+ if ( len > 1 ) {
+ var argNames = [ "transition", "reverse", "changeHash", "fromHashChange" ], i;
+ for ( i = 1; i < len; i++ ) {
+ var a = arguments[ i ];
+ if ( typeof a !== "undefined" ) {
+ opts = opts || {};
+ opts[ argNames[ i - 1 ] ] = a;
+ }
+ }
+ }
+
+ // If an options object was created, then we know changePage() was called
+ // with an old signature.
+ if ( opts ) {
+ return $.mobile.changePage( toPage, opts );
+ }
+ }
+ // XXX: REMOVE_BEFORE_SHIPPING_1.0
+
+ // If we are in the midst of a transition, queue the current request.
+ // We'll call changePage() once we're done with the current transition to
+ // service the request.
+ if( isPageTransitioning ) {
+ pageTransitionQueue.unshift( arguments );
+ return;
+ }
+
+ var settings = $.extend( {}, $.mobile.changePage.defaults, options );
+
+ // Make sure we have a pageContainer to work with.
+ settings.pageContainer = settings.pageContainer || $.mobile.pageContainer;
+
+ // Make sure we have a fromPage.
+ settings.fromPage = settings.fromPage || $.mobile.activePage;
+
+ var mpc = settings.pageContainer,
+ pbcEvent = new $.Event( "pagebeforechange" ),
+ triggerData = { toPage: toPage, options: settings };
+
+ // Let listeners know we're about to change the current page.
+ mpc.trigger( pbcEvent, triggerData );
+
+ mpc.trigger( "beforechangepage", triggerData ); // XXX: DEPRECATED for 1.0
+
+ // If the default behavior is prevented, stop here!
+ if( pbcEvent.isDefaultPrevented() ){
+ return;
+ }
+
+ // We allow "pagebeforechange" observers to modify the toPage in the trigger
+ // data to allow for redirects. Make sure our toPage is updated.
+
+ toPage = triggerData.toPage;
+
+ // Set the isPageTransitioning flag to prevent any requests from
+ // entering this method while we are in the midst of loading a page
+ // or transitioning.
+
+ isPageTransitioning = true;
+
+ // If the caller passed us a url, call loadPage()
+ // to make sure it is loaded into the DOM. We'll listen
+ // to the promise object it returns so we know when
+ // it is done loading or if an error ocurred.
+ if ( typeof toPage == "string" ) {
+ $.mobile.loadPage( toPage, settings )
+ .done(function( url, options, newPage, dupCachedPage ) {
+ isPageTransitioning = false;
+ options.duplicateCachedPage = dupCachedPage;
+ $.mobile.changePage( newPage, options );
+ })
+ .fail(function( url, options ) {
+ // XXX_jblas: Fire off changepagefailed notificaiton.
+ isPageTransitioning = false;
+
+ //clear out the active button state
+ removeActiveLinkClass( true );
+
+ //release transition lock so navigation is free again
+ releasePageTransitionLock();
+ settings.pageContainer.trigger( "pagechangefailed", triggerData );
+ settings.pageContainer.trigger( "changepagefailed", triggerData ); // XXX: DEPRECATED for 1.0
+ });
+ return;
+ }
+
+ // The caller passed us a real page DOM element. Update our
+ // internal state and then trigger a transition to the page.
+ var fromPage = settings.fromPage,
+ url = ( settings.dataUrl && path.convertUrlToDataUrl( settings.dataUrl ) ) || toPage.jqmData( "url" ),
+ // The pageUrl var is usually the same as url, except when url is obscured as a dialog url. pageUrl always contains the file path
+ pageUrl = url,
+ fileUrl = path.getFilePath( url ),
+ active = urlHistory.getActive(),
+ activeIsInitialPage = urlHistory.activeIndex === 0,
+ historyDir = 0,
+ pageTitle = document.title,
+ isDialog = settings.role === "dialog" || toPage.jqmData( "role" ) === "dialog";
+
+ // If we are trying to transition to the same page that we are currently on ignore the request.
+ // an illegal same page request is defined by the current page being the same as the url, as long as there's history
+ // and toPage is not an array or object (those are allowed to be "same")
+ //
+ // XXX_jblas: We need to remove this at some point when we allow for transitions
+ // to the same page.
+ if( fromPage && fromPage[0] === toPage[0] ) {
+ isPageTransitioning = false;
+ mpc.trigger( "pagechange", triggerData );
+ mpc.trigger( "changepage", triggerData ); // XXX: DEPRECATED for 1.0
+ return;
+ }
+
+ // We need to make sure the page we are given has already been enhanced.
+ enhancePage( toPage, settings.role );
+
+ // If the changePage request was sent from a hashChange event, check to see if the
+ // page is already within the urlHistory stack. If so, we'll assume the user hit
+ // the forward/back button and will try to match the transition accordingly.
+ if( settings.fromHashChange ) {
+ urlHistory.directHashChange({
+ currentUrl: url,
+ isBack: function() { historyDir = -1; },
+ isForward: function() { historyDir = 1; }
+ });
+ }
+
+ // Kill the keyboard.
+ // XXX_jblas: We need to stop crawling the entire document to kill focus. Instead,
+ // we should be tracking focus with a live() handler so we already have
+ // the element in hand at this point.
+ // Wrap this in a try/catch block since IE9 throw "Unspecified error" if document.activeElement
+ // is undefined when we are in an IFrame.
+ try {
+ $( document.activeElement || "" ).add( "input:focus, textarea:focus, select:focus" ).blur();
+ } catch(e) {}
+
+ // If we're displaying the page as a dialog, we don't want the url
+ // for the dialog content to be used in the hash. Instead, we want
+ // to append the dialogHashKey to the url of the current page.
+ if ( isDialog && active ) {
+ // on the initial page load active.url is undefined and in that case should
+ // be an empty string. Moving the undefined -> empty string back into
+ // urlHistory.addNew seemed imprudent given undefined better represents
+ // the url state
+ url = ( active.url || "" ) + dialogHashKey;
+ }
+
+ // Set the location hash.
+ if( settings.changeHash !== false && url ) {
+ //disable hash listening temporarily
+ urlHistory.ignoreNextHashChange = true;
+ //update hash and history
+ path.set( url );
+ }
+
+ //if title element wasn't found, try the page div data attr too
+ var newPageTitle = toPage.jqmData( "title" ) || toPage.children(":jqmData(role='header')").find(".ui-title" ).text();
+ if( !!newPageTitle && pageTitle == document.title ) {
+ pageTitle = newPageTitle;
+ }
+
+ //add page to history stack if it's not back or forward
+ if( !historyDir ) {
+ urlHistory.addNew( url, settings.transition, pageTitle, pageUrl, settings.role );
+ }
+
+ //set page title
+ document.title = urlHistory.getActive().title;
+
+ //set "toPage" as activePage
+ $.mobile.activePage = toPage;
+
+ // Make sure we have a transition defined.
+ settings.transition = settings.transition
+ || ( ( historyDir && !activeIsInitialPage ) ? active.transition : undefined )
+ || ( isDialog ? $.mobile.defaultDialogTransition : $.mobile.defaultPageTransition );
+
+ // If we're navigating back in the URL history, set reverse accordingly.
+ settings.reverse = settings.reverse || historyDir < 0;
+
+ transitionPages( toPage, fromPage, settings.transition, settings.reverse )
+ .done(function() {
+ removeActiveLinkClass();
+
+ //if there's a duplicateCachedPage, remove it from the DOM now that it's hidden
+ if ( settings.duplicateCachedPage ) {
+ settings.duplicateCachedPage.remove();
+ }
+
+ //remove initial build class (only present on first pageshow)
+ $html.removeClass( "ui-mobile-rendering" );
+
+ releasePageTransitionLock();
+
+ // Let listeners know we're all done changing the current page.
+ mpc.trigger( "pagechange", triggerData );
+
+ mpc.trigger( "changepage", triggerData ); // XXX: DEPRECATED for 1.0
+ });
+ };
+
+ $.mobile.changePage.defaults = {
+ transition: undefined,
+ reverse: false,
+ changeHash: true,
+ fromHashChange: false,
+ role: undefined, // By default we rely on the role defined by the @data-role attribute.
+ duplicateCachedPage: undefined,
+ pageContainer: undefined,
+ showLoadMsg: true, //loading message shows by default when pages are being fetched during changePage
+ dataUrl: undefined,
+ fromPage: undefined
+ };
+
+/* Event Bindings - hashchange, submit, and click */
+ function findClosestLink( ele )
+ {
+ while ( ele ) {
+ if ( ele.nodeName.toLowerCase() == "a" ) {
+ break;
+ }
+ ele = ele.parentNode;
+ }
+ return ele;
+ }
+
+ // The base URL for any given element depends on the page it resides in.
+ function getClosestBaseUrl( ele )
+ {
+ // Find the closest page and extract out its url.
+ var url = $( ele ).closest( ".ui-page" ).jqmData( "url" ),
+ base = documentBase.hrefNoHash;
+
+ if ( !url || !path.isPath( url ) ) {
+ url = base;
+ }
+
+ return path.makeUrlAbsolute( url, base);
+ }
+
+
+ //The following event bindings should be bound after mobileinit has been triggered
+ //the following function is called in the init file
+ $.mobile._registerInternalEvents = function(){
+
+ //bind to form submit events, handle with Ajax
+ $( "form" ).live('submit', function( event ) {
+ var $this = $( this );
+ if( !$.mobile.ajaxEnabled ||
+ $this.is( ":jqmData(ajax='false')" ) ) {
+ return;
+ }
+
+ var type = $this.attr( "method" ),
+ target = $this.attr( "target" ),
+ url = $this.attr( "action" );
+
+ // If no action is specified, browsers default to using the
+ // URL of the document containing the form. Since we dynamically
+ // pull in pages from external documents, the form should submit
+ // to the URL for the source document of the page containing
+ // the form.
+ if ( !url ) {
+ // Get the @data-url for the page containing the form.
+ url = getClosestBaseUrl( $this );
+ if ( url === documentBase.hrefNoHash ) {
+ // The url we got back matches the document base,
+ // which means the page must be an internal/embedded page,
+ // so default to using the actual document url as a browser
+ // would.
+ url = documentUrl.hrefNoSearch;
+ }
+ }
+
+ url = path.makeUrlAbsolute( url, getClosestBaseUrl($this) );
+
+ //external submits use regular HTTP
+ if( path.isExternal( url ) || target ) {
+ return;
+ }
+
+ $.mobile.changePage(
+ url,
+ {
+ type: type && type.length && type.toLowerCase() || "get",
+ data: $this.serialize(),
+ transition: $this.jqmData( "transition" ),
+ direction: $this.jqmData( "direction" ),
+ reloadPage: true
+ }
+ );
+ event.preventDefault();
+ });
+
+ //add active state on vclick
+ $( document ).bind( "vclick", function( event ) {
+ var link = findClosestLink( event.target );
+ if ( link ) {
+ if ( path.parseUrl( link.getAttribute( "href" ) || "#" ).hash !== "#" ) {
+ removeActiveLinkClass( true );
+ $activeClickedLink = $( link ).closest( ".ui-btn" ).not( ".ui-disabled" );
+ $activeClickedLink.addClass( $.mobile.activeBtnClass );
+ $( "." + $.mobile.activePageClass + " .ui-btn" ).not( link ).blur();
+ }
+ }
+ });
+
+ // click routing - direct to HTTP or Ajax, accordingly
+ $( document ).bind( "click", function( event ) {
+ var link = findClosestLink( event.target );
+ if ( !link ) {
+ return;
+ }
+
+ var $link = $( link ),
+ //remove active link class if external (then it won't be there if you come back)
+ httpCleanup = function(){
+ window.setTimeout( function() { removeActiveLinkClass( true ); }, 200 );
+ };
+
+ //if there's a data-rel=back attr, go back in history
+ if( $link.is( ":jqmData(rel='back')" ) ) {
+ window.history.back();
+ return false;
+ }
+
+ //if ajax is disabled, exit early
+ if( !$.mobile.ajaxEnabled ){
+ httpCleanup();
+ //use default click handling
+ return;
+ }
+
+ var baseUrl = getClosestBaseUrl( $link ),
+
+ //get href, if defined, otherwise default to empty hash
+ href = path.makeUrlAbsolute( $link.attr( "href" ) || "#", baseUrl );
+
+ // XXX_jblas: Ideally links to application pages should be specified as
+ // an url to the application document with a hash that is either
+ // the site relative path or id to the page. But some of the
+ // internal code that dynamically generates sub-pages for nested
+ // lists and select dialogs, just write a hash in the link they
+ // create. This means the actual URL path is based on whatever
+ // the current value of the base tag is at the time this code
+ // is called. For now we are just assuming that any url with a
+ // hash in it is an application page reference.
+ if ( href.search( "#" ) != -1 ) {
+ href = href.replace( /[^#]*#/, "" );
+ if ( !href ) {
+ //link was an empty hash meant purely
+ //for interaction, so we ignore it.
+ event.preventDefault();
+ return;
+ } else if ( path.isPath( href ) ) {
+ //we have apath so make it the href we want to load.
+ href = path.makeUrlAbsolute( href, baseUrl );
+ } else {
+ //we have a simple id so use the documentUrl as its base.
+ href = path.makeUrlAbsolute( "#" + href, documentUrl.hrefNoHash );
+ }
+ }
+
+ // Should we handle this link, or let the browser deal with it?
+ var useDefaultUrlHandling = $link.is( "[rel='external']" ) || $link.is( ":jqmData(ajax='false')" ) || $link.is( "[target]" ),
+
+ // Some embedded browsers, like the web view in Phone Gap, allow cross-domain XHR
+ // requests if the document doing the request was loaded via the file:// protocol.
+ // This is usually to allow the application to "phone home" and fetch app specific
+ // data. We normally let the browser handle external/cross-domain urls, but if the
+ // allowCrossDomainPages option is true, we will allow cross-domain http/https
+ // requests to go through our page loading logic.
+ isCrossDomainPageLoad = ( $.mobile.allowCrossDomainPages && documentUrl.protocol === "file:" && href.search( /^https?:/ ) != -1 ),
+
+ //check for protocol or rel and its not an embedded page
+ //TODO overlap in logic from isExternal, rel=external check should be
+ // moved into more comprehensive isExternalLink
+ isExternal = useDefaultUrlHandling || ( path.isExternal( href ) && !isCrossDomainPageLoad );
+
+ if( isExternal ) {
+ httpCleanup();
+ //use default click handling
+ return;
+ }
+
+ //use ajax
+ var transition = $link.jqmData( "transition" ),
+ direction = $link.jqmData( "direction" ),
+ reverse = ( direction && direction === "reverse" ) ||
+ // deprecated - remove by 1.0
+ $link.jqmData( "back" ),
+
+ //this may need to be more specific as we use data-rel more
+ role = $link.attr( "data-" + $.mobile.ns + "rel" ) || undefined;
+
+ $.mobile.changePage( href, { transition: transition, reverse: reverse, role: role } );
+ event.preventDefault();
+ });
+
+ //prefetch pages when anchors with data-prefetch are encountered
+ $( ".ui-page" ).live( "pageshow.prefetch", function(){
+ var urls = [];
+ $( this ).find( "a:jqmData(prefetch)" ).each(function(){
+ var url = $( this ).attr( "href" );
+ if ( url && $.inArray( url, urls ) === -1 ) {
+ urls.push( url );
+ $.mobile.loadPage( url );
+ }
+ });
+ } );
+
+ $.mobile._handleHashChange = function( hash ) {
+ //find first page via hash
+ var to = path.stripHash( hash ),
+ //transition is false if it's the first page, undefined otherwise (and may be overridden by default)
+ transition = $.mobile.urlHistory.stack.length === 0 ? "none" : undefined,
+
+ // default options for the changPage calls made after examining the current state
+ // of the page and the hash
+ changePageOptions = {
+ transition: transition,
+ changeHash: false,
+ fromHashChange: true
+ };
+
+ //if listening is disabled (either globally or temporarily), or it's a dialog hash
+ if( !$.mobile.hashListeningEnabled || urlHistory.ignoreNextHashChange ) {
+ urlHistory.ignoreNextHashChange = false;
+ return;
+ }
+
+ // special case for dialogs
+ if( urlHistory.stack.length > 1 && to.indexOf( dialogHashKey ) > -1 ) {
+
+ // If current active page is not a dialog skip the dialog and continue
+ // in the same direction
+ if(!$.mobile.activePage.is( ".ui-dialog" )) {
+ //determine if we're heading forward or backward and continue accordingly past
+ //the current dialog
+ urlHistory.directHashChange({
+ currentUrl: to,
+ isBack: function() { window.history.back(); },
+ isForward: function() { window.history.forward(); }
+ });
+
+ // prevent changepage
+ return;
+ } else {
+ // if the current active page is a dialog and we're navigating
+ // to a dialog use the dialog objected saved in the stack
+ urlHistory.directHashChange({
+ currentUrl: to,
+
+ // regardless of the direction of the history change
+ // do the following
+ either: function( isBack ) {
+ var active = $.mobile.urlHistory.getActive();
+
+ to = active.pageUrl;
+
+ // make sure to set the role, transition and reversal
+ // as most of this is lost by the domCache cleaning
+ $.extend( changePageOptions, {
+ role: active.role,
+ transition: active.transition,
+ reverse: isBack
+ });
+ }
+ });
+ }
+ }
+
+ //if to is defined, load it
+ if ( to ) {
+ to = ( typeof to === "string" && !path.isPath( to ) ) ? ( '#' + to ) : to;
+ $.mobile.changePage( to, changePageOptions );
+ } else {
+ //there's no hash, go to the first page in the dom
+ $.mobile.changePage( $.mobile.firstPage, changePageOptions );
+ }
+ };
+
+ //hashchange event handler
+ $window.bind( "hashchange", function( e, triggered ) {
+ $.mobile._handleHashChange( location.hash );
+ });
+
+ //set page min-heights to be device specific
+ $( document ).bind( "pageshow", resetActivePageHeight );
+ $( window ).bind( "throttledresize", resetActivePageHeight );
+
+ };//_registerInternalEvents callback
+
+})( jQuery );
+/*
+* jQuery Mobile Framework : history.pushState support, layered on top of hashchange
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+( function( $, window ) {
+ // For now, let's Monkeypatch this onto the end of $.mobile._registerInternalEvents
+ // Scope self to pushStateHandler so we can reference it sanely within the
+ // methods handed off as event handlers
+ var pushStateHandler = {},
+ self = pushStateHandler,
+ $win = $( window ),
+ url = $.mobile.path.parseUrl( location.href );
+
+ $.extend( pushStateHandler, {
+ // TODO move to a path helper, this is rather common functionality
+ initialFilePath: (function() {
+ return url.pathname + url.search;
+ })(),
+
+ initialHref: url.hrefNoHash,
+
+ // Flag for tracking if a Hashchange naturally occurs after each popstate + replace
+ hashchangeFired: false,
+
+ state: function() {
+ return {
+ hash: location.hash || "#" + self.initialFilePath,
+ title: document.title,
+
+ // persist across refresh
+ initialHref: self.initialHref
+ };
+ },
+
+ resetUIKeys: function( url ) {
+ var dialog = $.mobile.dialogHashKey,
+ subkey = "&" + $.mobile.subPageUrlKey,
+ dialogIndex = url.indexOf( dialog );
+
+ if( dialogIndex > -1 ) {
+ url = url.slice( 0, dialogIndex ) + "#" + url.slice( dialogIndex );
+ } else if( url.indexOf( subkey ) > -1 ) {
+ url = url.split( subkey ).join( "#" + subkey );
+ }
+
+ return url;
+ },
+
+ // on hash change we want to clean up the url
+ // NOTE this takes place *after* the vanilla navigation hash change
+ // handling has taken place and set the state of the DOM
+ onHashChange: function( e ) {
+ var href, state;
+
+ self.hashchangeFired = true;
+
+ // only replaceState when the hash doesn't represent an embeded page
+ if( $.mobile.path.isPath(location.hash) ) {
+
+ // propulate the hash when its not available
+ state = self.state();
+
+ // make the hash abolute with the current href
+ href = $.mobile.path.makeUrlAbsolute( state.hash.replace("#", ""), location.href );
+
+ href = self.resetUIKeys( href );
+
+ // replace the current url with the new href and store the state
+ history.replaceState( state, document.title, href );
+ }
+ },
+
+ // on popstate (ie back or forward) we need to replace the hash that was there previously
+ // cleaned up by the additional hash handling
+ onPopState: function( e ) {
+ var poppedState = e.originalEvent.state, holdnexthashchange = false;
+
+ // if there's no state its not a popstate we care about, ie chrome's initial popstate
+ // or forward popstate
+ if( poppedState ) {
+ // disable any hashchange triggered by the browser
+ $.mobile.urlHistory.ignoreNextHashChange = true;
+
+ // defer our manual hashchange until after the browser fired
+ // version has come and gone
+ setTimeout(function() {
+ // make sure that the manual hash handling takes place
+ $.mobile.urlHistory.ignoreNextHashChange = false;
+
+ // change the page based on the hash
+ $.mobile._handleHashChange( poppedState.hash );
+ }, 100);
+ }
+ },
+
+ init: function() {
+ $win.bind( "hashchange", self.onHashChange );
+
+ // Handle popstate events the occur through history changes
+ $win.bind( "popstate", self.onPopState );
+
+ // if there's no hash, we need to replacestate for returning to home
+ if ( location.hash === "" ) {
+ history.replaceState( self.state(), document.title, location.href );
+ }
+ }
+ });
+
+ $( function() {
+ if( $.mobile.pushStateEnabled && $.support.pushState ){
+ pushStateHandler.init();
+ }
+ });
+})( jQuery, this );/*!
+ * jQuery Mobile v@VERSION
+ * http://jquerymobile.com/
+ *
+ * Copyright 2010, jQuery Project
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ */
+
+(function( $, window, undefined ) {
+
+function css3TransitionHandler( name, reverse, $to, $from ) {
+
+ var deferred = new $.Deferred(),
+ reverseClass = reverse ? " reverse" : "",
+ viewportClass = "ui-mobile-viewport-transitioning viewport-" + name,
+ doneFunc = function() {
+
+ $to.add( $from ).removeClass( "out in reverse " + name );
+
+ if ( $from ) {
+ $from.removeClass( $.mobile.activePageClass );
+ }
+
+ $to.parent().removeClass( viewportClass );
+
+ deferred.resolve( name, reverse, $to, $from );
+ };
+
+ $to.animationComplete( doneFunc );
+
+ $to.parent().addClass( viewportClass );
+
+ if ( $from ) {
+ $from.addClass( name + " out" + reverseClass );
+ }
+ $to.addClass( $.mobile.activePageClass + " " + name + " in" + reverseClass );
+
+ return deferred.promise();
+}
+
+// Make our transition handler public.
+$.mobile.css3TransitionHandler = css3TransitionHandler;
+
+// If the default transition handler is the 'none' handler, replace it with our handler.
+if ( $.mobile.defaultTransitionHandler === $.mobile.noneTransitionHandler ) {
+ $.mobile.defaultTransitionHandler = css3TransitionHandler;
+}
+
+})( jQuery, this );
+/*
+* jQuery Mobile Framework : "degradeInputs" plugin - degrades inputs to another type after custom enhancements are made.
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+(function( $, undefined ) {
+
+$.mobile.page.prototype.options.degradeInputs = {
+ color: false,
+ date: false,
+ datetime: false,
+ "datetime-local": false,
+ email: false,
+ month: false,
+ number: false,
+ range: "number",
+ search: "text",
+ tel: false,
+ time: false,
+ url: false,
+ week: false
+};
+
+$.mobile.page.prototype.options.keepNative = ":jqmData(role='none'), :jqmData(role='nojs')";
+
+
+//auto self-init widgets
+$( document ).bind( "pagecreate enhance", function( e ){
+
+ var page = $( e.target ).data( "page" ),
+ o = page.options;
+
+ // degrade inputs to avoid poorly implemented native functionality
+ $( e.target ).find( "input" ).not( o.keepNative ).each(function() {
+ var $this = $( this ),
+ type = this.getAttribute( "type" ),
+ optType = o.degradeInputs[ type ] || "text";
+
+ if ( o.degradeInputs[ type ] ) {
+ $this.replaceWith(
+ $( "<div>" ).html( $this.clone() ).html()
+ .replace( /\s+type=["']?\w+['"]?/, " type=\"" + optType + "\" data-" + $.mobile.ns + "type=\"" + type + "\" " )
+ );
+ }
+ });
+
+});
+
+})( jQuery );/*
+* jQuery Mobile Framework : "dialog" plugin.
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
+*/
+
+(function( $, window, undefined ) {
+
+$.widget( "mobile.dialog", $.mobile.widget, {
+ options: {
+ closeBtnText : "Close",
+ theme : "a",
+ initSelector : ":jqmData(role='dialog')"
+ },
+ _create: function() {
+ var $el = this.element,
+ pageTheme = $el.attr( "class" ).match( /ui-body-[a-z]/ );
+
+ if( pageTheme.length ){
+ $el.removeClass( pageTheme[ 0 ] );
+ }
+
+ $el.addClass( "ui-body-" + this.options.theme );
+
+ // Class the markup for dialog styling
+ // Set aria role
+ $el.attr( "role", "dialog" )
+ .addClass( "ui-dialog" )
+ .find( ":jqmData(role='header')" )
+ .addClass( "ui-corner-top ui-overlay-shadow" )
+ .prepend( "<a href='#' data-" + $.mobile.ns + "icon='delete' data-" + $.mobile.ns + "rel='back' data-" + $.mobile.ns + "iconpos='notext'>"+ this.options.closeBtnText + "</a>" )
+ .end()
+ .find( ":jqmData(role='content'),:jqmData(role='footer')" )
+ .last()
+ .addClass( "ui-corner-bottom ui-overlay-shadow" );
+
+ /* bind events
+ - clicks and submits should use the closing transition that the dialog opened with
+ unless a data-transition is specified on the link/form
+ - if the click was on the close button, or the link has a data-rel="back" it'll go back in history naturally
+ */
+ $el.bind( "vclick submit", function( event ) {
+ var $target = $( event.target ).closest( event.type === "vclick" ? "a" : "form" ),
+ active;
+
+ if ( $target.length && !$target.jqmData( "transition" ) ) {
+
+ active = $.mobile.urlHistory.getActive() || {};
+
+ $target.attr( "data-" + $.mobile.ns + "transition", ( active.transition || $.mobile.defaultDialogTransition ) )
+ .attr( "data-" + $.mobile.ns + "direction", "reverse" );
+ }
+ })
+ .bind( "pagehide", function() {
+ $( this ).find( "." + $.mobile.activeBtnClass ).removeClass( $.mobile.activeBtnClass );
+ });
+ },
+
+ // Close method goes back in history
+ close: function() {
+ window.history.back();
+ }
+});
+
+//auto self-init widgets
+$( $.mobile.dialog.prototype.options.initSelector ).live( "pagecreate", function(){
+ $( this ).dialog();
+});
+
+})( jQuery, this );
+/*
+* jQuery Mobile Framework : This plugin handles theming and layout of headers, footers, and content areas
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+(function( $, undefined ) {
+
+$.mobile.page.prototype.options.backBtnText = "Back";
+$.mobile.page.prototype.options.addBackBtn = false;
+$.mobile.page.prototype.options.backBtnTheme = null;
+$.mobile.page.prototype.options.headerTheme = "a";
+$.mobile.page.prototype.options.footerTheme = "a";
+$.mobile.page.prototype.options.contentTheme = null;
+
+$( ":jqmData(role='page'), :jqmData(role='dialog')" ).live( "pagecreate", function( e ) {
+
+ var $page = $( this ),
+ o = $page.data( "page" ).options,
+ pageTheme = o.theme;
+
+ $( ":jqmData(role='header'), :jqmData(role='footer'), :jqmData(role='content')", this ).each(function() {
+ var $this = $( this ),
+ role = $this.jqmData( "role" ),
+ theme = $this.jqmData( "theme" ),
+ $headeranchors,
+ leftbtn,
+ rightbtn,
+ backBtn;
+
+ $this.addClass( "ui-" + role );
+
+ //apply theming and markup modifications to page,header,content,footer
+ if ( role === "header" || role === "footer" ) {
+
+ var thisTheme = theme || ( role === "header" ? o.headerTheme : o.footerTheme ) || pageTheme;
+
+ //add theme class
+ $this.addClass( "ui-bar-" + thisTheme );
+
+ // Add ARIA role
+ $this.attr( "role", role === "header" ? "banner" : "contentinfo" );
+
+ // Right,left buttons
+ $headeranchors = $this.children( "a" );
+ leftbtn = $headeranchors.hasClass( "ui-btn-left" );
+ rightbtn = $headeranchors.hasClass( "ui-btn-right" );
+
+ if ( !leftbtn ) {
+ leftbtn = $headeranchors.eq( 0 ).not( ".ui-btn-right" ).addClass( "ui-btn-left" ).length;
+ }
+
+ if ( !rightbtn ) {
+ rightbtn = $headeranchors.eq( 1 ).addClass( "ui-btn-right" ).length;
+ }
+
+ // Auto-add back btn on pages beyond first view
+ if ( o.addBackBtn && role === "header" &&
+ $( ".ui-page" ).length > 1 &&
+ $this.jqmData( "url" ) !== $.mobile.path.stripHash( location.hash ) &&
+ !leftbtn ) {
+
+ backBtn = $( "<a href='#' class='ui-btn-left' data-"+ $.mobile.ns +"rel='back' data-"+ $.mobile.ns +"icon='arrow-l'>"+ o.backBtnText +"</a>" ).prependTo( $this );
+
+ // If theme is provided, override default inheritance
+ backBtn.attr( "data-"+ $.mobile.ns +"theme", o.backBtnTheme || thisTheme );
+ }
+
+ // Page title
+ $this.children( "h1, h2, h3, h4, h5, h6" )
+ .addClass( "ui-title" )
+ // Regardless of h element number in src, it becomes h1 for the enhanced page
+ .attr({
+ "tabindex": "0",
+ "role": "heading",
+ "aria-level": "1"
+ });
+
+ } else if ( role === "content" ) {
+
+ if (theme || o.contentTheme) {
+ $this.addClass( "ui-body-" + ( theme || o.contentTheme ) );
+ }
+
+ // Add ARIA role
+ $this.attr( "role", "main" );
+
+ }
+ });
+});
+
+})( jQuery );/*
+* jQuery Mobile Framework : "collapsible" plugin
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function( $, undefined ) {
+
+$.widget( "mobile.collapsible", $.mobile.widget, {
+ options: {
+ expandCueText: " click to expand contents",
+ collapseCueText: " click to collapse contents",
+ collapsed: true,
+ heading: ">:header,>legend",
+ theme: null,
+ iconTheme: "d",
+ initSelector: ":jqmData(role='collapsible')"
+ },
+ _create: function() {
+
+ var $el = this.element,
+ o = this.options,
+ collapsibleContain = $el.addClass( "ui-collapsible-contain" ),
+ collapsibleHeading = $el.find( o.heading ).eq( 0 ),
+ collapsibleContent = collapsibleContain.wrapInner( "<div class='ui-collapsible-content'></div>" ).find( ".ui-collapsible-content" ),
+ collapsibleParent = $el.closest( ":jqmData(role='collapsible-set')" ).addClass( "ui-collapsible-set" );
+
+ // Replace collapsibleHeading if it's a legend
+ if ( collapsibleHeading.is( "legend" ) ) {
+ collapsibleHeading = $( "<div role='heading'>"+ collapsibleHeading.html() +"</div>" ).insertBefore( collapsibleHeading );
+ collapsibleHeading.next().remove();
+ }
+
+ collapsibleHeading
+ //drop heading in before content
+ .insertBefore( collapsibleContent )
+ //modify markup & attributes
+ .addClass( "ui-collapsible-heading" )
+ .append( "<span class='ui-collapsible-heading-status'></span>" )
+ .wrapInner( "<a href='#' class='ui-collapsible-heading-toggle'></a>" )
+ .find( "a:eq(0)" )
+ .buttonMarkup({
+ shadow: !collapsibleParent.length,
+ corners: false,
+ iconPos: "left",
+ icon: "plus",
+ theme: o.theme
+ })
+ .find( ".ui-icon" )
+ .removeAttr( "class" )
+ .buttonMarkup({
+ shadow: true,
+ corners: true,
+ iconPos: "notext",
+ icon: "plus",
+ theme: o.iconTheme
+ });
+
+ if ( !collapsibleParent.length ) {
+ collapsibleHeading
+ .find( "a:eq(0)" )
+ .addClass( "ui-corner-all" )
+ .find( ".ui-btn-inner" )
+ .addClass( "ui-corner-all" );
+ } else {
+ if ( collapsibleContain.jqmData( "collapsible-last" ) ) {
+ collapsibleHeading
+ .find( "a:eq(0), .ui-btn-inner" )
+ .addClass( "ui-corner-bottom" );
+ }
+ }
+
+ //events
+ collapsibleContain
+ .bind( "collapse", function( event ) {
+ if ( ! event.isDefaultPrevented() &&
+ $( event.target ).closest( ".ui-collapsible-contain" ).is( collapsibleContain ) ) {
+
+ event.preventDefault();
+
+ collapsibleHeading
+ .addClass( "ui-collapsible-heading-collapsed" )
+ .find( ".ui-collapsible-heading-status" )
+ .text( o.expandCueText )
+ .end()
+ .find( ".ui-icon" )
+ .removeClass( "ui-icon-minus" )
+ .addClass( "ui-icon-plus" );
+
+ collapsibleContent.addClass( "ui-collapsible-content-collapsed" ).attr( "aria-hidden", true );
+
+ if ( collapsibleContain.jqmData( "collapsible-last" ) ) {
+ collapsibleHeading
+ .find( "a:eq(0), .ui-btn-inner" )
+ .addClass( "ui-corner-bottom" );
+ }
+ }
+ })
+ .bind( "expand", function( event ) {
+ if ( !event.isDefaultPrevented() ) {
+
+ event.preventDefault();
+
+ collapsibleHeading
+ .removeClass( "ui-collapsible-heading-collapsed" )
+ .find( ".ui-collapsible-heading-status" ).text( o.collapseCueText );
+
+ collapsibleHeading.find( ".ui-icon" ).removeClass( "ui-icon-plus" ).addClass( "ui-icon-minus" );
+
+ collapsibleContent.removeClass( "ui-collapsible-content-collapsed" ).attr( "aria-hidden", false );
+
+ if ( collapsibleContain.jqmData( "collapsible-last" ) ) {
+
+ collapsibleHeading
+ .find( "a:eq(0), .ui-btn-inner" )
+ .removeClass( "ui-corner-bottom" );
+ }
+ }
+ })
+ .trigger( o.collapsed ? "collapse" : "expand" );
+
+ // Close others in a set
+ if ( collapsibleParent.length && !collapsibleParent.jqmData( "collapsiblebound" ) ) {
+
+ collapsibleParent
+ .jqmData( "collapsiblebound", true )
+ .bind( "expand", function( event ) {
+
+ $( event.target )
+ .closest( ".ui-collapsible-contain" )
+ .siblings( ".ui-collapsible-contain" )
+ .trigger( "collapse" );
+
+ });
+
+ var set = collapsibleParent.children( ":jqmData(role='collapsible')" );
+
+ set.first()
+ .find( "a:eq(0)" )
+ .addClass( "ui-corner-top" )
+ .find( ".ui-btn-inner" )
+ .addClass( "ui-corner-top" );
+
+ set.last().jqmData( "collapsible-last", true );
+ }
+
+ collapsibleHeading
+ .bind( "vclick", function( event ) {
+
+ var type = collapsibleHeading.is( ".ui-collapsible-heading-collapsed" ) ?
+ "expand" : "collapse";
+
+ collapsibleContain.trigger( type );
+
+ event.preventDefault();
+ });
+ }
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+ $( $.mobile.collapsible.prototype.options.initSelector, e.target ).collapsible();
+});
+
+})( jQuery );
+/*
+* jQuery Mobile Framework : "fieldcontain" plugin - simple class additions to make form row separators
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+(function( $, undefined ) {
+
+$.fn.fieldcontain = function( options ) {
+ return this.addClass( "ui-field-contain ui-body ui-br" );
+};
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+ $( ":jqmData(role='fieldcontain')", e.target ).fieldcontain();
+});
+
+})( jQuery );/*
+* jQuery Mobile Framework : plugin for creating CSS grids
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+(function( $, undefined ) {
+
+$.fn.grid = function( options ) {
+ return this.each(function() {
+
+ var $this = $( this ),
+ o = $.extend({
+ grid: null
+ },options),
+ $kids = $this.children(),
+ gridCols = {solo:1, a:2, b:3, c:4, d:5},
+ grid = o.grid,
+ iterator;
+
+ if ( !grid ) {
+ if ( $kids.length <= 5 ) {
+ for ( var letter in gridCols ) {
+ if ( gridCols[ letter ] === $kids.length ) {
+ grid = letter;
+ }
+ }
+ } else {
+ grid = "a";
+ }
+ }
+ iterator = gridCols[grid];
+
+ $this.addClass( "ui-grid-" + grid );
+
+ $kids.filter( ":nth-child(" + iterator + "n+1)" ).addClass( "ui-block-a" );
+
+ if ( iterator > 1 ) {
+ $kids.filter( ":nth-child(" + iterator + "n+2)" ).addClass( "ui-block-b" );
+ }
+ if ( iterator > 2 ) {
+ $kids.filter( ":nth-child(3n+3)" ).addClass( "ui-block-c" );
+ }
+ if ( iterator > 3 ) {
+ $kids.filter( ":nth-child(4n+4)" ).addClass( "ui-block-d" );
+ }
+ if ( iterator > 4 ) {
+ $kids.filter( ":nth-child(5n+5)" ).addClass( "ui-block-e" );
+ }
+ });
+};
+})( jQuery );/*
+* jQuery Mobile Framework : "navbar" plugin
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+(function( $, undefined ) {
+
+$.widget( "mobile.navbar", $.mobile.widget, {
+ options: {
+ iconpos: "top",
+ grid: null,
+ initSelector: ":jqmData(role='navbar')"
+ },
+
+ _create: function(){
+
+ var $navbar = this.element,
+ $navbtns = $navbar.find( "a" ),
+ iconpos = $navbtns.filter( ":jqmData(icon)" ).length ?
+ this.options.iconpos : undefined;
+
+ $navbar.addClass( "ui-navbar" )
+ .attr( "role","navigation" )
+ .find( "ul" )
+ .grid({ grid: this.options.grid });
+
+ if ( !iconpos ) {
+ $navbar.addClass( "ui-navbar-noicons" );
+ }
+
+ $navbtns.buttonMarkup({
+ corners: false,
+ shadow: false,
+ iconpos: iconpos
+ });
+
+ $navbar.delegate( "a", "vclick", function( event ) {
+ $navbtns.not( ".ui-state-persist" ).removeClass( $.mobile.activeBtnClass );
+ $( this ).addClass( $.mobile.activeBtnClass );
+ });
+ }
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+ $( $.mobile.navbar.prototype.options.initSelector, e.target ).navbar();
+});
+
+})( jQuery );
+/*
+* jQuery Mobile Framework : "listview" plugin
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+(function( $, undefined ) {
+
+//Keeps track of the number of lists per page UID
+//This allows support for multiple nested list in the same page
+//https://github.com/jquery/jquery-mobile/issues/1617
+var listCountPerPage = {};
+
+$.widget( "mobile.listview", $.mobile.widget, {
+ options: {
+ theme: "c",
+ countTheme: "c",
+ headerTheme: "b",
+ dividerTheme: "b",
+ splitIcon: "arrow-r",
+ splitTheme: "b",
+ inset: false,
+ initSelector: ":jqmData(role='listview')"
+ },
+
+ _create: function() {
+ var t = this;
+
+ // create listview markup
+ t.element.addClass(function( i, orig ) {
+ return orig + " ui-listview " + ( t.options.inset ? " ui-listview-inset ui-corner-all ui-shadow " : "" );
+ });
+
+ t.refresh( true );
+ },
+
+ _itemApply: function( $list, item ) {
+ var $countli = item.find( ".ui-li-count" );
+ if ( $countli.length ) {
+ item.addClass( "ui-li-has-count" );
+ }
+ $countli.addClass( "ui-btn-up-" + ( $list.jqmData( "counttheme" ) || this.options.countTheme ) + " ui-btn-corner-all" );
+
+ // TODO class has to be defined in markup
+ item.find( "h1, h2, h3, h4, h5, h6" ).addClass( "ui-li-heading" ).end()
+ .find( "p, dl" ).addClass( "ui-li-desc" ).end()
+ .find( ">img:eq(0), .ui-link-inherit>img:eq(0)" ).addClass( "ui-li-thumb" ).each(function() {
+ item.addClass( $(this).is( ".ui-li-icon" ) ? "ui-li-has-icon" : "ui-li-has-thumb" );
+ }).end()
+ .find( ".ui-li-aside" ).each(function() {
+ var $this = $(this);
+ $this.prependTo( $this.parent() ); //shift aside to front for css float
+ });
+ },
+
+ _removeCorners: function( li, which ) {
+ var top = "ui-corner-top ui-corner-tr ui-corner-tl",
+ bot = "ui-corner-bottom ui-corner-br ui-corner-bl";
+
+ li = li.add( li.find( ".ui-btn-inner, .ui-li-link-alt, .ui-li-thumb" ) );
+
+ if ( which === "top" ) {
+ li.removeClass( top );
+ } else if ( which === "bottom" ) {
+ li.removeClass( bot );
+ } else {
+ li.removeClass( top + " " + bot );
+ }
+ },
+
+ _refreshCorners: function( create ) {
+ var $li,
+ $visibleli,
+ $topli,
+ $bottomli;
+
+ if ( this.options.inset ) {
+ $li = this.element.children( "li" );
+ // at create time the li are not visible yet so we need to rely on .ui-screen-hidden
+ $visibleli = create?$li.not( ".ui-screen-hidden" ):$li.filter( ":visible" );
+
+ this._removeCorners( $li );
+
+ // Select the first visible li element
+ $topli = $visibleli.first()
+ .addClass( "ui-corner-top" );
+
+ $topli.add( $topli.find( ".ui-btn-inner" ) )
+ .find( ".ui-li-link-alt" )
+ .addClass( "ui-corner-tr" )
+ .end()
+ .find( ".ui-li-thumb" )
+ .addClass( "ui-corner-tl" );
+
+ // Select the last visible li element
+ $bottomli = $visibleli.last()
+ .addClass( "ui-corner-bottom" );
+
+ $bottomli.add( $bottomli.find( ".ui-btn-inner" ) )
+ .find( ".ui-li-link-alt" )
+ .addClass( "ui-corner-br" )
+ .end()
+ .find( ".ui-li-thumb" )
+ .addClass( "ui-corner-bl" );
+ }
+ },
+
+ refresh: function( create ) {
+ this.parentPage = this.element.closest( ".ui-page" );
+ this._createSubPages();
+
+ var o = this.options,
+ $list = this.element,
+ self = this,
+ dividertheme = $list.jqmData( "dividertheme" ) || o.dividerTheme,
+ listsplittheme = $list.jqmData( "splittheme" ),
+ listspliticon = $list.jqmData( "spliticon" ),
+ li = $list.children( "li" ),
+ counter = $.support.cssPseudoElement || !$.nodeName( $list[ 0 ], "ol" ) ? 0 : 1,
+ item, itemClass, itemTheme,
+ a, last, splittheme, countParent, icon;
+
+ if ( counter ) {
+ $list.find( ".ui-li-dec" ).remove();
+ }
+
+ for ( var pos = 0, numli = li.length; pos < numli; pos++ ) {
+ item = li.eq( pos );
+ itemClass = "ui-li";
+
+ // If we're creating the element, we update it regardless
+ if ( create || !item.hasClass( "ui-li" ) ) {
+ itemTheme = item.jqmData("theme") || o.theme;
+ a = item.children( "a" );
+
+ if ( a.length ) {
+ icon = item.jqmData("icon");
+
+ item.buttonMarkup({
+ wrapperEls: "div",
+ shadow: false,
+ corners: false,
+ iconpos: "right",
+ icon: a.length > 1 || icon === false ? false : icon || "arrow-r",
+ theme: itemTheme
+ });
+
+ if ( ( icon != false ) && ( a.length == 1 ) ) {
+ item.addClass( "ui-li-has-arrow" );
+ }
+
+ a.first().addClass( "ui-link-inherit" );
+
+ if ( a.length > 1 ) {
+ itemClass += " ui-li-has-alt";
+
+ last = a.last();
+ splittheme = listsplittheme || last.jqmData( "theme" ) || o.splitTheme;
+
+ last.appendTo(item)
+ .attr( "title", last.text() )
+ .addClass( "ui-li-link-alt" )
+ .empty()
+ .buttonMarkup({
+ shadow: false,
+ corners: false,
+ theme: itemTheme,
+ icon: false,
+ iconpos: false
+ })
+ .find( ".ui-btn-inner" )
+ .append(
+ $( "<span />" ).buttonMarkup({
+ shadow: true,
+ corners: true,
+ theme: splittheme,
+ iconpos: "notext",
+ icon: listspliticon || last.jqmData( "icon" ) || o.splitIcon
+ })
+ );
+ }
+ } else if ( item.jqmData( "role" ) === "list-divider" ) {
+
+ itemClass += " ui-li-divider ui-btn ui-bar-" + dividertheme;
+ item.attr( "role", "heading" );
+
+ //reset counter when a divider heading is encountered
+ if ( counter ) {
+ counter = 1;
+ }
+
+ } else {
+ itemClass += " ui-li-static ui-body-" + itemTheme;
+ }
+ }
+
+ if ( counter && itemClass.indexOf( "ui-li-divider" ) < 0 ) {
+ countParent = item.is( ".ui-li-static:first" ) ? item : item.find( ".ui-link-inherit" );
+
+ countParent.addClass( "ui-li-jsnumbering" )
+ .prepend( "<span class='ui-li-dec'>" + (counter++) + ". </span>" );
+ }
+
+ item.add( item.children( ".ui-btn-inner" ) ).addClass( itemClass );
+
+ self._itemApply( $list, item );
+ }
+
+ this._refreshCorners( create );
+ },
+
+ //create a string for ID/subpage url creation
+ _idStringEscape: function( str ) {
+ return str.replace(/[^a-zA-Z0-9]/g, '-');
+ },
+
+ _createSubPages: function() {
+ var parentList = this.element,
+ parentPage = parentList.closest( ".ui-page" ),
+ parentUrl = parentPage.jqmData( "url" ),
+ parentId = parentUrl || parentPage[ 0 ][ $.expando ],
+ parentListId = parentList.attr( "id" ),
+ o = this.options,
+ dns = "data-" + $.mobile.ns,
+ self = this,
+ persistentFooterID = parentPage.find( ":jqmData(role='footer')" ).jqmData( "id" ),
+ hasSubPages;
+
+ if ( typeof listCountPerPage[ parentId ] === "undefined" ) {
+ listCountPerPage[ parentId ] = -1;
+ }
+
+ parentListId = parentListId || ++listCountPerPage[ parentId ];
+
+ $( parentList.find( "li>ul, li>ol" ).toArray().reverse() ).each(function( i ) {
+ var self = this,
+ list = $( this ),
+ listId = list.attr( "id" ) || parentListId + "-" + i,
+ parent = list.parent(),
+ nodeEls = $( list.prevAll().toArray().reverse() ),
+ nodeEls = nodeEls.length ? nodeEls : $( "<span>" + $.trim(parent.contents()[ 0 ].nodeValue) + "</span>" ),
+ title = nodeEls.first().text(),//url limits to first 30 chars of text
+ id = ( parentUrl || "" ) + "&" + $.mobile.subPageUrlKey + "=" + listId,
+ theme = list.jqmData( "theme" ) || o.theme,
+ countTheme = list.jqmData( "counttheme" ) || parentList.jqmData( "counttheme" ) || o.countTheme,
+ newPage, anchor;
+
+ //define hasSubPages for use in later removal
+ hasSubPages = true;
+
+ newPage = list.detach()
+ .wrap( "<div " + dns + "role='page' " + dns + "url='" + id + "' " + dns + "theme='" + theme + "' " + dns + "count-theme='" + countTheme + "'><div " + dns + "role='content'></div></div>" )
+ .parent()
+ .before( "<div " + dns + "role='header' " + dns + "theme='" + o.headerTheme + "'><div class='ui-title'>" + title + "</div></div>" )
+ .after( persistentFooterID ? $( "<div " + dns + "role='footer' " + dns + "id='"+ persistentFooterID +"'>") : "" )
+ .parent()
+ .appendTo( $.mobile.pageContainer );
+
+ newPage.page();
+
+ anchor = parent.find('a:first');
+
+ if ( !anchor.length ) {
+ anchor = $( "<a/>" ).html( nodeEls || title ).prependTo( parent.empty() );
+ }
+
+ anchor.attr( "href", "#" + id );
+
+ }).listview();
+
+ //on pagehide, remove any nested pages along with the parent page, as long as they aren't active
+ if( hasSubPages && parentPage.data("page").options.domCache === false ){
+ var newRemove = function( e, ui ){
+ var nextPage = ui.nextPage, npURL;
+
+ if( ui.nextPage ){
+ npURL = nextPage.jqmData( "url" );
+ if( npURL.indexOf( parentUrl + "&" + $.mobile.subPageUrlKey ) !== 0 ){
+ self.childPages().remove();
+ parentPage.remove();
+ }
+ }
+ };
+
+ // unbind the original page remove and replace with our specialized version
+ parentPage
+ .unbind( "pagehide.remove" )
+ .bind( "pagehide.remove", newRemove);
+ }
+ },
+
+ // TODO sort out a better way to track sub pages of the listview this is brittle
+ childPages: function(){
+ var parentUrl = this.parentPage.jqmData( "url" );
+
+ return $( ":jqmData(url^='"+ parentUrl + "&" + $.mobile.subPageUrlKey +"')");
+ }
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+ $( $.mobile.listview.prototype.options.initSelector, e.target ).listview();
+});
+
+})( jQuery );
+/*
+* jQuery Mobile Framework : "listview" filter extension
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+(function( $, undefined ) {
+
+$.mobile.listview.prototype.options.filter = false;
+$.mobile.listview.prototype.options.filterPlaceholder = "Filter items...";
+$.mobile.listview.prototype.options.filterTheme = "c";
+$.mobile.listview.prototype.options.filterCallback = function( text, searchValue ){
+ return text.toLowerCase().indexOf( searchValue ) === -1;
+};
+
+$( ":jqmData(role='listview')" ).live( "listviewcreate", function() {
+
+ var list = $( this ),
+ listview = list.data( "listview" );
+
+ if ( !listview.options.filter ) {
+ return;
+ }
+
+ var wrapper = $( "<form>", {
+ "class": "ui-listview-filter ui-bar-" + listview.options.filterTheme,
+ "role": "search"
+ }),
+ search = $( "<input>", {
+ placeholder: listview.options.filterPlaceholder
+ })
+ .attr( "data-" + $.mobile.ns + "type", "search" )
+ .jqmData( "lastval", "" )
+ .bind( "keyup change", function() {
+
+ var $this = $(this),
+ val = this.value.toLowerCase(),
+ listItems = null,
+ lastval = $this.jqmData( "lastval" ) + "",
+ childItems = false,
+ itemtext = "",
+ item, change;
+
+ // Change val as lastval for next execution
+ $this.jqmData( "lastval" , val );
+
+ change = val.replace( new RegExp( "^" + lastval ) , "" );
+
+ if ( val.length < lastval.length || change.length != ( val.length - lastval.length ) ) {
+
+ // Removed chars or pasted something totaly different, check all items
+ listItems = list.children();
+ } else {
+
+ // Only chars added, not removed, only use visible subset
+ listItems = list.children( ":not(.ui-screen-hidden)" );
+ }
+
+ if ( val ) {
+
+ // This handles hiding regular rows without the text we search for
+ // and any list dividers without regular rows shown under it
+
+ for ( var i = listItems.length - 1; i >= 0; i-- ) {
+ item = $( listItems[ i ] );
+ itemtext = item.jqmData( "filtertext" ) || item.text();
+
+ if ( item.is( "li:jqmData(role=list-divider)" ) ) {
+
+ item.toggleClass( "ui-filter-hidequeue" , !childItems );
+
+ // New bucket!
+ childItems = false;
+
+ } else if ( listview.options.filterCallback( itemtext, val ) ) {
+
+ //mark to be hidden
+ item.toggleClass( "ui-filter-hidequeue" , true );
+ } else {
+
+ // There"s a shown item in the bucket
+ childItems = true;
+ }
+ }
+
+ // Show items, not marked to be hidden
+ listItems
+ .filter( ":not(.ui-filter-hidequeue)" )
+ .toggleClass( "ui-screen-hidden", false );
+
+ // Hide items, marked to be hidden
+ listItems
+ .filter( ".ui-filter-hidequeue" )
+ .toggleClass( "ui-screen-hidden", true )
+ .toggleClass( "ui-filter-hidequeue", false );
+
+ } else {
+
+ //filtervalue is empty => show all
+ listItems.toggleClass( "ui-screen-hidden", false );
+ }
+ listview._refreshCorners();
+ })
+ .appendTo( wrapper )
+ .textinput();
+
+ if ( $( this ).jqmData( "inset" ) ) {
+ wrapper.addClass( "ui-listview-filter-inset" );
+ }
+
+ wrapper.bind( "submit", function() {
+ return false;
+ })
+ .insertBefore( list );
+});
+
+})( jQuery );/*
+* jQuery Mobile Framework : "fieldcontain" plugin - simple class additions to make form row separators
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+(function( $, undefined ) {
+
+$( document ).bind( "pagecreate create", function( e ){
+ $( ":jqmData(role='nojs')", e.target ).addClass( "ui-nojs" );
+
+});
+
+})( jQuery );/*
+* jQuery Mobile Framework : "checkboxradio" plugin
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+(function( $, undefined ) {
+
+$.widget( "mobile.checkboxradio", $.mobile.widget, {
+ options: {
+ theme: null,
+ initSelector: "input[type='checkbox'],input[type='radio']"
+ },
+ _create: function() {
+ var self = this,
+ input = this.element,
+ // NOTE: Windows Phone could not find the label through a selector
+ // filter works though.
+ label = input.closest( "form,fieldset,:jqmData(role='page')" ).find( "label" ).filter( "[for='" + input[ 0 ].id + "']"),
+ inputtype = input.attr( "type" ),
+ checkedState = inputtype + "-on",
+ uncheckedState = inputtype + "-off",
+ icon = input.parents( ":jqmData(type='horizontal')" ).length ? undefined : uncheckedState,
+ activeBtn = icon ? "" : " " + $.mobile.activeBtnClass,
+ checkedClass = "ui-" + checkedState + activeBtn,
+ uncheckedClass = "ui-" + uncheckedState,
+ checkedicon = "ui-icon-" + checkedState,
+ uncheckedicon = "ui-icon-" + uncheckedState;
+
+ if ( inputtype !== "checkbox" && inputtype !== "radio" ) {
+ return;
+ }
+
+ // Expose for other methods
+ $.extend( this, {
+ label: label,
+ inputtype: inputtype,
+ checkedClass: checkedClass,
+ uncheckedClass: uncheckedClass,
+ checkedicon: checkedicon,
+ uncheckedicon: uncheckedicon
+ });
+
+ // If there's no selected theme...
+ if( !this.options.theme ) {
+ this.options.theme = this.element.jqmData( "theme" );
+ }
+
+ label.buttonMarkup({
+ theme: this.options.theme,
+ icon: icon,
+ shadow: false
+ });
+
+ // Wrap the input + label in a div
+ input.add( label )
+ .wrapAll( "<div class='ui-" + inputtype + "'></div>" );
+
+ label.bind({
+ vmouseover: function() {
+ if ( $( this ).parent().is( ".ui-disabled" ) ) {
+ return false;
+ }
+ },
+
+ vclick: function( event ) {
+ if ( input.is( ":disabled" ) ) {
+ event.preventDefault();
+ return;
+ }
+
+ self._cacheVals();
+
+ input.prop( "checked", inputtype === "radio" && true || !input.prop( "checked" ) );
+
+ // Input set for common radio buttons will contain all the radio
+ // buttons, but will not for checkboxes. clearing the checked status
+ // of other radios ensures the active button state is applied properly
+ self._getInputSet().not( input ).prop( "checked", false );
+
+ self._updateAll();
+ return false;
+ }
+
+ });
+
+ input
+ .bind({
+ vmousedown: function() {
+ this._cacheVals();
+ },
+
+ vclick: function() {
+
+ var $this = $(this);
+
+ // Adds checked attribute to checked input when keyboard is used
+ if ( $this.is( ":checked" ) ) {
+
+ $this.prop( "checked", true);
+ self._getInputSet().not($this).prop( "checked", false );
+ } else {
+
+ $this.prop( "checked", false );
+ }
+
+ self._updateAll();
+ },
+
+ focus: function() {
+ label.addClass( "ui-focus" );
+ },
+
+ blur: function() {
+ label.removeClass( "ui-focus" );
+ }
+ });
+
+ this.refresh();
+ },
+
+ _cacheVals: function() {
+ this._getInputSet().each(function() {
+ var $this = $(this);
+
+ $this.jqmData( "cacheVal", $this.is( ":checked" ) );
+ });
+ },
+
+ //returns either a set of radios with the same name attribute, or a single checkbox
+ _getInputSet: function(){
+ if(this.inputtype == "checkbox") {
+ return this.element;
+ }
+ return this.element.closest( "form,fieldset,:jqmData(role='page')" )
+ .find( "input[name='"+ this.element.attr( "name" ) +"'][type='"+ this.inputtype +"']" );
+ },
+
+ _updateAll: function() {
+ var self = this;
+
+ this._getInputSet().each(function() {
+ var $this = $(this);
+
+ if ( $this.is( ":checked" ) || self.inputtype === "checkbox" ) {
+ $this.trigger( "change" );
+ }
+ })
+ .checkboxradio( "refresh" );
+ },
+
+ refresh: function() {
+ var input = this.element,
+ label = this.label,
+ icon = label.find( ".ui-icon" );
+
+ // input[0].checked expando doesn't always report the proper value
+ // for checked='checked'
+ if ( $( input[ 0 ] ).prop( "checked" ) ) {
+
+ label.addClass( this.checkedClass ).removeClass( this.uncheckedClass );
+ icon.addClass( this.checkedicon ).removeClass( this.uncheckedicon );
+
+ } else {
+
+ label.removeClass( this.checkedClass ).addClass( this.uncheckedClass );
+ icon.removeClass( this.checkedicon ).addClass( this.uncheckedicon );
+ }
+
+ if ( input.is( ":disabled" ) ) {
+ this.disable();
+ } else {
+ this.enable();
+ }
+ },
+
+ disable: function() {
+ this.element.prop( "disabled", true ).parent().addClass( "ui-disabled" );
+ },
+
+ enable: function() {
+ this.element.prop( "disabled", false ).parent().removeClass( "ui-disabled" );
+ }
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+ $( $.mobile.checkboxradio.prototype.options.initSelector, e.target )
+ .not( ":jqmData(role='none'), :jqmData(role='nojs')" )
+ .checkboxradio();
+});
+
+})( jQuery );
+/*
+* jQuery Mobile Framework : "button" plugin - links that proxy to native input/buttons
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+(function( $, undefined ) {
+
+$.widget( "mobile.button", $.mobile.widget, {
+ options: {
+ theme: null,
+ icon: null,
+ iconpos: null,
+ inline: null,
+ corners: true,
+ shadow: true,
+ iconshadow: true,
+ initSelector: "button, [type='button'], [type='submit'], [type='reset'], [type='image']"
+ },
+ _create: function() {
+ var $el = this.element,
+ o = this.options,
+ type;
+
+ // Add ARIA role
+ this.button = $( "<div></div>" )
+ .text( $el.text() || $el.val() )
+ .buttonMarkup({
+ theme: o.theme,
+ icon: o.icon,
+ iconpos: o.iconpos,
+ inline: o.inline,
+ corners: o.corners,
+ shadow: o.shadow,
+ iconshadow: o.iconshadow
+ })
+ .insertBefore( $el )
+ .append( $el.addClass( "ui-btn-hidden" ) );
+
+ // Add hidden input during submit
+ type = $el.attr( "type" );
+
+ if ( type !== "button" && type !== "reset" ) {
+
+ $el.bind( "vclick", function() {
+
+ var $buttonPlaceholder = $( "<input>", {
+ type: "hidden",
+ name: $el.attr( "name" ),
+ value: $el.attr( "value" )
+ })
+ .insertBefore( $el );
+
+ // Bind to doc to remove after submit handling
+ $( document ).submit(function(){
+ $buttonPlaceholder.remove();
+ });
+ });
+ }
+
+ this.refresh();
+ },
+
+ enable: function() {
+ this.element.attr( "disabled", false );
+ this.button.removeClass( "ui-disabled" ).attr( "aria-disabled", false );
+ return this._setOption( "disabled", false );
+ },
+
+ disable: function() {
+ this.element.attr( "disabled", true );
+ this.button.addClass( "ui-disabled" ).attr( "aria-disabled", true );
+ return this._setOption( "disabled", true );
+ },
+
+ refresh: function() {
+ if ( this.element.attr( "disabled" ) ) {
+ this.disable();
+ } else {
+ this.enable();
+ }
+ }
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+ $( $.mobile.button.prototype.options.initSelector, e.target )
+ .not( ":jqmData(role='none'), :jqmData(role='nojs')" )
+ .button();
+});
+
+})( jQuery );/*
+* jQuery Mobile Framework : "slider" plugin
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+( function( $, undefined ) {
+
+$.widget( "mobile.slider", $.mobile.widget, {
+ options: {
+ theme: null,
+ trackTheme: null,
+ disabled: false,
+ initSelector: "input[type='range'], :jqmData(type='range'), :jqmData(role='slider')"
+ },
+
+ _create: function() {
+
+ // TODO: Each of these should have comments explain what they're for
+ var self = this,
+
+ control = this.element,
+
+ parentTheme = control.parents( "[class*='ui-bar-'],[class*='ui-body-']" ).eq( 0 ),
+
+ parentTheme = parentTheme.length ? parentTheme.attr( "class" ).match( /ui-(bar|body)-([a-z])/ )[ 2 ] : "c",
+
+ theme = this.options.theme ? this.options.theme : parentTheme,
+
+ trackTheme = this.options.trackTheme ? this.options.trackTheme : parentTheme,
+
+ cType = control[ 0 ].nodeName.toLowerCase(),
+
+ selectClass = ( cType == "select" ) ? "ui-slider-switch" : "",
+
+ controlID = control.attr( "id" ),
+
+ labelID = controlID + "-label",
+
+ label = $( "[for='"+ controlID +"']" ).attr( "id", labelID ),
+
+ val = function() {
+ return cType == "input" ? parseFloat( control.val() ) : control[0].selectedIndex;
+ },
+
+ min = cType == "input" ? parseFloat( control.attr( "min" ) ) : 0,
+
+ max = cType == "input" ? parseFloat( control.attr( "max" ) ) : control.find( "option" ).length-1,
+
+ step = window.parseFloat( control.attr( "step" ) || 1 ),
+
+ slider = $( "<div class='ui-slider " + selectClass + " ui-btn-down-" + trackTheme +
+ " ui-btn-corner-all' role='application'></div>" ),
+
+ handle = $( "<a href='#' class='ui-slider-handle'></a>" )
+ .appendTo( slider )
+ .buttonMarkup({ corners: true, theme: theme, shadow: true })
+ .attr({
+ "role": "slider",
+ "aria-valuemin": min,
+ "aria-valuemax": max,
+ "aria-valuenow": val(),
+ "aria-valuetext": val(),
+ "title": val(),
+ "aria-labelledby": labelID
+ }),
+ options;
+
+ $.extend( this, {
+ slider: slider,
+ handle: handle,
+ dragging: false,
+ beforeStart: null,
+ userModified: false
+ });
+
+ if ( cType == "select" ) {
+
+ slider.wrapInner( "<div class='ui-slider-inneroffset'></div>" );
+
+ options = control.find( "option" );
+
+ control.find( "option" ).each(function( i ) {
+
+ var side = !i ? "b":"a",
+ corners = !i ? "right" :"left",
+ theme = !i ? " ui-btn-down-" + trackTheme :( " " + $.mobile.activeBtnClass );
+
+ $( "<div class='ui-slider-labelbg ui-slider-labelbg-" + side + theme + " ui-btn-corner-" + corners + "'></div>" )
+ .prependTo( slider );
+
+ $( "<span class='ui-slider-label ui-slider-label-" + side + theme + " ui-btn-corner-" + corners + "' role='img'>" + $( this ).text() + "</span>" )
+ .prependTo( handle );
+ });
+
+ }
+
+ label.addClass( "ui-slider" );
+
+ // monitor the input for updated values
+ control.addClass( cType === "input" ? "ui-slider-input" : "ui-slider-switch" )
+ .change( function() {
+ self.refresh( val(), true );
+ })
+ .keyup( function() { // necessary?
+ self.refresh( val(), true, true );
+ })
+ .blur( function() {
+ self.refresh( val(), true );
+ });
+
+ // prevent screen drag when slider activated
+ $( document ).bind( "vmousemove", function( event ) {
+ if ( self.dragging ) {
+ self.refresh( event );
+ self.userModified = self.userModified || self.beforeStart !== control[0].selectedIndex;
+ return false;
+ }
+ });
+
+ slider.bind( "vmousedown", function( event ) {
+ self.dragging = true;
+ self.userModified = false;
+
+ if ( cType === "select" ) {
+ self.beforeStart = control[0].selectedIndex;
+ }
+ self.refresh( event );
+ return false;
+ });
+
+ slider.add( document )
+ .bind( "vmouseup", function() {
+ if ( self.dragging ) {
+
+ self.dragging = false;
+
+ if ( cType === "select" ) {
+
+ if ( !self.userModified ) {
+ //tap occurred, but value didn't change. flip it!
+ handle.addClass( "ui-slider-handle-snapping" );
+ self.refresh( !self.beforeStart ? 1 : 0 );
+ }
+ }
+ return false;
+ }
+ });
+
+ slider.insertAfter( control );
+
+ // NOTE force focus on handle
+ this.handle
+ .bind( "vmousedown", function() {
+ $( this ).focus();
+ })
+ .bind( "vclick", false );
+
+ this.handle
+ .bind( "keydown", function( event ) {
+ var index = val();
+
+ if ( self.options.disabled ) {
+ return;
+ }
+
+ // In all cases prevent the default and mark the handle as active
+ switch ( event.keyCode ) {
+ case $.mobile.keyCode.HOME:
+ case $.mobile.keyCode.END:
+ case $.mobile.keyCode.PAGE_UP:
+ case $.mobile.keyCode.PAGE_DOWN:
+ case $.mobile.keyCode.UP:
+ case $.mobile.keyCode.RIGHT:
+ case $.mobile.keyCode.DOWN:
+ case $.mobile.keyCode.LEFT:
+ event.preventDefault();
+
+ if ( !self._keySliding ) {
+ self._keySliding = true;
+ $( this ).addClass( "ui-state-active" );
+ }
+ break;
+ }
+
+ // move the slider according to the keypress
+ switch ( event.keyCode ) {
+ case $.mobile.keyCode.HOME:
+ self.refresh( min );
+ break;
+ case $.mobile.keyCode.END:
+ self.refresh( max );
+ break;
+ case $.mobile.keyCode.PAGE_UP:
+ case $.mobile.keyCode.UP:
+ case $.mobile.keyCode.RIGHT:
+ self.refresh( index + step );
+ break;
+ case $.mobile.keyCode.PAGE_DOWN:
+ case $.mobile.keyCode.DOWN:
+ case $.mobile.keyCode.LEFT:
+ self.refresh( index - step );
+ break;
+ }
+ }) // remove active mark
+ .keyup( function( event ) {
+ if ( self._keySliding ) {
+ self._keySliding = false;
+ $( this ).removeClass( "ui-state-active" );
+ }
+ });
+
+ this.refresh(undefined, undefined, true);
+ },
+
+ refresh: function( val, isfromControl, preventInputUpdate ) {
+ if ( this.options.disabled ) { return; }
+
+ var control = this.element, percent,
+ cType = control[0].nodeName.toLowerCase(),
+ min = cType === "input" ? parseFloat( control.attr( "min" ) ) : 0,
+ max = cType === "input" ? parseFloat( control.attr( "max" ) ) : control.find( "option" ).length - 1;
+
+ if ( typeof val === "object" ) {
+ var data = val,
+ // a slight tolerance helped get to the ends of the slider
+ tol = 8;
+ if ( !this.dragging ||
+ data.pageX < this.slider.offset().left - tol ||
+ data.pageX > this.slider.offset().left + this.slider.width() + tol ) {
+ return;
+ }
+ percent = Math.round( ( ( data.pageX - this.slider.offset().left ) / this.slider.width() ) * 100 );
+ } else {
+ if ( val == null ) {
+ val = cType === "input" ? parseFloat( control.val() ) : control[0].selectedIndex;
+ }
+ percent = ( parseFloat( val ) - min ) / ( max - min ) * 100;
+ }
+
+ if ( isNaN( percent ) ) {
+ return;
+ }
+
+ if ( percent < 0 ) {
+ percent = 0;
+ }
+
+ if ( percent > 100 ) {
+ percent = 100;
+ }
+
+ var newval = Math.round( ( percent / 100 ) * ( max - min ) ) + min;
+
+ if ( newval < min ) {
+ newval = min;
+ }
+
+ if ( newval > max ) {
+ newval = max;
+ }
+
+ // Flip the stack of the bg colors
+ if ( percent > 60 && cType === "select" ) {
+ // TODO: Dead path?
+ }
+ this.handle.css( "left", percent + "%" );
+ this.handle.attr( {
+ "aria-valuenow": cType === "input" ? newval : control.find( "option" ).eq( newval ).attr( "value" ),
+ "aria-valuetext": cType === "input" ? newval : control.find( "option" ).eq( newval ).text(),
+ title: newval
+ });
+
+ // add/remove classes for flip toggle switch
+ if ( cType === "select" ) {
+ if ( newval === 0 ) {
+ this.slider.addClass( "ui-slider-switch-a" )
+ .removeClass( "ui-slider-switch-b" );
+ } else {
+ this.slider.addClass( "ui-slider-switch-b" )
+ .removeClass( "ui-slider-switch-a" );
+ }
+ }
+
+ if ( !preventInputUpdate ) {
+ // update control"s value
+ if ( cType === "input" ) {
+ control.val( newval );
+ } else {
+ control[ 0 ].selectedIndex = newval;
+ }
+ if ( !isfromControl ) {
+ control.trigger( "change" );
+ }
+ }
+ },
+
+ enable: function() {
+ this.element.attr( "disabled", false );
+ this.slider.removeClass( "ui-disabled" ).attr( "aria-disabled", false );
+ return this._setOption( "disabled", false );
+ },
+
+ disable: function() {
+ this.element.attr( "disabled", true );
+ this.slider.addClass( "ui-disabled" ).attr( "aria-disabled", true );
+ return this._setOption( "disabled", true );
+ }
+
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+
+ $( $.mobile.slider.prototype.options.initSelector, e.target )
+ .not( ":jqmData(role='none'), :jqmData(role='nojs')" )
+ .slider();
+
+});
+
+})( jQuery );
+/*
+* jQuery Mobile Framework : "textinput" plugin for text inputs, textareas
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+(function( $, undefined ) {
+
+$.widget( "mobile.textinput", $.mobile.widget, {
+ options: {
+ theme: null,
+ initSelector: "input[type='text'], input[type='search'], :jqmData(type='search'), input[type='number'], :jqmData(type='number'), input[type='password'], input[type='email'], input[type='url'], input[type='tel'], textarea"
+ },
+
+ _create: function() {
+
+ var input = this.element,
+ o = this.options,
+ theme = o.theme,
+ themedParent, themeclass, themeLetter, focusedEl, clearbtn;
+
+ if ( !theme ) {
+ themedParent = this.element.closest( "[class*='ui-bar-'],[class*='ui-body-']" );
+ themeLetter = themedParent.length && /ui-(bar|body)-([a-z])/.exec( themedParent.attr( "class" ) );
+ theme = themeLetter && themeLetter[2] || "c";
+ }
+
+ themeclass = " ui-body-" + theme;
+
+ $( "label[for='" + input.attr( "id" ) + "']" ).addClass( "ui-input-text" );
+
+ input.addClass("ui-input-text ui-body-"+ o.theme );
+
+ focusedEl = input;
+
+ // XXX: Temporary workaround for issue 785. Turn off autocorrect and
+ // autocomplete since the popup they use can't be dismissed by
+ // the user. Note that we test for the presence of the feature
+ // by looking for the autocorrect property on the input element.
+ if ( typeof input[0].autocorrect !== "undefined" ) {
+ // Set the attribute instead of the property just in case there
+ // is code that attempts to make modifications via HTML.
+ input[0].setAttribute( "autocorrect", "off" );
+ input[0].setAttribute( "autocomplete", "off" );
+ }
+
+
+ //"search" input widget
+ if ( input.is( "[type='search'],:jqmData(type='search')" ) ) {
+
+ focusedEl = input.wrap( "<div class='ui-input-search ui-shadow-inset ui-btn-corner-all ui-btn-shadow ui-icon-searchfield" + themeclass + "'></div>" ).parent();
+ clearbtn = $( "<a href='#' class='ui-input-clear' title='clear text'>clear text</a>" )
+ .tap(function( event ) {
+ input.val( "" ).focus();
+ input.trigger( "change" );
+ clearbtn.addClass( "ui-input-clear-hidden" );
+ event.preventDefault();
+ })
+ .appendTo( focusedEl )
+ .buttonMarkup({
+ icon: "delete",
+ iconpos: "notext",
+ corners: true,
+ shadow: true
+ });
+
+ function toggleClear() {
+ if ( !input.val() ) {
+ clearbtn.addClass( "ui-input-clear-hidden" );
+ } else {
+ clearbtn.removeClass( "ui-input-clear-hidden" );
+ }
+ }
+
+ toggleClear();
+
+ input.keyup( toggleClear )
+ .focus( toggleClear );
+
+ } else {
+ input.addClass( "ui-corner-all ui-shadow-inset" + themeclass );
+ }
+
+ input.focus(function() {
+ focusedEl.addClass( "ui-focus" );
+ })
+ .blur(function(){
+ focusedEl.removeClass( "ui-focus" );
+ });
+
+ // Autogrow
+ if ( input.is( "textarea" ) ) {
+ var extraLineHeight = 15,
+ keyupTimeoutBuffer = 100,
+ keyup = function() {
+ var scrollHeight = input[ 0 ].scrollHeight,
+ clientHeight = input[ 0 ].clientHeight;
+
+ if ( clientHeight < scrollHeight ) {
+ input.css({
+ height: (scrollHeight + extraLineHeight)
+ });
+ }
+ },
+ keyupTimeout;
+
+ input.keyup(function() {
+ clearTimeout( keyupTimeout );
+ keyupTimeout = setTimeout( keyup, keyupTimeoutBuffer );
+ });
+ }
+ },
+
+ disable: function(){
+ ( this.element.attr( "disabled", true ).is( "[type='search'],:jqmData(type='search')" ) ?
+ this.element.parent() : this.element ).addClass( "ui-disabled" );
+ },
+
+ enable: function(){
+ ( this.element.attr( "disabled", false).is( "[type='search'],:jqmData(type='search')" ) ?
+ this.element.parent() : this.element ).removeClass( "ui-disabled" );
+ }
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+
+ $( $.mobile.textinput.prototype.options.initSelector, e.target )
+ .not( ":jqmData(role='none'), :jqmData(role='nojs')" )
+ .textinput();
+
+});
+
+})( jQuery );
+/*
+* jQuery Mobile Framework : custom "selectmenu" plugin
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+(function( $, undefined ) {
+ var extendSelect = function( widget ){
+
+ var select = widget.select,
+ selectID = widget.selectID,
+ label = widget.label,
+ thisPage = widget.select.closest( ".ui-page" ),
+ screen = $( "<div>", {"class": "ui-selectmenu-screen ui-screen-hidden"} ).appendTo( thisPage ),
+ selectOptions = widget.select.find("option"),
+ isMultiple = widget.isMultiple = widget.select[ 0 ].multiple,
+ buttonId = selectID + "-button",
+ menuId = selectID + "-menu",
+ menuPage = $( "<div data-" + $.mobile.ns + "role='dialog' data-" +$.mobile.ns + "theme='"+ widget.options.menuPageTheme +"'>" +
+ "<div data-" + $.mobile.ns + "role='header'>" +
+ "<div class='ui-title'>" + label.text() + "</div>"+
+ "</div>"+
+ "<div data-" + $.mobile.ns + "role='content'></div>"+
+ "</div>" ).appendTo( $.mobile.pageContainer ).page(),
+
+ listbox = $("<div>", { "class": "ui-selectmenu ui-selectmenu-hidden ui-overlay-shadow ui-corner-all ui-body-" + widget.options.overlayTheme + " " + $.mobile.defaultDialogTransition } ).insertAfter(screen),
+
+ list = $( "<ul>", {
+ "class": "ui-selectmenu-list",
+ "id": menuId,
+ "role": "listbox",
+ "aria-labelledby": buttonId
+ }).attr( "data-" + $.mobile.ns + "theme", widget.options.theme ).appendTo( listbox ),
+
+ header = $( "<div>", {
+ "class": "ui-header ui-bar-" + widget.options.theme
+ }).prependTo( listbox ),
+
+ headerTitle = $( "<h1>", {
+ "class": "ui-title"
+ }).appendTo( header ),
+
+ headerClose = $( "<a>", {
+ "text": widget.options.closeText,
+ "href": "#",
+ "class": "ui-btn-left"
+ }).attr( "data-" + $.mobile.ns + "iconpos", "notext" ).attr( "data-" + $.mobile.ns + "icon", "delete" ).appendTo( header ).buttonMarkup(),
+
+ menuPageContent = menuPage.find( ".ui-content" ),
+
+ menuPageClose = menuPage.find( ".ui-header a" );
+
+
+ $.extend( widget, {
+ select: widget.select,
+ selectID: selectID,
+ buttonId: buttonId,
+ menuId: menuId,
+ thisPage: thisPage,
+ menuPage: menuPage,
+ label: label,
+ screen: screen,
+ selectOptions: selectOptions,
+ isMultiple: isMultiple,
+ theme: widget.options.theme,
+ listbox: listbox,
+ list: list,
+ header: header,
+ headerTitle: headerTitle,
+ headerClose: headerClose,
+ menuPageContent: menuPageContent,
+ menuPageClose: menuPageClose,
+ placeholder: "",
+
+ build: function() {
+ var self = this;
+
+ // Create list from select, update state
+ self.refresh();
+
+ self.select.attr( "tabindex", "-1" ).focus(function() {
+ $( this ).blur();
+ self.button.focus();
+ });
+
+ // Button events
+ self.button.bind( "vclick keydown" , function( event ) {
+ if ( event.type == "vclick" ||
+ event.keyCode && ( event.keyCode === $.mobile.keyCode.ENTER ||
+ event.keyCode === $.mobile.keyCode.SPACE ) ) {
+
+ self.open();
+ event.preventDefault();
+ }
+ });
+
+ // Events for list items
+ self.list.attr( "role", "listbox" )
+ .delegate( ".ui-li>a", "focusin", function() {
+ $( this ).attr( "tabindex", "0" );
+ })
+ .delegate( ".ui-li>a", "focusout", function() {
+ $( this ).attr( "tabindex", "-1" );
+ })
+ .delegate( "li:not(.ui-disabled, .ui-li-divider)", "click", function( event ) {
+
+ // index of option tag to be selected
+ var oldIndex = self.select[ 0 ].selectedIndex,
+ newIndex = self.list.find( "li:not(.ui-li-divider)" ).index( this ),
+ option = self.selectOptions.eq( newIndex )[ 0 ];
+
+ // toggle selected status on the tag for multi selects
+ option.selected = self.isMultiple ? !option.selected : true;
+
+ // toggle checkbox class for multiple selects
+ if ( self.isMultiple ) {
+ $( this ).find( ".ui-icon" )
+ .toggleClass( "ui-icon-checkbox-on", option.selected )
+ .toggleClass( "ui-icon-checkbox-off", !option.selected );
+ }
+
+ // trigger change if value changed
+ if ( self.isMultiple || oldIndex !== newIndex ) {
+ self.select.trigger( "change" );
+ }
+
+ //hide custom select for single selects only
+ if ( !self.isMultiple ) {
+ self.close();
+ }
+
+ event.preventDefault();
+ })
+ .keydown(function( event ) { //keyboard events for menu items
+ var target = $( event.target ),
+ li = target.closest( "li" ),
+ prev, next;
+
+ // switch logic based on which key was pressed
+ switch ( event.keyCode ) {
+ // up or left arrow keys
+ case 38:
+ prev = li.prev();
+
+ // if there's a previous option, focus it
+ if ( prev.length ) {
+ target
+ .blur()
+ .attr( "tabindex", "-1" );
+
+ prev.find( "a" ).first().focus();
+ }
+
+ return false;
+ break;
+
+ // down or right arrow keys
+ case 40:
+ next = li.next();
+
+ // if there's a next option, focus it
+ if ( next.length ) {
+ target
+ .blur()
+ .attr( "tabindex", "-1" );
+
+ next.find( "a" ).first().focus();
+ }
+
+ return false;
+ break;
+
+ // If enter or space is pressed, trigger click
+ case 13:
+ case 32:
+ target.trigger( "click" );
+
+ return false;
+ break;
+ }
+ });
+
+ // button refocus ensures proper height calculation
+ // by removing the inline style and ensuring page inclusion
+ self.menuPage.bind( "pagehide", function() {
+ self.list.appendTo( self.listbox );
+ self._focusButton();
+ });
+
+ // Events on "screen" overlay
+ self.screen.bind( "vclick", function( event ) {
+ self.close();
+ });
+
+ // Close button on small overlays
+ self.headerClose.click( function() {
+ if ( self.menuType == "overlay" ) {
+ self.close();
+ return false;
+ }
+ });
+ },
+
+ refresh: function( forceRebuild ){
+ var self = this,
+ select = this.element,
+ isMultiple = this.isMultiple,
+ options = this.selectOptions = select.find( "option" ),
+ selected = this.selected(),
+ // return an array of all selected index's
+ indicies = this.selectedIndices();
+
+ if ( forceRebuild || select[0].options.length != self.list.find( "li" ).length ) {
+ self._buildList();
+ }
+
+ self.setButtonText();
+ self.setButtonCount();
+
+ self.list.find( "li:not(.ui-li-divider)" )
+ .removeClass( $.mobile.activeBtnClass )
+ .attr( "aria-selected", false )
+ .each(function( i ) {
+
+ if ( $.inArray( i, indicies ) > -1 ) {
+ var item = $( this );
+
+ // Aria selected attr
+ item.attr( "aria-selected", true );
+
+ // Multiple selects: add the "on" checkbox state to the icon
+ if ( self.isMultiple ) {
+ item.find( ".ui-icon" ).removeClass( "ui-icon-checkbox-off" ).addClass( "ui-icon-checkbox-on" );
+ } else {
+ item.addClass( $.mobile.activeBtnClass );
+ }
+ }
+ });
+ },
+
+ close: function() {
+ if ( this.options.disabled || !this.isOpen ) {
+ return;
+ }
+
+ var self = this;
+
+ if ( self.menuType == "page" ) {
+ // TODO centralize page removal binding / handling in the page plugin.
+ // Suggestion from @jblas to do refcounting
+ //
+ // rebind the page remove that was unbound in the open function
+ // to allow for the parent page removal from actions other than the use
+ // of a dialog sized custom select
+ if( !self.thisPage.data("page").options.domCache ){
+ self.thisPage.bind( "pagehide.remove", function() {
+ $(self).remove();
+ });
+ }
+
+ // doesn't solve the possible issue with calling change page
+ // where the objects don't define data urls which prevents dialog key
+ // stripping - changePage has incoming refactor
+ window.history.back();
+ } else {
+ self.screen.addClass( "ui-screen-hidden" );
+ self.listbox.addClass( "ui-selectmenu-hidden" ).removeAttr( "style" ).removeClass( "in" );
+ self.list.appendTo( self.listbox );
+ self._focusButton();
+ }
+
+ // allow the dialog to be closed again
+ self.isOpen = false;
+ },
+
+ open: function() {
+ if ( this.options.disabled ) {
+ return;
+ }
+
+ var self = this,
+ menuHeight = self.list.parent().outerHeight(),
+ menuWidth = self.list.parent().outerWidth(),
+ scrollTop = $( window ).scrollTop(),
+ btnOffset = self.button.offset().top,
+ screenHeight = window.innerHeight,
+ screenWidth = window.innerWidth;
+
+ //add active class to button
+ self.button.addClass( $.mobile.activeBtnClass );
+
+ //remove after delay
+ setTimeout( function() {
+ self.button.removeClass( $.mobile.activeBtnClass );
+ }, 300);
+
+ function focusMenuItem() {
+ self.list.find( $.mobile.activeBtnClass ).focus();
+ }
+
+ if ( menuHeight > screenHeight - 80 || !$.support.scrollTop ) {
+ // prevent the parent page from being removed from the DOM,
+ // otherwise the results of selecting a list item in the dialog
+ // fall into a black hole
+ self.thisPage.unbind( "pagehide.remove" );
+
+ //for webos (set lastscroll using button offset)
+ if ( scrollTop == 0 && btnOffset > screenHeight ) {
+ self.thisPage.one( "pagehide", function() {
+ $( this ).jqmData( "lastScroll", btnOffset );
+ });
+ }
+
+ self.menuPage.one( "pageshow", function() {
+ // silentScroll() is called whenever a page is shown to restore
+ // any previous scroll position the page may have had. We need to
+ // wait for the "silentscroll" event before setting focus to avoid
+ // the browser"s "feature" which offsets rendering to make sure
+ // whatever has focus is in view.
+ $( window ).one( "silentscroll", function() {
+ focusMenuItem();
+ });
+
+ self.isOpen = true;
+ });
+
+ self.menuType = "page";
+ self.menuPageContent.append( self.list );
+ $.mobile.changePage( self.menuPage, {
+ transition: $.mobile.defaultDialogTransition
+ });
+ } else {
+ self.menuType = "overlay";
+
+ self.screen.height( $(document).height() )
+ .removeClass( "ui-screen-hidden" );
+
+ // Try and center the overlay over the button
+ var roomtop = btnOffset - scrollTop,
+ roombot = scrollTop + screenHeight - btnOffset,
+ halfheight = menuHeight / 2,
+ maxwidth = parseFloat( self.list.parent().css( "max-width" ) ),
+ newtop, newleft;
+
+ if ( roomtop > menuHeight / 2 && roombot > menuHeight / 2 ) {
+ newtop = btnOffset + ( self.button.outerHeight() / 2 ) - halfheight;
+ } else {
+ // 30px tolerance off the edges
+ newtop = roomtop > roombot ? scrollTop + screenHeight - menuHeight - 30 : scrollTop + 30;
+ }
+
+ // If the menuwidth is smaller than the screen center is
+ if ( menuWidth < maxwidth ) {
+ newleft = ( screenWidth - menuWidth ) / 2;
+ } else {
+
+ //otherwise insure a >= 30px offset from the left
+ newleft = self.button.offset().left + self.button.outerWidth() / 2 - menuWidth / 2;
+
+ // 30px tolerance off the edges
+ if ( newleft < 30 ) {
+ newleft = 30;
+ } else if ( (newleft + menuWidth) > screenWidth ) {
+ newleft = screenWidth - menuWidth - 30;
+ }
+ }
+
+ self.listbox.append( self.list )
+ .removeClass( "ui-selectmenu-hidden" )
+ .css({
+ top: newtop,
+ left: newleft
+ })
+ .addClass( "in" );
+
+ focusMenuItem();
+
+ // duplicate with value set in page show for dialog sized selects
+ self.isOpen = true;
+ }
+ },
+
+ _buildList: function() {
+ var self = this,
+ o = this.options,
+ placeholder = this.placeholder,
+ optgroups = [],
+ lis = [],
+ dataIcon = self.isMultiple ? "checkbox-off" : "false";
+
+ self.list.empty().filter( ".ui-listview" ).listview( "destroy" );
+
+ // Populate menu with options from select element
+ self.select.find( "option" ).each( function( i ) {
+ var $this = $( this ),
+ $parent = $this.parent(),
+ text = $this.text(),
+ anchor = "<a href='#'>"+ text +"</a>",
+ classes = [],
+ extraAttrs = [];
+
+ // Are we inside an optgroup?
+ if ( $parent.is( "optgroup" ) ) {
+ var optLabel = $parent.attr( "label" );
+
+ // has this optgroup already been built yet?
+ if ( $.inArray( optLabel, optgroups ) === -1 ) {
+ lis.push( "<li data-" + $.mobile.ns + "role='list-divider'>"+ optLabel +"</li>" );
+ optgroups.push( optLabel );
+ }
+ }
+
+ // Find placeholder text
+ // TODO: Are you sure you want to use getAttribute? ^RW
+ if ( !this.getAttribute( "value" ) || text.length == 0 || $this.jqmData( "placeholder" ) ) {
+ if ( o.hidePlaceholderMenuItems ) {
+ classes.push( "ui-selectmenu-placeholder" );
+ }
+ placeholder = self.placeholder = text;
+ }
+
+ // support disabled option tags
+ if ( this.disabled ) {
+ classes.push( "ui-disabled" );
+ extraAttrs.push( "aria-disabled='true'" );
+ }
+
+ lis.push( "<li data-" + $.mobile.ns + "option-index='" + i + "' data-" + $.mobile.ns + "icon='"+ dataIcon +"' class='"+ classes.join(" ") + "' " + extraAttrs.join(" ") +">"+ anchor +"</li>" );
+ });
+
+ self.list.html( lis.join(" ") );
+
+ self.list.find( "li" )
+ .attr({ "role": "option", "tabindex": "-1" })
+ .first().attr( "tabindex", "0" );
+
+ // Hide header close link for single selects
+ if ( !this.isMultiple ) {
+ this.headerClose.hide();
+ }
+
+ // Hide header if it's not a multiselect and there's no placeholder
+ if ( !this.isMultiple && !placeholder.length ) {
+ this.header.hide();
+ } else {
+ this.headerTitle.text( this.placeholder );
+ }
+
+ // Now populated, create listview
+ self.list.listview();
+ },
+
+ _button: function(){
+ return $( "<a>", {
+ "href": "#",
+ "role": "button",
+ // TODO value is undefined at creation
+ "id": this.buttonId,
+ "aria-haspopup": "true",
+
+ // TODO value is undefined at creation
+ "aria-owns": this.menuId
+ });
+ }
+ });
+ };
+
+ $( "select" ).live( "selectmenubeforecreate", function(){
+ var selectmenuWidget = $( this ).data( "selectmenu" );
+
+ if( !selectmenuWidget.options.nativeMenu ){
+ extendSelect( selectmenuWidget );
+ }
+ });
+})( jQuery );
+/*
+* jQuery Mobile Framework : "selectmenu" plugin
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+(function( $, undefined ) {
+
+$.widget( "mobile.selectmenu", $.mobile.widget, {
+ options: {
+ theme: null,
+ disabled: false,
+ icon: "arrow-d",
+ iconpos: "right",
+ inline: null,
+ corners: true,
+ shadow: true,
+ iconshadow: true,
+ menuPageTheme: "b",
+ overlayTheme: "a",
+ hidePlaceholderMenuItems: true,
+ closeText: "Close",
+ nativeMenu: true,
+ initSelector: "select:not(:jqmData(role='slider'))"
+ },
+
+ _button: function(){
+ return $( "<div/>" );
+ },
+
+ _theme: function(){
+ var themedParent, theme;
+ // if no theme is defined, try to find closest theme container
+ // TODO move to core as something like findCurrentTheme
+ themedParent = this.select.closest( "[class*='ui-bar-'], [class*='ui-body-']" );
+ theme = themedParent.length ?
+ /ui-(bar|body)-([a-z])/.exec( themedParent.attr( "class" ) )[2] :
+ "c";
+
+ return theme;
+ },
+
+ _setDisabled: function( value ) {
+ this.element.attr( "disabled", value );
+ this.button.attr( "aria-disabled", value );
+ return this._setOption( "disabled", value );
+ },
+
+ _focusButton : function() {
+ var self = this;
+
+ setTimeout( function() {
+ self.button.focus();
+ }, 40);
+ },
+
+ // setup items that are generally necessary for select menu extension
+ _preExtension: function(){
+ this.select = this.element.wrap( "<div class='ui-select'>" );
+ this.selectID = this.select.attr( "id" );
+ this.label = $( "label[for='"+ this.selectID +"']" ).addClass( "ui-select" );
+ this.isMultiple = this.select[ 0 ].multiple;
+ this.options.theme = this._theme();
+ this.selectOptions = this.select.find( "option" );
+ },
+
+ _create: function() {
+ this._preExtension();
+
+ // Allows for extension of the native select for custom selects and other plugins
+ // see select.custom for example extension
+ // TODO explore plugin registration
+ this._trigger( "beforeCreate" );
+
+ this.button = this._button();
+
+ var self = this,
+
+ options = this.options,
+
+ // IE throws an exception at options.item() function when
+ // there is no selected item
+ // select first in this case
+ selectedIndex = this.select[ 0 ].selectedIndex == -1 ? 0 : this.select[ 0 ].selectedIndex,
+
+ // TODO values buttonId and menuId are undefined here
+ button = this.button
+ .text( $( this.select[ 0 ].options.item( selectedIndex ) ).text() )
+ .insertBefore( this.select )
+ .buttonMarkup( {
+ theme: options.theme,
+ icon: options.icon,
+ iconpos: options.iconpos,
+ inline: options.inline,
+ corners: options.corners,
+ shadow: options.shadow,
+ iconshadow: options.iconshadow
+ });
+
+ // Opera does not properly support opacity on select elements
+ // In Mini, it hides the element, but not its text
+ // On the desktop,it seems to do the opposite
+ // for these reasons, using the nativeMenu option results in a full native select in Opera
+ if ( options.nativeMenu && window.opera && window.opera.version ) {
+ this.select.addClass( "ui-select-nativeonly" );
+ }
+
+ // Add counter for multi selects
+ if ( this.isMultiple ) {
+ this.buttonCount = $( "<span>" )
+ .addClass( "ui-li-count ui-btn-up-c ui-btn-corner-all" )
+ .hide()
+ .appendTo( button );
+ }
+
+ // Disable if specified
+ if ( options.disabled ) {
+ this.disable();
+ }
+
+ // Events on native select
+ this.select.change( function() {
+ self.refresh();
+ });
+
+ this.build();
+ },
+
+ build: function() {
+ var self = this;
+
+ this.select
+ .appendTo( self.button )
+ .bind( "vmousedown", function() {
+ // Add active class to button
+ self.button.addClass( $.mobile.activeBtnClass );
+ })
+ .bind( "focus vmouseover", function() {
+ self.button.trigger( "vmouseover" );
+ })
+ .bind( "vmousemove", function() {
+ // Remove active class on scroll/touchmove
+ self.button.removeClass( $.mobile.activeBtnClass );
+ })
+ .bind( "change blur vmouseout", function() {
+ self.button.trigger( "vmouseout" )
+ .removeClass( $.mobile.activeBtnClass );
+ })
+ .bind( "change blur", function() {
+ self.button.removeClass( "ui-btn-down-" + self.options.theme );
+ });
+ },
+
+ selected: function() {
+ return this.selectOptions.filter( ":selected" );
+ },
+
+ selectedIndices: function() {
+ var self = this;
+
+ return this.selected().map( function() {
+ return self.selectOptions.index( this );
+ }).get();
+ },
+
+ setButtonText: function() {
+ var self = this, selected = this.selected();
+
+ this.button.find( ".ui-btn-text" ).text( function() {
+ if ( !self.isMultiple ) {
+ return selected.text();
+ }
+
+ return selected.length ? selected.map( function() {
+ return $( this ).text();
+ }).get().join( ", " ) : self.placeholder;
+ });
+ },
+
+ setButtonCount: function() {
+ var selected = this.selected();
+
+ // multiple count inside button
+ if ( this.isMultiple ) {
+ this.buttonCount[ selected.length > 1 ? "show" : "hide" ]().text( selected.length );
+ }
+ },
+
+ refresh: function() {
+ this.setButtonText();
+ this.setButtonCount();
+ },
+
+ disable: function() {
+ this._setDisabled( true );
+ this.button.addClass( "ui-disabled" );
+ },
+
+ enable: function() {
+ this._setDisabled( false );
+ this.button.removeClass( "ui-disabled" );
+ }
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+ $( $.mobile.selectmenu.prototype.options.initSelector, e.target )
+ .not( ":jqmData(role='none'), :jqmData(role='nojs')" )
+ .selectmenu();
+});
+})( jQuery );
+/*
+* jQuery Mobile Framework : plugin for making button-like links
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+( function( $, undefined ) {
+
+$.fn.buttonMarkup = function( options ) {
+ return this.each( function() {
+ var el = $( this ),
+ o = $.extend( {}, $.fn.buttonMarkup.defaults, el.jqmData(), options ),
+
+ // Classes Defined
+ innerClass = "ui-btn-inner",
+ buttonClass, iconClass,
+ themedParent, wrap;
+
+ if ( attachEvents ) {
+ attachEvents();
+ }
+
+ // if not, try to find closest theme container
+ if ( !o.theme ) {
+ themedParent = el.closest( "[class*='ui-bar-'],[class*='ui-body-']" );
+ o.theme = themedParent.length ?
+ /ui-(bar|body)-([a-z])/.exec( themedParent.attr( "class" ) )[2] :
+ "c";
+ }
+
+ buttonClass = "ui-btn ui-btn-up-" + o.theme;
+
+ if ( o.inline ) {
+ buttonClass += " ui-btn-inline";
+ }
+
+ if ( o.icon ) {
+ o.icon = "ui-icon-" + o.icon;
+ o.iconpos = o.iconpos || "left";
+
+ iconClass = "ui-icon " + o.icon;
+
+ if ( o.iconshadow ) {
+ iconClass += " ui-icon-shadow";
+ }
+ }
+
+ if ( o.iconpos ) {
+ buttonClass += " ui-btn-icon-" + o.iconpos;
+
+ if ( o.iconpos == "notext" && !el.attr( "title" ) ) {
+ el.attr( "title", el.text() );
+ }
+ }
+
+ if ( o.corners ) {
+ buttonClass += " ui-btn-corner-all";
+ innerClass += " ui-btn-corner-all";
+ }
+
+ if ( o.shadow ) {
+ buttonClass += " ui-shadow";
+ }
+
+ el.attr( "data-" + $.mobile.ns + "theme", o.theme )
+ .addClass( buttonClass );
+
+ wrap = ( "<D class='" + innerClass + "'><D class='ui-btn-text'></D>" +
+ ( o.icon ? "<span class='" + iconClass + "'></span>" : "" ) +
+ "</D>" ).replace( /D/g, o.wrapperEls );
+
+ el.wrapInner( wrap );
+ });
+};
+
+$.fn.buttonMarkup.defaults = {
+ corners: true,
+ shadow: true,
+ iconshadow: true,
+ wrapperEls: "span"
+};
+
+function closestEnabledButton( element ) {
+ while ( element ) {
+ var $ele = $( element );
+ if ( $ele.hasClass( "ui-btn" ) && !$ele.hasClass( "ui-disabled" ) ) {
+ break;
+ }
+ element = element.parentNode;
+ }
+ return element;
+}
+
+var attachEvents = function() {
+ $( document ).bind( {
+ "vmousedown": function( event ) {
+ var btn = closestEnabledButton( event.target ),
+ $btn, theme;
+
+ if ( btn ) {
+ $btn = $( btn );
+ theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
+ $btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-down-" + theme );
+ }
+ },
+ "vmousecancel vmouseup": function( event ) {
+ var btn = closestEnabledButton( event.target ),
+ $btn, theme;
+
+ if ( btn ) {
+ $btn = $( btn );
+ theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
+ $btn.removeClass( "ui-btn-down-" + theme ).addClass( "ui-btn-up-" + theme );
+ }
+ },
+ "vmouseover focus": function( event ) {
+ var btn = closestEnabledButton( event.target ),
+ $btn, theme;
+
+ if ( btn ) {
+ $btn = $( btn );
+ theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
+ $btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-hover-" + theme );
+ }
+ },
+ "vmouseout blur": function( event ) {
+ var btn = closestEnabledButton( event.target ),
+ $btn, theme;
+
+ if ( btn ) {
+ $btn = $( btn );
+ theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
+ $btn.removeClass( "ui-btn-hover-" + theme ).addClass( "ui-btn-up-" + theme );
+ }
+ }
+ });
+
+ attachEvents = null;
+};
+
+//links in bars, or those with data-role become buttons
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+
+ $( ":jqmData(role='button'), .ui-bar > a, .ui-header > a, .ui-footer > a, .ui-bar > :jqmData(role='controlgroup') > a", e.target )
+ .not( ".ui-btn, :jqmData(role='none'), :jqmData(role='nojs')" )
+ .buttonMarkup();
+});
+
+})( jQuery );
+/*
+* jQuery Mobile Framework: "controlgroup" plugin - corner-rounding for groups of buttons, checks, radios, etc
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function( $, undefined ) {
+
+$.fn.controlgroup = function( options ) {
+
+ return this.each(function() {
+
+ var $el = $( this ),
+ o = $.extend({
+ direction: $el.jqmData( "type" ) || "vertical",
+ shadow: false,
+ excludeInvisible: true
+ }, options ),
+ groupheading = $el.find( ">legend" ),
+ flCorners = o.direction == "horizontal" ? [ "ui-corner-left", "ui-corner-right" ] : [ "ui-corner-top", "ui-corner-bottom" ],
+ type = $el.find( "input:eq(0)" ).attr( "type" );
+
+ // Replace legend with more stylable replacement div
+ if ( groupheading.length ) {
+ $el.wrapInner( "<div class='ui-controlgroup-controls'></div>" );
+ $( "<div role='heading' class='ui-controlgroup-label'>" + groupheading.html() + "</div>" ).insertBefore( $el.children(0) );
+ groupheading.remove();
+ }
+
+ $el.addClass( "ui-corner-all ui-controlgroup ui-controlgroup-" + o.direction );
+
+ // TODO: This should be moved out to the closure
+ // otherwise it is redefined each time controlgroup() is called
+ function flipClasses( els ) {
+ els.removeClass( "ui-btn-corner-all ui-shadow" )
+ .eq( 0 ).addClass( flCorners[ 0 ] )
+ .end()
+ .filter( ":last" ).addClass( flCorners[ 1 ] ).addClass( "ui-controlgroup-last" );
+ }
+
+ flipClasses( $el.find( ".ui-btn" + ( o.excludeInvisible ? ":visible" : "" ) ) );
+ flipClasses( $el.find( ".ui-btn-inner" ) );
+
+ if ( o.shadow ) {
+ $el.addClass( "ui-shadow" );
+ }
+ });
+};
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+ $( ":jqmData(role='controlgroup')", e.target ).controlgroup({ excludeInvisible: false });
+});
+
+})(jQuery);/*
+* jQuery Mobile Framework : "fieldcontain" plugin - simple class additions to make form row separators
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+(function( $, undefined ) {
+
+$( document ).bind( "pagecreate create", function( e ){
+
+ //links within content areas
+ $( e.target )
+ .find( "a" )
+ .not( ".ui-btn, .ui-link-inherit, :jqmData(role='none'), :jqmData(role='nojs')" )
+ .addClass( "ui-link" );
+
+});
+
+})( jQuery );/*
+* jQuery Mobile Framework : "fixHeaderFooter" plugin - on-demand positioning for headers,footers
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+(function( $, undefined ) {
+
+var slideDownClass = "ui-header-fixed ui-fixed-inline fade",
+ slideUpClass = "ui-footer-fixed ui-fixed-inline fade",
+
+ slideDownSelector = ".ui-header:jqmData(position='fixed')",
+ slideUpSelector = ".ui-footer:jqmData(position='fixed')";
+
+$.fn.fixHeaderFooter = function( options ) {
+
+ if ( !$.support.scrollTop ) {
+ return this;
+ }
+
+ return this.each(function() {
+ var $this = $( this );
+
+ if ( $this.jqmData( "fullscreen" ) ) {
+ $this.addClass( "ui-page-fullscreen" );
+ }
+
+ // Should be slidedown
+ $this.find( slideDownSelector ).addClass( slideDownClass );
+
+ // Should be slideup
+ $this.find( slideUpSelector ).addClass( slideUpClass );
+ });
+};
+
+// single controller for all showing,hiding,toggling
+$.mobile.fixedToolbars = (function() {
+
+ if ( !$.support.scrollTop || $.support.touchOverflow ) {
+ return;
+ }
+
+ var stickyFooter, delayTimer,
+ currentstate = "inline",
+ autoHideMode = false,
+ showDelay = 100,
+ ignoreTargets = "a,input,textarea,select,button,label,.ui-header-fixed,.ui-footer-fixed",
+ toolbarSelector = ".ui-header-fixed:first, .ui-footer-fixed:not(.ui-footer-duplicate):last",
+ // for storing quick references to duplicate footers
+ supportTouch = $.support.touch,
+ touchStartEvent = supportTouch ? "touchstart" : "mousedown",
+ touchStopEvent = supportTouch ? "touchend" : "mouseup",
+ stateBefore = null,
+ scrollTriggered = false,
+ touchToggleEnabled = true;
+
+ function showEventCallback( event ) {
+ // An event that affects the dimensions of the visual viewport has
+ // been triggered. If the header and/or footer for the current page are in overlay
+ // mode, we want to hide them, and then fire off a timer to show them at a later
+ // point. Events like a resize can be triggered continuously during a scroll, on
+ // some platforms, so the timer is used to delay the actual positioning until the
+ // flood of events have subsided.
+ //
+ // If we are in autoHideMode, we don't do anything because we know the scroll
+ // callbacks for the plugin will fire off a show when the scrolling has stopped.
+ if ( !autoHideMode && currentstate === "overlay" ) {
+ if ( !delayTimer ) {
+ $.mobile.fixedToolbars.hide( true );
+ }
+
+ $.mobile.fixedToolbars.startShowTimer();
+ }
+ }
+
+ $(function() {
+ var $document = $( document ),
+ $window = $( window );
+
+ $document
+ .bind( "vmousedown", function( event ) {
+ if ( touchToggleEnabled ) {
+ stateBefore = currentstate;
+ }
+ })
+ .bind( "vclick", function( event ) {
+ if ( touchToggleEnabled ) {
+
+ if ( $(event.target).closest( ignoreTargets ).length ) {
+ return;
+ }
+
+ if ( !scrollTriggered ) {
+ $.mobile.fixedToolbars.toggle( stateBefore );
+ stateBefore = null;
+ }
+ }
+ })
+ .bind( "silentscroll", showEventCallback );
+
+
+ // The below checks first for a $(document).scrollTop() value, and if zero, binds scroll events to $(window) instead.
+ // If the scrollTop value is actually zero, both will return zero anyway.
+ //
+ // Works with $(document), not $(window) : Opera Mobile (WinMO phone; kinda broken anyway)
+ // Works with $(window), not $(document) : IE 7/8
+ // Works with either $(window) or $(document) : Chrome, FF 3.6/4, Android 1.6/2.1, iOS
+ // Needs work either way : BB5, Opera Mobile (iOS)
+
+ ( ( $document.scrollTop() === 0 ) ? $window : $document )
+ .bind( "scrollstart", function( event ) {
+
+ scrollTriggered = true;
+
+ if ( stateBefore === null ) {
+ stateBefore = currentstate;
+ }
+
+ // We only enter autoHideMode if the headers/footers are in
+ // an overlay state or the show timer was started. If the
+ // show timer is set, clear it so the headers/footers don't
+ // show up until after we're done scrolling.
+ var isOverlayState = stateBefore == "overlay";
+
+ autoHideMode = isOverlayState || !!delayTimer;
+
+ if ( autoHideMode ) {
+ $.mobile.fixedToolbars.clearShowTimer();
+
+ if ( isOverlayState ) {
+ $.mobile.fixedToolbars.hide( true );
+ }
+ }
+ })
+ .bind( "scrollstop", function( event ) {
+
+ if ( $( event.target ).closest( ignoreTargets ).length ) {
+ return;
+ }
+
+ scrollTriggered = false;
+
+ if ( autoHideMode ) {
+ $.mobile.fixedToolbars.startShowTimer();
+ autoHideMode = false;
+ }
+ stateBefore = null;
+ });
+
+ $window.bind( "resize", showEventCallback );
+ });
+
+ // 1. Before page is shown, check for duplicate footer
+ // 2. After page is shown, append footer to new page
+ $( ".ui-page" )
+ .live( "pagebeforeshow", function( event, ui ) {
+
+ var page = $( event.target ),
+ footer = page.find( ":jqmData(role='footer')" ),
+ id = footer.data( "id" ),
+ prevPage = ui.prevPage,
+ prevFooter = prevPage && prevPage.find( ":jqmData(role='footer')" ),
+ prevFooterMatches = prevFooter.length && prevFooter.jqmData( "id" ) === id;
+
+ if ( id && prevFooterMatches ) {
+ stickyFooter = footer;
+ setTop( stickyFooter.removeClass( "fade in out" ).appendTo( $.mobile.pageContainer ) );
+ }
+ })
+ .live( "pageshow", function( event, ui ) {
+
+ var $this = $( this );
+
+ if ( stickyFooter && stickyFooter.length ) {
+
+ setTimeout(function() {
+ setTop( stickyFooter.appendTo( $this ).addClass( "fade" ) );
+ stickyFooter = null;
+ }, 500);
+ }
+
+ $.mobile.fixedToolbars.show( true, this );
+ });
+
+ // When a collapsiable is hidden or shown we need to trigger the fixed toolbar to reposition itself (#1635)
+ $( ".ui-collapsible-contain" ).live( "collapse expand", showEventCallback );
+
+ // element.getBoundingClientRect() is broken in iOS 3.2.1 on the iPad. The
+ // coordinates inside of the rect it returns don't have the page scroll position
+ // factored out of it like the other platforms do. To get around this,
+ // we'll just calculate the top offset the old fashioned way until core has
+ // a chance to figure out how to handle this situation.
+ //
+ // TODO: We'll need to get rid of getOffsetTop() once a fix gets folded into core.
+
+ function getOffsetTop( ele ) {
+ var top = 0,
+ op, body;
+
+ if ( ele ) {
+ body = document.body;
+ op = ele.offsetParent;
+ top = ele.offsetTop;
+
+ while ( ele && ele != body ) {
+ top += ele.scrollTop || 0;
+
+ if ( ele == op ) {
+ top += op.offsetTop;
+ op = ele.offsetParent;
+ }
+
+ ele = ele.parentNode;
+ }
+ }
+ return top;
+ }
+
+ function setTop( el ) {
+ var fromTop = $(window).scrollTop(),
+ thisTop = getOffsetTop( el[ 0 ] ), // el.offset().top returns the wrong value on iPad iOS 3.2.1, call our workaround instead.
+ thisCSStop = el.css( "top" ) == "auto" ? 0 : parseFloat(el.css( "top" )),
+ screenHeight = window.innerHeight,
+ thisHeight = el.outerHeight(),
+ useRelative = el.parents( ".ui-page:not(.ui-page-fullscreen)" ).length,
+ relval;
+
+ if ( el.is( ".ui-header-fixed" ) ) {
+
+ relval = fromTop - thisTop + thisCSStop;
+
+ if ( relval < thisTop ) {
+ relval = 0;
+ }
+
+ return el.css( "top", useRelative ? relval : fromTop );
+ } else {
+ // relval = -1 * (thisTop - (fromTop + screenHeight) + thisCSStop + thisHeight);
+ // if ( relval > thisTop ) { relval = 0; }
+ relval = fromTop + screenHeight - thisHeight - (thisTop - thisCSStop );
+
+ return el.css( "top", useRelative ? relval : fromTop + screenHeight - thisHeight );
+ }
+ }
+
+ // Exposed methods
+ return {
+
+ show: function( immediately, page ) {
+
+ $.mobile.fixedToolbars.clearShowTimer();
+
+ currentstate = "overlay";
+
+ var $ap = page ? $( page ) :
+ ( $.mobile.activePage ? $.mobile.activePage :
+ $( ".ui-page-active" ) );
+
+ return $ap.children( toolbarSelector ).each(function() {
+
+ var el = $( this ),
+ fromTop = $( window ).scrollTop(),
+ // el.offset().top returns the wrong value on iPad iOS 3.2.1, call our workaround instead.
+ thisTop = getOffsetTop( el[ 0 ] ),
+ screenHeight = window.innerHeight,
+ thisHeight = el.outerHeight(),
+ alreadyVisible = ( el.is( ".ui-header-fixed" ) && fromTop <= thisTop + thisHeight ) ||
+ ( el.is( ".ui-footer-fixed" ) && thisTop <= fromTop + screenHeight );
+
+ // Add state class
+ el.addClass( "ui-fixed-overlay" ).removeClass( "ui-fixed-inline" );
+
+ if ( !alreadyVisible && !immediately ) {
+ el.animationComplete(function() {
+ el.removeClass( "in" );
+ }).addClass( "in" );
+ }
+ setTop(el);
+ });
+ },
+
+ hide: function( immediately ) {
+
+ currentstate = "inline";
+
+ var $ap = $.mobile.activePage ? $.mobile.activePage :
+ $( ".ui-page-active" );
+
+ return $ap.children( toolbarSelector ).each(function() {
+
+ var el = $(this),
+ thisCSStop = el.css( "top" ),
+ classes;
+
+ thisCSStop = thisCSStop == "auto" ? 0 :
+ parseFloat(thisCSStop);
+
+ // Add state class
+ el.addClass( "ui-fixed-inline" ).removeClass( "ui-fixed-overlay" );
+
+ if ( thisCSStop < 0 || ( el.is( ".ui-header-fixed" ) && thisCSStop !== 0 ) ) {
+
+ if ( immediately ) {
+ el.css( "top", 0);
+ } else {
+
+ if ( el.css( "top" ) !== "auto" && parseFloat( el.css( "top" ) ) !== 0 ) {
+
+ classes = "out reverse";
+
+ el.animationComplete(function() {
+ el.removeClass( classes ).css( "top", 0 );
+ }).addClass( classes );
+ }
+ }
+ }
+ });
+ },
+
+ startShowTimer: function() {
+
+ $.mobile.fixedToolbars.clearShowTimer();
+
+ var args = [].slice.call( arguments );
+
+ delayTimer = setTimeout(function() {
+ delayTimer = undefined;
+ $.mobile.fixedToolbars.show.apply( null, args );
+ }, showDelay);
+ },
+
+ clearShowTimer: function() {
+ if ( delayTimer ) {
+ clearTimeout( delayTimer );
+ }
+ delayTimer = undefined;
+ },
+
+ toggle: function( from ) {
+ if ( from ) {
+ currentstate = from;
+ }
+ return ( currentstate === "overlay" ) ? $.mobile.fixedToolbars.hide() :
+ $.mobile.fixedToolbars.show();
+ },
+
+ setTouchToggleEnabled: function( enabled ) {
+ touchToggleEnabled = enabled;
+ }
+ };
+})();
+
+// TODO - Deprecated namepace on $. Remove in a later release
+$.fixedToolbars = $.mobile.fixedToolbars;
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( event ) {
+
+ if ( $( ":jqmData(position='fixed')", event.target ).length ) {
+
+ $( event.target ).each(function() {
+
+ if ( !$.support.scrollTop || $.support.touchOverflow ) {
+ return this;
+ }
+
+ var $this = $( this );
+
+ if ( $this.jqmData( "fullscreen" ) ) {
+ $this.addClass( "ui-page-fullscreen" );
+ }
+
+ // Should be slidedown
+ $this.find( slideDownSelector ).addClass( slideDownClass );
+
+ // Should be slideup
+ $this.find( slideUpSelector ).addClass( slideUpClass );
+
+ })
+
+ }
+});
+
+})( jQuery );
+/*
+* jQuery Mobile Framework : "fixHeaderFooter" native plugin - Behavior for "fixed" headers,footers, and scrolling inner content
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+(function( $, undefined ) {
+
+$.mobile.touchOverflowEnabled = false;
+
+$( document ).bind( "pagecreate", function( event ) {
+ if( $.support.touchOverflow && $.mobile.touchOverflowEnabled ){
+
+ var $target = $( event.target ),
+ scrollStartY = 0;
+
+ if( $target.is( ":jqmData(role='page')" ) ){
+
+ $target.each(function() {
+ var $page = $( this ),
+ $fixies = $page.find( ":jqmData(role='header'), :jqmData(role='footer')" ).filter( ":jqmData(position='fixed')" ),
+ fullScreen = $page.jqmData( "fullscreen" ),
+ $scrollElem = $fixies.length ? $page.find( ".ui-content" ) : $page;
+
+ $page.addClass( "ui-mobile-touch-overflow" );
+
+ $scrollElem.bind( "scrollstop", function(){
+ if( $scrollElem.scrollTop() > 0 ){
+ window.scrollTo( 0, $.mobile.defaultHomeScroll );
+ }
+ });
+
+ if( $fixies.length ){
+
+ $page.addClass( "ui-native-fixed" );
+
+ if( fullScreen ){
+
+ $page.addClass( "ui-native-fullscreen" );
+
+ $fixies.addClass( "fade in" );
+
+ $( document ).bind( "vclick", function(){
+ $fixies
+ .removeClass( "ui-native-bars-hidden" )
+ .toggleClass( "in out" )
+ .animationComplete(function(){
+ $(this).not( ".in" ).addClass( "ui-native-bars-hidden" );
+ });
+ });
+ }
+ }
+ });
+ }
+ }
+});
+
+})( jQuery );
+/*
+* jQuery Mobile Framework : resolution and CSS media query related helpers and behavior
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function( $, undefined ) {
+
+var $window = $( window ),
+ $html = $( "html" ),
+
+ //media-query-like width breakpoints, which are translated to classes on the html element
+ resolutionBreakpoints = [ 320, 480, 768, 1024 ];
+
+/*
+ private function for adding/removing breakpoint classes to HTML element for faux media-query support
+ It does not require media query support, instead using JS to detect screen width > cross-browser support
+ This function is called on orientationchange, resize, and mobileinit, and is bound via the 'htmlclass' event namespace
+*/
+function detectResolutionBreakpoints() {
+ var currWidth = $window.width(),
+ minPrefix = "min-width-",
+ maxPrefix = "max-width-",
+ minBreakpoints = [],
+ maxBreakpoints = [],
+ unit = "px",
+ breakpointClasses;
+
+ $html.removeClass( minPrefix + resolutionBreakpoints.join(unit + " " + minPrefix) + unit + " " +
+ maxPrefix + resolutionBreakpoints.join( unit + " " + maxPrefix) + unit );
+
+ $.each( resolutionBreakpoints, function( i, breakPoint ) {
+ if( currWidth >= breakPoint ) {
+ minBreakpoints.push( minPrefix + breakPoint + unit );
+ }
+ if( currWidth <= breakPoint ) {
+ maxBreakpoints.push( maxPrefix + breakPoint + unit );
+ }
+ });
+
+ if ( minBreakpoints.length ) {
+ breakpointClasses = minBreakpoints.join(" ");
+ }
+ if ( maxBreakpoints.length ) {
+ breakpointClasses += " " + maxBreakpoints.join(" ");
+ }
+
+ $html.addClass( breakpointClasses );
+};
+
+/* $.mobile.addResolutionBreakpoints method:
+ pass either a number or an array of numbers and they'll be added to the min/max breakpoint classes
+ Examples:
+ $.mobile.addResolutionBreakpoints( 500 );
+ $.mobile.addResolutionBreakpoints( [500, 1200] );
+*/
+$.mobile.addResolutionBreakpoints = function( newbps ) {
+ if( $.type( newbps ) === "array" ){
+ resolutionBreakpoints = resolutionBreakpoints.concat( newbps );
+ } else {
+ resolutionBreakpoints.push( newbps );
+ }
+
+ resolutionBreakpoints.sort(function( a, b ) {
+ return a - b;
+ });
+
+ detectResolutionBreakpoints();
+};
+
+/* on mobileinit, add classes to HTML element
+ and set handlers to update those on orientationchange and resize
+*/
+$( document ).bind( "mobileinit.htmlclass", function() {
+ // bind to orientationchange and resize
+ // to add classes to HTML element for min/max breakpoints and orientation
+
+ var ev = $.support.orientation;
+
+ $window.bind( "orientationchange.htmlclass throttledresize.htmlclass", function( event ) {
+
+ // add orientation class to HTML element on flip/resize.
+ if ( event.orientation ) {
+ $html.removeClass( "portrait landscape" ).addClass( event.orientation );
+ }
+
+ // add classes to HTML element for min/max breakpoints
+ detectResolutionBreakpoints();
+ });
+});
+
+/* Manually trigger an orientationchange event when the dom ready event fires.
+ This will ensure that any viewport meta tag that may have been injected
+ has taken effect already, allowing us to properly calculate the width of the
+ document.
+*/
+$(function() {
+ //trigger event manually
+ $window.trigger( "orientationchange.htmlclass" );
+});
+
+})(jQuery);/*!
+ * jQuery Mobile v@VERSION
+ * http://jquerymobile.com/
+ *
+ * Copyright 2010, jQuery Project
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ */
+
+(function( $, window, undefined ) {
+ var $html = $( "html" ),
+ $head = $( "head" ),
+ $window = $( window );
+
+ // trigger mobileinit event - useful hook for configuring $.mobile settings before they're used
+ $( window.document ).trigger( "mobileinit" );
+
+ // support conditions
+ // if device support condition(s) aren't met, leave things as they are -> a basic, usable experience,
+ // otherwise, proceed with the enhancements
+ if ( !$.mobile.gradeA() ) {
+ return;
+ }
+
+ // override ajaxEnabled on platforms that have known conflicts with hash history updates
+ // or generally work better browsing in regular http for full page refreshes (BB5, Opera Mini)
+ if ( $.mobile.ajaxBlacklist ) {
+ $.mobile.ajaxEnabled = false;
+ }
+
+ // add mobile, initial load "rendering" classes to docEl
+ $html.addClass( "ui-mobile ui-mobile-rendering" );
+
+ // loading div which appears during Ajax requests
+ // will not appear if $.mobile.loadingMessage is false
+ var $loader = $( "<div class='ui-loader ui-body-a ui-corner-all'><span class='ui-icon ui-icon-loading spin'></span><h1></h1></div>" );
+
+ $.extend($.mobile, {
+ // turn on/off page loading message.
+ showPageLoadingMsg: function() {
+ if ( $.mobile.loadingMessage ) {
+ var activeBtn = $( "." + $.mobile.activeBtnClass ).first();
+
+ $loader
+ .find( "h1" )
+ .text( $.mobile.loadingMessage )
+ .end()
+ .appendTo( $.mobile.pageContainer )
+ // position at y center (if scrollTop supported), above the activeBtn (if defined), or just 100px from top
+ .css({
+ top: $.support.scrollTop && $window.scrollTop() + $window.height() / 2 ||
+ activeBtn.length && activeBtn.offset().top || 100
+ });
+ }
+
+ $html.addClass( "ui-loading" );
+ },
+
+ hidePageLoadingMsg: function() {
+ $html.removeClass( "ui-loading" );
+ },
+
+ // XXX: deprecate for 1.0
+ pageLoading: function ( done ) {
+ if ( done ) {
+ $.mobile.hidePageLoadingMsg();
+ } else {
+ $.mobile.showPageLoadingMsg();
+ }
+ },
+
+ // find and enhance the pages in the dom and transition to the first page.
+ initializePage: function() {
+ // find present pages
+ var $pages = $( ":jqmData(role='page')" );
+
+ // if no pages are found, create one with body's inner html
+ if ( !$pages.length ) {
+ $pages = $( "body" ).wrapInner( "<div data-" + $.mobile.ns + "role='page'></div>" ).children( 0 );
+ }
+
+ // add dialogs, set data-url attrs
+ $pages.add( ":jqmData(role='dialog')" ).each(function() {
+ var $this = $(this);
+
+ // unless the data url is already set set it to the pathname
+ if ( !$this.jqmData("url") ) {
+ $this.attr( "data-" + $.mobile.ns + "url", $this.attr( "id" ) || location.pathname + location.search );
+ }
+ });
+
+ // define first page in dom case one backs out to the directory root (not always the first page visited, but defined as fallback)
+ $.mobile.firstPage = $pages.first();
+
+ // define page container
+ $.mobile.pageContainer = $pages.first().parent().addClass( "ui-mobile-viewport" );
+
+ // cue page loading message
+ $.mobile.showPageLoadingMsg();
+
+ // if hashchange listening is disabled or there's no hash deeplink, change to the first page in the DOM
+ if ( !$.mobile.hashListeningEnabled || !$.mobile.path.stripHash( location.hash ) ) {
+ $.mobile.changePage( $.mobile.firstPage, { transition: "none", reverse: true, changeHash: false, fromHashChange: true } );
+ }
+ // otherwise, trigger a hashchange to load a deeplink
+ else {
+ $window.trigger( "hashchange", [ true ] );
+ }
+ }
+ });
+
+ // initialize events now, after mobileinit has occurred
+ $.mobile._registerInternalEvents();
+
+ // check which scrollTop value should be used by scrolling to 1 immediately at domready
+ // then check what the scroll top is. Android will report 0... others 1
+ // note that this initial scroll won't hide the address bar. It's just for the check.
+ $(function() {
+ window.scrollTo( 0, 1 );
+
+ // if defaultHomeScroll hasn't been set yet, see if scrollTop is 1
+ // it should be 1 in most browsers, but android treats 1 as 0 (for hiding addr bar)
+ // so if it's 1, use 0 from now on
+ $.mobile.defaultHomeScroll = ( !$.support.scrollTop || $(window).scrollTop() === 1 ) ? 0 : 1;
+
+ //dom-ready inits
+ if( $.mobile.autoInitializePage ){
+ $.mobile.initializePage();
+ }
+
+ // window load event
+ // hide iOS browser chrome on load
+ $window.load( $.mobile.silentScroll );
+ });
+})( jQuery, this );
+
--- a/labs/index.php
+++ b/labs/index.php
@@ -1,29 +1,16 @@
<?php
include ('../include/common.inc.php');
-include_header("Busness R&D", "index")
+
+include_header("Busness R&D", "index");
?>
<ul data-role="listview" data-theme="e" data-groupingtheme="e">
<li data-role="list-divider" > Experimental Features </li>
- <li><a href="mywaybalance.php"><h3>MyWay Balance for mobile</h3>
- <p>Mobile viewer for MyWay balance. Warning! No HTTPS security.</p></a></li>
<li><a href="busstopdensity.php"><h3>Bus Stop Density Map</h3>
<p>Analysis of bus stop coverage</p></a></li>
<li><a href="stopBrowser.php"><h3>Bus Stop Browser Map</h3>
<p>Bus stop location/route browser</p></a></li>
</ul>
- <ul data-role="listview" data-theme="e" data-groupingtheme="e">
-
- <li data-role="list-divider" > MyWay Timeliness Graphs </li>
- <li><a href="myway_timeliness.php"><h3>Timeliness over Day</h3>
- <p>Displays the deviation from the timetable over the day</p></a></li>
- <li><a href="myway_timeliness_freqdist.php"><h3>Frequency Distribution of Time Deviation</h3>
- <p>Displays spread of time deviations</p></a></li>
- <li><a href="myway_timeliness_route.php"><h3>Timeliness over Route</h3>
- <p>Displays the deviation from timetable as a specific route progresses</p></a></li>
- <li><a href="myway_timeliness_stop.php"><h3>Timeliness at Stop</h3>
- <p>Displays the deviation from the timetable at a specific stop</p></a></li>
- </ul>
- </div>
+ </div>
<?php
include_footer()
?>
--- a/labs/myway_api.json.php
+++ /dev/null
@@ -1,141 +1,1 @@
-<?php
-function cleanString($subject)
-{
- $subject = str_replace(" ", " ", $subject);
- $subject = str_replace("&", "&", $subject);
- $subject = preg_replace('/[^\r\n\t\x20-\x7E\xA0-\xFF]/', '', $subject);
- $subject = str_replace(" ", " ", $subject);
- return trim($subject);
-}
-$return = Array();
-/*if (file_exists("mywayresponse.txt")) {
- @$fh = fopen("mywayresponse.txt", 'r');
- if ($fh) {
- $pageHTML = fread($fh, filesize("mywayresponse.txt"));
- fclose($fh);
- }
-}*/
-//set POST variables
-$url = 'https://www.action.act.gov.au/ARTS/use_Funcs.asp';
-//$url = 'http://localhost/myway.htm';
-$field_mapping = Array(
- "card_number" => "SRNO",
- "DOBmonth" => "month",
- "DOBday" => "day",
- "DOByear" => "year",
- "secret_answer" => "pwrd",
- "button" => "Submit"
-);
-foreach (Array(
- "card_number",
- "DOBday",
- "DOBmonth",
- "DOByear"
-) as $field_name) {
- if (isset($_REQUEST[$field_name])) {
- $fields[$field_name] = filter_var($_REQUEST[$field_name], FILTER_SANITIZE_NUMBER_INT);
- }
- else {
- $return["error"][] = $field_name. " parameter invalid or unspecified";
- }
-}
-if (isset($_REQUEST['secret_answer'])) {
- $fields['secret_answer'] = filter_var($_REQUEST['secret_answer'], FILTER_SANITIZE_STRING, Array(
- FILTER_FLAG_NO_ENCODE_QUOTES,
- FILTER_FLAG_STRIP_HIGH,
- FILTER_FLAG_STRIP_LOW
- ));
-}
-else {
- $return["error"][] = "secret_answer parameter invalid or unspecified";
-}
-$fields['button'] = 'Submit';
-$fields_string = "";
-//url-ify the data for the POST
-foreach ($fields as $key => $value) {
- if (sizeof($value) === 0) $return['error'][] = $key . " parameter invalid or unspecified";
- $fields_string.= $field_mapping[$key] . '=' . $value . '&';
-}
-$fields_string = rtrim($fields_string, '&');
-if (!isset($return['error'])) {
- //open connection
- $ch = curl_init();
- //set the url, number of POST vars, POST data
- curl_setopt($ch, CURLOPT_URL, $url);
- curl_setopt($ch, CURLOPT_POST, count($fields));
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
- curl_setopt($ch, CURLOPT_REFERER, "https://www.action.act.gov.au/ARTS/getbalance.asp");
- curl_setopt($ch, CURLOPT_HEADER, 0);
- curl_setopt($ch, CURLOPT_TIMEOUT, 30);
- //execute post
- $pageHTML = curl_exec($ch);
- if (curl_errno($ch)) $return["error"][] = "Network error " . curl_errno($ch) . " " . curl_error($ch) . " " . $url . $fields_string;
- //close connection
- curl_close($ch);
-}
-if (!isset($return['error'])) {
- include_once ('../lib/simple_html_dom.php');
- //print_r($pageHTML);
- $page = str_get_html($pageHTML);
- $pageAlerts = $page->find(".smartCardAlert");
- if (sizeof($pageAlerts) > 0) {
- $return['error'][] = $pageAlerts[0]->plaintext;
- }
- if (!isset($return['error'])) {
- $tableNum = 0;
- $tableName = Array(
- 1 => "myway_carddetails",
- 2 => "myway_transactions"
- );
- foreach ($page->find("table") as $table) {
- $tableNum++;
- $tableColumns = Array();
- $tableColumnNum = 0;
- foreach ($table->find("th") as $th) {
- $tableColumns[$tableColumnNum] = cleanString($th->plaintext);
- $tableColumnNum++;
- }
- //print_r($tableColumns);
- $tableRowNum = 0;
- foreach ($table->find("tr") as $tr) {
- $tableColumnNum = 0;
- foreach ($tr->find("td") as $td) {
- if ($tableNum == 1) {
- // first table has card/cardholder details
- $return[$tableName[$tableNum]][$tableColumns[$tableColumnNum]] = cleanString($td->plaintext);
- } else {
- // second table has transactions
-
- if ($tableColumns[$tableColumnNum] == "TX Reference No / Type") {
- $return[$tableName[$tableNum]][$tableRowNum]["TX Reference No"] = substr(cleanString($td->plaintext), 0,6);
- $return[$tableName[$tableNum]][$tableRowNum]["TX Type"] = substr(cleanString($td->plaintext), 7);
- } else {
- $return[$tableName[$tableNum]][$tableRowNum][$tableColumns[$tableColumnNum]] = cleanString($td->plaintext);
- }
- }
- //print_r($return);
- $tableColumnNum++;
- }
- $tableRowNum++;
- }
- }
- }
-}
-if (sizeof($return) == 0) {
-$return['error'][] = "No data extracted from MyWay website - API may be out of date";
-}
-
-header('Content-Type: text/javascript; charset=utf8');
-// header('Access-Control-Allow-Origin: http://bus.lambdacomplex.org/');
-header('Access-Control-Max-Age: 3628800');
-header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
-if (isset($_GET['callback'])) {
- $json = '(' . json_encode($return) . ');'; //must wrap in parens and end with semicolon
- print_r($_GET['callback'] . $json); //callback is prepended for json-p
-
-}
-else echo json_encode($return);
-?>
-
--- a/labs/myway_timeliness.php
+++ /dev/null
@@ -1,118 +1,1 @@
-<?php
-include ('../include/common.inc.php');
-include_header("MyWay Deltas", "mywayDelta");
-?>
- <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../js/flot/excanvas.min.js"></script><![endif]-->
-
- <script language="javascript" type="text/javascript" src="../js/flot/jquery.flot.js"></script>
- <center><div id="placeholder" style="width:900px;height:550px"></div></center>
-<script type="text/javascript">
-$(function () {
- var d = new Date();
- d.setUTCMinutes(0);
- d.setUTCHours(0);
- var midnight = d.getTime();
-
-<?php
-$query = "select * from myway_timingdeltas where abs(timing_delta) < 2*(select stddev(timing_delta) from myway_timingdeltas) order by route_full_name;";
-$query = $conn->prepare($query);
-$query->execute();
-if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
-}
-$i = 0;
-$labels = Array();
-$lastRoute = "";
-foreach ($query->fetchAll() as $delta) {
- $routeName = $delta['route_full_name'];
- if (strstr($routeName, " 3")) $routeName = "312-319";
- else $routeName = preg_replace('/\D/', '', $routeName);
- if ($routeName != $lastRoute) {
- $i++;
- echo " var d$i = [];";
- $lastRoute = $routeName;
- $labels[$i] = $routeName;
- }
- echo "d$i.push([ midnight+ (1000*" . midnight_seconds(strtotime($delta['time'])) . "), ".intval($delta['timing_delta'])."]); \n";
-};
-?>
-
- var placeholder = $("#placeholder");
-
- var plot = $.plot(placeholder, [
-<?php
-foreach ($labels as $key => $label) {
- echo " {
- data: d$key,
- points: { show: true },
- label: '$label'
- },";
-}
-?>
- ],
- {
- xaxis: {
- mode: "time",
- min: midnight + (1000*60*60*8),
- max: midnight + (1000*60*60*23.5)
- },
- yaxis: {
- tickFormatter: yformatter
- },
- grid: { hoverable: true, clickable: true, labelMargin: 32 },
- });
- var o;
- o = plot.pointOffset({ x: midnight+ (9*60*60*1000), y: -1.2});
- placeholder.append('<div style="position:absolute;left:' + (o.left + 4) + 'px;top:' + o.top + 'px;color:#666;font-size:smaller">9am</div>');
- o = plot.pointOffset({ x: midnight+ (16*60*60*1000), y: -1.2});
- placeholder.append('<div style="position:absolute;left:' + (o.left + 4) + 'px;top:' + o.top + 'px;color:#666;font-size:smaller">4pm</div>');
-
- });
-function yformatter(v) {
- if (Math.floor(v/60) < -9) return "";
- return Math.abs(Math.floor(v/60)) + " min " + (v == 0 ? "" : (v >0 ? "early":"late"))
-}
- function showTooltip(x, y, contents) {
- $('<div id="tooltip">' + contents + '</div>').css( {
- position: 'absolute',
- display: 'none',
- top: y + 5,
- left: x + 5,
- border: '1px solid #fdd',
- padding: '2px',
- 'background-color': '#fee',
- opacity: 0.80
- }).appendTo("body").fadeIn(200);
- }
-
- var previousPoint = null;
- $("#placeholder").bind("plothover", function (event, pos, item) {
- $("#x").text(pos.x.toFixed(2));
- $("#y").text(pos.y.toFixed(2));
-
- if (item) {
- if (previousPoint != item.dataIndex) {
- previousPoint = item.dataIndex;
-
- $("#tooltip").remove();
- var x = item.datapoint[0].toFixed(2),
- y = item.datapoint[1].toFixed(2);
-
- var d = new Date();
-d.setTime(x);
-var time = d.getUTCHours() +':'+ (d.getUTCMinutes().toString().length == 1 ? '0'+ d.getMinutes(): d.getUTCMinutes())
-
-
- showTooltip(item.pageX, item.pageY,
- item.series.label + " at "+ time +" = " + Math.abs(new Number(y/60).toFixed(2))+" minutes "+(y >0 ? "early":"late"));
- }
- }
- else {
- $("#tooltip").remove();
- previousPoint = null;
- }
- });
-
-</script>
--- a/labs/myway_timeliness_calculate.php
+++ /dev/null
@@ -1,142 +1,1 @@
-<?php
-include ('../include/common.inc.php');
-include_header("MyWay Delta Calculate", "mywayDeltaCalc");
-flush();
-ob_flush();
-function abssort($a, $b)
-{
- if ($a['timeDiff'] == $b['timeDiff']) {
- return 0;
- }
- return (abs($a['timeDiff']) < abs($b['timeDiff'])) ? -1 : 1;
-}
-//collect all observation not in delta
-$query = "select * from myway_observations INNER JOIN myway_stops
-ON myway_observations.myway_stop=myway_stops.myway_stop INNER JOIN myway_routes
-ON myway_observations.myway_route=myway_routes.myway_route
- WHERE observation_id NOT IN
-(
-SELECT observation_id
-FROM myway_timingdeltas
-)";
-debug($query, "database");
-$query = $conn->prepare($query);
-$query->execute();
-if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
-}
-$uncalcdObservations = $query->fetchAll();
-//Display count
-echo "<h3>" . sizeof($uncalcdObservations) . " observations not yet processed</h2>";
-//foreach observation not in delta
-foreach ($uncalcdObservations as $obsv) {
- //var_dump($obsv);
- echo "<h3>Observation {$obsv['observation_id']}:</h1>
-<small>{$obsv['myway_stop']} @ {$obsv['time']} on {$obsv['myway_route']}</small><br>";
- if ($obsv["stop_code"] == "") {
- echo "error, stop '{$obsv['myway_stop']}' unknown";
- continue;
- }
- if ($obsv["route_full_name"] == "") {
- echo "error, route '{$obsv['myway_route']}' unknown";
- continue;
- }
- // convert timestamp into time of day and date
-// timezones from http://www.postgresql.org/docs/8.0/static/datetime-keywords.html
- $time = date("H:i:s", strtotime($obsv['time']));
- $time_tz = date("H:i:s", strtotime($obsv['time']))." AESST";
- $search_time = date("H:i:s", strtotime($obsv['time'])-(30*60)); // 30 minutes margin
- $date = date("c", strtotime($obsv['time']));
- $timing_period = service_period(strtotime($date));
- $potentialStops = getStopsByStopCode($obsv["stop_code"], $obsv["stop_street"]);
- //:get myway_stops records
- //:search by starts with stopcode and starts with street if street is not null
- //no result, skip and display error
- if (sizeof($potentialStops) < 1) {
- echo "error, potential stops for stopcode {$obsv["stop_code"]} street {$obsv["stop_street"]} unknown";
- continue;
- }
- //print out stops
- echo "Matched stops: ";
- foreach ($potentialStops as $potentialStop) echo $potentialStop['stop_code'] . " ";
- echo "<br>";
- //:get myway_route record
- //no result, skip and display error
- //print out route
- $potentialRoute = getRouteByFullName($obsv["route_full_name"]);
- if ($potentialRoute["route_short_name"] == "") {
- echo "error, route '{$obsv["route_full_name"]}' unknown";
- continue;
- }
- echo "Matched route: {$potentialRoute['route_short_name']}{$potentialRoute['route_long_name']} {$timing_period}<br>";
- $timeDeltas = Array();
- foreach ($potentialStops as $potentialStop) {
- $stopRoutes = getStopRoutes($potentialStop['stop_id'], $timing_period);
- $foundRoute = Array();
- foreach ($stopRoutes as $stopRoute) {
- //Check if this route stops at each stop
- if ($stopRoute['route_short_name'] . $stopRoute['route_long_name'] == $obsv["route_full_name"]) {
- echo "Matching route {$stopRoute['route_id']} found at {$potentialStop['stop_code']}<br>";
- $foundRoute = $stopRoute;
- //if does get tripstoptimes for this route
- $trips = getStopTrips($potentialStop['stop_id'], $timing_period, $search_time);
- foreach ($trips as $trip) {
- //echo $trip['route_id']." ".$stopRoute['route_id'].";";
- if ($trip['route_id'] == $stopRoute['route_id']) {
- $timedTrip = getTimeInterpolatedTripAtStop($trip['trip_id'], $trip['stop_sequence']);
- $actual_time = strtotime($time);
- $trip_time = strtotime($timedTrip['arrival_time']);
- $timeDiff = $actual_time - $trip_time;
- //work out time delta, put into array with index of delta
- $timeDeltas[] = Array(
- "timeDiff" => $timeDiff,
- "stop_code" => $potentialStop['stop_code'],
- "stop_sequence" => $timedTrip['stop_sequence']
- );
- echo "Found trip {$trip['trip_id']} at stop {$potentialStop['stop_code']} (#{$potentialStop['stop_id']}, sequence #{$trip['stop_sequence']})<br>";
- echo "Arriving at {$timedTrip['arrival_time']}, difference of " . round($timeDiff / 60, 2) . " minutes<br>";
- }
- }
- break; // because have found route
-
- }
- }
- if (sizeof($foundRoute) < 1) {
- //print out that stops/does not stop
- echo "No matching routes found at {$potentialStop['stop_code']}<br>";
- var_dump($stopRoutes);
- flush();
- }
- }
- // lowest delta is recorded delta
- usort($timeDeltas, "abssort");
- $lowestDelta = $timeDeltas[0]["timeDiff"];
- if (sizeof($timeDeltas) != 0) {
- echo "Lowest difference of " . round($lowestDelta / 60, 2) . " minutes will be recorded for this observation<br>";
- $observation_id = $obsv['observation_id'];
- $route_full_name = $obsv['route_full_name'];
- $stop_code = $timeDeltas[0]["stop_code"];
- $stop_sequence = $timeDeltas[0]["stop_sequence"];
- $stmt = $conn->prepare("insert into myway_timingdeltas (observation_id, route_full_name, stop_code, timing_delta, time, date, timing_period, stop_sequence)
- values (:observation_id, :route_full_name, :stop_code, :timing_delta, :time, :date, :timing_period, :stop_sequence)");
- $stmt->bindParam(':observation_id', $observation_id);
- $stmt->bindParam(':route_full_name', $route_full_name);
- $stmt->bindParam(':stop_code', $stop_code);
- $stmt->bindParam(':timing_delta', $lowestDelta);
- $stmt->bindParam(':time', $time_tz);
- $stmt->bindParam(':date', $date);
- $stmt->bindParam(':timing_period', $timing_period);
- $stmt->bindParam(':stop_sequence', $stop_sequence);
- // insert a record
- $stmt->execute();
- if ($stmt->rowCount() > 0) {
- echo "Recorded.<br>";
- }
- var_dump($conn->errorInfo());
- flush();
- }
- flush();
-}
-
--- a/labs/myway_timeliness_freqdist.php
+++ /dev/null
@@ -1,45 +1,1 @@
-<?php
-include ('../include/common.inc.php');
-include_header("MyWay Deltas", "mywayDelta");
-?>
- <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../js/flot/excanvas.min.js"></script><![endif]-->
-
- <script language="javascript" type="text/javascript" src="../js/flot/jquery.flot.js"></script>
- <center><div id="placeholder" style="width:900px;height:550px"></div></center>
-<script type="text/javascript">
-$(function () {
-
- var d1 = [];
-<?php
-$query = "select td, count(*) from (select (timing_delta - MOD(timing_delta,10)) as td from myway_timingdeltas where abs(timing_delta) < 2*(select stddev(timing_delta) from myway_timingdeltas)) as a group by td order by td";
-$query = $conn->prepare($query);
-$query->execute();
-if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
-}
-
-foreach ($query->fetchAll() as $delta) {
-
- echo "d1.push([ ".intval($delta['td']).", ".intval($delta['count'])."]); \n";
-};
-?>
-
- var placeholder = $("#placeholder");
-
- var plot = $.plot(placeholder, [
- {
- data: d1,
- bars: { show: true }
- },
- ],
- {
-
- grid: { hoverable: true, clickable: true, labelMargin: 17 },
- });
-
- });
-
-
-</script>
--- a/labs/myway_timeliness_overview.php
+++ /dev/null
@@ -1,97 +1,1 @@
-<?php
-include ('../include/common.inc.php');
-include_header("MyWay Deltas", "mywayDelta");
-?>
-<table>
- <tr><td></td><td>Mean</td><td>Standard<br>Deviation</td><td>Sample Size</td></tr>
-<th> Overall </th>
-<?php
-$query = "select '', avg(timing_delta), stddev(timing_delta), count(*) from myway_timingdeltas ";
-$query = $conn->prepare($query);
-$query->execute();
-if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
-}
-foreach ($query->fetchAll() as $row) {
- echo "<tr><td>{$row[0]}</td><td>" . floor($row[1]) . "</td><td>" . floor($row[2]) . "</td><td>{$row[3]}</td></tr>";
-};
-?>
-
-<th> Hour of Day </th>
-<?php
-$query = "select extract(hour from time), avg(timing_delta), stddev(timing_delta), count(*) from myway_timingdeltas group by extract(hour from time) order by extract(hour from time)";
-$query = $conn->prepare($query);
-$query->execute();
-if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
-}
-foreach ($query->fetchAll() as $row) {
- echo "<tr><td>{$row[0]}</td><td>" . floor($row[1]) . "</td><td>" . floor($row[2]) . "</td><td>{$row[3]}</td></tr>";
-};
-?>
-
-<th> Day of Week </th>
-<?php
-$query = "select to_char(date, 'Day'), avg(timing_delta), stddev(timing_delta), count(*) from myway_timingdeltas group by to_char(date, 'Day') order by to_char(date, 'Day')";
-$query = $conn->prepare($query);
-$query->execute();
-if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
-}
-foreach ($query->fetchAll() as $row) {
- echo "<tr><td>{$row[0]}</td><td>" . floor($row[1]) . "</td><td>" . floor($row[2]) . "</td><td>{$row[3]}</td></tr>";
-};
-?>
-<th>Month </th>
-<?php
-$query = "select to_char(date, 'Month'), avg(timing_delta), stddev(timing_delta), count(*) from myway_timingdeltas group by to_char(date, 'Month') order by to_char(date, 'Month')";
-$query = $conn->prepare($query);
-$query->execute();
-if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
-}
-foreach ($query->fetchAll() as $row) {
- echo "<tr><td>{$row[0]}</td><td>" . floor($row[1]) . "</td><td>" . floor($row[2]) . "</td><td>{$row[3]}</td></tr>";
-};
-?>
-
-<th>Stop </th>
-<?php
-$query = "select myway_stop, avg(timing_delta), stddev(timing_delta), count(*) from myway_timingdeltas INNER JOIN myway_observations
-ON myway_observations.observation_id=myway_timingdeltas.observation_id group by myway_stop having count(*) > 1 order by myway_stop";
-$query = $conn->prepare($query);
-$query->execute();
-if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
-}
-foreach ($query->fetchAll() as $row) {
- echo "<tr><td>{$row[0]}</td><td>" . floor($row[1]) . "</td><td>" . floor($row[2]) . "</td><td>{$row[3]}</td></tr>";
-};
-?>
-<th>Route </th>
-<?php
-$query = "select route_full_name, avg(timing_delta), stddev(timing_delta), count(*) from myway_timingdeltas group by route_full_name having count(*) > 1 order by route_full_name";
-$query = $conn->prepare($query);
-$query->execute();
-if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
-}
-foreach ($query->fetchAll() as $row) {
- echo "<tr><td>{$row[0]}</td><td>" . floor($row[1]) . "</td><td>" . floor($row[2]) . "</td><td>{$row[3]}</td></tr>";
-};
-?>
-
-
-</table>
-
-<?php
-include_footer();
-?>
-
--- a/labs/myway_timeliness_reconcile.php
+++ /dev/null
@@ -1,132 +1,1 @@
-<?php
-include ('../include/common.inc.php');
-foreach ($_REQUEST as $key => $value) {
- if (strstr($key, "route") && !strstr($value, "Select")) {
- $myway_route = str_replace("route", "", $key);
- $route_full_name = $value;
- $query = "update myway_routes set route_full_name = :route_full_name where myway_route = :myway_route";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":myway_route", $myway_route,PDO::PARAM_STR, 5);
- $query->bindParam(":route_full_name", $route_full_name,PDO::PARAM_STR, 42);
- $query->execute();
- die(print_r($conn->errorInfo() , true));
- }
- if (strstr($key, "myway_stop")) {
- $myway_stop = $value;
- $stop_code = $_REQUEST['stop_code'];
- $stop_street = $_REQUEST['stop_street'];
- $query = "update myway_stops set stop_code = :stop_code, stop_street = :stop_street where myway_stop = :myway_stop";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":myway_stop", $myway_stop, PDO::PARAM_STR, 25);
- $query->bindParam(":stop_code", $stop_code, PDO::PARAM_STR, 32);
- $query->bindParam(":stop_street", $stop_street);
- $query->execute();
- die(print_r($conn->errorInfo() , true));
- }
-}
-include_header("MyWay Data Reconcile", "mywayTimeRec");
-// initialise
-$count = $conn->exec("insert into myway_stops
- select distinct myway_stop from myway_observations
- WHERE myway_stop NOT IN
- (
- SELECT myway_stop
- FROM myway_stops
- )");
-echo "$count new stops.<br>";
-if (!$count) {
- print_r($conn->errorInfo());
-}
-$count = $conn->exec("insert into myway_routes select distinct myway_route from myway_observations
- WHERE myway_route NOT IN
- (
- SELECT myway_route
- FROM myway_routes
- )");
-echo "$count new routes.<br>";
-if (!$count) {
- print_r($conn->errorInfo());
-}
-echo "<h2>Stops</h2>";
-/*stops
- search start of name, display map and table nuimbered, two text boxes */
-$query = "Select * from myway_stops where stop_code is NULL and stop_street is NUll;";
-debug($query, "database");
-$query = $conn->prepare($query);
-$query->execute();
-if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
-}
-foreach ($query->fetchAll() as $myway_stop) {
- echo "<h3>{$myway_stop[0]}</h3>";
- $stopNameParts = explode(" ", $myway_stop[0]);
- $markers = array();
- $stopKey = 1;
- $foundStops = getStops(false, "", $stopNameParts[0] . " " . $stopNameParts[1]);
- if (sizeof($foundStops) > 0) {
- echo "<table>";
- foreach ($foundStops as $stopResult) {
- $markers[] = array(
- $stopResult['stop_lat'],
- $stopResult['stop_lon']
- );
- echo "<tr><td>" . $stopKey++ . "</td><td>" . $stopResult['stop_name'] . "</td><td>" . $stopResult['stop_code'] . "</td></tr>";
- }
- echo '</table>';
- echo "" . staticmap($markers, 0, "icong", false) . "<br>\n";
- }
- echo '<form id="inputform' .md5($myway_stop[0]).'">
- <input type="hidden" name="myway_stop" value="' .$myway_stop[0].'">
- <div data-role="fieldcontain">
- <label for="stop_code">Stop Code</label>
- <input type="text" name="stop_code" id="stop_code" value="' . $foundStops[0]['stop_code'] . '" />
- </div>
- <div data-role="fieldcontain">
- <label for="stop_street">Stop Street </label>
- <input type="text" name="stop_street" id="stop_street" value="' . $foundStops[0]['stop_name'] . '" />
- </div> <input type="button" onclick="$.post(\'myway_timeliness_reconcile.php\', $(\'#inputform' .md5($myway_stop[0]) . '\').serialize())" value="Go!"></form>
-';
- echo '<hr>';
-}
-echo '<h2>Routes</h2>';
-/*routes
- remove alpha char, search present dropdown*/
-$query = "Select * from myway_routes where route_full_name is NUll;";
-debug($query, "database");
-$query = $conn->prepare($query);
-$query->execute();
-if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
-}
-foreach ($query->fetchAll() as $myway_route) {
- echo "<h3>{$myway_route[0]}</h3>";
- $query = "Select * from myway_observations where myway_route = :route order by time";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->bindParam(":route", $myway_route[0]);
- $query->execute();
- if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
- }
- foreach ($query->fetchAll() as $myway_obvs) {
- echo $myway_obvs['myway_stop'] . $myway_obvs['time'] . "<br>";
- }
- $searchRouteNo = preg_replace("/[A-Z]/", "", $myway_route[0]);
- echo $searchRouteNo;
- echo '<form id="inputform' . $myway_route[0] . '">
-<select name="route' . $myway_route[0] . '" onchange=\'$.post("myway_timeliness_reconcile.php", $("#inputform' . $myway_route[0] . '").serialize())\'>
-<option>Select a from/to pair...</option>';
- foreach (getRoutesByNumber($searchRouteNo) as $routeResult) {
- echo "<option value=\"{$routeResult['route_short_name']}{$routeResult['route_long_name']}\"> {$routeResult['route_short_name']}{$routeResult['route_long_name']} </option>\n";
- }
- echo "</select></form>";
- echo '<hr>';
-}
-include_footer();
-?>
--- a/labs/myway_timeliness_route.json.php
+++ /dev/null
@@ -1,25 +1,1 @@
-<?php
-include ('../include/common.inc.php');
-header('Content-Type: text/javascript; charset=utf8');
-// header('Access-Control-Allow-Origin: http://bus.lambdacomplex.org/');
-header('Access-Control-Max-Age: 3628800');
-header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
-?>
-{
- "label": "<?php echo $_REQUEST['routeid']; ?>",
- "data": <?php
- $query = "select * from myway_timingdeltas where route_full_name = :route_full_name AND abs(timing_delta) < 2*(select stddev(timing_delta) from myway_timingdeltas) order by stop_sequence;";
-$query = $conn->prepare($query);
-$query->bindParam(':route_full_name', $_REQUEST['routeid'],PDO::PARAM_STR, 42);
-
-$query->execute();
-if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
-}
-foreach ($query->fetchAll() as $delta) {
- $points[] = "[{$delta['stop_sequence']}, {$delta['timing_delta']}]";
-};
-echo "[".implode(",",$points)."]";
-?>
-}
+
--- a/labs/myway_timeliness_route.php
+++ /dev/null
@@ -1,125 +1,1 @@
-<?php
-include ('../include/common.inc.php');
-include_header("MyWay Deltas", "mywayDelta");
-?>
- <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../js/flot/excanvas.min.js"></script><![endif]-->
-
- <script language="javascript" type="text/javascript" src="../js/flot/jquery.flot.js"></script>
- <form method="get" action="">
- <select id="routeid" name="routeid">
-<?php
-$query = "select distinct route_full_name from myway_routes where myway_route != '' order by route_full_name";
-$query = $conn->prepare($query);
-$query->execute();
-if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
-}
-foreach ($query->fetchAll() as $route) {
- echo "<option value=\"{$route['route_full_name']}\">{$route['route_full_name']}</option>";
-
-};
-?> </select>
- <center><div id="placeholder" style="width:900px;height:550px"></div></center>
-<script type="text/javascript">
-$(function () {
-
- var placeholder = $("#placeholder");
- var data = [];
- var options = {
- xaxis: {
- },
- yaxis: {
- tickFormatter: yformatter
- },
- grid: { hoverable: true, clickable: true, labelMargin: 32 },
-series: {
- lines: { show: false },
- points: { show: true }
- }
- };
-
- var plot = $.plot(placeholder, data, options);
-
-// fetch one series, adding to what we got
- var alreadyFetched = {};
-
- $("#routeid").change(function () {
- var select = $(this);
-
- // find the URL in the link right next to us
- // var dataurl = button.siblings('a').attr('href');
- var dataurl = "myway_timeliness_route.json.php?routeid=" + select.val();
- // then fetch the data with jQuery
- function onDataReceived(series) {
- // extract the first coordinate pair so you can see that
- // data is now an ordinary Javascript object
- var firstcoordinate = '(' + series.data[0][0] + ', ' + series.data[0][1] + ')';
-
-
- // let's add it to our current data
- if (!alreadyFetched[series.label]) {
- alreadyFetched[series.label] = true;
- data.push(series);
- }
-
- // and plot all we got
- $.plot(placeholder, data, options);
- }
-
- $.ajax({
- url: dataurl,
- method: 'GET',
- dataType: 'json',
- success: onDataReceived
- });
- });
-
-
- });
-
-
-
-function yformatter(v) {
- if (Math.floor(v/60) < -9) return "";
- return Math.abs(Math.floor(v/60)) + " min " + (v == 0 ? "" : (v >0 ? "early":"late"))
-}
- function showTooltip(x, y, contents) {
- $('<div id="tooltip">' + contents + '</div>').css( {
- position: 'absolute',
- display: 'none',
- top: y + 5,
- left: x + 5,
- border: '1px solid #fdd',
- padding: '2px',
- 'background-color': '#fee',
- opacity: 0.80
- }).appendTo("body").fadeIn(200);
- }
-
- var previousPoint = null;
- $("#placeholder").bind("plothover", function (event, pos, item) {
- $("#x").text(pos.x.toFixed(2));
- $("#y").text(pos.y.toFixed(2));
-
- if (item) {
- if (previousPoint != item.dataIndex) {
- previousPoint = item.dataIndex;
-
- $("#tooltip").remove();
- var x = item.datapoint[0],
- y = item.datapoint[1].toFixed(2);
-
- showTooltip(item.pageX, item.pageY,
- item.series.label + " at stop_sequence "+ x +" = " + Math.abs(new Number(y/60).toFixed(2))+" minutes "+(y >0 ? "early":"late"));
- }
- }
- else {
- $("#tooltip").remove();
- previousPoint = null;
- }
- });
-
-</script>
-
--- a/labs/myway_timeliness_stop.json.php
+++ /dev/null
@@ -1,32 +1,1 @@
-<?php
-include ('../include/common.inc.php');
-header('Content-Type: text/javascript; charset=utf8');
-// header('Access-Control-Allow-Origin: http://bus.lambdacomplex.org/');
-header('Access-Control-Max-Age: 3628800');
-header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
-?>
-{
- "label": "<?php echo $_REQUEST['stopid']; ?>",
- "data": <?php
- $query = "select * from myway_timingdeltas INNER JOIN myway_observations
-ON myway_observations.observation_id=myway_timingdeltas.observation_id
- where myway_stop = :myway_stop
- AND abs(timing_delta) < 2*(select stddev(timing_delta) from myway_timingdeltas)
- order by myway_timingdeltas.time;";
-$query = $conn->prepare($query);
-$query->bindParam(':myway_stop', $_REQUEST['stopid'],PDO::PARAM_STR, 42);
-
-$query->execute();
-if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
-}
-foreach ($query->fetchAll() as $delta) {
- $points[] = "[".((strtotime("00:00Z") + midnight_seconds(strtotime($delta['time'])))*1000).", {$delta['timing_delta']}]";
-};
-if (count($points) == 0) {
- echo "[]"; }
- else echo "[".implode(",",$points)."]";
-?>
-}
--- a/labs/myway_timeliness_stop.php
+++ /dev/null
@@ -1,136 +1,1 @@
-<?php
-include ('../include/common.inc.php');
-include_header("MyWay Deltas", "mywayDelta");
-?>
- <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../js/flot/excanvas.min.js"></script><![endif]-->
-
- <script language="javascript" type="text/javascript" src="../js/flot/jquery.flot.js"></script>
- <form method="get" action="">
- <select id="stopid" name="stopid">
-<?php
-$query = "select distinct myway_stop from myway_stops where myway_stop != '' order by myway_stop";
-$query = $conn->prepare($query);
-$query->execute();
-if (!$query) {
- databaseError($conn->errorInfo());
- return Array();
-}
-foreach ($query->fetchAll() as $stop) {
- echo "<option value=\"{$stop['myway_stop']}\">{$stop['myway_stop']}</option>";
-
-};
-?> </select> <center><div id="placeholder" style="width:900px;height:550px"></div></center>
-<script type="text/javascript">
-$(function () {
- var d = new Date();
- d.setUTCMinutes(0);
- d.setUTCHours(0);
- var midnight = d.getTime();
-
- var placeholder = $("#placeholder");
- var data = [];
- var options = {
- xaxis: {
- mode: "time",
- min: midnight + (1000*60*60*8),
- max: midnight + (1000*60*60*23.5)
- },
- yaxis: {
- tickFormatter: yformatter
- },
- grid: { hoverable: true, clickable: true, labelMargin: 32 },
- series: {
- lines: { show: false },
- points: { show: true }
- }
- };
-
- var plot = $.plot(placeholder, data, options);
- var o;
- o = plot.pointOffset({ x: midnight+ (9*60*60*1000), y: -1.2});
- placeholder.append('<div style="position:absolute;left:' + (o.left + 4) + 'px;top:' + o.top + 'px;color:#666;font-size:smaller">9am</div>');
- o = plot.pointOffset({ x: midnight+ (16*60*60*1000), y: -1.2});
- placeholder.append('<div style="position:absolute;left:' + (o.left + 4) + 'px;top:' + o.top + 'px;color:#666;font-size:smaller">4pm</div>');
-// fetch one series, adding to what we got
- var alreadyFetched = {};
-
- $("#stopid").change(function () {
- var select = $(this);
-
- // find the URL in the link right next to us
- // var dataurl = button.siblings('a').attr('href');
- var dataurl = "myway_timeliness_stop.json.php?stopid=" + select.val();
- // then fetch the data with jQuery
- function onDataReceived(series) {
- // extract the first coordinate pair so you can see that
- // data is now an ordinary Javascript object
- var firstcoordinate = '(' + series.data[0][0] + ', ' + series.data[0][1] + ')';
-
-
- // let's add it to our current data
- if (!alreadyFetched[series.label]) {
- alreadyFetched[series.label] = true;
- data.push(series);
- }
-
- // and plot all we got
- $.plot(placeholder, data, options);
- }
-
- $.ajax({
- url: dataurl,
- method: 'GET',
- dataType: 'json',
- success: onDataReceived
- });
- });
-
- });
-function yformatter(v) {
- if (Math.floor(v/60) < -9) return "";
- return Math.abs(Math.floor(v/60)) + " min " + (v == 0 ? "" : (v >0 ? "early":"late"))
-}
- function showTooltip(x, y, contents) {
- $('<div id="tooltip">' + contents + '</div>').css( {
- position: 'absolute',
- display: 'none',
- top: y + 5,
- left: x + 5,
- border: '1px solid #fdd',
- padding: '2px',
- 'background-color': '#fee',
- opacity: 0.80
- }).appendTo("body").fadeIn(200);
- }
-
- var previousPoint = null;
- $("#placeholder").bind("plothover", function (event, pos, item) {
- $("#x").text(pos.x.toFixed(2));
- $("#y").text(pos.y.toFixed(2));
-
- if (item) {
- if (previousPoint != item.dataIndex) {
- previousPoint = item.dataIndex;
-
- $("#tooltip").remove();
- var x = item.datapoint[0].toFixed(2),
- y = item.datapoint[1].toFixed(2);
-
- var d = new Date();
-d.setTime(x);
-var time = d.getUTCHours() +':'+ (d.getUTCMinutes().toString().length == 1 ? '0'+ d.getMinutes(): d.getUTCMinutes())
-
-
- showTooltip(item.pageX, item.pageY,
- item.series.label + " at "+ time +" = " + Math.abs(new Number(y/60).toFixed(2))+" minutes "+(y >0 ? "early":"late"));
- }
- }
- else {
- $("#tooltip").remove();
- previousPoint = null;
- }
- });
-
-</script>
-
--- a/labs/mywaybalance.php
+++ /dev/null
@@ -1,124 +1,1 @@
-<?php
-include ('../include/common.inc.php');
-include_header("MyWay Balance", "mywayBalance", false, false, true);
-echo '<div data-role="page">
- <div data-role="header" data-position="inline">
- <a href="' . $_SERVER["HTTP_REFERER"] . '" data-icon="arrow-l" data-rel="back" class="ui-btn-left">Back</a>
- <h1>MyWay Balance</h1>
- <a href="mywaybalance.php?logout=yes" data-icon="delete" class="ui-btn-right">Logout</a>
- </div><!-- /header -->
- <a name="maincontent" id="maincontent"></a>
- <div data-role="content"> ';
-$return = Array();
-function logout()
-{
- setcookie("card_number", "", time() - 60 * 60 * 24 * 100, "/");
- setcookie("date", "", time() - 60 * 60 * 24 * 100, "/");
- setcookie("secret_answer", "", time() - 60 * 60 * 24 * 100, "/");
- setcookie("contribute_myway", "", time() - 60 * 60 * 24 * 100, "/");
-}
-function printBalance($mywayResult)
-{
- if (isset($mywayResult['error'])) {
- logout();
- echo '<h3><font color="red">' . $mywayResult['error'][0] . "</font></h3>";
- }
- else {
- echo "<h2>Balance: " . $mywayResult['myway_carddetails']['Card Balance'] . "</h2>";
- echo '<ul data-role="listview" data-inset="true"><li data-role="list-divider"> Recent Transactions </li>';
- $txCount = 0;
- foreach ($mywayResult['myway_transactions'] as $transaction) {
- echo "<li>";
- if ($transaction["Deduction Type"] == "DEFAULT") echo '<img src="css/images/warning.png" alt="Failed to tap off: " class="ui-li-icon">';
- echo "<b>" . $transaction["Date / Time"] . "</b>";
- echo "<br><small>" . $transaction["Route"] . " at " . $transaction["Stop Name"] . "<br>";
- echo $transaction["TX Reference No"] . " " . $transaction["TX Type"] . "</small>";
- echo '<p class="ui-li-aside">' . $transaction["TX Amount"] . '</p>';
- echo "</li>";
- $txCount++;
- if ($txCount > 10) break;
- }
- echo "</ul>";
- }
-}
-function recordMyWayObservations($mywayResult)
-{
- global $conn;
- if (!isset($mywayResult['error'])) {
- $stmt = $conn->prepare("insert into myway_observations (observation_id, myway_stop, time, myway_route)
- values (:observation_id, :myway_stop, :time, :myway_route)");
- $stmt->bindParam(':observation_id', $observation_hash);
- $stmt->bindParam(':myway_stop', $myway_stop);
- $stmt->bindParam(':time', $timestamp);
- $stmt->bindParam(':myway_route', $myway_route);
- // insert a record
- $resultCount = 0;
- foreach ($mywayResult['myway_transactions'] as $transaction) {
- if ($transaction["Stop Name"] != "" && $transaction["Deduction Type"] != "DEFAULT") {
- $observation_hash = md5($mywayResult['myway_carddetails']['MyWay Number'] . $transaction["TX Reference No"]);
- $timestamp = date("c", strtotime($transaction["Date / Time"]));
- $myway_stop = $transaction["Stop Name"];
- $myway_route = $transaction["Route"];
- if ($stmt->execute()) $resultCount++;
- }
- }
- echo "<h3>Thanks for participating in the study! $resultCount transactions were recorded</h3>";
- }
-}
-if (isset($_REQUEST['card_number']) && isset($_REQUEST['date']) && isset($_REQUEST['secret_answer'])) {
- $cardNumber = $_REQUEST['card_number'];
- $date = explode("/", $_REQUEST['date']);
- $pwrd = $_REQUEST['secret_answer'];
- if ($_REQUEST['remember'] == "on") {
- setcookie("card_number", $cardNumber, time() + 60 * 60 * 24 * 100, "/");
- setcookie("date", $_REQUEST['date'], time() + 60 * 60 * 24 * 100, "/");
- setcookie("contribute_myway", $_REQUEST['contribute_myway'], time() + 60 * 60 * 24 * 100, "/");
- setcookie("secret_answer", $pwrd, time() + 60 * 60 * 24 * 100, "/");
- }
- $mywayResult = json_decode(getPage(curPageURL() . "/myway_api.json.php?card_number=$cardNumber&DOBday={$date[0]}&DOBmonth={$date[1]}&DOByear={$date[2]}&secret_answer=$pwrd") , true);
- if ($_REQUEST['contribute_myway'] == "on") recordMyWayObservations($mywayResult);
- printBalance($mywayResult);
-}
-else if (isset($_REQUEST['logout'])) {
- echo '<center><h3> Logged out of MyWay balance </h3><a href="/index.php">Back to main menu...</a><center>';
-}
-else if (isset($_COOKIE['card_number']) && isset($_COOKIE['date']) && isset($_COOKIE['secret_answer'])) {
- $cardNumber = $_COOKIE['card_number'];
- $date = explode("/", $_COOKIE['date']);
- $pwrd = $_COOKIE['secret_answer'];
- $mywayResult = json_decode(getPage(curPageURL() . "/myway_api.json.php?card_number=$cardNumber&DOBday={$date[0]}&DOBmonth={$date[1]}&DOByear={$date[2]}&secret_answer=$pwrd") , true);
- if ($_COOKIE['contribute_myway'] == "on") recordMyWayObservations($mywayResult);
- printBalance($mywayResult);
-}
-else {
- $date = (isset($_REQUEST['date']) ? filter_var($_REQUEST['date'], FILTER_SANITIZE_STRING) : date("m/d/Y"));
- echo '<form action="" method="post">
- <div data-role="fieldcontain">
- <label for="card_number">Card number</label>
- <input type="text" name="card_number" id="card_number" value="' . $card_number . '" />
- </div>
- <div data-role="fieldcontain">
- <label for="date"> Date of birth </label>
- <input type="text" name="date" id="date" value="' . $date . '" />
- </div>
- <div data-role="fieldcontain">
- <label for="secret_answer"> Secret question answer </label>
- <input type="text" name="secret_answer" id="secret_answer" value="' . $secret_answer . '" />
- </div>
- <div data-role="fieldcontain">
- <label for="remember"> Remember these details? </label>
- <input type="checkbox" name="remember" id="remember" checked="yes" />
- </div>
- <div data-role="fieldcontain">
- <label for="contribute_myway">Contribute MyWay records to timeliness study? </label>
- <input type="checkbox" name="contribute_myway" id="contribute_myway" defaultChecked="no" />
- </div>
- <div data-role="fieldcontain">
- <label for="accept_warning">I accept that Transport for Canberra <a href="http://transport.act.gov.au/myway/protect.html">advise against the use of third party MyWay applications</a> </label>
- <input type="checkbox" name="accept_warning" id="accept_warning" defaultChecked="no" />
- </div>
- <input type="submit" value="Go!"></form>';
-}
-include_footer();
-?>
--- a/labs/stop.pdf.php
+++ b/labs/stop.pdf.php
@@ -1,4 +1,20 @@
<?php
+
+/*
+ * Copyright 2010,2011 Alexander Sadleir
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
include ('../include/common.inc.php');
$stopid = filter_var($_REQUEST['stopid'], FILTER_SANITIZE_NUMBER_INT);
$url = $APIurl . "/json/stop?stop_id=" . $stopid;
@@ -7,139 +23,135 @@
$url = $APIurl . "/json/stoproutes?stop=" . $stopid . "&time=" . midnight_seconds() . "&service_period=" . service_period();
$routes = json_decode(getPage($url));
foreach ($routes as $route) {
- $html.= '<br> <a href="trip.php?routeid=' . $route[0] . '&stopid=' . $stopid . '">' . $route[1] . ' - ' . $route[2] . '</a>';
- $viaPoints = viaPointNames($route[3], $stopid);
- if ($viaPoints != "") $html.= '<br><small>Via: ' . $viaPoints . '</small>';
- $html.= "<br>";
+ $html.= '<br> <a href="trip.php?routeid=' . $route[0] . '&stopid=' . $stopid . '">' . $route[1] . ' - ' . $route[2] . '</a>';
+ $viaPoints = viaPointNames($route[3], $stopid);
+ if ($viaPoints != "")
+ $html.= '<br><small>Via: ' . $viaPoints . '</small>';
+ $html.= "<br>";
}
$html.= '</td><td>' . staticmap(Array(
- 0 => Array(
- $stop[2],
- $stop[3]
- )
-) , 0, "iconb", false) . "</td></tr>";
+ 0 => Array(
+ $stop[2],
+ $stop[3]
+ )
+ ), 0, "iconb", false) . "</td></tr>";
$url = $APIurl . "/json/stoptrips?stop=" . $stopid . "&time=" . midnight_seconds() . "&service_period=" . service_period();
$trips = json_decode(getPage($url));
$html.= "</table><br><br><table>";
$html.= "<thead><tr><th>Route</th><th>Time</th></tr></thead>";
debug(print_r($trips, true));
foreach ($trips as $row) {
- $html.= '<tr><td><a href="trip.php?stopid=' . $stopid . '&tripid=' . $row[1][0] . '">' . $row[1][1] . "</a></td>";
- $html.= '<td>' . midnight_seconds_to_time($row[0]) . '</td>';
- $html.= '</tr>';
+ $html.= '<tr><td><a href="trip.php?stopid=' . $stopid . '&tripid=' . $row[1][0] . '">' . $row[1][1] . "</a></td>";
+ $html.= '<td>' . midnight_seconds_to_time($row[0]) . '</td>';
+ $html.= '</tr>';
}
$html.= '</table>';
-if (sizeof($trips) == 0) $html.= "<center>No trips in the near future.</center>";
+if (sizeof($trips) == 0)
+ $html.= "<center>No trips in the near future.</center>";
require_once ('lib/tcpdf/config/lang/eng.php');
require_once ('lib/tcpdf/tcpdf.php');
+
// create new PDF document
-class Custom_TCPDF extends TCPDF
-{
- var $QRCodeURL;
- function set_QRCodeURL($url)
- {
- $this->QRCodeURL = $url;
- }
- /**
- * This method is used to render the page header.
- * It is automatically called by AddPage() and could be overwritten in your own inherited class.
- * @public
- */
- public function Header()
- {
- if ($this->header_xobjid < 0) {
- // start a new XObject Template
- $this->header_xobjid = $this->startTemplate($this->w, $this->tMargin + 10);
- $headerfont = $this->getHeaderFont();
- $headerdata = $this->getHeaderData();
- $this->y = $this->header_margin;
- if ($this->rtl) {
- $this->x = $this->w - $this->original_rMargin;
- }
- else {
- $this->x = $this->original_lMargin - 10;
- }
- if (isset($this->QRCodeURL)) {
- // QRCODE,H : QR-CODE Best error correction
- $style = array(
- 'border' => 1,
- 'padding' => 0,
- 'fgcolor' => array(
- 0,
- 0,
- 0
- ) ,
- 'bgcolor' => false, //array(255,255,255)
- 'module_width' => 1, // width of a single module in points
- 'module_height' => 1
- // height of a single module in points
-
- );
- $this->write2DBarcode($this->QRCodeURL, 'QRCODE,H', '', '', 25, 25, $style, 'T');
- $imgy = 50 + 20;
- }
- elseif (($headerdata['logo']) AND ($headerdata['logo'] != K_BLANK_IMAGE)) {
- $imgtype = $this->getImageFileType(K_PATH_IMAGES . $headerdata['logo']);
- if (($imgtype == 'eps') OR ($imgtype == 'ai')) {
- $this->ImageEps(K_PATH_IMAGES . $headerdata['logo'], '', '', $headerdata['logo_width']);
- }
- elseif ($imgtype == 'svg') {
- $this->ImageSVG(K_PATH_IMAGES . $headerdata['logo'], '', '', $headerdata['logo_width']);
- }
- else {
- $this->Image(K_PATH_IMAGES . $headerdata['logo'], '', '', $headerdata['logo_width']);
- }
- $imgy = $this->getImageRBY();
- }
- else {
- $imgy = $this->y;
- }
- $cell_height = round(($this->cell_height_ratio * $headerfont[2]) / $this->k, 2);
- // set starting margin for text data cell
- if ($this->getRTL()) {
- $header_x = $this->original_rMargin + ($headerdata['logo_width'] * 1.1);
- }
- else {
- $header_x = $this->original_lMargin + ($headerdata['logo_width'] * 1.1);
- }
- $cw = $this->w - $this->original_lMargin - $this->original_rMargin - ($headerdata['logo_width'] * 1.1);
- $this->SetTextColor(0, 0, 0);
- // header title
- $this->SetFont($headerfont[0], 'B', $headerfont[2] + 1);
- $this->SetX($header_x);
- $this->Cell($cw, $cell_height, $headerdata['title'], 0, 1, '', 0, '', 0);
- // header string
- $this->SetFont($headerfont[0], $headerfont[1], $headerfont[2]);
- $this->SetX($header_x);
- $this->MultiCell($cw, $cell_height, $headerdata['string'], 0, '', 0, 1, '', '', true, 0, false);
- // print an ending header line
- //$this->SetLineStyle(array('width' => 0.85 / $this->k, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)));
- //$this->SetY((2.835 / $this->k) + max($imgy, $this->y));
- if ($this->rtl) {
- $this->SetX($this->original_rMargin);
- }
- else {
- $this->SetX($this->original_lMargin);
- }
- //$this->Cell(($this->w - $this->original_lMargin - $this->original_rMargin), 0, '', 'T', 0, 'C');
- $this->endTemplate();
- }
- // print header template
- $x = 0;
- $dx = 0;
- if ($this->booklet AND (($this->page % 2) == 0)) {
- // adjust margins for booklet mode
- $dx = ($this->original_lMargin - $this->original_rMargin);
- }
- if ($this->rtl) {
- $x = $this->w + $dx;
- }
- else {
- $x = 0 + $dx;
- }
- $this->printTemplate($this->header_xobjid, $x, 0, 0, 0, '', '', false);
- }
+class Custom_TCPDF extends TCPDF {
+
+ var $QRCodeURL;
+
+ function set_QRCodeURL($url) {
+ $this->QRCodeURL = $url;
+ }
+
+ /**
+ * This method is used to render the page header.
+ * It is automatically called by AddPage() and could be overwritten in your own inherited class.
+ * @public
+ */
+ public function Header() {
+ if ($this->header_xobjid < 0) {
+ // start a new XObject Template
+ $this->header_xobjid = $this->startTemplate($this->w, $this->tMargin + 10);
+ $headerfont = $this->getHeaderFont();
+ $headerdata = $this->getHeaderData();
+ $this->y = $this->header_margin;
+ if ($this->rtl) {
+ $this->x = $this->w - $this->original_rMargin;
+ } else {
+ $this->x = $this->original_lMargin - 10;
+ }
+ if (isset($this->QRCodeURL)) {
+ // QRCODE,H : QR-CODE Best error correction
+ $style = array(
+ 'border' => 1,
+ 'padding' => 0,
+ 'fgcolor' => array(
+ 0,
+ 0,
+ 0
+ ),
+ 'bgcolor' => false, //array(255,255,255)
+ 'module_width' => 1, // width of a single module in points
+ 'module_height' => 1
+ // height of a single module in points
+ );
+ $this->write2DBarcode($this->QRCodeURL, 'QRCODE,H', '', '', 25, 25, $style, 'T');
+ $imgy = 50 + 20;
+ } elseif (($headerdata['logo']) AND ($headerdata['logo'] != K_BLANK_IMAGE)) {
+ $imgtype = $this->getImageFileType(K_PATH_IMAGES . $headerdata['logo']);
+ if (($imgtype == 'eps') OR ($imgtype == 'ai')) {
+ $this->ImageEps(K_PATH_IMAGES . $headerdata['logo'], '', '', $headerdata['logo_width']);
+ } elseif ($imgtype == 'svg') {
+ $this->ImageSVG(K_PATH_IMAGES . $headerdata['logo'], '', '', $headerdata['logo_width']);
+ } else {
+ $this->Image(K_PATH_IMAGES . $headerdata['logo'], '', '', $headerdata['logo_width']);
+ }
+ $imgy = $this->getImageRBY();
+ } else {
+ $imgy = $this->y;
+ }
+ $cell_height = round(($this->cell_height_ratio * $headerfont[2]) / $this->k, 2);
+ // set starting margin for text data cell
+ if ($this->getRTL()) {
+ $header_x = $this->original_rMargin + ($headerdata['logo_width'] * 1.1);
+ } else {
+ $header_x = $this->original_lMargin + ($headerdata['logo_width'] * 1.1);
+ }
+ $cw = $this->w - $this->original_lMargin - $this->original_rMargin - ($headerdata['logo_width'] * 1.1);
+ $this->SetTextColor(0, 0, 0);
+ // header title
+ $this->SetFont($headerfont[0], 'B', $headerfont[2] + 1);
+ $this->SetX($header_x);
+ $this->Cell($cw, $cell_height, $headerdata['title'], 0, 1, '', 0, '', 0);
+ // header string
+ $this->SetFont($headerfont[0], $headerfont[1], $headerfont[2]);
+ $this->SetX($header_x);
+ $this->MultiCell($cw, $cell_height, $headerdata['string'], 0, '', 0, 1, '', '', true, 0, false);
+ // print an ending header line
+ //$this->SetLineStyle(array('width' => 0.85 / $this->k, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)));
+ //$this->SetY((2.835 / $this->k) + max($imgy, $this->y));
+ if ($this->rtl) {
+ $this->SetX($this->original_rMargin);
+ } else {
+ $this->SetX($this->original_lMargin);
+ }
+ //$this->Cell(($this->w - $this->original_lMargin - $this->original_rMargin), 0, '', 'T', 0, 'C');
+ $this->endTemplate();
+ }
+ // print header template
+ $x = 0;
+ $dx = 0;
+ if ($this->booklet AND (($this->page % 2) == 0)) {
+ // adjust margins for booklet mode
+ $dx = ($this->original_lMargin - $this->original_rMargin);
+ }
+ if ($this->rtl) {
+ $x = $this->w + $dx;
+ } else {
+ $x = 0 + $dx;
+ }
+ $this->printTemplate($this->header_xobjid, $x, 0, 0, 0, '', '', false);
+ }
+
}
+
$pdf = new Custom_TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
// set document information
$pdf->SetCreator(PDF_CREATOR);
@@ -150,14 +162,14 @@
$pdf->set_QRCodeURL(curPageURL() . "stop.php?stopid=" . $_REQUEST['stopid']);
// set header and footer fonts
$pdf->setHeaderFont(Array(
- PDF_FONT_NAME_MAIN,
- '',
- PDF_FONT_SIZE_MAIN
+ PDF_FONT_NAME_MAIN,
+ '',
+ PDF_FONT_SIZE_MAIN
));
$pdf->setFooterFont(Array(
- PDF_FONT_NAME_DATA,
- '',
- PDF_FONT_SIZE_DATA
+ PDF_FONT_NAME_DATA,
+ '',
+ PDF_FONT_SIZE_DATA
));
// set default monospaced font
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
@@ -191,6 +203,5 @@
//============================================================+
// END OF FILE
//============================================================+
-
?>
--- a/labs/stopBrowser.kml.php
+++ b/labs/stopBrowser.kml.php
@@ -1,62 +1,77 @@
<?php
- header('Content-type: application/vnd.google-earth.kml+xml');
+
+/*
+ * Copyright 2010,2011 Alexander Sadleir
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+header('Content-type: application/vnd.google-earth.kml+xml');
//http://wiki.openstreetmap.org/wiki/OpenLayers_Dynamic_KML
+// Creates the KML/XML Document.
+$dom = new DOMDocument('1.0', 'UTF-8');
-// Creates the KML/XML Document.
- $dom = new DOMDocument('1.0', 'UTF-8');
-
- // Creates the root KML element and appends it to the root document.
- $node = $dom->createElementNS('http://earth.google.com/kml/2.1', 'kml');
- $parNode = $dom->appendChild($node);
-
- // Creates a KML Document element and append it to the KML element.
- $dnode = $dom->createElement('Document');
- $docNode = $parNode->appendChild($dnode);
-
-
+// Creates the root KML element and appends it to the root document.
+$node = $dom->createElementNS('http://earth.google.com/kml/2.1', 'kml');
+$parNode = $dom->appendChild($node);
+
+// Creates a KML Document element and append it to the KML element.
+$dnode = $dom->createElement('Document');
+$docNode = $parNode->appendChild($dnode);
+
+
$bbox = $_GET['bbox']; // get the bbox param from google earth
-list($bbox_south, $bbox_west, $bbox_north,$bbox_east) = explode(",", $bbox); // west, south, east, north
+list($bbox_south, $bbox_west, $bbox_north, $bbox_east) = explode(",", $bbox); // west, south, east, north
include ('../include/common.inc.php');
$debugOkay = Array();
-$contents = getNearbyStops( (($bbox_west+ $bbox_east) /2), ($bbox_south + $bbox_north)/2 ,50, 3000);
+$contents = getNearbyStops((($bbox_west + $bbox_east) / 2), ($bbox_south + $bbox_north) / 2, 50, 3000);
foreach ($contents as $stop) {
- $description = 'http://bus.lambdacomplex.org/' . 'stop.php?stopid=' . $stop['stop_id'] ." <br>";
- $trips = getStopTripsWithTimes($stop['stop_id'], "", "", "", 3);
- if ($trips) {
- foreach ($trips as $key => $row) {
- if ($key < 3) {
- $description .= $row['route_short_name'] . ' ' . $row['route_long_name'] . ' @ ' . $row['arrival_time'] . "<br>";
- }
- }
- } else {
- $description .= "No more trips today";
- }
- // Creates a Placemark and append it to the Document.
- $node = $dom->createElement('Placemark');
- $placeNode = $docNode->appendChild($node);
-
- // Creates an id attribute and assign it the value of id column.
- $placeNode->setAttribute('id', 'placemark' . $stop['stop_id']);
-
- // Create name, and description elements and assigns them the values of the name and address columns from the results.
- $nameNode = $dom->createElement('name',htmlentities($stop['stop_name']));
- $descriptionNode = $dom->createElement('description',$description);
- $placeNode->appendChild($nameNode);
- $placeNode->appendChild($descriptionNode);
-
- // Creates a Point element.
- $pointNode = $dom->createElement('Point');
- $placeNode->appendChild($pointNode);
-
- // Creates a coordinates element and gives it the value of the lng and lat columns from the results.
- $coorStr = $stop['stop_lon'] . ',' . $stop['stop_lat'];
- $coorNode = $dom->createElement('coordinates', $coorStr);
- $pointNode->appendChild($coorNode);
- }
-
-
- $kmlOutput = $dom->saveXML();
- echo $kmlOutput;
+ $description = 'http://bus.lambdacomplex.org/' . 'stop.php?stopid=' . $stop['stop_id'] . " <br>";
+ $trips = getStopTripsWithTimes($stop['stop_id'], "", "", "", 3);
+ if ($trips) {
+ foreach ($trips as $key => $row) {
+ if ($key < 3) {
+ $description .= $row['route_short_name'] . ' ' . $row['route_long_name'] . ' @ ' . $row['arrival_time'] . "<br>";
+ }
+ }
+ } else {
+ $description .= "No more trips today";
+ }
+ // Creates a Placemark and append it to the Document.
+ $node = $dom->createElement('Placemark');
+ $placeNode = $docNode->appendChild($node);
+
+ // Creates an id attribute and assign it the value of id column.
+ $placeNode->setAttribute('id', 'placemark' . $stop['stop_id']);
+
+ // Create name, and description elements and assigns them the values of the name and address columns from the results.
+ $nameNode = $dom->createElement('name', htmlentities($stop['stop_name']));
+ $descriptionNode = $dom->createElement('description', $description);
+ $placeNode->appendChild($nameNode);
+ $placeNode->appendChild($descriptionNode);
+
+ // Creates a Point element.
+ $pointNode = $dom->createElement('Point');
+ $placeNode->appendChild($pointNode);
+
+ // Creates a coordinates element and gives it the value of the lng and lat columns from the results.
+ $coorStr = $stop['stop_lon'] . ',' . $stop['stop_lat'];
+ $coorNode = $dom->createElement('coordinates', $coorStr);
+ $pointNode->appendChild($coorNode);
+}
+
+
+$kmlOutput = $dom->saveXML();
+echo $kmlOutput;
?>
--- a/labs/stopBrowser.php
+++ b/labs/stopBrowser.php
@@ -1,102 +1,119 @@
<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <script src="openlayers/OpenLayers.js"></script>
- <SCRIPT TYPE="text/javascript" SRC="OpenStreetMap.js"></SCRIPT>
- <script type="text/javascript">
- var map,select;
+ <!--
+ /*
+ * Copyright 2010,2011 Alexander Sadleir
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+ -->
+ <head>
+ <script src="openlayers/OpenLayers.js"></script>
+ <SCRIPT TYPE="text/javascript" SRC="OpenStreetMap.js"></SCRIPT>
+ <script type="text/javascript">
+ var map,select;
-function init()
-{
- var extent = new OpenLayers.Bounds(148.98, -35.48, 149.25, -35.15);
+ function init()
+ {
+ var extent = new OpenLayers.Bounds(148.98, -35.48, 149.25, -35.15);
- // set up the map options
- var options =
- {
- maxExtent: extent,
- numZoomLevels: 20,
- };
+ // set up the map options
+ var options =
+ {
+ maxExtent: extent,
+ numZoomLevels: 20,
+ };
- // create the ol map object
- map = new OpenLayers.Map('map', options);
+ // create the ol map object
+ map = new OpenLayers.Map('map', options);
-var osmtiles = new OpenLayers.Layer.OSM("OSM");
+ var osmtiles = new OpenLayers.Layer.OSM("OSM");
-var nearmap = new OpenLayers.Layer.OSM.NearMap("NearMap");
+ var nearmap = new OpenLayers.Layer.OSM.NearMap("NearMap");
- var stopbrowser = new OpenLayers.Layer.Vector("POI", {
- projection: new OpenLayers.Projection("EPSG:4326"),
- strategies: [
- new OpenLayers.Strategy.BBOX(),
- ],
- protocol: new OpenLayers.Protocol.HTTP({
+ var stopbrowser = new OpenLayers.Layer.Vector("POI", {
+ projection: new OpenLayers.Projection("EPSG:4326"),
+ strategies: [
+ new OpenLayers.Strategy.BBOX(),
+ ],
+ protocol: new OpenLayers.Protocol.HTTP({
url: "stopBrowser.kml.php", //Note that it is probably worth adding a Math.random() on the end of the URL to stop caching.
- format: new OpenLayers.Format.KML({
- extractStyles: true,
- extractAttributes: true
+ format: new OpenLayers.Format.KML({
+ extractStyles: true,
+ extractAttributes: true
}),
- })
- });
+ })
+ });
- map.addLayers([osmtiles,stopbrowser,nearmap]);
+ map.addLayers([osmtiles,stopbrowser,nearmap]);
- var lonLat = new OpenLayers.LonLat(149.11, -35.28).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
- map.setCenter(lonLat, 15);
- map.addControl( new OpenLayers.Control.LayerSwitcher({'ascending':false}));
- map.addControl(new OpenLayers.Control.MousePosition(
- {
- displayProjection: new OpenLayers.Projection("EPSG:4326"),
- suffix: "__________________________________"
- }));
- map.addControl(new OpenLayers.Control.MousePosition(
- {
- displayProjection: new OpenLayers.Projection("EPSG:900913")
- }));
+ var lonLat = new OpenLayers.LonLat(149.11, -35.28).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
+ map.setCenter(lonLat, 15);
+ map.addControl( new OpenLayers.Control.LayerSwitcher({'ascending':false}));
+ map.addControl(new OpenLayers.Control.MousePosition(
+ {
+ displayProjection: new OpenLayers.Projection("EPSG:4326"),
+ suffix: "__________________________________"
+ }));
+ map.addControl(new OpenLayers.Control.MousePosition(
+ {
+ displayProjection: new OpenLayers.Projection("EPSG:900913")
+ }));
- select = new OpenLayers.Control.SelectFeature(stopbrowser);
+ select = new OpenLayers.Control.SelectFeature(stopbrowser);
- stopbrowser.events.on({
- "featureselected": onFeatureSelect,
- "featureunselected": onFeatureUnselect
- });
+ stopbrowser.events.on({
+ "featureselected": onFeatureSelect,
+ "featureunselected": onFeatureUnselect
+ });
- map.addControl(select);
- select.activate();
+ map.addControl(select);
+ select.activate();
-}
- function onPopupClose(evt) {
- select.unselectAll();
- }
- function onFeatureSelect(event) {
- var feature = event.feature;
- // Since KML is user-generated, do naive protection against
- // Javascript.
- var content = "<h2>"+feature.attributes.name + "</h2>" + feature.attributes.description;
- if (content.search("<script") != -1) {
- content = "Content contained Javascript! Escaped content below.<br />" + content.replace(/</g, "<");
}
- popup = new OpenLayers.Popup.FramedCloud("chicken",
- feature.geometry.getBounds().getCenterLonLat(),
- new OpenLayers.Size(100,100),
- content,
- null, true, onPopupClose);
- feature.popup = popup;
- map.addPopup(popup);
- }
- function onFeatureUnselect(event) {
- var feature = event.feature;
- if(feature.popup) {
- map.removePopup(feature.popup);
- feature.popup.destroy();
- delete feature.popup;
+ function onPopupClose(evt) {
+ select.unselectAll();
}
- }
- </script>
+ function onFeatureSelect(event) {
+ var feature = event.feature;
+ // Since KML is user-generated, do naive protection against
+ // Javascript.
+ var content = "<h2>"+feature.attributes.name + "</h2>" + feature.attributes.description;
+ if (content.search("<script") != -1) {
+ content = "Content contained Javascript! Escaped content below.<br />" + content.replace(/</g, "<");
+ }
+ popup = new OpenLayers.Popup.FramedCloud("chicken",
+ feature.geometry.getBounds().getCenterLonLat(),
+ new OpenLayers.Size(100,100),
+ content,
+ null, true, onPopupClose);
+ feature.popup = popup;
+ map.addPopup(popup);
+ }
+ function onFeatureUnselect(event) {
+ var feature = event.feature;
+ if(feature.popup) {
+ map.removePopup(feature.popup);
+ feature.popup.destroy();
+ delete feature.popup;
+ }
+ }
+ </script>
- </head>
- <body onload="init()">
- <div id="map" width="100%" height="100%" class="smallmap"></div>
- </body>
+ </head>
+ <body onload="init()">
+ <div id="map" width="100%" height="100%" class="smallmap"></div>
+ </body>
</html>
--- a/labs/travelAllRoutes.php
+++ /dev/null
@@ -1,23 +1,1 @@
-<?php
-include ('../include/common.inc.php');
- $query = "Select route_short_name,max(route_id) as route_id from routes where route_short_name NOT LIKE '7__' AND route_short_name != '170' AND route_short_name NOT LIKE '9__' group by route_short_name order by route_short_name ;";
- debug($query, "database");
- $query = $conn->prepare($query);
- $query->execute();
-echo "<table><tr><th>Route Number</th><th>First Trip Start</th><th>First Trip End</th><th>Length</th>";
-$total = 0;
-$count = 0;
-foreach($query->fetchAll() as $r) {
- $trips = getRouteTrips($r['route_id']);
- $startTime = $trips[0]['arrival_time'];
- $endTime = getTripEndTime($trips[0]['trip_id']);
- $timeDiff = strtotime($endTime) - strtotime($startTime);
- $total += $timeDiff;
- $count ++;
- echo "<tr><td>{$r['route_short_name']}</td><td>$startTime</td><td>$endTime</td><td>$timeDiff seconds ie. ". ($timeDiff/60). " minutes</td></tr>";
-}
-echo "</table>";
-echo "Total time: $total seconds ie. " .($total/60/60). " hours<br>";
-echo "$count Routes";
-?>
--- a/labs/tripPlannerTester.kml.php
+++ /dev/null
@@ -1,208 +1,1 @@
-<?php
-// http://www.herethere.net/~samson/php/color_gradient/color_gradient_generator.php.txt
-// return the interpolated value between pBegin and pEnd
-function interpolate($pBegin, $pEnd, $pStep, $pMax)
-{
- if ($pBegin < $pEnd) {
- return (($pEnd - $pBegin) * ($pStep / $pMax)) + $pBegin;
- }
- else {
- return (($pBegin - $pEnd) * (1 - ($pStep / $pMax))) + $pEnd;
- }
-}
-require ("../lib/rolling-curl/RollingCurl.php");
-function processResult_cb($response, $info, $request)
-{
- global $testRegions, $regionTimes,$csv,$kml, $latdeltasize,$londeltasize;
- $md = $request->metadata;
- $tripplan = json_decode($response);
- $plans = Array();
- //var_dump(Array($info, $request));
- if (is_array($tripplan->plan->itineraries->itinerary)) {
- foreach ($tripplan->plan->itineraries->itinerary as $itineraryNumber => $itinerary) {
- $plans[floor($itinerary->duration / 60000) ] = $itinerary;
- }
- }
- else {
- $plans[floor($tripplan->plan->itineraries->itinerary->duration / 60000) ] = $tripplan->plan->itineraries->itinerary;
- }
- if ($csv) echo "{$md['i']},{$md['j']}," . min(array_keys($plans)) . ",$latdeltasize, $londeltasize,{$md['key']}\n";
- if ($kml) {
- $time = min(array_keys($plans));
- $plan = "";
- if (is_array($plans[min(array_keys($plans)) ]->legs->leg)) {
- foreach ($plans[min(array_keys($plans)) ]->legs->leg as $legNumber => $leg) {
- $plan.= processLeg($legNumber, $leg) . ",";
- }
- }
- else {
- $plan.= processLeg(0, $plans[min(array_keys($plans)) ]->legs->leg);
- }
- if (isset($tripplan->error) && $tripplan->error->id == 404) {
- $time = 999;
- $plan = "Trip not possible without excessive walking from nearest bus stop";
- }
- $testRegions[] = Array(
- "lat" => $md['i'],
- "lon" => $md['j'],
- "time" => $time,
- "latdeltasize" => $latdeltasize,
- "londeltasize" => $londeltasize,
- "regionname" => $md['key'],
- "plan" => $plan . '<br/><a href="' . htmlspecialchars($md['url']) . '">original plan</a>'
- );
- $regionTimes[] = $time;
- }
-}
-function Gradient($HexFrom, $HexTo, $ColorSteps)
-{
- $theColorBegin = hexdec($HexFrom);
- $theColorEnd = hexdec($HexTo);
- $theNumSteps = intval($ColorSteps);
- $theR0 = ($theColorBegin & 0xff0000) >> 16;
- $theG0 = ($theColorBegin & 0x00ff00) >> 8;
- $theB0 = ($theColorBegin & 0x0000ff) >> 0;
- $theR1 = ($theColorEnd & 0xff0000) >> 16;
- $theG1 = ($theColorEnd & 0x00ff00) >> 8;
- $theB1 = ($theColorEnd & 0x0000ff) >> 0;
- $GradientColors = array();
- // generate gradient swathe now
- for ($i = 0; $i <= $theNumSteps; $i++) {
- $theR = interpolate($theR0, $theR1, $i, $theNumSteps);
- $theG = interpolate($theG0, $theG1, $i, $theNumSteps);
- $theB = interpolate($theB0, $theB1, $i, $theNumSteps);
- $theVal = ((($theR << 8) | $theG) << 8) | $theB;
- $GradientColors[] = sprintf("%06X", $theVal);
- }
- return $GradientColors;
-}
-function processLeg($legNumber, $leg)
-{
- $legArray = object2array($leg);
- if ($legArray["@mode"] === "BUS") {
- return "bus {$legArray['@route']} " . str_replace("To", "towards", $legArray['@headsign']);
- }
- else {
- return "walk";
- //$walkingstep = "walk ";
- //if (strpos($step->streetName, "from") !== false && strpos($step->streetName, "way") !== false) {
- // $walkingstep.= "footpath";
- //}
- //else {
- // $walkingstep.= $step->streetName;
- //}
- //$walkingstep.= floor($step->distance) . "m";
- //return $walkingstep;
-
- }
-}
-$csv = false;
-$kml = true;
-$gearthcolors = false;
-if ($kml) {
- header('Content-Type: application/vnd.google-earth.kml+xml');
- echo '<?xml version="1.0" encoding="UTF-8"?>
-<kml xmlns="http://www.opengis.net/kml/2.2"><Document>';
-}
-include ('../include/common.inc.php');
-$boundingBoxes = Array(
- "belconnen" => Array(
- "startlat" => - 35.1928,
- "startlon" => 149.006,
- "finishlat" => - 35.2630,
- "finishlon" => 149.1045,
- ) ,
- "north gungahlin civic" => Array(
- "startlat" => - 35.1828,
- "startlon" => 149.1045,
- "finishlat" => - 35.2955,
- "finishlon" => 149.1559,
- ) ,
- "west duffy" => Array(
- "startlat" => - 35.3252,
- "startlon" => 149.0240,
- "finishlat" => - 35.3997,
- "finishlon" => 149.0676,
- ) ,
- "central south" => Array(
- "startlat" => - 35.3042,
- "startlon" => 149.0762,
- "finishlat" => - 35.3370,
- "finishlon" => 149.1806,
- ) ,
- "south" => Array(
- "startlat" => - 35.3403,
- "startlon" => 149.0714,
- "finishlat" => - 35.4607,
- "finishlon" => 149.1243,
- )
-);
-$latdeltasize = 0.005;
-$londeltasize = 0.005;
-$from = "Wattle Street";
-$fromPlace = (startsWith($from, "-") ? $from : geocode($from, false));
-$startTime = "9:00 am";
-$startDate = "03/21/2011"; // american dates, OTP does not validate!
-$counter = 0;
-$regionTimes = Array();
-$testRegions = Array();
-$useragent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1";
-if ($kml) echo "<name> $from at $startTime on $startDate </name>";
-if ($csv) echo "<pre>";
-if ($csv) echo "lat,lon,time,latdeltasize, londeltasize, region key name\n";
-$rc = new RollingCurl("processResult_cb");
-$rc->window_size = 2;
-foreach ($boundingBoxes as $key => $boundingBox) {
- for ($i = $boundingBox['startlat']; $i >= $boundingBox['finishlat']; $i-= $latdeltasize) {
- for ($j = $boundingBox['startlon']; $j <= $boundingBox['finishlon']; $j+= $londeltasize) {
- $url = $otpAPIurl . "ws/plan?date=" . urlencode($startDate) . "&time=" . urlencode($startTime) . "&mode=TRANSIT%2CWALK&optimize=QUICK&maxWalkDistance=440&wheelchair=false&toPlace=" . $i . "," . $j . "&fromPlace=$fromPlace";
- //debug($url);
- $request = new RollingCurlRequest($url);
- $request->headers = Array(
- "Accept: application/json"
- );
- $request->metadata = Array( "i" => $i, "j" => $j, "key" => $key, "url" => $url);
- $rc->add($request);
- }
- }
-}
-$rc->execute();
-if ($kml) {
- $colorSteps = 9;
- //$minTime = min($regionTimes);
- //$maxTime = max($regionTimes);
- //$rangeTime = $maxTime - $minTime;
- //$deltaTime = $rangeTime / $colorSteps;
- $Gradients = Gradient(strrev("66FF00") , strrev("FF0000") , $colorSteps); // KML is BGR not RGB so strrev
- foreach ($testRegions as $testRegion) {
- //$band = (floor(($testRegion[time] - $minTime) / $deltaTime));
- $band = (floor($testRegion[time] / 10));
- if ($band > $colorSteps) $band = $colorSteps;
- echo "<Placemark>
- <name>" . $testRegion['regionname'] . " time {$testRegion['time']} band $band</name>
- <description> <![CDATA[ {$testRegion['plan']} ]]> </description>
- <Style>
- <PolyStyle>
- <color>c7" . $Gradients[$band] . "</color>" . // 7f = 50% alpha, c7=78%
- "</PolyStyle>
- <LineStyle>
- <color>c7" . $Gradients[$band] . "</color>" . "</LineStyle>
- </Style>
- <Polygon>
-<altitudeMode>relativeToGround</altitudeMode>
- <outerBoundaryIs>
- <LinearRing>
- <coordinates>
- " . ($testRegion['lon'] - ($testRegion['londeltasize'] / 2)) . "," . ($testRegion['lat'] - ($testRegion['latdeltasize'] / 2)) . ",500\n" . ($testRegion['lon'] - ($testRegion['londeltasize'] / 2)) . "," . ($testRegion['lat'] + ($testRegion['latdeltasize'] / 2)) . ",500\n" . ($testRegion['lon'] + ($testRegion['londeltasize'] / 2)) . "," . ($testRegion['lat'] + ($testRegion['latdeltasize'] / 2)) . ",500\n" . ($testRegion['lon'] + ($testRegion['londeltasize'] / 2)) . "," . ($testRegion['lat'] - ($testRegion['latdeltasize'] / 2)) . ",500\n" . ($testRegion['lon'] - ($testRegion['londeltasize'] / 2)) . "," . ($testRegion['lat'] - ($testRegion['latdeltasize'] / 2)) . ",500\n" . "
-
- </coordinates>
- </LinearRing>
- </outerBoundaryIs>
- </Polygon>
-</Placemark>";
- }
- echo "\n</Document></kml>\n";
-}
-if ($csv) echo "</pre>";
-?>
--- a/labs/tripPlannerTester.php
+++ /dev/null
@@ -1,96 +1,1 @@
-<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <script src="openlayers/OpenLayers.js"></script>
- <SCRIPT TYPE="text/javascript" SRC="OpenStreetMap.js"></SCRIPT>
- <script type="text/javascript">
- var map,select;
-
-
-function init()
-{
- var extent = new OpenLayers.Bounds(148.98, -35.48, 149.25, -35.15);
-
- // set up the map options
- var options =
- {
- maxExtent: extent,
- numZoomLevels: 20,
- };
-
- // create the ol map object
- map = new OpenLayers.Map('map', options);
-
-var osmtiles = new OpenLayers.Layer.OSM("OSM");
-var nearmap = new OpenLayers.Layer.OSM.NearMap("NearMap");
-
- var tripplantest = new OpenLayers.Layer.GML("tripplantest", "tripPlannerTester.kml", {
- format: OpenLayers.Format.KML,
- formatOptions: {
- extractStyles: true,
- extractAttributes: true,
- maxDepth: 2
- }
- });
- map.addLayers([osmtiles,tripplantest,nearmap]);
-
- var lonLat = new OpenLayers.LonLat(149.11, -35.28).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
- map.setCenter(lonLat, 11);
- map.addControl( new OpenLayers.Control.LayerSwitcher({'ascending':false}));
- map.addControl(new OpenLayers.Control.MousePosition(
- {
- displayProjection: new OpenLayers.Projection("EPSG:4326"),
- suffix: "__________________________________"
- }));
- map.addControl(new OpenLayers.Control.MousePosition(
- {
- displayProjection: new OpenLayers.Projection("EPSG:900913")
- }));
-
- select = new OpenLayers.Control.SelectFeature(tripplantest);
-
- tripplantest.events.on({
- "featureselected": onFeatureSelect,
- "featureunselected": onFeatureUnselect
- });
-
- map.addControl(select);
- select.activate();
-
-}
- function onPopupClose(evt) {
- select.unselectAll();
- }
- function onFeatureSelect(event) {
- var feature = event.feature;
- // Since KML is user-generated, do naive protection against
- // Javascript.
- var content = "<h2>"+feature.attributes.name + "</h2>" + feature.attributes.description;
- if (content.search("<script") != -1) {
- content = "Content contained Javascript! Escaped content below.<br />" + content.replace(/</g, "<");
- }
- popup = new OpenLayers.Popup.FramedCloud("chicken",
- feature.geometry.getBounds().getCenterLonLat(),
- new OpenLayers.Size(100,100),
- content,
- null, true, onPopupClose);
- feature.popup = popup;
- map.addPopup(popup);
- }
- function onFeatureUnselect(event) {
- var feature = event.feature;
- if(feature.popup) {
- map.removePopup(feature.popup);
- feature.popup.destroy();
- delete feature.popup;
- }
- }
- </script>
-
- </head>
- <body onload="init()">
- <div id="map" width="100%" height="100%" class="smallmap"></div>
- </body>
-</html>
-
-
--- a/layar_api.php
+++ b/layar_api.php
@@ -1,4 +1,20 @@
<?php
+
+/*
+ * Copyright 2010,2011 Alexander Sadleir
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
include ('include/common.inc.php');
$output = Array();
$output['hotspots'] = Array();
@@ -10,47 +26,46 @@
$contents = getNearbyStops($lat, $lon, 50, $max_distance);
$stopNum = 0;
foreach ($contents as $stop) {
- $stopNum++;
- if ($stopNum > $page_start && $stopNum <= $page_end) {
- $hotspot = Array();
- $hotspot['id'] = $stop['stop_id'];
- $hotspot['title'] = $stop['stop_name'];
- $hotspot['type'] = 0;
- $hotspot['lat'] = floor($stop['stop_lat'] * 1000000);
- $hotspot['lon'] = floor($stop['stop_lon'] * 1000000);
- $hotspot['distance'] = floor($stop['distance']);
- $hotspot['attribution'] = "ACTION Buses";
- $hotspot['actions'] = Array(
- Array(
- "label" => 'View more trips/information',
- 'uri' => 'http://bus.lambdacomplex.org/' . 'stop.php?stopid=' . $stop['stop_id']
- )
- );
- $trips = getStopTripsWithTimes($stop['stop_id'], "", "", "", 3);
- foreach ($trips as $key => $row) {
- if ($key < 3) {
- $hotspot['line' . strval($key + 2) ] = $row['route_short_name'] . ' ' . $row['route_long_name'] . ' @ ' . $row['arrival_time'];
- }
- }
- if (sizeof($trips) == 0) $hotspot['line2'] = 'No trips in the near future.';
- $output['hotspots'][] = $hotspot;
- }
+ $stopNum++;
+ if ($stopNum > $page_start && $stopNum <= $page_end) {
+ $hotspot = Array();
+ $hotspot['id'] = $stop['stop_id'];
+ $hotspot['title'] = $stop['stop_name'];
+ $hotspot['type'] = 0;
+ $hotspot['lat'] = floor($stop['stop_lat'] * 1000000);
+ $hotspot['lon'] = floor($stop['stop_lon'] * 1000000);
+ $hotspot['distance'] = floor($stop['distance']);
+ $hotspot['attribution'] = "ACTION Buses";
+ $hotspot['actions'] = Array(
+ Array(
+ "label" => 'View more trips/information',
+ 'uri' => 'http://bus.lambdacomplex.org/' . 'stop.php?stopid=' . $stop['stop_id']
+ )
+ );
+ $trips = getStopTripsWithTimes($stop['stop_id'], "", "", "", 3);
+ foreach ($trips as $key => $row) {
+ if ($key < 3) {
+ $hotspot['line' . strval($key + 2)] = $row['route_short_name'] . ' ' . $row['route_long_name'] . ' @ ' . $row['arrival_time'];
+ }
+ }
+ if (sizeof($trips) == 0)
+ $hotspot['line2'] = 'No trips in the near future.';
+ $output['hotspots'][] = $hotspot;
+ }
}
if (sizeof($hotspot) > 0) {
- $output['errorString'] = 'ok';
- $output['errorCode'] = 0;
+ $output['errorString'] = 'ok';
+ $output['errorCode'] = 0;
+} else {
+ $output['errorString'] = 'no results, try increasing range';
+ $output['errorCode'] = 21;
}
-else {
- $output['errorString'] = 'no results, try increasing range';
- $output['errorCode'] = 21;
-}
-if ($page_end >= $max_results || sizeof($contents) < $page_start+$max_page) {
- $output["morePages"] = false;
- $output["nextPageKey"] = null;
-}
-else {
- $output["morePages"] = true;
- $output["nextPageKey"] = $page_end;
+if ($page_end >= $max_results || sizeof($contents) < $page_start + $max_page) {
+ $output["morePages"] = false;
+ $output["nextPageKey"] = null;
+} else {
+ $output["morePages"] = true;
+ $output["nextPageKey"] = $page_end;
}
echo json_encode($output);
?>
--- /dev/null
+++ b/lib/Protobuf-PHP/LICENSE
@@ -1,1 +1,21 @@
+The MIT License
+Copyright (c) 2011 Iván -DrSlump- Montes
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
--- /dev/null
+++ b/lib/Protobuf-PHP/README.md
@@ -1,1 +1,198 @@
+Protobuf for PHP
+================
+Protobuf for PHP is an implementation of Google's Protocol Buffers for the PHP
+language, supporting its binary data serialization and including a `protoc`
+plugin to generate PHP classes from .proto files.
+
+Great effort has been put into generating PHP files that include all sort of type
+hints to aide IDE's with autocompletion. Therefore, it can not only be used to
+communicate with Protocol Buffers services but also as a generation tool for
+_data objects_ no matter what the final serialization is.
+
+For more information see the [included man pages](http://drslump.github.com/Protobuf-PHP/).
+
+
+## Requirements
+
+ - PHP 5.3
+ - Pear's Console_CommandLine (for the protoc wrapper tool)
+ - Google's `protoc` compiler version 2.3 or above
+ - GMP or BC Math extensions ¹
+
+ ¹ Only needed for negative values in `int32`, `int64` or `fixed64` types. See
+ the _known issues_ section.
+
+
+## Features
+
+### Working
+
+ - Standard types (numbers, string, enums, messages, etc)
+ - Pluggable serialization backends (codecs)
+ - Standard Binary
+ - Standard TextFormat ¹
+ - PhpArray
+ - JSON
+ - [ProtoJson](https://github.com/drslump/ProtoJson) (_TagMap_ and _Indexed_ variants)
+ - XML
+ - Protoc compiler plugin to generate the PHP classes
+ - Extensions
+ - Unknown fields
+ - Packed fields
+ - Reflection
+ - Dynamic messages with annotations support
+ - Generates service interfaces
+ - Includes comments from .proto files in the generated files
+ - Pear package for easy installation
+
+¹ Only serialization is supported
+
+### Future
+
+ - Speed optimized code generation mode
+ - Support numbers beyond PHP's native limits
+
+
+
+## Example usage
+
+ $person = new Tutorial\Person();
+ $person->name = 'DrSlump';
+ $person->setId(12);
+
+ $book = new Tutorial\AddressBook();
+ $book->addPerson($person);
+
+ // Use default codec
+ $data = $book->serialize();
+
+ // Use custom codec
+ $codec = new \DrSlump\Protobuf\Codec\Binary();
+ $data = $codec->encode($book);
+ // ... or ...
+ $data = $book->serialize($codec);
+
+
+## Installation
+
+Install with Pear
+
+ pear channel-discover pear.pollinimini.net
+ pear install drslump/Protobuf-beta
+
+You can also get the latest version by checking out a copy of the
+repository in your computer.
+
+
+
+## Known issues
+
+
+### Types
+
+PHP is very weak when dealing with numbers processing. Several work arounds have been applied
+to the standard binary codec to reduce incompatibilities between Protobuf types and PHP ones.
+
+ - Protobuf stores floating point values using the [IEEE 754](http://en.wikipedia.org/wiki/IEEE_754) standard
+ with 64bit words for the `double` and 32bit for the `float` types. PHP supports IEEE 754 natively although
+ the precission is platform dependant, however it typically supports 64bit doubles. It means that
+ if your PHP was compiled with 64bit sized doubles (or greater) you shouldn't have any problem encoding
+ and decoded float and double typed values with Protobuf.
+
+ - Integer values are also [platform dependant in PHP](http://www.php.net/manual/en/language.types.integer.php).
+ The library has been developed and tested against PHP binaries compiled with 64bit integers. The encoding and
+ decoding algorithm should in theory work no matter if PHP uses 32bit or 64bit integers internally, just take
+ into account that with 32bit integers the numbers cannot exceed in any case the `PHP_INT_MAX` value (2147483647).
+
+ While Protobuf supports unsigned integers PHP does not. In fact, numbers above the compiled PHP maximum
+ integer (`PHP_INT_MAX`, 0x7FFFFFFFFFFFFFFF for 64bits) will be automatically casted to doubles, which
+ typically will offer 53bits of decimal precission, allowing to safely work with numbers upto
+ 0x20000000000000 (2^53), even if they are represented in PHP as floats instead of integers. Higher numbers
+ will loose precission or might even return an _infinity_ value, note that the library does not include
+ any checking for these numbers and using them might provoke unexpected behaviour.
+
+ Negative values when encoded as `int32`, `int64` or `fixed64` types require the big integer extensions
+ [GMP](http://www.php.net/gmp) or [BC Math](http://www.php.net/bc) (the later only for 64bit architectures)
+ to be available in your PHP environment. The reason is that when encoding these negative numbers without
+ using _zigzag_ the binary representation uses the most significant bit for the sign, thus the numbers become
+ above the maximum supported values in PHP. The library will check for these conditions and will automatically
+ try to use GMP or BC to process the value.
+
+
+### Strings
+
+The binary codec expects strings to be encoded using UTF-8. PHP does not natively support string encodings,
+PHP's string data type is basically a length delimited stream of bytes, so it's not trivial to include
+automatic encoding conversion into the library encoding and decoding routines. Instead of trying to guess
+or offer a configuration interface for the encoding, the binary codec will process the `string` type just as
+it would process `byte` one, delegating on your application the task of encoding or decoding in the desired
+character set.
+
+### Memory usage
+
+Large messages might be troublesome since the way the library is modelled does not allow to parse or
+serialize messages as a streams, instead the whole operation is performed in memory, which allows for faster
+processing but could consume too much RAM if messages are too large.
+
+
+### Unknown fields
+
+Since wire types are different across different codec's formats, it's not possible to transcode unkwnon
+fields consumed in one codec to another. This means, for example, that when consuming a message using the
+binary codec, if it contains unknown fields, they won't be included when serializing the message using the
+Json codec.
+
+
+## Generating PHP classes
+
+The generation tool is designed to be run as a `protoc` plugin, thus it should
+work with any proto file supported by the official compiler.
+
+ protoc --plugin=protoc-gen-php --php_out=./build tutorial.proto
+
+To make use of non-standard options in your proto files (like `php.namespace`) you'll
+have to import the `php.proto` file included with the library. It's location will
+depend on where you've installed this library.
+
+ protoc -I=./Protobuf-PHP/library/DrSlump/Protobuf/Compiler/protos \
+ --plugin=protoc-gen-php --php_out=./build tutorial.proto
+
+In order to make your life easier, the supplied protoc plugin offers an additional
+execution mode, where it acts as a wrapper for the `protoc` invocation. It will
+automatically include the `php.proto` path so that you don't need to worry about it.
+
+ protoc-gen-php -o ./build tutorial.proto
+
+
+## LICENSE:
+
+ The MIT License
+
+ Copyright (c) 2011 Iván -DrSlump- Montes
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ 'Software'), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+
+
+
+
+
--- /dev/null
+++ b/lib/Protobuf-PHP/Rakefile
@@ -1,1 +1,120 @@
+# encoding: utf-8
+namespace :pear do
+ support_files = ['README.md', 'LICENSE', 'protoc-gen-php.php', 'protoc-gen-php.bat']
+ tpl_file = 'package.pear'
+ xml_file = 'library/package.xml'
+
+ desc "Generate package.xml"
+ task :xml => [:clean] do |t, args|
+ unless ENV['version'] then
+ puts 'Version number not given. Use "pear:xml version=1.0"'
+ exit 1
+ end
+
+ # Get template contents
+ text = File.read(tpl_file, :encoding => "UTF-8")
+ # Replace the version, date and time
+ text = text.gsub("{VERSION}", ENV['version'])
+ text = text.gsub('{DATE}', Time.now.strftime('%Y-%m-%d'))
+ text = text.gsub('{TIME}', Time.now.strftime('%H:%M:%S'))
+
+ # Include source files
+ dirs = []
+ Dir.glob('library/**/*.*') do |file|
+ file[0, 'library/'.length] = ''
+ dirs << '<file name="' + file + '" role="php">'
+ dirs << '<tasks:replace from="@package_version@" to="version" type="package-info" />'
+ dirs << '</file>'
+ end
+
+ text = text.gsub('{DIRS}', dirs.join("\n"))
+
+ # Generate a new pear package.xml
+ xml = File.new(xml_file, 'w')
+ xml.syswrite(text);
+ xml.close();
+ end
+
+ desc "Build a release"
+ task :package => ['doc:build', :xml] do
+
+ # Copy supporting files to the package root
+
+ support_files.each do |file|
+ cp file, "library/#{file}"
+ end
+
+ begin
+ sh "pear package -n #{xml_file}"
+ rescue Exception => e
+ puts "Rolling back..."
+ Rake::Task['pear:clean'].execute
+ raise
+ end
+
+ Rake::Task['pear:clean'].execute
+ end
+
+ desc "Clean up"
+ task :clean do
+ puts "Cleaning up..."
+
+ # Remove package.xml
+ rm_f xml_file
+
+ # Remove supporting files
+ support_files.each { |file| rm_f "library/#{file}" }
+ end
+
+end
+
+namespace :doc do
+
+ desc "Generate manual"
+ task :build do
+ version = ENV['version']
+ ENV['RONN_MANUAL'] = "Protobuf-PHP #{version}"
+ ENV['RONN_ORGANIZATION'] = "Ivan -DrSlump- Montes"
+ sh "ronn -w -s toc -r5 --markdown man/*.ronn"
+ end
+
+ desc 'Publish to github pages'
+ task :github => 'doc:build' do
+ require 'git'
+ require 'logger'
+
+ remote = `git remote show origin`
+ .split(%r{\n}) # Ruby 1.9 only has grep() on Array
+ .grep(/Push.*URL/)
+ .first[/git@.*/]
+
+ files = [
+ 'protoc-gen-php.1.html',
+ 'protobuf-php.3.html',
+ 'protobuf-php.5.html',
+ ]
+
+ root = "/tmp/checkout-#{Time.now.to_i}"
+ g = Git.clone(remote, root, :log => Logger.new(STDOUT))
+
+ # Make sure this actually switches branches.
+ g.checkout(g.branch('gh-pages'))
+
+ files.each {|file|
+ cp "man/#{file}", "#{root}/."
+ g.add(file)
+ }
+
+ g.commit('Regenerating Github Pages.')
+
+ # PUSH!
+ g.push(g.remote('origin'), g.branch('gh-pages'))
+
+ puts '--> GitHub Pages Commit and Push successful.'
+ end
+
+end
+
+
+
--- /dev/null
+++ b/lib/Protobuf-PHP/gtfs-realtime.php
@@ -1,1 +1,3673 @@
-
+<?php
+// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin @package_version@
+// cmd line php -f protoc-gen-php.php gtfs-realtime.proto -i ./
+// Source: gtfs-realtime.proto
+// Date: 2011-08-23 07:08:46
+
+// @@protoc_insertion_point(scope_file)
+
+namespace transit_realtime {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime)
+
+ class FeedMessage extends \DrSlump\Protobuf\Message {
+
+ /** @var \Closure[] */
+ protected static $__extensions = array();
+
+ public static function descriptor()
+ {
+ $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.FeedMessage');
+
+ // required .transit_realtime.FeedHeader header = 1
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 1;
+ $f->name = "header";
+ $f->type = 11;
+ $f->rule = 2;
+ $f->reference = '\transit_realtime\FeedHeader';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.FeedMessage:header)
+ $descriptor->addField($f);
+
+ // repeated .transit_realtime.FeedEntity entity = 2
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 2;
+ $f->name = "entity";
+ $f->type = 11;
+ $f->rule = 3;
+ $f->reference = '\transit_realtime\FeedEntity';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.FeedMessage:entity)
+ $descriptor->addField($f);
+
+ foreach (self::$__extensions as $cb) {
+ $descriptor->addField($cb(), true);
+ }
+
+ // @@protoc_insertion_point(scope_descriptor)
+ // @@protoc_insertion_point(descriptor_transit_realtime.FeedMessage)
+
+ return $descriptor;
+ }
+
+ /** @var \transit_realtime\FeedHeader */
+ public $header = null;
+
+ /** @var \transit_realtime\FeedEntity[] */
+ public $entity = array();
+
+
+ /**
+ * Check if <header> has a value
+ *
+ * @return boolean
+ */
+ public function hasHeader(){
+ return $this->_has(1);
+ }
+
+ /**
+ * Clear <header> value
+ *
+ * @return \transit_realtime\FeedMessage
+ */
+ public function clearHeader(){
+ return $this->_clear(1);
+ }
+
+ /**
+ * Get <header> value
+ *
+ * @return \transit_realtime\FeedHeader
+ */
+ public function getHeader(){
+ return $this->_get(1);
+ }
+
+ /**
+ * Set <header> value
+ *
+ * @param \transit_realtime\FeedHeader $value
+ * @return \transit_realtime\FeedMessage
+ */
+ public function setHeader(\transit_realtime\FeedHeader $value){
+ return $this->_set(1, $value);
+ }
+
+ /**
+ * Check if <entity> has a value
+ *
+ * @return boolean
+ */
+ public function hasEntity(){
+ return $this->_has(2);
+ }
+
+ /**
+ * Clear <entity> value
+ *
+ * @return \transit_realtime\FeedMessage
+ */
+ public function clearEntity(){
+ return $this->_clear(2);
+ }
+
+ /**
+ * Get <entity> value
+ *
+ * @param int $idx
+ * @return \transit_realtime\FeedEntity
+ */
+ public function getEntity($idx = NULL){
+ return $this->_get(2, $idx);
+ }
+
+ /**
+ * Set <entity> value
+ *
+ * @param \transit_realtime\FeedEntity $value
+ * @return \transit_realtime\FeedMessage
+ */
+ public function setEntity(\transit_realtime\FeedEntity $value, $idx = NULL){
+ return $this->_set(2, $value, $idx);
+ }
+
+ /**
+ * Get all elements of <entity>
+ *
+ * @return \transit_realtime\FeedEntity[]
+ */
+ public function getEntityList(){
+ return $this->_get(2);
+ }
+
+ /**
+ * Add a new element to <entity>
+ *
+ * @param \transit_realtime\FeedEntity $value
+ * @return \transit_realtime\FeedMessage
+ */
+ public function addEntity(\transit_realtime\FeedEntity $value){
+ return $this->_add(2, $value);
+ }
+
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.FeedMessage)
+ }
+}
+
+namespace transit_realtime\FeedHeader {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime.FeedHeader)
+
+ class Incrementality {
+ const FULL_DATASET = 0;
+ const DIFFERENTIAL = 1;
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.FeedHeader.Incrementality)
+ }
+}
+namespace transit_realtime {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime)
+
+ class FeedHeader extends \DrSlump\Protobuf\Message {
+
+ /** @var \Closure[] */
+ protected static $__extensions = array();
+
+ public static function descriptor()
+ {
+ $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.FeedHeader');
+
+ // required gtfs_realtime_version = 1
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 1;
+ $f->name = "gtfs_realtime_version";
+ $f->type = 9;
+ $f->rule = 2;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.FeedHeader:gtfs_realtime_version)
+ $descriptor->addField($f);
+
+ // optional .transit_realtime.FeedHeader.Incrementality incrementality = 2
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 2;
+ $f->name = "incrementality";
+ $f->type = 14;
+ $f->rule = 1;
+ $f->reference = '\transit_realtime\FeedHeader\Incrementality';
+ $f->default = \transit_realtime\FeedHeader\Incrementality::FULL_DATASET;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.FeedHeader:incrementality)
+ $descriptor->addField($f);
+
+ // optional timestamp = 3
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 3;
+ $f->name = "timestamp";
+ $f->type = 4;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.FeedHeader:timestamp)
+ $descriptor->addField($f);
+
+ foreach (self::$__extensions as $cb) {
+ $descriptor->addField($cb(), true);
+ }
+
+ // @@protoc_insertion_point(scope_descriptor)
+ // @@protoc_insertion_point(descriptor_transit_realtime.FeedHeader)
+
+ return $descriptor;
+ }
+
+ /** @var string */
+ public $gtfs_realtime_version = null;
+
+ /** @var int - \transit_realtime\FeedHeader\Incrementality */
+ public $incrementality = \transit_realtime\FeedHeader\Incrementality::FULL_DATASET;
+
+ /** @var int */
+ public $timestamp = null;
+
+
+ /**
+ * Check if <gtfs_realtime_version> has a value
+ *
+ * @return boolean
+ */
+ public function hasGtfsRealtimeVersion(){
+ return $this->_has(1);
+ }
+
+ /**
+ * Clear <gtfs_realtime_version> value
+ *
+ * @return \transit_realtime\FeedHeader
+ */
+ public function clearGtfsRealtimeVersion(){
+ return $this->_clear(1);
+ }
+
+ /**
+ * Get <gtfs_realtime_version> value
+ *
+ * @return string
+ */
+ public function getGtfsRealtimeVersion(){
+ return $this->_get(1);
+ }
+
+ /**
+ * Set <gtfs_realtime_version> value
+ *
+ * @param string $value
+ * @return \transit_realtime\FeedHeader
+ */
+ public function setGtfsRealtimeVersion( $value){
+ return $this->_set(1, $value);
+ }
+
+ /**
+ * Check if <incrementality> has a value
+ *
+ * @return boolean
+ */
+ public function hasIncrementality(){
+ return $this->_has(2);
+ }
+
+ /**
+ * Clear <incrementality> value
+ *
+ * @return \transit_realtime\FeedHeader
+ */
+ public function clearIncrementality(){
+ return $this->_clear(2);
+ }
+
+ /**
+ * Get <incrementality> value
+ *
+ * @return int - \transit_realtime\FeedHeader\Incrementality
+ */
+ public function getIncrementality(){
+ return $this->_get(2);
+ }
+
+ /**
+ * Set <incrementality> value
+ *
+ * @param int - \transit_realtime\FeedHeader\Incrementality $value
+ * @return \transit_realtime\FeedHeader
+ */
+ public function setIncrementality( $value){
+ return $this->_set(2, $value);
+ }
+
+ /**
+ * Check if <timestamp> has a value
+ *
+ * @return boolean
+ */
+ public function hasTimestamp(){
+ return $this->_has(3);
+ }
+
+ /**
+ * Clear <timestamp> value
+ *
+ * @return \transit_realtime\FeedHeader
+ */
+ public function clearTimestamp(){
+ return $this->_clear(3);
+ }
+
+ /**
+ * Get <timestamp> value
+ *
+ * @return int
+ */
+ public function getTimestamp(){
+ return $this->_get(3);
+ }
+
+ /**
+ * Set <timestamp> value
+ *
+ * @param int $value
+ * @return \transit_realtime\FeedHeader
+ */
+ public function setTimestamp( $value){
+ return $this->_set(3, $value);
+ }
+
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.FeedHeader)
+ }
+}
+
+namespace transit_realtime {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime)
+
+ class FeedEntity extends \DrSlump\Protobuf\Message {
+
+ /** @var \Closure[] */
+ protected static $__extensions = array();
+
+ public static function descriptor()
+ {
+ $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.FeedEntity');
+
+ // required id = 1
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 1;
+ $f->name = "id";
+ $f->type = 9;
+ $f->rule = 2;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.FeedEntity:id)
+ $descriptor->addField($f);
+
+ // optional is_deleted = 2
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 2;
+ $f->name = "is_deleted";
+ $f->type = 8;
+ $f->rule = 1;
+ $f->default = false;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.FeedEntity:is_deleted)
+ $descriptor->addField($f);
+
+ // optional .transit_realtime.TripUpdate trip_update = 3
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 3;
+ $f->name = "trip_update";
+ $f->type = 11;
+ $f->rule = 1;
+ $f->reference = '\transit_realtime\TripUpdate';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.FeedEntity:trip_update)
+ $descriptor->addField($f);
+
+ // optional .transit_realtime.VehiclePosition vehicle = 4
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 4;
+ $f->name = "vehicle";
+ $f->type = 11;
+ $f->rule = 1;
+ $f->reference = '\transit_realtime\VehiclePosition';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.FeedEntity:vehicle)
+ $descriptor->addField($f);
+
+ // optional .transit_realtime.Alert alert = 5
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 5;
+ $f->name = "alert";
+ $f->type = 11;
+ $f->rule = 1;
+ $f->reference = '\transit_realtime\Alert';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.FeedEntity:alert)
+ $descriptor->addField($f);
+
+ foreach (self::$__extensions as $cb) {
+ $descriptor->addField($cb(), true);
+ }
+
+ // @@protoc_insertion_point(scope_descriptor)
+ // @@protoc_insertion_point(descriptor_transit_realtime.FeedEntity)
+
+ return $descriptor;
+ }
+
+ /** @var string */
+ public $id = null;
+
+ /** @var boolean */
+ public $is_deleted = true;
+
+ /** @var \transit_realtime\TripUpdate */
+ public $trip_update = null;
+
+ /** @var \transit_realtime\VehiclePosition */
+ public $vehicle = null;
+
+ /** @var \transit_realtime\Alert */
+ public $alert = null;
+
+
+ /**
+ * Check if <id> has a value
+ *
+ * @return boolean
+ */
+ public function hasId(){
+ return $this->_has(1);
+ }
+
+ /**
+ * Clear <id> value
+ *
+ * @return \transit_realtime\FeedEntity
+ */
+ public function clearId(){
+ return $this->_clear(1);
+ }
+
+ /**
+ * Get <id> value
+ *
+ * @return string
+ */
+ public function getId(){
+ return $this->_get(1);
+ }
+
+ /**
+ * Set <id> value
+ *
+ * @param string $value
+ * @return \transit_realtime\FeedEntity
+ */
+ public function setId( $value){
+ return $this->_set(1, $value);
+ }
+
+ /**
+ * Check if <is_deleted> has a value
+ *
+ * @return boolean
+ */
+ public function hasIsDeleted(){
+ return $this->_has(2);
+ }
+
+ /**
+ * Clear <is_deleted> value
+ *
+ * @return \transit_realtime\FeedEntity
+ */
+ public function clearIsDeleted(){
+ return $this->_clear(2);
+ }
+
+ /**
+ * Get <is_deleted> value
+ *
+ * @return boolean
+ */
+ public function getIsDeleted(){
+ return $this->_get(2);
+ }
+
+ /**
+ * Set <is_deleted> value
+ *
+ * @param boolean $value
+ * @return \transit_realtime\FeedEntity
+ */
+ public function setIsDeleted( $value){
+ return $this->_set(2, $value);
+ }
+
+ /**
+ * Check if <trip_update> has a value
+ *
+ * @return boolean
+ */
+ public function hasTripUpdate(){
+ return $this->_has(3);
+ }
+
+ /**
+ * Clear <trip_update> value
+ *
+ * @return \transit_realtime\FeedEntity
+ */
+ public function clearTripUpdate(){
+ return $this->_clear(3);
+ }
+
+ /**
+ * Get <trip_update> value
+ *
+ * @return \transit_realtime\TripUpdate
+ */
+ public function getTripUpdate(){
+ return $this->_get(3);
+ }
+
+ /**
+ * Set <trip_update> value
+ *
+ * @param \transit_realtime\TripUpdate $value
+ * @return \transit_realtime\FeedEntity
+ */
+ public function setTripUpdate(\transit_realtime\TripUpdate $value){
+ return $this->_set(3, $value);
+ }
+
+ /**
+ * Check if <vehicle> has a value
+ *
+ * @return boolean
+ */
+ public function hasVehicle(){
+ return $this->_has(4);
+ }
+
+ /**
+ * Clear <vehicle> value
+ *
+ * @return \transit_realtime\FeedEntity
+ */
+ public function clearVehicle(){
+ return $this->_clear(4);
+ }
+
+ /**
+ * Get <vehicle> value
+ *
+ * @return \transit_realtime\VehiclePosition
+ */
+ public function getVehicle(){
+ return $this->_get(4);
+ }
+
+ /**
+ * Set <vehicle> value
+ *
+ * @param \transit_realtime\VehiclePosition $value
+ * @return \transit_realtime\FeedEntity
+ */
+ public function setVehicle(\transit_realtime\VehiclePosition $value){
+ return $this->_set(4, $value);
+ }
+
+ /**
+ * Check if <alert> has a value
+ *
+ * @return boolean
+ */
+ public function hasAlert(){
+ return $this->_has(5);
+ }
+
+ /**
+ * Clear <alert> value
+ *
+ * @return \transit_realtime\FeedEntity
+ */
+ public function clearAlert(){
+ return $this->_clear(5);
+ }
+
+ /**
+ * Get <alert> value
+ *
+ * @return \transit_realtime\Alert
+ */
+ public function getAlert(){
+ return $this->_get(5);
+ }
+
+ /**
+ * Set <alert> value
+ *
+ * @param \transit_realtime\Alert $value
+ * @return \transit_realtime\FeedEntity
+ */
+ public function setAlert(\transit_realtime\Alert $value){
+ return $this->_set(5, $value);
+ }
+
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.FeedEntity)
+ }
+}
+
+namespace transit_realtime\TripUpdate {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime.TripUpdate)
+
+ class StopTimeEvent extends \DrSlump\Protobuf\Message {
+
+ /** @var \Closure[] */
+ protected static $__extensions = array();
+
+ public static function descriptor()
+ {
+ $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.TripUpdate.StopTimeEvent');
+
+ // optional delay = 1
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 1;
+ $f->name = "delay";
+ $f->type = 5;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TripUpdate.StopTimeEvent:delay)
+ $descriptor->addField($f);
+
+ // optional time = 2
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 2;
+ $f->name = "time";
+ $f->type = 3;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TripUpdate.StopTimeEvent:time)
+ $descriptor->addField($f);
+
+ // optional uncertainty = 3
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 3;
+ $f->name = "uncertainty";
+ $f->type = 5;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TripUpdate.StopTimeEvent:uncertainty)
+ $descriptor->addField($f);
+
+ foreach (self::$__extensions as $cb) {
+ $descriptor->addField($cb(), true);
+ }
+
+ // @@protoc_insertion_point(scope_descriptor)
+ // @@protoc_insertion_point(descriptor_transit_realtime.TripUpdate.StopTimeEvent)
+
+ return $descriptor;
+ }
+
+ /** @var int */
+ public $delay = null;
+
+ /** @var int */
+ public $time = null;
+
+ /** @var int */
+ public $uncertainty = null;
+
+
+ /**
+ * Check if <delay> has a value
+ *
+ * @return boolean
+ */
+ public function hasDelay(){
+ return $this->_has(1);
+ }
+
+ /**
+ * Clear <delay> value
+ *
+ * @return \transit_realtime\TripUpdate\StopTimeEvent
+ */
+ public function clearDelay(){
+ return $this->_clear(1);
+ }
+
+ /**
+ * Get <delay> value
+ *
+ * @return int
+ */
+ public function getDelay(){
+ return $this->_get(1);
+ }
+
+ /**
+ * Set <delay> value
+ *
+ * @param int $value
+ * @return \transit_realtime\TripUpdate\StopTimeEvent
+ */
+ public function setDelay( $value){
+ return $this->_set(1, $value);
+ }
+
+ /**
+ * Check if <time> has a value
+ *
+ * @return boolean
+ */
+ public function hasTime(){
+ return $this->_has(2);
+ }
+
+ /**
+ * Clear <time> value
+ *
+ * @return \transit_realtime\TripUpdate\StopTimeEvent
+ */
+ public function clearTime(){
+ return $this->_clear(2);
+ }
+
+ /**
+ * Get <time> value
+ *
+ * @return int
+ */
+ public function getTime(){
+ return $this->_get(2);
+ }
+
+ /**
+ * Set <time> value
+ *
+ * @param int $value
+ * @return \transit_realtime\TripUpdate\StopTimeEvent
+ */
+ public function setTime( $value){
+ return $this->_set(2, $value);
+ }
+
+ /**
+ * Check if <uncertainty> has a value
+ *
+ * @return boolean
+ */
+ public function hasUncertainty(){
+ return $this->_has(3);
+ }
+
+ /**
+ * Clear <uncertainty> value
+ *
+ * @return \transit_realtime\TripUpdate\StopTimeEvent
+ */
+ public function clearUncertainty(){
+ return $this->_clear(3);
+ }
+
+ /**
+ * Get <uncertainty> value
+ *
+ * @return int
+ */
+ public function getUncertainty(){
+ return $this->_get(3);
+ }
+
+ /**
+ * Set <uncertainty> value
+ *
+ * @param int $value
+ * @return \transit_realtime\TripUpdate\StopTimeEvent
+ */
+ public function setUncertainty( $value){
+ return $this->_set(3, $value);
+ }
+
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.TripUpdate.StopTimeEvent)
+ }
+}
+
+namespace transit_realtime\TripUpdate\StopTimeUpdate {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime.TripUpdate.StopTimeUpdate)
+
+ class ScheduleRelationship {
+ const SCHEDULED = 0;
+ const SKIPPED = 1;
+ const NO_DATA = 2;
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.TripUpdate.StopTimeUpdate.ScheduleRelationship)
+ }
+}
+namespace transit_realtime\TripUpdate {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime.TripUpdate)
+
+ class StopTimeUpdate extends \DrSlump\Protobuf\Message {
+
+ /** @var \Closure[] */
+ protected static $__extensions = array();
+
+ public static function descriptor()
+ {
+ $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.TripUpdate.StopTimeUpdate');
+
+ // optional stop_sequence = 1
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 1;
+ $f->name = "stop_sequence";
+ $f->type = 13;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TripUpdate.StopTimeUpdate:stop_sequence)
+ $descriptor->addField($f);
+
+ // optional stop_id = 4
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 4;
+ $f->name = "stop_id";
+ $f->type = 9;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TripUpdate.StopTimeUpdate:stop_id)
+ $descriptor->addField($f);
+
+ // optional .transit_realtime.TripUpdate.StopTimeEvent arrival = 2
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 2;
+ $f->name = "arrival";
+ $f->type = 11;
+ $f->rule = 1;
+ $f->reference = '\transit_realtime\TripUpdate\StopTimeEvent';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TripUpdate.StopTimeUpdate:arrival)
+ $descriptor->addField($f);
+
+ // optional .transit_realtime.TripUpdate.StopTimeEvent departure = 3
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 3;
+ $f->name = "departure";
+ $f->type = 11;
+ $f->rule = 1;
+ $f->reference = '\transit_realtime\TripUpdate\StopTimeEvent';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TripUpdate.StopTimeUpdate:departure)
+ $descriptor->addField($f);
+
+ // optional .transit_realtime.TripUpdate.StopTimeUpdate.ScheduleRelationship schedule_relationship = 5
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 5;
+ $f->name = "schedule_relationship";
+ $f->type = 14;
+ $f->rule = 1;
+ $f->reference = '\transit_realtime\TripUpdate\StopTimeUpdate\ScheduleRelationship';
+ $f->default = \transit_realtime\TripUpdate\StopTimeUpdate\ScheduleRelationship::SCHEDULED;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TripUpdate.StopTimeUpdate:schedule_relationship)
+ $descriptor->addField($f);
+
+ foreach (self::$__extensions as $cb) {
+ $descriptor->addField($cb(), true);
+ }
+
+ // @@protoc_insertion_point(scope_descriptor)
+ // @@protoc_insertion_point(descriptor_transit_realtime.TripUpdate.StopTimeUpdate)
+
+ return $descriptor;
+ }
+
+ /** @var int */
+ public $stop_sequence = null;
+
+ /** @var string */
+ public $stop_id = null;
+
+ /** @var \transit_realtime\TripUpdate\StopTimeEvent */
+ public $arrival = null;
+
+ /** @var \transit_realtime\TripUpdate\StopTimeEvent */
+ public $departure = null;
+
+ /** @var int - \transit_realtime\TripUpdate\StopTimeUpdate\ScheduleRelationship */
+ public $schedule_relationship = \transit_realtime\TripUpdate\StopTimeUpdate\ScheduleRelationship::SCHEDULED;
+
+
+ /**
+ * Check if <stop_sequence> has a value
+ *
+ * @return boolean
+ */
+ public function hasStopSequence(){
+ return $this->_has(1);
+ }
+
+ /**
+ * Clear <stop_sequence> value
+ *
+ * @return \transit_realtime\TripUpdate\StopTimeUpdate
+ */
+ public function clearStopSequence(){
+ return $this->_clear(1);
+ }
+
+ /**
+ * Get <stop_sequence> value
+ *
+ * @return int
+ */
+ public function getStopSequence(){
+ return $this->_get(1);
+ }
+
+ /**
+ * Set <stop_sequence> value
+ *
+ * @param int $value
+ * @return \transit_realtime\TripUpdate\StopTimeUpdate
+ */
+ public function setStopSequence( $value){
+ return $this->_set(1, $value);
+ }
+
+ /**
+ * Check if <stop_id> has a value
+ *
+ * @return boolean
+ */
+ public function hasStopId(){
+ return $this->_has(4);
+ }
+
+ /**
+ * Clear <stop_id> value
+ *
+ * @return \transit_realtime\TripUpdate\StopTimeUpdate
+ */
+ public function clearStopId(){
+ return $this->_clear(4);
+ }
+
+ /**
+ * Get <stop_id> value
+ *
+ * @return string
+ */
+ public function getStopId(){
+ return $this->_get(4);
+ }
+
+ /**
+ * Set <stop_id> value
+ *
+ * @param string $value
+ * @return \transit_realtime\TripUpdate\StopTimeUpdate
+ */
+ public function setStopId( $value){
+ return $this->_set(4, $value);
+ }
+
+ /**
+ * Check if <arrival> has a value
+ *
+ * @return boolean
+ */
+ public function hasArrival(){
+ return $this->_has(2);
+ }
+
+ /**
+ * Clear <arrival> value
+ *
+ * @return \transit_realtime\TripUpdate\StopTimeUpdate
+ */
+ public function clearArrival(){
+ return $this->_clear(2);
+ }
+
+ /**
+ * Get <arrival> value
+ *
+ * @return \transit_realtime\TripUpdate\StopTimeEvent
+ */
+ public function getArrival(){
+ return $this->_get(2);
+ }
+
+ /**
+ * Set <arrival> value
+ *
+ * @param \transit_realtime\TripUpdate\StopTimeEvent $value
+ * @return \transit_realtime\TripUpdate\StopTimeUpdate
+ */
+ public function setArrival(\transit_realtime\TripUpdate\StopTimeEvent $value){
+ return $this->_set(2, $value);
+ }
+
+ /**
+ * Check if <departure> has a value
+ *
+ * @return boolean
+ */
+ public function hasDeparture(){
+ return $this->_has(3);
+ }
+
+ /**
+ * Clear <departure> value
+ *
+ * @return \transit_realtime\TripUpdate\StopTimeUpdate
+ */
+ public function clearDeparture(){
+ return $this->_clear(3);
+ }
+
+ /**
+ * Get <departure> value
+ *
+ * @return \transit_realtime\TripUpdate\StopTimeEvent
+ */
+ public function getDeparture(){
+ return $this->_get(3);
+ }
+
+ /**
+ * Set <departure> value
+ *
+ * @param \transit_realtime\TripUpdate\StopTimeEvent $value
+ * @return \transit_realtime\TripUpdate\StopTimeUpdate
+ */
+ public function setDeparture(\transit_realtime\TripUpdate\StopTimeEvent $value){
+ return $this->_set(3, $value);
+ }
+
+ /**
+ * Check if <schedule_relationship> has a value
+ *
+ * @return boolean
+ */
+ public function hasScheduleRelationship(){
+ return $this->_has(5);
+ }
+
+ /**
+ * Clear <schedule_relationship> value
+ *
+ * @return \transit_realtime\TripUpdate\StopTimeUpdate
+ */
+ public function clearScheduleRelationship(){
+ return $this->_clear(5);
+ }
+
+ /**
+ * Get <schedule_relationship> value
+ *
+ * @return int - \transit_realtime\TripUpdate\StopTimeUpdate\ScheduleRelationship
+ */
+ public function getScheduleRelationship(){
+ return $this->_get(5);
+ }
+
+ /**
+ * Set <schedule_relationship> value
+ *
+ * @param int - \transit_realtime\TripUpdate\StopTimeUpdate\ScheduleRelationship $value
+ * @return \transit_realtime\TripUpdate\StopTimeUpdate
+ */
+ public function setScheduleRelationship( $value){
+ return $this->_set(5, $value);
+ }
+
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.TripUpdate.StopTimeUpdate)
+ }
+}
+
+namespace transit_realtime {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime)
+
+ class TripUpdate extends \DrSlump\Protobuf\Message {
+
+ /** @var \Closure[] */
+ protected static $__extensions = array();
+
+ public static function descriptor()
+ {
+ $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.TripUpdate');
+
+ // required .transit_realtime.TripDescriptor trip = 1
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 1;
+ $f->name = "trip";
+ $f->type = 11;
+ $f->rule = 2;
+ $f->reference = '\transit_realtime\TripDescriptor';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TripUpdate:trip)
+ $descriptor->addField($f);
+
+ // optional .transit_realtime.VehicleDescriptor vehicle = 3
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 3;
+ $f->name = "vehicle";
+ $f->type = 11;
+ $f->rule = 1;
+ $f->reference = '\transit_realtime\VehicleDescriptor';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TripUpdate:vehicle)
+ $descriptor->addField($f);
+
+ // repeated .transit_realtime.TripUpdate.StopTimeUpdate stop_time_update = 2
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 2;
+ $f->name = "stop_time_update";
+ $f->type = 11;
+ $f->rule = 3;
+ $f->reference = '\transit_realtime\TripUpdate\StopTimeUpdate';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TripUpdate:stop_time_update)
+ $descriptor->addField($f);
+
+ foreach (self::$__extensions as $cb) {
+ $descriptor->addField($cb(), true);
+ }
+
+ // @@protoc_insertion_point(scope_descriptor)
+ // @@protoc_insertion_point(descriptor_transit_realtime.TripUpdate)
+
+ return $descriptor;
+ }
+
+ /** @var \transit_realtime\TripDescriptor */
+ public $trip = null;
+
+ /** @var \transit_realtime\VehicleDescriptor */
+ public $vehicle = null;
+
+ /** @var \transit_realtime\TripUpdate\StopTimeUpdate[] */
+ public $stop_time_update = array();
+
+
+ /**
+ * Check if <trip> has a value
+ *
+ * @return boolean
+ */
+ public function hasTrip(){
+ return $this->_has(1);
+ }
+
+ /**
+ * Clear <trip> value
+ *
+ * @return \transit_realtime\TripUpdate
+ */
+ public function clearTrip(){
+ return $this->_clear(1);
+ }
+
+ /**
+ * Get <trip> value
+ *
+ * @return \transit_realtime\TripDescriptor
+ */
+ public function getTrip(){
+ return $this->_get(1);
+ }
+
+ /**
+ * Set <trip> value
+ *
+ * @param \transit_realtime\TripDescriptor $value
+ * @return \transit_realtime\TripUpdate
+ */
+ public function setTrip(\transit_realtime\TripDescriptor $value){
+ return $this->_set(1, $value);
+ }
+
+ /**
+ * Check if <vehicle> has a value
+ *
+ * @return boolean
+ */
+ public function hasVehicle(){
+ return $this->_has(3);
+ }
+
+ /**
+ * Clear <vehicle> value
+ *
+ * @return \transit_realtime\TripUpdate
+ */
+ public function clearVehicle(){
+ return $this->_clear(3);
+ }
+
+ /**
+ * Get <vehicle> value
+ *
+ * @return \transit_realtime\VehicleDescriptor
+ */
+ public function getVehicle(){
+ return $this->_get(3);
+ }
+
+ /**
+ * Set <vehicle> value
+ *
+ * @param \transit_realtime\VehicleDescriptor $value
+ * @return \transit_realtime\TripUpdate
+ */
+ public function setVehicle(\transit_realtime\VehicleDescriptor $value){
+ return $this->_set(3, $value);
+ }
+
+ /**
+ * Check if <stop_time_update> has a value
+ *
+ * @return boolean
+ */
+ public function hasStopTimeUpdate(){
+ return $this->_has(2);
+ }
+
+ /**
+ * Clear <stop_time_update> value
+ *
+ * @return \transit_realtime\TripUpdate
+ */
+ public function clearStopTimeUpdate(){
+ return $this->_clear(2);
+ }
+
+ /**
+ * Get <stop_time_update> value
+ *
+ * @param int $idx
+ * @return \transit_realtime\TripUpdate\StopTimeUpdate
+ */
+ public function getStopTimeUpdate($idx = NULL){
+ return $this->_get(2, $idx);
+ }
+
+ /**
+ * Set <stop_time_update> value
+ *
+ * @param \transit_realtime\TripUpdate\StopTimeUpdate $value
+ * @return \transit_realtime\TripUpdate
+ */
+ public function setStopTimeUpdate(\transit_realtime\TripUpdate\StopTimeUpdate $value, $idx = NULL){
+ return $this->_set(2, $value, $idx);
+ }
+
+ /**
+ * Get all elements of <stop_time_update>
+ *
+ * @return \transit_realtime\TripUpdate\StopTimeUpdate[]
+ */
+ public function getStopTimeUpdateList(){
+ return $this->_get(2);
+ }
+
+ /**
+ * Add a new element to <stop_time_update>
+ *
+ * @param \transit_realtime\TripUpdate\StopTimeUpdate $value
+ * @return \transit_realtime\TripUpdate
+ */
+ public function addStopTimeUpdate(\transit_realtime\TripUpdate\StopTimeUpdate $value){
+ return $this->_add(2, $value);
+ }
+
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.TripUpdate)
+ }
+}
+
+namespace transit_realtime\VehiclePosition {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime.VehiclePosition)
+
+ class VehicleStopStatus {
+ const INCOMING_AT = 0;
+ const STOPPED_AT = 1;
+ const IN_TRANSIT_TO = 2;
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.VehiclePosition.VehicleStopStatus)
+ }
+}
+namespace transit_realtime\VehiclePosition {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime.VehiclePosition)
+
+ class CongestionLevel {
+ const UNKNOWN_CONGESTION_LEVEL = 0;
+ const RUNNING_SMOOTHLY = 1;
+ const STOP_AND_GO = 2;
+ const CONGESTION = 3;
+ const SEVERE_CONGESTION = 4;
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.VehiclePosition.CongestionLevel)
+ }
+}
+namespace transit_realtime {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime)
+
+ class VehiclePosition extends \DrSlump\Protobuf\Message {
+
+ /** @var \Closure[] */
+ protected static $__extensions = array();
+
+ public static function descriptor()
+ {
+ $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.VehiclePosition');
+
+ // optional .transit_realtime.TripDescriptor trip = 1
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 1;
+ $f->name = "trip";
+ $f->type = 11;
+ $f->rule = 1;
+ $f->reference = '\transit_realtime\TripDescriptor';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.VehiclePosition:trip)
+ $descriptor->addField($f);
+
+ // optional .transit_realtime.VehicleDescriptor vehicle = 8
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 8;
+ $f->name = "vehicle";
+ $f->type = 11;
+ $f->rule = 1;
+ $f->reference = '\transit_realtime\VehicleDescriptor';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.VehiclePosition:vehicle)
+ $descriptor->addField($f);
+
+ // optional .transit_realtime.Position position = 2
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 2;
+ $f->name = "position";
+ $f->type = 11;
+ $f->rule = 1;
+ $f->reference = '\transit_realtime\Position';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.VehiclePosition:position)
+ $descriptor->addField($f);
+
+ // optional current_stop_sequence = 3
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 3;
+ $f->name = "current_stop_sequence";
+ $f->type = 13;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.VehiclePosition:current_stop_sequence)
+ $descriptor->addField($f);
+
+ // optional stop_id = 7
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 7;
+ $f->name = "stop_id";
+ $f->type = 9;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.VehiclePosition:stop_id)
+ $descriptor->addField($f);
+
+ // optional .transit_realtime.VehiclePosition.VehicleStopStatus current_status = 4
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 4;
+ $f->name = "current_status";
+ $f->type = 14;
+ $f->rule = 1;
+ $f->reference = '\transit_realtime\VehiclePosition\VehicleStopStatus';
+ $f->default = \transit_realtime\VehiclePosition\VehicleStopStatus::IN_TRANSIT_TO;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.VehiclePosition:current_status)
+ $descriptor->addField($f);
+
+ // optional timestamp = 5
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 5;
+ $f->name = "timestamp";
+ $f->type = 4;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.VehiclePosition:timestamp)
+ $descriptor->addField($f);
+
+ // optional .transit_realtime.VehiclePosition.CongestionLevel congestion_level = 6
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 6;
+ $f->name = "congestion_level";
+ $f->type = 14;
+ $f->rule = 1;
+ $f->reference = '\transit_realtime\VehiclePosition\CongestionLevel';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.VehiclePosition:congestion_level)
+ $descriptor->addField($f);
+
+ foreach (self::$__extensions as $cb) {
+ $descriptor->addField($cb(), true);
+ }
+
+ // @@protoc_insertion_point(scope_descriptor)
+ // @@protoc_insertion_point(descriptor_transit_realtime.VehiclePosition)
+
+ return $descriptor;
+ }
+
+ /** @var \transit_realtime\TripDescriptor */
+ public $trip = null;
+
+ /** @var \transit_realtime\VehicleDescriptor */
+ public $vehicle = null;
+
+ /** @var \transit_realtime\Position */
+ public $position = null;
+
+ /** @var int */
+ public $current_stop_sequence = null;
+
+ /** @var string */
+ public $stop_id = null;
+
+ /** @var int - \transit_realtime\VehiclePosition\VehicleStopStatus */
+ public $current_status = \transit_realtime\VehiclePosition\VehicleStopStatus::IN_TRANSIT_TO;
+
+ /** @var int */
+ public $timestamp = null;
+
+ /** @var int - \transit_realtime\VehiclePosition\CongestionLevel */
+ public $congestion_level = null;
+
+
+ /**
+ * Check if <trip> has a value
+ *
+ * @return boolean
+ */
+ public function hasTrip(){
+ return $this->_has(1);
+ }
+
+ /**
+ * Clear <trip> value
+ *
+ * @return \transit_realtime\VehiclePosition
+ */
+ public function clearTrip(){
+ return $this->_clear(1);
+ }
+
+ /**
+ * Get <trip> value
+ *
+ * @return \transit_realtime\TripDescriptor
+ */
+ public function getTrip(){
+ return $this->_get(1);
+ }
+
+ /**
+ * Set <trip> value
+ *
+ * @param \transit_realtime\TripDescriptor $value
+ * @return \transit_realtime\VehiclePosition
+ */
+ public function setTrip(\transit_realtime\TripDescriptor $value){
+ return $this->_set(1, $value);
+ }
+
+ /**
+ * Check if <vehicle> has a value
+ *
+ * @return boolean
+ */
+ public function hasVehicle(){
+ return $this->_has(8);
+ }
+
+ /**
+ * Clear <vehicle> value
+ *
+ * @return \transit_realtime\VehiclePosition
+ */
+ public function clearVehicle(){
+ return $this->_clear(8);
+ }
+
+ /**
+ * Get <vehicle> value
+ *
+ * @return \transit_realtime\VehicleDescriptor
+ */
+ public function getVehicle(){
+ return $this->_get(8);
+ }
+
+ /**
+ * Set <vehicle> value
+ *
+ * @param \transit_realtime\VehicleDescriptor $value
+ * @return \transit_realtime\VehiclePosition
+ */
+ public function setVehicle(\transit_realtime\VehicleDescriptor $value){
+ return $this->_set(8, $value);
+ }
+
+ /**
+ * Check if <position> has a value
+ *
+ * @return boolean
+ */
+ public function hasPosition(){
+ return $this->_has(2);
+ }
+
+ /**
+ * Clear <position> value
+ *
+ * @return \transit_realtime\VehiclePosition
+ */
+ public function clearPosition(){
+ return $this->_clear(2);
+ }
+
+ /**
+ * Get <position> value
+ *
+ * @return \transit_realtime\Position
+ */
+ public function getPosition(){
+ return $this->_get(2);
+ }
+
+ /**
+ * Set <position> value
+ *
+ * @param \transit_realtime\Position $value
+ * @return \transit_realtime\VehiclePosition
+ */
+ public function setPosition(\transit_realtime\Position $value){
+ return $this->_set(2, $value);
+ }
+
+ /**
+ * Check if <current_stop_sequence> has a value
+ *
+ * @return boolean
+ */
+ public function hasCurrentStopSequence(){
+ return $this->_has(3);
+ }
+
+ /**
+ * Clear <current_stop_sequence> value
+ *
+ * @return \transit_realtime\VehiclePosition
+ */
+ public function clearCurrentStopSequence(){
+ return $this->_clear(3);
+ }
+
+ /**
+ * Get <current_stop_sequence> value
+ *
+ * @return int
+ */
+ public function getCurrentStopSequence(){
+ return $this->_get(3);
+ }
+
+ /**
+ * Set <current_stop_sequence> value
+ *
+ * @param int $value
+ * @return \transit_realtime\VehiclePosition
+ */
+ public function setCurrentStopSequence( $value){
+ return $this->_set(3, $value);
+ }
+
+ /**
+ * Check if <stop_id> has a value
+ *
+ * @return boolean
+ */
+ public function hasStopId(){
+ return $this->_has(7);
+ }
+
+ /**
+ * Clear <stop_id> value
+ *
+ * @return \transit_realtime\VehiclePosition
+ */
+ public function clearStopId(){
+ return $this->_clear(7);
+ }
+
+ /**
+ * Get <stop_id> value
+ *
+ * @return string
+ */
+ public function getStopId(){
+ return $this->_get(7);
+ }
+
+ /**
+ * Set <stop_id> value
+ *
+ * @param string $value
+ * @return \transit_realtime\VehiclePosition
+ */
+ public function setStopId( $value){
+ return $this->_set(7, $value);
+ }
+
+ /**
+ * Check if <current_status> has a value
+ *
+ * @return boolean
+ */
+ public function hasCurrentStatus(){
+ return $this->_has(4);
+ }
+
+ /**
+ * Clear <current_status> value
+ *
+ * @return \transit_realtime\VehiclePosition
+ */
+ public function clearCurrentStatus(){
+ return $this->_clear(4);
+ }
+
+ /**
+ * Get <current_status> value
+ *
+ * @return int - \transit_realtime\VehiclePosition\VehicleStopStatus
+ */
+ public function getCurrentStatus(){
+ return $this->_get(4);
+ }
+
+ /**
+ * Set <current_status> value
+ *
+ * @param int - \transit_realtime\VehiclePosition\VehicleStopStatus $value
+ * @return \transit_realtime\VehiclePosition
+ */
+ public function setCurrentStatus( $value){
+ return $this->_set(4, $value);
+ }
+
+ /**
+ * Check if <timestamp> has a value
+ *
+ * @return boolean
+ */
+ public function hasTimestamp(){
+ return $this->_has(5);
+ }
+
+ /**
+ * Clear <timestamp> value
+ *
+ * @return \transit_realtime\VehiclePosition
+ */
+ public function clearTimestamp(){
+ return $this->_clear(5);
+ }
+
+ /**
+ * Get <timestamp> value
+ *
+ * @return int
+ */
+ public function getTimestamp(){
+ return $this->_get(5);
+ }
+
+ /**
+ * Set <timestamp> value
+ *
+ * @param int $value
+ * @return \transit_realtime\VehiclePosition
+ */
+ public function setTimestamp( $value){
+ return $this->_set(5, $value);
+ }
+
+ /**
+ * Check if <congestion_level> has a value
+ *
+ * @return boolean
+ */
+ public function hasCongestionLevel(){
+ return $this->_has(6);
+ }
+
+ /**
+ * Clear <congestion_level> value
+ *
+ * @return \transit_realtime\VehiclePosition
+ */
+ public function clearCongestionLevel(){
+ return $this->_clear(6);
+ }
+
+ /**
+ * Get <congestion_level> value
+ *
+ * @return int - \transit_realtime\VehiclePosition\CongestionLevel
+ */
+ public function getCongestionLevel(){
+ return $this->_get(6);
+ }
+
+ /**
+ * Set <congestion_level> value
+ *
+ * @param int - \transit_realtime\VehiclePosition\CongestionLevel $value
+ * @return \transit_realtime\VehiclePosition
+ */
+ public function setCongestionLevel( $value){
+ return $this->_set(6, $value);
+ }
+
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.VehiclePosition)
+ }
+}
+
+namespace transit_realtime\Alert {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime.Alert)
+
+ class Cause {
+ const UNKNOWN_CAUSE = 1;
+ const OTHER_CAUSE = 2;
+ const TECHNICAL_PROBLEM = 3;
+ const STRIKE = 4;
+ const DEMONSTRATION = 5;
+ const ACCIDENT = 6;
+ const HOLIDAY = 7;
+ const WEATHER = 8;
+ const MAINTENANCE = 9;
+ const CONSTRUCTION = 10;
+ const POLICE_ACTIVITY = 11;
+ const MEDICAL_EMERGENCY = 12;
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.Alert.Cause)
+ }
+}
+namespace transit_realtime\Alert {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime.Alert)
+
+ class Effect {
+ const NO_SERVICE = 1;
+ const REDUCED_SERVICE = 2;
+ const SIGNIFICANT_DELAYS = 3;
+ const DETOUR = 4;
+ const ADDITIONAL_SERVICE = 5;
+ const MODIFIED_SERVICE = 6;
+ const OTHER_EFFECT = 7;
+ const UNKNOWN_EFFECT = 8;
+ const STOP_MOVED = 9;
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.Alert.Effect)
+ }
+}
+namespace transit_realtime {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime)
+
+ class Alert extends \DrSlump\Protobuf\Message {
+
+ /** @var \Closure[] */
+ protected static $__extensions = array();
+
+ public static function descriptor()
+ {
+ $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.Alert');
+
+ // repeated .transit_realtime.TimeRange active_period = 1
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 1;
+ $f->name = "active_period";
+ $f->type = 11;
+ $f->rule = 3;
+ $f->reference = '\transit_realtime\TimeRange';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.Alert:active_period)
+ $descriptor->addField($f);
+
+ // repeated .transit_realtime.EntitySelector informed_entity = 5
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 5;
+ $f->name = "informed_entity";
+ $f->type = 11;
+ $f->rule = 3;
+ $f->reference = '\transit_realtime\EntitySelector';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.Alert:informed_entity)
+ $descriptor->addField($f);
+
+ // optional .transit_realtime.Alert.Cause cause = 6
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 6;
+ $f->name = "cause";
+ $f->type = 14;
+ $f->rule = 1;
+ $f->reference = '\transit_realtime\Alert\Cause';
+ $f->default = \transit_realtime\Alert\Cause::UNKNOWN_CAUSE;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.Alert:cause)
+ $descriptor->addField($f);
+
+ // optional .transit_realtime.Alert.Effect effect = 7
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 7;
+ $f->name = "effect";
+ $f->type = 14;
+ $f->rule = 1;
+ $f->reference = '\transit_realtime\Alert\Effect';
+ $f->default = \transit_realtime\Alert\Effect::UNKNOWN_EFFECT;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.Alert:effect)
+ $descriptor->addField($f);
+
+ // optional .transit_realtime.TranslatedString url = 8
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 8;
+ $f->name = "url";
+ $f->type = 11;
+ $f->rule = 1;
+ $f->reference = '\transit_realtime\TranslatedString';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.Alert:url)
+ $descriptor->addField($f);
+
+ // optional .transit_realtime.TranslatedString header_text = 10
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 10;
+ $f->name = "header_text";
+ $f->type = 11;
+ $f->rule = 1;
+ $f->reference = '\transit_realtime\TranslatedString';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.Alert:header_text)
+ $descriptor->addField($f);
+
+ // optional .transit_realtime.TranslatedString description_text = 11
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 11;
+ $f->name = "description_text";
+ $f->type = 11;
+ $f->rule = 1;
+ $f->reference = '\transit_realtime\TranslatedString';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.Alert:description_text)
+ $descriptor->addField($f);
+
+ foreach (self::$__extensions as $cb) {
+ $descriptor->addField($cb(), true);
+ }
+
+ // @@protoc_insertion_point(scope_descriptor)
+ // @@protoc_insertion_point(descriptor_transit_realtime.Alert)
+
+ return $descriptor;
+ }
+
+ /** @var \transit_realtime\TimeRange[] */
+ public $active_period = array();
+
+ /** @var \transit_realtime\EntitySelector[] */
+ public $informed_entity = array();
+
+ /** @var int - \transit_realtime\Alert\Cause */
+ public $cause = \transit_realtime\Alert\Cause::UNKNOWN_CAUSE;
+
+ /** @var int - \transit_realtime\Alert\Effect */
+ public $effect = \transit_realtime\Alert\Effect::UNKNOWN_EFFECT;
+
+ /** @var \transit_realtime\TranslatedString */
+ public $url = null;
+
+ /** @var \transit_realtime\TranslatedString */
+ public $header_text = null;
+
+ /** @var \transit_realtime\TranslatedString */
+ public $description_text = null;
+
+
+ /**
+ * Check if <active_period> has a value
+ *
+ * @return boolean
+ */
+ public function hasActivePeriod(){
+ return $this->_has(1);
+ }
+
+ /**
+ * Clear <active_period> value
+ *
+ * @return \transit_realtime\Alert
+ */
+ public function clearActivePeriod(){
+ return $this->_clear(1);
+ }
+
+ /**
+ * Get <active_period> value
+ *
+ * @param int $idx
+ * @return \transit_realtime\TimeRange
+ */
+ public function getActivePeriod($idx = NULL){
+ return $this->_get(1, $idx);
+ }
+
+ /**
+ * Set <active_period> value
+ *
+ * @param \transit_realtime\TimeRange $value
+ * @return \transit_realtime\Alert
+ */
+ public function setActivePeriod(\transit_realtime\TimeRange $value, $idx = NULL){
+ return $this->_set(1, $value, $idx);
+ }
+
+ /**
+ * Get all elements of <active_period>
+ *
+ * @return \transit_realtime\TimeRange[]
+ */
+ public function getActivePeriodList(){
+ return $this->_get(1);
+ }
+
+ /**
+ * Add a new element to <active_period>
+ *
+ * @param \transit_realtime\TimeRange $value
+ * @return \transit_realtime\Alert
+ */
+ public function addActivePeriod(\transit_realtime\TimeRange $value){
+ return $this->_add(1, $value);
+ }
+
+ /**
+ * Check if <informed_entity> has a value
+ *
+ * @return boolean
+ */
+ public function hasInformedEntity(){
+ return $this->_has(5);
+ }
+
+ /**
+ * Clear <informed_entity> value
+ *
+ * @return \transit_realtime\Alert
+ */
+ public function clearInformedEntity(){
+ return $this->_clear(5);
+ }
+
+ /**
+ * Get <informed_entity> value
+ *
+ * @param int $idx
+ * @return \transit_realtime\EntitySelector
+ */
+ public function getInformedEntity($idx = NULL){
+ return $this->_get(5, $idx);
+ }
+
+ /**
+ * Set <informed_entity> value
+ *
+ * @param \transit_realtime\EntitySelector $value
+ * @return \transit_realtime\Alert
+ */
+ public function setInformedEntity(\transit_realtime\EntitySelector $value, $idx = NULL){
+ return $this->_set(5, $value, $idx);
+ }
+
+ /**
+ * Get all elements of <informed_entity>
+ *
+ * @return \transit_realtime\EntitySelector[]
+ */
+ public function getInformedEntityList(){
+ return $this->_get(5);
+ }
+
+ /**
+ * Add a new element to <informed_entity>
+ *
+ * @param \transit_realtime\EntitySelector $value
+ * @return \transit_realtime\Alert
+ */
+ public function addInformedEntity(\transit_realtime\EntitySelector $value){
+ return $this->_add(5, $value);
+ }
+
+ /**
+ * Check if <cause> has a value
+ *
+ * @return boolean
+ */
+ public function hasCause(){
+ return $this->_has(6);
+ }
+
+ /**
+ * Clear <cause> value
+ *
+ * @return \transit_realtime\Alert
+ */
+ public function clearCause(){
+ return $this->_clear(6);
+ }
+
+ /**
+ * Get <cause> value
+ *
+ * @return int - \transit_realtime\Alert\Cause
+ */
+ public function getCause(){
+ return $this->_get(6);
+ }
+
+ /**
+ * Set <cause> value
+ *
+ * @param int - \transit_realtime\Alert\Cause $value
+ * @return \transit_realtime\Alert
+ */
+ public function setCause( $value){
+ return $this->_set(6, $value);
+ }
+
+ /**
+ * Check if <effect> has a value
+ *
+ * @return boolean
+ */
+ public function hasEffect(){
+ return $this->_has(7);
+ }
+
+ /**
+ * Clear <effect> value
+ *
+ * @return \transit_realtime\Alert
+ */
+ public function clearEffect(){
+ return $this->_clear(7);
+ }
+
+ /**
+ * Get <effect> value
+ *
+ * @return int - \transit_realtime\Alert\Effect
+ */
+ public function getEffect(){
+ return $this->_get(7);
+ }
+
+ /**
+ * Set <effect> value
+ *
+ * @param int - \transit_realtime\Alert\Effect $value
+ * @return \transit_realtime\Alert
+ */
+ public function setEffect( $value){
+ return $this->_set(7, $value);
+ }
+
+ /**
+ * Check if <url> has a value
+ *
+ * @return boolean
+ */
+ public function hasUrl(){
+ return $this->_has(8);
+ }
+
+ /**
+ * Clear <url> value
+ *
+ * @return \transit_realtime\Alert
+ */
+ public function clearUrl(){
+ return $this->_clear(8);
+ }
+
+ /**
+ * Get <url> value
+ *
+ * @return \transit_realtime\TranslatedString
+ */
+ public function getUrl(){
+ return $this->_get(8);
+ }
+
+ /**
+ * Set <url> value
+ *
+ * @param \transit_realtime\TranslatedString $value
+ * @return \transit_realtime\Alert
+ */
+ public function setUrl(\transit_realtime\TranslatedString $value){
+ return $this->_set(8, $value);
+ }
+
+ /**
+ * Check if <header_text> has a value
+ *
+ * @return boolean
+ */
+ public function hasHeaderText(){
+ return $this->_has(10);
+ }
+
+ /**
+ * Clear <header_text> value
+ *
+ * @return \transit_realtime\Alert
+ */
+ public function clearHeaderText(){
+ return $this->_clear(10);
+ }
+
+ /**
+ * Get <header_text> value
+ *
+ * @return \transit_realtime\TranslatedString
+ */
+ public function getHeaderText(){
+ return $this->_get(10);
+ }
+
+ /**
+ * Set <header_text> value
+ *
+ * @param \transit_realtime\TranslatedString $value
+ * @return \transit_realtime\Alert
+ */
+ public function setHeaderText(\transit_realtime\TranslatedString $value){
+ return $this->_set(10, $value);
+ }
+
+ /**
+ * Check if <description_text> has a value
+ *
+ * @return boolean
+ */
+ public function hasDescriptionText(){
+ return $this->_has(11);
+ }
+
+ /**
+ * Clear <description_text> value
+ *
+ * @return \transit_realtime\Alert
+ */
+ public function clearDescriptionText(){
+ return $this->_clear(11);
+ }
+
+ /**
+ * Get <description_text> value
+ *
+ * @return \transit_realtime\TranslatedString
+ */
+ public function getDescriptionText(){
+ return $this->_get(11);
+ }
+
+ /**
+ * Set <description_text> value
+ *
+ * @param \transit_realtime\TranslatedString $value
+ * @return \transit_realtime\Alert
+ */
+ public function setDescriptionText(\transit_realtime\TranslatedString $value){
+ return $this->_set(11, $value);
+ }
+
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.Alert)
+ }
+}
+
+namespace transit_realtime {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime)
+
+ class TimeRange extends \DrSlump\Protobuf\Message {
+
+ /** @var \Closure[] */
+ protected static $__extensions = array();
+
+ public static function descriptor()
+ {
+ $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.TimeRange');
+
+ // optional start = 1
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 1;
+ $f->name = "start";
+ $f->type = 4;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TimeRange:start)
+ $descriptor->addField($f);
+
+ // optional end = 2
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 2;
+ $f->name = "end";
+ $f->type = 4;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TimeRange:end)
+ $descriptor->addField($f);
+
+ foreach (self::$__extensions as $cb) {
+ $descriptor->addField($cb(), true);
+ }
+
+ // @@protoc_insertion_point(scope_descriptor)
+ // @@protoc_insertion_point(descriptor_transit_realtime.TimeRange)
+
+ return $descriptor;
+ }
+
+ /** @var int */
+ public $start = null;
+
+ /** @var int */
+ public $end = null;
+
+
+ /**
+ * Check if <start> has a value
+ *
+ * @return boolean
+ */
+ public function hasStart(){
+ return $this->_has(1);
+ }
+
+ /**
+ * Clear <start> value
+ *
+ * @return \transit_realtime\TimeRange
+ */
+ public function clearStart(){
+ return $this->_clear(1);
+ }
+
+ /**
+ * Get <start> value
+ *
+ * @return int
+ */
+ public function getStart(){
+ return $this->_get(1);
+ }
+
+ /**
+ * Set <start> value
+ *
+ * @param int $value
+ * @return \transit_realtime\TimeRange
+ */
+ public function setStart( $value){
+ return $this->_set(1, $value);
+ }
+
+ /**
+ * Check if <end> has a value
+ *
+ * @return boolean
+ */
+ public function hasEnd(){
+ return $this->_has(2);
+ }
+
+ /**
+ * Clear <end> value
+ *
+ * @return \transit_realtime\TimeRange
+ */
+ public function clearEnd(){
+ return $this->_clear(2);
+ }
+
+ /**
+ * Get <end> value
+ *
+ * @return int
+ */
+ public function getEnd(){
+ return $this->_get(2);
+ }
+
+ /**
+ * Set <end> value
+ *
+ * @param int $value
+ * @return \transit_realtime\TimeRange
+ */
+ public function setEnd( $value){
+ return $this->_set(2, $value);
+ }
+
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.TimeRange)
+ }
+}
+
+namespace transit_realtime {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime)
+
+ class Position extends \DrSlump\Protobuf\Message {
+
+ /** @var \Closure[] */
+ protected static $__extensions = array();
+
+ public static function descriptor()
+ {
+ $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.Position');
+
+ // required latitude = 1
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 1;
+ $f->name = "latitude";
+ $f->type = 2;
+ $f->rule = 2;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.Position:latitude)
+ $descriptor->addField($f);
+
+ // required longitude = 2
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 2;
+ $f->name = "longitude";
+ $f->type = 2;
+ $f->rule = 2;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.Position:longitude)
+ $descriptor->addField($f);
+
+ // optional bearing = 3
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 3;
+ $f->name = "bearing";
+ $f->type = 2;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.Position:bearing)
+ $descriptor->addField($f);
+
+ // optional odometer = 4
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 4;
+ $f->name = "odometer";
+ $f->type = 1;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.Position:odometer)
+ $descriptor->addField($f);
+
+ // optional speed = 5
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 5;
+ $f->name = "speed";
+ $f->type = 2;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.Position:speed)
+ $descriptor->addField($f);
+
+ foreach (self::$__extensions as $cb) {
+ $descriptor->addField($cb(), true);
+ }
+
+ // @@protoc_insertion_point(scope_descriptor)
+ // @@protoc_insertion_point(descriptor_transit_realtime.Position)
+
+ return $descriptor;
+ }
+
+ /** @var float */
+ public $latitude = null;
+
+ /** @var float */
+ public $longitude = null;
+
+ /** @var float */
+ public $bearing = null;
+
+ /** @var float */
+ public $odometer = null;
+
+ /** @var float */
+ public $speed = null;
+
+
+ /**
+ * Check if <latitude> has a value
+ *
+ * @return boolean
+ */
+ public function hasLatitude(){
+ return $this->_has(1);
+ }
+
+ /**
+ * Clear <latitude> value
+ *
+ * @return \transit_realtime\Position
+ */
+ public function clearLatitude(){
+ return $this->_clear(1);
+ }
+
+ /**
+ * Get <latitude> value
+ *
+ * @return float
+ */
+ public function getLatitude(){
+ return $this->_get(1);
+ }
+
+ /**
+ * Set <latitude> value
+ *
+ * @param float $value
+ * @return \transit_realtime\Position
+ */
+ public function setLatitude( $value){
+ return $this->_set(1, $value);
+ }
+
+ /**
+ * Check if <longitude> has a value
+ *
+ * @return boolean
+ */
+ public function hasLongitude(){
+ return $this->_has(2);
+ }
+
+ /**
+ * Clear <longitude> value
+ *
+ * @return \transit_realtime\Position
+ */
+ public function clearLongitude(){
+ return $this->_clear(2);
+ }
+
+ /**
+ * Get <longitude> value
+ *
+ * @return float
+ */
+ public function getLongitude(){
+ return $this->_get(2);
+ }
+
+ /**
+ * Set <longitude> value
+ *
+ * @param float $value
+ * @return \transit_realtime\Position
+ */
+ public function setLongitude( $value){
+ return $this->_set(2, $value);
+ }
+
+ /**
+ * Check if <bearing> has a value
+ *
+ * @return boolean
+ */
+ public function hasBearing(){
+ return $this->_has(3);
+ }
+
+ /**
+ * Clear <bearing> value
+ *
+ * @return \transit_realtime\Position
+ */
+ public function clearBearing(){
+ return $this->_clear(3);
+ }
+
+ /**
+ * Get <bearing> value
+ *
+ * @return float
+ */
+ public function getBearing(){
+ return $this->_get(3);
+ }
+
+ /**
+ * Set <bearing> value
+ *
+ * @param float $value
+ * @return \transit_realtime\Position
+ */
+ public function setBearing( $value){
+ return $this->_set(3, $value);
+ }
+
+ /**
+ * Check if <odometer> has a value
+ *
+ * @return boolean
+ */
+ public function hasOdometer(){
+ return $this->_has(4);
+ }
+
+ /**
+ * Clear <odometer> value
+ *
+ * @return \transit_realtime\Position
+ */
+ public function clearOdometer(){
+ return $this->_clear(4);
+ }
+
+ /**
+ * Get <odometer> value
+ *
+ * @return float
+ */
+ public function getOdometer(){
+ return $this->_get(4);
+ }
+
+ /**
+ * Set <odometer> value
+ *
+ * @param float $value
+ * @return \transit_realtime\Position
+ */
+ public function setOdometer( $value){
+ return $this->_set(4, $value);
+ }
+
+ /**
+ * Check if <speed> has a value
+ *
+ * @return boolean
+ */
+ public function hasSpeed(){
+ return $this->_has(5);
+ }
+
+ /**
+ * Clear <speed> value
+ *
+ * @return \transit_realtime\Position
+ */
+ public function clearSpeed(){
+ return $this->_clear(5);
+ }
+
+ /**
+ * Get <speed> value
+ *
+ * @return float
+ */
+ public function getSpeed(){
+ return $this->_get(5);
+ }
+
+ /**
+ * Set <speed> value
+ *
+ * @param float $value
+ * @return \transit_realtime\Position
+ */
+ public function setSpeed( $value){
+ return $this->_set(5, $value);
+ }
+
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.Position)
+ }
+}
+
+namespace transit_realtime\TripDescriptor {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime.TripDescriptor)
+
+ class ScheduleRelationship {
+ const SCHEDULED = 0;
+ const ADDED = 1;
+ const UNSCHEDULED = 2;
+ const CANCELED = 3;
+ const REPLACEMENT = 5;
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.TripDescriptor.ScheduleRelationship)
+ }
+}
+namespace transit_realtime {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime)
+
+ class TripDescriptor extends \DrSlump\Protobuf\Message {
+
+ /** @var \Closure[] */
+ protected static $__extensions = array();
+
+ public static function descriptor()
+ {
+ $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.TripDescriptor');
+
+ // optional trip_id = 1
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 1;
+ $f->name = "trip_id";
+ $f->type = 9;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TripDescriptor:trip_id)
+ $descriptor->addField($f);
+
+ // optional route_id = 5
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 5;
+ $f->name = "route_id";
+ $f->type = 9;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TripDescriptor:route_id)
+ $descriptor->addField($f);
+
+ // optional start_time = 2
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 2;
+ $f->name = "start_time";
+ $f->type = 9;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TripDescriptor:start_time)
+ $descriptor->addField($f);
+
+ // optional start_date = 3
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 3;
+ $f->name = "start_date";
+ $f->type = 9;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TripDescriptor:start_date)
+ $descriptor->addField($f);
+
+ // optional .transit_realtime.TripDescriptor.ScheduleRelationship schedule_relationship = 4
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 4;
+ $f->name = "schedule_relationship";
+ $f->type = 14;
+ $f->rule = 1;
+ $f->reference = '\transit_realtime\TripDescriptor\ScheduleRelationship';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TripDescriptor:schedule_relationship)
+ $descriptor->addField($f);
+
+ foreach (self::$__extensions as $cb) {
+ $descriptor->addField($cb(), true);
+ }
+
+ // @@protoc_insertion_point(scope_descriptor)
+ // @@protoc_insertion_point(descriptor_transit_realtime.TripDescriptor)
+
+ return $descriptor;
+ }
+
+ /** @var string */
+ public $trip_id = null;
+
+ /** @var string */
+ public $route_id = null;
+
+ /** @var string */
+ public $start_time = null;
+
+ /** @var string */
+ public $start_date = null;
+
+ /** @var int - \transit_realtime\TripDescriptor\ScheduleRelationship */
+ public $schedule_relationship = null;
+
+
+ /**
+ * Check if <trip_id> has a value
+ *
+ * @return boolean
+ */
+ public function hasTripId(){
+ return $this->_has(1);
+ }
+
+ /**
+ * Clear <trip_id> value
+ *
+ * @return \transit_realtime\TripDescriptor
+ */
+ public function clearTripId(){
+ return $this->_clear(1);
+ }
+
+ /**
+ * Get <trip_id> value
+ *
+ * @return string
+ */
+ public function getTripId(){
+ return $this->_get(1);
+ }
+
+ /**
+ * Set <trip_id> value
+ *
+ * @param string $value
+ * @return \transit_realtime\TripDescriptor
+ */
+ public function setTripId( $value){
+ return $this->_set(1, $value);
+ }
+
+ /**
+ * Check if <route_id> has a value
+ *
+ * @return boolean
+ */
+ public function hasRouteId(){
+ return $this->_has(5);
+ }
+
+ /**
+ * Clear <route_id> value
+ *
+ * @return \transit_realtime\TripDescriptor
+ */
+ public function clearRouteId(){
+ return $this->_clear(5);
+ }
+
+ /**
+ * Get <route_id> value
+ *
+ * @return string
+ */
+ public function getRouteId(){
+ return $this->_get(5);
+ }
+
+ /**
+ * Set <route_id> value
+ *
+ * @param string $value
+ * @return \transit_realtime\TripDescriptor
+ */
+ public function setRouteId( $value){
+ return $this->_set(5, $value);
+ }
+
+ /**
+ * Check if <start_time> has a value
+ *
+ * @return boolean
+ */
+ public function hasStartTime(){
+ return $this->_has(2);
+ }
+
+ /**
+ * Clear <start_time> value
+ *
+ * @return \transit_realtime\TripDescriptor
+ */
+ public function clearStartTime(){
+ return $this->_clear(2);
+ }
+
+ /**
+ * Get <start_time> value
+ *
+ * @return string
+ */
+ public function getStartTime(){
+ return $this->_get(2);
+ }
+
+ /**
+ * Set <start_time> value
+ *
+ * @param string $value
+ * @return \transit_realtime\TripDescriptor
+ */
+ public function setStartTime( $value){
+ return $this->_set(2, $value);
+ }
+
+ /**
+ * Check if <start_date> has a value
+ *
+ * @return boolean
+ */
+ public function hasStartDate(){
+ return $this->_has(3);
+ }
+
+ /**
+ * Clear <start_date> value
+ *
+ * @return \transit_realtime\TripDescriptor
+ */
+ public function clearStartDate(){
+ return $this->_clear(3);
+ }
+
+ /**
+ * Get <start_date> value
+ *
+ * @return string
+ */
+ public function getStartDate(){
+ return $this->_get(3);
+ }
+
+ /**
+ * Set <start_date> value
+ *
+ * @param string $value
+ * @return \transit_realtime\TripDescriptor
+ */
+ public function setStartDate( $value){
+ return $this->_set(3, $value);
+ }
+
+ /**
+ * Check if <schedule_relationship> has a value
+ *
+ * @return boolean
+ */
+ public function hasScheduleRelationship(){
+ return $this->_has(4);
+ }
+
+ /**
+ * Clear <schedule_relationship> value
+ *
+ * @return \transit_realtime\TripDescriptor
+ */
+ public function clearScheduleRelationship(){
+ return $this->_clear(4);
+ }
+
+ /**
+ * Get <schedule_relationship> value
+ *
+ * @return int - \transit_realtime\TripDescriptor\ScheduleRelationship
+ */
+ public function getScheduleRelationship(){
+ return $this->_get(4);
+ }
+
+ /**
+ * Set <schedule_relationship> value
+ *
+ * @param int - \transit_realtime\TripDescriptor\ScheduleRelationship $value
+ * @return \transit_realtime\TripDescriptor
+ */
+ public function setScheduleRelationship( $value){
+ return $this->_set(4, $value);
+ }
+
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.TripDescriptor)
+ }
+}
+
+namespace transit_realtime {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime)
+
+ class VehicleDescriptor extends \DrSlump\Protobuf\Message {
+
+ /** @var \Closure[] */
+ protected static $__extensions = array();
+
+ public static function descriptor()
+ {
+ $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.VehicleDescriptor');
+
+ // optional id = 1
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 1;
+ $f->name = "id";
+ $f->type = 9;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.VehicleDescriptor:id)
+ $descriptor->addField($f);
+
+ // optional label = 2
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 2;
+ $f->name = "label";
+ $f->type = 9;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.VehicleDescriptor:label)
+ $descriptor->addField($f);
+
+ // optional license_plate = 3
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 3;
+ $f->name = "license_plate";
+ $f->type = 9;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.VehicleDescriptor:license_plate)
+ $descriptor->addField($f);
+
+ foreach (self::$__extensions as $cb) {
+ $descriptor->addField($cb(), true);
+ }
+
+ // @@protoc_insertion_point(scope_descriptor)
+ // @@protoc_insertion_point(descriptor_transit_realtime.VehicleDescriptor)
+
+ return $descriptor;
+ }
+
+ /** @var string */
+ public $id = null;
+
+ /** @var string */
+ public $label = null;
+
+ /** @var string */
+ public $license_plate = null;
+
+
+ /**
+ * Check if <id> has a value
+ *
+ * @return boolean
+ */
+ public function hasId(){
+ return $this->_has(1);
+ }
+
+ /**
+ * Clear <id> value
+ *
+ * @return \transit_realtime\VehicleDescriptor
+ */
+ public function clearId(){
+ return $this->_clear(1);
+ }
+
+ /**
+ * Get <id> value
+ *
+ * @return string
+ */
+ public function getId(){
+ return $this->_get(1);
+ }
+
+ /**
+ * Set <id> value
+ *
+ * @param string $value
+ * @return \transit_realtime\VehicleDescriptor
+ */
+ public function setId( $value){
+ return $this->_set(1, $value);
+ }
+
+ /**
+ * Check if <label> has a value
+ *
+ * @return boolean
+ */
+ public function hasLabel(){
+ return $this->_has(2);
+ }
+
+ /**
+ * Clear <label> value
+ *
+ * @return \transit_realtime\VehicleDescriptor
+ */
+ public function clearLabel(){
+ return $this->_clear(2);
+ }
+
+ /**
+ * Get <label> value
+ *
+ * @return string
+ */
+ public function getLabel(){
+ return $this->_get(2);
+ }
+
+ /**
+ * Set <label> value
+ *
+ * @param string $value
+ * @return \transit_realtime\VehicleDescriptor
+ */
+ public function setLabel( $value){
+ return $this->_set(2, $value);
+ }
+
+ /**
+ * Check if <license_plate> has a value
+ *
+ * @return boolean
+ */
+ public function hasLicensePlate(){
+ return $this->_has(3);
+ }
+
+ /**
+ * Clear <license_plate> value
+ *
+ * @return \transit_realtime\VehicleDescriptor
+ */
+ public function clearLicensePlate(){
+ return $this->_clear(3);
+ }
+
+ /**
+ * Get <license_plate> value
+ *
+ * @return string
+ */
+ public function getLicensePlate(){
+ return $this->_get(3);
+ }
+
+ /**
+ * Set <license_plate> value
+ *
+ * @param string $value
+ * @return \transit_realtime\VehicleDescriptor
+ */
+ public function setLicensePlate( $value){
+ return $this->_set(3, $value);
+ }
+
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.VehicleDescriptor)
+ }
+}
+
+namespace transit_realtime {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime)
+
+ class EntitySelector extends \DrSlump\Protobuf\Message {
+
+ /** @var \Closure[] */
+ protected static $__extensions = array();
+
+ public static function descriptor()
+ {
+ $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.EntitySelector');
+
+ // optional agency_id = 1
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 1;
+ $f->name = "agency_id";
+ $f->type = 9;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.EntitySelector:agency_id)
+ $descriptor->addField($f);
+
+ // optional route_id = 2
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 2;
+ $f->name = "route_id";
+ $f->type = 9;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.EntitySelector:route_id)
+ $descriptor->addField($f);
+
+ // optional route_type = 3
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 3;
+ $f->name = "route_type";
+ $f->type = 5;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.EntitySelector:route_type)
+ $descriptor->addField($f);
+
+ // optional .transit_realtime.TripDescriptor trip = 4
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 4;
+ $f->name = "trip";
+ $f->type = 11;
+ $f->rule = 1;
+ $f->reference = '\transit_realtime\TripDescriptor';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.EntitySelector:trip)
+ $descriptor->addField($f);
+
+ // optional stop_id = 5
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 5;
+ $f->name = "stop_id";
+ $f->type = 9;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.EntitySelector:stop_id)
+ $descriptor->addField($f);
+
+ foreach (self::$__extensions as $cb) {
+ $descriptor->addField($cb(), true);
+ }
+
+ // @@protoc_insertion_point(scope_descriptor)
+ // @@protoc_insertion_point(descriptor_transit_realtime.EntitySelector)
+
+ return $descriptor;
+ }
+
+ /** @var string */
+ public $agency_id = null;
+
+ /** @var string */
+ public $route_id = null;
+
+ /** @var int */
+ public $route_type = null;
+
+ /** @var \transit_realtime\TripDescriptor */
+ public $trip = null;
+
+ /** @var string */
+ public $stop_id = null;
+
+
+ /**
+ * Check if <agency_id> has a value
+ *
+ * @return boolean
+ */
+ public function hasAgencyId(){
+ return $this->_has(1);
+ }
+
+ /**
+ * Clear <agency_id> value
+ *
+ * @return \transit_realtime\EntitySelector
+ */
+ public function clearAgencyId(){
+ return $this->_clear(1);
+ }
+
+ /**
+ * Get <agency_id> value
+ *
+ * @return string
+ */
+ public function getAgencyId(){
+ return $this->_get(1);
+ }
+
+ /**
+ * Set <agency_id> value
+ *
+ * @param string $value
+ * @return \transit_realtime\EntitySelector
+ */
+ public function setAgencyId( $value){
+ return $this->_set(1, $value);
+ }
+
+ /**
+ * Check if <route_id> has a value
+ *
+ * @return boolean
+ */
+ public function hasRouteId(){
+ return $this->_has(2);
+ }
+
+ /**
+ * Clear <route_id> value
+ *
+ * @return \transit_realtime\EntitySelector
+ */
+ public function clearRouteId(){
+ return $this->_clear(2);
+ }
+
+ /**
+ * Get <route_id> value
+ *
+ * @return string
+ */
+ public function getRouteId(){
+ return $this->_get(2);
+ }
+
+ /**
+ * Set <route_id> value
+ *
+ * @param string $value
+ * @return \transit_realtime\EntitySelector
+ */
+ public function setRouteId( $value){
+ return $this->_set(2, $value);
+ }
+
+ /**
+ * Check if <route_type> has a value
+ *
+ * @return boolean
+ */
+ public function hasRouteType(){
+ return $this->_has(3);
+ }
+
+ /**
+ * Clear <route_type> value
+ *
+ * @return \transit_realtime\EntitySelector
+ */
+ public function clearRouteType(){
+ return $this->_clear(3);
+ }
+
+ /**
+ * Get <route_type> value
+ *
+ * @return int
+ */
+ public function getRouteType(){
+ return $this->_get(3);
+ }
+
+ /**
+ * Set <route_type> value
+ *
+ * @param int $value
+ * @return \transit_realtime\EntitySelector
+ */
+ public function setRouteType( $value){
+ return $this->_set(3, $value);
+ }
+
+ /**
+ * Check if <trip> has a value
+ *
+ * @return boolean
+ */
+ public function hasTrip(){
+ return $this->_has(4);
+ }
+
+ /**
+ * Clear <trip> value
+ *
+ * @return \transit_realtime\EntitySelector
+ */
+ public function clearTrip(){
+ return $this->_clear(4);
+ }
+
+ /**
+ * Get <trip> value
+ *
+ * @return \transit_realtime\TripDescriptor
+ */
+ public function getTrip(){
+ return $this->_get(4);
+ }
+
+ /**
+ * Set <trip> value
+ *
+ * @param \transit_realtime\TripDescriptor $value
+ * @return \transit_realtime\EntitySelector
+ */
+ public function setTrip(\transit_realtime\TripDescriptor $value){
+ return $this->_set(4, $value);
+ }
+
+ /**
+ * Check if <stop_id> has a value
+ *
+ * @return boolean
+ */
+ public function hasStopId(){
+ return $this->_has(5);
+ }
+
+ /**
+ * Clear <stop_id> value
+ *
+ * @return \transit_realtime\EntitySelector
+ */
+ public function clearStopId(){
+ return $this->_clear(5);
+ }
+
+ /**
+ * Get <stop_id> value
+ *
+ * @return string
+ */
+ public function getStopId(){
+ return $this->_get(5);
+ }
+
+ /**
+ * Set <stop_id> value
+ *
+ * @param string $value
+ * @return \transit_realtime\EntitySelector
+ */
+ public function setStopId( $value){
+ return $this->_set(5, $value);
+ }
+
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.EntitySelector)
+ }
+}
+
+namespace transit_realtime\TranslatedString {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime.TranslatedString)
+
+ class Translation extends \DrSlump\Protobuf\Message {
+
+ /** @var \Closure[] */
+ protected static $__extensions = array();
+
+ public static function descriptor()
+ {
+ $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.TranslatedString.Translation');
+
+ // required text = 1
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 1;
+ $f->name = "text";
+ $f->type = 9;
+ $f->rule = 2;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TranslatedString.Translation:text)
+ $descriptor->addField($f);
+
+ // optional language = 2
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 2;
+ $f->name = "language";
+ $f->type = 9;
+ $f->rule = 1;
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TranslatedString.Translation:language)
+ $descriptor->addField($f);
+
+ foreach (self::$__extensions as $cb) {
+ $descriptor->addField($cb(), true);
+ }
+
+ // @@protoc_insertion_point(scope_descriptor)
+ // @@protoc_insertion_point(descriptor_transit_realtime.TranslatedString.Translation)
+
+ return $descriptor;
+ }
+
+ /** @var string */
+ public $text = null;
+
+ /** @var string */
+ public $language = null;
+
+
+ /**
+ * Check if <text> has a value
+ *
+ * @return boolean
+ */
+ public function hasText(){
+ return $this->_has(1);
+ }
+
+ /**
+ * Clear <text> value
+ *
+ * @return \transit_realtime\TranslatedString\Translation
+ */
+ public function clearText(){
+ return $this->_clear(1);
+ }
+
+ /**
+ * Get <text> value
+ *
+ * @return string
+ */
+ public function getText(){
+ return $this->_get(1);
+ }
+
+ /**
+ * Set <text> value
+ *
+ * @param string $value
+ * @return \transit_realtime\TranslatedString\Translation
+ */
+ public function setText( $value){
+ return $this->_set(1, $value);
+ }
+
+ /**
+ * Check if <language> has a value
+ *
+ * @return boolean
+ */
+ public function hasLanguage(){
+ return $this->_has(2);
+ }
+
+ /**
+ * Clear <language> value
+ *
+ * @return \transit_realtime\TranslatedString\Translation
+ */
+ public function clearLanguage(){
+ return $this->_clear(2);
+ }
+
+ /**
+ * Get <language> value
+ *
+ * @return string
+ */
+ public function getLanguage(){
+ return $this->_get(2);
+ }
+
+ /**
+ * Set <language> value
+ *
+ * @param string $value
+ * @return \transit_realtime\TranslatedString\Translation
+ */
+ public function setLanguage( $value){
+ return $this->_set(2, $value);
+ }
+
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.TranslatedString.Translation)
+ }
+}
+
+namespace transit_realtime {
+
+ // @@protoc_insertion_point(scope_namespace)
+ // @@protoc_insertion_point(namespace_transit_realtime)
+
+ class TranslatedString extends \DrSlump\Protobuf\Message {
+
+ /** @var \Closure[] */
+ protected static $__extensions = array();
+
+ public static function descriptor()
+ {
+ $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'transit_realtime.TranslatedString');
+
+ // repeated .transit_realtime.TranslatedString.Translation translation = 1
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 1;
+ $f->name = "translation";
+ $f->type = 11;
+ $f->rule = 3;
+ $f->reference = '\transit_realtime\TranslatedString\Translation';
+ // @@protoc_insertion_point(scope_field)
+ // @@protoc_insertion_point(field_transit_realtime.TranslatedString:translation)
+ $descriptor->addField($f);
+
+ foreach (self::$__extensions as $cb) {
+ $descriptor->addField($cb(), true);
+ }
+
+ // @@protoc_insertion_point(scope_descriptor)
+ // @@protoc_insertion_point(descriptor_transit_realtime.TranslatedString)
+
+ return $descriptor;
+ }
+
+ /** @var \transit_realtime\TranslatedString\Translation[] */
+ public $translation = array();
+
+
+ /**
+ * Check if <translation> has a value
+ *
+ * @return boolean
+ */
+ public function hasTranslation(){
+ return $this->_has(1);
+ }
+
+ /**
+ * Clear <translation> value
+ *
+ * @return \transit_realtime\TranslatedString
+ */
+ public function clearTranslation(){
+ return $this->_clear(1);
+ }
+
+ /**
+ * Get <translation> value
+ *
+ * @param int $idx
+ * @return \transit_realtime\TranslatedString\Translation
+ */
+ public function getTranslation($idx = NULL){
+ return $this->_get(1, $idx);
+ }
+
+ /**
+ * Set <translation> value
+ *
+ * @param \transit_realtime\TranslatedString\Translation $value
+ * @return \transit_realtime\TranslatedString
+ */
+ public function setTranslation(\transit_realtime\TranslatedString\Translation $value, $idx = NULL){
+ return $this->_set(1, $value, $idx);
+ }
+
+ /**
+ * Get all elements of <translation>
+ *
+ * @return \transit_realtime\TranslatedString\Translation[]
+ */
+ public function getTranslationList(){
+ return $this->_get(1);
+ }
+
+ /**
+ * Add a new element to <translation>
+ *
+ * @param \transit_realtime\TranslatedString\Translation $value
+ * @return \transit_realtime\TranslatedString
+ */
+ public function addTranslation(\transit_realtime\TranslatedString\Translation $value){
+ return $this->_add(1, $value);
+ }
+
+
+ // @@protoc_insertion_point(scope_class)
+ // @@protoc_insertion_point(class_transit_realtime.TranslatedString)
+ }
+}
+
+
--- /dev/null
+++ b/lib/Protobuf-PHP/gtfs-realtime.proto
@@ -1,1 +1,498 @@
-
+// Copyright 2010 Google Inc
+//
+// The content of this file is licensed under the Creative Commons Attribution
+// 3.0 License.
+//
+// Protocol definition file for GTFS-realtime.
+//
+// GTFS-realtime lets transit agencies provide consumers with realtime
+// information about disruptions to their service (stations closed, lines not
+// operating, important delays etc), location of their vehicles and expected
+// arrival times.
+//
+// This protocol is published on http://code.google.com/transit/realtime/ .
+
+syntax = "proto2";
+
+option cc_api_version = 2;
+option py_api_version = 1;
+
+option java_package = "com.google.transit.realtime";
+package transit_realtime;
+
+// The contents of a feed message.
+// A feed is a continuous stream of feed messages. Each message in the stream is
+// obtained as a response to an appropriate HTTP GET request.
+// A realtime feed is always defined with relation to an existing GTFS feed.
+// All the entity ids are resolved with respect to the GTFS feed.
+//
+// A feed depends on some external configuration:
+// - The corresponding GTFS feed.
+// - Feed application (updates, positions or alerts). A feed should contain only
+// items of one specified application; all the other entities will be ignored.
+// - Polling frequency
+message FeedMessage {
+ // Metadata about this feed and feed message.
+ required FeedHeader header = 1;
+
+ // Contents of the feed.
+ repeated FeedEntity entity = 2;
+}
+
+// Metadata about a feed, included in feed messages.
+message FeedHeader {
+ // Version of the feed specification.
+ // The current version is 1.0.
+ required string gtfs_realtime_version = 1;
+
+ // Determines whether the current fetch is incremental.
+ enum Incrementality {
+ FULL_DATASET = 0;
+ DIFFERENTIAL = 1;
+ }
+ optional Incrementality incrementality = 2 [default = FULL_DATASET];
+
+ // This timestamp identifies the moment when the content of this feed has been
+ // created (in server time). In POSIX time (i.e., number of seconds since
+ // January 1st 1970 00:00:00 UTC).
+ optional uint64 timestamp = 3;
+}
+
+// A definition (or update) of an entity in the transit feed.
+message FeedEntity {
+ // The ids are used only to provide incrementality support. The id should be
+ // unique within a FeedMessage. Consequent FeedMessages may contain
+ // FeedEntities with the same id. In case of a DIFFERENTIAL update the new
+ // FeedEntity with some id will replace the old FeedEntity with the same id
+ // (or delete it - see is_deleted below).
+ // The actual GTFS entities (e.g. stations, routes, trips) referenced by the
+ // feed must be specified by explicit selectors (see EntitySelector below for
+ // more info).
+ required string id = 1;
+
+ // Whether this entity is to be deleted. Relevant only for incremental
+ // fetches.
+ optional bool is_deleted = 2 [default = false];
+
+ // Data about the entity itself. Exactly one of the following fields must be
+ // present (unless the entity is being deleted).
+ optional TripUpdate trip_update = 3;
+ optional VehiclePosition vehicle = 4;
+ optional Alert alert = 5;
+}
+
+//
+// Entities used in the feed.
+//
+
+// Realtime update of the progress of a vehicle along a trip.
+// Depending on the value of ScheduleRelationship, a TripUpdate can specify:
+// - A trip that proceeds along the schedule.
+// - A trip that proceeds along a route but has no fixed schedule.
+// - A trip that have been added or removed with regard to schedule.
+//
+// The updates can be for future, predicted arrival/departure events, or for
+// past events that already occurred.
+// Normally, updates should get more precise and more certain (see
+// uncertainty below) as the events gets closer to current time.
+// Even if that is not possible, the information for past events should be
+// precise and certain. In particular, if an update points to time in the past
+// but its update's uncertainty is not 0, the client should conclude that the
+// update is a (wrong) prediction and that the trip has not completed yet.
+//
+// Note that the update can describe a trip that is already completed.
+// To this end, it is enough to provide an update for the last stop of the trip.
+// If the time of that is in the past, the client will conclude from that that
+// the whole trip is in the past (it is possible, although inconsequential, to
+// also provide updates for preceding stops).
+// This option is most relevant for a trip that has completed ahead of schedule,
+// but according to the schedule, the trip is still proceeding at the current
+// time. Removing the updates for this trip could make the client assume
+// that the trip is still proceeding.
+// Note that the feed provider is allowed, but not required, to purge past
+// updates - this is one case where this would be practically useful.
+message TripUpdate {
+ // The Trip that this message applies to. There can be at most one
+ // TripUpdate entity for each actual trip instance.
+ // If there is none, that means there is no prediction information available.
+ // It does *not* mean that the trip is progressing according to schedule.
+ required TripDescriptor trip = 1;
+
+ // Additional information on the vehicle that is serving this trip.
+ optional VehicleDescriptor vehicle = 3;
+
+ // Timing information for a single predicted event (either arrival or
+ // departure).
+ // Timing consists of delay and/or estimated time, and uncertainty.
+ // - delay should be used when the prediction is given relative to some
+ // existing schedule in GTFS.
+ // - time should be given whether there is a predicted schedule or not. If
+ // both time and delay are specified, time will take precedence
+ // (although normally, time, if given for a scheduled trip, should be
+ // equal to scheduled time in GTFS + delay).
+ //
+ // Uncertainty applies equally to both time and delay.
+ // The uncertainty roughly specifies the expected error in true delay (but
+ // note, we don't yet define its precise statistical meaning). It's possible
+ // for the uncertainty to be 0, for example for trains that are driven under
+ // computer timing control.
+ message StopTimeEvent {
+ // Delay (in seconds) can be positive (meaning that the vehicle is late) or
+ // negative (meaning that the vehicle is ahead of schedule). Delay of 0
+ // means that the vehicle is exactly on time.
+ optional int32 delay = 1;
+
+ // Event as absolute time.
+ // In Unix time (i.e., number of seconds since January 1st 1970 00:00:00
+ // UTC).
+ optional int64 time = 2;
+
+ // If uncertainty is omitted, it is interpreted as unknown.
+ // If the prediction is unknown or too uncertain, the delay (or time) field
+ // should be empty. In such case, the uncertainty field is ignored.
+ // To specify a completely certain prediction, set its uncertainty to 0.
+ optional int32 uncertainty = 3;
+ }
+
+ // Realtime update for arrival and/or departure events for a given stop on a
+ // trip. Updates can be supplied for both past and future events.
+ // The producer is allowed, although not required, to drop past events.
+ message StopTimeUpdate {
+ // The update is linked to a specific stop either through stop_sequence or
+ // stop_id, so one of the fields below must necessarily be set.
+ // See the documentation in TripDescriptor for more information.
+
+ // Must be the same as in stop_times.txt in the corresponding GTFS feed.
+ optional uint32 stop_sequence = 1;
+ // Must be the same as in stops.txt in the corresponding GTFS feed.
+ optional string stop_id = 4;
+
+ optional StopTimeEvent arrival = 2;
+ optional StopTimeEvent departure = 3;
+
+ // The relation between this StopTime and the static schedule.
+ enum ScheduleRelationship {
+ // The vehicle is proceeding in accordance with its static schedule of
+ // stops, although not necessarily according to the times of the schedule.
+ // At least one of arrival and departure must be provided. If the schedule
+ // for this stop contains both arrival and departure times then so must
+ // this update. An update with only an arrival, say, where the schedule
+ // has both, indicates that the trip is terminating early at this stop.
+ SCHEDULED = 0;
+
+ // The stop is skipped, i.e., the vehicle will not stop at this stop.
+ // Arrival and departure are optional.
+ SKIPPED = 1;
+
+ // No data is given for this stop. The main intention for this value is to
+ // give the predictions only for part of a trip, i.e., if the last update
+ // for a trip has a NO_DATA specifier, then StopTimes for the rest of the
+ // stops in the trip are considered to be unspecified as well.
+ // Neither arrival nor departure should be supplied.
+ NO_DATA = 2;
+ }
+ optional ScheduleRelationship schedule_relationship = 5
+ [default = SCHEDULED];
+ }
+
+ // Updates to StopTimes for the trip (both future, i.e., predictions, and in
+ // some cases, past ones, i.e., those that already happened).
+ // The updates must be sorted by stop_sequence, and apply for all the
+ // following stops of the trip up to the next specified one.
+ //
+ // Example 1:
+ // For a trip with 20 stops, a StopTimeUpdate with arrival delay and departure
+ // delay of 0 for stop_sequence of the current stop means that the trip is
+ // exactly on time.
+ //
+ // Example 2:
+ // For the same trip instance, 3 StopTimeUpdates are provided:
+ // - delay of 5 min for stop_sequence 3
+ // - delay of 1 min for stop_sequence 8
+ // - delay of unspecified duration for stop_sequence 10
+ // This will be interpreted as:
+ // - stop_sequences 3,4,5,6,7 have delay of 5 min.
+ // - stop_sequences 8,9 have delay of 1 min.
+ // - stop_sequences 10,... have unknown delay.
+ repeated StopTimeUpdate stop_time_update = 2;
+}
+
+// Realtime positioning information for a given vehicle.
+message VehiclePosition {
+ // The Trip that this vehicle is serving.
+ // Can be empty or partial if the vehicle can not be identified with a given
+ // trip instance.
+ optional TripDescriptor trip = 1;
+
+ // Additional information on the vehicle that is serving this trip.
+ optional VehicleDescriptor vehicle = 8;
+
+ // Current position of this vehicle.
+ optional Position position = 2;
+
+ // The stop sequence index of the current stop. The meaning of
+ // current_stop_sequence (i.e., the stop that it refers to) is determined by
+ // current_status.
+ // If current_status is missing IN_TRANSIT_TO is assumed.
+ optional uint32 current_stop_sequence = 3;
+ // Identifies the current stop. The value must be the same as in stops.txt in
+ // the corresponding GTFS feed.
+ optional string stop_id = 7;
+
+ enum VehicleStopStatus {
+ // The vehicle is just about to arrive at the stop (on a stop
+ // display, the vehicle symbol typically flashes).
+ INCOMING_AT = 0;
+
+ // The vehicle is standing at the stop.
+ STOPPED_AT = 1;
+
+ // The vehicle has departed and is in transit to the next stop.
+ IN_TRANSIT_TO = 2;
+ }
+ // The exact status of the vehicle with respect to the current stop.
+ // Ignored if current_stop_sequence is missing.
+ optional VehicleStopStatus current_status = 4 [default = IN_TRANSIT_TO];
+
+ // Moment at which the vehicle's position was measured. In POSIX time
+ // (i.e., number of seconds since January 1st 1970 00:00:00 UTC).
+ optional uint64 timestamp = 5;
+
+ // Congestion level that is affecting this vehicle.
+ enum CongestionLevel {
+ UNKNOWN_CONGESTION_LEVEL = 0;
+ RUNNING_SMOOTHLY = 1;
+ STOP_AND_GO = 2;
+ CONGESTION = 3;
+ SEVERE_CONGESTION = 4; // People leaving their cars.
+ }
+ optional CongestionLevel congestion_level = 6;
+}
+
+// An alert, indicating some sort of incident in the public transit network.
+message Alert {
+ // Time when the alert should be shown to the user. If missing, the
+ // alert will be shown as long as it appears in the feed.
+ // If multiple ranges are given, the alert will be shown during all of them.
+ repeated TimeRange active_period = 1;
+
+ // Entities whose users we should notify of this alert.
+ repeated EntitySelector informed_entity = 5;
+
+ // Cause of this alert.
+ enum Cause {
+ UNKNOWN_CAUSE = 1;
+ OTHER_CAUSE = 2; // Not machine-representable.
+ TECHNICAL_PROBLEM = 3;
+ STRIKE = 4; // Public transit agency employees stopped working.
+ DEMONSTRATION = 5; // People are blocking the streets.
+ ACCIDENT = 6;
+ HOLIDAY = 7;
+ WEATHER = 8;
+ MAINTENANCE = 9;
+ CONSTRUCTION = 10;
+ POLICE_ACTIVITY = 11;
+ MEDICAL_EMERGENCY = 12;
+ }
+ optional Cause cause = 6 [default = UNKNOWN_CAUSE];
+
+ // What is the effect of this problem on the affected entity.
+ enum Effect {
+ NO_SERVICE = 1;
+ REDUCED_SERVICE = 2;
+
+ // We don't care about INsignificant delays: they are hard to detect, have
+ // little impact on the user, and would clutter the results as they are too
+ // frequent.
+ SIGNIFICANT_DELAYS = 3;
+
+ DETOUR = 4;
+ ADDITIONAL_SERVICE = 5;
+ MODIFIED_SERVICE = 6;
+ OTHER_EFFECT = 7;
+ UNKNOWN_EFFECT = 8;
+ STOP_MOVED = 9;
+ }
+ optional Effect effect = 7 [default = UNKNOWN_EFFECT];
+
+ // The URL which provides additional information about the alert.
+ optional TranslatedString url = 8;
+
+ // Alert header. Contains a short summary of the alert text.
+ optional TranslatedString header_text = 10;
+
+ // Full description for the alert. The information in the description
+ // should add to the information of the header.
+ optional TranslatedString description_text = 11;
+}
+
+//
+// Low level data structures used above.
+//
+
+// A time interval.
+message TimeRange {
+ // Start time, in POSIX time (i.e., number of seconds since January 1st 1970
+ // 00:00:00 UTC).
+ // If missing, the interval starts at minus infinity.
+ optional uint64 start = 1;
+
+ // End time, in POSIX time (i.e., number of seconds since January 1st 1970
+ // 00:00:00 UTC).
+ // If missing, the interval ends at plus infinity.
+ optional uint64 end = 2;
+}
+
+// A position.
+message Position {
+ // Degrees North, in the WGS-84 coordinate system.
+ required float latitude = 1;
+
+ // Degrees East, in the WGS-84 coordinate system.
+ required float longitude = 2;
+
+ // Bearing, in degrees, clockwise from North, i.e., 0 is North and 90 is East.
+ // This can be the compass bearing, or the direction towards the next stop
+ // or intermediate location.
+ // This should not be direction deduced from the sequence of previous
+ // positions, which can be computed from previous data.
+ optional float bearing = 3;
+
+ // Odometer value, in meters.
+ optional double odometer = 4;
+ // Momentary speed measured by the vehicle, in meters per second.
+ optional float speed = 5;
+
+}
+
+// A descriptor that identifies an instance of a GTFS trip, or all instances of
+// a trip along a route.
+// - To specify a single trip instance, the trip_id (and if necessary,
+// start_time) is set. If route_id is also set, then it should be same as one
+// that the given trip corresponds to.
+// - To specify all the trips along a given route, only the route_id should be
+// set. Note that if the trip_id is not known, then stop sequence ids in
+// TripUpdate are not sufficient, and stop_ids must be provided as well. In
+// addition, absolute arrival/departure times must be provided.
+message TripDescriptor {
+ // The trip_id from the GTFS feed that this selector refers to.
+ // For non frequency expanded trips, this field is enough to uniquely identify
+ // the trip. For frequency expanded, start_time and start_date might also be
+ // necessary.
+ optional string trip_id = 1;
+
+ // The route_id from the GTFS that this selector refers to.
+ optional string route_id = 5;
+
+ // The scheduled start time of this trip instance.
+ // This field should be given only if the trip is frequency-expanded in the
+ // GTFS feed. The value must precisely correspond to start_time specified for
+ // the route in the GTFS feed plus some multiple of headway_secs.
+ // Format of the field is same as that of GTFS/frequencies.txt/start_time,
+ // e.g., 11:15:35 or 25:15:35.
+ optional string start_time = 2;
+
+ // The scheduled start date of this trip instance.
+ // Must be provided to disambiguate trips that are so late as to collide with
+ // a scheduled trip on a next day. For example, for a train that departs 8:00
+ // and 20:00 every day, and is 12 hours late, there would be two distinct
+ // trips on the same time.
+ // This field can be provided but is not mandatory for schedules in which such
+ // collisions are impossible - for example, a service running on hourly
+ // schedule where a vehicle that is one hour late is not considered to be
+ // related to schedule anymore.
+ // In YYYYMMDD format.
+ optional string start_date = 3;
+
+ // The relation between this trip and the static schedule. If a trip is done
+ // in accordance with temporary schedule, not reflected in GTFS, then it
+ // shouldn't be marked as SCHEDULED, but likely as ADDED.
+ enum ScheduleRelationship {
+ // Trip that is running in accordance with its GTFS schedule, or is close
+ // enough to the scheduled trip to be associated with it.
+ SCHEDULED = 0;
+
+ // An extra trip that was added in addition to a running schedule, for
+ // example, to replace a broken vehicle or to respond to sudden passenger
+ // load.
+ ADDED = 1;
+
+ // A trip that is running with no schedule associated to it, for example, if
+ // there is no schedule at all.
+ UNSCHEDULED = 2;
+
+ // A trip that existed in the schedule but was removed.
+ CANCELED = 3;
+
+ // A trip that replaces a portion of static schedule.
+ // If the trip selector identifies a certain trip instance, then only that
+ // instance is replaced. If the selector identifies a route, then all the
+ // trips along that route are replaced.
+ //
+ // The replacement applies only to the portion of the trip supplied. For
+ // instance, consider a route that goes through stops A,B,C,D,E,F, and a
+ // REPLACEMENT trip provides data for stops A,B,C. Then, the times for stops
+ // D,E,F are still taken from the static schedule.
+ //
+ // A feed might supply several REPLACEMENT trips. In this case, the portion
+ // of static schedule that is replaced is the union of what is defined by
+ // all the feeds. Normally, all the REPLACEMENT trips should either
+ // correspond to the same route or to individual trip instances.
+ REPLACEMENT = 5;
+ }
+ optional ScheduleRelationship schedule_relationship = 4;
+}
+
+// Identification information for the vehicle performing the trip.
+message VehicleDescriptor {
+ // Internal system identification of the vehicle. Should be unique per
+ // vehicle, and can be used for tracking the vehicle as it proceeds through
+ // the system.
+ optional string id = 1;
+
+ // User visible label, i.e., something that must be shown to the passenger to
+ // help identify the correct vehicle.
+ optional string label = 2;
+
+ // The license plate of the vehicle.
+ optional string license_plate = 3;
+}
+
+// A selector for an entity in a GTFS feed.
+message EntitySelector {
+ // The values of the fields should correspond to the appropriate fields in the
+ // GTFS feed.
+ // At least one specifier must be given. If several are given, then the
+ // matching has to apply to all the given specifiers.
+ optional string agency_id = 1;
+ optional string route_id = 2;
+ // corresponds to route_type in GTFS.
+ optional int32 route_type = 3;
+ optional TripDescriptor trip = 4;
+ optional string stop_id = 5;
+}
+
+// An internationalized message containing per-language versions of a snippet of
+// text or a URL.
+// One of the strings from a message will be picked up. The resolution proceeds
+// as follows:
+// 1. If the UI language matches the language code of a translation,
+// the first matching translation is picked.
+// 2. If a default UI language (e.g., English) matches the language code of a
+// translation, the first matching translation is picked.
+// 3. If some translation has an unspecified language code, that translation is
+// picked.
+message TranslatedString {
+ message Translation {
+ // A UTF-8 string containing the message.
+ required string text = 1;
+ // BCP-47 language code. Can be omitted if the language is unknown or if
+ // no i18n is done at all for the feed. At most one translation is
+ // allowed to have an unspecified language tag.
+ optional string language = 2;
+ }
+ // At least one translation must be provided.
+ repeated Translation translation = 1;
+}
+
+
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf.php
@@ -1,1 +1,167 @@
+<?php
+namespace DrSlump;
+
+use DrSlump\Protobuf;
+
+class Protobuf
+{
+ const VERSION = '@package_version@';
+
+ const RULE_OPTIONAL = 1;
+ const RULE_REQUIRED = 2;
+ const RULE_REPEATED = 3;
+ const RULE_UNKNOWN = -1;
+
+ const TYPE_DOUBLE = 1;
+ const TYPE_FLOAT = 2;
+ const TYPE_INT64 = 3;
+ const TYPE_UINT64 = 4;
+ const TYPE_INT32 = 5;
+ const TYPE_FIXED64 = 6;
+ const TYPE_FIXED32 = 7;
+ const TYPE_BOOL = 8;
+ const TYPE_STRING = 9;
+ const TYPE_GROUP = 10;
+ const TYPE_MESSAGE = 11;
+ const TYPE_BYTES = 12;
+ const TYPE_UINT32 = 13;
+ const TYPE_ENUM = 14;
+ const TYPE_SFIXED32 = 15;
+ const TYPE_SFIXED64 = 16;
+ const TYPE_SINT32 = 17;
+ const TYPE_SINT64 = 18;
+ const TYPE_UNKNOWN = -1;
+
+
+ static protected $codecs = array();
+
+
+ /**
+ * Setup SPL autoloader for Protobuf library classes
+ *
+ * @static
+ * @return void
+ */
+ static public function autoload()
+ {
+ spl_autoload_register(function($class){
+ $prefix = __CLASS__ . '\\';
+ if (strpos($class, $prefix) === 0) {
+ // Remove vendor from name
+ $class = substr($class, strlen(__NAMESPACE__)+1);
+ // Convert namespace separator to directory ones
+ $class = str_replace('\\', DIRECTORY_SEPARATOR, $class);
+ // Prefix with this file's directory
+ $class = __DIR__ . DIRECTORY_SEPARATOR . $class;
+
+ include($class . '.php');
+ return true;
+ }
+
+ return false;
+ });
+ }
+
+ /**
+ * Obtain an instance of the descriptor's registry
+ *
+ * @static
+ * @return Protobuf\Registry
+ */
+ static public function getRegistry()
+ {
+ static $registry = NULL;
+
+ if (NULL === $registry) {
+ $registry = new Protobuf\Registry();
+ }
+
+ return $registry;
+ }
+
+
+ static public function getCodec($codec = null)
+ {
+ if ($codec instanceof Protobuf\CodecInterface) {
+ return $codec;
+ }
+
+ // Bootstrap the library's default codec if none is available
+ if (!isset(self::$codecs['default'])) {
+ $default = new Protobuf\Codec\Binary();
+ self::registerCodec('default', $default);
+ self::registerCodec('binary', $default);
+ }
+
+ if (is_string($codec)) {
+ $codec = strtolower($codec);
+ if (!isset(self::$codecs[$codec])) {
+ throw new Protobuf\Exception('No codec found by name "' . $codec . '"');
+ }
+ return self::$codecs[$codec];
+ }
+
+ return self::getCodec('default');
+ }
+
+ static public function setDefaultCodec($codec)
+ {
+ if (is_string($codec)) {
+ $codec = self::getCodec($codec);
+ }
+
+ if ($codec instanceof Protobuf\CodecInterface) {
+ self::registerCodec('default', $codec);
+ } else {
+ throw new Protobuf\Exception('Codec must implement DrSlump\Protobuf\CodecInterface');
+ }
+ }
+
+ static public function registerCodec($name, Protobuf\CodecInterface $codec)
+ {
+ $name = strtolower($name);
+ self::$codecs[$name] = $codec;
+ }
+
+ static public function unregisterCodec($name)
+ {
+ $name = strtolower($name);
+ if (isset(self::$codecs[$name])) {
+ unset(self::$codecs[$name]);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Encodes a message using the default codec
+ *
+ * @static
+ * @param \DrSlump\Protobuf\Message $message
+ * @return string
+ */
+ static public function encode(Protobuf\Message $message)
+ {
+ $codec = self::getCodec();
+ return $codec->encode($message);
+ }
+
+ /**
+ * @static
+ * @param String|Message $message
+ * @param String $data
+ * @return \DrSlump\Protobuf\Message
+ */
+ static public function decode($message, $data)
+ {
+ if (is_string($message)) {
+ $message = '\\' . ltrim($message, '\\');
+ $message = new $message;
+ }
+
+ $codec = self::getCodec();
+ return $codec->decode($message, $data);
+ }
+}
+
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/AnnotatedMessage.php
@@ -1,1 +1,116 @@
+<?php
+namespace DrSlump\Protobuf;
+
+use DrSlump\Protobuf;
+
+abstract class AnnotatedMessage extends Message
+{
+ static public function descriptor()
+ {
+ $class = get_called_class();
+
+ // Instantiate a new descriptor
+ $descriptor = new Descriptor($class);
+
+ $rflClass = new \ReflectionClass($class);
+ $props = $rflClass->getProperties();
+ foreach ($props as $prop) {
+ $doc = $prop->getDocComment();
+ if (empty($doc)) {
+ continue;
+ }
+
+ // Format: @protobuf(tag=X, type=bool, required=true)
+
+ // Extract annotation from the comment
+ if (!preg_match('/@protobuf\s?\(([^\)]+)\)/', $doc, $m)) {
+ continue;
+ }
+
+ // Parse params
+ $params = explode(',', $m[1]);
+ $params = array_filter(array_map('trim', $params));
+
+ $options = array();
+ foreach ($params as $param) {
+ $parts = explode('=', $param);
+ $parts = array_filter(array_map('trim', $parts));
+ $options[$parts[0]] = count($parts) < 2
+ ? true
+ : $parts[1];
+ }
+
+ // Check if we have the minimum required options
+ if (empty($options['tag'])) {
+ throw new \InvalidArgumentException('The tag option is required for property ' . $prop->getName());
+ }
+ if (empty($options['type'])) {
+ throw new \InvalidArgumentException('The type option is required for property ' . $prop->getName());
+ }
+
+ // Normalize boolean values
+ foreach(array('required', 'optional', 'repeated', 'packed') as $opt) {
+ if (isset($options[$opt])) {
+ $options[$opt] = filter_var($options[$opt], FILTER_VALIDATE_BOOLEAN);
+ }
+ }
+
+ // Build a field descriptor
+ $f = new Protobuf\Field();
+ $f->number = (int)$options['tag'];
+ $f->name = $prop->getName();
+
+ // Convert type name to its numeric constant
+ switch (strtolower($options['type'])) {
+ case 'double' : $f->type = Protobuf::TYPE_DOUBLE; break;
+ case 'float' : $f->type = Protobuf::TYPE_FLOAT; break;
+ case 'int64' : $f->type = Protobuf::TYPE_INT64; break;
+ case 'uint64' : $f->type = Protobuf::TYPE_UINT64; break;
+ case 'int32' : $f->type = Protobuf::TYPE_INT32; break;
+ case 'fixed64' : $f->type = Protobuf::TYPE_FIXED64; break;
+ case 'fixed32' : $f->type = Protobuf::TYPE_FIXED32; break;
+ case 'bool' : $f->type = Protobuf::TYPE_BOOL; break;
+ case 'string' : $f->type = Protobuf::TYPE_STRING; break;
+ case 'message' : $f->type = Protobuf::TYPE_MESSAGE; break;
+ case 'bytes' : $f->type = Protobuf::TYPE_BYTES; break;
+ case 'uint32' : $f->type = Protobuf::TYPE_UINT32; break;
+ case 'enum' : $f->type = Protobuf::TYPE_ENUM; break;
+ case 'sfixed32': $f->type = Protobuf::TYPE_SFIXED32; break;
+ case 'sfixed64': $f->type = Protobuf::TYPE_SFIXED64; break;
+ case 'sint32' : $f->type = Protobuf::TYPE_SINT32; break;
+ case 'sint64' : $f->type = Protobuf::TYPE_SINT64; break;
+ default:
+ throw new \InvalidArgumentException('Type ' . $options['type'] . ' is not recognized as valid for property ' . $prop->getName());
+ }
+
+ // Define the rule type
+ $f->rule = Protobuf::RULE_OPTIONAL;
+ if (!empty($options['required'])) $f->rule = Protobuf::RULE_REQUIRED;
+ if (!empty($options['repeated'])) $f->rule = Protobuf::RULE_REPEATED;
+
+ // Check if it's flagged as packed
+ if (isset($options['packed'])) {
+ $f->packed = $options['packed'];
+ }
+
+ // Get the reference
+ if (isset($options['reference'])) {
+ $f->reference = $options['reference'];
+ } else if ($f->type === Protobuf::TYPE_MESSAGE || $f->type === Protobuf::TYPE_ENUM) {
+ throw new \InvalidArgumentException('Property ' . $prop->getName() . ' requires the "reference" option');
+ }
+
+ if (isset($options['default'])) {
+ $f->default = $options['default'];
+ }
+
+ // Add the field to the message descriptor
+ $descriptor->addField($f);
+ }
+
+ return $descriptor;
+ }
+
+}
+
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/Binary.php
@@ -1,1 +1,389 @@
-
+<?php
+
+namespace DrSlump\Protobuf\Codec;
+
+use DrSlump\Protobuf;
+
+class Binary implements Protobuf\CodecInterface
+{
+ const WIRE_VARINT = 0;
+ const WIRE_FIXED64 = 1;
+ const WIRE_LENGTH = 2;
+ const WIRE_GROUP_START = 3;
+ const WIRE_GROUP_END = 4;
+ const WIRE_FIXED32 = 5;
+ const WIRE_UNKNOWN = -1;
+
+ /**
+ * @param \DrSlump\Protobuf\Message $message
+ * @return string
+ */
+ public function encode(Protobuf\Message $message)
+ {
+ return $this->encodeMessage($message);
+ }
+
+ /**
+ * @param String|Message $message
+ * @param String $data
+ * @return \DrSlump\Protobuf\Message
+ */
+ public function decode(Protobuf\Message $message, $data)
+ {
+ return $this->decodeMessage($message, $data);
+ }
+
+
+ protected function encodeMessage(Protobuf\Message $message)
+ {
+ $writer = new Binary\Writer();
+
+ // Get message descriptor
+ $descriptor = Protobuf::getRegistry()->getDescriptor($message);
+
+ foreach ($descriptor->getFields() as $tag=>$field) {
+
+ $empty = !$message->_has($tag);
+ if ($field->isRequired() && $empty) {
+ throw new \UnexpectedValueException(
+ 'Message ' . get_class($message) . '\'s field tag ' . $tag . '(' . $field->getName() . ') is required but has no value'
+ );
+ }
+
+ // Skip empty fields
+ if ($empty) {
+ continue;
+ }
+
+ $type = $field->getType();
+ $wire = $field->isPacked() ? self::WIRE_LENGTH : $this->getWireType($type, null);
+
+ // Compute key with tag number and wire type
+ $key = $tag << 3 | $wire;
+
+ $value = $message->_get($tag);
+
+ if ($field->isRepeated()) {
+
+ // Packed fields are encoded as a length-delimited stream containing
+ // the concatenated encoding of each value.
+ if ($field->isPacked() && !empty($value)) {
+ $subwriter = new Binary\Writer();
+ foreach($value as $val) {
+ $this->encodeSimpleType($subwriter, $type, $val);
+ }
+ $data = $subwriter->getBytes();
+ $writer->varint($key);
+ $writer->varint(strlen($data));
+ $writer->write($data);
+ } else {
+ foreach($value as $val) {
+ if ($type !== Protobuf::TYPE_MESSAGE) {
+ $writer->varint($key);
+ $this->encodeSimpleType($writer, $type, $val);
+ } else {
+ $writer->varint($key);
+ $data = $this->encodeMessage($val);
+ $writer->varint(strlen($data));
+ $writer->write($data);
+ }
+ }
+ }
+ } else {
+ if ($type !== Protobuf::TYPE_MESSAGE) {
+ $writer->varint($key);
+ $this->encodeSimpleType($writer, $type, $value);
+ } else {
+ $writer->varint($key);
+ $data = $this->encodeMessage($value);
+ $writer->varint(strlen($data));
+ $writer->write($data);
+ }
+ }
+ }
+
+ return $writer->getBytes();
+ }
+
+ protected function encodeSimpleType($writer, $type, $value)
+ {
+ switch ($type) {
+ case Protobuf::TYPE_INT32:
+ case Protobuf::TYPE_INT64:
+ case Protobuf::TYPE_UINT64:
+ case Protobuf::TYPE_UINT32:
+ $writer->varint($value);
+ break;
+
+ case Protobuf::TYPE_SINT32: // ZigZag
+ $writer->zigzag($value, 32);
+ break;
+
+ case Protobuf::TYPE_SINT64 : // ZigZag
+ $writer->zigzag($value, 64);
+ break;
+
+ case Protobuf::TYPE_DOUBLE:
+ $writer->double($value);
+ break;
+ case Protobuf::TYPE_FIXED64:
+ $writer->fixed64($value);
+ break;
+ case Protobuf::TYPE_SFIXED64:
+ $writer->sFixed64($value);
+ break;
+
+ case Protobuf::TYPE_FLOAT:
+ $writer->float($value);
+ break;
+ case Protobuf::TYPE_FIXED32:
+ $writer->fixed32($value);
+ break;
+ case Protobuf::TYPE_SFIXED32:
+ $writer->sFixed32($value);
+ break;
+
+ case Protobuf::TYPE_BOOL:
+ $writer->varint($value ? 1 : 0);
+ break;
+
+ case Protobuf::TYPE_STRING:
+ case Protobuf::TYPE_BYTES:
+ $writer->varint(strlen($value));
+ $writer->write($value);
+ break;
+
+ case Protobuf::TYPE_MESSAGE:
+ // Messages are not supported in this method
+ return null;
+
+ case Protobuf::TYPE_ENUM:
+ $writer->varint($value);
+ break;
+
+ default:
+ throw new \Exception('Unknown field type ' . $type);
+ }
+ }
+
+
+ protected function decodeMessage(\DrSlump\Protobuf\Message $message, $data)
+ {
+ /** @var $message \DrSlump\Protobuf\Message */
+ /** @var $descriptor \DrSlump\Protobuf\Descriptor */
+
+ // Create a binary reader for the data
+ $reader = new Protobuf\Codec\Binary\Reader($data);
+
+ // Get message descriptor
+ $descriptor = Protobuf::getRegistry()->getDescriptor($message);
+
+ while (!$reader->eof()) {
+
+ // Get initial varint with tag number and wire type
+ $key = $reader->varint();
+ if ($reader->eof()) break;
+
+ $wire = $key & 0x7;
+ $tag = $key >> 3;
+
+ // Find the matching field for the tag number
+ $field = $descriptor->getField($tag);
+ if (!$field) {
+ $data = $this->decodeUnknown($reader, $wire);
+ $unknown = new Binary\Unknown($tag, $wire, $data);
+ $message->addUnknown($unknown);
+ continue;
+ }
+
+ $type = $field->getType();
+
+ // Check if we are dealing with a packed stream, we cannot rely on the packed
+ // flag of the message since we cannot be certain if the creator of the message
+ // was using it.
+ if ($wire === self::WIRE_LENGTH && $field->isRepeated() && $this->isPackable($type)) {
+ $length = $reader->varint();
+ $until = $reader->pos() + $length;
+ while ($reader->pos() < $until) {
+ $item = $this->decodeSimpleType($reader, $type, self::WIRE_VARINT);
+ $message->_add($tag, $item);
+ }
+
+ } else {
+
+ // Assert wire and type match
+ $this->assertWireType($wire, $type);
+
+ // Check if it's a sub-message
+ if ($type === Protobuf::TYPE_MESSAGE) {
+ $submessage = $field->getReference();
+ $submessage = new $submessage;
+
+ $length = $this->decodeSimpleType($reader, Protobuf::TYPE_INT64, self::WIRE_VARINT);
+ $data = $reader->read($length);
+
+ $value = $this->decodeMessage($submessage, $data);
+ } else {
+ $value = $this->decodeSimpleType($reader, $type, $wire);
+ }
+
+ // Support non-packed repeated fields
+ if ($field->isRepeated()) {
+ $message->_add($tag, $value);
+ } else {
+ $message->_set($tag, $value);
+ }
+ }
+ }
+
+ return $message;
+ }
+
+ protected function isPackable($type)
+ {
+ static $packable = array(
+ Protobuf::TYPE_INT64,
+ Protobuf::TYPE_UINT64,
+ Protobuf::TYPE_INT32,
+ Protobuf::TYPE_UINT32,
+ Protobuf::TYPE_SINT32,
+ Protobuf::TYPE_SINT64,
+ Protobuf::TYPE_DOUBLE,
+ Protobuf::TYPE_FIXED64,
+ Protobuf::TYPE_SFIXED64,
+ Protobuf::TYPE_FLOAT,
+ Protobuf::TYPE_FIXED32,
+ Protobuf::TYPE_SFIXED32,
+ Protobuf::TYPE_BOOL,
+ Protobuf::TYPE_ENUM
+ );
+
+ return in_array($type, $packable);
+ }
+
+ protected function decodeUnknown($reader, $wire)
+ {
+ switch ($wire) {
+ case self::WIRE_VARINT:
+ return $reader->varint();
+ case self::WIRE_LENGTH:
+ $length = $reader->varint();
+ return $reader->read($length);
+ case self::WIRE_FIXED32:
+ return $reader->fixed32();
+ case self::WIRE_FIXED64:
+ return $reader->fixed64();
+ case self::WIRE_GROUP_START:
+ case self::WIRE_GROUP_END:
+ throw new \RuntimeException('Groups are deprecated in Protocol Buffers and unsupported by this library');
+ default:
+ throw new \RuntimeException('Unsupported wire type (' . $wire . ') while consuming unknown field');
+ }
+ }
+
+ protected function assertWireType($wire, $type)
+ {
+ $expected = $this->getWireType($type, $wire);
+ if ($wire !== $expected) {
+ throw new \RuntimeException("Expected wire type $expected but got $wire for type $type");
+ }
+ }
+
+ protected function getWireType($type, $default)
+ {
+ switch ($type) {
+ case Protobuf::TYPE_INT32:
+ case Protobuf::TYPE_INT64:
+ case Protobuf::TYPE_UINT32:
+ case Protobuf::TYPE_UINT64:
+ case Protobuf::TYPE_SINT32:
+ case Protobuf::TYPE_SINT64:
+ case Protobuf::TYPE_BOOL:
+ case Protobuf::TYPE_ENUM:
+ return self::WIRE_VARINT;
+ case Protobuf::TYPE_FIXED64:
+ case Protobuf::TYPE_SFIXED64:
+ case Protobuf::TYPE_DOUBLE:
+ return self::WIRE_FIXED64;
+ case Protobuf::TYPE_STRING:
+ case Protobuf::TYPE_BYTES:
+ case Protobuf::TYPE_MESSAGE:
+ return self::WIRE_LENGTH;
+ case Protobuf::TYPE_FIXED32:
+ case Protobuf::TYPE_SFIXED32:
+ case Protobuf::TYPE_FLOAT:
+ return self::WIRE_FIXED32;
+ default:
+ // Unknown fields just return the reported wire type
+ return $default;
+ }
+ }
+
+ protected function decodeSimpleType($reader, $type, $wireType)
+ {
+ switch ($type) {
+ case Protobuf::TYPE_INT64:
+ case Protobuf::TYPE_UINT64:
+ case Protobuf::TYPE_INT32:
+ case Protobuf::TYPE_UINT32:
+ return $reader->varint();
+
+ case Protobuf::TYPE_SINT32: // ZigZag
+ return $reader->zigzag();
+ case Protobuf::TYPE_SINT64: // ZigZag
+ return $reader->zigzag();
+ case Protobuf::TYPE_DOUBLE:
+ return $reader->double();
+ case Protobuf::TYPE_FIXED64:
+ return $reader->fixed64();
+ case Protobuf::TYPE_SFIXED64:
+ return $reader->sFixed64();
+
+ case Protobuf::TYPE_FLOAT:
+ return $reader->float();
+ case Protobuf::TYPE_FIXED32:
+ return $reader->fixed32();
+ case Protobuf::TYPE_SFIXED32:
+ return $reader->sFixed32();
+
+ case Protobuf::TYPE_BOOL:
+ return (bool)$reader->varint();
+
+ case Protobuf::TYPE_STRING:
+ $length = $reader->varint();
+ return $reader->read($length);
+
+ case Protobuf::TYPE_MESSAGE:
+ // Messages are not supported in this method
+ return null;
+
+ case Protobuf::TYPE_BYTES:
+ $length = $reader->varint();
+ return $reader->read($length);
+
+ case Protobuf::TYPE_ENUM:
+ return $reader->varint();
+
+ default:
+ // Unknown type, follow wire type rules
+ switch ($wireType) {
+ case self::WIRE_VARINT:
+ return $reader->varint();
+ case self::WIRE_FIXED32:
+ return $reader->fixed32();
+ case self::WIRE_FIXED64:
+ return $reader->fixed64();
+ case self::WIRE_LENGTH:
+ $length = $reader->varint();
+ return $reader->read($length);
+ case self::WIRE_GROUP_START:
+ case self::WIRE_GROUP_END:
+ throw new \RuntimeException('Group is deprecated and not supported');
+ default:
+ throw new \RuntimeException('Unsupported wire type number ' . $wireType);
+ }
+ }
+
+ }
+
+}
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/Binary/Reader.php
@@ -1,1 +1,223 @@
-
+<?php
+
+namespace DrSlump\Protobuf\Codec\Binary;
+
+/**
+ * Implements reading primitives for Protobuf binary streams
+ *
+ * Important: There are no checks in place for overflows, so you must
+ * be aware of PHP's integer and floating point limits.
+ *
+ * @note Protobuf uses little-endian order
+ */
+class Reader
+{
+ /** @var resource */
+ protected $_fd;
+
+ /**
+ * Create a new reader from a file descriptor or a string of bytes
+ *
+ * @param resource|string $fdOrString
+ */
+ public function __construct($fdOrString)
+ {
+ if (is_resource($fdOrString)) {
+ $this->_fd = $fdOrString;
+ } else {
+ // @todo Could this be faster by using a custom String wrapper?
+ $this->_fd = fopen('data://text/plain,' . urlencode($fdOrString), 'rb');
+ }
+ }
+
+ public function __destruct()
+ {
+ fclose($this->_fd);
+ }
+
+ /**
+ * Obtain a number of bytes from the string
+ *
+ * @throws \RuntimeException
+ * @param int $length
+ * @return string
+ */
+ public function read($length)
+ {
+ // Protect against 0 byte reads when an EOF
+ if ($length < 1) return '';
+
+ $bytes = fread($this->_fd, $length);
+ if (FALSE === $bytes) {
+ throw new \RuntimeException('Failed to read ' . $length . ' bytes');
+ }
+
+ return $bytes;
+ }
+
+ /**
+ * Check if we have reached the end of the stream
+ *
+ * @return bool
+ */
+ public function eof()
+ {
+ return feof($this->_fd);
+ }
+
+ /**
+ * Obtain the current position in the stream
+ *
+ * @return int
+ */
+ public function pos()
+ {
+ return ftell($this->_fd);
+ }
+
+ /**
+ * Obtain a byte
+ *
+ * @return int
+ */
+ public function byte()
+ {
+ return ord($this->read(1));
+ }
+
+ /**
+ * Decode a varint
+ *
+ * @return int
+ */
+ public function varint()
+ {
+ $result = $shift = 0;
+ do {
+ $byte = $this->byte();
+ $result |= ($byte & 0x7f) << $shift;
+ $shift += 7;
+ } while ($byte > 0x7f);
+
+ return $result;
+ }
+
+ /**
+ * Decodes a zigzag integer of the given bits
+ *
+ * @param int $bits - Either 32 or 64
+ */
+ public function zigzag()
+ {
+ $number = $this->varint();
+ return ($number >> 1) ^ (-($number & 1));
+ }
+
+ /**
+ * Decode a fixed 32bit integer with sign
+ *
+ * @return int
+ */
+ public function sFixed32()
+ {
+ $bytes = $this->read(4);
+ if ($this->isBigEndian()) {
+ $bytes = strrev($bytes);
+ }
+
+ list(, $result) = unpack('l', $bytes);
+ return $result;
+ }
+
+ /**
+ * Decode a fixed 32bit integer without sign
+ *
+ * @return int
+ */
+ public function fixed32()
+ {
+ $bytes = $this->read(4);
+
+ if (PHP_INT_SIZE < 8) {
+ list(, $lo, $hi) = unpack('v*', $bytes);
+ $result = $hi << 16 | $lo;
+ } else {
+ list(, $result) = unpack('V*', $bytes);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Decode a fixed 62bit integer with sign
+ *
+ * @return int
+ */
+ public function sFixed64()
+ {
+ $bytes = $this->read(8);
+
+ list(, $lo0, $lo1, $hi0, $hi1) = unpack('v*', $bytes);
+ return ($hi1 << 16 | $hi0) << 32 | ($lo1 << 16 | $lo0);
+ }
+
+ /**
+ * Decode a fixed 62bit integer without sign
+ *
+ * @return int
+ */
+ public function fixed64()
+ {
+ return $this->sFixed64();
+ }
+
+ /**
+ * Decode a 32bit float
+ *
+ * @return float
+ */
+ public function float()
+ {
+ $bytes = $this->read(4);
+ if ($this->isBigEndian()) {
+ $bytes = strrev($bytes);
+ }
+
+ list(, $result) = unpack('f', $bytes);
+ return $result;
+ }
+
+ /**
+ * Decode a 64bit double
+ *
+ * @return float
+ */
+ public function double()
+ {
+ $bytes = $this->read(8);
+ if ($this->isBigEndian()) {
+ $bytes = strrev($bytes);
+ }
+
+ list(, $result) = unpack('d', $bytes);
+ return $result;
+ }
+
+ /**
+ * Check if the current architecture is Big Endian
+ *
+ * @return bool
+ */
+ public function isBigEndian()
+ {
+ static $endianness;
+
+ if (NULL === $endianness) {
+ list(,$result) = unpack('L', pack('V', 1));
+ $endianness = $result !== 1;
+ }
+
+ return $endianness;
+ }
+}
+
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/Binary/Unknown.php
@@ -1,1 +1,14 @@
+<?php
+namespace DrSlump\Protobuf\Codec\Binary;
+
+class Unknown extends \DrSlump\Protobuf\Unknown
+{
+ public function __construct($tag, $type, $data)
+ {
+ $this->tag = $tag;
+ $this->type = $type;
+ $this->data = $data;
+ }
+}
+
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/Binary/Writer.php
@@ -1,1 +1,318 @@
-
+<?php
+
+namespace DrSlump\Protobuf\Codec\Binary;
+
+/**
+ * Implements writing primitives for Protobuf binary streams
+ *
+ * @note Protobuf uses little-endian order
+ */
+class Writer
+{
+ /** @var resource */
+ protected $_fd;
+
+
+ public function __construct()
+ {
+ $this->_fd = fopen('php://memory', 'wb');
+ }
+
+ public function __destruct()
+ {
+ fclose($this->_fd);
+ }
+
+ /**
+ * Get the current bytes in the stream
+ *
+ * @return string
+ */
+ public function getBytes()
+ {
+ fseek($this->_fd, 0, SEEK_SET);
+ return stream_get_contents($this->_fd);
+ }
+
+ /**
+ * Store the given bytes in the stream
+ *
+ * @throws \RuntimeException
+ * @param string $bytes
+ * @param int $length
+ */
+ public function write($bytes, $length = null)
+ {
+ if ($length === NULL) {
+ $length = strlen($bytes);
+ }
+
+ $written = fwrite($this->_fd, $bytes, $length);
+ if ($written !== $length) {
+ throw new \RuntimeException('Failed to write ' . $length . ' bytes');
+ }
+ }
+
+ /**
+ * Store a single byte
+ *
+ * @param int $value
+ */
+ public function byte($value)
+ {
+ $this->write(chr($value), 1);
+ }
+
+ /**
+ * Store an integer encoded as varint
+ *
+ * @throws \OutOfBoundsException
+ * @param int $value
+ */
+ public function varint($value)
+ {
+ // Small values do not need to be encoded
+ if ($value >= 0 && $value < 0x80) {
+ $this->byte($value);
+ return;
+ }
+
+ // Build an array of bytes with the encoded values
+ if ($value > 0) {
+ $values = array();
+ while ($value > 0) {
+ $values[] = 0x80 | ($value & 0x7f);
+ $value = $value >> 7;
+ }
+ } else if (function_exists('gmp_init')) {
+ $value = PHP_INT_SIZE < 8
+ ? gmp_and($value, '0x0ffffffffffffffff')
+ : sprintf('%u', $value);
+
+ $values = $this->varint_gmp($value);
+ } else if (PHP_INT_SIZE < 8) {
+ throw new \OutOfBoundsException(
+ "PHP versions compiled with 32bit integers can only support negative integer encoding with GMP extension ($value was given)"
+ );
+ } else if (function_exists('bccomp')) {
+ $value = sprintf('%u', $value);
+ $values = $this->varint_bc($value);
+ } else {
+ throw new \OutOfBoundsException("Varints of negative integers are only supported with GMP or BC big integers PHP extensions ($value was given)");
+ }
+
+ // Remove the MSB flag from the last byte
+ $values[count($values)-1] &= 0x7f;
+
+ // Convert the byte sized ints to actual bytes in a string
+ //$bytes = implode('', array_map('chr', $values));
+ $bytes = call_user_func_array('pack', array_merge(array('C*'), $values));;
+
+ $this->write($bytes);
+ }
+
+ public function varint_gmp($value)
+ {
+ static $x00, $x7f, $x80;
+
+ if (NULL === $x00) {
+ $x00 = \gmp_init(0x00);
+ $x7f = \gmp_init(0x7f);
+ $x80 = \gmp_init(0x80);
+ }
+
+ $values = array();
+ while (\gmp_cmp($value, $x00) > 0) {
+ $values[] = \gmp_intval(\gmp_and($value, $x7f)) | 0x80;
+ $value = \gmp_div_q($value, $x80);
+ }
+
+ return $values;
+ }
+
+ public function varint_bc($value)
+ {
+ $values = array();
+ while (\bccomp($value, 0, 0) > 0) {
+ // Get the last 7bits of the number
+ $bin = '';
+ $dec = $value;
+ do {
+ $rest = bcmod($dec, 2);
+ $dec = bcdiv($dec, 2, 0);
+ $bin = $rest . $bin;
+ } while ($dec > 0 && strlen($bin) < 7);
+
+ // Pack as a decimal and apply the flag
+ $values[] = intval($bin, 2) | 0x80;
+
+ $value = bcdiv($value, 0x80, 0);
+ }
+
+ return $values;
+ }
+
+ /**
+ * Encodes an integer with zigzag
+ *
+ * @param int $value
+ * @param int $base Either 32 or 64 bits
+ */
+ public function zigzag($value, $base = 32)
+ {
+ $value = ($value << 1) ^ ($value >> $base-1);
+ $this->varint($value);
+ }
+
+ /**
+ * Encode an integer as a fixed of 32bits with sign
+ *
+ * @param int $value
+ */
+ public function sFixed32($value)
+ {
+ $bytes = pack('l*', $value);
+ if ($this->isBigEndian()) {
+ $bytes = strrev($bytes);
+ }
+
+ $this->write($bytes, 4);
+ }
+
+ /**
+ * Encode an integer as a fixed of 32bits without sign
+ *
+ * @param int $value
+ */
+ public function fixed32($value)
+ {
+ $bytes = pack('V*', $value);
+ $this->write($bytes, 4);
+ }
+
+ /**
+ * Encode an integer as a fixed of 64bits with sign
+ *
+ * @param int $value
+ */
+ public function sFixed64($value)
+ {
+ if ($value >= 0) {
+ $this->fixed64($value);
+ } else if (function_exists('gmp_init')) {
+ $this->sFixed64_gmp($value);
+ } else if (function_exists('bcadd')) {
+ $this->sFixed64_bc($value);
+ } else {
+ throw new \OutOfBoundsException("The signed Fixed64 type with negative integers is only supported with GMP or BC big integers PHP extensions ($value was given)");
+ }
+ }
+
+ public function sFixed64_gmp($value)
+ {
+ static $xff, $x100;
+
+ if (NULL === $xff) {
+ $xff = gmp_init(0xff);
+ $x100 = gmp_init(0x100);
+ }
+
+ $value = PHP_INT_SIZE < 8
+ ? gmp_and($value, '0x0ffffffffffffffff')
+ : gmp_init(sprintf('%u', $value));
+
+ $bytes = '';
+ for ($i=0; $i<8; $i++) {
+ $bytes .= chr(gmp_intval(gmp_and($value, $xff)));
+ $value = gmp_div_q($value, $x100);
+ }
+
+ $this->write($bytes);
+ }
+
+ public function sFixed64_bc($value)
+ {
+ if (PHP_INT_SIZE < 8) {
+ throw new \OutOfBoundsException(
+ "PHP versions compiled with 32bit integers can only support negative integer encoding with GMP extension ($value was given)"
+ );
+ }
+
+ $value = sprintf('%u', $value);
+
+ $bytes = '';
+ for ($i=0; $i<8; $i++) {
+ // Get the last 8bits of the number
+ $bin = '';
+ $dec = $value;
+ do {
+ $bin = bcmod($dec, 2) . $bin;
+ $dec = bcdiv($dec, 2, 0);
+ } while (strlen($bin) < 8);
+
+ // Pack the byte
+ $bytes .= chr(intval($bin, 2));
+
+ $value = bcdiv($value, 0x100, 0);
+ }
+
+ $this->write($bytes);
+ }
+
+ /**
+ * Encode an integer as a fixed of 64bits without sign
+ *
+ * @param int $value
+ */
+ public function fixed64($value)
+ {
+ $bytes = pack('V*', $value & 0xffffffff, $value / (0xffffffff+1));
+ $this->write($bytes, 8);
+ }
+
+ /**
+ * Encode a number as a 32bit float
+ *
+ * @param float $value
+ */
+ public function float($value)
+ {
+ $bytes = pack('f*', $value);
+ if ($this->isBigEndian()) {
+ $bytes = strrev($bytes);
+ }
+ $this->write($bytes, 4);
+ }
+
+ /**
+ * Encode a number as a 64bit double
+ *
+ * @param float $value
+ */
+ public function double($value)
+ {
+ $bytes = pack('d*', $value);
+ if ($this->isBigEndian()) {
+ $bytes = strrev($bytes);
+ }
+ $this->write($bytes, 8);
+ }
+
+ /**
+ * Checks if the current architecture is Big Endian
+ *
+ * @return bool
+ */
+ public function isBigEndian()
+ {
+ static $endianness;
+
+ if (NULL === $endianness) {
+ list(,$result) = unpack('L', pack('V', 1));
+ $endianness = $result !== 1;
+ }
+
+ return $endianness;
+ }
+}
+
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/Json.php
@@ -1,1 +1,39 @@
+<?php
+namespace DrSlump\Protobuf\Codec;
+
+use DrSlump\Protobuf;
+
+/**
+ * This codec serializes and unserializes from/to Json strings
+ * where the keys represent the field's name.
+ *
+ * It makes use of the PhpArray codec to do the heavy work to just
+ * take care of converting the array to/from Json strings.
+ */
+class Json extends PhpArray
+ implements Protobuf\CodecInterface
+{
+ /**
+ * @param \DrSlump\Protobuf\Message $message
+ * @return string
+ */
+ public function encode(Protobuf\Message $message)
+ {
+ $data = $this->encodeMessage($message);
+ return json_encode($data);
+ }
+
+ /**
+ * @param \DrSlump\Protobuf\Message $message
+ * @param string $data
+ * @return \DrSlump\Protobuf\Message
+ */
+ public function decode(Protobuf\Message $message, $data)
+ {
+ $data = json_decode($data);
+ return $this->decodeMessage($message, $data);
+ }
+
+}
+
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/JsonIndexed.php
@@ -1,1 +1,140 @@
+<?php
+namespace DrSlump\Protobuf\Codec;
+
+use DrSlump\Protobuf;
+
+/**
+ * This codec serializes and unserializes from/to Json strings
+ * where the keys are packed as the first element of numeric arrays,
+ * optimizing the resulting payload size.
+ *
+ */
+class JsonIndexed extends Json
+ implements Protobuf\CodecInterface
+{
+
+ protected function encodeMessage(Protobuf\Message $message)
+ {
+ $descriptor = Protobuf::getRegistry()->getDescriptor($message);
+
+ $index = '';
+ $data = array();
+ foreach ($descriptor->getFields() as $tag=>$field) {
+ $empty = !$message->_has($tag);
+ if ($field->isRequired() && $empty) {
+ throw new \UnexpectedValueException(
+ 'Message ' . get_class($message) . '\'s field tag ' . $tag . '(' . $field->getName() . ') is required but has no value'
+ );
+ }
+
+ if ($empty) {
+ continue;
+ }
+
+ $index .= $this->i2c($tag + 48);
+
+ $value = $message->_get($tag);
+
+ if ($field->isRepeated()) {
+ $repeats = array();
+ foreach ($value as $val) {
+ if ($field->getType() !== Protobuf::TYPE_MESSAGE) {
+ $repeats[] = $val;
+ } else {
+ $repeats[] = $this->encodeMessage($val);
+ }
+ }
+ $data[] = $repeats;
+ } else {
+ if ($field->getType() === Protobuf::TYPE_MESSAGE) {
+ $data[] = $this->encodeMessage($value);
+ } else {
+ $data[] = $value;
+ }
+ }
+ }
+
+ // Insert the index at first element
+ array_unshift($data, $index);
+
+ return $data;
+ }
+
+ protected function decodeMessage(Protobuf\Message $message, $data)
+ {
+ // Get message descriptor
+ $descriptor = Protobuf::getRegistry()->getDescriptor($message);
+
+ // Split the index in UTF8 characters
+ preg_match_all('/./u', $data[0], $chars);
+
+ $chars = $chars[0];
+ for ($i=1; $i<count($data); $i++) {
+
+ $k = $this->c2i($chars[$i-1]) - 48;
+ $v = $data[$i];
+
+ $field = $descriptor->getField($k);
+
+ if (NULL === $field) {
+ // Unknown
+ $unknown = new PhpArray\Unknown($k, gettype($v), $v);
+ $message->addUnknown($unknown);
+ continue;
+ }
+
+ if ($field->getType() === Protobuf::TYPE_MESSAGE) {
+ $nested = $field->getReference();
+ if ($field->isRepeated()) {
+ foreach ($v as $vv) {
+ $obj = $this->decodeMessage(new $nested, $vv);
+ $message->_add($k, $obj);
+ }
+ } else {
+ $obj = $this->decodeMessage(new $nested, $v);
+ $message->_set($k, $obj);
+ }
+ } else {
+ $message->_set($k, $v);
+ }
+ }
+
+ return $message;
+ }
+
+ /**
+ * Converts an Unicode codepoint number to an UTF-8 character
+ *
+ * @param int $codepoint
+ * @return string
+ */
+ protected function i2c($codepoint)
+ {
+ return $codepoint < 128
+ ? chr($codepoint)
+ : html_entity_decode("&#$codepoint;", ENT_NOQUOTES, 'UTF-8');
+ }
+
+ /**
+ * Converts an UTF-8 character to an Unicode codepoint number
+ *
+ * @param string $char
+ * @return int
+ */
+ protected function c2i($char)
+ {
+ $value = ord($char[0]);
+ if ($value < 128) return $value;
+
+ if ($value < 224) {
+ return (($value % 32) * 64) + (ord($char[1]) % 64);
+ } else {
+ return (($value % 16) * 4096) +
+ ((ord($char[1]) % 64) * 64) +
+ (ord($char[2]) % 64);
+ }
+ }
+
+}
+
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/JsonTagMap.php
@@ -1,1 +1,24 @@
+<?php
+namespace DrSlump\Protobuf\Codec;
+
+use DrSlump\Protobuf;
+
+/**
+ * This codec serializes and unserializes from/to Json strings
+ * where the keys represent the field's tag numbers.
+ *
+ * It makes use of the PhpArray codec to do the heavy work to just
+ * take care of converting the array to/from Json strings.
+ */
+class JsonTagMap extends Json
+ implements Protobuf\CodecInterface
+{
+
+ public function __construct()
+ {
+ // Setup the codec to use tag numbers as keys
+ $this->useTagNumberAsKey(true);
+ }
+}
+
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/PhpArray.php
@@ -1,1 +1,147 @@
+<?php
+namespace DrSlump\Protobuf\Codec;
+
+use DrSlump\Protobuf;
+
+/**
+ * This codec serializes and unserializes data from/to PHP associative
+ * arrays, allowing it to be used as a base for an arbitrary number
+ * of different serializations (json, yaml, ini, xml ...).
+ *
+ */
+class PhpArray implements Protobuf\CodecInterface
+{
+ /** @var bool */
+ protected $useTagNumber = false;
+
+ /**
+ * Tells the codec to expect the array keys to contain the
+ * field's tag number instead of the name.
+ *
+ * @param bool $useIt
+ */
+ public function useTagNumberAsKey($useIt = true)
+ {
+ $this->useTagNumber = $useIt;
+ }
+
+ /**
+ * @param \DrSlump\Protobuf\Message $message
+ * @return array
+ */
+ public function encode(Protobuf\Message $message)
+ {
+ return $this->encodeMessage($message);
+ }
+
+ /**
+ * @param \DrSlump\Protobuf\Message $message
+ * @param array $data
+ * @return \DrSlump\Protobuf\Message
+ */
+ public function decode(Protobuf\Message $message, $data)
+ {
+ return $this->decodeMessage($message, $data);
+ }
+
+ protected function encodeMessage(Protobuf\Message $message)
+ {
+ $descriptor = Protobuf::getRegistry()->getDescriptor($message);
+
+ $data = array();
+ foreach ($descriptor->getFields() as $tag=>$field) {
+
+ $empty = !$message->_has($tag);
+ if ($field->isRequired() && $empty) {
+ throw new \UnexpectedValueException(
+ 'Message ' . get_class($message) . '\'s field tag ' . $tag . '(' . $field->getName() . ') is required but has no value'
+ );
+ }
+
+ if ($empty) {
+ continue;
+ }
+
+ $key = $this->useTagNumber ? $field->getNumber() : $field->getName();
+ $v = $message->_get($tag);
+
+ if ($field->isRepeated()) {
+ // Make sure the value is an array of values
+ $v = is_array($v) ? $v : array($v);
+ foreach ($v as $k=>$vv) {
+ $v[$k] = $this->filterValue($vv, $field);
+ }
+ } else {
+ $v = $this->filterValue($v, $field);
+ }
+
+ $data[$key] = $v;
+ }
+
+ return $data;
+ }
+
+ protected function decodeMessage(Protobuf\Message $message, $data)
+ {
+ // Get message descriptor
+ $descriptor = Protobuf::getRegistry()->getDescriptor($message);
+
+ foreach ($data as $key=>$v) {
+
+ // Get the field by tag number or name
+ $field = $this->useTagNumber
+ ? $descriptor->getField($key)
+ : $descriptor->getFieldByName($key);
+
+ // Unknown field found
+ if (!$field) {
+ $unknown = new PhpArray\Unknown($key, gettype($v), $v);
+ $message->addUnknown($unknown);
+ continue;
+ }
+
+ if ($field->isRepeated()) {
+ // Make sure the value is an array of values
+ $v = is_array($v) && is_int(key($v)) ? $v : array($v);
+ foreach ($v as $k=>$vv) {
+ $v[$k] = $this->filterValue($vv, $field);
+ }
+ } else {
+ $v = $this->filterValue($v, $field);
+ }
+
+ $message->_set($field->getNumber(), $v);
+ }
+
+ return $message;
+ }
+
+ protected function filterValue($value, Protobuf\Field $field)
+ {
+ switch ($field->getType()) {
+ case Protobuf::TYPE_MESSAGE:
+ // Tell apart encoding and decoding
+ if ($value instanceof Protobuf\Message) {
+ return $this->encodeMessage($value);
+ } else {
+ $nested = $field->getReference();
+ return $this->decodeMessage(new $nested, $value);
+ }
+ case Protobuf::TYPE_BOOL:
+ return filter_var($value, FILTER_VALIDATE_BOOLEAN);
+ case Protobuf::TYPE_STRING:
+ case Protobuf::TYPE_BYTES:
+ return (string)$value;
+ case Protobuf::TYPE_FLOAT:
+ case Protobuf::TYPE_DOUBLE:
+ return filter_var($value, FILTER_VALIDATE_FLOAT);
+ // Assume the rest are ints
+ default:
+ return filter_var($value, FILTER_VALIDATE_INT);
+ }
+ }
+
+
+}
+
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/PhpArray/Unknown.php
@@ -1,1 +1,14 @@
+<?php
+namespace DrSlump\Protobuf\Codec\PhpArray;
+
+class Unknown extends \DrSlump\Protobuf\Unknown
+{
+ public function __construct($tag, $type, $data)
+ {
+ $this->tag = $tag;
+ $this->type = $type;
+ $this->data = $data;
+ }
+}
+
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/TextFormat.php
@@ -1,1 +1,82 @@
+<?php
+namespace DrSlump\Protobuf\Codec;
+
+use DrSlump\Protobuf;
+
+/**
+ * This codec serializes to Protobuf's TextFormat, unserialization
+ * is not supported.
+ *
+ */
+class TextFormat implements Protobuf\CodecInterface
+{
+ /**
+ * @param \DrSlump\Protobuf\Message $message
+ * @return string
+ */
+ public function encode(Protobuf\Message $message)
+ {
+ return $this->encodeMessage($message);
+ }
+
+ /**
+ *
+ * @throw \DrSlump\Protobuf\Exception - Decoding is not supported
+ * @param \DrSlump\Protobuf\Message $message
+ * @param String $data
+ * @return \DrSlump\Protobuf\Message
+ */
+ public function decode(Protobuf\Message $message, $data)
+ {
+ throw new \BadMethodCallException('TextFormat codec does not support decoding');
+ }
+
+ protected function encodeMessage(Protobuf\Message $message, $level = 0)
+ {
+ $descriptor = Protobuf::getRegistry()->getDescriptor($message);
+
+ $indent = str_repeat(' ', $level);
+ $data = '';
+ foreach ($descriptor->getFields() as $tag=>$field) {
+
+ $empty = !$message->_has($tag);
+ if ($field->isRequired() && $empty) {
+ throw new \UnexpectedValueException(
+ 'Message ' . get_class($message) . '\'s field tag ' . $tag . '(' . $field->getName() . ') is required but has no value'
+ );
+ }
+
+ if ($empty) {
+ continue;
+ }
+
+ $name = $field->getName();
+ $value = $message->_get($tag);
+
+ if ($field->isRepeated()) {
+ foreach ($value as $val) {
+ if ($field->getType() !== Protobuf::TYPE_MESSAGE) {
+ $data .= $indent . $name . ': ' . json_encode($val) . "\n";
+ } else {
+ $data .= $indent . $name . " {\n";
+ $data .= $this->encodeMessage($val, $level+1);
+ $data .= $indent . "}\n";
+ }
+ }
+ } else {
+ if ($field->getType() === Protobuf::TYPE_MESSAGE) {
+ $data .= $indent . $name . " {\n";
+ $data .= $this->encodeMessage($value, $level+1);
+ $data .= $indent . "}\n";
+ } else {
+ $data .= $indent . $name . ': ' . json_encode($value) . "\n";
+ }
+ }
+ }
+
+ return $data;
+ }
+}
+
+
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Codec/Xml.php
@@ -1,1 +1,139 @@
+<?php
+namespace DrSlump\Protobuf\Codec;
+
+use DrSlump\Protobuf;
+
+/**
+ * This codec serializes and unserializes from/to Xml documents
+ * where the elements represent the field's name.
+ *
+ * It makes use of the PhpArray codec to do the heavy work to just
+ * take care of converting the array to/from XML.
+ */
+class Xml extends PhpArray
+ implements Protobuf\CodecInterface
+{
+ /** @var bool */
+ protected $dom = false;
+ /** @var string */
+ protected $root;
+
+ /**
+ * @param array $options
+ */
+ public function __construct(array $options = array())
+ {
+ foreach ($options as $option=>$value) {
+ $this->setOption($option, $value);
+ }
+ }
+
+ /**
+ * @throws \InvalidArgumentException
+ * @param string $option
+ * @param mixed $value
+ * @return void
+ */
+ public function setOption($option, $value)
+ {
+ switch (strtolower($option)) {
+ case 'root':
+ $this->root = $value;
+ break;
+ case 'dom':
+ $this->dom = (bool)$value;
+ break;
+ default:
+ throw new \InvalidArgumentException('Unknown option ' . $option);
+ }
+ }
+
+ /**
+ * @param \DrSlump\Protobuf\Message $message
+ * @return string | \SimpleXMLElement
+ */
+ public function encode(Protobuf\Message $message)
+ {
+ // Generate an associative array
+ $data = $this->encodeMessage($message);
+
+ // Build an XML representation
+ $root = $this->root ?: str_replace('\\', '_', get_class($message));
+ $root = new \SimpleXMLElement('<?xml version="1.0"?><' . $root . '></' . $root . '>');
+ $this->arrayToXml($root, $data);
+
+ return $this->dom ? $root : $root->asXML();
+ }
+
+ /**
+ * @param \SimpleXMLElement $elem
+ * @param array $data
+ * @param null $label
+ */
+ protected function arrayToXml(\SimpleXMLElement $elem, array $data, $label = null)
+ {
+ foreach ($data as $k=>$v) {
+ if (is_array($v)) {
+ // Detect nested messages
+ if (!is_int(key($v))) {
+ $child = $elem->addChild($label ?: $k);
+ $this->arrayToXml($child, $v);
+ // Lists are forced a fixed label
+ } else {
+ $this->arrayToXml($elem, $v, $k);
+ }
+ } else {
+ $elem->addChild($label ?: $k, $v);
+ }
+ }
+ }
+
+ /**
+ * @param \DrSlump\Protobuf\Message $message
+ * @param string | \SimpleXMLElement $xml
+ * @return \DrSlump\Protobuf\Message
+ */
+ public function decode(Protobuf\Message $message, $xml)
+ {
+ if (is_string($xml)) {
+ $xml = new \SimpleXMLElement($xml);
+ }
+
+ // Build an associative array from the XML
+ $data = $this->xmlToArray($xml);
+ // Generate a message from the data
+ return $this->decodeMessage($message, $data);
+ }
+
+ /**
+ * @param \SimpleXMLElement $elem
+ * @return array
+ */
+ protected function xmlToArray(\SimpleXMLElement $elem)
+ {
+ $data = array();
+ foreach ($elem->children() as $child) {
+ if (count($child->children())) {
+ $value = $this->xmlToArray($child);
+ } else {
+ $value = (string)$child;
+ }
+
+ $name = $child->getName();
+ if (isset($data[$name])) {
+ // If not yet a "list" array
+ if (!is_array($data[$name]) || !is_int(key($data[$name]))) {
+ $data[$name] = array($data[$name]);
+ }
+ $data[$name][] = $value;
+ } else {
+ $data[$name] = $value;
+ }
+ }
+
+ return $data;
+ }
+
+}
+
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/CodecInterface.php
@@ -1,1 +1,9 @@
+<?php
+namespace DrSlump\Protobuf;
+
+interface CodecInterface
+{
+ public function encode(\DrSlump\Protobuf\Message $message);
+ public function decode(\DrSlump\Protobuf\Message $message, $data);
+}
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler.php
@@ -1,1 +1,212 @@
-
+<?php
+
+namespace DrSlump\Protobuf;
+
+// Load descriptor messages
+require_once __DIR__ . '/Compiler/protos/descriptor.pb.php';
+require_once __DIR__ . '/Compiler/protos/plugin.pb.php';
+require_once __DIR__ . '/Compiler/protos/php.pb.php';
+require_once __DIR__ . '/Compiler/protos/json.pb.php';
+
+use DrSlump\Protobuf;
+use google\protobuf as proto;
+
+class Compiler
+{
+ /** @var bool */
+ protected $verbose = false;
+ /** @var array */
+ protected $packages = array();
+ /** @var \DrSlump\Protobuf\Compiler\CommentsParser */
+ protected $comments;
+ /** @var bool */
+ protected $skipImported = false;
+ /** @var array */
+ protected $options = array();
+ /** @var array */
+ protected $protos = array();
+
+ public function __construct($verbose = false)
+ {
+ $this->verbose = $verbose;
+ $this->comments = new Compiler\CommentsParser();
+ }
+
+ public function stderr($str)
+ {
+ $str = str_replace("\n", PHP_EOL, $str);
+ fputs(STDERR, $str . PHP_EOL);
+ }
+
+ public function notice($str)
+ {
+ if ($this->verbose) {
+ $this->stderr('NOTICE: ' . $str);
+ }
+ }
+
+ public function warning($str)
+ {
+ $this->stderr('WARNING: ' . $str);
+ }
+
+ protected function error($str)
+ {
+ $this->stderr('ERROR: ' . $str);
+ }
+
+ public function getPackages()
+ {
+ return $this->packages;
+ }
+
+ public function hasPackage($package)
+ {
+ return isset($this->packages[$package]);
+ }
+
+ public function getPackage($package)
+ {
+ return $this->packages[$package];
+ }
+
+ public function setPackage($package, $namespace)
+ {
+ $this->packages[$package] = $namespace;
+ }
+
+ public function getOption($option, $type = 'string')
+ {
+ $value = isset($this->options[$option])
+ ? $this->options[$option]
+ : null;
+
+ switch ($type) {
+ case 'bool':
+ return filter_var($value, FILTER_VALIDATE_BOOLEAN);
+ default:
+ return $value;
+ }
+ }
+
+ public function camelize($name)
+ {
+ return preg_replace_callback(
+ '/_([a-z])/i',
+ function($m){ return strtoupper($m[1]); },
+ $name
+ );
+ }
+
+ public function compile($data)
+ {
+ // Parse the request
+ $req = new \google\protobuf\compiler\CodeGeneratorRequest($data);
+
+ // Set default generator class
+ $generator = __CLASS__ . '\PhpGenerator';
+
+ // Reset comments parser
+ $this->comments->reset();
+ $parseComments = false;
+
+ // Get plugin arguments
+ if ($req->hasParameter()) {
+ parse_str($req->getParameter(), $args);
+ foreach ($args as $arg=>$val) {
+ switch($arg){
+ case 'verbose':
+ $this->verbose = filter_var($val, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
+ break;
+ case 'json':
+ $this->notice("Using ProtoJson generator");
+ $generator = __CLASS__ . '\JsonGenerator';
+ break;
+ case 'comments':
+ $parseComments = filter_var($val, FILTER_VALIDATE_BOOLEAN);
+ break;
+ case 'protos':
+ $this->protos = $val;
+ break;
+ case 'skip-imported':
+ $this->skipImported = filter_var($val, FILTER_VALIDATE_BOOLEAN);
+ break;
+ case 'options':
+ $this->options = $val;
+ break;
+ default:
+ $this->warning('Skipping unknown option ' . $arg);
+ }
+ }
+ }
+
+ // Parse comments if we're told to do so
+ if ($parseComments) {
+ if (empty($this->protos)) {
+ throw new \RuntimeException('Unable to port comments if .proto files are not passed as argument');
+ }
+ foreach ($this->protos as $fname) {
+ $src = file_get_contents($fname);
+ if (FALSE === $src) {
+ throw new \RuntimeException('Unable to parse file ' . $fname . ' for comments');
+ }
+ $this->comments->parse($src);
+ }
+ }
+
+ /** @var $generator \DrSlump\Protobuf\Compiler\AbstractGenerator */
+ $generator = new $generator($this);
+
+ // Setup response object
+ $resp = new \google\protobuf\compiler\CodeGeneratorResponse();
+
+ // First iterate over all the protos to get a map of namespaces
+ $this->packages = array();
+ foreach($req->getProtoFileList() as $proto) {
+ $package = $proto->getPackage();
+ $namespace = $generator->getNamespace($proto);
+ if (isset($this->packages[$package]) && $namespace !== $this->packages[$package]) {
+ $this->warning("Package $package was already mapped to {$this->packages[$package]} but has now been overridden to $namespace");
+ }
+ $this->packages[$package] = $namespace;
+ $this->notice("Mapping $package to $namespace");
+ }
+
+ // Get the list of files to generate
+ $files = $req->getFileToGenerate();
+
+ // Run each file
+ foreach ($req->getProtoFileList() as $file) {
+ // Only compile those given to generate, not the imported ones
+ if ($this->skipImported && !in_array($file->getName(), $files)) {
+ $this->notice('Skipping generation of imported file "' . $file->getName() . '"');
+ continue;
+ }
+
+ $sources = $generator->generate($file);
+ foreach ($sources as $source) {
+ $this->notice('Generating "' . $source->getName() . '"');
+ $resp->addFile($source);
+ }
+ }
+
+ // Finally serialize the response object
+ return $resp->serialize();
+ }
+
+ public function getComment($ident, $prefix = '')
+ {
+ if (!$this->comments->hasComment($ident)) {
+ return null;
+ }
+
+ $comment = $this->comments->getComment($ident);
+ if (0 < strlen($prefix)) {
+ $comment = $prefix . str_replace("\n", "\n$prefix", $comment);
+ }
+
+ return $comment;
+ }
+}
+
+
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/AbstractGenerator.php
@@ -1,1 +1,41 @@
+<?php
+namespace DrSlump\Protobuf\Compiler;
+
+use google\protobuf as proto;
+
+abstract class AbstractGenerator
+{
+ /** @var \DrSlump\Protobuf\Compiler */
+ protected $compiler;
+ /** @var \google\protobuf\FileDescriptorProto */
+ protected $proto;
+
+ /** @var array */
+ protected $extensions = array();
+
+ public function __construct(\DrSlump\Protobuf\Compiler $compiler)
+ {
+ $this->compiler = $compiler;
+ }
+
+ public function getNamespace(proto\FileDescriptorProto $proto = NULL)
+ {
+ return NULL === $proto
+ ? $this->proto->getPackage()
+ : $proto->getPackage();
+ }
+
+ public function generate(proto\FileDescriptorProto $proto)
+ {
+ $this->proto = $proto;
+ }
+
+
+ abstract protected function compileEnum(proto\EnumDescriptorProto $enum, $namespace);
+
+ abstract protected function compileMessage(proto\DescriptorProto $msg, $namespace);
+
+ abstract protected function compileExtension(proto\FieldDescriptorProto $field, $ns, $indent);
+}
+
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/Cli.php
@@ -1,1 +1,238 @@
-
+<?php
+
+namespace DrSlump\Protobuf\Compiler;
+
+require_once 'Console/CommandLine.php';
+
+use DrSlump\Protobuf;
+
+class Cli
+{
+ public static function run($pluginExecutable)
+ {
+ // Open STDIN in non-blocking mode
+ $fp = fopen('php://stdin', 'rb');
+ stream_set_blocking($fp, FALSE);
+
+ // Loop until STDIN is closed or we've waited too long for data
+ $cnt = 0;
+ $stdin = '';
+ while (!feof($fp) && $cnt++ < 10) {
+ // give protoc some time to feed the data
+ usleep(10000);
+ // read the bytes
+ $bytes = fread($fp, 1024);
+ if (strlen($bytes)) {
+ $cnt = 0;
+ $stdin .= $bytes;
+ }
+ }
+
+ // If no input was given we launch protoc from here
+ if (0 === strlen($stdin)) {
+ self::runProtoc($pluginExecutable);
+ exit(0);
+ }
+
+ // We have data from stdin so compile it
+ try {
+ // Create a compiler interface
+ $comp = new Protobuf\Compiler();
+ echo $comp->compile($stdin);
+ exit(0);
+ } catch(\Exception $e) {
+ fputs(STDERR, 'ERROR: ' . $e->getMessage());
+ fputs(STDERR, $e->getTraceAsString());
+ exit(255);
+ }
+ }
+
+ public static function runProtoc($pluginExecutable)
+ {
+ $result = self::parseArguments();
+
+ $protocBin = $result->options['protoc'];
+
+ // Check if protoc is available
+ exec("$protocBin --version", $output, $return);
+
+ if (0 !== $return && 1 !== $return) {
+ fputs(STDERR, "ERROR: Unable to find the protoc command.". PHP_EOL);
+ fputs(STDERR, " Please make sure it's installed and available in the path." . PHP_EOL);
+ exit(1);
+ }
+
+ if (!preg_match('/[0-9\.]+/', $output[0], $m)) {
+ fputs(STDERR, "ERROR: Unable to get protoc command version.". PHP_EOL);
+ fputs(STDERR, " Please make sure it's installed and available in the path." . PHP_EOL);
+ exit(1);
+ }
+
+ if (version_compare($m[0], '2.3.0') < 0) {
+ fputs(STDERR, "ERROR: The protoc command in your system is too old." . PHP_EOL);
+ fputs(STDERR, " Minimum version required is 2.3.0 but found {$m[0]}." . PHP_EOL);
+ exit(1);
+ }
+
+ $cmd[] = $protocBin;
+ $cmd[] = '--plugin=protoc-gen-php=' . escapeshellarg($pluginExecutable);
+
+ // Include paths
+ $cmd[] = '--proto_path=' . escapeshellarg(__DIR__ . DIRECTORY_SEPARATOR . 'protos');
+ if (!empty($result->options['include'])) {
+ foreach($result->options['include'] as $include) {
+ $include = realpath($include);
+ $cmd[] = '--proto_path=' . escapeshellarg($include);
+ }
+ }
+
+ // Convert proto files to absolute paths
+ $protos = array();
+ foreach ($result->args['protos'] as $proto) {
+ $realpath = realpath($proto);
+ if (FALSE === $realpath) {
+ fputs(STDERR, "ERROR: File '$proto' does not exists");
+ exit(1);
+ }
+
+ $protos[] = $realpath;
+ }
+
+ // Protoc will pass custom arguments to the plugin if they are given
+ // before a colon character. ie: --php_out="foo=bar:/path/to/plugin"
+ // We make use of it to pass arguments encoded as an URI query string
+
+ $args = array();
+ if ($result->options['comments']) {
+ $args['comments'] = 1;
+ // Protos are only needed for comments right now
+ $args['protos'] = $protos;
+ }
+ if ($result->options['verbose']) {
+ $args['verbose'] = 1;
+ }
+ if ($result->options['json']) {
+ $args['json'] = 1;
+ }
+ if ($result->options['skipImported']) {
+ $args['skip-imported'] = 1;
+ }
+ if ($result->options['define']) {
+ $args['options'] = array();
+ foreach($result->options['define'] as $define) {
+ $parts = explode('=', $define);
+ $parts = array_filter(array_map('trim', $parts));
+ if (count($parts) === 1) {
+ $parts[1] = 1;
+ }
+ $args['options'][$parts[0]] = $parts[1];
+ }
+ }
+
+ $cmd[] = '--php_out=' .
+ escapeshellarg(
+ http_build_query($args, '', '&') .
+ ':' .
+ $result->options['out']
+ );
+
+ // Add the chosen proto files to generate
+ foreach ($protos as $proto) {
+ $cmd[] = escapeshellarg($proto);
+ }
+
+ $cmdStr = implode(' ', $cmd);
+
+ // Run command with stderr redirected to stdout
+ passthru($cmdStr . ' 2>&1', $return);
+
+ if ($return !== 0) {
+ fputs(STDERR, PHP_EOL);
+ fputs(STDERR, 'ERROR: protoc exited with an error (' . $return . ') when executed with: ' . PHP_EOL);
+ fputs(STDERR, ' ' . implode(" \\\n ", $cmd) . PHP_EOL);
+ exit($return);
+ }
+ }
+
+
+ public static function parseArguments()
+ {
+ $main = new \Console_CommandLine();
+
+ $main->addOption('out', array(
+ 'short_name' => '-o',
+ 'long_name' => '--out',
+ 'action' => 'StoreString',
+ 'description' => 'destination directory for generated files',
+ 'default' => './',
+ ));
+
+ $main->addOption('include', array(
+ 'short_name' => '-i',
+ 'long_name' => '--include',
+ 'action' => 'StoreArray',
+ 'description' => 'define an include path (can be repeated)',
+ 'multiple' => true,
+ ));
+
+
+ $main->addOption('json', array(
+ 'short_name' => '-j',
+ 'long_name' => '--json',
+ 'action' => 'StoreTrue',
+ 'description' => 'turn on ProtoJson Javascript file generation',
+ ));
+
+ $main->addOption('protoc', array(
+ 'long_name' => '--protoc',
+ 'action' => 'StoreString',
+ 'default' => 'protoc',
+ 'description' => 'protoc compiler executable path',
+ ));
+
+ $main->addOption('skipImported', array(
+ 'long_name' => '--skip-imported',
+ 'action' => 'StoreTrue',
+ 'default' => false,
+ 'description' => 'do not generate imported proto files',
+ ));
+
+ $main->addOption('comments', array(
+ 'long_name' => '--comments',
+ 'action' => 'StoreTrue',
+ 'description' => 'port .proto comments to generated code',
+ ));
+
+ $main->addOption('define', array(
+ 'short_name' => '-D',
+ 'long_name' => '--define',
+ 'action' => 'StoreArray',
+ 'multiple' => true,
+ 'description' => 'define a generator option (ie: -Dmultifile -Dsuffix=pb.php)',
+ ));
+
+ $main->addOption('verbose', array(
+ 'short_name' => '-v',
+ 'long_name' => '--verbose',
+ 'action' => 'StoreTrue',
+ 'description' => 'turn on verbose output',
+ ));
+
+
+ $main->addArgument('protos', array(
+ 'multiple' => true,
+ 'description' => 'proto files',
+ ));
+
+ try {
+ echo 'Protobuf-PHP ' . Protobuf::VERSION . ' by Ivan -DrSlump- Montes' . PHP_EOL . PHP_EOL;
+ $result = $main->parse();
+ return $result;
+ } catch (\Exception $e) {
+ $main->displayError($e->getMessage());
+ exit(1);
+ }
+ }
+
+}
+
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/CommentsParser.php
@@ -1,1 +1,136 @@
+<?php
+namespace DrSlump\Protobuf\Compiler;
+
+class CommentsParser
+{
+ /** @var array - Hold a mapping of entity => comment */
+ protected $comments = array();
+
+ /** @var array - Define tokenizer regular expressions */
+ protected $tokens = array(
+ 'comment' => '/\*([\S\s]+?)\*/',
+ 'package' => 'package\s+([A-Z0-9_]+)',
+ 'struct' => '(?:message|enum|service)\s+([A-Z0-9_]+)',
+ 'close' => '}',
+ 'field' => '(?:required|optional|repeated)\s+[^=]+=\s*([0-9]+)[^;]*;',
+ 'rpc' => 'rpc\s+([A-Z0-9_]+)[^;]+'
+ );
+
+ /** @var string - The regular expresion for the tokenizer */
+ protected $regexp;
+
+ public function __construct()
+ {
+ // Generate a regular expression for all tokens
+ $regexp = array();
+ foreach ($this->tokens as $token=>$exp) {
+ $regexp[] = '(?<' . $token . '>' . $exp . ')';
+ }
+ $this->regexp = '@' . implode('|', $regexp) . '@i';
+ }
+
+ /**
+ * Reset the currently stored comments
+ */
+ public function reset()
+ {
+ $this->comments = array();
+ }
+
+ /**
+ * Parse a Proto file source code to fetch comments
+ *
+ * @param string $src
+ */
+ public function parse($src)
+ {
+ // Build an stream of tokens from the regular expression
+ $tokens = array();
+ $offset = 0;
+ while (preg_match($this->regexp, $src, $m, PREG_OFFSET_CAPTURE, $offset)) {
+ foreach ($this->tokens as $k=>$v) {
+ if (!empty($m[$k]) && 0 < strlen($m[$k][0])) {
+ $tokens[] = array(
+ 'token' => $k,
+ 'value' => array_shift(array_pop($m)),
+ );
+ }
+ }
+ $offset = $m[0][1] + strlen($m[0][0]);
+ }
+
+ // Parse the tokens stream to assign comments
+ $comment = null;
+ $stack = array();
+ foreach ($tokens as $token) {
+ if ($token['token'] === 'comment') {
+ $comment = $token['value'];
+ } elseif ($token['token'] === 'package') {
+ $stack[] = $token['value'];
+ $comment = null;
+ } elseif ($token['token'] === 'struct') {
+ $stack[] = $token['value'];
+ if ($comment) {
+ $this->setComment(implode('.', $stack), $comment);
+ $comment = null;
+ }
+ } elseif ($token['token'] === 'close') {
+ array_pop($stack);
+ $comment = null;
+ } elseif ($token['token'] === 'field' || $token['token'] === 'rpc') {
+ if ($comment) {
+ $this->setComment(implode('.', $stack) . '.' . $token['value'], $comment);
+ $comment = null;
+ }
+ }
+ }
+ }
+
+ /**
+ * Set a comment for the given identifier. The identifier is composed
+ * of the package, followed by the message (and nested messages). Field
+ * comments are suffixed with the tag number.
+ *
+ * @example
+ *
+ * $this->setComment('MyPackage.MyMessage.Nested.2', 'field comment');
+ *
+ * @param string $ident
+ * @param string $comment
+ */
+ public function setComment($ident, $comment)
+ {
+ $comment = str_replace("\r\n", "\n", $comment);
+ $comment = preg_replace('/^[\s\*]+/m', '', $comment);
+ $comment = trim($comment, "* \n");
+ $this->comments[$ident] = $comment;
+ }
+
+ /**
+ * Get the comment for a given identifier
+ *
+ * @param string $ident
+ * @return string|null
+ */
+ public function getComment($ident)
+ {
+ return isset($this->comments[$ident])
+ ? $this->comments[$ident]
+ : null;
+ }
+
+ /**
+ * Checks if a comment exists for a given identifier
+ *
+ * @param string $ident
+ * @return bool
+ */
+ public function hasComment($ident)
+ {
+ return isset($this->comments[$ident]);
+ }
+}
+
+
+
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/JsonGenerator.php
@@ -1,1 +1,353 @@
-
+<?php
+
+namespace DrSlump\Protobuf\Compiler;
+
+use DrSlump\Protobuf;
+use google\protobuf as proto;
+
+class JsonGenerator extends AbstractGenerator
+{
+ public function getNamespace(proto\FileDescriptorProto $proto)
+ {
+ $namespace = $proto->getPackage();
+ $opts = $proto->getOptions();
+ if (isset($opts['json.package'])) {
+ $namespace = $opts['jsonpackage'];
+ }
+ if (isset($opts['json.namespace'])) {
+ $namespace = $opts['json.namespace'];
+ }
+
+ $namespace = trim($namespace, '.');
+ return $namespace;
+ }
+
+ public function compileEnum(proto\EnumDescriptorProto $enum, $namespace)
+ {
+ $s[]= "$namespace.$enum->name = {";
+ $lines = array();
+ foreach ($enum->getValueList() as $value) {
+ $lines[] = " /** @const */ $value->name: $value->number";
+ }
+ $s[]= implode(",\n", $lines);
+ $s[]= '};';
+ $s[]= '';
+ return implode("\n", $s);
+ }
+
+ public function compileExtension(proto\FieldDescriptorProto $field, $ns, $indent)
+ {
+ $extendee = $this->normalizeReference($field->getExtendee());
+ $name = $field->getName();
+ if ($ns) {
+ $name = $ns . '.' . $name;
+ }
+ $field->setName($name);
+
+ $s[]= "ProtoJson.extend($extendee, {";
+ $s[]= " $field->number: " . $this->generateField($field);
+ $s[]= "});";
+ $s[]= '';
+
+ return $indent . implode("\n$indent", $s);
+ }
+
+ public function compileMessage(proto\DescriptorProto $msg, $namespace)
+ {
+ $s[]= "/**";
+ $s[]= " * @constructor";
+ $s[]= " * @augments {ProtoJson.Message}";
+ $s[]= " * @extends ProtoJson.Message";
+ $s[]= " * @memberOf $namespace";
+ $s[]= " * @param {object} data - Optional, provide initial data to parse";
+ $s[]= " */";
+ $s[]= "$namespace.$msg->name = ProtoJson.create({";
+ $s[]= " fields: {";
+
+ $lines = array();
+ foreach ($msg->getFieldList() as $field) {
+ $lines[] = " $field->number: " . $this->generateField($field);
+ }
+ $s[] = implode(",\n", $lines);
+
+ $s[]= " },";
+ $s[]= " ranges: [";
+ // @todo dump extension ranges
+ $s[]= " ]";
+ $s[]= "});";
+ $s[]= "";
+
+ // Compute a new namespace with the message name as suffix
+ $namespace .= "." . $msg->getName();
+
+ // Generate getters/setters
+ foreach ($msg->getFieldList() as $field) {
+ $s[]= $this->generateAccessors($field, $namespace);
+ }
+
+ // Generate Enums
+ foreach ($msg->getEnumTypeList() as $enum):
+ $s[]= $this->compileEnum($enum, $namespace);
+ endforeach;
+
+ // Generate nested messages
+ foreach ($msg->getNestedTypeList() as $msg):
+ $s[]= $this->compileMessage($msg, $namespace);
+ endforeach;
+
+ // Collect extensions
+ foreach ($msg->getExtensionList() as $field) {
+ $this->extensions[$field->getExtendee()][] = array($namespace, $field);
+ }
+
+ return implode("\n", $s);
+ }
+
+ public function compileProtoFile(proto\FileDescriptorProto $proto)
+ {
+ $file = new proto\compiler\CodeGeneratorResponse\File();
+
+ $opts = $proto->getOptions();
+ $name = pathinfo($proto->getName(), PATHINFO_FILENAME);
+ $name .= isset($opts['json.suffix'])
+ ? $opts['json.suffix']
+ : '.js';
+ $file->setName($name);
+
+ $namespace = $this->getNamespace($proto);
+
+ $s[]= "// DO NOT EDIT! Generated by Protobuf for PHP protoc plugin " . Protobuf::VERSION;
+ $s[]= "// Source: " . $proto->getName();
+ $s[]= "// Date: " . date('Y-m-d H:i:s');
+ $s[]= "";
+
+ $s[]= "(function(){";
+ $s[]= "/** @namespace */";
+ $s[]= "var $namespace = $namespace || {};";
+ $s[]= "";
+ $s[]= "// Make it CommonJS compatible";
+ $s[]= "if (typeof exports !== 'undefined') {";
+ $s[]= " var ProtoJson = this.ProtoJson;";
+ $s[]= " if (!ProtoJson && typeof require !== 'undefined')";
+ $s[]= " ProtoJson = require('ProtoJson');";
+ $s[]= " $namespace = exports;";
+ $s[]= "} else {";
+ $s[]= " this.$namespace = $namespace;";
+ $s[]= "}";
+ $s[]= "";
+
+
+ // Generate Enums
+ foreach ($proto->getEnumTypeList() as $enum) {
+ $s[]= $this->compileEnum($enum, $namespace);
+ }
+
+ // Generate Messages
+ foreach ($proto->getMessageTypeList() as $msg) {
+ $s[] = $this->compileMessage($msg, $namespace);
+ }
+
+ // Collect extensions
+ if ($proto->hasExtension()) {
+ foreach ($proto->getExtensionList() as $field) {
+ $this->extensions[$field->getExtendee()][] = array($namespace, $field);
+ }
+ }
+
+ // Dump all extensions found in this proto file
+ if (count($this->extensions)) {
+ foreach ($this->extensions as $extendee => $fields) {
+ foreach ($fields as $pair) {
+ list($ns, $field) = $pair;
+ $s[]= $this->compileExtension($field, $ns, '');
+ }
+ }
+ }
+
+ $s[]= "})();";
+
+ $src = implode("\n", $s);
+ $file->setContent($src);
+ return array($file);
+ }
+
+ public function generateField(proto\FieldDescriptorProto $field)
+ {
+ $reference = 'null';
+ if ($field->hasTypeName()) {
+ $reference = $field->getTypeName();
+ if (substr($reference, 0, 1) !== '.') {
+ throw new \RuntimeException('Only fully qualified names are supported: ' . $reference);
+ }
+ $reference = "'" . $this->normalizeReference($reference) . "'";
+ }
+
+ $default = 'null';
+ if ($field->hasDefaultValue()):
+ switch ($field->getType()) {
+ case Protobuf::TYPE_BOOL:
+ $default = $field->getDefaultValue() ? 'true' : 'false';
+ break;
+ case Protobuf::TYPE_STRING:
+ $default = '"' . addcslashes($field->getDefaultValue(), '"\\') . '"';
+ break;
+ case Protobuf::TYPE_ENUM:
+ $default = $this->normalizeReference($field->getTypeName()) . '.' . $field->getDefaultValue();
+ break;
+ default: // Numbers
+ $default = $field->getDefaultValue();
+ }
+ endif;
+
+ $data = array(
+ "'" . $field->getName() . "'",
+ $field->getLabel(),
+ $field->getType(),
+ $reference,
+ $default,
+ '{}'
+ );
+
+ return '[' . implode(', ', $data) . ']';
+ }
+
+ public function generateAccessors($field, $namespace)
+ {
+ $camel = $this->comp->camelize(ucfirst($field->getName()));
+
+ $s[]= "/**";
+ $s[]= " * Check <$field->name> value";
+ $s[]= " * @return {Boolean}";
+ $s[]= " */";
+ $s[]= "$namespace.prototype.has$camel = function(){";
+ $s[]= " return this._has($field->number);";
+ $s[]= "};";
+ $s[]= "";
+
+ $s[]= "/**";
+ $s[]= " * Set a value for <$field->name>";
+ $s[]= " * @param {" . $this->getJsDoc($field) . "} value";
+ $s[]= " * @return {". $namespace . "}";
+ $s[]= " */";
+ $s[]= "$namespace.prototype.set$camel = function(value){";
+ $s[]= " return this._set($field->number, value);";
+ $s[]= "};";
+ $s[]= "";
+
+
+ $s[]= "/**";
+ $s[]= " * Clear the value of <$field->name>";
+ $s[]= " * @return {". $namespace . "}";
+ $s[]= " */";
+ $s[]= "$namespace.prototype.clear$camel = function(){";
+ $s[]= " return this._clear($field->number);";
+ $s[]= "};";
+ $s[]= "";
+
+
+ if ($field->getLabel() !== Protobuf::RULE_REPEATED):
+
+ $s[]= "/**";
+ $s[]= " * Get <$field->name> value";
+ $s[]= " * @return {" . $this->getJsDoc($field) . "}";
+ $s[]= " */";
+ $s[]= "$namespace.prototype.get$camel = function(){";
+ $s[]= " return this._get($field->number);";
+ $s[]= "};";
+ $s[]= "";
+
+ else:
+
+ $s[]= "/**";
+ $s[]= " * Get an item from <$field->name>";
+ $s[]= " * @param {int} idx";
+ $s[]= " * @return {" . $this->getJsDoc($field) . "}";
+ $s[]= " */";
+ $s[]= "$namespace.prototype.get$camel = function(idx){";
+ $s[]= " return this._get($field->number, idx);";
+ $s[]= "};";
+ $s[]= "";
+
+
+ $s[]= "/**";
+ $s[]= " * Get <$field->name> value";
+ $s[]= " * @return {" . $this->getJsDoc($field) . "[]}";
+ $s[]= " */";
+ $s[]= "$namespace.prototype.get{$camel}List = function(){";
+ $s[]= " return this._get($field->number);";
+ $s[]= "};";
+ $s[]= "";
+
+ $s[]= "/**";
+ $s[]= " * Add a value to <$field->name>";
+ $s[]= " * @param {" . $this->getJsDoc($field) . "} value";
+ $s[]= " * @return {" . $namespace . "}";
+ $s[]= " */";
+ $s[]= "$namespace.prototype.add$camel = function(value){";
+ $s[]= " return this._add($field->number, value);";
+ $s[]= "};";
+ $s[]= "";
+
+ endif;
+
+
+ return implode("\n", $s);
+ }
+
+ public function getJsDoc(proto\FieldDescriptorProto $field)
+ {
+ switch ($field->getType()) {
+ case Protobuf::TYPE_DOUBLE:
+ case Protobuf::TYPE_FLOAT:
+ return 'Float';
+ case Protobuf::TYPE_INT64:
+ case Protobuf::TYPE_UINT64:
+ case Protobuf::TYPE_INT32:
+ case Protobuf::TYPE_FIXED64:
+ case Protobuf::TYPE_FIXED32:
+ case Protobuf::TYPE_UINT32:
+ case Protobuf::TYPE_SFIXED32:
+ case Protobuf::TYPE_SFIXED64:
+ case Protobuf::TYPE_SINT32:
+ case Protobuf::TYPE_SINT64:
+ return 'Int';
+ case Protobuf::TYPE_BOOL:
+ return 'Boolean';
+ case Protobuf::TYPE_STRING:
+ return 'String';
+ case Protobuf::TYPE_MESSAGE:
+ return $this->normalizeReference($field->getTypeName());
+ case Protobuf::TYPE_BYTES:
+ return 'String';
+ case Protobuf::TYPE_ENUM:
+ return 'Int (' . $this->normalizeReference($field->getTypeName()) . ')';
+
+ case Protobuf::TYPE_GROUP:
+ default:
+ return 'unknown';
+ }
+ }
+
+ public function normalizeReference($reference)
+ {
+ // Remove leading dot
+ $reference = ltrim($reference, '.');
+
+ if (!$this->comp->hasPackage($reference)) {
+ $found = false;
+ foreach ($this->comp->getPackages() as $package=>$namespace) {
+ if (0 === strpos($reference, $package.'.')) {
+ $reference = $namespace . substr($reference, strlen($package));
+ $found = true;
+ }
+ }
+ if (!$found) {
+ $this->comp->warning('Non tracked package name found "' . $reference . '"');
+ }
+ } else {
+ $reference = $this->comp->getPackage($reference);
+ }
+
+ return $reference;
+ }
+}
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/PhpGenerator.php
@@ -1,1 +1,610 @@
-
+<?php
+
+namespace DrSlump\Protobuf\Compiler;
+
+use DrSlump\Protobuf;
+use google\protobuf as proto;
+
+class PhpGenerator extends AbstractGenerator
+{
+ protected $components = array();
+
+ protected function addComponent($ns, $name, $src)
+ {
+ if (NULL !== $ns) {
+ $name = $this->normalizeNS($ns . '.' . $name);
+ }
+ $this->components[$name] = $src;
+ }
+
+ /**
+ * Get an option from the compiler arguments or from the proto file.
+ *
+ * @param string $name
+ * @return string|null
+ */
+ protected function getOption($name)
+ {
+ $opt = $this->compiler->getOption($name);
+
+ if (NULL === $opt) {
+ $opts = $this->proto->getOptions();
+ if (!empty($opts) && isset($opts['php.' . $name])) {
+ $opt = $opts['php.' . $name];
+ }
+ }
+
+ return $opt;
+ }
+
+ public function getNamespace(proto\FileDescriptorProto $proto = NULL)
+ {
+ $proto = $proto ?: $this->proto;
+
+ $opts = $proto->getOptions();
+ if ($this->compiler->getOption('namespace')) {
+ $namespace = $this->compiler->getOption('namespace');
+ } else if ($this->compiler->getOption('package')) {
+ $namespace = $this->compiler->getOption('package');
+ } else if (isset($opts['php.namespace'])) {
+ $namespace = $opts['php.namespace'];
+ } else {
+ $namespace = parent::getNamespace($proto);
+ }
+
+ $namespace = trim($namespace, '.\\');
+ return str_replace('.', '\\', $namespace);
+ }
+
+ public function generate(proto\FileDescriptorProto $proto)
+ {
+ parent::generate($proto);
+
+ $this->components = array();
+ $namespace = $proto->getPackage();
+
+ // Generate Enums
+ foreach ($proto->getEnumType() as $enum) {
+ $src = $this->compileEnum($enum, $namespace);
+ $this->addComponent($namespace, $enum->getName(), $src);
+ }
+
+ // Generate Messages
+ foreach ($proto->getMessageType() as $msg) {
+ $src = $this->compileMessage($msg, $namespace);
+ $this->addComponent($namespace, $msg->getName(), $src);
+ }
+
+ // Generate services
+ if ($this->getOption('generic_services') && count($proto->hasService())):
+ foreach ($proto->getServiceList() as $service) {
+ $src = $this->compileService($service, $namespace);
+ $this->addComponent($namespace, $service->getName(), $src);
+ }
+ endif;
+
+ // Collect extensions
+ if ($proto->hasExtension()) {
+ foreach ($proto->getExtensionList() as $field) {
+ $this->extensions[$field->getExtendee()][] = array($namespace, $field);
+ }
+ }
+
+ // Dump all extensions found in this proto file
+ if (count($this->extensions)):
+ $s[]= 'namespace {';
+ foreach ($this->extensions as $extendee => $fields) {
+ foreach ($fields as $pair) {
+ list($ns, $field) = $pair;
+ $s[] = $this->compileExtension($field, $ns, ' ');
+ }
+ }
+ $s[]= '}';
+
+ $src = implode(PHP_EOL, $s);
+
+ // In multifile mode we output all the extensions in a file named after
+ // the proto file, since it's not trivial or even possible in all cases
+ // to include the extensions with the extended message file.
+ $fname = pathinfo($proto->getName(), PATHINFO_FILENAME);
+ $this->addComponent(null, $fname . '-extensions', $src);
+
+ // Reset extensions for next proto file
+ $this->extensions = array();
+ endif;
+
+
+ $files = array();
+ if (!$this->getOption('multifile')) {
+ $src = '';
+ foreach ($this->components as $content) {
+ $src .= $content;
+ }
+ $fname = pathinfo($proto->getName(), PATHINFO_FILENAME);
+ $files[] = $this->buildFile($proto, $fname, $src);
+ } else {
+ foreach ($this->components as $ns => $content) {
+ $fname = str_replace('\\', '/', $ns);
+ $files[] = $this->buildFile($proto, $fname, $content);
+ }
+ }
+
+ return $files;
+ }
+
+ protected function buildFile(proto\FileDescriptorProto $proto, $fname, $contents)
+ {
+ $suffix = $this->getOption('suffix') ?: '.php';
+ $fname .= $suffix;
+
+ $file = new \google\protobuf\compiler\CodeGeneratorResponse\File();
+ $file->setName($fname);
+
+ $s = array();
+ $s[]= "<?php";
+ $s[]= "// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin " . Protobuf::VERSION;
+ $s[]= "// Source: " . $proto->getName();
+ $s[]= "// Date: " . date('Y-m-d H:i:s');
+ $s[]= "";
+ $s[]= "// @@protoc_insertion_point(scope_file)";
+ $s[]= "";
+
+ $contents = implode(PHP_EOL, $s) . PHP_EOL . $contents;
+ $file->setContent($contents);
+ return $file;
+ }
+
+ protected function compileEnum(proto\EnumDescriptorProto $enum, $ns)
+ {
+ $s = array();
+
+ $s[]= "namespace " . $this->normalizeNS($ns) . " {";
+ $s[]= "";
+ $s[]= " // @@protoc_insertion_point(scope_namespace)";
+ $s[]= " // @@protoc_insertion_point(namespace_$ns)";
+ $s[]= "";
+
+ $cmt = $this->compiler->getComment($ns . '.' . $enum->getName(), ' * ');
+ if ($cmt):
+ $s[]= " /**";
+ $s[]= $cmt;
+ $s[]= " */";
+ endif;
+
+ $s[]= " class " . $enum->getName() . " {";
+ foreach ($enum->getValueList() as $value):
+ $s[]= " const " . $value->getName() . " = " . $value->getNumber() . ";";
+ endforeach;
+ $s[]= "";
+ $s[]= " // @@protoc_insertion_point(scope_class)";
+ $s[]= ' // @@protoc_insertion_point(class_' . $ns . '.' . $enum->getName() . ')';
+ $s[]= " }";
+ $s[]= "}";
+ $s[]= "";
+
+ return implode(PHP_EOL, $s);
+ }
+
+ protected function compileMessage(proto\DescriptorProto $msg, $ns)
+ {
+ $s = array();
+ $s[]= "namespace " . $this->normalizeNS($ns) . " {";
+ $s[]= "";
+ $s[]= " // @@protoc_insertion_point(scope_namespace)";
+ $s[]= " // @@protoc_insertion_point(namespace_$ns)";
+ $s[]= "";
+
+ $cmt = $this->compiler->getComment($ns . '.' . $msg->getName(), ' * ');
+ if ($cmt):
+ $s[]= " /**";
+ $s[]= $cmt;
+ $s[]= " */";
+ endif;
+
+ // Compute a new namespace with the message name as suffix
+ $ns .= '.' . $msg->getName();
+
+ $s[]= ' class ' . $msg->getName() . ' extends \DrSlump\Protobuf\Message {';
+ $s[]= "";
+ $s[]= ' /** @var \Closure[] */';
+ $s[]= ' protected static $__extensions = array();';
+ $s[]= '';
+ $s[]= ' public static function descriptor()';
+ $s[]= ' {';
+ $s[]= ' $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, \'' . $ns . '\');';
+ $s[]= '';
+ foreach ($msg->getField() as $field):
+ $s[]= $this->compileField($field, $ns, " ");
+ $s[]= ' $descriptor->addField($f);';
+ $s[]= '';
+ endforeach;
+ $s[]= ' foreach (self::$__extensions as $cb) {';
+ $s[]= ' $descriptor->addField($cb(), true);';
+ $s[]= ' }';
+ $s[]= '';
+ $s[]= ' // @@protoc_insertion_point(scope_descriptor)';
+ $s[]= ' // @@protoc_insertion_point(descriptor_' . $ns . ')';
+ $s[]= '';
+ $s[]= ' return $descriptor;';
+ $s[]= ' }';
+ $s[]= '';
+
+ //$s[]= " protected static \$__exts = array(";
+ //foreach ($msg->getExtensionRange() as $range):
+ //$s[]= ' array(' . $range->getStart() . ', ' . ($range->getEnd()-1) . '),';
+ //endforeach;
+ //$s[]= " );";
+ //$s[]= "";
+
+ foreach ($msg->getField() as $field):
+ $s[]= $this->generatePublicField($field, $ns, " ");
+ endforeach;
+ $s[]= "";
+
+ foreach ($msg->getField() as $field):
+ $s[]= $this->generateAccessors($field, $ns, " ");
+ endforeach;
+
+ $s[]= "";
+ $s[]= " // @@protoc_insertion_point(scope_class)";
+ $s[]= ' // @@protoc_insertion_point(class_' . $ns . ')';
+ $s[]= " }";
+ $s[]= "}";
+ $s[]= "";
+
+ // Generate Enums
+ if ($msg->hasEnumType()):
+ foreach ($msg->getEnumType() as $enum):
+ $src = $this->compileEnum($enum, $ns);
+ $this->addComponent($ns, $enum->getName(), $src);
+ endforeach;
+ endif;
+
+ // Generate nested messages
+ if ($msg->hasNestedType()):
+ foreach ($msg->getNestedType() as $msg):
+ $src = $this->compileMessage($msg, $ns);
+ $this->addComponent($ns, $msg->getName(), $src);
+ endforeach;
+ endif;
+
+ // Collect extensions
+ if ($msg->hasExtension()) {
+ foreach ($msg->getExtensionList() as $field) {
+ $this->_extensions[$field->getExtendee()][] = array($ns, $field);
+ }
+ }
+
+ return implode(PHP_EOL, $s) . PHP_EOL;
+ }
+
+
+ protected function compileField(proto\FieldDescriptorProto $field, $ns, $indent)
+ {
+ switch ($field->getLabel()) {
+ case Protobuf::RULE_REQUIRED:
+ $rule = 'required';
+ break;
+ case Protobuf::RULE_OPTIONAL:
+ $rule = 'optional';
+ break;
+ case Protobuf::RULE_REPEATED:
+ $rule = 'repeated';
+ break;
+ }
+
+ $s[]= "// $rule " . $field->getTypeName() . " " . $field->getName() . " = " . $field->getNumber();
+ $s[]= '$f = new \DrSlump\Protobuf\Field();';
+ $s[]= '$f->number = ' . $field->getNumber() . ';';
+ $s[]= '$f->name = "'. $field->getName() . '";';
+ $s[]= '$f->type = ' . $field->getType() . ';';
+ $s[]= '$f->rule = ' . $field->getLabel() . ';';
+
+ if ($field->hasTypeName()):
+ $ref = $field->getTypeName();
+ if (substr($ref, 0, 1) !== '.') {
+ throw new \RuntimeException("Only fully qualified names are supported but found '$ref' at $ns");
+ }
+ $s[]= '$f->reference = \'\\' . $this->normalizeNS($ref) . "';";
+ endif;
+
+ if ($field->hasDefaultValue()):
+ switch ($field->getType()) {
+ case Protobuf::TYPE_BOOL:
+ $bool = filter_var($field->getDefaultValue(), FILTER_VALIDATE_BOOLEAN);
+ $s[]= '$f->default = ' . ($bool ? 'true' : 'false') . ';';
+ break;
+ case Protobuf::TYPE_STRING:
+ $s[]= '$f->default = "' . addcslashes($field->getDefaultValue(), '"\\') . '";';
+ break;
+ case Protobuf::TYPE_ENUM:
+ $value = '\\' . $this->normalizeNS($field->getTypeName()) . '::' . $field->getDefaultValue();
+ $s[]= '$f->default = ' . $value . ';';
+ break;
+ default: // Numbers
+ $s[]= '$f->default = ' . $field->getDefaultValue() . ';';
+ }
+ endif;
+
+ $s[]= '// @@protoc_insertion_point(scope_field)';
+ $s[]= '// @@protoc_insertion_point(field_' . $ns . ':' . $field->getName() . ')';
+
+ return $indent . implode(PHP_EOL.$indent, $s);
+ }
+
+ protected function compileExtension(proto\FieldDescriptorProto $field, $ns, $indent)
+ {
+ $extendee = $this->normalizeNS($field->getExtendee());
+ $name = $this->normalizeNS($ns . '.' . $field->getName());
+ $field->setName($name);
+
+ $s[]= "\\$extendee::extension(function(){";
+ $s[]= $this->compileField($field, $ns, $indent.' ');
+ $s[]= ' // @@protoc_insertion_point(scope_extension)';
+ $s[]= ' // @@protoc_insertion_point(extension_' . $ns . ':' . $field->getName() . ')';
+ $s[]= ' return $f;';
+ $s[]= "});";
+
+ return $indent . implode(PHP_EOL.$indent, $s);
+ }
+
+ protected function compileService(proto\ServiceDescriptorProto $service, $ns)
+ {
+ $s = array();
+ $s[]= 'namespace ' . $this->normalizeNS($ns) . ' {';
+ $s[]= '';
+ $s[]= " // @@protoc_insertion_point(scope_namespace)";
+ $s[]= " // @@protoc_insertion_point(namespace_$ns)";
+ $s[]= '';
+
+ $cmt = $this->compiler->getComment($ns . '.' . $service->getName(), ' * ');
+ if ($cmt):
+ $s[]= " /**";
+ $s[]= $cmt;
+ $s[]= " */";
+ endif;
+
+ $s[]= ' interface ' . $service->getName();
+ $s[]= ' {';
+ $s[]= ' // @@protoc_insertion_point(scope_interface)';
+ $s[]= ' // @@protoc_insertion_point(interface_' . $ns . '.' . $service->getName() . ')';
+ $s[]= '';
+
+ foreach ($service->getMethodList() as $method):
+ $s[]= ' /**';
+
+ $cmt = $this->compiler->getComment($ns . '.' . $service->getName() . '.' . $method->getName(), ' * ');
+ if ($cmt):
+ $s[]= $cmt;
+ $s[]= ' * ';
+ endif;
+
+ $s[]= ' * @param ' . $this->normalizeNS($method->getInputType()) . ' $input';
+ $s[]= ' * @return ' . $this->normalizeNS($method->getOutputType());
+ $s[]= ' */';
+ $s[]= ' public function ' . $method->getName() . '(' . $this->normalizeNS($method->getInputType()) . ' $input);';
+ $s[]= '';
+ endforeach;
+ $s[]= ' }';
+ $s[]= '}';
+ $s[]= '';
+
+ return implode(PHP_EOL, $s) . PHP_EOL;
+ }
+
+ protected function generatePublicField(proto\FieldDescriptorProto $field, $ns, $indent)
+ {
+ $cmt = $this->compiler->getComment($ns . '.' . $field->getNumber(), "$indent * ");
+ if ($cmt) {
+ $cmt = "\n" . $cmt . "\n$indent *";
+ }
+
+ if ($field->getLabel() === Protobuf::RULE_REPEATED) {
+ $s[]= "/** $cmt @var " . $this->getJavaDocType($field) . "[] " . ($cmt ? "\n$indent" : '') . " */";
+ $s[]= 'public $' . $field->getName() . " = array();";
+ } else {
+ $s[]= "/** $cmt @var " . $this->getJavaDocType($field) . ($cmt ? "\n$indent" : '') . " */";
+ $default = 'null';
+ if ($field->hasDefaultValue()) {
+ switch ($field->getType()) {
+ case Protobuf::TYPE_BOOL:
+ $default = $field->getDefaultValue() ? 'true' : 'false';
+ break;
+ case Protobuf::TYPE_STRING:
+ $default = '"' . addcslashes($field->getDefaultValue(), '"\\') . '"';
+ break;
+ case Protobuf::TYPE_ENUM:
+ $default = '\\' . $this->normalizeNS($field->getTypeName()) . '::' . $field->getDefaultValue();
+ break;
+ default: // Numbers
+ $default = $field->getDefaultValue();
+ }
+ }
+ $s[]= 'public $' . $field->getName() . ' = ' . $default . ';';
+ }
+ $s[]= "";
+
+ return $indent . implode(PHP_EOL.$indent, $s);
+ }
+
+ protected function generateAccessors(proto\FieldDescriptorProto $field, $ns, $indent)
+ {
+ $tag = $field->getNumber();
+ $name = $field->getName();
+ $camel = $this->compiler->camelize(ucfirst($name));
+
+ $typehint = '';
+ $typedoc = $this->getJavaDocType($field);
+ if (0 === strpos($typedoc, '\\')) {
+ $typehint = $typedoc;
+ }
+
+ // hasXXX
+ $s[]= "/**";
+ $s[]= " * Check if <$name> has a value";
+ $s[]= " *";
+ $s[]= " * @return boolean";
+ $s[]= " */";
+ $s[]= "public function has$camel(){";
+ $s[]= " return \$this->_has($tag);";
+ $s[]= "}";
+ $s[]= "";
+
+ // clearXXX
+ $s[]= "/**";
+ $s[]= " * Clear <$name> value";
+ $s[]= " *";
+ $s[]= " * @return \\" . $this->normalizeNS($ns);
+ $s[]= " */";
+ $s[]= "public function clear$camel(){";
+ $s[]= " return \$this->_clear($tag);";
+ $s[]= "}";
+ $s[]= "";
+
+
+ if ($field->getLabel() === Protobuf::RULE_REPEATED):
+
+ // getXXX
+ $s[]= "/**";
+ $s[]= " * Get <$name> value";
+ $s[]= " *";
+ $s[]= " * @param int \$idx";
+ $s[]= " * @return $typedoc";
+ $s[]= " */";
+ $s[]= "public function get$camel(\$idx = NULL){";
+ $s[]= " return \$this->_get($tag, \$idx);";
+ $s[]= "}";
+ $s[]= "";
+
+ // setXXX
+ $s[]= "/**";
+ $s[]= " * Set <$name> value";
+ $s[]= " *";
+ $s[]= " * @param $typedoc \$value";
+ $s[]= " * @return \\" . $this->normalizeNS($ns);
+ $s[]= " */";
+ $s[]= "public function set$camel($typehint \$value, \$idx = NULL){";
+ $s[]= " return \$this->_set($tag, \$value, \$idx);";
+ $s[]= "}";
+ $s[]= "";
+
+ $s[]= "/**";
+ $s[]= " * Get all elements of <$name>";
+ $s[]= " *";
+ $s[]= " * @return {$typedoc}[]";
+ $s[]= " */";
+ $s[]= "public function get{$camel}List(){";
+ $s[]= " return \$this->_get($tag);";
+ $s[]= "}";
+ $s[]= "";
+
+ $s[]= "/**";
+ $s[]= " * Add a new element to <$name>";
+ $s[]= " *";
+ $s[]= " * @param $typedoc \$value";
+ $s[]= " * @return \\" . $this->normalizeNS($ns);
+ $s[]= " */";
+ $s[]= "public function add$camel($typehint \$value){";
+ $s[]= " return \$this->_add($tag, \$value);";
+ $s[]= "}";
+ $s[]= "";
+
+ else:
+
+ // getXXX
+ $s[]= "/**";
+ $s[]= " * Get <$name> value";
+ $s[]= " *";
+ $s[]= " * @return $typedoc";
+ $s[]= " */";
+ $s[]= "public function get$camel(){";
+ $s[]= " return \$this->_get($tag);";
+ $s[]= "}";
+ $s[]= "";
+
+ // setXXX
+ $s[]= "/**";
+ $s[]= " * Set <$name> value";
+ $s[]= " *";
+ $s[]= " * @param $typedoc \$value";
+ $s[]= " * @return \\" . $this->normalizeNS($ns);
+ $s[]= " */";
+ $s[]= "public function set$camel($typehint \$value){";
+ $s[]= " return \$this->_set($tag, \$value);";
+ $s[]= "}";
+ $s[]= "";
+
+ endif;
+
+ return $indent . implode(PHP_EOL.$indent, $s);
+ }
+
+ protected function getJavaDocType(proto\FieldDescriptorProto $field)
+ {
+ switch ($field->getType()) {
+ case Protobuf::TYPE_DOUBLE:
+ case Protobuf::TYPE_FLOAT:
+ return 'float';
+ case Protobuf::TYPE_INT64:
+ case Protobuf::TYPE_UINT64:
+ case Protobuf::TYPE_INT32:
+ case Protobuf::TYPE_FIXED64:
+ case Protobuf::TYPE_FIXED32:
+ case Protobuf::TYPE_UINT32:
+ case Protobuf::TYPE_SFIXED32:
+ case Protobuf::TYPE_SFIXED64:
+ case Protobuf::TYPE_SINT32:
+ case Protobuf::TYPE_SINT64:
+ return 'int';
+ case Protobuf::TYPE_BOOL:
+ return 'boolean';
+ case Protobuf::TYPE_STRING:
+ return 'string';
+ case Protobuf::TYPE_MESSAGE:
+ return '\\' . $this->normalizeNS($field->getTypeName());
+ case Protobuf::TYPE_BYTES:
+ return 'string';
+ case Protobuf::TYPE_ENUM:
+ return 'int - \\' . $this->normalizeNS($field->getTypeName());
+
+ case Protobuf::TYPE_GROUP:
+ default:
+ return 'unknown';
+ }
+ }
+
+ protected function normalizeNS($package)
+ {
+ // Remove leading dot (used in references)
+ $package = ltrim($package, '.');
+
+ if ($this->compiler->hasPackage($package)) {
+ return $this->compiler->getPackage($package);
+ }
+
+ // Check the currently registered packages to find a root one
+ $found = null;
+ foreach ($this->compiler->getPackages() as $pkg=>$ns) {
+ // Keep only the longest match
+ if (0 === strpos($package, $pkg.'.') && strlen($found) < strlen($pkg)) {
+ $found = $pkg;
+ }
+ }
+
+ // If no matching package was found issue a warning and use the package name
+ if (!$found) {
+ $this->compiler->warning('Non tracked package name found "' . $package . '"');
+ $namespace = str_replace('.', '\\', $package);
+ } else {
+ // Complete the namespace with the remaining package
+ $namespace = $this->compiler->getPackage($found);
+ $namespace .= substr($package, strlen($found));
+ $namespace = str_replace('.', '\\', $namespace);
+ // Set the newly found namespace in the registry
+ $this->compiler->setPackage($package, $namespace);
+ }
+
+ return $namespace;
+ }
+}
+
--- /dev/null
+++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/protos/descriptor.pb.php
@@ -1,1 +1,4780 @@
-
+<?php
+// DO NOT EDIT! Generated by Protobuf for PHP protoc plugin @package_version@
+// Source: descriptor.proto
+// Date: 2011-03-20 01:26:49
+
+namespace google\protobuf {
+
+ class FileDescriptorSet extends \DrSlump\Protobuf\Message {
+
+ /** @var \DrSlump\Protobuf\Descriptor */
+ protected static $__descriptor;
+ /** @var \Closure[] */
+ protected static $__extensions = array();
+
+ public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+ {
+ if (NULL !== $descriptor) {
+ self::$__descriptor = $descriptor;
+ return self::$__descriptor;
+ }
+
+ if (!self::$__descriptor) {
+ $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\FileDescriptorSet");
+
+ // repeated .google.protobuf.FileDescriptorProto file = 1
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 1;
+ $f->name = "file";
+ $f->nameOrig = "file";
+ $f->type = 11;
+ $f->rule = 3;
+ $f->reference = "\google\protobuf\FileDescriptorProto";
+ $descriptor->addField($f);
+
+ foreach (self::$__extensions as $cb) {
+ $descriptor->addField($cb(), true);
+ }
+
+ self::$__descriptor = $descriptor;
+ }
+
+ return self::$__descriptor;
+ }
+
+ /** @var \google\protobuf\FileDescriptorProto[] */
+ public $file = array();
+
+
+ /**
+ * Check if <file> has a value
+ *
+ * @return boolean
+ */
+ public function hasFile(){
+ return $this->_has(1);
+ }
+
+ /**
+ * Clear <file> value
+ *
+ * @return \google\protobuf\FileDescriptorSet
+ */
+ public function clearFile(){
+ return $this->_clear(1);
+ }
+
+ /**
+ * Get <file> value
+ *
+ * @param int $idx
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function getFile($idx = NULL){
+ return $this->_get(1, $idx);
+ }
+
+ /**
+ * Set <file> value
+ *
+ * @param \google\protobuf\FileDescriptorProto $value
+ * @return \google\protobuf\FileDescriptorSet
+ */
+ public function setFile(\google\protobuf\FileDescriptorProto $value, $idx = NULL){
+ return $this->_set(1, $value, $idx);
+ }
+
+ /**
+ * Get all elements of <file>
+ *
+ * @return \google\protobuf\FileDescriptorProto[]
+ */
+ public function getFileList(){
+ return $this->_get(1);
+ }
+
+ /**
+ * Add a new element to <file>
+ *
+ * @param \google\protobuf\FileDescriptorProto $value
+ * @return \google\protobuf\FileDescriptorSet
+ */
+ public function addFile(\google\protobuf\FileDescriptorProto $value){
+ return $this->_add(1, $value);
+ }
+
+ }
+}
+
+namespace google\protobuf {
+
+ class FileDescriptorProto extends \DrSlump\Protobuf\Message {
+
+ /** @var \DrSlump\Protobuf\Descriptor */
+ protected static $__descriptor;
+ /** @var \Closure[] */
+ protected static $__extensions = array();
+
+ public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+ {
+ if (NULL !== $descriptor) {
+ self::$__descriptor = $descriptor;
+ return self::$__descriptor;
+ }
+
+ if (!self::$__descriptor) {
+ $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\FileDescriptorProto");
+
+ // optional name = 1
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 1;
+ $f->name = "name";
+ $f->nameOrig = "name";
+ $f->type = 9;
+ $f->rule = 1;
+ $descriptor->addField($f);
+
+ // optional package = 2
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 2;
+ $f->name = "package";
+ $f->nameOrig = "package";
+ $f->type = 9;
+ $f->rule = 1;
+ $descriptor->addField($f);
+
+ // repeated dependency = 3
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 3;
+ $f->name = "dependency";
+ $f->nameOrig = "dependency";
+ $f->type = 9;
+ $f->rule = 3;
+ $descriptor->addField($f);
+
+ // repeated .google.protobuf.DescriptorProto message_type = 4
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 4;
+ $f->name = "message_type";
+ $f->type = 11;
+ $f->rule = 3;
+ $f->reference = "\google\protobuf\DescriptorProto";
+ $descriptor->addField($f);
+
+ // repeated .google.protobuf.EnumDescriptorProto enum_type = 5
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 5;
+ $f->name = "enum_type";
+ $f->type = 11;
+ $f->rule = 3;
+ $f->reference = "\google\protobuf\EnumDescriptorProto";
+ $descriptor->addField($f);
+
+ // repeated .google.protobuf.ServiceDescriptorProto service = 6
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 6;
+ $f->name = "service";
+ $f->nameOrig = "service";
+ $f->type = 11;
+ $f->rule = 3;
+ $f->reference = "\google\protobuf\ServiceDescriptorProto";
+ $descriptor->addField($f);
+
+ // repeated .google.protobuf.FieldDescriptorProto extension = 7
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 7;
+ $f->name = "extension";
+ $f->nameOrig = "extension";
+ $f->type = 11;
+ $f->rule = 3;
+ $f->reference = "\google\protobuf\FieldDescriptorProto";
+ $descriptor->addField($f);
+
+ // optional .google.protobuf.FileOptions options = 8
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 8;
+ $f->name = "options";
+ $f->nameOrig = "options";
+ $f->type = 11;
+ $f->rule = 1;
+ $f->reference = "\google\protobuf\FileOptions";
+ $descriptor->addField($f);
+
+ // optional .google.protobuf.SourceCodeInfo source_code_info = 9
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 9;
+ $f->name = "source_code_info";
+ $f->type = 11;
+ $f->rule = 1;
+ $f->reference = "\google\protobuf\SourceCodeInfo";
+ $descriptor->addField($f);
+
+ foreach (self::$__extensions as $cb) {
+ $descriptor->addField($cb(), true);
+ }
+
+ self::$__descriptor = $descriptor;
+ }
+
+ return self::$__descriptor;
+ }
+
+ /** @var string */
+ public $name = null;
+
+ /** @var string */
+ public $package = null;
+
+ /** @var string[] */
+ public $dependency = array();
+
+ /** @var \google\protobuf\DescriptorProto[] */
+ public $message_type = array();
+
+ /** @var \google\protobuf\EnumDescriptorProto[] */
+ public $enum_type = array();
+
+ /** @var \google\protobuf\ServiceDescriptorProto[] */
+ public $service = array();
+
+ /** @var \google\protobuf\FieldDescriptorProto[] */
+ public $extension = array();
+
+ /** @var \google\protobuf\FileOptions */
+ public $options = null;
+
+ /** @var \google\protobuf\SourceCodeInfo */
+ public $source_code_info = null;
+
+
+ /**
+ * Check if <name> has a value
+ *
+ * @return boolean
+ */
+ public function hasName(){
+ return $this->_has(1);
+ }
+
+ /**
+ * Clear <name> value
+ *
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function clearName(){
+ return $this->_clear(1);
+ }
+
+ /**
+ * Get <name> value
+ *
+ * @return string
+ */
+ public function getName(){
+ return $this->_get(1);
+ }
+
+ /**
+ * Set <name> value
+ *
+ * @param string $value
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function setName( $value){
+ return $this->_set(1, $value);
+ }
+
+ /**
+ * Check if <package> has a value
+ *
+ * @return boolean
+ */
+ public function hasPackage(){
+ return $this->_has(2);
+ }
+
+ /**
+ * Clear <package> value
+ *
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function clearPackage(){
+ return $this->_clear(2);
+ }
+
+ /**
+ * Get <package> value
+ *
+ * @return string
+ */
+ public function getPackage(){
+ return $this->_get(2);
+ }
+
+ /**
+ * Set <package> value
+ *
+ * @param string $value
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function setPackage( $value){
+ return $this->_set(2, $value);
+ }
+
+ /**
+ * Check if <dependency> has a value
+ *
+ * @return boolean
+ */
+ public function hasDependency(){
+ return $this->_has(3);
+ }
+
+ /**
+ * Clear <dependency> value
+ *
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function clearDependency(){
+ return $this->_clear(3);
+ }
+
+ /**
+ * Get <dependency> value
+ *
+ * @param int $idx
+ * @return string
+ */
+ public function getDependency($idx = NULL){
+ return $this->_get(3, $idx);
+ }
+
+ /**
+ * Set <dependency> value
+ *
+ * @param string $value
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function setDependency( $value, $idx = NULL){
+ return $this->_set(3, $value, $idx);
+ }
+
+ /**
+ * Get all elements of <dependency>
+ *
+ * @return string[]
+ */
+ public function getDependencyList(){
+ return $this->_get(3);
+ }
+
+ /**
+ * Add a new element to <dependency>
+ *
+ * @param string $value
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function addDependency( $value){
+ return $this->_add(3, $value);
+ }
+
+ /**
+ * Check if <message_type> has a value
+ *
+ * @return boolean
+ */
+ public function hasMessageType(){
+ return $this->_has(4);
+ }
+
+ /**
+ * Clear <message_type> value
+ *
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function clearMessageType(){
+ return $this->_clear(4);
+ }
+
+ /**
+ * Get <message_type> value
+ *
+ * @param int $idx
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function getMessageType($idx = NULL){
+ return $this->_get(4, $idx);
+ }
+
+ /**
+ * Set <message_type> value
+ *
+ * @param \google\protobuf\DescriptorProto $value
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function setMessageType(\google\protobuf\DescriptorProto $value, $idx = NULL){
+ return $this->_set(4, $value, $idx);
+ }
+
+ /**
+ * Get all elements of <message_type>
+ *
+ * @return \google\protobuf\DescriptorProto[]
+ */
+ public function getMessageTypeList(){
+ return $this->_get(4);
+ }
+
+ /**
+ * Add a new element to <message_type>
+ *
+ * @param \google\protobuf\DescriptorProto $value
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function addMessageType(\google\protobuf\DescriptorProto $value){
+ return $this->_add(4, $value);
+ }
+
+ /**
+ * Check if <enum_type> has a value
+ *
+ * @return boolean
+ */
+ public function hasEnumType(){
+ return $this->_has(5);
+ }
+
+ /**
+ * Clear <enum_type> value
+ *
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function clearEnumType(){
+ return $this->_clear(5);
+ }
+
+ /**
+ * Get <enum_type> value
+ *
+ * @param int $idx
+ * @return \google\protobuf\EnumDescriptorProto
+ */
+ public function getEnumType($idx = NULL){
+ return $this->_get(5, $idx);
+ }
+
+ /**
+ * Set <enum_type> value
+ *
+ * @param \google\protobuf\EnumDescriptorProto $value
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function setEnumType(\google\protobuf\EnumDescriptorProto $value, $idx = NULL){
+ return $this->_set(5, $value, $idx);
+ }
+
+ /**
+ * Get all elements of <enum_type>
+ *
+ * @return \google\protobuf\EnumDescriptorProto[]
+ */
+ public function getEnumTypeList(){
+ return $this->_get(5);
+ }
+
+ /**
+ * Add a new element to <enum_type>
+ *
+ * @param \google\protobuf\EnumDescriptorProto $value
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function addEnumType(\google\protobuf\EnumDescriptorProto $value){
+ return $this->_add(5, $value);
+ }
+
+ /**
+ * Check if <service> has a value
+ *
+ * @return boolean
+ */
+ public function hasService(){
+ return $this->_has(6);
+ }
+
+ /**
+ * Clear <service> value
+ *
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function clearService(){
+ return $this->_clear(6);
+ }
+
+ /**
+ * Get <service> value
+ *
+ * @param int $idx
+ * @return \google\protobuf\ServiceDescriptorProto
+ */
+ public function getService($idx = NULL){
+ return $this->_get(6, $idx);
+ }
+
+ /**
+ * Set <service> value
+ *
+ * @param \google\protobuf\ServiceDescriptorProto $value
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function setService(\google\protobuf\ServiceDescriptorProto $value, $idx = NULL){
+ return $this->_set(6, $value, $idx);
+ }
+
+ /**
+ * Get all elements of <service>
+ *
+ * @return \google\protobuf\ServiceDescriptorProto[]
+ */
+ public function getServiceList(){
+ return $this->_get(6);
+ }
+
+ /**
+ * Add a new element to <service>
+ *
+ * @param \google\protobuf\ServiceDescriptorProto $value
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function addService(\google\protobuf\ServiceDescriptorProto $value){
+ return $this->_add(6, $value);
+ }
+
+ /**
+ * Check if <extension> has a value
+ *
+ * @return boolean
+ */
+ public function hasExtension(){
+ return $this->_has(7);
+ }
+
+ /**
+ * Clear <extension> value
+ *
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function clearExtension(){
+ return $this->_clear(7);
+ }
+
+ /**
+ * Get <extension> value
+ *
+ * @param int $idx
+ * @return \google\protobuf\FieldDescriptorProto
+ */
+ public function getExtension($idx = NULL){
+ return $this->_get(7, $idx);
+ }
+
+ /**
+ * Set <extension> value
+ *
+ * @param \google\protobuf\FieldDescriptorProto $value
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function setExtension(\google\protobuf\FieldDescriptorProto $value, $idx = NULL){
+ return $this->_set(7, $value, $idx);
+ }
+
+ /**
+ * Get all elements of <extension>
+ *
+ * @return \google\protobuf\FieldDescriptorProto[]
+ */
+ public function getExtensionList(){
+ return $this->_get(7);
+ }
+
+ /**
+ * Add a new element to <extension>
+ *
+ * @param \google\protobuf\FieldDescriptorProto $value
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function addExtension(\google\protobuf\FieldDescriptorProto $value){
+ return $this->_add(7, $value);
+ }
+
+ /**
+ * Check if <options> has a value
+ *
+ * @return boolean
+ */
+ public function hasOptions(){
+ return $this->_has(8);
+ }
+
+ /**
+ * Clear <options> value
+ *
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function clearOptions(){
+ return $this->_clear(8);
+ }
+
+ /**
+ * Get <options> value
+ *
+ * @return \google\protobuf\FileOptions
+ */
+ public function getOptions(){
+ return $this->_get(8);
+ }
+
+ /**
+ * Set <options> value
+ *
+ * @param \google\protobuf\FileOptions $value
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function setOptions(\google\protobuf\FileOptions $value){
+ return $this->_set(8, $value);
+ }
+
+ /**
+ * Check if <source_code_info> has a value
+ *
+ * @return boolean
+ */
+ public function hasSourceCodeInfo(){
+ return $this->_has(9);
+ }
+
+ /**
+ * Clear <source_code_info> value
+ *
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function clearSourceCodeInfo(){
+ return $this->_clear(9);
+ }
+
+ /**
+ * Get <source_code_info> value
+ *
+ * @return \google\protobuf\SourceCodeInfo
+ */
+ public function getSourceCodeInfo(){
+ return $this->_get(9);
+ }
+
+ /**
+ * Set <source_code_info> value
+ *
+ * @param \google\protobuf\SourceCodeInfo $value
+ * @return \google\protobuf\FileDescriptorProto
+ */
+ public function setSourceCodeInfo(\google\protobuf\SourceCodeInfo $value){
+ return $this->_set(9, $value);
+ }
+
+ }
+}
+
+namespace google\protobuf {
+
+ class DescriptorProto extends \DrSlump\Protobuf\Message {
+
+ /** @var \DrSlump\Protobuf\Descriptor */
+ protected static $__descriptor;
+ /** @var \Closure[] */
+ protected static $__extensions = array();
+
+ public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+ {
+ if (NULL !== $descriptor) {
+ self::$__descriptor = $descriptor;
+ return self::$__descriptor;
+ }
+
+ if (!self::$__descriptor) {
+ $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\DescriptorProto");
+
+ // optional name = 1
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 1;
+ $f->name = "name";
+ $f->nameOrig = "name";
+ $f->type = 9;
+ $f->rule = 1;
+ $descriptor->addField($f);
+
+ // repeated .google.protobuf.FieldDescriptorProto field = 2
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 2;
+ $f->name = "field";
+ $f->nameOrig = "field";
+ $f->type = 11;
+ $f->rule = 3;
+ $f->reference = "\google\protobuf\FieldDescriptorProto";
+ $descriptor->addField($f);
+
+ // repeated .google.protobuf.FieldDescriptorProto extension = 6
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 6;
+ $f->name = "extension";
+ $f->nameOrig = "extension";
+ $f->type = 11;
+ $f->rule = 3;
+ $f->reference = "\google\protobuf\FieldDescriptorProto";
+ $descriptor->addField($f);
+
+ // repeated .google.protobuf.DescriptorProto nested_type = 3
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 3;
+ $f->name = "nested_type";
+ $f->type = 11;
+ $f->rule = 3;
+ $f->reference = "\google\protobuf\DescriptorProto";
+ $descriptor->addField($f);
+
+ // repeated .google.protobuf.EnumDescriptorProto enum_type = 4
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 4;
+ $f->name = "enum_type";
+ $f->type = 11;
+ $f->rule = 3;
+ $f->reference = "\google\protobuf\EnumDescriptorProto";
+ $descriptor->addField($f);
+
+ // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 5;
+ $f->name = "extension_range";
+ $f->type = 11;
+ $f->rule = 3;
+ $f->reference = "\google\protobuf\DescriptorProto\ExtensionRange";
+ $descriptor->addField($f);
+
+ // optional .google.protobuf.MessageOptions options = 7
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 7;
+ $f->name = "options";
+ $f->nameOrig = "options";
+ $f->type = 11;
+ $f->rule = 1;
+ $f->reference = "\google\protobuf\MessageOptions";
+ $descriptor->addField($f);
+
+ foreach (self::$__extensions as $cb) {
+ $descriptor->addField($cb(), true);
+ }
+
+ self::$__descriptor = $descriptor;
+ }
+
+ return self::$__descriptor;
+ }
+
+ /** @var string */
+ public $name = null;
+
+ /** @var \google\protobuf\FieldDescriptorProto[] */
+ public $field = array();
+
+ /** @var \google\protobuf\FieldDescriptorProto[] */
+ public $extension = array();
+
+ /** @var \google\protobuf\DescriptorProto[] */
+ public $nested_type = array();
+
+ /** @var \google\protobuf\EnumDescriptorProto[] */
+ public $enum_type = array();
+
+ /** @var \google\protobuf\DescriptorProto\ExtensionRange[] */
+ public $extension_range = array();
+
+ /** @var \google\protobuf\MessageOptions */
+ public $options = null;
+
+
+ /**
+ * Check if <name> has a value
+ *
+ * @return boolean
+ */
+ public function hasName(){
+ return $this->_has(1);
+ }
+
+ /**
+ * Clear <name> value
+ *
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function clearName(){
+ return $this->_clear(1);
+ }
+
+ /**
+ * Get <name> value
+ *
+ * @return string
+ */
+ public function getName(){
+ return $this->_get(1);
+ }
+
+ /**
+ * Set <name> value
+ *
+ * @param string $value
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function setName( $value){
+ return $this->_set(1, $value);
+ }
+
+ /**
+ * Check if <field> has a value
+ *
+ * @return boolean
+ */
+ public function hasField(){
+ return $this->_has(2);
+ }
+
+ /**
+ * Clear <field> value
+ *
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function clearField(){
+ return $this->_clear(2);
+ }
+
+ /**
+ * Get <field> value
+ *
+ * @param int $idx
+ * @return \google\protobuf\FieldDescriptorProto
+ */
+ public function getField($idx = NULL){
+ return $this->_get(2, $idx);
+ }
+
+ /**
+ * Set <field> value
+ *
+ * @param \google\protobuf\FieldDescriptorProto $value
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function setField(\google\protobuf\FieldDescriptorProto $value, $idx = NULL){
+ return $this->_set(2, $value, $idx);
+ }
+
+ /**
+ * Get all elements of <field>
+ *
+ * @return \google\protobuf\FieldDescriptorProto[]
+ */
+ public function getFieldList(){
+ return $this->_get(2);
+ }
+
+ /**
+ * Add a new element to <field>
+ *
+ * @param \google\protobuf\FieldDescriptorProto $value
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function addField(\google\protobuf\FieldDescriptorProto $value){
+ return $this->_add(2, $value);
+ }
+
+ /**
+ * Check if <extension> has a value
+ *
+ * @return boolean
+ */
+ public function hasExtension(){
+ return $this->_has(6);
+ }
+
+ /**
+ * Clear <extension> value
+ *
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function clearExtension(){
+ return $this->_clear(6);
+ }
+
+ /**
+ * Get <extension> value
+ *
+ * @param int $idx
+ * @return \google\protobuf\FieldDescriptorProto
+ */
+ public function getExtension($idx = NULL){
+ return $this->_get(6, $idx);
+ }
+
+ /**
+ * Set <extension> value
+ *
+ * @param \google\protobuf\FieldDescriptorProto $value
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function setExtension(\google\protobuf\FieldDescriptorProto $value, $idx = NULL){
+ return $this->_set(6, $value, $idx);
+ }
+
+ /**
+ * Get all elements of <extension>
+ *
+ * @return \google\protobuf\FieldDescriptorProto[]
+ */
+ public function getExtensionList(){
+ return $this->_get(6);
+ }
+
+ /**
+ * Add a new element to <extension>
+ *
+ * @param \google\protobuf\FieldDescriptorProto $value
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function addExtension(\google\protobuf\FieldDescriptorProto $value){
+ return $this->_add(6, $value);
+ }
+
+ /**
+ * Check if <nested_type> has a value
+ *
+ * @return boolean
+ */
+ public function hasNestedType(){
+ return $this->_has(3);
+ }
+
+ /**
+ * Clear <nested_type> value
+ *
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function clearNestedType(){
+ return $this->_clear(3);
+ }
+
+ /**
+ * Get <nested_type> value
+ *
+ * @param int $idx
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function getNestedType($idx = NULL){
+ return $this->_get(3, $idx);
+ }
+
+ /**
+ * Set <nested_type> value
+ *
+ * @param \google\protobuf\DescriptorProto $value
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function setNestedType(\google\protobuf\DescriptorProto $value, $idx = NULL){
+ return $this->_set(3, $value, $idx);
+ }
+
+ /**
+ * Get all elements of <nested_type>
+ *
+ * @return \google\protobuf\DescriptorProto[]
+ */
+ public function getNestedTypeList(){
+ return $this->_get(3);
+ }
+
+ /**
+ * Add a new element to <nested_type>
+ *
+ * @param \google\protobuf\DescriptorProto $value
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function addNestedType(\google\protobuf\DescriptorProto $value){
+ return $this->_add(3, $value);
+ }
+
+ /**
+ * Check if <enum_type> has a value
+ *
+ * @return boolean
+ */
+ public function hasEnumType(){
+ return $this->_has(4);
+ }
+
+ /**
+ * Clear <enum_type> value
+ *
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function clearEnumType(){
+ return $this->_clear(4);
+ }
+
+ /**
+ * Get <enum_type> value
+ *
+ * @param int $idx
+ * @return \google\protobuf\EnumDescriptorProto
+ */
+ public function getEnumType($idx = NULL){
+ return $this->_get(4, $idx);
+ }
+
+ /**
+ * Set <enum_type> value
+ *
+ * @param \google\protobuf\EnumDescriptorProto $value
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function setEnumType(\google\protobuf\EnumDescriptorProto $value, $idx = NULL){
+ return $this->_set(4, $value, $idx);
+ }
+
+ /**
+ * Get all elements of <enum_type>
+ *
+ * @return \google\protobuf\EnumDescriptorProto[]
+ */
+ public function getEnumTypeList(){
+ return $this->_get(4);
+ }
+
+ /**
+ * Add a new element to <enum_type>
+ *
+ * @param \google\protobuf\EnumDescriptorProto $value
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function addEnumType(\google\protobuf\EnumDescriptorProto $value){
+ return $this->_add(4, $value);
+ }
+
+ /**
+ * Check if <extension_range> has a value
+ *
+ * @return boolean
+ */
+ public function hasExtensionRange(){
+ return $this->_has(5);
+ }
+
+ /**
+ * Clear <extension_range> value
+ *
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function clearExtensionRange(){
+ return $this->_clear(5);
+ }
+
+ /**
+ * Get <extension_range> value
+ *
+ * @param int $idx
+ * @return \google\protobuf\DescriptorProto\ExtensionRange
+ */
+ public function getExtensionRange($idx = NULL){
+ return $this->_get(5, $idx);
+ }
+
+ /**
+ * Set <extension_range> value
+ *
+ * @param \google\protobuf\DescriptorProto\ExtensionRange $value
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function setExtensionRange(\google\protobuf\DescriptorProto\ExtensionRange $value, $idx = NULL){
+ return $this->_set(5, $value, $idx);
+ }
+
+ /**
+ * Get all elements of <extension_range>
+ *
+ * @return \google\protobuf\DescriptorProto\ExtensionRange[]
+ */
+ public function getExtensionRangeList(){
+ return $this->_get(5);
+ }
+
+ /**
+ * Add a new element to <extension_range>
+ *
+ * @param \google\protobuf\DescriptorProto\ExtensionRange $value
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function addExtensionRange(\google\protobuf\DescriptorProto\ExtensionRange $value){
+ return $this->_add(5, $value);
+ }
+
+ /**
+ * Check if <options> has a value
+ *
+ * @return boolean
+ */
+ public function hasOptions(){
+ return $this->_has(7);
+ }
+
+ /**
+ * Clear <options> value
+ *
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function clearOptions(){
+ return $this->_clear(7);
+ }
+
+ /**
+ * Get <options> value
+ *
+ * @return \google\protobuf\MessageOptions
+ */
+ public function getOptions(){
+ return $this->_get(7);
+ }
+
+ /**
+ * Set <options> value
+ *
+ * @param \google\protobuf\MessageOptions $value
+ * @return \google\protobuf\DescriptorProto
+ */
+ public function setOptions(\google\protobuf\MessageOptions $value){
+ return $this->_set(7, $value);
+ }
+
+ }
+}
+
+namespace google\protobuf\DescriptorProto {
+
+ class ExtensionRange extends \DrSlump\Protobuf\Message {
+
+ /** @var \DrSlump\Protobuf\Descriptor */
+ protected static $__descriptor;
+ /** @var \Closure[] */
+ protected static $__extensions = array();
+
+ public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+ {
+ if (NULL !== $descriptor) {
+ self::$__descriptor = $descriptor;
+ return self::$__descriptor;
+ }
+
+ if (!self::$__descriptor) {
+ $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\DescriptorProto\ExtensionRange");
+
+ // optional start = 1
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 1;
+ $f->name = "start";
+ $f->nameOrig = "start";
+ $f->type = 5;
+ $f->rule = 1;
+ $descriptor->addField($f);
+
+ // optional end = 2
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 2;
+ $f->name = "end";
+ $f->nameOrig = "end";
+ $f->type = 5;
+ $f->rule = 1;
+ $descriptor->addField($f);
+
+ foreach (self::$__extensions as $cb) {
+ $descriptor->addField($cb(), true);
+ }
+
+ self::$__descriptor = $descriptor;
+ }
+
+ return self::$__descriptor;
+ }
+
+ /** @var int */
+ public $start = null;
+
+ /** @var int */
+ public $end = null;
+
+
+ /**
+ * Check if <start> has a value
+ *
+ * @return boolean
+ */
+ public function hasStart(){
+ return $this->_has(1);
+ }
+
+ /**
+ * Clear <start> value
+ *
+ * @return \google\protobuf\DescriptorProto\ExtensionRange
+ */
+ public function clearStart(){
+ return $this->_clear(1);
+ }
+
+ /**
+ * Get <start> value
+ *
+ * @return int
+ */
+ public function getStart(){
+ return $this->_get(1);
+ }
+
+ /**
+ * Set <start> value
+ *
+ * @param int $value
+ * @return \google\protobuf\DescriptorProto\ExtensionRange
+ */
+ public function setStart( $value){
+ return $this->_set(1, $value);
+ }
+
+ /**
+ * Check if <end> has a value
+ *
+ * @return boolean
+ */
+ public function hasEnd(){
+ return $this->_has(2);
+ }
+
+ /**
+ * Clear <end> value
+ *
+ * @return \google\protobuf\DescriptorProto\ExtensionRange
+ */
+ public function clearEnd(){
+ return $this->_clear(2);
+ }
+
+ /**
+ * Get <end> value
+ *
+ * @return int
+ */
+ public function getEnd(){
+ return $this->_get(2);
+ }
+
+ /**
+ * Set <end> value
+ *
+ * @param int $value
+ * @return \google\protobuf\DescriptorProto\ExtensionRange
+ */
+ public function setEnd( $value){
+ return $this->_set(2, $value);
+ }
+
+ }
+}
+
+namespace google\protobuf {
+
+ class FieldDescriptorProto extends \DrSlump\Protobuf\Message {
+
+ /** @var \DrSlump\Protobuf\Descriptor */
+ protected static $__descriptor;
+ /** @var \Closure[] */
+ protected static $__extensions = array();
+
+ public static function descriptor(\DrSlump\Protobuf\Descriptor $descriptor = NULL)
+ {
+ if (NULL !== $descriptor) {
+ self::$__descriptor = $descriptor;
+ return self::$__descriptor;
+ }
+
+ if (!self::$__descriptor) {
+ $descriptor = new \DrSlump\Protobuf\Descriptor("\google\protobuf\FieldDescriptorProto");
+
+ // optional name = 1
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 1;
+ $f->name = "name";
+ $f->nameOrig = "name";
+ $f->type = 9;
+ $f->rule = 1;
+ $descriptor->addField($f);
+
+ // optional number = 3
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 3;
+ $f->name = "number";
+ $f->nameOrig = "number";
+ $f->type = 5;
+ $f->rule = 1;
+ $descriptor->addField($f);
+
+ // optional .google.protobuf.FieldDescriptorProto.Label label = 4
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 4;
+ $f->name = "label";
+ $f->nameOrig = "label";
+ $f->type = 14;
+ $f->rule = 1;
+ $f->reference = "\google\protobuf\FieldDescriptorProto\Label";
+ $descriptor->addField($f);
+
+ // optional .google.protobuf.FieldDescriptorProto.Type type = 5
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 5;
+ $f->name = "type";
+ $f->nameOrig = "type";
+ $f->type = 14;
+ $f->rule = 1;
+ $f->reference = "\google\protobuf\FieldDescriptorProto\Type";
+ $descriptor->addField($f);
+
+ // optional type_name = 6
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 6;
+ $f->name = "type_name";
+ $f->type = 9;
+ $f->rule = 1;
+ $descriptor->addField($f);
+
+ // optional extendee = 2
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 2;
+ $f->name = "extendee";
+ $f->nameOrig = "extendee";
+ $f->type = 9;
+ $f->rule = 1;
+ $descriptor->addField($f);
+
+ // optional default_value = 7
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 7;
+ $f->name = "default_value";
+ $f->type = 9;
+ $f->rule = 1;
+ $descriptor->addField($f);
+
+ // optional .google.protobuf.FieldOptions options = 8
+ $f = new \DrSlump\Protobuf\Field();
+ $f->number = 8;
+ $f->name = "options";
+ $f->nameOrig = "options";
+ $f->type = 11;
+ $f->rule = 1;
+ $f->reference = "\google\protobuf\FieldOptions";
+ $descriptor->addField($f);
+
+ foreach (self::$__extensions as $cb) {
+ $descriptor->addField($cb(), true);
+ }
+
+ self::$__descriptor = $descriptor;
+ }
+
+ return self::$__descriptor;
+ }
+
+ /** @var string */
+ public $name = null;
+
+ /** @var int */
+ public $number = null;
+
+ /** @var int - \google\protobuf\FieldDescriptorProto\Label */
+ public $label = null;
+
+ /** @var int - \google\protobuf\FieldDescriptorProto\Type */
+ public $type = null;
+
+ /** @var string */
+ public $type_name = null;
+
+ /** @var string */
+ public $extendee = null;
+
+ /** @var string */
+ public $default_value = null;
+
+ /** @var \google\protobuf\FieldOptions */
+ public $options = null;
+
+
+ /**
+ * Check if <name> has a value
+ *
+ * @return boolean
+ */
+ public function hasName(){
+ return $this->_has(1);
+ }
+
+ /**
+ * Clear <name> value
+ *
+ * @return \google\protobuf\FieldDescriptorProto
+ */
+ public function clearName(){
+ return $this->_clear(1);
+ }
+
+ /**
+ * Get <name> value
+ *
+ * @return string
+ */
+ public function getName(){
+ return $this->_get(1);
+ }
+
+ /**
+ * Set <name> value
+ *
+ * @param string $value
+ * @return \google\protobuf\FieldDescriptorProto
+ */
+ public function setName( $value){
+ return $this->_set(1, $value);
+ }
+
+ /**
+ * Check if <number> has a value
+ *
+ * @return boolean
+ */
+ public function hasNumber(){
+ return $this->_has(3);
+ }
+
+ /**
+ * Clear <number> value
+ *
+ * @return \google\protobuf\FieldDescriptorProto
+ */
+ public function clearNumber(){
+ return $this->_clear(3);
+ }
+
+ /**
+ * Get <number> value
+ *
+ * @return int
+ */
+ public function getNumber(){
+ return $this->_get(3);
+ }
+
+ /**
+ * Set <number> value
+ *
+ * @param int $value
+ * @return \google\protobuf\FieldDescriptorProto
+ */
+ public function setNumber( $value){
+ return $this->_set(3, $value);
+ }
+
+ /**
+ * Check if <label> has a value
+ *
+ * @return boolean
+ */
+ public function hasLabel(){
+ return $this->_has(4);
+ }
+
+ /**
+ * Clear <label> value
+ *
+ * @return \google\protobuf\FieldDescriptorProto
+ */
+ public function clearLabel(){
+ return $this->_clear(4);
+ }
+
+ /**
+ * Get <label> value
+ *
+ * @return int - \google\protobuf\FieldDescriptorProto\Label
+ */
+ public function getLabel(){
+ return $this->_get(4);
+ }
+
+ /**
+ * Set <label> value
+ *
+ * @param int - \google\protobuf\FieldDescriptorProto\Label $value
+ * @return \google\protobuf\FieldDescriptorProto
+ */
+ public function setLabel( $value){
+ return $this->_set(4, $value);
+ }
+
+ /**
+ * Check if <type> has a value
+ *
+ * @return boolean
+ */
+ public function hasType(){
+ return $this->_has(5);
+ }
+
+ /**
+ * Clear <type> value
+ *
+ * @return \google\protobuf\FieldDescriptorProto
+ */
+ public function clearType(){
+ return $this->_clear(5);
+ }
+
+ /**
+ * Get <type> value
+ *
+ * @return int - \google\protobuf\FieldDescriptorProto\Type
+ */