Merge remote branch 'origin/master'

This commit is contained in:
toddparker 2011-01-23 23:27:55 -05:00
commit 821f0d88d5
21 changed files with 599 additions and 342 deletions

View file

@ -14,9 +14,9 @@ FILES = js/jquery.ui.widget.js \
js/jquery.mobile.support.js \
js/jquery.mobile.event.js \
js/jquery.mobile.hashchange.js \
js/jquery.mobile.page.js \
js/jquery.mobile.core.js \
js/jquery.mobile.navigation.js \
js/jquery.mobile.page.js \
js/jquery.ui.position.js \
js/jquery.mobile.fixHeaderFooter.js \
js/jquery.mobile.forms.checkboxradio.js \

View file

@ -27,9 +27,9 @@
jquery.mobile.support.js,
jquery.mobile.event.js,
jquery.mobile.hashchange.js,
jquery.mobile.page.js,
jquery.mobile.core.js,
jquery.mobile.navigation.js,
jquery.mobile.page.js,
jquery.mobile.buttonMarkup.js,
jquery.mobile.collapsible.js,
jquery.mobile.controlGroup.js,
@ -52,15 +52,15 @@
<antcall target="merge_js" />
</target>
<target name="merge_css">
<target name="merge_css">
<concat destfile="combine/jquery.mobile.css">
<filelist dir="${cssdir}" files="${css-sources}"/>
</concat>
</target>
<target name="merge_js">
<target name="merge_js">
<concat destfile="combine/jquery.mobile.js">
<filelist dir="${jsdir}" files="${js-sources}"/>
</concat>
</target>
</project>
</project>

View file

@ -80,11 +80,14 @@ $(document).bind("mobileinit", function(){
<dt>activeBtnClass (<em>string</em>, default: "ui-page-active"):</dt>
<dd>The class used for "active" button state, from CSS framework.</dd>
<dt>ajaxEnabled (<em>boolean</em>, default: true):</dt>
<dd>jQuery Mobile will automatically handle link clicks and form submissions through Ajax, when possible. If false, url hash listening will be disabled as well, and urls will load as regular http requests.</dd>
<dt>ajaxLinksEnabled (<em>boolean</em>, default: true):</dt>
<dt>ajaxLinksEnabled (<strong>deprecated</strong> <em>boolean</em>, default: true):</dt>
<dd>jQuery Mobile will automatically handle link clicks through Ajax, when possible.</dd>
<dt>ajaxFormsEnabled (<em>boolean</em>, default: true):</dt>
<dt>ajaxFormsEnabled (<strong>deprecated</strong> <em>boolean</em>, default: true):</dt>
<dd>jQuery Mobile will automatically handle form submissions through Ajax, when possible.</dd>
<dt>defaultTransition (<em>string</em>, default: 'slide'):</dt>

View file

@ -40,7 +40,7 @@
</dd>
<dd><code>transition</code> (<em>string</em>, examples: "pop", "slide"," "none")</dd>
<dd><code>back</code> (<em>boolean</em>, default: false). True will cause a reverse-direction transition.</dd>
<dd><code>reverse</code> (<em>boolean</em>, default: false). True will cause a reverse-direction transition.</dd>
<dd><code>changeHash</code> (<em>boolean</em>, default: true). Update the hash to the to page's URL when page change is complete.</dd>
</dl>
</dd>
@ -89,6 +89,14 @@ $.mobile.pageLoading( true );
</dd>
<dt><code>$.mobile.path</code> (<em>methods, properties</em>)</dt>
<dd>Utilities for getting, setting, and manipulating url paths. TODO: document as public API is finalized.</dd>
<dt><code>$.mobile.base</code> (<em>methods, properties</em>)</dt>
<dd>Utilities for working with generated base element. TODO: document as public API is finalized.</dd>
<dt><code>$.mobile.silentScroll</code> (<em>method</em>)</dt>
<dd>Scroll to a particular Y position without triggering scroll event listeners.</dd>
<dd>

View file

@ -37,7 +37,7 @@
<a href="transition-success.html" data-role="button" data-rel="dialog" data-transition="flip">flip</a>
</p>
<p>In addition, you can also force a "backwards" transition by specifying <code>data-back="true"</code> on your link.</p>
<p>In addition, you can also force a "backwards" transition by specifying <code>data-direction="reverse"</code> on your link. Note: (this was formerly <code>data-back="true"</code>, which will remain supported until 1.0)</p>
<div class="ui-body ui-body-e">
<p><strong>Transitions from <a href="http://www.jqtouch.com/">jQtouch</a></strong> (<em>with small modifications</em>): Built by David Kaneda and maintained by Jonathan Stark.</p>

View file

@ -20,7 +20,7 @@
<p>That was an animated page transition effect that we added with a <code>data-transition</code> attribute on the link.</p>
<p>Since it uses CSS transforms, this should be hardware accelerated on many mobile devices.</p>
<p>What do you think?</p>
<a href="docs-transitions.html" data-role="button" data-theme="b">I like it</a>
<a href="docs-transitions.html" data-role="button" data-theme="b" data-direction="reverse">I like it</a>
</div>
</div>

View file

@ -7,9 +7,9 @@ $elements = array(
'jquery.mobile.support.js',
'jquery.mobile.event.js',
'jquery.mobile.hashchange.js',
'jquery.mobile.page.js',
'jquery.mobile.core.js',
'jquery.mobile.navigation.js',
'jquery.mobile.page.js',
'jquery.ui.position.js',
'jquery.mobile.fixHeaderFooter.js',
'jquery.mobile.forms.checkboxradio.js',

View file

@ -27,11 +27,16 @@
//class used for "active" button state, from CSS framework
activeBtnClass: 'ui-btn-active',
//automatically handle link clicks through Ajax, when possible
ajaxLinksEnabled: true,
//automatically handle clicks and form submissions through Ajax, when same-domain
ajaxEnabled: true,
// TODO: deprecated - remove at 1.0
//automatically handle link clicks through Ajax, when possible
ajaxLinksEnabled: true,
//automatically handle form submissions through Ajax, when possible
ajaxFormsEnabled: true,
// TODO: deprecated - remove at 1.0
//automatically handle form submissions through Ajax, when possible
ajaxFormsEnabled: true,
//set default transition - 'none' for no transitions
defaultTransition: 'slide',

View file

@ -10,19 +10,27 @@ $.widget( "mobile.dialog", $.mobile.widget, {
_create: function(){
var self = this,
$el = self.element,
$prevPage = $.mobile.activePage,
$closeBtn = $('<a href="#" data-icon="delete" data-iconpos="notext">Close</a>'),
dialogClickHandler = function(e){
var $target = $(e.target);
var $target = $(e.target),
href = $.mobile.path.stripHash( $target.closest("a").attr("href") ),
isRelative = $.mobile.path.isRelative( href ),
absUrl = isRelative ? $.mobile.path.makeAbsolute( href ) : href;
// fixes issues with target links in dialogs breaking
// page transitions by reseting the active page below
if( $.mobile.isExternalLink($target) ) {
if( $.mobile.path.isExternal( href ) ||
$target.closest("a[target]").length ||
$target.is( "[rel='external']" ) ) {
return;
}
if( e.type == "click" && ( $(e.target).closest('[data-back]')[0] || this==$closeBtn[0] ) ){
//if it's a close button click
//or the href is the same as the page we're on, close the dialog
if( e.type == "click" &&
( this==$closeBtn[0] || absUrl == $.mobile.path.stripHash( location.hash ) ) ){
self.close();
return false;
}
@ -38,8 +46,15 @@ $.widget( "mobile.dialog", $.mobile.widget, {
this.element
.bind("pageshow",function(){
self.thisPage = $.mobile.urlHistory.getActive();
self.prevPage = $.mobile.urlHistory.getPrev();
return false;
})
.bind("pagehide", function(){
$.mobile.urlHistory.stack = $.mobile.urlHistory.stack.slice(0,$.mobile.urlHistory.stack.length-2);
$.mobile.urlHistory.activeIndex = $.mobile.urlHistory.stack.length -1;
})
//add ARIA role
.attr("role","dialog")
.addClass('ui-page ui-dialog ui-body-a')
@ -54,11 +69,15 @@ $.widget( "mobile.dialog", $.mobile.widget, {
.last()
.addClass('ui-corner-bottom ui-overlay-shadow');
$(window).bind('hashchange',function(){
$.mobile.urlHistory.listeningEnabled = true;
if( $el.is('.ui-page-active') ){
self.close();
$el.bind('pagehide',function(){
$.mobile.updateHash( $prevPage.attr('data-url'), true);
$.mobile.urlHistory.listeningEnabled = false;
$.mobile.updateHash( self.prevPage.url );
});
}
});
@ -66,7 +85,7 @@ $.widget( "mobile.dialog", $.mobile.widget, {
},
close: function(){
$.mobile.changePage([this.element, $.mobile.activePage], undefined, true, true );
$.mobile.changePage([this.element, $.mobile.activePage], this.thisPage.transition, true, true, true );
}
});
})( jQuery );

View file

@ -63,21 +63,37 @@ $.event.special.tap = {
$this = $( thisObject );
$this
.bind( touchStartEvent, function( event ) {
if ( event.which && event.which !== 1 ) {
return;
.bind( "mousedown touchstart", function( event ) {
if ( event.which && event.which !== 1 ||
//check if event fired once already by a device that fires both mousedown and touchstart (while supporting both events)
$this.data( "prevEvent") && $this.data( "prevEvent") !== event.type ) {
return false;
}
//save event type so only this type is let through for a temp duration,
//allowing quick repetitive taps but not duplicative events
$this.data( "prevEvent", event.type );
setTimeout(function(){
$this.removeData( "prevEvent" );
}, 800);
var moved = false,
touching = true,
origTarget = event.target,
origPos = [ event.pageX, event.pageY ],
origEvent = event.originalEvent,
origPos = event.type == "touchstart" ? [origEvent.touches[0].pageX, origEvent.touches[0].pageY] : [ event.pageX, event.pageY ],
originalType,
timer;
function moveHandler() {
if ((Math.abs(origPos[0] - event.pageX) > 10) ||
(Math.abs(origPos[1] - event.pageY) > 10)) {
function moveHandler( event ) {
if( event.type == "scroll" ){
moved = true;
return;
}
var newPageXY = event.type == "touchmove" ? event.originalEvent.touches[0] : event;
if ((Math.abs(origPos[0] - newPageXY.pageX) > 10) ||
(Math.abs(origPos[1] - newPageXY.pageY) > 10)) {
moved = true;
}
}
@ -91,17 +107,21 @@ $.event.special.tap = {
}
}, 750 );
//scroll now cancels tap
$(window).one("scroll", moveHandler);
$this
.one( touchMoveEvent, moveHandler)
.one( touchStopEvent, function( event ) {
$this.unbind( touchMoveEvent, moveHandler );
.bind( "mousemove touchmove", moveHandler )
.one( "mouseup touchend", function( event ) {
$this.unbind( "mousemove touchmove", moveHandler );
$(window).unbind("scroll", moveHandler);
clearTimeout( timer );
touching = false;
/* ONLY trigger a 'tap' event if the start target is
* the same as the stop target.
*/
if ( !moved && (origTarget == event.target)) {
if ( !moved && ( origTarget == event.target ) ) {
originalType = event.type;
event.type = "tap";
$.event.handle.call( thisObject, event );

View file

@ -19,7 +19,7 @@
if( newPath == undefined ){
newPath = location.hash;
}
return newPath.replace(/#/,'').replace(/[^\/]*\.[^\/*]+$/, '');
return path.stripHash( newPath ).replace(/[^\/]*\.[^\/*]+$/, '');
},
//return the substring of a filepath before the sub-page key, for making a server request
@ -27,9 +27,9 @@
var splitkey = '&' + $.mobile.subPageUrlKey;
return path && path.indexOf( splitkey ) > -1 ? path.split( splitkey )[0] : path;
},
set: function( path, disableListening){
if(disableListening) { hashListener = false; }
//set location hash to path
set: function( path ){
location.hash = path;
},
@ -38,29 +38,91 @@
setOrigin: function(){
path.origin = path.get( location.protocol + '//' + location.host + location.pathname );
},
//prefix a relative url with the current path
makeAbsolute: function( url ){
return path.get() + url;
},
//return a url path with the window's location protocol/hostname removed
clean: function( url ){
return url.replace( location.protocol + "//" + location.host, "");
},
//just return the url without an initial #
stripHash: function( url ){
return url.replace( /^#/, "" );
},
//check whether a url is referencing the same domain, or an external domain or different protocol
//could be mailto, etc
isExternal: function( url ){
return path.hasProtocol( path.clean( url ) );
},
hasProtocol: function( url ){
return /^(:?\w+:)/.test( url );
},
//check if the url is relative
isRelative: function( url ){
return /^[^\/|#]/.test( url ) && !path.hasProtocol( url );
}
},
//will be defined when a link is clicked and given an active class
$activeClickedLink = null,
//array of pages that are visited during a single page load
//length will grow as pages are visited, and shrink as "back" link/button is clicked
//each item has a url (string matches ID), and transition (saved for reuse when "back" link/button is clicked)
urlStack = [ {
url: location.hash.replace( /^#/, "" ),
transition: undefined
} ],
//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
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 ){
//if there's forward history, wipe it
if( urlHistory.getNext() ){
urlHistory.clearForward();
}
urlHistory.stack.push( {url : url, transition: transition } );
urlHistory.activeIndex = urlHistory.stack.length - 1;
},
//wipe urls ahead of active index
clearForward: function(){
urlHistory.stack = urlHistory.stack.slice( 0, urlHistory.activeIndex + 1 );
},
//enable/disable hashchange event listener
//toggled internally when location.hash is updated to match the url of a successful page load
listeningEnabled: true
},
//define first selector to receive focus when a page is shown
focusable = "[tabindex],a,button:visible,select:visible,input",
//contains role for next page, if defined on clicked link via data-rel
nextPageRole = null,
//enable/disable hashchange event listener
//toggled internally when location.hash is updated to match the url of a successful page load
hashListener = true;
nextPageRole = null;
//existing base tag?
var $base = $head.children("base"),
@ -83,7 +145,7 @@
//the href is a document relative url
docBase = docLocation + href;
//XXX: we need some code here to calculate the final path
// just in case the docBase contains up-level (../) references.
// just in case the docBase contains up-level (../) references.
}
}
else {
@ -142,7 +204,6 @@
$activeClickedLink = null;
};
//animation complete callback
$.fn.animationComplete = function( callback ){
if($.support.cssTransitions){
@ -158,41 +219,77 @@
/* exposed $.mobile methods */
//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
$.mobile.urlStack = urlStack;
//check for an external resource
$.mobile.isExternalLink = function(anchor){
var $anchor = $(anchor),
hasProtocol = /^(:?\w+:)/.test( $anchor.attr('href') ),
hasRelExternal = $anchor.is( "[rel=external]" ),
hasTarget = $anchor.is( "[target]" );
return hasProtocol || hasRelExternal || hasTarget;
},
//TODO: deprecate this one at 1.0
$.mobile.urlstack = urlHistory.stack;
//history stack
$.mobile.urlHistory = urlHistory;
// changepage function
$.mobile.changePage = function( to, transition, back, changeHash){
// TODO : consider moving args to an object hash
$.mobile.changePage = function( to, transition, reverse, changeHash, fromHashChange ){
//from is always the currently viewed page
var toIsArray = $.type(to) === "array",
toIsObject = $.type(to) === "object",
from = toIsArray ? to[0] : $.mobile.activePage,
to = toIsArray ? to[1] : to,
url = fileUrl = $.type(to) === "string" ? to.replace( /^#/, "" ) : null,
url = fileUrl = $.type(to) === "string" ? path.stripHash( to ) : "",
data = undefined,
type = 'get',
isFormRequest = false,
duplicateCachedPage = null,
back = (back !== undefined) ? back : ( urlStack.length > 1 && urlStack[ urlStack.length - 2 ].url === url );
//If we are trying to transition to the same page that we are currently on ignore the request.
if(urlStack.length > 1 && url === urlStack[urlStack.length -1].url && !toIsArray ) {
currPage = urlHistory.getActive(),
back = false,
forward = false;
// 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 to is not an array or object (those are allowed to be "same")
if( currPage && urlHistory.stack.length > 1 && currPage.url === url && !toIsArray && !toIsObject ) {
return;
}
// if the changePage was sent from a hashChange event
// guess if it came from the history menu
if( fromHashChange ){
// check if url is in history and if it's ahead or behind current page
$.each( urlHistory.stack, function( i ){
//if the url is in the stack, it's a forward or a back
if( this.url == url ){
urlIndex = i;
//define back and forward by whether url is older or newer than current page
back = i < urlHistory.activeIndex;
//forward set to opposite of back
forward = !back;
//reset activeIndex to this one
urlHistory.activeIndex = i;
}
});
//if it's a back, use reverse animation
if( back ){
reverse = true;
transition = transition || currPage.transition;
}
else if ( forward ){
transition = transition || urlHistory.getActive().transition;
}
}
if( $.type(to) === "object" && to.url ){
if( toIsObject && to.url ){
url = to.url,
data = to.data,
type = to.type,
@ -216,25 +313,6 @@
}
}
// if the new href is the same as the previous one
if ( back ) {
var pop = urlStack.pop();
// prefer the explicitly set transition
if( pop && !transition ){
transition = pop.transition;
}
// ensure a transition has been set where pop is undefined
defaultTransition();
} else {
// If no transition has been passed
defaultTransition();
// push the url and transition onto the stack
urlStack.push({ url: url, transition: transition });
}
//function for transitioning between two existing pages
function transitionPages() {
@ -256,8 +334,18 @@
reFocus( to );
if( changeHash !== false && url ){
path.set(url, (back !== true));
if( !back ){
urlHistory.listeningEnabled = false;
}
path.set( url );
urlHistory.listeningEnabled = true;
}
//add page to history stack if it's not back or forward, or a dialog
if( !back && !forward ){
urlHistory.addNew( url, transition );
}
removeActiveLinkClass();
//jump to top or prev scroll, if set
@ -296,9 +384,9 @@
addContainerClass('ui-mobile-viewport-transitioning');
// animate in / out
from.addClass( transition + " out " + ( back ? "reverse" : "" ) );
from.addClass( transition + " out " + ( reverse ? "reverse" : "" ) );
to.addClass( $.mobile.activePageClass + " " + transition +
" in " + ( back ? "reverse" : "" ) );
" in " + ( reverse ? "reverse" : "" ) );
// callback - remove classes, etc
to.animationComplete(function() {
@ -344,6 +432,9 @@
fileUrl = toIDfileurl;
}
}
// ensure a transition has been set where pop is undefined
defaultTransition();
// find the "to" page, either locally existing in the dom or by creating it through ajax
if ( to.length && !isFormRequest ) {
@ -417,20 +508,22 @@
/* Event Bindings - hashchange, submit, and click */
//bind to form submit events, handle with Ajax
$("form[data-ajax!='false']").live('submit', function(event){
if( !$.mobile.ajaxFormsEnabled ){ return; }
$( "form[data-ajax!='false']" ).live('submit', function(event){
if( !$.mobile.ajaxEnabled ||
//TODO: deprecated - remove at 1.0
!$.mobile.ajaxFormsEnabled ){ return; }
var type = $(this).attr("method"),
url = $(this).attr( "action" ).replace( location.protocol + "//" + location.host, "");
url = path.clean( $(this).attr( "action" ) );
//external submits use regular HTTP
if( /^(:?\w+:)/.test( url ) ){
if( path.isExternal( url ) ){
return;
}
//if it's a relative href, prefix href with base url
if( url.indexOf('/') && url.indexOf('#') !== 0 ){
url = path.get() + url;
if( path.isRelative( url ) ){
url = path.makeAbsolute( url );
}
$.mobile.changePage({
@ -448,51 +541,57 @@
//click routing - direct to HTTP or Ajax, accordingly
$( "a" ).live( "click", function(event) {
if( !$.mobile.ajaxLinksEnabled ){ return; }
var $this = $(this),
//get href, remove same-domain protocol and host
href = $this.attr( "href" ).replace( location.protocol + "//" + location.host, ""),
//if target attr is specified, it's external, and we mimic _blank... for now
target = $this.is( "[target]" ),
url = path.clean( $this.attr( "href" ) ),
//check if it's external
isExternal = path.isExternal( url ) || $this.is( "[rel='external']" ),
//if target attr is specified we mimic _blank... for now
hasTarget = $this.is( "[target]" );
//if it still starts with a protocol, it's external, or could be :mailto, etc
external = $.mobile.isExternalLink(this);
if( href === '#' ){
if( url === "#" ){
//for links created purely for interaction - ignore
return false;
}
$activeClickedLink = $this.closest( ".ui-btn" ).addClass( $.mobile.activeBtnClass );
if( external || !$.mobile.ajaxLinksEnabled ){
//remove active link class if external
if( isExternal || hasTarget || !$.mobile.ajaxEnabled ||
// TODO: deprecated - remove at 1.0
!$.mobile.ajaxLinksEnabled ){
//remove active link class if external (then it won't be there if you come back)
removeActiveLinkClass(true);
//deliberately redirect, in case click was triggered
if( target ){
window.open(href);
if( hasTarget ){
window.open( url );
}
else{
location.href = href;
location.href = url;
}
}
else {
//use ajax
var transition = $this.data( "transition" ),
back = $this.data( "back" );
direction = $this.data("direction"),
reverse = direction && direction == "reverse" ||
// deprecated - remove by 1.0
$this.data( "back" );
nextPageRole = $this.attr( "data-rel" );
//if it's a relative href, prefix href with base url
if( href.indexOf('/') && href.indexOf('#') !== 0 ){
href = path.get() + href;
if( path.isRelative( url ) ){
url = path.makeAbsolute( url );
}
href.replace(/^#/,'');
url = path.stripHash( url );
$.mobile.changePage(href, transition, back);
$.mobile.changePage( url, transition, reverse);
}
event.preventDefault();
});
@ -501,8 +600,10 @@
//hashchange event handler
$window.bind( "hashchange", function(e, triggered) {
if( !hashListener ){
hashListener = true;
if( !urlHistory.listeningEnabled || !$.mobile.ajaxEnabled ||
// TODO: deprecated - remove at 1.0
// only links need to be checked here, as forms don't trigger a hashchange event (they just silently update the hash)
( !$.mobile.ajaxLinksEnabled ) ){
return;
}
@ -510,20 +611,21 @@
return;
}
var to = location.hash,
var to = path.stripHash( location.hash ),
transition = triggered ? false : undefined;
//if to is defined, use it
if ( to ){
$.mobile.changePage( to, transition, undefined, false);
$.mobile.changePage( to, transition, undefined, false, true );
}
//there's no hash, the active page is not the start page, and it's not manually triggered hashchange
//we probably backed out to the first page visited
else if( $.mobile.activePage.length && $.mobile.startPage[0] !== $.mobile.activePage[0] && !triggered ) {
$.mobile.changePage( $.mobile.startPage, transition, true, false );
$.mobile.changePage( $.mobile.startPage, transition, true, false, true );
}
//probably the first page - show it
else{
urlHistory.addNew( "" );
$.mobile.startPage.trigger("pagebeforeshow", {prevPage: $('')});
$.mobile.startPage.addClass( $.mobile.activePageClass );
$.mobile.pageLoading( true );

View file

@ -75,7 +75,7 @@ $.widget( "mobile.page", $.mobile.widget, {
// auto-add back btn on pages beyond first view
if ( o.addBackBtn && role === "header" &&
($.mobile.urlStack.length > 1 || $(".ui-page").length > 1) &&
($.mobile.urlHistory.getPrev() || $(".ui-page").length > 1) &&
!leftbtn && $this.data( "backbtn" ) !== false ) {
$( "<a href='#' class='ui-btn-left' data-icon='arrow-l'>"+ o.backBtnText +"</a>" )

47
tests/functional/addrbar.html Executable file
View file

@ -0,0 +1,47 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>jQuery Mobile: Event Logger</title>
<link rel="stylesheet" href="../../themes/default/" />
<link rel="stylesheet" href="../../docs/_assets/css/jqm-docs.css" />
<script type="text/javascript" src="../../js/jquery.js"></script>
<script type="text/javascript" src="../../js/"></script>
<script>
$(function(){
$( "a" ).bind("tap",function( e ){
$("#log")
.prepend("<li>"+ e.type +" event; target: "+ e.target.nodeName +"</li>")
.listview("refresh");
return false;
})
.bind("click", false);
});
</script>
<style>
#jqm-home {
height: 500px;
}
</style>
</head>
<body>
<div data-role="page" data-theme="b" id="jqm-home">
<div data-role="header">
<h1>Event Logger</h1>
</div>
<div data-role="content">
<p>Touch events on this page will log out below, prepending to the top as they arrive.</p>
<a href="foo.html" data-role="button">Click me</a>
<ul data-role="listview" id="log">
</ul>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>jQuery Mobile: Event Logger</title>
<link rel="stylesheet" href="../../themes/default/" />
<link rel="stylesheet" href="../../docs/_assets/css/jqm-docs.css" />
<script type="text/javascript" src="../../js/jquery.js"></script>
<script type="text/javascript" src="../../js/"></script>
<script>
$( document )
.bind("tap taphold swipe swipeleft swiperight scrollstart scrollstop orientationchange",function( e ){
$("#log")
.prepend("<li>"+ e.type +" event; target: "+ e.target.nodeName +"</li>")
.listview("refresh");
});
</script>
</head>
<body>
<div data-role="page" data-theme="b" id="jqm-home">
<div data-role="header">
<h1>Event Logger</h1>
</div>
<div data-role="content">
<p>Touch events on this page will log out below, prepending to the top as they arrive.</p>
<ul data-role="listview" id="log">
</ul>
</div>
</div>
</body>
</html>

View file

@ -2,148 +2,148 @@
* mobile core unit tests
*/
var libName = "jquery.mobile.core.js",
setGradeA = function(value) { $.support.mediaquery = value; },
extendFn = $.extend;
(function($){
var libName = "jquery.mobile.core.js",
setGradeA = function(value) { $.support.mediaquery = value; },
extendFn = $.extend;
module(libName, {
setup: function(){
// NOTE reset for gradeA tests
$('html').removeClass('ui-mobile');
module(libName, {
setup: function(){
// NOTE reset for gradeA tests
$('html').removeClass('ui-mobile');
// NOTE reset for pageLoading tests
$('.ui-loader').remove();
},
teardown: function(){
$.extend = extendFn;
}
});
$.testHelper.excludeFileProtocol(function(){
test( "grade A browser support media queries", function(){
setGradeA(false);
$.testHelper.reloadLib(libName);
ok(!$.mobile.gradeA());
setGradeA(true);
$.testHelper.reloadLib(libName);
ok($.mobile.gradeA());
// NOTE reset for pageLoading tests
$('.ui-loader').remove();
},
teardown: function(){
$.extend = extendFn;
}
});
test( "loading the core library triggers mobilinit on the document", function(){
expect( 1 );
$.testHelper.excludeFileProtocol(function(){
test( "grade A browser support media queries", function(){
setGradeA(false);
$.testHelper.reloadLib(libName);
ok(!$.mobile.gradeA());
$(window.document).bind('mobileinit', function(event){
ok(true);
setGradeA(true);
$.testHelper.reloadLib(libName);
ok($.mobile.gradeA());
});
$.testHelper.reloadLib(libName);
});
test( "loading the core library triggers mobilinit on the document", function(){
expect( 1 );
test( "enhancments are skipped when the browser is not grade A", function(){
setGradeA(false);
$.testHelper.reloadLib(libName);
$(window.document).bind('mobileinit', function(event){
ok(true);
});
//NOTE easiest way to check for enhancements, not the most obvious
ok(!$("html").hasClass("ui-mobile"));
});
test( "enhancments are added when the browser is grade A", function(){
setGradeA(true);
$.testHelper.reloadLib(libName);
ok($("html").hasClass("ui-mobile"));
});
//TODO lots of duplication
test( "pageLoading doesn't add the dialog to the page when loading message is false", function(){
$.testHelper.alterExtend({loadingMessage: false});
$.testHelper.reloadLib(libName);
$.mobile.pageLoading(false);
ok(!$(".ui-loader").length);
});
test( "pageLoading doesn't add the dialog to the page when done is passed as true", function(){
$.testHelper.alterExtend({loadingMessage: true});
$.testHelper.reloadLib(libName);
// TODO add post reload callback
$('.ui-loader').remove();
$.mobile.pageLoading(true);
ok(!$(".ui-loader").length);
});
test( "pageLoading adds the dialog to the page when done is true", function(){
$.testHelper.alterExtend({loadingMessage: true});
$.testHelper.reloadLib(libName);
$.mobile.pageLoading(false);
ok($(".ui-loader").length);
});
var metaViewportSelector = "head meta[name=viewport]",
setViewPortContent = function(value){
$(metaViewportSelector).remove();
$.testHelper.alterExtend({metaViewportContent: value});
$.testHelper.reloadLib(libName);
};
test( "meta view port element is added to head when defined on mobile", function(){
setViewPortContent("width=device-width");
same($(metaViewportSelector).length, 1);
});
test( "meta view port element not added to head when not defined on mobile", function(){
setViewPortContent(false);
same($(metaViewportSelector).length, 0);
});
var findFirstPage = function() {
return $("[data-role='page']").first();
};
test( "active page and start page should be set to the fist page in the selected set", function(){
var firstPage = findFirstPage();
$.testHelper.reloadLib(libName);
same($.mobile.startPage, firstPage);
same($.mobile.activePage, firstPage);
});
test( "mobile viewport class is defined on the first page's parent", function(){
var firstPage = findFirstPage();
$.testHelper.reloadLib(libName);
ok(firstPage.parent().hasClass('ui-mobile-viewport'));
});
test( "mobile page container is the first page's parent", function(){
var firstPage = findFirstPage();
$.testHelper.reloadLib(libName);
same($.mobile.pageContainer, firstPage.parent());
});
test( "page loading is called on document ready", function(){
expect( 2 );
$.testHelper.alterExtend({ pageLoading: function(){
ok("called");
}});
$.testHelper.reloadLib(libName);
});
test( "hashchange triggered on document ready with single argument: true", function(){
expect( 2 );
$(window).bind("hashchange", function(ev, arg){
same(arg, true);
$.testHelper.reloadLib(libName);
});
$.testHelper.reloadLib(libName);
});
test( "enhancments are skipped when the browser is not grade A", function(){
setGradeA(false);
$.testHelper.reloadLib(libName);
//TODO test that silentScroll is called on window load
});
//NOTE easiest way to check for enhancements, not the most obvious
ok(!$("html").hasClass("ui-mobile"));
});
test( "enhancments are added when the browser is grade A", function(){
setGradeA(true);
$.testHelper.reloadLib(libName);
ok($("html").hasClass("ui-mobile"));
});
//TODO lots of duplication
test( "pageLoading doesn't add the dialog to the page when loading message is false", function(){
$.testHelper.alterExtend({loadingMessage: false});
$.testHelper.reloadLib(libName);
$.mobile.pageLoading(false);
ok(!$(".ui-loader").length);
});
test( "pageLoading doesn't add the dialog to the page when done is passed as true", function(){
$.testHelper.alterExtend({loadingMessage: true});
$.testHelper.reloadLib(libName);
// TODO add post reload callback
$('.ui-loader').remove();
$.mobile.pageLoading(true);
ok(!$(".ui-loader").length);
});
test( "pageLoading adds the dialog to the page when done is true", function(){
$.testHelper.alterExtend({loadingMessage: true});
$.testHelper.reloadLib(libName);
$.mobile.pageLoading(false);
ok($(".ui-loader").length);
});
var metaViewportSelector = "head meta[name=viewport]",
setViewPortContent = function(value){
$(metaViewportSelector).remove();
$.testHelper.alterExtend({metaViewportContent: value});
$.testHelper.reloadLib(libName);
};
test( "meta view port element is added to head when defined on mobile", function(){
setViewPortContent("width=device-width");
same($(metaViewportSelector).length, 1);
});
test( "meta view port element not added to head when not defined on mobile", function(){
setViewPortContent(false);
same($(metaViewportSelector).length, 0);
});
var findFirstPage = function() {
return $("[data-role='page']").first();
};
test( "active page and start page should be set to the fist page in the selected set", function(){
var firstPage = findFirstPage();
$.testHelper.reloadLib(libName);
same($.mobile.startPage, firstPage);
same($.mobile.activePage, firstPage);
});
test( "mobile viewport class is defined on the first page's parent", function(){
var firstPage = findFirstPage();
$.testHelper.reloadLib(libName);
ok(firstPage.parent().hasClass('ui-mobile-viewport'));
});
test( "mobile page container is the first page's parent", function(){
var firstPage = findFirstPage();
$.testHelper.reloadLib(libName);
same($.mobile.pageContainer, firstPage.parent());
});
test( "page loading is called on document ready", function(){
$.testHelper.alterExtend({ pageLoading: function(){
start();
ok("called");
}});
stop();
$.testHelper.reloadLib(libName);
});
test( "hashchange triggered on document ready with single argument: true", function(){
$(window).bind("hashchange", function(ev, arg){
same(arg, true);
start();
});
stop();
$.testHelper.reloadLib(libName);
});
});
})(jQuery);

View file

@ -0,0 +1,18 @@
/*
* mobile core unit tests
*/
(function($){
var mobilePage = undefined;
module('jquery.mobile.core.js');
// NOTE important to use $.fn.one here to make sure library reloads don't fire
// the event before the test check below
$(document).one("mobileinit", function(){
mobilePage = $.mobile.page;
});
test( "mobile.page is available when mobile init is fired", function(){
ok(mobilePage !== undefined, "$.mobile.page is defined");
});
})(jQuery);

View file

@ -2,71 +2,75 @@
* mobile core unit tests
*/
var libName = "jquery.mobile.core.js",
scrollTimeout = 20, // TODO expose timing as an attribute
scrollStartEnabledTimeout = 150;
(function($){
var libName = "jquery.mobile.core.js",
scrollTimeout = 20, // TODO expose timing as an attribute
scrollStartEnabledTimeout = 150;
module(libName, {
setup: function(){
$("<div id='scroll-testing' style='height: 1000px'></div>").appendTo("body");
},
module(libName, {
setup: function(){
$("<div id='scroll-testing' style='height: 1000px'></div>").appendTo("body");
},
teardown: function(){
$("#scroll-testing").remove();
}
});
teardown: function(){
$("#scroll-testing").remove();
}
});
var scrollUp = function( pos ){
$(window).scrollTop(1000);
ok($(window).scrollTop() > 0);
var scrollUp = function( pos ){
$(window).scrollTop(1000);
ok($(window).scrollTop() > 0);
if(pos) {
$.mobile.silentScroll(pos);
} else {
$.mobile.silentScroll();
}
};
if(pos) {
$.mobile.silentScroll(pos);
} else {
$.mobile.silentScroll();
}
};
test( "silent scroll scrolls the page to the top by default", function(){
scrollUp();
test( "silent scroll scrolls the page to the top by default", function(){
scrollUp();
stop();
setTimeout(function(){
same($(window).scrollTop(), 0);
start();
}, scrollTimeout);
});
stop();
setTimeout(function(){
same($(window).scrollTop(), 0);
start();
}, scrollTimeout);
});
test( "silent scroll scrolls the page to the passed y position", function(){
var pos = 10;
scrollUp(pos);
test( "silent scroll scrolls the page to the passed y position", function(){
var pos = 10;
scrollUp(pos);
stop();
setTimeout(function(){
same($(window).scrollTop(), pos);
start();
}, scrollTimeout);
});
stop();
setTimeout(function(){
same($(window).scrollTop(), pos);
start();
}, scrollTimeout);
});
// NOTE may be brittle depending on timing
test( "silent scroll takes at least 20 ms to scroll to the top", function(){
scrollUp();
// NOTE may be brittle depending on timing
test( "silent scroll takes at least 20 ms to scroll to the top", function(){
scrollUp();
stop();
setTimeout(function(){
ok($(window).scrollTop() != 0);
start();
}, scrollTimeout - 1);
});
stop();
setTimeout(function(){
ok($(window).scrollTop() != 0);
start();
}, scrollTimeout - 1);
});
test( "scrolling marks scrollstart as disabled for 150 ms", function(){
$.event.special.scrollstart.enabled = true;
scrollUp();
ok(!$.event.special.scrollstart.enabled);
test( "scrolling marks scrollstart as disabled for 150 ms", function(){
$.event.special.scrollstart.enabled = true;
scrollUp();
ok(!$.event.special.scrollstart.enabled);
stop();
setTimeout(function(){
ok($.event.special.scrollstart.enabled);
start();
}, scrollStartEnabledTimeout);
});
stop();
setTimeout(function(){
ok($.event.special.scrollstart.enabled);
start();
}, scrollStartEnabledTimeout);
});
//TODO test that silentScroll is called on window load
})(jQuery);

View file

@ -5,27 +5,13 @@
<title>jQuery Mobile Core Test Suite</title>
<script type="text/javascript" src="../../../js/jquery.js"></script>
<script type="text/javascript" src="../../../tests/jquery.testHelper.js"></script>
<script type="text/javascript" src="../../../js/jquery.ui.widget.js"></script>
<script type="text/javascript" src="../../../js/jquery.mobile.widget.js"></script>
<script type="text/javascript" src="../../../js/jquery.mobile.media.js"></script>
<script type="text/javascript" src="../../../js/jquery.mobile.support.js"></script>
<script type="text/javascript" src="../../../js/jquery.mobile.event.js"></script>
<script type="text/javascript" src="../../../js/jquery.mobile.core.js"></script>
<script type="text/javascript" src="../../../js/jquery.mobile.page.js"></script>
<script type="text/javascript" src="../../../js/jquery.ui.position.js"></script>
<script type="text/javascript" src="../../../js/jquery.mobile.fixHeaderFooter.js"></script>
<script type="text/javascript" src="../../../js/jquery.mobile.forms.checkboxradio.js"></script>
<script type="text/javascript" src="../../../js/jquery.mobile.forms.textinput.js"></script>
<script type="text/javascript" src="../../../js/jquery.mobile.forms.select.js"></script>
<script type="text/javascript" src="../../../js/jquery.mobile.buttonMarkup.js"></script>
<script type="text/javascript" src="../../../js/jquery.mobile.forms.button.js"></script>
<script type="text/javascript" src="../../../js/jquery.mobile.forms.slider.js"></script>
<script type="text/javascript" src="../../../js/jquery.mobile.controlGroup.js"></script>
<link rel="stylesheet" href="../../../external/qunit.css" type="text/css"/>
<script type="text/javascript" src="../../../external/qunit.js"></script>
<script type="text/javascript" src="core_mobileinit.js"></script>
<script type="text/javascript" src="../../../js/"></script>
<script type="text/javascript" src="../../../js/jquery.mobile.core.js"></script>
<script type="text/javascript" src="../../jquery.testHelper.js"></script>
<link rel="stylesheet" href="../../../themes/default" />
<link rel="stylesheet" href="../../../external/qunit.css" type="text/css"/>
<script type="text/javascript" src="core.js"></script>
<script type="text/javascript" src="core_scroll.js"></script>

View file

@ -37,16 +37,24 @@
same(called, 2, "change page should be called twice");
});
test( "check for external link succeeds", function(){
same($.mobile.isExternalLink("<a href='mailto:'></a>"), true, "mailto");
same($.mobile.isExternalLink("<a href='http://foo.com'></a>"), true, "http protocol");
same($.mobile.isExternalLink("<a href='foo' rel='external'></a>"), true, "rel=external");
same($.mobile.isExternalLink("<a href='foo' target='foo'></a>"), true, "target");
test( "path.get method is working properly", function(){
same($.mobile.path.get(), window.location.hash, "get method returns location.hash");
same($.mobile.path.get( "#foo/bar/baz.html" ), "foo/bar/", "get method with hash arg returns path with no filename or hash prefix");
same($.mobile.path.get( "#foo/bar/baz.html/" ), "foo/bar/baz.html/", "last segment of hash is retained if followed by a trailing slash");
});
test( "check for external link fails", function(){
same($.mobile.isExternalLink("<a href='foo.html'></a>"), false, "mailto");
same($.mobile.isExternalLink("<a href='#foo'></a>"), false, "mailto");
test( "path.isExternal method is working properly", function(){
same($.mobile.path.isExternal("mailto:"), true, "mailto protocol");
same($.mobile.path.isExternal("http://foo.com"), true, "http protocol");
same($.mobile.path.isExternal("http://www.foo.com"), true, "http protocol with www");
same($.mobile.path.isExternal("tel:16178675309"), true, "tel protocol");
same($.mobile.path.isExternal("foo.html"), false, "filename");
same($.mobile.path.isExternal("foo/foo/foo.html"), false, "file path");
same($.mobile.path.isExternal("../../index.html"), false, "relative parent path");
same($.mobile.path.isExternal("/foo"), false, "root-relative path");
same($.mobile.path.isExternal("foo"), false, "simple string");
same($.mobile.path.isExternal("#foo"), false, "local id reference");
});
})(jQuery);