/labs/tiles/12 | /labs/tiles/12 |
/labs/tiles/13 | /labs/tiles/13 |
/labs/tiles/14 | /labs/tiles/14 |
/labs/tiles/15 | /labs/tiles/15 |
/labs/tiles/16 | /labs/tiles/16 |
/labs/tiles/17 | /labs/tiles/17 |
/labs/tiles/19 | /labs/tiles/19 |
/nbproject/private/ |
<?php | <?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 ('include/common.inc.php'); |
include_header("About", "about") | include_header("About", "about") |
?> | ?> |
<p> | <p> |
Busness Time - An ACT bus timetable webapp<br /> | Busness Time - An ACT bus timetable webapp<br /> |
Based on the maxious-canberra-transit-feed (<a | Based on the maxious-canberra-transit-feed (<a |
href="http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip">download</a>, | href="http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip">download</a>, |
last updated <?php | last updated <?php echo date("F d Y.", @filemtime('cbrfeed.zip')); ?>)<br /> |
echo date("F d Y.", @filemtime('cbrfeed.zip')); ?>)<br /> | Source code for the <a |
Source code for the <a | href="https://github.com/maxious/ACTBus-data">transit |
href="https://github.com/maxious/ACTBus-data">transit | feed</a> and <a href="https://github.com/maxious/ACTBus-ui">this |
feed</a> and <a href="https://github.com/maxious/ACTBus-ui">this | site</a> available from github.<br /> |
site</a> available from github.<br /> | Uses jQuery Mobile, PHP, PostgreSQL, OpenTripPlanner, OpenLayers, OpenStreetMap, Cloudmade Geocoder and Tile Service<br /> |
Uses jQuery Mobile, PHP, PostgreSQL, OpenTripPlanner, OpenLayers, OpenStreetMap, Cloudmade Geocoder and Tile Service<br /> | |
<br /> | |
Feedback encouraged; contact maxious@lambdacomplex.org<br /> | |
<br /> | <br /> |
Some icons by Joseph Wain / glyphish.com<br /> | Feedback encouraged; contact maxious@lambdacomplex.org<br /> |
Native clients also available for iPhone(<a href="http://itunes.apple.com/au/app/cbrtimetable/id444287349?mt=8">cbrTimetable by Sandor Kolotenko</a> | <br /> |
, <a href="http://itunes.apple.com/au/app/act-buses/id376634797?mt=8">ACT Buses by David Sullivan</a>) | Some icons by Joseph Wain / glyphish.com<br /> |
and Android (<a href="https://market.android.com/details?id=com.action">MyBus 2.0 by Imagine Team</a>) | Native clients also available for iPhone(<a href="http://itunes.apple.com/au/app/cbrtimetable/id444287349?mt=8">cbrTimetable by Sandor Kolotenko</a> |
<br /> | , <a href="http://itunes.apple.com/au/app/act-buses/id376634797?mt=8">ACT Buses by David Sullivan</a>) |
GTFS-realtime API; | and Android (<a href="https://market.android.com/details?id=com.action">MyBus 2.0 by Imagine Team</a>) |
Alerts and Trip Updates (but only Cancelled or Stop Skipped) | <br /> |
Default format binary but can get JSON by adding ?ascii=yes | GTFS-realtime API; |
<br /> | Alerts and Trip Updates (but only Cancelled or Stop Skipped) |
<br /> | Default format binary but can get JSON by adding ?ascii=yes |
<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. | <br /> |
Whilst every effort has been made to ensure the high quality and accuracy of the Site, the Author makes no warranty, | <br /> |
express or implied concerning the topicality, correctness, completeness or quality of the information, which is provided | <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. |
"as is". The Author expressly disclaims all warranties, including but not limited to warranties of fitness for a particular purpose and warranties of merchantability. | Whilst every effort has been made to ensure the high quality and accuracy of the Site, the Author makes no warranty, |
All offers are not binding and without obligation. The Author expressly reserves the right, in his discretion, to suspend, | express or implied concerning the topicality, correctness, completeness or quality of the information, which is provided |
change, modify, add or remove portions of the Site and to restrict or terminate the use and accessibility of the Site | "as is". The Author expressly disclaims all warranties, including but not limited to warranties of fitness for a particular purpose and warranties of merchantability. |
without prior notice. </small> | All offers are not binding and without obligation. The Author expressly reserves the right, in his discretion, to suspend, |
<?php | change, modify, add or remove portions of the Site and to restrict or terminate the use and accessibility of the Site |
include_footer(); | without prior notice. </small> |
?> | <?php |
include_footer(); | |
?> | |
cp /root/aws.php /tmp/ | cp /root/aws.php /tmp/ |
mkdir /var/www/lib/staticmaplite/cache | chmod 777 /var/cache/lighttpd/compress/ |
chcon -h system_u:object_r:httpd_sys_content_t /var/www | 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 -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 | chcon -R -t httpd_sys_content_rw_t /var/www/labs/tiles |
chmod -R 777 /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 \ | wget http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip \ |
-O /var/www/cbrfeed.zip | -O /var/www/cbrfeed.zip |
/*! | |
* 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 } | |
/*! | |
* jQuery Mobile v1.0rc1 | |
* 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. | |
*/ | |
/* Swatches */ | |
/* A | |
-----------------------------------------------------------------------------------------------------------*/ | |
.ui-bar-a { | |
border: 1px solid #2A2A2A /*{a-bar-border}*/; | |
background: #111111 /*{a-bar-background-color}*/; | |
color: #ffffff /*{a-bar-color}*/; | |
font-weight: bold; | |
text-shadow: 0 /*{a-bar-shadow-x}*/ -1px /*{a-bar-shadow-y}*/ 1px /*{a-bar-shadow-radius}*/ #000000 /*{a-bar-shadow-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c /*{a-bar-background-start}*/), to(#111 /*{a-bar-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #3c3c3c /*{a-bar-background-start}*/, #111 /*{a-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #3c3c3c /*{a-bar-background-start}*/, #111 /*{a-bar-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #3c3c3c /*{a-bar-background-start}*/, #111 /*{a-bar-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #3c3c3c /*{a-bar-background-start}*/, #111 /*{a-bar-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #3c3c3c /*{a-bar-background-start}*/, #111 /*{a-bar-background-end}*/); | |
} | |
.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 /*{a-bar-font}*/; | |
} | |
.ui-bar-a .ui-link-inherit { | |
color: #fff /*{a-bar-color}*/; | |
} | |
.ui-bar-a .ui-link { | |
color: #7cc4e7 /*{global-link-color}*/; | |
font-weight: bold; | |
} | |
.ui-body-a { | |
border: 1px solid #2A2A2A /*{a-body-border}*/; | |
background: #222222 /*{a-body-background-color}*/; | |
color: #fff /*{a-body-color}*/; | |
text-shadow: 0 /*{a-body-shadow-x}*/ 1px /*{a-body-shadow-y}*/ 0 /*{a-body-shadow-radius}*/ #000 /*{a-body-shadow-color}*/; | |
font-weight: normal; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#666 /*{a-body-background-start}*/), to(#222 /*{a-body-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #666 /*{a-body-background-start}*/, #222 /*{a-body-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #666 /*{a-body-background-start}*/, #222 /*{a-body-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #666 /*{a-body-background-start}*/, #222 /*{a-body-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #666 /*{a-body-background-start}*/, #222 /*{a-body-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #666 /*{a-body-background-start}*/, #222 /*{a-body-background-end}*/); | |
} | |
.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 /*{a-body-font}*/; | |
} | |
.ui-body-a .ui-link-inherit { | |
color: #fff /*{a-body-color}*/; | |
} | |
.ui-body-a .ui-link { | |
color: #2489CE /*{global-link-color}*/; | |
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 /*{a-bup-border}*/; | |
background: #333333 /*{a-bup-background-color}*/; | |
font-weight: bold; | |
color: #fff /*{a-bup-color}*/; | |
text-shadow: 0 /*{a-bup-shadow-x}*/ -1px /*{a-bup-shadow-y}*/ 1px /*{a-bup-shadow-radius}*/ #000 /*{a-bup-shadow-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#555 /*{a-bup-background-start}*/), to(#333 /*{a-bup-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #555 /*{a-bup-background-start}*/, #333 /*{a-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #555 /*{a-bup-background-start}*/, #333 /*{a-bup-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #555 /*{a-bup-background-start}*/, #333 /*{a-bup-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #555 /*{a-bup-background-start}*/, #333 /*{a-bup-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #555 /*{a-bup-background-start}*/, #333 /*{a-bup-background-end}*/); | |
} | |
.ui-btn-up-a a.ui-link-inherit { | |
color: #fff /*{a-bup-color}*/; | |
} | |
.ui-btn-hover-a { | |
border: 1px solid #000 /*{a-bhover-border}*/; | |
background: #444444 /*{a-bhover-background-color}*/; | |
font-weight: bold; | |
color: #fff /*{a-bhover-color}*/; | |
text-shadow: 0 /*{a-bhover-shadow-x}*/ -1px /*{a-bhover-shadow-y}*/ 1px /*{a-bhover-shadow-radius}*/ #000 /*{a-bhover-shadow-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#666 /*{a-bhover-background-start}*/), to(#444 /*{a-bhover-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #666 /*{a-bhover-background-start}*/, #444 /*{a-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #666 /*{a-bhover-background-start}*/, #444 /*{a-bhover-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #666 /*{a-bhover-background-start}*/, #444 /*{a-bhover-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #666 /*{a-bhover-background-start}*/, #444 /*{a-bhover-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #666 /*{a-bhover-background-start}*/, #444 /*{a-bhover-background-end}*/); | |
} | |
.ui-btn-hover-a a.ui-link-inherit { | |
color: #fff /*{a-bhover-color}*/; | |
} | |
.ui-btn-down-a { | |
border: 1px solid #000 /*{a-bdown-border}*/; | |
background: #3d3d3d /*{a-bdown-background-color}*/; | |
font-weight: bold; | |
color: #fff /*{a-bdown-color}*/; | |
text-shadow: 0 /*{a-bdown-shadow-x}*/ -1px /*{a-bdown-shadow-y}*/ 1px /*{a-bdown-shadow-radius}*/ #000 /*{a-bdown-shadow-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#333 /*{a-bdown-background-start}*/), to(#5a5a5a /*{a-bdown-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #333 /*{a-bdown-background-start}*/, #5a5a5a /*{a-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #333 /*{a-bdown-background-start}*/, #5a5a5a /*{a-bdown-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #333 /*{a-bdown-background-start}*/, #5a5a5a /*{a-bdown-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #333 /*{a-bdown-background-start}*/, #5a5a5a /*{a-bdown-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #333 /*{a-bdown-background-start}*/, #5a5a5a /*{a-bdown-background-end}*/); | |
} | |
.ui-btn-down-a a.ui-link-inherit { | |
color: #fff /*{a-bdown-color}*/; | |
} | |
.ui-btn-up-a, | |
.ui-btn-hover-a, | |
.ui-btn-down-a { | |
font-family: Helvetica, Arial, sans-serif /*{a-button-font}*/; | |
text-decoration: none; | |
} | |
/* B | |
-----------------------------------------------------------------------------------------------------------*/ | |
.ui-bar-b { | |
border: 1px solid #456f9a /*{b-bar-border}*/; | |
background: #5e87b0 /*{b-bar-background-color}*/; | |
color: #fff /*{b-bar-color}*/; | |
font-weight: bold; | |
text-shadow: 0 /*{b-bar-shadow-x}*/ -1px /*{b-bar-shadow-y}*/ 1px /*{b-bar-shadow-radius}*/ #254f7a /*{b-bar-shadow-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#81a8ce /*{b-bar-background-start}*/), to(#5e87b0 /*{b-bar-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #81a8ce /*{b-bar-background-start}*/, #5e87b0 /*{b-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #81a8ce /*{b-bar-background-start}*/, #5e87b0 /*{b-bar-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #81a8ce /*{b-bar-background-start}*/, #5e87b0 /*{b-bar-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #81a8ce /*{b-bar-background-start}*/, #5e87b0 /*{b-bar-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #81a8ce /*{b-bar-background-start}*/, #5e87b0 /*{b-bar-background-end}*/); | |
} | |
.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 /*{b-bar-font}*/; | |
} | |
.ui-bar-b .ui-link-inherit { | |
color: #fff /*{b-bar-color}*/; | |
} | |
.ui-bar-b .ui-link { | |
color: #7cc4e7 /*{global-link-color}*/; | |
font-weight: bold; | |
} | |
.ui-body-b { | |
border: 1px solid #C6C6C6 /*{b-body-border}*/; | |
background: #cccccc /*{b-body-background-color}*/; | |
color: #333333 /*{b-body-color}*/; | |
text-shadow: 0 /*{b-body-shadow-x}*/ 1px /*{b-body-shadow-y}*/ 0 /*{b-body-shadow-radius}*/ #fff /*{b-body-shadow-color}*/; | |
font-weight: normal; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#e6e6e6 /*{b-body-background-start}*/), to(#ccc /*{b-body-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #e6e6e6 /*{b-body-background-start}*/, #ccc /*{b-body-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #e6e6e6 /*{b-body-background-start}*/, #ccc /*{b-body-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #e6e6e6 /*{b-body-background-start}*/, #ccc /*{b-body-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #e6e6e6 /*{b-body-background-start}*/, #ccc /*{b-body-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #e6e6e6 /*{b-body-background-start}*/, #ccc /*{b-body-background-end}*/); | |
} | |
.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 /*{b-body-font}*/; | |
} | |
.ui-body-b .ui-link-inherit { | |
color: #333333 /*{b-body-color}*/; | |
} | |
.ui-body-b .ui-link { | |
color: #2489CE /*{global-link-color}*/; | |
font-weight: bold; | |
} | |
.ui-btn-up-b { | |
border: 1px solid #145072 /*{b-bup-border}*/; | |
background: #2567ab /*{b-bup-background-color}*/; | |
font-weight: bold; | |
color: #fff /*{b-bup-color}*/; | |
text-shadow: 0 /*{b-bup-shadow-x}*/ -1px /*{b-bup-shadow-y}*/ 1px /*{b-bup-shadow-radius}*/ #145072 /*{b-bup-shadow-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#5f9cc5 /*{b-bup-background-start}*/), to(#396b9e /*{b-bup-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #5f9cc5 /*{b-bup-background-start}*/, #396b9e /*{b-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #5f9cc5 /*{b-bup-background-start}*/, #396b9e /*{b-bup-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #5f9cc5 /*{b-bup-background-start}*/, #396b9e /*{b-bup-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #5f9cc5 /*{b-bup-background-start}*/, #396b9e /*{b-bup-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #5f9cc5 /*{b-bup-background-start}*/, #396b9e /*{b-bup-background-end}*/); | |
} | |
.ui-btn-up-b a.ui-link-inherit { | |
color: #fff /*{b-bup-color}*/; | |
} | |
.ui-btn-hover-b { | |
border: 1px solid #00516e /*{b-bhover-border}*/; | |
background: #4b88b6 /*{b-bhover-background-color}*/; | |
font-weight: bold; | |
color: #fff /*{b-bhover-color}*/; | |
text-shadow: 0 /*{b-bhover-shadow-x}*/ -1px /*{b-bhover-shadow-y}*/ 1px /*{b-bhover-shadow-radius}*/ #014D68 /*{b-bhover-shadow-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#72b0d4 /*{b-bhover-background-start}*/), to(#4b88b6 /*{b-bhover-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #72b0d4 /*{b-bhover-background-start}*/, #4b88b6 /*{b-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #72b0d4 /*{b-bhover-background-start}*/, #4b88b6 /*{b-bhover-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #72b0d4 /*{b-bhover-background-start}*/, #4b88b6 /*{b-bhover-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #72b0d4 /*{b-bhover-background-start}*/, #4b88b6 /*{b-bhover-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #72b0d4 /*{b-bhover-background-start}*/, #4b88b6 /*{b-bhover-background-end}*/); | |
} | |
.ui-btn-hover-b a.ui-link-inherit { | |
color: #fff /*{b-bhover-color}*/; | |
} | |
.ui-btn-down-b { | |
border: 1px solid #225377 /*{b-bdown-border}*/; | |
background: #4e89c5 /*{b-bdown-background-color}*/; | |
font-weight: bold; | |
color: #fff /*{b-bdown-color}*/; | |
text-shadow: 0 /*{b-bdown-shadow-x}*/ -1px /*{b-bdown-shadow-y}*/ 1px /*{b-bdown-shadow-radius}*/ #225377 /*{b-bdown-shadow-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#396b9e /*{b-bdown-background-start}*/), to(#4e89c5 /*{b-bdown-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #396b9e /*{b-bdown-background-start}*/, #4e89c5 /*{b-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #396b9e /*{b-bdown-background-start}*/, #4e89c5 /*{b-bdown-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #396b9e /*{b-bdown-background-start}*/, #4e89c5 /*{b-bdown-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #396b9e /*{b-bdown-background-start}*/, #4e89c5 /*{b-bdown-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #396b9e /*{b-bdown-background-start}*/, #4e89c5 /*{b-bdown-background-end}*/); | |
} | |
.ui-btn-down-b a.ui-link-inherit { | |
color: #fff /*{b-bdown-color}*/; | |
} | |
.ui-btn-up-b, | |
.ui-btn-hover-b, | |
.ui-btn-down-b { | |
font-family: Helvetica, Arial, sans-serif /*{b-button-font}*/; | |
text-decoration: none; | |
} | |
/* C | |
-----------------------------------------------------------------------------------------------------------*/ | |
.ui-bar-c { | |
border: 1px solid #B3B3B3 /*{c-bar-border}*/; | |
background: #e9eaeb /*{c-bar-background-color}*/; | |
color: #3E3E3E /*{c-bar-color}*/; | |
font-weight: bold; | |
text-shadow: 0 /*{c-bar-shadow-x}*/ 1px /*{c-bar-shadow-y}*/ 1px /*{c-bar-shadow-radius}*/ #fff /*{c-bar-shadow-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#f0f0f0 /*{c-bar-background-start}*/), to(#e9eaeb /*{c-bar-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #f0f0f0 /*{c-bar-background-start}*/, #e9eaeb /*{c-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #f0f0f0 /*{c-bar-background-start}*/, #e9eaeb /*{c-bar-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #f0f0f0 /*{c-bar-background-start}*/, #e9eaeb /*{c-bar-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #f0f0f0 /*{c-bar-background-start}*/, #e9eaeb /*{c-bar-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #f0f0f0 /*{c-bar-background-start}*/, #e9eaeb /*{c-bar-background-end}*/); | |
} | |
.ui-bar-c .ui-link { | |
color: #2489CE /*{global-link-color}*/; | |
font-weight: bold; | |
} | |
.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 /*{c-bar-font}*/; | |
} | |
.ui-body-c { | |
border: 1px solid #B3B3B3 /*{c-body-border}*/; | |
color: #333333 /*{c-body-color}*/; | |
text-shadow: 0 /*{c-body-shadow-x}*/ 1px /*{c-body-shadow-y}*/ 0 /*{c-body-shadow-radius}*/ #fff /*{c-body-shadow-color}*/; | |
background: #f0f0f0 /*{c-body-background-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#eee /*{c-body-background-start}*/), to(#ddd /*{c-body-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #eee /*{c-body-background-start}*/, #ddd /*{c-body-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #eee /*{c-body-background-start}*/, #ddd /*{c-body-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #eee /*{c-body-background-start}*/, #ddd /*{c-body-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #eee /*{c-body-background-start}*/, #ddd /*{c-body-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #eee /*{c-body-background-start}*/, #ddd /*{c-body-background-end}*/); | |
} | |
.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 /*{c-body-font}*/; | |
} | |
.ui-body-c .ui-link-inherit { | |
color: #333333 /*{c-body-color}*/; | |
} | |
.ui-body-c .ui-link { | |
color: #2489CE /*{global-link-color}*/; | |
font-weight: bold; | |
} | |
.ui-btn-up-c { | |
border: 1px solid #ccc /*{c-bup-border}*/; | |
background: #eee /*{c-bup-background-color}*/; | |
font-weight: bold; | |
color: #444 /*{c-bup-color}*/; | |
text-shadow: 0 /*{c-bup-shadow-x}*/ 1px /*{c-bup-shadow-y}*/ 1px /*{c-bup-shadow-radius}*/ #f6f6f6 /*{c-bup-shadow-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#fdfdfd /*{c-bup-background-start}*/), to(#eee /*{c-bup-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #fdfdfd /*{c-bup-background-start}*/, #eee /*{c-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #fdfdfd /*{c-bup-background-start}*/, #eee /*{c-bup-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #fdfdfd /*{c-bup-background-start}*/, #eee /*{c-bup-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #fdfdfd /*{c-bup-background-start}*/, #eee /*{c-bup-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #fdfdfd /*{c-bup-background-start}*/, #eee /*{c-bup-background-end}*/); | |
} | |
.ui-btn-up-c a.ui-link-inherit { | |
color: #2F3E46 /*{c-bup-color}*/; | |
} | |
.ui-btn-hover-c { | |
border: 1px solid #bbb /*{c-bhover-border}*/; | |
background: #dadada /*{c-bhover-background-color}*/; | |
font-weight: bold; | |
color: #101010 /*{c-bhover-color}*/; | |
text-shadow: 0 /*{c-bhover-shadow-x}*/ 1px /*{c-bhover-shadow-y}*/ 1px /*{c-bhover-shadow-radius}*/ #fff /*{c-bhover-shadow-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#ededed /*{c-bhover-background-start}*/), to(#dadada /*{c-bhover-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #ededed /*{c-bhover-background-start}*/, #dadada /*{c-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #ededed /*{c-bhover-background-start}*/, #dadada /*{c-bhover-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #ededed /*{c-bhover-background-start}*/, #dadada /*{c-bhover-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #ededed /*{c-bhover-background-start}*/, #dadada /*{c-bhover-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #ededed /*{c-bhover-background-start}*/, #dadada /*{c-bhover-background-end}*/); | |
} | |
.ui-btn-hover-c a.ui-link-inherit { | |
color: #2F3E46 /*{c-bhover-color}*/; | |
} | |
.ui-btn-down-c { | |
border: 1px solid #808080 /*{c-bdown-border}*/; | |
background: #fdfdfd /*{c-bdown-background-color}*/; | |
font-weight: bold; | |
color: #111111 /*{c-bdown-color}*/; | |
text-shadow: 0 /*{c-bdown-shadow-x}*/ 1px /*{c-bdown-shadow-y}*/ 1px /*{c-bdown-shadow-radius}*/ #ffffff /*{c-bdown-shadow-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#eee /*{c-bdown-background-start}*/), to(#fdfdfd /*{c-bdown-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #eee /*{c-bdown-background-start}*/, #fdfdfd /*{c-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #eee /*{c-bdown-background-start}*/, #fdfdfd /*{c-bdown-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #eee /*{c-bdown-background-start}*/, #fdfdfd /*{c-bdown-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #eee /*{c-bdown-background-start}*/, #fdfdfd /*{c-bdown-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #eee /*{c-bdown-background-start}*/, #fdfdfd /*{c-bdown-background-end}*/); | |
} | |
.ui-btn-down-c a.ui-link-inherit { | |
color: #2F3E46 /*{c-bdown-color}*/; | |
} | |
.ui-btn-up-c, | |
.ui-btn-hover-c, | |
.ui-btn-down-c { | |
font-family: Helvetica, Arial, sans-serif /*{c-button-font}*/; | |
text-decoration: none; | |
} | |
/* D | |
-----------------------------------------------------------------------------------------------------------*/ | |
.ui-bar-d { | |
border: 1px solid #ccc /*{d-bar-border}*/; | |
background: #bbb /*{d-bar-background-color}*/; | |
color: #333 /*{d-bar-color}*/; | |
text-shadow: 0 /*{d-bar-shadow-x}*/ 1px /*{d-bar-shadow-y}*/ 0 /*{d-bar-shadow-radius}*/ #eee /*{d-bar-shadow-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#ddd /*{d-bar-background-start}*/), to(#bbb /*{d-bar-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #ddd /*{d-bar-background-start}*/, #bbb /*{d-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #ddd /*{d-bar-background-start}*/, #bbb /*{d-bar-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #ddd /*{d-bar-background-start}*/, #bbb /*{d-bar-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #ddd /*{d-bar-background-start}*/, #bbb /*{d-bar-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #ddd /*{d-bar-background-start}*/, #bbb /*{d-bar-background-end}*/); | |
} | |
.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 /*{d-bar-font}*/; | |
} | |
.ui-bar-d .ui-link-inherit { | |
color: #333 /*{d-bar-color}*/; | |
} | |
.ui-bar-d .ui-link { | |
color: #2489CE /*{global-link-color}*/; | |
font-weight: bold; | |
} | |
.ui-body-d { | |
border: 1px solid #ccc /*{d-body-border}*/; | |
color: #333333 /*{d-body-color}*/; | |
text-shadow: 0 /*{d-body-shadow-x}*/ 1px /*{d-body-shadow-y}*/ 0 /*{d-body-shadow-radius}*/ #fff /*{d-body-shadow-color}*/; | |
background: #ffffff /*{d-body-background-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#fff /*{d-body-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #fff /*{d-body-background-start}*/, #fff /*{d-body-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #fff /*{d-body-background-start}*/, #fff /*{d-body-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #fff /*{d-body-background-start}*/, #fff /*{d-body-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #fff /*{d-body-background-start}*/, #fff /*{d-body-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #fff /*{d-body-background-start}*/, #fff /*{d-body-background-end}*/); | |
} | |
.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 /*{d-body-font}*/; | |
} | |
.ui-body-d .ui-link-inherit { | |
color: #333333 /*{d-body-color}*/; | |
} | |
.ui-body-d .ui-link { | |
color: #2489CE /*{global-link-color}*/; | |
font-weight: bold; | |
} | |
.ui-btn-up-d { | |
border: 1px solid #ccc /*{d-bup-border}*/; | |
background: #fff /*{d-bup-background-color}*/; | |
font-weight: bold; | |
color: #444 /*{d-bup-color}*/; | |
text-shadow: 0 /*{d-bup-shadow-x}*/ 1px /*{d-bup-shadow-y}*/ 1px /*{d-bup-shadow-radius}*/ #fff /*{d-bup-shadow-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#fff /*{d-bup-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #fff /*{d-bup-background-start}*/, #fff /*{d-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #fff /*{d-bup-background-start}*/, #fff /*{d-bup-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #fff /*{d-bup-background-start}*/, #fff /*{d-bup-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #fff /*{d-bup-background-start}*/, #fff /*{d-bup-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #fff /*{d-bup-background-start}*/, #fff /*{d-bup-background-end}*/); | |
} | |
.ui-btn-up-d a.ui-link-inherit { | |
color: #333 /*{d-bup-color}*/; | |
} | |
.ui-btn-hover-d { | |
border: 1px solid #aaa /*{d-bhover-border}*/; | |
background: #eeeeee /*{d-bhover-background-color}*/; | |
font-weight: bold; | |
color: #222 /*{d-bhover-color}*/; | |
cursor: pointer; | |
text-shadow: 0 /*{d-bhover-shadow-x}*/ 1px /*{d-bhover-shadow-y}*/ 1px /*{d-bhover-shadow-radius}*/ #fff /*{d-bhover-shadow-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#fdfdfd), to(#eee /*{d-bhover-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #fdfdfd /*{d-bhover-background-start}*/, #eee /*{d-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #fdfdfd /*{d-bhover-background-start}*/, #eee /*{d-bhover-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #fdfdfd /*{d-bhover-background-start}*/, #eee /*{d-bhover-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #fdfdfd /*{d-bhover-background-start}*/, #eee /*{d-bhover-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #fdfdfd /*{d-bhover-background-start}*/, #eee /*{d-bhover-background-end}*/); | |
} | |
.ui-btn-hover-d a.ui-link-inherit { | |
color: #222 /*{d-bhover-color}*/; | |
} | |
.ui-btn-down-d { | |
border: 1px solid #aaaaaa /*{d-bdown-border}*/; | |
background: #ffffff /*{d-bdown-background-color}*/; | |
font-weight: bold; | |
color: #111 /*{d-bdown-color}*/; | |
text-shadow: 0 /*{d-bdown-shadow-x}*/ 1px /*{d-bdown-shadow-y}*/ 1px /*{d-bdown-shadow-radius}*/ #ffffff /*{d-bdown-shadow-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#eee /*{d-bdown-background-start}*/), to(#fff /*{d-bdown-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #eee /*{d-bdown-background-start}*/, #fff /*{d-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #eee /*{d-bdown-background-start}*/, #fff /*{d-bdown-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #eee /*{d-bdown-background-start}*/, #fff /*{d-bdown-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #eee /*{d-bdown-background-start}*/, #fff /*{d-bdown-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #eee /*{d-bdown-background-start}*/, #fff /*{d-bdown-background-end}*/); | |
} | |
.ui-btn-down-d a.ui-link-inherit { | |
color: #111 /*{d-bdown-color}*/; | |
} | |
.ui-btn-up-d, | |
.ui-btn-hover-d, | |
.ui-btn-down-d { | |
font-family: Helvetica, Arial, sans-serif /*{d-button-font}*/; | |
text-decoration: none; | |
} | |
/* E | |
-----------------------------------------------------------------------------------------------------------*/ | |
.ui-bar-e { | |
border: 1px solid #F7C942 /*{e-bar-border}*/; | |
background: #fadb4e /*{e-bar-background-color}*/; | |
color: #333 /*{e-bar-color}*/; | |
text-shadow: 0 /*{e-bar-shadow-x}*/ 1px /*{e-bar-shadow-y}*/ 0 /*{e-bar-shadow-radius}*/ #fff /*{e-bar-shadow-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#fceda7 /*{e-bar-background-start}*/), to(#fadb4e /*{e-bar-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #fceda7 /*{e-bar-background-start}*/, #fadb4e /*{e-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #fceda7 /*{e-bar-background-start}*/, #fadb4e /*{e-bar-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #fceda7 /*{e-bar-background-start}*/, #fadb4e /*{e-bar-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #fceda7 /*{e-bar-background-start}*/, #fadb4e /*{e-bar-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #fceda7 /*{e-bar-background-start}*/, #fadb4e /*{e-bar-background-end}*/); | |
} | |
.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 /*{e-bar-font}*/; | |
} | |
.ui-bar-e .ui-link-inherit { | |
color: #333 /*{e-bar-color}*/; | |
} | |
.ui-bar-e .ui-link { | |
color: #2489CE /*{global-link-color}*/; | |
font-weight: bold; | |
} | |
.ui-body-e { | |
border: 1px solid #F7C942 /*{e-body-border}*/; | |
color: #333333 /*{e-body-color}*/; | |
text-shadow: 0 /*{e-body-shadow-x}*/ 1px /*{e-body-shadow-y}*/ 0 /*{e-body-shadow-radius}*/ #fff /*{e-body-shadow-color}*/; | |
background: #faeb9e /*{e-body-background-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff /*{e-body-background-start}*/), to(#faeb9e /*{e-body-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #fff /*{e-body-background-start}*/, #faeb9e /*{e-body-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #fff /*{e-body-background-start}*/, #faeb9e /*{e-body-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #fff /*{e-body-background-start}*/, #faeb9e /*{e-body-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #fff /*{e-body-background-start}*/, #faeb9e /*{e-body-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #fff /*{e-body-background-start}*/, #faeb9e /*{e-body-background-end}*/); | |
} | |
.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 /*{e-body-font}*/; | |
} | |
.ui-body-e .ui-link-inherit { | |
color: #333333 /*{e-body-color}*/; | |
} | |
.ui-body-e .ui-link { | |
color: #2489CE /*{global-link-color}*/; | |
font-weight: bold; | |
} | |
.ui-btn-up-e { | |
border: 1px solid #F7C942 /*{e-bup-border}*/; | |
background: #fadb4e /*{e-bup-background-color}*/; | |
font-weight: bold; | |
color: #333 /*{e-bup-color}*/; | |
text-shadow: 0 /*{e-bup-shadow-x}*/ 1px /*{e-bup-shadow-y}*/ 0 /*{e-bup-shadow-radius}*/ #fff /*{e-bup-shadow-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#fceda7 /*{e-bup-background-start}*/), to(#fadb4e /*{e-bup-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #fceda7 /*{e-bup-background-start}*/, #fadb4e /*{e-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #fceda7 /*{e-bup-background-start}*/, #fadb4e /*{e-bup-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #fceda7 /*{e-bup-background-start}*/, #fadb4e /*{e-bup-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #fceda7 /*{e-bup-background-start}*/, #fadb4e /*{e-bup-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #fceda7 /*{e-bup-background-start}*/, #fadb4e /*{e-bup-background-end}*/); | |
} | |
.ui-btn-up-e a.ui-link-inherit { | |
color: #333 /*{e-bup-color}*/; | |
} | |
.ui-btn-hover-e { | |
border: 1px solid #e79952 /*{e-bhover-border}*/; | |
background: #fbe26f /*{e-bhover-background-color}*/; | |
font-weight: bold; | |
color: #111 /*{e-bhover-color}*/; | |
text-shadow: 0 /*{e-bhover-shadow-x}*/ 1px /*{e-bhover-shadow-y}*/ 1px /*{e-bhover-shadow-radius}*/ #fff /*{e-bhover-shadow-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf0b5 /*{e-bhover-background-start}*/), to(#fbe26f /*{e-bhover-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #fcf0b5 /*{e-bhover-background-start}*/, #fbe26f /*{e-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #fcf0b5 /*{e-bhover-background-start}*/, #fbe26f /*{e-bhover-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #fcf0b5 /*{e-bhover-background-start}*/, #fbe26f /*{e-bhover-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #fcf0b5 /*{e-bhover-background-start}*/, #fbe26f /*{e-bhover-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #fcf0b5 /*{e-bhover-background-start}*/, #fbe26f /*{e-bhover-background-end}*/); | |
} | |
.ui-btn-hover-e a.ui-link-inherit { | |
color: #333 /*{e-bhover-color}*/; | |
} | |
.ui-btn-down-e { | |
border: 1px solid #F7C942 /*{e-bdown-border}*/; | |
background: #fceda7 /*{e-bdown-background-color}*/; | |
font-weight: bold; | |
color: #111 /*{e-bdown-color}*/; | |
text-shadow: 0 /*{e-bdown-shadow-x}*/ 1px /*{e-bdown-shadow-y}*/ 1px /*{e-bdown-shadow-radius}*/ #ffffff /*{e-bdown-shadow-color}*/; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#fadb4e /*{e-bdown-background-start}*/), to(#fceda7 /*{e-bdown-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #fadb4e /*{e-bdown-background-start}*/, #fceda7 /*{e-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #fadb4e /*{e-bdown-background-start}*/, #fceda7 /*{e-bdown-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #fadb4e /*{e-bdown-background-start}*/, #fceda7 /*{e-bdown-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #fadb4e /*{e-bdown-background-start}*/, #fceda7 /*{e-bdown-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #fadb4e /*{e-bdown-background-start}*/, #fceda7 /*{e-bdown-background-end}*/); | |
} | |
.ui-btn-down-e a.ui-link-inherit { | |
color: #333 /*{e-bdown-color}*/; | |
} | |
.ui-btn-up-e, | |
.ui-btn-hover-e, | |
.ui-btn-down-e { | |
font-family: Helvetica, Arial, sans-serif /*{e-button-font}*/; | |
text-decoration: none; | |
} | |
/* Structure */ | |
/* links within "buttons" | |
-----------------------------------------------------------------------------------------------------------*/ | |
a.ui-link-inherit { | |
text-decoration: none !important; | |
} | |
/* links and their different states | |
-----------------------------------------------------------------------------------------------------------*/ | |
.ui-link{ | |
color: #2489CE /*{global-link-color}*/ | |
} | |
.ui-link:hover{ | |
color: #2489CE /*{global-link-hover}*/ | |
} | |
.ui-link:active{ | |
color: #2489CE /*{global-link-active}*/ | |
} | |
.ui-link:visited{ | |
color: #2489CE /*{global-link-visited}*/ | |
} | |
/* Active class used as the "on" state across all themes | |
-----------------------------------------------------------------------------------------------------------*/ | |
.ui-btn-active { | |
border: 1px solid #155678 /*{global-active-border}*/; | |
background: #4596ce /*{global-active-background-color}*/; | |
font-weight: bold; | |
color: #fff /*{global-active-color}*/; | |
cursor: pointer; | |
text-shadow: 0 /*{global-active-shadow-x}*/ -1px /*{global-active-shadow-y}*/ 1px /*{global-active-shadow-radius}*/ #145072 /*{global-active-shadow-color}*/; | |
text-decoration: none; | |
background-image: -webkit-gradient(linear, left top, left bottom, from(#85bae4 /*{global-active-background-start}*/), to(#5393c5 /*{global-active-background-end}*/)); /* Saf4+, Chrome */ | |
background-image: -webkit-linear-gradient(top, #85bae4 /*{global-active-background-start}*/, #5393c5 /*{global-active-background-end}*/); /* Chrome 10+, Saf5.1+ */ | |
background-image: -moz-linear-gradient(top, #85bae4 /*{global-active-background-start}*/, #5393c5 /*{global-active-background-end}*/); /* FF3.6 */ | |
background-image: -ms-linear-gradient(top, #85bae4 /*{global-active-background-start}*/, #5393c5 /*{global-active-background-end}*/); /* IE10 */ | |
background-image: -o-linear-gradient(top, #85bae4 /*{global-active-background-start}*/, #5393c5 /*{global-active-background-end}*/); /* Opera 11.10+ */ | |
background-image: linear-gradient(top, #85bae4 /*{global-active-background-start}*/, #5393c5 /*{global-active-background-end}*/); | |
outline: none; | |
font-family: Helvetica, Arial, sans-serif /*{global-active-font}*/; | |
} | |
.ui-btn-active a.ui-link-inherit { | |
color: #fff /*{global-active-color}*/; | |
} | |
/* 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 /*{global-radii-blocks}*/; | |
-webkit-border-top-left-radius: .6em /*{global-radii-blocks}*/; | |
border-top-left-radius: .6em /*{global-radii-blocks}*/; | |
} | |
.ui-corner-tr { | |
-moz-border-radius-topright: .6em /*{global-radii-blocks}*/; | |
-webkit-border-top-right-radius: .6em /*{global-radii-blocks}*/; | |
border-top-right-radius: .6em /*{global-radii-blocks}*/; | |
} | |
.ui-corner-bl { | |
-moz-border-radius-bottomleft: .6em /*{global-radii-blocks}*/; | |
-webkit-border-bottom-left-radius: .6em /*{global-radii-blocks}*/; | |
border-bottom-left-radius: .6em /*{global-radii-blocks}*/; | |
} | |
.ui-corner-br { | |
-moz-border-radius-bottomright: .6em /*{global-radii-blocks}*/; | |
-webkit-border-bottom-right-radius: .6em /*{global-radii-blocks}*/; | |
border-bottom-right-radius: .6em /*{global-radii-blocks}*/; | |
} | |
.ui-corner-top { | |
-moz-border-radius-topleft: .6em /*{global-radii-blocks}*/; | |
-webkit-border-top-left-radius: .6em /*{global-radii-blocks}*/; | |
border-top-left-radius: .6em /*{global-radii-blocks}*/; | |
-moz-border-radius-topright: .6em /*{global-radii-blocks}*/; | |
-webkit-border-top-right-radius: .6em /*{global-radii-blocks}*/; | |
border-top-right-radius: .6em /*{global-radii-blocks}*/; | |
} | |
.ui-corner-bottom { | |
-moz-border-radius-bottomleft: .6em /*{global-radii-blocks}*/; | |
-webkit-border-bottom-left-radius: .6em /*{global-radii-blocks}*/; | |
border-bottom-left-radius: .6em /*{global-radii-blocks}*/; | |
-moz-border-radius-bottomright: .6em /*{global-radii-blocks}*/; | |
-webkit-border-bottom-right-radius: .6em /*{global-radii-blocks}*/; | |
border-bottom-right-radius: .6em /*{global-radii-blocks}*/; | |
} | |
.ui-corner-right { | |
-moz-border-radius-topright: .6em /*{global-radii-blocks}*/; | |
-webkit-border-top-right-radius: .6em /*{global-radii-blocks}*/; | |
border-top-right-radius: .6em /*{global-radii-blocks}*/; | |
-moz-border-radius-bottomright: .6em /*{global-radii-blocks}*/; | |
-webkit-border-bottom-right-radius: .6em /*{global-radii-blocks}*/; | |
border-bottom-right-radius: .6em /*{global-radii-blocks}*/; | |
} | |
.ui-corner-left { | |
-moz-border-radius-topleft: .6em /*{global-radii-blocks}*/; | |
-webkit-border-top-left-radius: .6em /*{global-radii-blocks}*/; | |
border-top-left-radius: .6em /*{global-radii-blocks}*/; | |
-moz-border-radius-bottomleft: .6em /*{global-radii-blocks}*/; | |
-webkit-border-bottom-left-radius: .6em /*{global-radii-blocks}*/; | |
border-bottom-left-radius: .6em /*{global-radii-blocks}*/; | |
} | |
.ui-corner-all { | |
-moz-border-radius: .6em /*{global-radii-blocks}*/; | |
-webkit-border-radius: .6em /*{global-radii-blocks}*/; | |
border-radius: .6em /*{global-radii-blocks}*/; | |
} | |
.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, | |
.ui-icon-searchfield:after { | |
background: #666 /*{global-icon-color}*/; | |
background: rgba(0,0,0,.4) /*{global-icon-disc}*/; | |
background-image: url(images/icons-18-white.png) /*{global-icon-set}*/; | |
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-searchfield:after, | |
.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, | |
.ui-icon-searchfield:after { | |
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 /*{global-active-background-color}*/; /* NOTE: this hex should match the active state color. It's repeated here for cascade */ | |
} | |
/* 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 /*{global-radii-buttons}*/; | |
-webkit-border-top-left-radius: 1em /*{global-radii-buttons}*/; | |
border-top-left-radius: 1em /*{global-radii-buttons}*/; | |
} | |
.ui-btn-corner-tr { | |
-moz-border-radius-topright: 1em /*{global-radii-buttons}*/; | |
-webkit-border-top-right-radius: 1em /*{global-radii-buttons}*/; | |
border-top-right-radius: 1em /*{global-radii-buttons}*/; | |
} | |
.ui-btn-corner-bl { | |
-moz-border-radius-bottomleft: 1em /*{global-radii-buttons}*/; | |
-webkit-border-bottom-left-radius: 1em /*{global-radii-buttons}*/; | |
border-bottom-left-radius: 1em /*{global-radii-buttons}*/; | |
} | |
.ui-btn-corner-br { | |
-moz-border-radius-bottomright: 1em /*{global-radii-buttons}*/; | |
-webkit-border-bottom-right-radius: 1em /*{global-radii-buttons}*/; | |
border-bottom-right-radius: 1em /*{global-radii-buttons}*/; | |
} | |
.ui-btn-corner-top { | |
-moz-border-radius-topleft: 1em /*{global-radii-buttons}*/; | |
-webkit-border-top-left-radius: 1em /*{global-radii-buttons}*/; | |
border-top-left-radius: 1em /*{global-radii-buttons}*/; | |
-moz-border-radius-topright: 1em /*{global-radii-buttons}*/; | |
-webkit-border-top-right-radius: 1em /*{global-radii-buttons}*/; | |
border-top-right-radius: 1em /*{global-radii-buttons}*/; | |
} | |
.ui-btn-corner-bottom { | |
-moz-border-radius-bottomleft: 1em /*{global-radii-buttons}*/; | |
-webkit-border-bottom-left-radius: 1em /*{global-radii-buttons}*/; | |
border-bottom-left-radius: 1em /*{global-radii-buttons}*/; | |
-moz-border-radius-bottomright: 1em /*{global-radii-buttons}*/; | |
-webkit-border-bottom-right-radius: 1em /*{global-radii-buttons}*/; | |
border-bottom-right-radius: 1em /*{global-radii-buttons}*/; | |
} | |
.ui-btn-corner-right { | |
-moz-border-radius-topright: 1em /*{global-radii-buttons}*/; | |
-webkit-border-top-right-radius: 1em /*{global-radii-buttons}*/; | |
border-top-right-radius: 1em /*{global-radii-buttons}*/; | |
-moz-border-radius-bottomright: 1em /*{global-radii-buttons}*/; | |
-webkit-border-bottom-right-radius: 1em /*{global-radii-buttons}*/; | |
border-bottom-right-radius: 1em /*{global-radii-buttons}*/; | |
} | |
.ui-btn-corner-left { | |
-moz-border-radius-topleft: 1em /*{global-radii-buttons}*/; | |
-webkit-border-top-left-radius: 1em /*{global-radii-buttons}*/; | |
border-top-left-radius: 1em /*{global-radii-buttons}*/; | |
-moz-border-radius-bottomleft: 1em /*{global-radii-buttons}*/; | |
-webkit-border-bottom-left-radius: 1em /*{global-radii-buttons}*/; | |
border-bottom-left-radius: 1em /*{global-radii-buttons}*/; | |
} | |
.ui-btn-corner-all { | |
-moz-border-radius: 1em /*{global-radii-buttons}*/; | |
-webkit-border-radius: 1em /*{global-radii-buttons}*/; | |
border-radius: 1em /*{global-radii-buttons}*/; | |
} | |
/* 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 /*{global-box-shadow-size}*/ rgba(0,0,0,.3) /*{global-box-shadow-color}*/; | |
-webkit-box-shadow: 0px 1px 4px /*{global-box-shadow-size}*/ rgba(0,0,0,.3) /*{global-box-shadow-color}*/; | |
box-shadow: 0px 1px 4px /*{global-box-shadow-size}*/ rgba(0,0,0,.3) /*{global-box-shadow-color}*/; | |
} | |
.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 /*{global-active-background-color}*/; | |
-webkit-box-shadow: 0px 0px 12px #387bbe /*{global-active-background-color}*/; | |
box-shadow: 0px 0px 12px #387bbe /*{global-active-background-color}*/; | |
} | |
/* 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; } | |
/* on ios4, setting focus on the page element causes flashing during transitions when there is an outline, so we turn off outlines */ | |
.ui-page { outline: none; } | |
/* 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-touch-overflow, | |
.ui-page.ui-mobile-touch-overflow * { | |
/* some level of transform keeps elements from blinking out of visibility on iOS */ | |
-webkit-transform: rotateY(0); | |
} | |
.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.out { | |
-webkit-transform: translateX(-100%); | |
-webkit-animation-name: slideouttoleft; | |
} | |
.slide.in { | |
-webkit-transform: translateX(0); | |
-webkit-animation-name: slideinfromright; | |
} | |
.slide.out.reverse { | |
-webkit-transform: translateX(100%); | |
-webkit-animation-name: slideouttoright; | |
} | |
.slide.in.reverse { | |
-webkit-transform: translateX(0); | |
-webkit-animation-name: slideinfromleft; | |
} | |
.slideup.out { | |
-webkit-animation-name: dontmove; | |
z-index: 0; | |
} | |
.slideup.in { | |
-webkit-transform: translateY(0); | |
-webkit-animation-name: slideinfrombottom; | |
z-index: 10; | |
} | |
.slideup.in.reverse { | |
z-index: 0; | |
-webkit-animation-name: dontmove; | |
} | |
.slideup.out.reverse { | |
-webkit-transform: translateY(100%); | |
z-index: 10; | |
-webkit-animation-name: slideouttobottom; | |
} | |
.slidedown.out { | |
-webkit-animation-name: dontmove; | |
z-index: 0; | |
} | |
.slidedown.in { | |
-webkit-transform: translateY(0); | |
-webkit-animation-name: slideinfromtop; | |
z-index: 10; | |
} | |
.slidedown.in.reverse { | |
z-index: 0; | |
-webkit-animation-name: dontmove; | |
} | |
.slidedown.out.reverse { | |
-webkit-transform: translateY(-100%); | |
z-index: 10; | |
-webkit-animation-name: slideouttotop; | |
} | |
@-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.out { | |
z-index: 0; | |
-webkit-animation-name: fadeout; | |
} | |
.fade.in { | |
opacity: 1; | |
z-index: 10; | |
-webkit-animation-name: fadein; | |
} | |
/* 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.out { | |
-webkit-transform: rotateY(-180deg) scale(.8); | |
-webkit-animation-name: flipouttoleft; | |
} | |
.flip.in { | |
-webkit-transform: rotateY(0) scale(1); | |
-webkit-animation-name: flipinfromleft; | |
} | |
/* Shake it all about */ | |
.flip.out.reverse { | |
-webkit-transform: rotateY(180deg) scale(.8); | |
-webkit-animation-name: flipouttoright; | |
} | |
.flip.in.reverse { | |
-webkit-transform: rotateY(0) scale(1); | |
-webkit-animation-name: flipinfromright; | |
} | |
@-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.in.reverse { | |
z-index: 0; | |
-webkit-animation-name: dontmove; | |
} | |
.pop.out.reverse { | |
-webkit-transform: scale(.2); | |
opacity: 0; | |
-webkit-animation-name: popout; | |
z-index: 10; | |
} | |
@-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 { width: 24px; height: 24px; } | |
.ui-btn-icon-notext .ui-btn-inner { padding: 2px 1px 2px 3px; } | |
.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-btn-icon-top .ui-icon { top: 10px; } | |
.ui-btn-icon-bottom .ui-icon { bottom: 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; } | |
/*hiding native button,inputs */ | |
.ui-btn-hidden { position: absolute; top: 0; left: 0; width: 100%; height: 100%; -webkit-appearance: button; opacity: .1; cursor: pointer; background: transparent; font-size: 1px; border: none; line-height: 999px; } | |
/* | |
* jQuery Mobile Framework | |
* Copyright (c) jQuery Project | |
* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses. | |
*/ | |
.ui-collapsible { 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; | |
margin: 0 -8px; | |
padding: 10px 16px; | |
border-top: none; /* Overrides ui-btn-up-* */ | |
background-image: none; /* Overrides ui-btn-up-* */ | |
font-weight: normal; /* Overrides ui-btn-up-* */ | |
} | |
.ui-collapsible-content-collapsed { display: none; } | |
.ui-collapsible-set { margin: .5em 0; } | |
.ui-collapsible-set .ui-collapsible { 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 { display: inline-block; margin: 0 -5px 0 0; } | |
.ui-controlgroup-horizontal .ui-checkbox, .ui-controlgroup-horizontal .ui-radio { float: left; margin: 0 -1px 0 0; } | |
.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%; min-height: 1.5em; min-height: 100%; height: 3em; max-height: 100%; opacity: 0; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter: alpha(opacity=0); z-index: 2; } | |
@-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 { vertical-align: top; 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-image: none; position: relative; } | |
.ui-icon-searchfield:after { position: absolute; left: 7px; top: 50%; margin-top: -9px; content: ""; width: 18px; height: 18px; opacity: .5; } | |
.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 { position: relative; z-index: 1; } | |
.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-has-count .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; z-index: 2; } | |
.ui-li-link-alt .ui-btn { overflow: hidden; position: absolute; right: 8px; top: 50%; margin: -11px 0 0 0; border-bottom-width: 1px; z-index: -1;} | |
.ui-li-link-alt .ui-btn-inner { padding: 0; height: 100%; position: absolute; width: 100%; top: 0; left: 0;} | |
.ui-li-link-alt .ui-btn .ui-icon { right: 50%; margin-right: -9px; } | |
.ui-listview * .ui-btn-inner > .ui-btn > .ui-btn-inner { border-top: 0px; } | |
.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 { vertical-align: top; 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 } | |
<?php | <?php |
header('Content-type: text/css'); | |
ob_start("compress"); | header('Content-type: text/css'); |
function compress($buffer) { | ob_start("compress"); |
function compress($buffer) { | |
/* remove comments */ | /* remove comments */ |
$buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer); | $buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer); |
/* remove tabs, spaces, newlines, etc. */ | /* remove tabs, spaces, newlines, etc. */ |
$buffer = str_replace(array("\r\n", "\r", "\n", "\t", ' ', ' ', ' '), '', $buffer); | $buffer = str_replace(array("\r\n", "\r", "\n", "\t", ' ', ' ', ' '), '', $buffer); |
return $buffer; | return $buffer; |
} | } |
echo ' | echo ' |
.ui-li-thumb, .ui-li-icon { position: relative; } | .ui-li-thumb, .ui-li-icon { position: relative; } |
.ui-navbar { | .ui-navbar { |
width: 100%; | width: 100%; |
} | } |
.ui-btn-inner { | .ui-btn-inner { |
white-space: normal !important; | white-space: normal !important; |
} | } |
.ui-li-heading { | .ui-li-heading { |
white-space: normal !important; | white-space: normal !important; |
} | } |
.ui-listview-filter { | .ui-listview-filter { |
margin: 0 !important; | margin: 0 !important; |
} | } |
.ui-icon-navigation { | .ui-icon-navigation { |
background-image: url(images/113-navigation.png); | background-image: url(images/113-navigation.png); |
background-position: 1px 0; | background-position: 1px 0; |
} | } |
.ui-icon-beaker { | .ui-icon-beaker { |
background-image: url(images/91-beaker-2.png); | background-image: url(images/91-beaker-2.png); |
background-position: 1px 0; | background-position: 1px 0; |
} | } |
#footer { | #footer { |
text-size: 0.75em; | text-size: 0.75em; |
text-align: center; | text-align: center; |
} | } |
body { | body { |
background-color: #F0F0F0; | background-color: #F0F0F0; |
} | } |
#jqm-homeheader { | #jqm-homeheader { |
text-align: center; | text-align: center; |
} | } |
.viaPoints { | .viaPoints { |
display: none; | display: none; |
text-size: 0.2em; | text-size: 0.2em; |
} | } |
.min-width-480px .viaPoints { | .min-width-480px .viaPoints { |
display: inline; | display: inline; |
} | } |
#extrainfo { | #extrainfo { |
visibility: hidden; | visibility: hidden; |
display: none; | display: none; |
} | } |
#servicewarning { | #servicewarning { |
padding: 1em; | padding: 1em; |
margin-bottom: 0.5em; | margin-bottom: 0.5em; |
text-size: 0.2em; | text-size: 0.2em; |
background-color: #FF9; | background-color: #FF9; |
-moz-border-radius: 15px; | -moz-border-radius: 15px; |
border-radius: 15px; | border-radius: 15px; |
} | } |
#footer { | #footer { |
clear:both; | clear:both; |
text-align:center; | text-align:center; |
} | } |
// source http://webaim.org/techniques/skipnav/ | // source http://webaim.org/techniques/skipnav/ |
#skip a, #skip a:hover, #skip a:visited | #skip a, #skip a:hover, #skip a:visited |
{ | { |
position:absolute; | position:absolute; |
left:0px; | left:0px; |
top:-500px; | top:-500px; |
width:1px; | width:1px; |
height:1px; | height:1px; |
overflow:hidden; | overflow:hidden; |
} | } |
#skip a:active, #skip a:focus | #skip a:active, #skip a:focus |
{ | { |
position:static; | position:static; |
width:auto; | width:auto; |
height:auto; | height:auto; |
}'; | }'; |
//if (false) | //if (false) |
echo ' | echo ' |
// adaptive layout from jQuery Mobile docs site | // adaptive layout from jQuery Mobile docs site |
.type-interior .content-secondary { | .type-interior .content-secondary { |
border-right: 0; | border-right: 0; |
border-left: 0; | border-left: 0; |
margin: 10px -15px 0; | margin: 10px -15px 0; |
background: #fff; | background: #fff; |
border-top: 1px solid #ccc; | border-top: 1px solid #ccc; |
} | } |
.type-home .ui-content { | .type-home .ui-content { |
margin-top: 5px; | margin-top: 5px; |
} | } |
.type-interior .ui-content { | .type-interior .ui-content { |
padding-bottom: 0; | padding-bottom: 0; |
} | } |
.content-secondary .ui-collapsible-contain { | .content-secondary .ui-collapsible-contain { |
padding: 10px 15px; | padding: 10px 15px; |
} | } |
.content-secondary .ui-collapsible-heading { | .content-secondary .ui-collapsible-heading { |
margin: 0 0 30px; | margin: 0 0 30px; |
} | } |
.content-secondary .ui-collapsible-heading-collapsed, | .content-secondary .ui-collapsible-heading-collapsed, |
.content-secondary .ui-collapsible-content { | .content-secondary .ui-collapsible-content { |
padding:0; | padding:0; |
margin: 0; | margin: 0; |
} | } |
/* hires ahoy */ | |
@media all and (min-width: 650px){ | @media all and (min-width: 650px){ |
.content-secondary { | .content-secondary { |
text-align: left; | text-align: left; |
float: left; | float: left; |
width: 45%; | width: 45%; |
background: none; | background: none; |
border-top: 0; | border-top: 0; |
} | } |
.content-secondary, | .content-secondary, |
.type-interior .content-secondary { | .type-interior .content-secondary { |
margin: 30px 0 20px 2%; | margin: 30px 0 20px 2%; |
padding: 20px 4% 0 0; | padding: 20px 4% 0 0; |
background: none; | background: none; |
} | } |
.type-index .content-secondary { | .type-index .content-secondary { |
padding: 0; | padding: 0; |
} | } |
.type-index .content-secondary .ui-listview { | .type-index .content-secondary .ui-listview { |
margin: 0; | margin: 0; |
} | } |
.content-primary { | .content-primary { |
width: 45%; | width: 45%; |
float: right; | float: right; |
margin-top: 30px; | margin-top: 30px; |
margin-right: 1%; | margin-right: 1%; |
padding-right: 1%; | padding-right: 1%; |
} | } |
.content-primary ul:first-child { | .content-primary ul:first-child { |
margin-top: 0; | margin-top: 0; |
} | } |
.type-interior .content-primary { | .type-interior .content-primary { |
padding: 1.5em 6% 3em 0; | padding: 1.5em 6% 3em 0; |
margin: 0; | margin: 0; |
} | } |
/* fix up the collapsibles - expanded on desktop */ | /* fix up the collapsibles - expanded on desktop */ |
.content-secondary .ui-collapsible-heading { | .content-secondary .ui-collapsible-heading { |
display: none; | display: none; |
} | } |
.content-secondary .ui-collapsible-contain { | .content-secondary .ui-collapsible-contain { |
margin:0; | margin:0; |
} | } |
.content-secondary .ui-collapsible-content { | .content-secondary .ui-collapsible-content { |
display: block; | display: block; |
margin: 0; | margin: 0; |
padding: 0; | padding: 0; |
} | } |
.type-interior .content-secondary .ui-li-divider { | .type-interior .content-secondary .ui-li-divider { |
padding-top: 1em; | padding-top: 1em; |
padding-bottom: 1em; | padding-bottom: 1em; |
} | } |
.type-interior .content-secondary { | .type-interior .content-secondary { |
margin: 0; | margin: 0; |
padding: 0; | padding: 0; |
} | } |
} | } |
@media all and (min-width: 750px){ | @media all and (min-width: 750px){ |
.type-home .ui-content, | .type-home .ui-content, |
.type-interior .ui-content { | .type-interior .ui-content { |
background-position: 39%; | background-position: 39%; |
} | } |
.content-secondary { | .content-secondary { |
width: 34%; | width: 34%; |
} | } |
.content-primary { | .content-primary { |
width: 56%; | width: 56%; |
padding-right: 1%; | padding-right: 1%; |
} | } |
.type-interior .ui-content { | .type-interior .ui-content { |
background-position: 34%; | background-position: 34%; |
} | } |
} | } |
@media all and (min-width: 1200px){ | @media all and (min-width: 1200px){ |
.type-home .ui-content{ | .type-home .ui-content{ |
background-position: 38.5%; | background-position: 38.5%; |
} | } |
.type-interior .ui-content { | .type-interior .ui-content { |
background-position: 30%; | background-position: 30%; |
} | } |
.content-secondary { | .content-secondary { |
width: 30%; | width: 30%; |
padding-right:6%; | padding-right:6%; |
margin: 30px 0 20px 5%; | margin: 30px 0 20px 5%; |
} | } |
.type-interior .content-secondary { | .type-interior .content-secondary { |
margin: 0; | margin: 0; |
padding: 0; | padding: 0; |
} | } |
.content-primary { | .content-primary { |
width: 50%; | width: 50%; |
margin-right: 5%; | margin-right: 5%; |
padding-right: 3%; | padding-right: 3%; |
} | } |
.type-interior .content-primary { | .type-interior .content-primary { |
width: 60%; | width: 60%; |
} | } |
}'; | } |
ob_end_flush(); | '; |
ob_end_flush(); | |
?> | ?> |
<?php | <?php |
header('Content-Type: application/vnd.google-earth.kml+xml'); | header('Content-Type: application/vnd.google-earth.kml+xml'); |
include ('../include/common.inc.php'); | include ('../include/common.inc.php'); |
echo '<?xml version="1.0" encoding="UTF-8"?> | echo '<?xml version="1.0" encoding="UTF-8"?> |
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom"><Document>'; | <kml xmlns="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom"><Document>'; |
echo ' | echo ' |
<Style id="yellowLineGreenPoly"> | <Style id="yellowLineGreenPoly"> |
<LineStyle> | <LineStyle> |
<color>7f00ff00</color> | <color>7f00ff00</color> |
<width>4</width> | <width>4</width> |
</LineStyle> | </LineStyle> |
<PolyStyle> | <PolyStyle> |
<color>7f00ffff</color> | <color>7f00ffff</color> |
</PolyStyle> | </PolyStyle> |
</Style>'; | </Style>'; |
$route = getRoute($routeid); | $route = getRoute($routeid); |
echo "\n<Placemark>\n"; | echo "\n<Placemark>\n"; |
$link = curPageURL()."/../trip.php?routeid=".htmlspecialchars ($route["route_id"]); | $link = curPageURL()."/../trip.php?routeid=".htmlspecialchars ($route["route_id"]); |
echo "<name>".$route['route_short_name']."</name>"; | echo "<name>".$route['route_short_name']."</name>"; |
echo '<atom:link href="'.$link.'"/>'; | echo '<atom:link href="'.$link.'"/>'; |
echo '<description><![CDATA[ <a href="'.$link.'">'.$route['route_short_name']." ".$route['route_long_name']."</a>]]> </description>"; | echo '<description><![CDATA[ <a href="'.$link.'">'.$route['route_short_name']." ".$route['route_long_name']."</a>]]> </description>"; |
echo "<styleUrl>#yellowLineGreenPoly</styleUrl>"; | echo "<styleUrl>#yellowLineGreenPoly</styleUrl>"; |
$trips = getRouteTrips($routeid); | $trips = getRouteTrips($routeid); |
echo getTripShape($trips[0]['trip_id']); | echo getTripShape($trips[0]['trip_id']); |
echo "</Placemark>\n</Document></kml>\n"; | echo "</Placemark>\n</Document></kml>\n"; |
?> | ?> |
<?php | <?php |
include ('../include/common.inc.php'); | |
header('Content-type: application/vnd.google-earth.kml+xml'); | header('Content-type: application/vnd.google-earth.kml+xml'); |
//http://wiki.openstreetmap.org/wiki/OpenLayers_Dynamic_KML | //http://wiki.openstreetmap.org/wiki/OpenLayers_Dynamic_KML |
// Creates the KML/XML Document. | // Creates the KML/XML Document. |
$dom = new DOMDocument('1.0', 'UTF-8'); | $dom = new DOMDocument('1.0', 'UTF-8'); |
// Creates the root KML element and appends it to the root document. | // Creates the root KML element and appends it to the root document. |
$node = $dom->createElementNS('http://earth.google.com/kml/2.1', 'kml'); | $node = $dom->createElementNS('http://earth.google.com/kml/2.1', 'kml'); |
$parNode = $dom->appendChild($node); | $parNode = $dom->appendChild($node); |
// Creates a KML Document element and append it to the KML element. | // Creates a KML Document element and append it to the KML element. |
$dnode = $dom->createElement('Document'); | $dnode = $dom->createElement('Document'); |
$docNode = $parNode->appendChild($dnode); | $docNode = $parNode->appendChild($dnode); |
if ($suburb != "") $result_stops = getStopsBySuburb($suburb); | if ($suburb != "") $result_stops = getStopsBySuburb($suburb); |
else $result_stops = getStops(); | else $result_stops = getStops(); |
foreach ($result_stops as $stop) { | foreach ($result_stops as $stop) { |
$description = 'http://bus.lambdacomplex.org/' . 'stop.php?stopid=' . $stop['stop_id'] . " <br>"; | $description = 'http://bus.lambdacomplex.org/' . 'stop.php?stopid=' . $stop['stop_id'] . " <br>"; |
// Creates a Placemark and append it to the Document. | // Creates a Placemark and append it to the Document. |
$node = $dom->createElement('Placemark'); | $node = $dom->createElement('Placemark'); |
$placeNode = $docNode->appendChild($node); | $placeNode = $docNode->appendChild($node); |
// Creates an id attribute and assign it the value of id column. | // Creates an id attribute and assign it the value of id column. |
$placeNode->setAttribute('id', 'placemark' . $stop['stop_id']); | $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. | // 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'])); | $nameNode = $dom->createElement('name', htmlentities($stop['stop_name'])); |
$descriptionNode = $dom->createElement('description', $description); | $descriptionNode = $dom->createElement('description', $description); |
$placeNode->appendChild($nameNode); | $placeNode->appendChild($nameNode); |
$placeNode->appendChild($descriptionNode); | $placeNode->appendChild($descriptionNode); |
// Creates a Point element. | // Creates a Point element. |
$pointNode = $dom->createElement('Point'); | $pointNode = $dom->createElement('Point'); |
$placeNode->appendChild($pointNode); | $placeNode->appendChild($pointNode); |
// Creates a coordinates element and gives it the value of the lng and lat columns from the results. | // 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']; | $coorStr = $stop['stop_lon'] . ',' . $stop['stop_lat']; |
$coorNode = $dom->createElement('coordinates', $coorStr); | $coorNode = $dom->createElement('coordinates', $coorStr); |
$pointNode->appendChild($coorNode); | $pointNode->appendChild($coorNode); |
} | } |
$kmlOutput = $dom->saveXML(); | $kmlOutput = $dom->saveXML(); |
echo $kmlOutput; | echo $kmlOutput; |
?> | ?> |
<?php | <?php |
function getScheme() | require $basePath.'lib/openid.php'; |
{ | $openid = new LightOpenID($_SERVER['HTTP_HOST']); |
$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 . $labsPath."lib/openid-php/"); | |
require_once "Auth/OpenID/Consumer.php"; | |
require_once "Auth/OpenID/FileStore.php"; | |
require_once "Auth/OpenID/AX.php"; | |
function login() | function login() |
{ | { |
// Just tested this with/for Google, needs trying with others ... | global $openid; |
$oid_identifier = 'https://www.google.com/accounts/o8/id'; | if(!$openid->mode) { |
// Create file storage area for OpenID data | $openid->required = array('contact/email'); |
$store = new Auth_OpenID_FileStore('lib/openid-php/oid_store'); | $openid->identity = 'https://www.google.com/accounts/o8/id'; |
// Create OpenID consumer | header('Location: ' . $openid->authUrl()); |
$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() | function auth() |
{ | { |
if ($_SESSION['authed'] == true) return true; | if ($_SESSION['authed'] == true) return true; |
global $openid; | |
// Create file storage area for OpenID data | |
$store = new Auth_OpenID_FileStore('lib/openid-php/oid_store'); | if($openid->mode) { |
// Create OpenID consumer | $attr = $openid->getAttributes(); |
$consumer = new Auth_OpenID_Consumer($store); | if ($attr["contact/email"] != "maxious@gmail.com") { |
// 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"); | die("Access Denied"); |
} else { | } else { |
$_SESSION['authed'] = true; | $_SESSION['authed'] = true; |
} | } |
} else { | } else { |
login(); | login(); |
} | } |
} | } |
if ($_REQUEST['janrain_nonce']) auth(); | |
?> | ?> |
<?php | <?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") { | if (php_uname('n') == "actbus-www") { |
$conn = new PDO("pgsql:dbname=transitdata;user=transitdata;password=transitdata;host=bus-main.lambdacomplex.org"); | $conn = new PDO("pgsql:dbname=transitdata;user=transitdata;password=transitdata;host=bus-main.lambdacomplex.org"); |
} | } else if (isDebugServer()) { |
else if (isDebugServer()) { | $conn = new PDO("pgsql:dbname=transitdata;user=postgres;password=snmc;host=localhost"); |
$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"); |
else { | |
$conn = new PDO("pgsql:dbname=transitdata;user=transitdata;password=transitdata;host=localhost"); | |
} | } |
if (!$conn) { | if (!$conn) { |
die("A database error occurred.\n"); | die("A database error occurred.\n"); |
} | } |
function databaseError($errMsg) | |
{ | function databaseError($errMsg) { |
die($errMsg); | die($errMsg); |
} | } |
include ('db/route-dao.inc.php'); | include ('db/route-dao.inc.php'); |
include ('db/trip-dao.inc.php'); | include ('db/trip-dao.inc.php'); |
include ('db/stop-dao.inc.php'); | include ('db/stop-dao.inc.php'); |
include ('db/servicealert-dao.inc.php'); | include ('db/servicealert-dao.inc.php'); |
?> | ?> |
<?php | <?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), ',') | // 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"); | $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) | |
{ | function staticmap($mapPoints, $collapsible = true, $twotone = false, $path = false, $numbered = false) { |
global $labsPath; | |
$width = 300; | $markers = ""; |
$height = 300; | $height = 300; |
$metersperpixel[9] = 305.492 * $width; | $width = $height; |
$metersperpixel[10] = 152.746 * $width; | $index = 0; |
$metersperpixel[11] = 76.373 * $width; | if (sizeof($mapPoints) < 1) |
$metersperpixel[12] = 38.187 * $width; | return "map error"; |
$metersperpixel[13] = 19.093 * $width; | if (sizeof($mapPoints) === 1) { |
$metersperpixel[14] = 9.547 * $width; | $markers = "markers={$mapPoints[0][0]},{$mapPoints[0][1]}"; |
$metersperpixel[15] = 4.773 * $width; | } else { |
//$metersperpixel[16] = 2.387 * $width; | if (!$numbered) { |
// $metersperpixel[17]=1.193*$width; | $markers = "markers="; |
$center = ""; | } |
$markers = ""; | if ($path) { |
$mapwidthinmeters = 50; | $markers.= "markers={$mapPoints[0][0]},{$mapPoints[0][1]}&path="; |
if (sizeof($mapPoints) < 1) return "map error"; | } |
if (sizeof($mapPoints) === 1) { | foreach ($mapPoints as $index => $mapPoint) { |
if ($zoom == 0) $zoom = 14; | if ($twotone && $index == 0) { |
$markers.= "{$mapPoints[0][0]},{$mapPoints[0][1]},$markerimage"; | $markers = "markerd=color:red|".$mapPoint[0] . "," . $mapPoint[1]."&markers="; |
$center = "{$mapPoints[0][0]},{$mapPoints[0][1]}"; | } else { |
} | if ($numbered) { |
else { | $label = ($index > 9 ? 9 : $index); |
foreach ($mapPoints as $index => $mapPoint) { | $markers.= "markers=label:$label|" . $mapPoint[0] . "," . $mapPoint[1]; |
if ($twotone && $index == 0) { | if ($index + 1 != sizeof($mapPoints)) { |
$markers.= $mapPoint[0] . "," . $mapPoint[1] . "," . "iconr" . ($index + 1); | $markers.= "&"; |
$center = "{$mapPoints[0][0]},{$mapPoints[0][1]}"; | } |
} | } else { |
else { | $markers.= $mapPoint[0] . "," . $mapPoint[1]; |
$markers.= $mapPoint[0] . "," . $mapPoint[1] . "," . $markerImage . ($index + 1); | if ($index + 1 != sizeof($mapPoints)) { |
} | $markers.= "|"; |
if ($index + 1 != sizeof($mapPoints)) $markers.= "|"; | } |
$dist = distance($mapPoints[0][0], $mapPoint[0][1], $mapPoint[0], $mapPoint[1]); | } |
$mapwidthinmeters = ($dist > $mapwidthinmeters ? $dist : $mapwidthinmeters); | $index++; |
$totalLat+= $mapPoint[0]; | } |
$totalLon+= $mapPoint[1]; | } |
} | } |
if ($zoom == 0) { | $output = ""; |
$mapwidthinmeters = distance($minlat, $minlon, $minlat, $maxlon); | if ($collapsible) |
foreach (array_reverse($metersperpixel, true) as $zoomLevel => $maxdistance) { | $output.= '<div class="map" data-role="collapsible" data-collapsed="true"><h3>Open Map...</h3>'; |
if ($zoom == 0 && $mapwidthinmeters * 1.5 < ($maxdistance)) $zoom = $zoomLevel; | if (isIOSDevice()) $output.= '<img class="hiresmap" src="http://maps.googleapis.com/maps/api/staticmap?size=' . $width . 'x' . $height . '&' . $markers . '&scale=2&sensor=true" width=' . $width . ' height=' . $height . '>'; |
} | else $output.= '<img class="lowresmap" src="http://maps.googleapis.com/maps/api/staticmap?size=' . $width . 'x' . $height . '&' . $markers . '&scale=1&format=jpg&sensor=true" width=' . $width . ' height=' . $height . '>'; |
} | |
$center = $totalLat / sizeof($mapPoints) . "," . $totalLon / sizeof($mapPoints); | if ($collapsible) |
} | $output.= '</div>'; |
$output = ""; | return $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 distance($lat1, $lng1, $lat2, $lng2, $roundLargeValues = false) | |
{ | function distance($lat1, $lng1, $lat2, $lng2, $roundLargeValues = false) { |
$pi80 = M_PI / 180; | $pi80 = M_PI / 180; |
$lat1*= $pi80; | $lat1*= $pi80; |
$lng1*= $pi80; | $lng1*= $pi80; |
$lat2*= $pi80; | $lat2*= $pi80; |
$lng2*= $pi80; | $lng2*= $pi80; |
$r = 6372.797; // mean radius of Earth in km | $r = 6372.797; // mean radius of Earth in km |
$dlat = $lat2 - $lat1; | $dlat = $lat2 - $lat1; |
$dlng = $lng2 - $lng1; | $dlng = $lng2 - $lng1; |
$a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlng / 2) * sin($dlng / 2); | $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)); | $c = 2 * atan2(sqrt($a), sqrt(1 - $a)); |
$km = $r * $c; | $km = $r * $c; |
if ($roundLargeValues) { | if ($roundLargeValues) { |
if ($km < 1) return floor($km * 1000); | if ($km < 1) |
else return round($km, 2) . "k"; | return floor($km * 1000); |
} | else |
else return floor($km * 1000); | return round($km, 2) . "k"; |
} | |
else | |
return floor($km * 1000); | |
} | } |
function decodePolylineToArray($encoded) | |
{ | function decodePolylineToArray($encoded) { |
// source: http://latlongeeks.com/forum/viewtopic.php?f=4&t=5 | // source: http://latlongeeks.com/forum/viewtopic.php?f=4&t=5 |
$length = strlen($encoded); | $length = strlen($encoded); |
$index = 0; | $index = 0; |
$points = array(); | $points = array(); |
$lat = 0; | $lat = 0; |
$lng = 0; | $lng = 0; |
while ($index < $length) { | while ($index < $length) { |
// Temporary variable to hold each ASCII byte. | // Temporary variable to hold each ASCII byte. |
$b = 0; | $b = 0; |
// The encoded polyline consists of a latitude value followed by a | // The encoded polyline consists of a latitude value followed by a |
// longitude value. They should always come in pairs. Read the | // longitude value. They should always come in pairs. Read the |
// latitude value first. | // latitude value first. |
$shift = 0; | $shift = 0; |
$result = 0; | $result = 0; |
do { | do { |
// The `ord(substr($encoded, $index++))` statement returns the ASCII | // The `ord(substr($encoded, $index++))` statement returns the ASCII |
// code for the character at $index. Subtract 63 to get the original | // code for the character at $index. Subtract 63 to get the original |
// value. (63 was added to ensure proper ASCII characters are displayed | // value. (63 was added to ensure proper ASCII characters are displayed |
// in the encoded polyline string, which is `human` readable) | // in the encoded polyline string, which is `human` readable) |
$b = ord(substr($encoded, $index++)) - 63; | $b = ord(substr($encoded, $index++)) - 63; |
// AND the bits of the byte with 0x1f to get the original 5-bit `chunk. | // 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 | // Then left shift the bits by the required amount, which increases |
// by 5 bits each time. | // by 5 bits each time. |
// OR the value into $results, which sums up the individual 5-bit chunks | // 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 | // into the original value. Since the 5-bit chunks were reversed in |
// order during encoding, reading them in this way ensures proper | // order during encoding, reading them in this way ensures proper |
// summation. | // summation. |
$result|= ($b & 0x1f) << $shift; | $result|= ($b & 0x1f) << $shift; |
$shift+= 5; | $shift+= 5; |
} | } |
// Continue while the read byte is >= 0x20 since the last `chunk` | // Continue while the read byte is >= 0x20 since the last `chunk` |
// was not OR'd with 0x20 during the conversion process. (Signals the end) | // was not OR'd with 0x20 during the conversion process. (Signals the end) |
while ($b >= 0x20); | while ($b >= 0x20); |
// Check if negative, and convert. (All negative values have the last bit | // Check if negative, and convert. (All negative values have the last bit |
// set) | // set) |
$dlat = (($result & 1) ? ~($result >> 1) : ($result >> 1)); | $dlat = (($result & 1) ? ~($result >> 1) : ($result >> 1)); |
// Compute actual latitude since value is offset from previous value. | // Compute actual latitude since value is offset from previous value. |
$lat+= $dlat; | $lat+= $dlat; |
// The next values will correspond to the longitude for this point. | // The next values will correspond to the longitude for this point. |
$shift = 0; | $shift = 0; |
$result = 0; | $result = 0; |
do { | do { |
$b = ord(substr($encoded, $index++)) - 63; | $b = ord(substr($encoded, $index++)) - 63; |
$result|= ($b & 0x1f) << $shift; | $result|= ($b & 0x1f) << $shift; |
$shift+= 5; | $shift+= 5; |
} while ($b >= 0x20); | } while ($b >= 0x20); |
$dlng = (($result & 1) ? ~($result >> 1) : ($result >> 1)); | $dlng = (($result & 1) ? ~($result >> 1) : ($result >> 1)); |
$lng+= $dlng; | $lng+= $dlng; |
// The actual latitude and longitude values were multiplied by | // The actual latitude and longitude values were multiplied by |
// 1e5 before encoding so that they could be converted to a 32-bit | // 1e5 before encoding so that they could be converted to a 32-bit |
// integer representation. (With a decimal accuracy of 5 places) | // integer representation. (With a decimal accuracy of 5 places) |
// Convert back to original values. | // Convert back to original values. |
$points[] = array( | $points[] = array( |
$lat * 1e-5, | $lat * 1e-5, |
$lng * 1e-5 | $lng * 1e-5 |
); | ); |
} | } |
return $points; | return $points; |
} | } |
function geocode($query, $giveOptions) | |
{ | function geocode($query, $giveOptions) { |
global $cloudmadeAPIkey; | 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"; | $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)); | $contents = json_decode(getPage($url)); |
if ($giveOptions) return $contents->features; | if ($giveOptions) |
elseif (isset($contents->features[0]->centroid)) return $contents->features[0]->centroid->coordinates[0] . "," . $contents->features[0]->centroid->coordinates[1]; | return $contents->features; |
else return ""; | 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) | |
{ | function reverseGeocode($lat, $lng) { |
global $cloudmadeAPIkey; | global $cloudmadeAPIkey; |
$url = "http://geocoding.cloudmade.com/$cloudmadeAPIkey/geocoding/v2/find.js?around=" . $lat . "," . $lng . "&distance=closest&object_type=road"; | $url = "http://geocoding.cloudmade.com/$cloudmadeAPIkey/geocoding/v2/find.js?around=" . $lat . "," . $lng . "&distance=closest&object_type=road"; |
$contents = json_decode(getPage($url)); | $contents = json_decode(getPage($url)); |
return $contents->features[0]->properties->name; | return $contents->features[0]->properties->name; |
} | } |
?> | ?> |
<?php | <?php |
function getPage($url) | |
{ | /* |
debug($url, "json"); | * Copyright 2010,2011 Alexander Sadleir |
$ch = curl_init($url); | |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); | Licensed under the Apache License, Version 2.0 (the "License"); |
curl_setopt($ch, CURLOPT_HEADER, 0); | you may not use this file except in compliance with the License. |
curl_setopt($ch, CURLOPT_TIMEOUT, 45); | You may obtain a copy of the License at |
$page = curl_exec($ch); | |
if (curl_errno($ch)) { | http://www.apache.org/licenses/LICENSE-2.0 |
echo "<font color=red> Database temporarily unavailable: "; | |
echo curl_errno($ch) . " " . curl_error($ch); | Unless required by applicable law or agreed to in writing, software |
if (isDebug()) { | distributed under the License is distributed on an "AS IS" BASIS, |
echo $url; | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
} | See the License for the specific language governing permissions and |
echo "</font><br>"; | limitations under the License. |
} | */ |
curl_close($ch); | |
debug(print_r($page,true),"json"); | function getPage($url) { |
return $page; | 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() | |
{ | function curPageURL() { |
$isHTTPS = (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on"); | $isHTTPS = (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on"); |
$port = (isset($_SERVER["SERVER_PORT"]) && ((!$isHTTPS && $_SERVER["SERVER_PORT"] != "80") || ($isHTTPS && $_SERVER["SERVER_PORT"] != "443"))); | $port = (isset($_SERVER["SERVER_PORT"]) && ((!$isHTTPS && $_SERVER["SERVER_PORT"] != "80") || ($isHTTPS && $_SERVER["SERVER_PORT"] != "443"))); |
$port = ($port) ? ':' . $_SERVER["SERVER_PORT"] : ''; | $port = ($port) ? ':' . $_SERVER["SERVER_PORT"] : ''; |
$url = ($isHTTPS ? 'https://' : 'http://') . $_SERVER["SERVER_NAME"] . $port . htmlentities(dirname($_SERVER['PHP_SELF']) , ENT_QUOTES); | $url = ($isHTTPS ? 'https://' : 'http://') . $_SERVER["SERVER_NAME"] . $port . htmlentities(dirname($_SERVER['PHP_SELF']), ENT_QUOTES); |
return $url; | return $url; |
} | } |
?> | ?> |
<?php | <?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'])) { | if (isset($_REQUEST['firstLetter'])) { |
$firstLetter = filter_var($_REQUEST['firstLetter'], FILTER_SANITIZE_STRING); | $firstLetter = filter_var($_REQUEST['firstLetter'], FILTER_SANITIZE_STRING); |
} | } |
if (isset($_REQUEST['bysuburbs'])) { | if (isset($_REQUEST['bysuburbs'])) { |
$bysuburbs = true; | $bysuburbs = true; |
} | } |
if (isset($_REQUEST['bynumber'])) { | if (isset($_REQUEST['bynumber'])) { |
$bynumber = true; | $bynumber = true; |
} | } |
if (isset($_REQUEST['allstops'])) { | if (isset($_REQUEST['allstops'])) { |
$allstops = true; | $allstops = true; |
} | } |
if (isset($_REQUEST['nearby'])) { | if (isset($_REQUEST['nearby'])) { |
$nearby = true; | $nearby = true; |
} | } |
if (isset($_REQUEST['suburb'])) { | if (isset($_REQUEST['suburb'])) { |
$suburb = $_REQUEST['suburb']; | $suburb = $_REQUEST['suburb']; |
} | } |
$pageKey = filter_var($_REQUEST['pageKey'], FILTER_SANITIZE_NUMBER_INT); | if (isset($_REQUEST['pageKey'])) { |
$lat = filter_var($_REQUEST['lat'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); | $pageKey = filter_var($_REQUEST['pageKey'], FILTER_SANITIZE_NUMBER_INT); |
$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['lat'])) { |
$lat = filter_var($_REQUEST['lat'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); | |
} | |
if (isset($_REQUEST['lon'])) { | |
$lon = filter_var($_REQUEST['lon'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); | |
} | |
if (isset($_REQUEST['radius'])) { | |
$max_distance = filter_var($_REQUEST['radius'], FILTER_SANITIZE_NUMBER_INT); | |
} | |
if (isset($_REQUEST['numberSeries'])) { | 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'])) { | 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'])) { | if (isset($_REQUEST['stopcode'])) { |
$stopcode = filter_var($_REQUEST['stopcode'], FILTER_SANITIZE_STRING); | $stopcode = filter_var($_REQUEST['stopcode'], FILTER_SANITIZE_STRING); |
} | } |
if (isset($_REQUEST['stopids'])) { | 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'])) { | 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'])) { | 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'])) { | 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'])) { | if (isset($_REQUEST['geolocate'])) { |
$geolocate = filter_var($_REQUEST['geolocate'], FILTER_SANITIZE_URL); | $geolocate = filter_var($_REQUEST['geolocate'], FILTER_SANITIZE_URL); |
} | } |
?> | ?> |
<?php | <?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 | // you have to open the session to be able to modify or remove it |
session_start(); | session_start(); |
if (isset($_REQUEST['service_period'])) { | if (isset($_REQUEST['service_period'])) { |
$_SESSION['service_period'] = filter_var($_REQUEST['service_period'], FILTER_SANITIZE_STRING); | $_SESSION['service_period'] = filter_var($_REQUEST['service_period'], FILTER_SANITIZE_STRING); |
sessionUpdated(); | sessionUpdated(); |
} | } |
if (isset($_REQUEST['time'])) { | if (isset($_REQUEST['time'])) { |
$_SESSION['time'] = filter_var($_REQUEST['time'], FILTER_SANITIZE_STRING); | $_SESSION['time'] = filter_var($_REQUEST['time'], FILTER_SANITIZE_STRING); |
sessionUpdated(); | sessionUpdated(); |
} | } |
if (isset($_REQUEST['geolocate']) && $_REQUEST['geolocate'] != "Enter co-ordinates or address here") { | if (isset($_REQUEST['geolocate']) && $_REQUEST['geolocate'] != "Enter co-ordinates or address here") { |
$geocoded = false; | $geocoded = false; |
if (isset($_REQUEST['lat']) && isset($_REQUEST['lon'])) { | if (isset($_REQUEST['lat']) && isset($_REQUEST['lon'])) { |
$_SESSION['lat'] = trim(filter_var($_REQUEST['lat'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION)); | $_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)); | $_SESSION['lon'] = trim(filter_var($_REQUEST['lon'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION)); |
} | } else { |
else { | if (startsWith($geolocate, "-")) { |
if (startsWith($geolocate, "-")) { | $locateparts = explode(",", $geolocate); |
$locateparts = explode(",", $geolocate); | $_SESSION['lat'] = $locateparts[0]; |
$_SESSION['lat'] = $locateparts[0]; | $_SESSION['lon'] = $locateparts[1]; |
$_SESSION['lon'] = $locateparts[1]; | } else if (strpos($geolocate, "(") !== false) { |
} | $geoParts = explode("(", $geolocate); |
else if (strpos($geolocate, "(") !== false) { | $locateparts = explode(",", str_replace(")", "", $geoParts[1])); |
$geoParts = explode("(", $geolocate); | $_SESSION['lat'] = $locateparts[0]; |
$locateparts = explode(",", str_replace(")", "",$geoParts[1])); | $_SESSION['lon'] = $locateparts[1]; |
$_SESSION['lat'] = $locateparts[0]; | } else { |
$_SESSION['lon'] = $locateparts[1]; | $contents = geocode($geolocate, true); |
} | print_r($contents); |
else { | if (isset($contents[0]->centroid)) { |
$contents = geocode($geolocate, true); | $geocoded = true; |
print_r($contents); | $_SESSION['lat'] = $contents[0]->centroid->coordinates[0]; |
if (isset($contents[0]->centroid)) { | $_SESSION['lon'] = $contents[0]->centroid->coordinates[1]; |
$geocoded = true; | } else { |
$_SESSION['lat'] = $contents[0]->centroid->coordinates[0]; | $_SESSION['lat'] = ""; |
$_SESSION['lon'] = $contents[0]->centroid->coordinates[1]; | $_SESSION['lon'] = ""; |
} | } |
else { | } |
$_SESSION['lat'] = ""; | } |
$_SESSION['lon'] = ""; | sessionUpdated(); |
} | |
} | |
} | |
sessionUpdated(); | |
} | } |
function sessionUpdated() | |
{ | function sessionUpdated() { |
$_SESSION['lastUpdated'] = time(); | $_SESSION['lastUpdated'] = time(); |
} | } |
// timeoutSession | // timeoutSession |
$TIMEOUT_LIMIT = 60 * 5; // 5 minutes | $TIMEOUT_LIMIT = 60 * 5; // 5 minutes |
if (isset($_SESSION['lastUpdated']) && $_SESSION['lastUpdated'] + $TIMEOUT_LIMIT < time()) { | if (isset($_SESSION['lastUpdated']) && $_SESSION['lastUpdated'] + $TIMEOUT_LIMIT < time()) { |
debug("Session timeout " . ($_SESSION['lastUpdated'] + $TIMEOUT_LIMIT) . ">" . time() , "session"); | debug("Session timeout " . ($_SESSION['lastUpdated'] + $TIMEOUT_LIMIT) . ">" . time(), "session"); |
session_destroy(); | session_destroy(); |
session_start(); | session_start(); |
} | } |
//debug(print_r($_SESSION, true) , "session"); | //debug(print_r($_SESSION, true) , "session"); |
function current_time() | function current_time() { |
{ | return ($_SESSION['time'] ? $_SESSION['time'] : date("H:i:s")); |
return ($_SESSION['time'] ? $_SESSION['time'] : date("H:i:s")); | |
} | } |
?> | ?> |
<?php | <?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. | // Copyright 2009 Google Inc. All Rights Reserved. |
$GA_ACCOUNT = "MO-22173039-1"; | $GA_ACCOUNT = "MO-22173039-1"; |
$GA_PIXEL = "/lib/ga.php"; | $GA_PIXEL = "/lib/ga.php"; |
function googleAnalyticsGetImageUrl() | |
{ | function googleAnalyticsGetImageUrl() { |
global $GA_ACCOUNT, $GA_PIXEL; | global $GA_ACCOUNT, $GA_PIXEL; |
//if (stristr($_SERVER['HTTP_USER_AGENT'], 'Googlebot') return ""; | //if (stristr($_SERVER['HTTP_USER_AGENT'], 'Googlebot') return ""; |
$url = ""; | $url = ""; |
$url.= $GA_PIXEL . "?"; | $url.= $GA_PIXEL . "?"; |
$url.= "utmac=" . $GA_ACCOUNT; | $url.= "utmac=" . $GA_ACCOUNT; |
$url.= "&utmn=" . rand(0, 0x7fffffff); | $url.= "&utmn=" . rand(0, 0x7fffffff); |
$referer = $_SERVER["HTTP_REFERER"]; | $referer = $_SERVER["HTTP_REFERER"]; |
$query = $_SERVER["QUERY_STRING"]; | $query = $_SERVER["QUERY_STRING"]; |
$path = $_SERVER["REQUEST_URI"]; | $path = $_SERVER["REQUEST_URI"]; |
if (empty($referer)) { | if (empty($referer)) { |
$referer = "-"; | $referer = "-"; |
} | } |
$url.= "&utmr=" . urlencode($referer); | $url.= "&utmr=" . urlencode($referer); |
if (!empty($path)) { | if (!empty($path)) { |
$url.= "&utmp=" . urlencode($path); | $url.= "&utmp=" . urlencode($path); |
} | } |
$url.= "&guid=ON"; | $url.= "&guid=ON"; |
return str_replace("&", "&", $url); | return str_replace("&", "&", $url); |
} | } |
function include_header($pageTitle, $pageType, $opendiv = true, $geolocate = false, $datepicker = false) | |
{ | function include_header($pageTitle, $pageType, $opendiv = true, $geolocate = false, $datepicker = false) { |
global $labsPath,$serviceAlertsEnabled; | global $basePath, $GTFSREnabled; |
echo ' | echo ' |
<!DOCTYPE html> | <!DOCTYPE html> |
<html lang="en"> | <html lang="en"> |
<head> | <head> |
<meta charset="UTF-8"> | <meta charset="UTF-8"> |
<meta name="viewport" content="width=device-width, initial-scale=1"> | <meta name="viewport" content="width=device-width, initial-scale=1"> |
<title>' . $pageTitle . ' - Canberra Bus Timetable</title> | <title>' . $pageTitle . ' - Canberra Bus Timetable</title> |
<meta name="google-site-verification" content="-53T5Qn4TB_de1NyfR_ZZkEVdUNcNFSaYKSFkWKx-sY" /> | <meta name="google-site-verification" content="-53T5Qn4TB_de1NyfR_ZZkEVdUNcNFSaYKSFkWKx-sY" /> |
<link rel="dns-prefetch" href="//code.jquery.com"> | <link rel="dns-prefetch" href="//code.jquery.com"> |
<link rel="dns-prefetch" href="//ajax.googleapis.com"> | <link rel="dns-prefetch" href="//ajax.googleapis.com"> |
<link rel="stylesheet" href="' . $labsPath . 'css/jquery-ui-1.8.12.custom.css" />'; | <link rel="stylesheet" href="' . $basePath . 'css/jquery-ui-1.8.12.custom.css" />'; |
if (isDebugServer()) { | $jqmVersion = "1.0rc1"; |
$jqmcss = $labsPath . 'css/jquery.mobile-1.0b2.css'; | if (isDebugServer()) { |
$jqjs = $labsPath . 'js/jquery-1.6.2.min.js'; | $jqmcss = $basePath . "css/jquery.mobile-$jqmVersion.css"; |
$jqmjs = $labsPath . 'js/jquery.mobile-1.0b2.js'; | $jqjs = $basePath . "js/jquery-1.6.2.min.js"; |
} | $jqmjs = $basePath . "js/jquery.mobile-$jqmVersion.js"; |
else { | } else { |
$jqmcss = "//code.jquery.com/mobile/1.0b2/jquery.mobile-1.0b2.min.css"; | $jqmcss = "//code.jquery.com/mobile/$jqmVersion/jquery.mobile-$jqmVersion.min.css"; |
$jqjs = "//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"; | $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"; | $jqmjs = "//code.jquery.com/mobile/$jqmVersion/jquery.mobile-$jqmVersion.min.js"; |
} | } |
echo '<link rel="stylesheet" href="' . $jqmcss . '" /> | echo '<link rel="stylesheet" href="' . $jqmcss . '" /> |
<script src="'.$jqjs.'"></script> | <script src="' . $jqjs . '"></script> |
<script>$(document).bind("mobileinit", function(){ | <script>$(document).bind("mobileinit", function(){ |
$.mobile.ajaxEnabled = false; | $.mobile.ajaxEnabled = false; |
}); | }); |
</script> | </script> |
<script src="'.$jqmjs.'"></script> | <script src="' . $jqmjs . '"></script> |
<script src="' . $labsPath . 'js/jquery.ui.core.min.js"></script> | <script src="' . $basePath . 'js/jquery.ui.core.min.js"></script> |
<script src="' . $labsPath . 'js/jquery.ui.position.min.js"></script> | <script src="' . $basePath . 'js/jquery.ui.position.min.js"></script> |
<script src="' . $labsPath . 'js/jquery.ui.widget.min.js"></script> | <script src="' . $basePath . 'js/jquery.ui.widget.min.js"></script> |
<script src="' . $labsPath . 'js/jquery.ui.autocomplete.min.js"></script> | <script src="' . $basePath . 'js/jquery.ui.autocomplete.min.js"></script> |
<script> | <script> |
$(function() { | $(function() { |
$( "#geolocate" ).autocomplete({ | $( "#geolocate" ).autocomplete({ |
source: "lib/autocomplete.php", | source: "lib/autocomplete.php", |
minLength: 2 | minLength: 2 |
}); | }); |
$( "#from" ).autocomplete({ | $( "#from" ).autocomplete({ |
source: "lib/autocomplete.php", | source: "lib/autocomplete.php", |
minLength: 2 | minLength: 2 |
}); | }); |
$( "#to" ).autocomplete({ | $( "#to" ).autocomplete({ |
source: "lib/autocomplete.php", | source: "lib/autocomplete.php", |
minLength: 2 | minLength: 2 |
}); | }); |
}); | }); |
</script>'; | </script>'; |
echo '<style type="text/css">'; | 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, | 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-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-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 { | .ui-btn-down-e,.ui-bar-e,.ui-overlay-shadow,.ui-shadow,.ui-btn-active,.ui-body-a,.ui-bar-a { |
text-shadow: none; | text-shadow: none; |
box-shadow: none; | box-shadow: none; |
-webkit-box-shadow: none; | -webkit-box-shadow: none; |
}'; | }'; |
echo '</style>'; | echo '</style>'; |
echo '<link rel="stylesheet" href="' . $labsPath . 'css/local.css.php" />'; | 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')) { | if (isIOSDevice()){ |
echo '<meta name="apple-mobile-web-app-capable" content="yes" /> | echo '<meta name="apple-mobile-web-app-capable" content="yes" /> |
<meta name="apple-mobile-web-app-status-bar-style" content="black" /> | <meta name="apple-mobile-web-app-status-bar-style" content="black" /> |
<link rel="apple-touch-startup-image" href="startup.png" /> | <link rel="apple-touch-startup-image" href="startup.png" /> |
<link rel="apple-touch-icon" href="apple-touch-icon.png" />'; | <link rel="apple-touch-icon" href="apple-touch-icon.png" />'; |
} | } |
if ($geolocate) { | if ($geolocate) { |
echo "<script> | echo "<script> |
function success(position) { | function success(position) { |
$('#error').val('Location now detected. Please wait for data to load.'); | $('#error').val('Location now detected. Please wait for data to load.'); |
$('#geolocate').val(position.coords.latitude+','+position.coords.longitude); | $('#geolocate').val(position.coords.latitude+','+position.coords.longitude); |
$.ajax({ url: \"include/common.inc.php?geolocate=yes&lat=\"+position.coords.latitude+\"&lon=\"+position.coords.longitude }); | $.ajax({ async: false, |
location.reload(true); | success: function(){ |
location.reload(true); | |
}, | |
url: \"include/common.inc.php?geolocate=yes&lat=\"+position.coords.latitude+\"&lon=\"+position.coords.longitude }); | |
} | } |
function error(msg) { | function error(msg) { |
$('#error').val('Error: '+msg); | $('#error').val('Error: '+msg); |
} | } |
function geolocate() { | function geolocate() { |
if (navigator.geolocation) { | if (navigator.geolocation) { |
var options = { | var options = { |
enableHighAccuracy: true, | enableHighAccuracy: true, |
timeout: 60000, | timeout: 60000, |
maximumAge: 10000 | maximumAge: 10000 |
} | } |
navigator.geolocation.getCurrentPosition(success, error, options); | navigator.geolocation.getCurrentPosition(success, error, options); |
} | } |
} | } |
$(document).ready(function() { | $(document).ready(function() { |
$('#here').click(function(event) { $('#geolocate').val(geolocate()); return false;}); | $('#here').click(function(event) { $('#geolocate').val(geolocate()); return false;}); |
$('#here').show(); | $('#here').show(); |
}); | }); |
"; | "; |
if (!isset($_SESSION['lat']) || $_SESSION['lat'] == "") echo "geolocate();"; | if (!isset($_SESSION['lat']) || $_SESSION['lat'] == "") |
echo "</script> "; | echo "geolocate();"; |
} | echo "</script> "; |
if (isAnalyticsOn()) echo ' | } |
if (isAnalyticsOn()) | |
echo ' | |
<script type="text/javascript">' . " | <script type="text/javascript">' . " |
var _gaq = _gaq || []; | var _gaq = _gaq || []; |
_gaq.push(['_setAccount', 'UA-22173039-1']); | _gaq.push(['_setAccount', 'UA-22173039-1']); |
_gaq.push(['_trackPageview']); | _gaq.push(['_trackPageview']); |
_gaq.push(['_trackPageLoadTime']); | _gaq.push(['_trackPageLoadTime']); |
</script>"; | </script>"; |
echo '</head> | echo '</head> |
<body> | <body> |
<div id="skip"> | <div id="skip"> |
<a href="#maincontent">Skip to content</a> | <a href="#maincontent">Skip to content</a> |
</div> | </div> |
'; | '; |
if ($opendiv) { | if ($opendiv) { |
echo '<div data-role="page"> | echo '<div data-role="page"> |
<div data-role="header" data-position="inline"> | <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> | <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> | <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 --> | </div><!-- /header --> |
<a name="maincontent" id="maincontent"></a> | <a name="maincontent" id="maincontent"></a> |
<div data-role="content"> '; | <div data-role="content"> '; |
$overrides = getServiceOverride(); | $overrides = getServiceOverride(); |
if ($overrides['service_id']) { | if ($overrides['service_id']) { |
if ($overrides['service_id'] == "noservice") { | if ($overrides['service_id'] == "noservice") { |
echo '<div id="servicewarning">Buses are <strong>not running today</strong> due to industrial action/public holiday. See <a | 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>'; | href="http://www.action.act.gov.au">http://www.action.act.gov.au</a> for details.</div>'; |
} | } else { |
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>'; |
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) { |
if ($GTFSREnabled) { | $serviceAlerts = getServiceAlertsAsArray("agency", "0"); |
$serviceAlerts = getServiceAlertsAsArray("agency","0"); | if (isset($serviceAlerts['entity']) && sizeof($serviceAlerts['entity']) > 0) { |
foreach ($serviceAlerts['entity'] as $entity) { | 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']} | 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>"; | <br><a href='{$entity['alert']['url']['translation'][0]['text']}'>Source</a> </div>"; |
} | } |
} | } |
} | } |
} | } |
function include_footer() | } |
{ | |
global $labsPath; | function include_footer() { |
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>'; | global $basePath; |
echo '</div>'; | 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>'; |
if (isAnalyticsOn()) { | echo '</div>'; |
echo "<script> (function() { | if (isAnalyticsOn()) { |
echo "<script> (function() { | |
var ga = document.createElement('script'); ga.type = | var ga = document.createElement('script'); ga.type = |
'text/javascript'; ga.async = true; | 'text/javascript'; ga.async = true; |
ga.src = ('https:' == document.location.protocol ? | ga.src = ('https:' == document.location.protocol ? |
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; | 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; |
var s = document.getElementsByTagName('script')[0]; | var s = document.getElementsByTagName('script')[0]; |
s.parentNode.insertBefore(ga, s); | s.parentNode.insertBefore(ga, s); |
})();</script>"; | })();</script>"; |
$googleAnalyticsImageUrl = googleAnalyticsGetImageUrl(); | $googleAnalyticsImageUrl = googleAnalyticsGetImageUrl(); |
echo '<noscript><img src="' . $googleAnalyticsImageUrl . '" /></noscript>'; | echo '<noscript><img src="' . $googleAnalyticsImageUrl . '" /></noscript>'; |
} | } |
echo "\n</div></div></body></html>"; | echo "\n</div></div></body></html>"; |
} | } |
function placeSettings() | |
{ | function placeSettings() { |
global $service_periods; | global $service_periods; |
$geoerror = false; | $geoerror = false; |
$geoerror = !isset($_SESSION['lat']) || !isset($_SESSION['lat']) || $_SESSION['lat'] == "" || $_SESSION['lon'] == ""; | $geoerror = !isset($_SESSION['lat']) || !isset($_SESSION['lat']) || $_SESSION['lat'] == "" || $_SESSION['lon'] == ""; |
echo '<div id="error">'; | echo '<div id="error">'; |
if ($geoerror) { | if ($geoerror) { |
echo 'Sorry, but your location could not currently be detected. | echo 'Sorry, but your location could not currently be detected. |
Please allow location permission, wait for your location to be detected, | Please allow location permission, wait for your location to be detected, |
or enter an address/co-ordinates in the box below.'; | or enter an address/co-ordinates in the box below.'; |
} | } |
echo '</div>'; | echo '</div>'; |
echo '<div id="settings" data-role="collapsible" data-collapsed="' . !$geoerror . '"> | echo '<div id="settings" data-role="collapsible" data-collapsed="' . !$geoerror . '"> |
<h3>Change Location...</h3> | <h3>Change Location...</h3> |
<form action="' . basename($_SERVER['PHP_SELF']) . "?" . $_SERVER['QUERY_STRING'] . '" method="post"> | <form action="' . basename($_SERVER['PHP_SELF']) . "?" . $_SERVER['QUERY_STRING'] . '" method="post"> |
<div class="ui-body"> | <div class="ui-body"> |
<div data-role="fieldcontain"> | <div data-role="fieldcontain"> |
<label for="geolocate"> Current Location: </label> | <label for="geolocate"> Current Location: </label> |
<input type="text" id="geolocate" name="geolocate" value="' . (isset($_SESSION['lat']) && isset($_SESSION['lon']) ? $_SESSION['lat'] . "," . $_SESSION['lon'] : "Enter co-ordinates or address here") . '"/> <a href="#" style="display:none" name="here" id="here">Here?</a> | <input type="text" id="geolocate" name="geolocate" value="' . (isset($_SESSION['lat']) && isset($_SESSION['lon']) ? $_SESSION['lat'] . "," . $_SESSION['lon'] : "Enter co-ordinates or address here") . '"/> <a href="#" style="display:none" name="here" id="here">Here?</a> |
</div> | </div> |
<input type="submit" value="Update"/> | <input type="submit" value="Update"/> |
</div></form> | </div></form> |
</div>'; | </div>'; |
} | } |
function trackEvent($category, $action, $label = "", $value = - 1) | |
{ | function trackEvent($category, $action, $label = "", $value = - 1) { |
if (isAnalyticsOn()) { | if (isAnalyticsOn()) { |
echo "\n<script> _gaq.push(['_trackEvent', '$category', '$action'" . ($label != "" ? ", '$label'" : "") . ($value != - 1 ? ", $value" : "") . "]);</script>"; | echo "\n<script> _gaq.push(['_trackEvent', '$category', '$action'" . ($label != "" ? ", '$label'" : "") . ($value != - 1 ? ", $value" : "") . "]);</script>"; |
} | } |
} | } |
?> | ?> |
<?php | <?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( | $service_periods = Array( |
'sunday', | 'sunday', |
'saturday', | 'saturday', |
'weekday' | 'weekday' |
); | ); |
function service_period($date = "") | function service_period($date = "") { |
{ | |
if (isset($_SESSION['service_period'])) | |
if (isset($_SESSION['service_period'])) return $_SESSION['service_period']; | return $_SESSION['service_period']; |
$override = getServiceOverride($date); | $override = getServiceOverride($date); |
if ($override['service_id']){ | if ($override['service_id']) { |
return $override['service_id']; | return $override['service_id']; |
} | } |
switch (date('w',($date != "" ? $date : time()))) { | switch (date('w', ($date != "" ? $date : time()))) { |
case 0: | case 0: |
return 'sunday'; | return 'sunday'; |
case 6: | case 6: |
return 'saturday'; | return 'saturday'; |
default: | default: |
return 'weekday'; | return 'weekday'; |
} | } |
} | } |
function midnight_seconds($time = "") | |
{ | function midnight_seconds($time = "") { |
// from http://www.perturb.org/display/Perlfunc__Seconds_Since_Midnight.html | // from http://www.perturb.org/display/Perlfunc__Seconds_Since_Midnight.html |
if ($time != "") { | if ($time != "") { |
return (date("G", $time) * 3600) + (date("i", $time) * 60) + date("s", $time); | return (date("G", $time) * 3600) + (date("i", $time) * 60) + date("s", $time); |
} | } |
if (isset($_SESSION['time'])) { | if (isset($_SESSION['time'])) { |
$time = strtotime($_SESSION['time']); | $time = strtotime($_SESSION['time']); |
return (date("G", $time) * 3600) + (date("i", $time) * 60) + date("s", $time); | return (date("G", $time) * 3600) + (date("i", $time) * 60) + date("s", $time); |
} | } |
return (date("G") * 3600) + (date("i") * 60) + date("s"); | return (date("G") * 3600) + (date("i") * 60) + date("s"); |
} | } |
function midnight_seconds_to_time($seconds) | |
{ | function midnight_seconds_to_time($seconds) { |
if ($seconds > 0) { | if ($seconds > 0) { |
$midnight = mktime(0, 0, 0, date("n") , date("j") , date("Y")); | $midnight = mktime(0, 0, 0, date("n"), date("j"), date("Y")); |
return date("h:ia", $midnight + $seconds); | return date("h:ia", $midnight + $seconds); |
} | } else { |
else { | return ""; |
return ""; | } |
} | } |
} | |
if ($GTFSREnabled) { | if ($GTFSREnabled) { |
$serviceAlertCause = Array( | $serviceAlertCause = Array( |
"UNKNOWN_CAUSE" => "Unknown cause", | "UNKNOWN_CAUSE" => "Unknown cause", |
"OTHER_CAUSE" => "Other cause", | "OTHER_CAUSE" => "Other cause", |
"TECHNICAL_PROBLEM" => "Technical problem", | "TECHNICAL_PROBLEM" => "Technical problem", |
"STRIKE" => "Strike", | "STRIKE" => "Strike", |
"DEMONSTRATION" => "Demonstration", | "DEMONSTRATION" => "Demonstration", |
"ACCIDENT" => "Accident", | "ACCIDENT" => "Accident", |
"HOLIDAY" => "Holiday", | "HOLIDAY" => "Holiday", |
"WEATHER" => "Weather", | "WEATHER" => "Weather", |
"MAINTENANCE" => "Maintenance", | "MAINTENANCE" => "Maintenance", |
"CONSTRUCTION" => "Construction", | "CONSTRUCTION" => "Construction", |
"POLICE_ACTIVITY" => "Police activity", | "POLICE_ACTIVITY" => "Police activity", |
"MEDICAL_EMERGENCY" => "Medical emergency" | "MEDICAL_EMERGENCY" => "Medical emergency" |
); | ); |
$serviceAlertEffect = Array( | $serviceAlertEffect = Array( |
"NO_SERVICE" => "No service", | "NO_SERVICE" => "No service", |
"REDUCED_SERVICE" => "Reduced service", | "REDUCED_SERVICE" => "Reduced service", |
"SIGNIFICANT_DELAYS" => "Significant delays", | "SIGNIFICANT_DELAYS" => "Significant delays", |
"DETOUR" => "Detour", | "DETOUR" => "Detour", |
"ADDITIONAL_SERVICE" => "Additional service", | "ADDITIONAL_SERVICE" => "Additional service", |
"MODIFIED_SERVICE" => "Modified service", | "MODIFIED_SERVICE" => "Modified service", |
"OTHER_EFFECT" => "Other effect", | "OTHER_EFFECT" => "Other effect", |
"UNKNOWN_EFFECT" => "Unknown effect", | "UNKNOWN_EFFECT" => "Unknown effect", |
"STOP_MOVED" => "Stop moved"); | "STOP_MOVED" => "Stop moved"); |
set_include_path(get_include_path() . PATH_SEPARATOR . $labsPath."lib/Protobuf-PHP/library/DrSlump/"); | set_include_path(get_include_path() . PATH_SEPARATOR . ($basePath . "lib/Protobuf-PHP/library/DrSlump/")); |
include_once("Protobuf.php"); | include_once("Protobuf.php"); |
include_once("Protobuf/Message.php"); | include_once("Protobuf/Message.php"); |
include_once("Protobuf/Registry.php"); | include_once("Protobuf/Registry.php"); |
include_once("Protobuf/Descriptor.php"); | include_once("Protobuf/Descriptor.php"); |
include_once("Protobuf/Field.php"); | include_once("Protobuf/Field.php"); |
include_once($labsPath."lib/Protobuf-PHP/gtfs-realtime.php"); | include_once($basePath . "lib/Protobuf-PHP/gtfs-realtime.php"); |
include_once("Protobuf/CodecInterface.php"); | include_once("Protobuf/CodecInterface.php"); |
include_once("Protobuf/Codec/PhpArray.php"); | include_once("Protobuf/Codec/PhpArray.php"); |
include_once("Protobuf/Codec/Binary.php"); | include_once("Protobuf/Codec/Binary.php"); |
include_once("Protobuf/Codec/Binary/Writer.php"); | include_once("Protobuf/Codec/Binary/Writer.php"); |
include_once("Protobuf/Codec/Json.php"); | include_once("Protobuf/Codec/Json.php"); |
function getServiceAlerts($filter_class = "", $filter_id = "") { | function getServiceAlerts($filter_class = "", $filter_id = "") { |
/* | /* |
also need last modified epoch of client gtfs | also need last modified epoch of client gtfs |
- add,remove,patch,inform (null) | - add,remove,patch,inform (null) |
- stop | - stop |
- trip | - trip |
- network | - network |
- classes (WHERE=) | - classes (WHERE=) |
- route (short_name or route_id) | - route (short_name or route_id) |
- street | - street |
- stop | - stop |
- trip | - trip |
Currently support: | Currently support: |
network inform | network inform |
trip patch: stop remove | trip patch: stop remove |
street inform: route inform, trip inform, stop inform | street inform: route inform, trip inform, stop inform |
route patch: trip remove | route patch: trip remove |
*/ | */ |
$fm = new transit_realtime\FeedMessage(); | $fm = new transit_realtime\FeedMessage(); |
$fh = new transit_realtime\FeedHeader(); | $fh = new transit_realtime\FeedHeader(); |
$fh->setGtfsRealtimeVersion(1); | $fh->setGtfsRealtimeVersion(1); |
$fh->setTimestamp(time()); | $fh->setTimestamp(time()); |
$fm->setHeader($fh); | $fm->setHeader($fh); |
foreach(getCurrentAlerts() as $alert) { | foreach (getCurrentAlerts() as $alert) { |
$fe = new transit_realtime\FeedEntity(); | $fe = new transit_realtime\FeedEntity(); |
$fe->setId($alert['id']); | $fe->setId($alert['id']); |
$fe->setIsDeleted(false); | $fe->setIsDeleted(false); |
$alert = new transit_realtime\Alert(); | $alert = new transit_realtime\Alert(); |
$tr = new transit_realtime\TimeRange(); | $tr = new transit_realtime\TimeRange(); |
$tr->setStart($alert['start']); | $tr->setStart($alert['start']); |
$tr->setEnd($alert['end']); | $tr->setEnd($alert['end']); |
$alert-> addActivePeriod($tr); | $alert->addActivePeriod($tr); |
$informedEntities = getInformedAlerts($alert['id'],$_REQUEST['filter_class'],$_REQUEST['filter_id']); | $informedEntities = getInformedAlerts($alert['id'], $_REQUEST['filter_class'], $_REQUEST['filter_id']); |
if (sizeof($informedEntities) >0) { | if (sizeof($informedEntities) > 0) { |
$informed = Array(); | $informed = Array(); |
$es = new transit_realtime\EntitySelector(); | $es = new transit_realtime\EntitySelector(); |
if ($informedEntity['informed_class'] == "agency") { | if ($informedEntity['informed_class'] == "agency") { |
$es->setAgencyId($informedEntity['informed_id']); | $es->setAgencyId($informedEntity['informed_id']); |
} | } |
if ($informedEntity['informed_class'] == "stop") { | if ($informedEntity['informed_class'] == "stop") { |
$es->setStopId($informedEntity['informed_id']); | $es->setStopId($informedEntity['informed_id']); |
} | } |
if ($informedEntity['informed_class'] == "route") { | if ($informedEntity['informed_class'] == "route") { |
$es->setRouteId($informedEntity['informed_id']); | $es->setRouteId($informedEntity['informed_id']); |
} | } |
if ($informedEntity['informed_class'] == "trip") { | if ($informedEntity['informed_class'] == "trip") { |
$td = new transit_realtime\TripDescriptor(); | $td = new transit_realtime\TripDescriptor(); |
$td->setTripId($informedEntity['informed_id']); | $td->setTripId($informedEntity['informed_id']); |
$es->setTrip($td); | $es->setTrip($td); |
} | } |
$alert-> addInformedEntity($es); | $alert->addInformedEntity($es); |
} | } |
$alert->setCause(constant("transit_realtime\Alert\Cause::".$alert['cause'])); | $alert->setCause(constant("transit_realtime\Alert\Cause::" . $alert['cause'])); |
$alert->setEffect(constant("transit_realtime\Alert\Effect::".$alert['effect'])); | $alert->setEffect(constant("transit_realtime\Alert\Effect::" . $alert['effect'])); |
$tsUrl = new transit_realtime\TranslatedString(); | $tsUrl = new transit_realtime\TranslatedString(); |
$tUrl = new transit_realtime\TranslatedString\Translation(); | $tUrl = new transit_realtime\TranslatedString\Translation(); |
$tUrl->setText($alert['url']); | $tUrl->setText($alert['url']); |
$tUrl->setLanguage("en"); | $tUrl->setLanguage("en"); |
$tsUrl->addTranslation($tUrl); | $tsUrl->addTranslation($tUrl); |
$alert->setUrl($tsUrl); | $alert->setUrl($tsUrl); |
$tsHeaderText= new transit_realtime\TranslatedString(); | $tsHeaderText = new transit_realtime\TranslatedString(); |
$tHeaderText = new transit_realtime\TranslatedString\Translation(); | $tHeaderText = new transit_realtime\TranslatedString\Translation(); |
$tHeaderText->setText($alert['header']); | $tHeaderText->setText($alert['header']); |
$tHeaderText->setLanguage("en"); | $tHeaderText->setLanguage("en"); |
$tsHeaderText->addTranslation($tHeaderText); | $tsHeaderText->addTranslation($tHeaderText); |
$alert->setHeaderText($tsHeaderText); | $alert->setHeaderText($tsHeaderText); |
$tsDescriptionText= new transit_realtime\TranslatedString(); | $tsDescriptionText = new transit_realtime\TranslatedString(); |
$tDescriptionText = new transit_realtime\TranslatedString\Translation(); | $tDescriptionText = new transit_realtime\TranslatedString\Translation(); |
$tDescriptionText->setText($alert['description']); | $tDescriptionText->setText($alert['description']); |
$tDescriptionText->setLanguage("en"); | $tDescriptionText->setLanguage("en"); |
$tsDescriptionText->addTranslation($tDescriptionText); | $tsDescriptionText->addTranslation($tDescriptionText); |
$alert->setDescriptionText($tsDescriptionText); | $alert->setDescriptionText($tsDescriptionText); |
$fe->setAlert($alert); | $fe->setAlert($alert); |
$fm->addEntity($fe); | $fm->addEntity($fe); |
} | } |
return $fm; | return $fm; |
} | } |
function getServiceAlertsAsArray($filter_class = "", $filter_id = "") { | |
$codec = new DrSlump\Protobuf\Codec\PhpArray(); | function getServiceAlertsAsArray($filter_class = "", $filter_id = "") { |
return $codec->encode(getServiceAlerts($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(); | function getServiceAlertsAsBinary($filter_class = "", $filter_id = "") { |
return $codec->encode(getServiceAlerts($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(); | function getServiceAlertsAsJSON($filter_class = "", $filter_id = "") { |
return $codec->encode(getServiceAlerts($filter_class, $filter_id)); | $codec = new DrSlump\Protobuf\Codec\Json(); |
} | return $codec->encode(getServiceAlerts($filter_class, $filter_id)); |
function getServiceAlertsByClass() { | } |
$return = Array(); | |
$alerts = getServiceAlertsAsArray("",""); | function getServiceAlertsByClass() { |
foreach ($alerts['entities'] as $entity) { | $return = Array(); |
foreach ($entity['informed'] as $informed) { | $alerts = getServiceAlertsAsArray("", ""); |
foreach($informed as $key => $value){ | foreach ($alerts['entities'] as $entity) { |
if (strpos("_id",$key) > 0) { | foreach ($entity['informed'] as $informed) { |
$parts = explode($key); | foreach ($informed as $key => $value) { |
$class = $parts[0]; | if (strpos("_id", $key) > 0) { |
$id = $value; | $parts = explode($key); |
} | $class = $parts[0]; |
} | $id = $value; |
$return[$class][$id][] = $entity; | } |
} | } |
} | $return[$class][$id][] = $entity; |
} | } |
} | |
function getTripUpdates($filter_class = "", $filter_id = "") { | } |
$fm = new transit_realtime\FeedMessage(); | |
$fh = new transit_realtime\FeedHeader(); | function getTripUpdates($filter_class = "", $filter_id = "") { |
$fh->setGtfsRealtimeVersion(1); | $fm = new transit_realtime\FeedMessage(); |
$fh->setTimestamp(time()); | $fh = new transit_realtime\FeedHeader(); |
$fm->setHeader($fh); | $fh->setGtfsRealtimeVersion(1); |
foreach(getCurrentAlerts() as $alert) { | $fh->setTimestamp(time()); |
$informedEntities = getInformedAlerts($alert['id'],$_REQUEST['filter_class'],$_REQUEST['filter_id']); | $fm->setHeader($fh); |
$stops = Array(); | foreach (getCurrentAlerts() as $alert) { |
$routestrips = Array(); | $informedEntities = getInformedAlerts($alert['id'], $_REQUEST['filter_class'], $_REQUEST['filter_id']); |
if (sizeof($informedEntities) >0) { | $stops = Array(); |
if ($informedEntity['informed_class'] == "stop" && $informed["x-action"] == "remove") { | $routestrips = Array(); |
$stops[] = $informedEntity['informed_id']; | if (sizeof($informedEntities) > 0) { |
} | if ($informedEntity['informed_class'] == "stop" && $informed["x-action"] == "remove") { |
if (($informedEntity['informed_class'] == "route" || $informedEntity['informed_class'] == "trip") && $informed["x-action"] == "patch" ) { | $stops[] = $informedEntity['informed_id']; |
$routestrips[] = Array( "id" => $informedEntity['informed_id'], | } |
"type"=>$informedEntity['informed_class']); | 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']); | foreach ($routestrips as $routetrip) { |
$fe->setIsDeleted(false); | $fe = new transit_realtime\FeedEntity(); |
$tu = new transit_realtime\TripUpdate(); | $fe->setId($alert['id'] . $routetrip['id']); |
$td = new transit_realtime\TripDescriptor(); | $fe->setIsDeleted(false); |
if ($routetrip['type'] == "route") { | $tu = new transit_realtime\TripUpdate(); |
$td->setRouteId($routetrip['id']); | $td = new transit_realtime\TripDescriptor(); |
} else if ($routetrip['type'] == "trip") { | if ($routetrip['type'] == "route") { |
$td->setTripId($routetrip['id']); | $td->setRouteId($routetrip['id']); |
} | } else if ($routetrip['type'] == "trip") { |
$tu->setTrip($td); | $td->setTripId($routetrip['id']); |
foreach ($stops as $stop) { | } |
$stu = new transit_realtime\TripUpdate\StopTimeUpdate(); | $tu->setTrip($td); |
$stu->setStopId($stop); | foreach ($stops as $stop) { |
$stu->setScheduleRelationship(transit_realtime\TripUpdate\StopTimeUpdate\ScheduleRelationship::SKIPPED); | $stu = new transit_realtime\TripUpdate\StopTimeUpdate(); |
$tu->addStopTimeUpdate($stu); | $stu->setStopId($stop); |
} | $stu->setScheduleRelationship(transit_realtime\TripUpdate\StopTimeUpdate\ScheduleRelationship::SKIPPED); |
$fe->setTripUpdate($tu); | $tu->addStopTimeUpdate($stu); |
$fm->addEntity($fe); | } |
} | $fe->setTripUpdate($tu); |
$fm->addEntity($fe); | |
} | } |
return $fm; | } |
return $fm; | |
} | } |
function getTripUpdatesAsArray($filter_class = "", $filter_id = "") { | |
$codec = new DrSlump\Protobuf\Codec\PhpArray(); | function getTripUpdatesAsArray($filter_class = "", $filter_id = "") { |
return $codec->encode(getTripUpdates($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(); | function getTripUpdatesAsBinary($filter_class = "", $filter_id = "") { |
return $codec->encode(getTripUpdates($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(); | function getTripUpdatesAsJSON($filter_class = "", $filter_id = "") { |
return $codec->encode(getTripUpdates($filter_class, $filter_id)); | $codec = new DrSlump\Protobuf\Codec\Json(); |
} | return $codec->encode(getTripUpdates($filter_class, $filter_id)); |
} | |
} | } |
?> | ?> |
<?php | <?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'); | date_default_timezone_set('Australia/ACT'); |
$debugOkay = Array( | $debugOkay = Array( |
"session", | "session", |
"json", | "json", |
"phperror", | "phperror", |
"awsotp", | "awsotp", |
//"squallotp", | //"squallotp", |
//"vanilleotp", | //"vanilleotp", |
"database", | "database", |
"other" | "other" |
); | ); |
$GTFSREnabled = true; | $GTFSREnabled = true; |
$cloudmadeAPIkey = "daa03470bb8740298d4b10e3f03d63e6"; | $cloudmadeAPIkey = "daa03470bb8740298d4b10e3f03d63e6"; |
$googleMapsAPIkey = "ABQIAAAA95XYXN0cki3Yj_Sb71CFvBTPaLd08ONybQDjcH_VdYtHHLgZvRTw2INzI_m17_IoOUqH3RNNmlTk1Q"; | $googleMapsAPIkey = "ABQIAAAA95XYXN0cki3Yj_Sb71CFvBTPaLd08ONybQDjcH_VdYtHHLgZvRTw2INzI_m17_IoOUqH3RNNmlTk1Q"; |
$otpAPIurl = 'http://localhost:8080/opentripplanner-api-webapp/'; | $otpAPIurl = 'http://localhost:8080/opentripplanner-api-webapp/'; |
if (isDebug("awsotp") || php_uname('n') == "maxious.xen.prgmr.com") { | 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") { | 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")) { | 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")) { | if (isDebug("vanilleotp")) { |
$otpAPIurl = 'http://10.0.1.135:8080/opentripplanner-api-webapp/'; | $otpAPIurl = 'http://10.0.1.135:8080/opentripplanner-api-webapp/'; |
} | } |
if (isDebug("phperror")) error_reporting(E_ALL ^ E_NOTICE); | if (isDebug("phperror")) |
$labsPath = ""; | error_reporting(E_ALL ^ E_NOTICE); |
if (strstr($_SERVER['PHP_SELF'],"labs")) $labsPath = "../"; | $basePath = ""; |
if (strstr($_SERVER['PHP_SELF'], "labs/") | |
function isDebugServer() | || strstr($_SERVER['PHP_SELF'], "myway/") |
{ | || strstr($_SERVER['PHP_SELF'], "lib/") |
return php_sapi_name() == "cli" || isset($_SERVER['SERVER_NAME']) && ( $_SERVER['SERVER_NAME'] == "azusa" || $_SERVER['SERVER_NAME'] == "vanille" || $_SERVER['SERVER_NAME'] == | || strstr($_SERVER['PHP_SELF'], "geo/") |
"localhost" || $_SERVER['SERVER_NAME'] == "127.0.0.1") ; | || strstr($_SERVER['PHP_SELF'], "include/") |
|| 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"); | include_once ("common-geo.inc.php"); |
include_once ("common-net.inc.php"); | include_once ("common-net.inc.php"); |
include_once ("common-transit.inc.php"); | include_once ("common-transit.inc.php"); |
include_once ("common-db.inc.php"); | include_once ("common-db.inc.php"); |
include_once ("common-request.inc.php"); | include_once ("common-request.inc.php"); |
include_once ("common-session.inc.php"); | include_once ("common-session.inc.php"); |
include_once ("common-auth.inc.php"); | include_once ("common-auth.inc.php"); |
include_once ("common-template.inc.php"); | include_once ("common-template.inc.php"); |
function isAnalyticsOn() { | |
function isAnalyticsOn() | $user_agent = $_SERVER['HTTP_USER_AGENT']; |
{ | return!isDebugServer() && !preg_match('/cloudkick/i', $user_agent) && !preg_match('/googlebot/i', $user_agent) && |
$user_agent = $_SERVER['HTTP_USER_AGENT']; | !preg_match('/baidu/i', $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") { |
function isDebug($debugReason = "other") | global $debugOkay; |
{ | return in_array($debugReason, $debugOkay, false) && isDebugServer(); |
global $debugOkay; | } |
return in_array($debugReason, $debugOkay, false) && isDebugServer(); | |
} | function debug($msg, $debugReason = "other") { |
if (isDebug($debugReason)) | |
function debug($msg, $debugReason = "other") | echo "\n<!-- " . date(DATE_RFC822) . "\n $msg -->\n"; |
{ | } |
if (isDebug($debugReason)) echo "\n<!-- " . date(DATE_RFC822) . "\n $msg -->\n"; | function isIOSDevice() { |
} | return strstr($_SERVER['HTTP_USER_AGENT'], 'iPhone') || strstr($_SERVER['HTTP_USER_AGENT'], 'iPod') || strstr($_SERVER['HTTP_USER_AGENT'], 'iPad'); |
function isJQueryMobileDevice() | } |
{ | function isJQueryMobileDevice() { |
// http://forum.jquery.com/topic/what-is-the-best-way-to-detect-all-useragents-which-can-handle-jquery-mobile#14737000002087897 | // 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']; | $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); | 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']; | function array_flatten($a, $f = array()) { |
$fastDevices = Array( | if (!$a || !is_array($a)) |
"Mozilla/5.0 (X11;", | return ''; |
"Mozilla/5.0 (Windows;", | foreach ($a as $k => $v) { |
"Mozilla/5.0 (iP", | if (is_array($v)) |
"Mozilla/5.0 (Linux; U; Android", | $f = array_flatten($v, $f); |
"Mozilla/4.0 (compatible; MSIE" | else |
); | $f[$k] = $v; |
$slowDevices = Array( | } |
"J2ME", | return $f; |
"MIDP", | } |
"Opera/", | |
"Mozilla/2.0 (compatible;", | function remove_spaces($string) { |
"Mozilla/3.0 (compatible;" | return str_replace(' ', '', $string); |
); | } |
return true; | |
} | function object2array($object) { |
function array_flatten($a, $f = array()) | if (is_object($object)) { |
{ | foreach ($object as $key => $value) { |
if (!$a || !is_array($a)) return ''; | $array[$key] = $value; |
foreach ($a as $k => $v) { | } |
if (is_array($v)) $f = array_flatten($v, $f); | } else { |
else $f[$k] = $v; | $array = $object; |
} | } |
return $f; | return $array; |
} | } |
function remove_spaces($string) | |
{ | function startsWith($haystack, $needle, $case = true) { |
return str_replace(' ', '', $string); | if ($case) { |
} | return (strcmp(substr($haystack, 0, strlen($needle)), $needle) === 0); |
function object2array($object) | } |
{ | return (strcasecmp(substr($haystack, 0, strlen($needle)), $needle) === 0); |
if (is_object($object)) { | } |
foreach ($object as $key => $value) { | |
$array[$key] = $value; | function endsWith($haystack, $needle, $case = true) { |
} | if ($case) { |
} | return (strcmp(substr($haystack, strlen($haystack) - strlen($needle)), $needle) === 0); |
else { | } |
$array = $object; | return (strcasecmp(substr($haystack, strlen($haystack) - strlen($needle)), $needle) === 0); |
} | } |
return $array; | |
} | function bracketsMeanNewLine($input) { |
function startsWith($haystack, $needle, $case = true) | return str_replace(")", "</small>", str_replace("(", "<br><small>", $input)); |
{ | } |
if ($case) { | |
return (strcmp(substr($haystack, 0, strlen($needle)) , $needle) === 0); | function sksort(&$array, $subkey = "id", $sort_ascending = false) { |
} | if (count($array)) |
return (strcasecmp(substr($haystack, 0, strlen($needle)) , $needle) === 0); | $temp_array[key($array)] = array_shift($array); |
} | foreach ($array as $key => $val) { |
$offset = 0; | |
function endsWith($haystack, $needle, $case = true) | $found = false; |
{ | foreach ($temp_array as $tmp_key => $tmp_val) { |
if ($case) { | if (!$found and strtolower($val[$subkey]) > strtolower($tmp_val[$subkey])) { |
return (strcmp(substr($haystack, strlen($haystack) - strlen($needle)) , $needle) === 0); | $temp_array = array_merge((array) array_slice($temp_array, 0, $offset), array( |
} | $key => $val |
return (strcasecmp(substr($haystack, strlen($haystack) - strlen($needle)) , $needle) === 0); | ), array_slice($temp_array, $offset)); |
} | $found = true; |
function bracketsMeanNewLine($input) | } |
{ | $offset++; |
return str_replace(")", "</small>", str_replace("(", "<br><small>", $input)); | } |
} | if (!$found) |
function sksort(&$array, $subkey = "id", $sort_ascending = false) | $temp_array = array_merge($temp_array, array( |
{ | $key => $val |
if (count($array)) $temp_array[key($array) ] = array_shift($array); | )); |
foreach ($array as $key => $val) { | } |
$offset = 0; | if ($sort_ascending) |
$found = false; | $array = array_reverse($temp_array); |
foreach ($temp_array as $tmp_key => $tmp_val) { | else |
if (!$found and strtolower($val[$subkey]) > strtolower($tmp_val[$subkey])) { | $array = $temp_array; |
$temp_array = array_merge((array)array_slice($temp_array, 0, $offset) , array( | } |
$key => $val | |
) , array_slice($temp_array, $offset)); | function sktimesort(&$array, $subkey = "id", $sort_ascending = false) { |
$found = true; | if (count($array)) |
} | $temp_array[key($array)] = array_shift($array); |
$offset++; | foreach ($array as $key => $val) { |
} | $offset = 0; |
if (!$found) $temp_array = array_merge($temp_array, array( | $found = false; |
$key => $val | 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( |
if ($sort_ascending) $array = array_reverse($temp_array); | $key => $val |
else $array = $temp_array; | ), array_slice($temp_array, $offset)); |
} | $found = true; |
function sktimesort(&$array, $subkey = "id", $sort_ascending = false) | } |
{ | $offset++; |
if (count($array)) $temp_array[key($array) ] = array_shift($array); | } |
foreach ($array as $key => $val) { | if (!$found) |
$offset = 0; | $temp_array = array_merge($temp_array, array( |
$found = false; | $key => $val |
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( | if ($sort_ascending && isset($temp_array)) |
$key => $val | $array = array_reverse($temp_array); |
) , array_slice($temp_array, $offset)); | else |
$found = true; | $array = $temp_array; |
} | } |
$offset++; | |
} | function r_implode($glue, $pieces) { |
if (!$found) $temp_array = array_merge($temp_array, array( | foreach ($pieces as $r_pieces) { |
$key => $val | if (is_array($r_pieces)) { |
)); | $retVal[] = r_implode($glue, $r_pieces); |
} | } else { |
if ($sort_ascending && isset($temp_array)) $array = array_reverse($temp_array); | $retVal[] = $r_pieces; |
else $array = $temp_array; | } |
} | } |
function r_implode( $glue, $pieces ) | return implode($glue, $retVal); |
{ | } |
foreach( $pieces as $r_pieces ) | |
{ | |
if( is_array( $r_pieces ) ) | |
{ | |
$retVal[] = r_implode( $glue, $r_pieces ); | |
} | |
else | |
{ | |
$retVal[] = $r_pieces; | |
} | |
} | |
return implode( $glue, $retVal ); | |
} | |
?> | ?> |
<?php | <?php |
function getRoute($routeID) | |
/* | |
{ | * Copyright 2010,2011 Alexander Sadleir |
global $conn; | |
$query = "Select * from routes where route_id = :routeID LIMIT 1"; | Licensed under the Apache License, Version 2.0 (the "License"); |
debug($query, "database"); | you may not use this file except in compliance with the License. |
$query = $conn -> prepare($query); | You may obtain a copy of the License at |
$query -> bindParam(":routeID", $routeID); | |
$query -> execute(); | http://www.apache.org/licenses/LICENSE-2.0 |
if (!$query) { | |
databaseError($conn -> errorInfo()); | Unless required by applicable law or agreed to in writing, software |
return Array(); | distributed under the License is distributed on an "AS IS" BASIS, |
} | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
return $query -> fetch(PDO :: FETCH_ASSOC); | See the License for the specific language governing permissions and |
} | limitations under the License. |
*/ | |
function getRouteByFullName($routeFullName) | |
function getRoute($routeID) { | |
{ | global $conn; |
global $conn; | $query = "Select * from routes where route_id = :routeID LIMIT 1"; |
$query = "Select * from routes where route_short_name||route_long_name = :routeFullName LIMIT 1"; | debug($query, "database"); |
debug($query, "database"); | $query = $conn->prepare($query); |
$query = $conn -> prepare($query); | $query->bindParam(":routeID", $routeID); |
$query -> bindParam(":routeFullName", $routeFullName); | $query->execute(); |
$query -> execute(); | if (!$query) { |
if (!$query) { | databaseError($conn->errorInfo()); |
databaseError($conn -> errorInfo()); | return Array(); |
return Array(); | } |
} | return $query->fetch(PDO :: FETCH_ASSOC); |
return $query -> fetch(PDO :: FETCH_ASSOC); | } |
} | |
function getRouteByFullName($routeFullName) { | |
function getRoutes() | global $conn; |
$query = "Select * from routes where route_short_name||route_long_name = :routeFullName LIMIT 1"; | |
{ | debug($query, "database"); |
global $conn; | $query = $conn->prepare($query); |
$query = "Select * from routes order by route_short_name;"; | $query->bindParam(":routeFullName", $routeFullName); |
debug($query, "database"); | $query->execute(); |
$query = $conn -> prepare($query); | if (!$query) { |
$query -> execute(); | databaseError($conn->errorInfo()); |
if (!$query) { | return Array(); |
databaseError($conn -> errorInfo()); | } |
return Array(); | return $query->fetch(PDO :: FETCH_ASSOC); |
} | } |
return $query -> fetchAll(); | |
} | function getRoutes() { |
function getRoutesByNumber($routeNumber = "") | global $conn; |
$query = "Select * from routes order by route_short_name;"; | |
{ | debug($query, "database"); |
global $conn; | $query = $conn->prepare($query); |
if ($routeNumber != "") { | $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 = | $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 | 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;"; | where route_short_name = :routeNumber OR route_short_name LIKE :routeNumber2 order by route_short_name;"; |
} | } else { |
else { | |
$query = "SELECT DISTINCT route_short_name from routes order by route_short_name"; | $query = "SELECT DISTINCT route_short_name from routes order by route_short_name"; |
} | } |
debug($query, "database"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
if ($routeNumber != "") { | if ($routeNumber != "") { |
$query -> bindParam(":routeNumber", $routeNumber); | $query->bindParam(":routeNumber", $routeNumber); |
$routeNumber2 = "% " . $routeNumber; | $routeNumber2 = "% " . $routeNumber; |
$query -> bindParam(":routeNumber2", $routeNumber2); | $query->bindParam(":routeNumber2", $routeNumber2); |
} | } |
$query -> execute(); | $query->execute(); |
if (!$query) { | if (!$query) { |
databaseError($conn -> errorInfo()); | databaseError($conn->errorInfo()); |
return Array(); | return Array(); |
} | } |
return $query -> fetchAll(); | return $query->fetchAll(); |
} | } |
function getRoutesByNumberSeries($routeNumberSeries = "") | |
function getRoutesByNumberSeries($routeNumberSeries = "") { | |
{ | global $conn; |
global $conn; | if (strlen($routeNumberSeries) == 1) { |
if (strlen($routeNumberSeries) == 1) { | |
return getRoutesByNumber($routeNumberSeries); | return getRoutesByNumber($routeNumberSeries); |
} | } |
$seriesMin = substr($routeNumberSeries, 0, -1) . "0"; | $seriesMin = substr($routeNumberSeries, 0, -1) . "0"; |
$seriesMax = substr($routeNumberSeries, 0, -1) . "9"; | $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 = | $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;"; | 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"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
$query -> bindParam(":seriesMin", $seriesMin); | $query->bindParam(":seriesMin", $seriesMin); |
$query -> bindParam(":seriesMax", $seriesMax); | $query->bindParam(":seriesMax", $seriesMax); |
$routeNumberSeries = "% " . substr($routeNumberSeries, 0, -1) . "%"; | $routeNumberSeries = "% " . substr($routeNumberSeries, 0, -1) . "%"; |
$query -> bindParam(":routeNumberSeries", $routeNumberSeries); | $query->bindParam(":routeNumberSeries", $routeNumberSeries); |
$query -> execute(); | $query->execute(); |
if (!$query) { | if (!$query) { |
databaseError($conn -> errorInfo()); | databaseError($conn->errorInfo()); |
return Array(); | return Array(); |
} | } |
return $query -> fetchAll(); | return $query->fetchAll(); |
} | } |
function getRouteNextTrip($routeID) | |
function getRouteNextTrip($routeID) { | |
{ | global $conn; |
global $conn; | $query = "select * from routes join trips on trips.route_id = routes.route_id |
$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 | join stop_times on stop_times.trip_id = trips.trip_id where |
arrival_time > :currentTime and routes.route_id = :routeID order by | arrival_time > :currentTime and routes.route_id = :routeID order by |
arrival_time limit 1"; | arrival_time limit 1"; |
debug($query, "database"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
$query -> bindParam(":currentTime", current_time()); | $query->bindParam(":currentTime", current_time()); |
$query -> bindParam(":routeID", $routeID); | $query->bindParam(":routeID", $routeID); |
$query -> execute(); | $query->execute(); |
if (!$query) { | if (!$query) { |
databaseError($conn -> errorInfo()); | databaseError($conn->errorInfo()); |
return Array(); | return Array(); |
} | } |
$r = $query -> fetch(PDO :: FETCH_ASSOC); | $r = $query->fetch(PDO :: FETCH_ASSOC); |
// past last trip of the day special case | // past last trip of the day special case |
if (sizeof($r) < 16) { | if (sizeof($r) < 16) { |
$query = "select * from routes join trips on trips.route_id = routes.route_id | $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 | join stop_times on stop_times.trip_id = trips.trip_id where routes.route_id = :routeID order by |
arrival_time DESC limit 1"; | arrival_time DESC limit 1"; |
debug($query, "database"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
$query -> bindParam(":routeID", $routeID); | $query->bindParam(":routeID", $routeID); |
$query -> execute(); | $query->execute(); |
if (!$query) { | if (!$query) { |
databaseError($conn -> errorInfo()); | databaseError($conn->errorInfo()); |
return Array(); | return Array(); |
} | } |
$r = $query -> fetch(PDO :: FETCH_ASSOC); | $r = $query->fetch(PDO :: FETCH_ASSOC); |
} | } |
return $r; | return $r; |
} | } |
function getTimeInterpolatedRouteAtStop($routeID, $stop_id) | |
function getTimeInterpolatedRouteAtStop($routeID, $stop_id) { | |
{ | $nextTrip = getRouteNextTrip($routeID); |
$nextTrip = getRouteNextTrip($routeID); | if ($nextTrip['trip_id']) { |
if ($nextTrip['trip_id']) { | |
foreach (getTimeInterpolatedTrip($nextTrip['trip_id']) as $tripStop) { | foreach (getTimeInterpolatedTrip($nextTrip['trip_id']) as $tripStop) { |
if ($tripStop['stop_id'] == $stop_id) return $tripStop; | if ($tripStop['stop_id'] == $stop_id) |
} | return $tripStop; |
} | } |
} | |
return Array(); | return Array(); |
} | } |
function getRouteTrips($routeID) | |
function getRouteTrips($routeID) { | |
{ | global $conn; |
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 |
$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 | join stop_times on stop_times.trip_id = trips.trip_id where routes.route_id = :routeID and stop_sequence = '1' order by |
arrival_time "; | arrival_time "; |
debug($query, "database"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
$query -> bindParam(":routeID", $routeID); | $query->bindParam(":routeID", $routeID); |
$query -> execute(); | $query->execute(); |
if (!$query) { | if (!$query) { |
databaseError($conn -> errorInfo()); | databaseError($conn->errorInfo()); |
return Array(); | return Array(); |
} | } |
return $query -> fetchAll(); | return $query->fetchAll(); |
} | } |
function getRoutesByDestination($destination = "", $service_period = "") | |
function getRoutesByDestination($destination = "", $service_period = "") { | |
{ | global $conn; |
global $conn; | if ($service_period == "") |
if ($service_period == "") $service_period = service_period(); | $service_period = service_period(); |
if ($destination != "") { | if ($destination != "") { |
$query = "SELECT DISTINCT trips.route_id,route_short_name,route_long_name, service_id | $query = "SELECT DISTINCT trips.route_id,route_short_name,route_long_name, service_id |
FROM stop_times join trips on trips.trip_id = | FROM stop_times join trips on trips.trip_id = |
stop_times.trip_id join routes on trips.route_id = routes.route_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"; | WHERE route_long_name = :destination AND service_id=:service_period order by route_short_name"; |
} | } else { |
else { | |
$query = "SELECT DISTINCT route_long_name | $query = "SELECT DISTINCT route_long_name |
FROM stop_times join trips on trips.trip_id = | FROM stop_times join trips on trips.trip_id = |
stop_times.trip_id join routes on trips.route_id = routes.route_id | stop_times.trip_id join routes on trips.route_id = routes.route_id |
WHERE service_id= :service_period order by route_long_name"; | WHERE service_id= :service_period order by route_long_name"; |
} | } |
debug($query, "database"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
$query -> bindParam(":service_period", $service_period); | $query->bindParam(":service_period", $service_period); |
if ($destination != "") $query -> bindParam(":destination", $destination); | if ($destination != "") |
$query -> execute(); | $query->bindParam(":destination", $destination); |
if (!$query) { | $query->execute(); |
databaseError($conn -> errorInfo()); | if (!$query) { |
return Array(); | databaseError($conn->errorInfo()); |
} | return Array(); |
return $query -> fetchAll(); | } |
} | return $query->fetchAll(); |
function getRoutesBySuburb($suburb, $service_period = "") | } |
{ | function getRoutesBySuburb($suburb, $service_period = "") { |
if ($service_period == "") $service_period = service_period(); | if ($service_period == "") |
global $conn; | $service_period = service_period(); |
$query = "SELECT DISTINCT service_id,trips.route_id,route_short_name,route_long_name | 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 | FROM stop_times join trips on trips.trip_id = stop_times.trip_id |
join routes on trips.route_id = routes.route_id | join routes on trips.route_id = routes.route_id |
join stops on stops.stop_id = stop_times.stop_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"; | WHERE zone_id LIKE ':suburb AND service_id=:service_period ORDER BY route_short_name"; |
debug($query, "database"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
$query -> bindParam(":service_period", $service_period); | $query->bindParam(":service_period", $service_period); |
$suburb = "%" . $suburb . ";%"; | $suburb = "%" . $suburb . ";%"; |
$query -> bindParam(":suburb", $suburb); | $query->bindParam(":suburb", $suburb); |
$query -> execute(); | $query->execute(); |
if (!$query) { | if (!$query) { |
databaseError($conn -> errorInfo()); | databaseError($conn->errorInfo()); |
return Array(); | return Array(); |
} | } |
return $query -> fetchAll(); | return $query->fetchAll(); |
} | } |
function getRoutesNearby($lat, $lng, $limit = "", $distance = 500) | |
function getRoutesNearby($lat, $lng, $limit = "", $distance = 500) { | |
{ | if ($service_period == "") |
if ($service_period == "") $service_period = service_period(); | $service_period = service_period(); |
if ($limit != "") $limitSQL = " LIMIT :limit "; | if ($limit != "") |
global $conn; | $limitSQL = " LIMIT :limit "; |
$query = "SELECT service_id,trips.route_id,route_short_name,route_long_name,min(stops.stop_id) as stop_id, | 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 | min(ST_Distance(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), FALSE)) as distance |
FROM stop_times | FROM stop_times |
join trips on trips.trip_id = stop_times.trip_id | join trips on trips.trip_id = stop_times.trip_id |
join routes on trips.route_id = routes.route_id | join routes on trips.route_id = routes.route_id |
join stops on stops.stop_id = stop_times.stop_id | join stops on stops.stop_id = stop_times.stop_id |
WHERE service_id=:service_period | WHERE service_id=:service_period |
AND ST_DWithin(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), :distance, FALSE) | 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 | group by service_id,trips.route_id,route_short_name,route_long_name |
order by distance $limitSQL"; | order by distance $limitSQL"; |
debug($query, "database"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
$query -> bindParam(":service_period", $service_period); | $query->bindParam(":service_period", $service_period); |
$query -> bindParam(":distance", $distance); | $query->bindParam(":distance", $distance); |
if ($limit != "") $query -> bindParam(":limit", $limit); | if ($limit != "") |
$query -> execute(); | $query->bindParam(":limit", $limit); |
if (!$query) { | $query->execute(); |
databaseError($conn -> errorInfo()); | if (!$query) { |
return Array(); | databaseError($conn->errorInfo()); |
} | return Array(); |
return $query -> fetchAll(); | } |
} | return $query->fetchAll(); |
} | |
?> | ?> |
<?php | <?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); | |
} | |
function getServiceAlert($alertID) | /* |
{ | * Copyright 2010,2011 Alexander Sadleir |
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); | |
} | |
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 | |
function updateServiceAlert($alertID, $start, $end, $header, $description, $url) | http://www.apache.org/licenses/LICENSE-2.0 |
{ | |
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()); | Unless required by applicable law or agreed to in writing, software |
if (!$query) { | distributed under the License is distributed on an "AS IS" BASIS, |
databaseError($conn -> errorInfo()); | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
return Array(); | See the License for the specific language governing permissions and |
} | limitations under the License. |
return $query -> fetch(PDO :: FETCH_ASSOC); | */ |
} | |
function addServiceAlert($start, $end, $header, $description, $url) | function getServiceOverride($date = "") { |
{ | global $conn; |
global $conn; | $query = "Select * from calendar_dates where date = :date and exception_type = '1' LIMIT 1"; |
$query = 'INSERT INTO servicealerts_alerts (start, "end", header, description, url) VALUES (:start, :end, :header, :description, :url) '; | // debug($query,"database"); |
debug($query, "database"); | $query = $conn->prepare($query); // Create a prepared statement |
$query = $conn -> prepare($query); | $query->bindParam(":date", date("Ymd", ($date != "" ? $date : time()))); |
$query -> bindParam(":start", $start); | $query->execute(); |
$query -> bindParam(":end", $end); | if (!$query) { |
$query -> bindParam(":header", $header); | databaseError($conn->errorInfo()); |
$query -> bindParam(":description", $description); | return Array(); |
$query -> bindParam(":url", $url); | } |
$query -> execute(); | return $query->fetch(PDO :: FETCH_ASSOC); |
} | |
print_r($conn -> errorInfo()); | function getServiceAlert($alertID) { |
if (!$query) { | global $conn; |
databaseError($conn -> errorInfo()); | $query = "SELECT id,extract('epoch' from start) as start, extract('epoch' from end) as end,cause,effect,header,description,url from servicealerts_alerts where id = :servicealert_id"; |
return Array(); | debug($query, "database"); |
} | $query = $conn->prepare($query); |
return $query -> fetch(PDO :: FETCH_ASSOC); | $query->bindParam(":servicealert_id", $alertID); |
} | $query->execute(); |
if (!$query) { | |
databaseError($conn->errorInfo()); | |
return Array(); | |
} | |
return $query->fetch(PDO :: FETCH_ASSOC); | |
} | |
function getCurrentAlerts() | function updateServiceAlert($alertID, $start, $end, $header, $description, $url) { |
{ | global $conn; |
global $conn; | $query = 'update servicealerts_alerts set start=:start, "end"=:end, header=:header, description=:description, url=:url where id = :servicealert_id'; |
$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"); |
// debug($query, "database"); | $query = $conn->prepare($query); |
$query = $conn -> prepare($query); | $query->bindParam(":servicealert_id", $alertID); |
$query -> execute(); | $query->bindParam(":start", $start); |
if (!$query) { | $query->bindParam(":end", $end); |
databaseError($conn -> errorInfo()); | $query->bindParam(":header", $header); |
return Array(); | $query->bindParam(":description", $description); |
} | $query->bindParam(":url", $url); |
return $query -> fetchAll(); | $query->execute(); |
} | |
function getFutureAlerts() | print_r($conn->errorInfo()); |
{ | if (!$query) { |
global $conn; | databaseError($conn->errorInfo()); |
$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\""; | return Array(); |
// debug($query, "database"); | } |
$query = $conn -> prepare($query); | return $query->fetch(PDO :: FETCH_ASSOC); |
$query -> execute(); | } |
if (!$query) { | |
databaseError($conn -> errorInfo()); | function addServiceAlert($start, $end, $header, $description, $url) { |
return Array(); | global $conn; |
} | $query = 'INSERT INTO servicealerts_alerts (start, "end", header, description, url) VALUES (:start, :end, :header, :description, :url) '; |
return $query -> fetchAll(); | debug($query, "database"); |
} | $query = $conn->prepare($query); |
function getInformedAlerts($id, $filter_class, $filter_id) | $query->bindParam(":start", $start); |
{ | $query->bindParam(":end", $end); |
$query->bindParam(":header", $header); | |
global $conn; | $query->bindParam(":description", $description); |
$query = "SELECT * from servicealerts_informed where servicealert_id = :servicealert_id"; | $query->bindParam(":url", $url); |
$query->execute(); | |
if ($filter_class != "") { | |
print_r($conn->errorInfo()); | |
if (!$query) { | |
databaseError($conn->errorInfo()); | |
return Array(); | |
} | |
return $query->fetch(PDO :: FETCH_ASSOC); | |
} | |
function getCurrentAlerts() { | |
global $conn; | |
$query = "SELECT id,extract('epoch' from start) as start, extract('epoch' from 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 getFutureAlerts() { | |
global $conn; | |
$query = "SELECT id,extract('epoch' from start) as start, extract('epoch' from 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 "; | $query .= " AND informed_class = :informed_class "; |
} | |
} | |
if ($filter_id != "") { | if ($filter_id != "") { |
$query .= " AND informed_id = :informed_id "; | $query .= " AND informed_id = :informed_id "; |
} | |
} | |
// debug($query, "database"); | // debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
if ($filter_class != "") { | if ($filter_class != "") { |
$query -> bindParam(":informed_class", $filter_class); | $query->bindParam(":informed_class", $filter_class); |
} | } |
if ($filter_id != "") { | if ($filter_id != "") { |
$query -> bindParam(":informed_id", $filter_id); | $query->bindParam(":informed_id", $filter_id); |
} | } |
$query -> bindParam(":servicealert_id", $id); | $query->bindParam(":servicealert_id", $id); |
$query -> execute(); | $query->execute(); |
if (!$query) { | if (!$query) { |
databaseError($conn -> errorInfo()); | databaseError($conn->errorInfo()); |
return Array(); | return Array(); |
} | } |
return $query -> fetchAll(); | return $query->fetchAll(); |
} | } |
function deleteInformedAlert($serviceAlertID, $class, $id) | |
{ | function deleteInformedAlert($serviceAlertID, $class, $id) { |
global $conn; | global $conn; |
$query = 'DELETE from servicealerts_informed where servicealert_id = :servicealert_id and informed_class = :informed_class AND informed_id = :informed_id'; | $query = 'DELETE from servicealerts_informed where servicealert_id = :servicealert_id and informed_class = :informed_class AND informed_id = :informed_id'; |
debug($query, "database"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
$query -> bindParam(":servicealert_id", $serviceAlertID); | $query->bindParam(":servicealert_id", $serviceAlertID); |
$query -> bindParam(":informed_class", $class); | $query->bindParam(":informed_class", $class); |
$query -> bindParam(":informed_id", $id); | $query->bindParam(":informed_id", $id); |
$query -> execute(); | $query->execute(); |
print_r($conn -> errorInfo()); | print_r($conn->errorInfo()); |
if (!$query) { | if (!$query) { |
databaseError($conn -> errorInfo()); | databaseError($conn->errorInfo()); |
return Array(); | return Array(); |
} | } |
return null; | 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()); | function addInformedAlert($serviceAlertID, $class, $id, $action) { |
if (!$query) { | global $conn; |
databaseError($conn -> errorInfo()); | $query = 'INSERT INTO servicealerts_informed (servicealert_id , informed_class , informed_id) VALUES(:servicealert_id ,:informed_class, :informed_id)'; |
return Array(); | 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; | return null; |
} | |
} | |
?> | ?> |
<?php | <?php |
function getStop($stopID) | |
/* | |
{ | * Copyright 2010,2011 Alexander Sadleir |
global $conn; | |
$query = "Select * from stops where stop_id = :stopID LIMIT 1"; | Licensed under the Apache License, Version 2.0 (the "License"); |
debug($query, "database"); | you may not use this file except in compliance with the License. |
$query = $conn -> prepare($query); | You may obtain a copy of the License at |
$query -> bindParam(":stopID", $stopID); | |
$query -> execute(); | http://www.apache.org/licenses/LICENSE-2.0 |
if (!$query) { | |
databaseError($conn -> errorInfo()); | Unless required by applicable law or agreed to in writing, software |
return Array(); | distributed under the License is distributed on an "AS IS" BASIS, |
} | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
return $query -> fetch(PDO :: FETCH_ASSOC); | See the License for the specific language governing permissions and |
} | limitations under the License. |
function getStops($timingPointsOnly = false, $firstLetter = "", $startsWith = "") | */ |
{ | function getStop($stopID) { |
global $conn; | global $conn; |
$conditions = Array(); | $query = "Select * from stops where stop_id = :stopID LIMIT 1"; |
if ($timingPointsOnly) $conditions[] = "substr(stop_code,1,2) != 'Wj'"; | debug($query, "database"); |
if ($firstLetter != "") $conditions[] = "substr(stop_name,1,1) = :firstLetter"; | $query = $conn->prepare($query); |
if ($startsWith != "") $conditions[] = "stop_name like :startsWith"; | $query->bindParam(":stopID", $stopID); |
$query = "Select * from stops"; | $query->execute(); |
if (sizeof($conditions) > 0) { | 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) { | if (sizeof($conditions) > 1) { |
$query .= " Where " . implode(" AND ", $conditions) . " "; | $query .= " Where " . implode(" AND ", $conditions) . " "; |
} | } else { |
else { | |
$query .= " Where " . $conditions[0] . " "; | $query .= " Where " . $conditions[0] . " "; |
} | } |
} | } |
$query .= " order by stop_name;"; | $query .= " order by stop_name;"; |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
if ($firstLetter != "") $query -> bindParam(":firstLetter", $firstLetter); | if ($firstLetter != "") |
$query->bindParam(":firstLetter", $firstLetter); | |
if ($startsWith != "") { | |
if ($startsWith != "") { | |
$startsWith = $startsWith . "%"; | $startsWith = $startsWith . "%"; |
$query -> bindParam(":startsWith", $startsWith); | $query->bindParam(":startsWith", $startsWith); |
} | } |
$query -> execute(); | $query->execute(); |
if (!$query) { | if (!$query) { |
databaseError($conn -> errorInfo()); | databaseError($conn->errorInfo()); |
return Array(); | return Array(); |
} | } |
return $query -> fetchAll(); | return $query->fetchAll(); |
} | } |
function getNearbyStops($lat, $lng, $limit = "", $distance = 1000) | |
function getNearbyStops($lat, $lng, $limit = "", $distance = 1000) { | |
{ | if ($lat == null || $lng == null) |
if ($lat == null || $lng == null) return Array(); | return Array(); |
if ($limit != "") $limitSQL = " LIMIT :limit "; | if ($limit != "") |
global $conn; | $limitSQL = " LIMIT :limit "; |
$query = "Select *, ST_Distance(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), FALSE) as distance | 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) | from stops WHERE ST_DWithin(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), :distance, FALSE) |
order by distance $limitSQL;"; | order by distance $limitSQL;"; |
debug($query, "database"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
$query -> bindParam(":distance", $distance); | $query->bindParam(":distance", $distance); |
$query -> bindParam(":limit", $limit); | $query->bindParam(":limit", $limit); |
$query -> execute(); | $query->execute(); |
if (!$query) { | if (!$query) { |
databaseError($conn -> errorInfo()); | databaseError($conn->errorInfo()); |
return Array(); | return Array(); |
} | } |
return $query -> fetchAll(); | return $query->fetchAll(); |
} | } |
function getStopsByName($name) | |
function getStopsByName($name) { | |
{ | global $conn; |
global $conn; | $query = "Select * from stops where stop_name LIKE :name;"; |
$query = "Select * from stops where stop_name LIKE :name;"; | debug($query, "database"); |
debug($query, "database"); | $query = $conn->prepare($query); |
$query = $conn -> prepare($query); | $name = "%" . $name . ";%"; |
$name = "%" . $name . ";%"; | $query->bindParam(":name", $name); |
$query -> bindParam(":name", $name); | $query->execute(); |
$query -> execute(); | if (!$query) { |
if (!$query) { | databaseError($conn->errorInfo()); |
databaseError($conn -> errorInfo()); | return Array(); |
return Array(); | } |
} | return $query->fetchAll(); |
return $query -> fetchAll(); | } |
} | |
function getStopsBySuburb($suburb) | function getStopsBySuburb($suburb) { |
global $conn; | |
{ | $query = "Select * from stops where zone_id LIKE :suburb order by stop_name;"; |
global $conn; | debug($query, "database"); |
$query = "Select * from stops where zone_id LIKE :suburb order by stop_name;"; | $query = $conn->prepare($query); |
debug($query, "database"); | $suburb = "%" . $suburb . ";%"; |
$query = $conn -> prepare($query); | $query->bindParam(":suburb", $suburb); |
$suburb = "%" . $suburb . ";%"; | $query->execute(); |
$query -> bindParam(":suburb", $suburb); | if (!$query) { |
$query -> execute(); | databaseError($conn->errorInfo()); |
if (!$query) { | return Array(); |
databaseError($conn -> errorInfo()); | } |
return Array(); | return $query->fetchAll(); |
} | } |
return $query -> fetchAll(); | |
} | function getStopsByStopCode($stop_code, $startsWith = "") { |
function getStopsByStopCode($stop_code, $startsWith = "") | global $conn; |
$query = "Select * from stops where (stop_code = :stop_code OR stop_code LIKE :stop_code2)"; | |
{ | if ($startsWith != "") |
global $conn; | $query .= " AND stop_name like :startsWith"; |
$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); | |
debug($query, "database"); | |
$query = $conn -> prepare($query); | $query->bindParam(":stop_code", $stop_code); |
$stop_code2 = $stop_code . "%"; | |
$query -> bindParam(":stop_code", $stop_code); | $query->bindParam(":stop_code2", $stop_code2); |
$stop_code2 = $stop_code . "%"; | if ($startsWith != "") { |
$query -> bindParam(":stop_code2", $stop_code2); | |
if ($startsWith != "") { | |
$startsWith = $startsWith . "%"; | $startsWith = $startsWith . "%"; |
$query -> bindParam(":startsWith", $startsWith); | $query->bindParam(":startsWith", $startsWith); |
} | } |
$query -> execute(); | $query->execute(); |
if (!$query) { | if (!$query) { |
databaseError($conn -> errorInfo()); | databaseError($conn->errorInfo()); |
return Array(); | return Array(); |
} | } |
return $query -> fetchAll(); | return $query->fetchAll(); |
} | } |
function getStopRoutes($stopID, $service_period) | |
function getStopRoutes($stopID, $service_period) { | |
{ | if ($service_period == "") |
if ($service_period == "") $service_period = service_period(); | $service_period = service_period(); |
global $conn; | global $conn; |
$query = "SELECT distinct service_id,trips.route_id,route_short_name,route_long_name | $query = "SELECT distinct service_id,trips.route_id,route_short_name,route_long_name |
FROM stop_times join trips on trips.trip_id = | 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"; | 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"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
$query -> bindParam(":service_period", $service_period); | $query->bindParam(":service_period", $service_period); |
$query -> bindParam(":stopID", $stopID); | $query->bindParam(":stopID", $stopID); |
$query -> execute(); | $query->execute(); |
if (!$query) { | if (!$query) { |
databaseError($conn -> errorInfo()); | databaseError($conn->errorInfo()); |
return Array(); | return Array(); |
} | } |
return $query -> fetchAll(); | return $query->fetchAll(); |
} | } |
function getStopTrips($stopID, $service_period = "", $afterTime = "", $limit = "") | |
function getStopTrips($stopID, $service_period = "", $afterTime = "", $limit = "") { | |
{ | if ($service_period == "") |
if ($service_period == "") $service_period = service_period(); | $service_period = service_period(); |
if ($limit != "") $limitSQL = " LIMIT :limit "; | if ($limit != "") |
global $conn; | $limitSQL = " LIMIT :limit "; |
if ($afterTime != "") { | 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 | $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 | FROM stop_times |
join trips on trips.trip_id = | join trips on trips.trip_id = |
stop_times.trip_id | stop_times.trip_id |
join routes on trips.route_id = routes.route_id , (SELECT trip_id,max(arrival_time) as arrival_time from stop_times | join routes on trips.route_id = routes.route_id , (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 stop_times.arrival_time IS NOT NULL group by trip_id) as end_times |
WHERE stop_times.stop_id = :stopID | WHERE stop_times.stop_id = :stopID |
AND stop_times.trip_id = end_times.trip_id | AND stop_times.trip_id = end_times.trip_id |
AND service_id=:service_period | AND service_id=:service_period |
AND end_times.arrival_time > :afterTime | AND end_times.arrival_time > :afterTime |
ORDER BY end_time $limitSQL"; | ORDER BY end_time $limitSQL"; |
} | } else { |
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 | $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 | FROM stop_times |
join trips on trips.trip_id = | join trips on trips.trip_id = |
stop_times.trip_id | stop_times.trip_id |
join routes on trips.route_id = routes.route_id | join routes on trips.route_id = routes.route_id |
WHERE stop_times.stop_id = :stopID | WHERE stop_times.stop_id = :stopID |
AND service_id=:service_period | AND service_id=:service_period |
ORDER BY arrival_time $limitSQL"; | ORDER BY arrival_time $limitSQL"; |
} | } |
debug($query, "database"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
$query -> bindParam(":service_period", $service_period); | $query->bindParam(":service_period", $service_period); |
$query -> bindParam(":stopID", $stopID); | $query->bindParam(":stopID", $stopID); |
if ($limit != "") $query -> bindParam(":limit", $limit); | if ($limit != "") |
if ($afterTime != "") $query -> bindParam(":afterTime", $afterTime); | $query->bindParam(":limit", $limit); |
$query -> execute(); | if ($afterTime != "") |
if (!$query) { | $query->bindParam(":afterTime", $afterTime); |
databaseError($conn -> errorInfo()); | $query->execute(); |
return Array(); | if (!$query) { |
} | databaseError($conn->errorInfo()); |
return $query -> fetchAll(); | return Array(); |
} | } |
function getStopTripsWithTimes($stopID, $time = "", $service_period = "", $time_range = "", $limit = "") | return $query->fetchAll(); |
} | |
{ | |
if ($service_period == "") $service_period = service_period(); | function getStopTripsWithTimes($stopID, $time = "", $service_period = "", $time_range = "", $limit = "") { |
if ($time_range == "") $time_range = (24 * 60 * 60); | if ($service_period == "") |
if ($time == "") $time = current_time(); | $service_period = service_period(); |
if ($limit == "") $limit = 10; | if ($time_range == "") |
$trips = getStopTrips($stopID, $service_period, $time); | $time_range = (24 * 60 * 60); |
$timedTrips = Array(); | if ($time == "") |
if ($trips && sizeof($trips) > 0) { | $time = current_time(); |
if ($limit == "") | |
$limit = 10; | |
$trips = getStopTrips($stopID, $service_period, $time); | |
$timedTrips = Array(); | |
if ($trips && sizeof($trips) > 0) { | |
foreach ($trips as $trip) { | foreach ($trips as $trip) { |
if ($trip['arrival_time'] != "") { | if ($trip['arrival_time'] != "") { |
if (strtotime($trip['arrival_time']) > strtotime($time) and strtotime($trip['arrival_time']) < (strtotime($time) + $time_range)) { | if (strtotime($trip['arrival_time']) > strtotime($time) and strtotime($trip['arrival_time']) < (strtotime($time) + $time_range)) { |
$timedTrips[] = $trip; | $timedTrips[] = $trip; |
} | } |
} | } else { |
else { | |
$timedTrip = getTimeInterpolatedTripAtStop($trip['trip_id'], $trip['stop_sequence']); | $timedTrip = getTimeInterpolatedTripAtStop($trip['trip_id'], $trip['stop_sequence']); |
if ($timedTrip['arrival_time'] > $time and strtotime($timedTrip['arrival_time']) < (strtotime($time) + $time_range)) { | if ($timedTrip['arrival_time'] > $time and strtotime($timedTrip['arrival_time']) < (strtotime($time) + $time_range)) { |
$timedTrips[] = $timedTrip; | $timedTrips[] = $timedTrip; |
} | } |
} | } |
if (sizeof($timedTrips) > $limit) break; | if (sizeof($timedTrips) > $limit) |
} | break; |
} | |
sktimesort($timedTrips, "arrival_time", true); | sktimesort($timedTrips, "arrival_time", true); |
} | } |
return $timedTrips; | return $timedTrips; |
} | } |
?> | ?> |
<?php | <?php |
function getTrip($tripID) | |
/* | |
{ | * Copyright 2010,2011 Alexander Sadleir |
global $conn; | |
$query = "Select * from trips | 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 | join routes on trips.route_id = routes.route_id |
where trip_id = :tripID | where trip_id = :tripID |
LIMIT 1"; | LIMIT 1"; |
debug($query, "database"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
$query -> bindParam(":tripID", $tripID); | $query->bindParam(":tripID", $tripID); |
$query -> execute(); | $query->execute(); |
if (!$query) { | if (!$query) { |
databaseError($conn -> errorInfo()); | databaseError($conn->errorInfo()); |
return Array(); | return Array(); |
} | } |
return $query -> fetch(PDO :: FETCH_ASSOC); | return $query->fetch(PDO :: FETCH_ASSOC); |
} | } |
function getTripShape($tripID) | |
function getTripShape($tripID) { | |
{ | global $conn; |
global $conn; | $query = "SELECT ST_AsKML(ST_MakeLine(geometry(a.position))) as the_route |
$query = "SELECT ST_AsKML(ST_MakeLine(geometry(a.position))) as the_route | |
FROM (SELECT position, | FROM (SELECT position, |
stop_sequence, trips.trip_id | stop_sequence, trips.trip_id |
FROM stop_times | FROM stop_times |
join trips on trips.trip_id = stop_times.trip_id | join trips on trips.trip_id = stop_times.trip_id |
join stops on stops.stop_id = stop_times.stop_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"; | WHERE trips.trip_id = :tripID ORDER BY stop_sequence) as a group by a.trip_id"; |
debug($query, "database"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
$query -> bindParam(":tripID", $tripID); | $query->bindParam(":tripID", $tripID); |
$query -> execute(); | $query->execute(); |
if (!$query) { | if (!$query) { |
databaseError($conn -> errorInfo()); | databaseError($conn->errorInfo()); |
return Array(); | return Array(); |
} | } |
return $query -> fetchColumn(0); | return $query->fetchColumn(0); |
} | } |
function getTimeInterpolatedTrip($tripID, $range = "") | |
function getTimeInterpolatedTrip($tripID, $range = "") { | |
{ | global $conn; |
global $conn; | $query = "SELECT stop_times.trip_id,arrival_time,stop_times.stop_id,stop_lat,stop_lon,stop_name,stop_code, |
$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 | stop_sequence,service_id,trips.route_id,route_short_name,route_long_name |
FROM stop_times | FROM stop_times |
join trips on trips.trip_id = stop_times.trip_id | join trips on trips.trip_id = stop_times.trip_id |
join routes on trips.route_id = routes.route_id | join routes on trips.route_id = routes.route_id |
join stops on stops.stop_id = stop_times.stop_id | join stops on stops.stop_id = stop_times.stop_id |
WHERE trips.trip_id = :tripID $range ORDER BY stop_sequence"; | WHERE trips.trip_id = :tripID $range ORDER BY stop_sequence"; |
debug($query, "database"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
$query -> bindParam(":tripID", $tripID); | $query->bindParam(":tripID", $tripID); |
$query -> execute(); | $query->execute(); |
if (!$query) { | if (!$query) { |
databaseError($conn -> errorInfo()); | databaseError($conn->errorInfo()); |
return Array(); | return Array(); |
} | } |
$stopTimes = $query -> fetchAll(); | $stopTimes = $query->fetchAll(); |
$cur_timepoint = Array(); | $cur_timepoint = Array(); |
$next_timepoint = Array(); | $next_timepoint = Array(); |
$distance_between_timepoints = 0.0; | $distance_between_timepoints = 0.0; |
$distance_traveled_between_timepoints = 0.0; | $distance_traveled_between_timepoints = 0.0; |
$rv = Array(); | $rv = Array(); |
foreach ($stopTimes as $i => $stopTime) { | foreach ($stopTimes as $i => $stopTime) { |
if ($stopTime['arrival_time'] != "") { | if ($stopTime['arrival_time'] != "") { |
// is timepoint | // is timepoint |
$cur_timepoint = $stopTime; | $cur_timepoint = $stopTime; |
$distance_between_timepoints = 0.0; | $distance_between_timepoints = 0.0; |
$distance_traveled_between_timepoints = 0.0; | $distance_traveled_between_timepoints = 0.0; |
if ($i + 1 < sizeof($stopTimes)) { | if ($i + 1 < sizeof($stopTimes)) { |
$k = $i + 1; | $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"]); | $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)) { | while ($stopTimes[$k]["arrival_time"] == "" && $k + 1 < sizeof($stopTimes)) { |
$k += 1; | $k += 1; |
// echo "k".$k; | // 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"]); | $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]; | $next_timepoint = $stopTimes[$k]; |
} | |
} | |
$rv[] = $stopTime; | $rv[] = $stopTime; |
} | } else { |
else { | |
// is untimed point | // is untimed point |
// echo "i".$i; | // 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"]); | $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>"; | // echo "$distance_traveled_between_timepoints / $distance_between_timepoints<br>"; |
$distance_percent = $distance_traveled_between_timepoints / $distance_between_timepoints; | $distance_percent = $distance_traveled_between_timepoints / $distance_between_timepoints; |
if ($next_timepoint["arrival_time"] != "") { | if ($next_timepoint["arrival_time"] != "") { |
$total_time = strtotime($next_timepoint["arrival_time"]) - strtotime($cur_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>"; | // echo strtotime($next_timepoint["arrival_time"])." - ".strtotime($cur_timepoint["arrival_time"])."<br>"; |
$time_estimate = ($distance_percent * $total_time) + strtotime($cur_timepoint["arrival_time"]); | $time_estimate = ($distance_percent * $total_time) + strtotime($cur_timepoint["arrival_time"]); |
$stopTime["arrival_time"] = date("H:i:s", $time_estimate); | $stopTime["arrival_time"] = date("H:i:s", $time_estimate); |
} | } else { |
else { | |
$stopTime["arrival_time"] = $cur_timepoint["arrival_time"]; | $stopTime["arrival_time"] = $cur_timepoint["arrival_time"]; |
} | } |
$rv[] = $stopTime; | $rv[] = $stopTime; |
} | |
} | |
} | |
} | |
// var_dump($rv); | // var_dump($rv); |
return $rv; | return $rv; |
} | } |
function getTripPreviousTimePoint($tripID, $stop_sequence) | |
function getTripPreviousTimePoint($tripID, $stop_sequence) { | |
{ | global $conn; |
global $conn; | $query = " SELECT trip_id,stop_id, |
$query = " SELECT trip_id,stop_id, | |
stop_sequence | stop_sequence |
FROM stop_times | FROM stop_times |
WHERE trip_id = :tripID and stop_sequence < :stop_sequence | WHERE trip_id = :tripID and stop_sequence < :stop_sequence |
and stop_times.arrival_time IS NOT NULL ORDER BY stop_sequence DESC LIMIT 1"; | and stop_times.arrival_time IS NOT NULL ORDER BY stop_sequence DESC LIMIT 1"; |
debug($query, "database"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
$query -> bindParam(":tripID", $tripID); | $query->bindParam(":tripID", $tripID); |
$query -> bindParam(":stop_sequence", $stop_sequence); | $query->bindParam(":stop_sequence", $stop_sequence); |
$query -> execute(); | $query->execute(); |
if (!$query) { | if (!$query) { |
databaseError($conn -> errorInfo()); | databaseError($conn->errorInfo()); |
return Array(); | return Array(); |
} | } |
return $query -> fetch(PDO :: FETCH_ASSOC); | return $query->fetch(PDO :: FETCH_ASSOC); |
} | } |
function getTripNextTimePoint($tripID, $stop_sequence) | |
function getTripNextTimePoint($tripID, $stop_sequence) { | |
{ | global $conn; |
global $conn; | $query = " SELECT trip_id,stop_id, |
$query = " SELECT trip_id,stop_id, | |
stop_sequence | stop_sequence |
FROM stop_times | FROM stop_times |
WHERE trip_id = :tripID and stop_sequence > :stop_sequence | WHERE trip_id = :tripID and stop_sequence > :stop_sequence |
and stop_times.arrival_time IS NOT NULL ORDER BY stop_sequence LIMIT 1"; | and stop_times.arrival_time IS NOT NULL ORDER BY stop_sequence LIMIT 1"; |
debug($query, "database"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
$query -> bindParam(":tripID", $tripID); | $query->bindParam(":tripID", $tripID); |
$query -> bindParam(":stop_sequence", $stop_sequence); | $query->bindParam(":stop_sequence", $stop_sequence); |
$query -> execute(); | $query->execute(); |
if (!$query) { | if (!$query) { |
databaseError($conn -> errorInfo()); | databaseError($conn->errorInfo()); |
return Array(); | return Array(); |
} | } |
return $query -> fetch(PDO :: FETCH_ASSOC); | return $query->fetch(PDO :: FETCH_ASSOC); |
} | } |
function getTimeInterpolatedTripAtStop($tripID, $stop_sequence) | |
function getTimeInterpolatedTripAtStop($tripID, $stop_sequence) { | |
{ | global $conn; |
global $conn; | // limit interpolation to between nearest actual points. |
// limit interpolation to between nearest actual points. | |
$prevTimePoint = getTripPreviousTimePoint($tripID, $stop_sequence); | $prevTimePoint = getTripPreviousTimePoint($tripID, $stop_sequence); |
$nextTimePoint = getTripNextTimePoint($tripID, $stop_sequence); | $nextTimePoint = getTripNextTimePoint($tripID, $stop_sequence); |
// echo " prev {$lowestDelta['stop_sequence']} next {$nextTimePoint['stop_sequence']} "; | // echo " prev {$lowestDelta['stop_sequence']} next {$nextTimePoint['stop_sequence']} "; |
$range = ""; | $range = ""; |
if ($prevTimePoint != "") $range .= " AND stop_sequence >= '{$prevTimePoint['stop_sequence']}'"; | if ($prevTimePoint != "") |
if ($nextTimePoint != "") $range .= " AND stop_sequence <= '{$nextTimePoint['stop_sequence']}'"; | $range .= " AND stop_sequence >= '{$prevTimePoint['stop_sequence']}'"; |
foreach (getTimeInterpolatedTrip($tripID, $range) as $tripStop) { | if ($nextTimePoint != "") |
if ($tripStop['stop_sequence'] == $stop_sequence) return $tripStop; | $range .= " AND stop_sequence <= '{$nextTimePoint['stop_sequence']}'"; |
} | foreach (getTimeInterpolatedTrip($tripID, $range) as $tripStop) { |
if ($tripStop['stop_sequence'] == $stop_sequence) | |
return $tripStop; | |
} | |
return Array(); | return Array(); |
} | } |
function getTripStartTime($tripID) | |
function getTripStartTime($tripID) { | |
{ | global $conn; |
global $conn; | $query = "Select * from stop_times |
$query = "Select * from stop_times | |
where trip_id = :tripID | where trip_id = :tripID |
AND arrival_time IS NOT NULL | AND arrival_time IS NOT NULL |
AND stop_sequence = '1'"; | AND stop_sequence = '1'"; |
debug($query, "database"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
$query -> bindParam(":tripID", $tripID); | $query->bindParam(":tripID", $tripID); |
$query -> execute(); | $query->execute(); |
if (!$query) { | if (!$query) { |
databaseError($conn -> errorInfo()); | databaseError($conn->errorInfo()); |
return Array(); | return Array(); |
} | } |
$r = $query -> fetch(PDO :: FETCH_ASSOC); | $r = $query->fetch(PDO :: FETCH_ASSOC); |
return $r['arrival_time']; | return $r['arrival_time']; |
} | } |
function getTripEndTime($tripID) | |
function getTripEndTime($tripID) { | |
{ | global $conn; |
global $conn; | $query = "SELECT trip_id,max(arrival_time) as arrival_time from stop_times |
$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"; | WHERE stop_times.arrival_time IS NOT NULL and trip_id = :tripID group by trip_id"; |
debug($query, "database"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
$query -> bindParam(":tripID", $tripID); | $query->bindParam(":tripID", $tripID); |
$query -> execute(); | $query->execute(); |
if (!$query) { | if (!$query) { |
databaseError($conn -> errorInfo()); | databaseError($conn->errorInfo()); |
return Array(); | return Array(); |
} | } |
$r = $query -> fetch(PDO :: FETCH_ASSOC); | $r = $query->fetch(PDO :: FETCH_ASSOC); |
return $r['arrival_time']; | return $r['arrival_time']; |
} | } |
function getActiveTrips($time) | |
function getActiveTrips($time) { | |
{ | global $conn; |
global $conn; | if ($time == "") |
if ($time == "") $time = current_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 | $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 | 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"; | 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"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
$query -> bindParam(":time", $time); | $query->bindParam(":time", $time); |
$query -> execute(); | $query->execute(); |
if (!$query) { | if (!$query) { |
databaseError($conn -> errorInfo()); | databaseError($conn->errorInfo()); |
return Array(); | return Array(); |
} | } |
return $query -> fetchAll(); | return $query->fetchAll(); |
} | } |
function viaPoints($tripID, $stop_sequence = "", $timing_points_only = true) | |
function viaPoints($tripID, $stop_sequence = "", $timing_points_only = true) { | |
{ | global $conn; |
global $conn; | $query = "SELECT stops.stop_id, stop_name, arrival_time |
$query = "SELECT stops.stop_id, stop_name, arrival_time | |
FROM stop_times join stops on stops.stop_id = stop_times.stop_id | FROM stop_times join stops on stops.stop_id = stop_times.stop_id |
WHERE stop_times.trip_id = :tripID | WHERE stop_times.trip_id = :tripID |
" . ($stop_sequence != "" ? " AND stop_sequence > :stop_sequence " : "") . ($timing_points_only ? "AND substr(stop_code,1,2) != 'Wj' ": ""). " ORDER BY stop_sequence"; | " . ($stop_sequence != "" ? " AND stop_sequence > :stop_sequence " : "") . ($timing_points_only ? "AND substr(stop_code,1,2) != 'Wj' " : "") . " ORDER BY stop_sequence"; |
debug($query, "database"); | debug($query, "database"); |
$query = $conn -> prepare($query); | $query = $conn->prepare($query); |
if ($stop_sequence != "") $query -> bindParam(":stop_sequence", $stop_sequence); | if ($stop_sequence != "") |
$query -> bindParam(":tripID", $tripID); | $query->bindParam(":stop_sequence", $stop_sequence); |
$query -> execute(); | $query->bindParam(":tripID", $tripID); |
if (!$query) { | $query->execute(); |
databaseError($conn -> errorInfo()); | if (!$query) { |
return Array(); | databaseError($conn->errorInfo()); |
} | return Array(); |
return $query -> fetchAll(); | } |
} | return $query->fetchAll(); |
function viaPointNames($tripid, $stop_sequence = "") | } |
{ | function viaPointNames($tripid, $stop_sequence = "") { |
$viaPointNames = Array(); | $viaPointNames = Array(); |
foreach (viaPoints($tripid, $stop_sequence) as $point) { | foreach (viaPoints($tripid, $stop_sequence) as $point) { |
$viaPointNames[] = $point['stop_name']; | $viaPointNames[] = $point['stop_name']; |
} | } |
if (sizeof($viaPointNames) > 0) { | if (sizeof($viaPointNames) > 0) { |
return r_implode(", ", $viaPointNames); | return r_implode(", ", $viaPointNames); |
} | } else { |
else { | |
return ""; | return ""; |
} | } |
} | } |
?> | ?> |
<?php | <?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 ('include/common.inc.php'); |
include_header("bus.lambdacomplex.org", "index", false) | include_header("bus.lambdacomplex.org", "index", false) |
?> | ?> |
<div data-role="page"> | <div data-role="page"> |
<div data-role="content"> | <div data-role="content"> |
<div id="jqm-homeheader"> | <div id="jqm-homeheader"> |
<h1>busness time</h1><br><small>Canberra Bus Timetables and Trip Planner</small> | <h1>busness time</h1><br><small>Canberra Bus Timetables and Trip Planner</small> |
</div> | </div> |
<a name="maincontent" id="maincontent"></a> | <a name="maincontent" id="maincontent"></a> |
<a href="tripPlanner.php" data-role="button" data-icon="navigation">Launch Trip Planner...</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"> | <ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b"> |
<li data-role="list-divider">Timetables - Stops</li> | <li data-role="list-divider">Timetables - Stops</li> |
<li><a href="stopList.php">Major (Timing Point) Stops</a></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?allstops=yes">All Stops</a></li> |
<li><a href="stopList.php?bysuburbs=yes">Stops By Suburb</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> | <li><a class="nearby" href="stopList.php?nearby=yes">Nearby Stops</a></li> |
</ul> | </ul> |
<ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b"> | <ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b"> |
<li data-role="list-divider">Timetables - Routes</li> | <li data-role="list-divider">Timetables - Routes</li> |
<li><a href="routeList.php">Routes By Final Destination</a></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?bynumber=yes">Routes By Number</a></li> |
<li><a href="routeList.php?bysuburbs=yes">Routes By Suburb</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> | <li><a class="nearby" href="routeList.php?nearby=yes">Nearby Routes</a></li> |
</ul> | </ul> |
<?php | <?php |
echo ' <a href="labs/index.php" data-role="button" data-icon="beaker">Busness R&D</a>'; | echo ' <a href="labs/index.php" data-role="button" data-icon="beaker">Busness R&D</a>'; |
include_footer(true) | echo ' <a href="myway/index.php" data-role="button">MyWay Balance and Timeliness Survey Results</a>'; |
?> | include_footer(true) |
?> | |
/*! | |
* 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 ); | |
/*! | |
* jQuery Mobile v1.0rc1 | |
* 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", { | |
// decorate the parent _createWidget to trigger `widgetinit` for users | |
// who wish to do post post `widgetcreate` alterations/additions | |
// | |
// TODO create a pull request for jquery ui to trigger this event | |
// in the original _createWidget | |
_createWidget: function() { | |
$.Widget.prototype._createWidget.apply( this, arguments ); | |
this._trigger( 'init' ); | |
}, | |
_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 : a workaround for window.matchMedia | |
* 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() | |
}); | |
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 = "addEventListener" in document, | |
$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 ]; | |
} | |
} | |
// make sure that if the mouse and click virtual events are generated | |
// without a .which one is defined | |
if ( t.search(/mouse(down|up)|click/) > -1 && !event.which ){ | |
event.which = 1; | |
} | |
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 ) { | |
var result; | |
if ( typeof prop != "undefined" ) { | |
result = this.data( prop ? $.mobile.nsNormalize( prop ) : prop, value ); | |
} | |
return result; | |
}; | |
$.jqmData = function( elem, prop, value ) { | |
var result; | |
if ( typeof prop != "undefined" ) { | |
result = $.data( elem, prop ? $.mobile.nsNormalize( prop ) : prop, value ); | |
} | |
return result; | |
}; | |
$.fn.jqmRemoveData = function( prop ) { | |
return this.removeData( $.mobile.nsNormalize( prop ) ); | |
}; | |
$.jqmRemoveData = function( elem, prop ) { | |
return $.removeData( elem, $.mobile.nsNormalize( prop ) ); | |
}; | |
$.fn.removeWithDependents = function() { | |
$.removeWithDependents( this ); | |
}; | |
$.removeWithDependents = function( elem ) { | |
var $elem = $( elem ); | |
( $elem.jqmData('dependents') || $() ).remove(); | |
$elem.remove(); | |
}; | |
$.fn.addDependents = function( newDependents ) { | |
$.addDependents( $(this), newDependents ); | |
}; | |
$.addDependents = function( elem, newDependents ) { | |
var dependents = $(elem).jqmData( 'dependents' ) || $(); | |
$(elem).jqmData( 'dependents', $.merge(dependents, newDependents) ); | |
}; | |
// note that this helper doesn't attempt to handle the callback | |
// or setting of an html elements text, its only purpose is | |
// to return the html encoded version of the text in all cases. (thus the name) | |
$.fn.getEncodedText = function() { | |
return $( "<div/>" ).text( $(this).text() ).html(); | |
}; | |
// 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]: // | |
// [6]: jblas:password@mycompany.com:8080 | |
// [7]: jblas:password | |
// [8]: jblas | |
// [9]: password | |
// [10]: mycompany.com:8080 | |
// [11]: mycompany.com | |
// [12]: 8080 | |
// [13]: /mail/inbox | |
// [14]: /mail/ | |
// [15]: inbox | |
// [16]: ?msg=1234&type=unread | |
// [17]: #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 matches = path.urlParseRE.exec( url || "" ) || []; | |
// 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. | |
return { | |
href: matches[ 0 ] || "", | |
hrefNoHash: matches[ 1 ] || "", | |
hrefNoSearch: matches[ 2 ] || "", | |
domain: matches[ 3 ] || "", | |
protocol: matches[ 4 ] || "", | |
doubleSlash: matches[ 5 ] || "", | |
authority: matches[ 6 ] || "", | |
username: matches[ 8 ] || "", | |
password: matches[ 9 ] || "", | |
host: matches[ 10 ] || "", | |
hostname: matches[ 11 ] || "", | |
port: matches[ 12 ] || "", | |
pathname: matches[ 13 ] || "", | |
directory: matches[ 14 ] || "", | |
filename: matches[ 15 ] || "", | |
search: matches[ 16 ] || "", | |
hash: matches[ 17 ] || "" | |
}; | |
}, | |
//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, | |
doubleSlash = relObj.protocol ? relObj.doubleSlash : ( relObj.doubleSlash || absObj.doubleSlash ); | |
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 + doubleSlash + 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 setLastScrollEnabled = true, | |
firstScrollElem, getScrollElem, setLastScroll, delayedSetLastScroll; | |
getScrollElem = function() { | |
var scrollElem = $window, activePage, | |
touchOverflow = $.support.touchOverflow && $.mobile.touchOverflowEnabled; | |
if( touchOverflow ){ | |
activePage = $( ".ui-page-active" ); | |
scrollElem = activePage.is( ".ui-native-fixed" ) ? activePage.find( ".ui-content" ) : activePage; | |
} | |
return scrollElem; | |
}; | |
setLastScroll = function( scrollElem ) { | |
// this barrier prevents setting the scroll value based on the browser | |
// scrolling the window based on a hashchange | |
if( !setLastScrollEnabled ) { | |
return; | |
} | |
var active = $.mobile.urlHistory.getActive(); | |
if( active ) { | |
var lastScroll = scrollElem && scrollElem.scrollTop(); | |
// Set active page's lastScroll prop. | |
// If the location we're scrolling to is less than minScrollBack, let it go. | |
active.lastScroll = lastScroll < $.mobile.minScrollBack ? $.mobile.defaultHomeScroll : lastScroll; | |
} | |
}; | |
// bind to scrollstop to gather scroll position. The delay allows for the hashchange | |
// event to fire and disable scroll recording in the case where the browser scrolls | |
// to the hash targets location (sometimes the top of the page). once pagechange fires | |
// getLastScroll is again permitted to operate | |
delayedSetLastScroll = function() { | |
setTimeout( setLastScroll, 100, $(this) ); | |
}; | |
// disable an scroll setting when a hashchange has been fired, this only works | |
// because the recording of the scroll position is delayed for 100ms after | |
// the browser might have changed the position because of the hashchange | |
$window.bind( $.support.pushState ? "popstate" : "hashchange", function() { | |
setLastScrollEnabled = false; | |
}); | |
// handle initial hashchange from chrome :( | |
$window.one( $.support.pushState ? "popstate" : "hashchange", function() { | |
setLastScrollEnabled = true; | |
}); | |
// wait until the mobile page container has been determined to bind to pagechange | |
$window.one( "pagecontainercreate", function(){ | |
// once the page has changed, re-enable the scroll recording | |
$.mobile.pageContainer.bind( "pagechange", function() { | |
var scrollElem = getScrollElem(); | |
setLastScrollEnabled = true; | |
// remove any binding that previously existed on the get scroll | |
// which may or may not be different than the scroll element determined for | |
// this page previously | |
scrollElem.unbind( "scrollstop", delayedSetLastScroll ); | |
// determine and bind to the current scoll element which may be the window | |
// or in the case of touch overflow the element with touch overflow | |
scrollElem.bind( "scrollstop", delayedSetLastScroll ); | |
}); | |
}); | |
// bind to scrollstop for the first page as "pagechange" won't be fired in that case | |
getScrollElem().bind( "scrollstop", delayedSetLastScroll ); | |
// 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(){ | |
// Don't apply this height in touch overflow enabled mode | |
if( $.support.touchOverflow && $.mobile.touchOverflowEnabled ){ | |
return; | |
} | |
$( "." + $.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 ); | |
} | |
}; | |
//expose path object on $.mobile | |
$.mobile.path = path; | |
//expose base object on $.mobile | |
$.mobile.base = base; | |
//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; | |
}; | |
$.mobile._bindPageRemove = function() { | |
var page = $(this); | |
// when dom caching is not enabled or the page is embedded bind to remove the page on hide | |
if( !page.data("page").options.domCache | |
&& page.is(":jqmData(external-page='true')") ) { | |
page.bind( 'pagehide.remove', function() { | |
var $this = $( this ), | |
prEvent = new $.Event( "pageremove" ); | |
$this.trigger( prEvent ); | |
if( !prEvent.isDefaultPrevented() ){ | |
$this.removeWithDependents(); | |
} | |
}); | |
} | |
}; | |
// 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; | |
} | |
// If the caller is using a "post" request, reloadPage must be true | |
if( settings.data && settings.type === "post" ){ | |
settings.reloadPage = true; | |
} | |
// 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 the page, check to see if the url is a | |
// reference to an embedded page. If so, it may have been dynamically | |
// injected by a developer, in which case it would be lacking a data-url | |
// attribute and in need of enhancement. | |
if ( page.length === 0 && !path.isPath( dataUrl ) ) { | |
page = settings.pageContainer.children( "#" + dataUrl ) | |
.attr( "data-" + $.mobile.ns + "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; | |
} | |
var mpc = settings.pageContainer, | |
pblEvent = new $.Event( "pagebeforeload" ), | |
triggerData = { url: url, absUrl: absUrl, dataUrl: dataUrl, deferred: deferred, options: settings }; | |
// Let listeners know we're about to load a page. | |
mpc.trigger( pblEvent, triggerData ); | |
// If the default behavior is prevented, stop here! | |
if( pblEvent.isDefaultPrevented() ){ | |
return deferred.promise(); | |
} | |
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 ); | |
} | |
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 | |
// TODO taging a page with external to make sure that embedded pages aren't removed | |
// by the various page handling code is bad. Having page handling code in many | |
// places is bad. Solutions post 1.0 | |
page | |
.attr( "data-" + $.mobile.ns + "url", path.convertUrlToDataUrl( fileUrl ) ) | |
.attr( "data-" + $.mobile.ns + "external-page", true ) | |
.appendTo( settings.pageContainer ); | |
// wait for page creation to leverage options defined on widget | |
page.one( 'pagecreate', $.mobile._bindPageRemove ); | |
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(); | |
} | |
// Add the page reference to our triggerData. | |
triggerData.page = page; | |
// Let listeners know the page loaded successfully. | |
settings.pageContainer.trigger( "pageload", triggerData ); | |
deferred.resolve( absUrl, options, page, dupCachedPage ); | |
}, | |
error: function() { | |
//set base back to current path | |
if( base ) { | |
base.set( path.get() ); | |
} | |
var plfEvent = new $.Event( "pageloadfailed" ); | |
// Let listeners know the page load failed. | |
settings.pageContainer.trigger( plfEvent, triggerData ); | |
// If the default behavior is prevented, stop here! | |
// Note that it is the responsibility of the listener/handler | |
// that called preventDefault(), to resolve/reject the | |
// deferred object within the triggerData. | |
if( plfEvent.isDefaultPrevented() ){ | |
return; | |
} | |
// 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 ) { | |
// 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 ); | |
// 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 ) { | |
isPageTransitioning = false; | |
//clear out the active button state | |
removeActiveLinkClass( true ); | |
//release transition lock so navigation is free again | |
releasePageTransitionLock(); | |
settings.pageContainer.trigger( "pagechangefailed", triggerData ); | |
}); | |
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"; | |
// By default, we prevent changePage requests when the fromPage and toPage | |
// are the same element, but folks that generate content manually/dynamically | |
// and reuse pages want to be able to transition to the same page. To allow | |
// this, they will need to change the default value of allowSamePageTransition | |
// to true, *OR*, pass it in as an option when they manually call changePage(). | |
// It should be noted that our default transition animations assume that the | |
// formPage and toPage are different elements, so they may behave unexpectedly. | |
// It is up to the developer that turns on the allowSamePageTransitiona option | |
// to either turn off transition animations, or make sure that an appropriate | |
// animation transition is used. | |
if( fromPage && fromPage[0] === toPage[0] && !settings.allowSamePageTransition ) { | |
isPageTransitioning = false; | |
mpc.trigger( "pagechange", triggerData ); | |
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 ); | |
}); | |
}; | |
$.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, | |
allowSamePageTransition: false | |
}; | |
/* 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 ) { | |
// if this isn't a left click we don't care. Its important to note | |
// that when the virtual event is generated it will create | |
if ( event.which > 1 ){ | |
return; | |
} | |
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 there is no link associated with the click or its not a left | |
// click we want to ignore the click | |
if ( !link || event.which > 1) { | |
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; | |
} | |
var baseUrl = getClosestBaseUrl( $link ), | |
//get href, if defined, otherwise default to empty hash | |
href = path.makeUrlAbsolute( $link.attr( "href" ) || "#", baseUrl ); | |
//if ajax is disabled, exit early | |
if( !$.mobile.ajaxEnabled && !path.isEmbeddedPage( href ) ){ | |
httpCleanup(); | |
//use default click handling | |
return; | |
} | |
// 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 ) { | |
// At this point, 'to' can be one of 3 things, a cached page element from | |
// a history stack entry, an id, or site-relative/absolute URL. If 'to' is | |
// an id, we need to resolve it against the documentBase, not the location.href, | |
// since the hashchange could've been the result of a forward/backward navigation | |
// that crosses from an external page/dialog to an internal page/dialog. | |
to = ( typeof to === "string" && !path.isPath( to ) ) ? ( path.makeUrlAbsolute( '#' + to, documentBase ) ) : 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; | |
}, | |
// TODO sort out a single barrier to hashchange functionality | |
nextHashChangePrevented: function( value ) { | |
$.mobile.urlHistory.ignoreNextHashChange = value; | |
self.onHashChangeDisabled = value; | |
}, | |
// 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 ) { | |
// disable this hash change | |
if( self.onHashChangeDisabled ){ | |
return; | |
} | |
var href, state, | |
hash = location.hash, | |
isPath = $.mobile.path.isPath( hash ); | |
hash = isPath ? hash.replace( "#", "" ) : hash; | |
// propulate the hash when its not available | |
state = self.state(); | |
// make the hash abolute with the current href | |
href = $.mobile.path.makeUrlAbsolute( hash, location.href ); | |
if ( isPath ) { | |
href = self.resetUIKeys( href ); | |
} | |
// replace the current url with the new href and store the state | |
// Note that in some cases we might be replacing an url with the | |
// same url. We do this anyways because we need to make sure that | |
// all of our history entries have a state object associated with | |
// them. This allows us to work around the case where window.history.back() | |
// is called to transition from an external page to an embedded page. | |
// In that particular case, a hashchange event is *NOT* generated by the browser. | |
// Ensuring each history entry has a state object means that onPopState() | |
// will always trigger our hashchange callback even when a hashchange event | |
// is not fired. | |
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 | |
self.nextHashChangePrevented( 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 | |
self.nextHashChangePrevented( 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[ 0 ] !== $to[ 0 ] ) { | |
$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 ] ) { | |
var html = $( "<div>" ).html( $this.clone() ).html(), | |
// In IE browsers, the type sometimes doesn't exist in the cloned markup, so we replace the closing tag instead | |
hasType = html.indexOf( " type=" ) > -1, | |
findstr = hasType ? /\s+type=["']?\w+['"]?/ : /\/?>/, | |
repstr = " type=\"" + optType + "\" data-" + $.mobile.ns + "type=\"" + type + "\"" + ( hasType ? "" : ">" ); | |
$this.replaceWith( html.replace( findstr, repstr ) ); | |
} | |
}); | |
}); | |
})( 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 self = this, | |
$el = this.element, | |
pageTheme = $el.attr( "class" ).match( /ui-body-[a-z]/ ), | |
headerCloseButton = $( "<a href='#' data-" + $.mobile.ns + "icon='delete' data-" + $.mobile.ns + "iconpos='notext'>"+ this.options.closeBtnText + "</a>" ); | |
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( headerCloseButton ) | |
.end() | |
.find( ":jqmData(role='content'),:jqmData(role='footer')" ) | |
.last() | |
.addClass( "ui-corner-bottom ui-overlay-shadow" ); | |
// this must be an anonymous function so that select menu dialogs can replace | |
// the close method. This is a change from previously just defining data-rel=back | |
// on the button and letting nav handle it | |
headerCloseButton.bind( "vclick", function() { | |
self.close(); | |
}); | |
/* 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, | |
contentTheme: null, | |
iconTheme: "d", | |
initSelector: ":jqmData(role='collapsible')" | |
}, | |
_create: function() { | |
var $el = this.element, | |
o = this.options, | |
collapsible = $el.addClass( "ui-collapsible" ), | |
collapsibleHeading = $el.find( o.heading ).eq( 0 ), | |
collapsibleContent = collapsible.wrapInner( "<div class='ui-collapsible-content'></div>" ).find( ".ui-collapsible-content" ), | |
collapsibleSet = $el.closest( ":jqmData(role='collapsible-set')" ).addClass( "ui-collapsible-set" ), | |
colllapsiblesInSet = collapsibleSet.children( ":jqmData(role='collapsible')" ); | |
// Replace collapsibleHeading if it's a legend | |
if ( collapsibleHeading.is( "legend" ) ) { | |
collapsibleHeading = $( "<div role='heading'>"+ collapsibleHeading.html() +"</div>" ).insertBefore( collapsibleHeading ); | |
collapsibleHeading.next().remove(); | |
} | |
// If we are in a collapsible set | |
if ( collapsibleSet.length ) { | |
// Inherit the theme from collapsible-set | |
if ( !o.theme ) { | |
o.theme = collapsibleSet.jqmData( "theme" ); | |
} | |
// Inherit the content-theme from collapsible-set | |
if ( !o.contentTheme ) { | |
o.contentTheme = collapsibleSet.jqmData( "content-theme" ); | |
} | |
} | |
collapsibleContent.addClass( ( o.contentTheme ) ? ( "ui-body-" + o.contentTheme ) : ""); | |
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: false, | |
corners: false, | |
iconPos: "left", | |
icon: "plus", | |
theme: o.theme | |
}); | |
if ( !collapsibleSet.length ) { | |
collapsibleHeading | |
.find( "a:eq(0), .ui-btn-inner" ) | |
.addClass( "ui-corner-top ui-corner-bottom" ); | |
} else { | |
// If we are in a collapsible set | |
// Initialize the collapsible set if it's not already initialized | |
if ( !collapsibleSet.jqmData( "collapsiblebound" ) ) { | |
collapsibleSet | |
.jqmData( "collapsiblebound", true ) | |
.bind( "expand", function( event ) { | |
$( event.target ) | |
.closest( ".ui-collapsible" ) | |
.siblings( ".ui-collapsible" ) | |
.trigger( "collapse" ); | |
}); | |
} | |
colllapsiblesInSet.first() | |
.find( "a:eq(0)" ) | |
.addClass( "ui-corner-top" ) | |
.find( ".ui-btn-inner" ) | |
.addClass( "ui-corner-top" ); | |
colllapsiblesInSet.last() | |
.jqmData( "collapsible-last", true ) | |
.find( "a:eq(0)" ) | |
.addClass( "ui-corner-bottom" ) | |
.find( ".ui-btn-inner" ) | |
.addClass( "ui-corner-bottom" ); | |
if ( collapsible.jqmData( "collapsible-last" ) ) { | |
collapsibleHeading | |
.find( "a:eq(0), .ui-btn-inner" ) | |
.addClass( "ui-corner-bottom" ); | |
} | |
} | |
//events | |
collapsible | |
.bind( "expand collapse", function( event ) { | |
if ( !event.isDefaultPrevented() ) { | |
event.preventDefault(); | |
var $this = $( this ), | |
isCollapse = ( event.type === "collapse" ), | |
contentTheme = o.contentTheme; | |
collapsibleHeading | |
.toggleClass( "ui-collapsible-heading-collapsed", isCollapse) | |
.find( ".ui-collapsible-heading-status" ) | |
.text( o.expandCueText ) | |
.end() | |
.find( ".ui-icon" ) | |
.toggleClass( "ui-icon-minus", !isCollapse ) | |
.toggleClass( "ui-icon-plus", isCollapse ); | |
$this.toggleClass( "ui-collapsible-collapsed", isCollapse ); | |
collapsibleContent.toggleClass( "ui-collapsible-content-collapsed", isCollapse ).attr( "aria-hidden", isCollapse ); | |
if ( contentTheme && ( !collapsibleSet.length || collapsible.jqmData( "collapsible-last" ) ) ) { | |
collapsibleHeading | |
.find( "a:eq(0), .ui-btn-inner" ) | |
.toggleClass( "ui-corner-bottom", isCollapse ); | |
collapsibleContent.toggleClass( "ui-corner-bottom", !isCollapse ); | |
} | |
} | |
}) | |
.trigger( o.collapsed ? "collapse" : "expand" ); | |
collapsibleHeading | |
.bind( "click", function( event ) { | |
var type = collapsibleHeading.is( ".ui-collapsible-heading-collapsed" ) ? | |
"expand" : "collapse"; | |
collapsible.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 | |
// and aren't embedded | |
if( hasSubPages && | |
parentPage.is( ":jqmData(external-page='true')" ) && | |
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 : "nojs" plugin - class to make elements hidden to A grade browsers | |
* 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, | |
name, | |
$buttonPlaceholder; | |
// 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" ) ); | |
type = $el.attr( "type" ); | |
name = $el.attr( "name" ); | |
// Add hidden input during submit if input type="submit" has a name. | |
if ( type !== "button" && type !== "reset" && name ) { | |
$el.bind( "vclick", function() { | |
// Add hidden input if it doesn’t already exist. | |
if( $buttonPlaceholder === undefined ) { | |
$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 ) { | |
var valueChanged = false; | |
// update control"s value | |
if ( cType === "input" ) { | |
valueChanged = control.val() !== newval; | |
control.val( newval ); | |
} else { | |
valueChanged = control[ 0 ].selectedIndex !== newval; | |
control[ 0 ].selectedIndex = newval; | |
} | |
if ( !isfromControl && valueChanged ) { | |
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, input:not([type])" | |
}, | |
_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 (Apple bug 8910589). | |
// Turn off autocorrect and autocomplete on non-iOS 5 devices | |
// 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. We currently | |
// have no test for iOS 5 or newer so we're temporarily using | |
// the touchOverflow support flag for jQM 1.0. Yes, I feel dirty. - jblas | |
if ( typeof input[0].autocorrect !== "undefined" && !$.support.touchOverflow ) { | |
// 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._selectOptions(), | |
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.getEncodedText() + "</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(); | |
// TODO centralize page removal binding / handling in the page plugin. | |
// Suggestion from @jblas to do refcounting | |
// | |
// TODO extremely confusing dependency on the open method where the pagehide.remove | |
// bindings are stripped to prevent the parent page from disappearing. The way | |
// we're keeping pages in the DOM right now sucks | |
// | |
// 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 | |
// | |
// doing this here provides for the back button on the custom select dialog | |
$.mobile._bindPageRemove.call( self.thisPage ); | |
}); | |
// 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; | |
} | |
}); | |
// track this dependency so that when the parent page | |
// is removed on pagehide it will also remove the menupage | |
self.thisPage.addDependents( this.menuPage ); | |
}, | |
_isRebuildRequired: function() { | |
var list = this.list.find( "li" ), | |
options = this._selectOptions(); | |
// TODO exceedingly naive method to determine difference | |
// ignores value changes etc in favor of a forcedRebuild | |
// from the user in the refresh method | |
return options.text() !== list.text(); | |
}, | |
refresh: function( forceRebuild , foo ){ | |
var self = this, | |
select = this.element, | |
isMultiple = this.isMultiple, | |
options = this._selectOptions(), | |
selected = this.selected(), | |
// return an array of all selected index's | |
indicies = this.selectedIndices(); | |
if ( forceRebuild || this._isRebuildRequired() ) { | |
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" ) { | |
// 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(), | |
activePage = $( ".ui-page-active" ), | |
tOverflow = $.support.touchOverflow && $.mobile.touchOverflowEnabled, | |
tScrollElem = activePage.is( ".ui-native-fixed" ) ? activePage.find( ".ui-content" ) : activePage; | |
scrollTop = tOverflow ? tScrollElem.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.getEncodedText(), | |
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(){ | |
if ( this.options.theme ){ | |
return this.options.theme; | |
} | |
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); | |
}, | |
_selectOptions: function() { | |
return this.select.find( "option" ); | |
}, | |
// 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(); | |
}, | |
_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.addClass('ui-li-has-count') ); | |
} | |
// 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(); | |
}, | |
// open and close preserved in native selects | |
// to simplify users code when looping over selects | |
open: $.noop, | |
close: $.noop, | |
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, { | |
icon: el.jqmData( "icon" ), | |
iconpos: el.jqmData( "iconpos" ), | |
theme: el.jqmData( "theme" ), | |
inline: el.jqmData( "inline" ) | |
}, 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, | |
inline: false, | |
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 : "links" plugin - simple class additions for links | |
* 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 || ( $.support.touchOverflow && $.mobile.touchOverflowEnabled ) ) { | |
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 && $.mobile.touchOverflowEnabled ) ) { | |
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; | |
} | |
}; | |
})(); | |
//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 && $.mobile.touchOverflowEnabled ) ) { | |
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 ) { | |
// Enable touch overflow scrolling when it's natively supported | |
$.mobile.touchOverflowEnabled = false; | |
// Enabled zoom when touch overflow is enabled. Can cause usability issues, unfortunately | |
$.mobile.touchOverflowZoomEnabled = 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 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" ); | |
}, | |
// 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" ); | |
// alert listeners that the pagecontainer has been determined for binding | |
// to events triggered on it | |
$window.trigger( "pagecontainercreate" ); | |
// 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 ] ); | |
} | |
} | |
}); | |
// This function injects a meta viewport tag to prevent scaling. Off by default, on by default when touchOverflow scrolling is enabled | |
function disableZoom() { | |
var cont = "user-scalable=no", | |
meta = $( "meta[name='viewport']" ); | |
if( meta.length ){ | |
meta.attr( "content", meta.attr( "content" ) + ", " + cont ); | |
} | |
else{ | |
$( "head" ).prepend( "<meta>", { "name": "viewport", "content": cont } ); | |
} | |
} | |
// if touch-overflow is enabled, disable user scaling, as it creates usability issues | |
if( $.support.touchOverflow && $.mobile.touchOverflowEnabled && !$.mobile.touchOverflowZoomEnabled ){ | |
disableZoom(); | |
} | |
// 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 ); | |
<?php | <?php |
include ('../include/common.inc.php'); | include ('../include/common.inc.php'); |
include_header("Busness R&D", "index"); | include_header("Busness R&D", "index"); |
if ($_SESSION['authed'] == true) { | |
echo '<ul data-role="listview" data-theme="e" data-groupingtheme="e"> | |
<li data-role="list-divider" > Admin Features </li> | |
<li><a href="myway_timeliness_calculate.php"><h3>myway_timeliness_calculate</h3> | |
<p>myway_timeliness_calculate</p></a></li> | |
<li><a href="myway_timeliness_reconcile.php"><h3>myway_timeliness_reconcile</h3> | |
<p>myway_timeliness_reconcile</p></a></li> | |
<li><a href="servicealert_editor.php"><h3>servicealert_editor</h3> | |
<p>servicealert_editor</p></a></li> | |
</ul>'; | |
} | |
?> | ?> |
<ul data-role="listview" data-theme="e" data-groupingtheme="e"> | <ul data-role="listview" data-theme="e" data-groupingtheme="e"> |
<li data-role="list-divider" > Experimental Features </li> | <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> | <li><a href="busstopdensity.php"><h3>Bus Stop Density Map</h3> |
<p>Analysis of bus stop coverage</p></a></li> | <p>Analysis of bus stop coverage</p></a></li> |
<li><a href="stopBrowser.php"><h3>Bus Stop Browser Map</h3> | <li><a href="stopBrowser.php"><h3>Bus Stop Browser Map</h3> |
<p>Bus stop location/route browser</p></a></li> | <p>Bus stop location/route browser</p></a></li> |
</ul> | </ul> |
<ul data-role="listview" data-theme="e" data-groupingtheme="e"> | </div> |
<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> | |
<?php | <?php |
include_footer() | include_footer() |
?> | ?> |
<?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"; | |
} | |
if (basename(__FILE__) == "myway_api.json.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'); | |
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); | |
} | |
?> | |
<?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> |
<?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(); | |
} | |
<?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> |
<?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(); | |
?> | |
<?php | |
include ('../include/common.inc.php'); | |
auth(); | |
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;"; |