Skip to content
This repository has been archived by the owner on Oct 8, 2021. It is now read-only.

Commit

Permalink
Removed the ajaxClick function and moved its logic into the live clic…
Browse files Browse the repository at this point in the history
…k event handler, where it is now refactored and simplified. Thx to Jeffrey Way for ideas that went into this refactor.

Also, clicks that are triggered on anchors will now be able to make a new http request, which improves listview behavior when clicking LIs that resolve to external urls.

Included in commit is a new demo/test page with various link types to make sure they behave as expected.

Fixes #272, Fixes #264
  • Loading branch information
scottjehl committed Oct 23, 2010
1 parent 6f5ce29 commit e736cae
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 37 deletions.
40 changes: 40 additions & 0 deletions docs/pages/docs-link-scenarios.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html>
<head>
<title>jQuery Mobile Docs - Pages</title>
<link rel="stylesheet" href="../../themes/default" />
<script type="text/javascript" src="../../js/all"></script>
</head>
<body>

<div data-role="page">

<div data-role="header">
<h1>Linking pages</h1>
</div><!-- /header -->

<div data-role="content">

<p>jQuery Mobile is designed to work with simple page linking conventions. The following list demonstrates how different types of links will be handled, either remotely or through an Ajax Request.</p>

<ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b">
<li data-role="list-divider">Examples of links that work within a single-page (if the page exists)</li>
<li><a href="docs/pages/index.html">[href="docs/pages/index.html"]</a></li>
<li><a href="/docs/toolbars/index.html">[href="/docs/toolbars/index.html"]</a></li>
<li><a href="#somelocalID">[href="#somelocalID"]</a></li>
<li>Note: an full URL to the same-domain will also work</li>
<li data-role="list-divider">Examples of links that trigger a refresh</li>
<li><a href="docs/pages/index.html" rel="external">[rel="external"]</a></li>
<li><a href="docs/pages/index.html" target="_blank">[target="_blank"]</a></li>
<li><a href="mailto:john@doe.com">[href="mailto:john@doe.com"]</a></li>
<li><a href="tel:543-434-3454">[href="tel:543-434-3454"]</a></li>
<li><a href="http://google.com">[href="http://google.com"]</a></li>
<li data-role="list-divider">Links that return false</li>
<li><a href="#">[href="#"]</a></li>
</ul>

</div><!-- /content -->
</div><!-- /page -->

</body>
</html>
66 changes: 29 additions & 37 deletions js/jquery.mobile.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,47 +104,39 @@
$('#ui-base').attr('href', baseUrl);
}


// send a link through hash tracking
jQuery.fn.ajaxClick = function() {
var href = jQuery( this ).attr( "href" );
pageTransition = jQuery( this ).data( "transition" ) || "slide";
forceBack = jQuery( this ).data( "back" ) || undefined;
nextPageRole = jQuery( this ).attr( "data-rel" );

//find new base for url building
var newBaseURL = getBaseURL();

//if href is absolute but local, or a local ID, no base needed
if( /^\//.test(href) || (/https?:\/\//.test(href) && !!(href).match(location.hostname)) || /^#/.test(href) ){
newBaseURL = '';
}

// set href to relative path using baseURL and
if( !/https?:\/\//.test(href) ){
href = newBaseURL + href;
//click routing - direct to HTTP or Ajax, accordingly
jQuery( "a" ).live( "click", function(event) {

This comment has been minimized.

Copy link
@JeffreyWay

JeffreyWay Oct 26, 2010

Contributor

Hmm - would it be better to use the delegate method, so that we're not attaching a listener to every single anchor on the page? I wonder if it'd make any noticeable difference..

This comment has been minimized.

Copy link
@scottjehl

scottjehl Oct 27, 2010

Live uses event delegation. So, only one event binding to document.

This comment has been minimized.

Copy link
@JeffreyWay

JeffreyWay Oct 27, 2010

Contributor

Oh, haha. I'd swear I read "bind," instead of "live." Disregard.

var $this = $(this),
//get href, remove same-domain protocol and host
href = $this.attr( "href" ).replace( location.protocol + "//" + location.host, ""),
//if it still starts with a protocol, it's external, or could be :mailto, etc
external = /^\w+:|#/.test( href ) || $this.is( "[target],[rel=external]" ),

This comment has been minimized.

Copy link
@JeffreyWay

JeffreyWay Oct 27, 2010

Contributor

The second OR part of the regex will match a hash that's anywhere in the href. The caret should be in front. So:
/^\w+:|^#/.test( href )
Or:
/^(\w+:|#)/.test( href )

This comment has been minimized.

Copy link
@jzaefferer

jzaefferer Oct 27, 2010

Contributor

If you don't need that group anyway, use a non-capturing group:

/^(:?\w+:|#)/.test( href )
nullLink = href == '#';

if( nullLink ){
//for links created purely for interaction - ignore
return false;
}

This comment has been minimized.

Copy link
@JeffreyWay

JeffreyWay Oct 27, 2010

Contributor

Is nullLink being used anywhere else in this script? If so, is there a need to create the variable? Maybe not...
//for links created purely for interaction - ignore
(href === '#') && return false;


//if it's a non-local-anchor and Ajax is not supported, or if it's an external link, go to page without ajax
if ( ( /^[^#]/.test(href) && !jQuery.support.ajax ) || ( /https?:\/\//.test(href) && !!!href.match(location.hostname) ) ) {
location = href
else if( external ){
//deliberately redirect, in case click was triggered
location.href = href;
}
else{
if( $(this).is(unHashedSelectors) ){
changePage(href, pageTransition, undefined);
}
else{
changePage(href, pageTransition, undefined, true);
else {
//use ajax
var pageTransition = $this.data( "transition" ) || "slide",
forceBack = $this.data( "back" ) || undefined,
changeHashOnSuccess = !$(this).is(unHashedSelectors);

This comment has been minimized.

Copy link
@JeffreyWay

JeffreyWay Oct 27, 2010

Contributor

Can we still use the 'cached' version of $(this)?
changeHashOnSuccess = !$this.is(unHashedSelectors);


nextPageRole = $this.attr( "data-rel" );

//if it's a relative href, prefix href with base url
if( href.indexOf('/') !== 0 && href.indexOf('#') !== 0 ){

This comment has been minimized.

Copy link
@JeffreyWay

JeffreyWay Oct 27, 2010

Contributor

Saves a few characters.
if ( href.indexOf('/') && href.indexOf('#') !== 0 ) { ...

This comment has been minimized.

Copy link
@JeffreyWay

JeffreyWay Oct 27, 2010

Contributor

So, this covers '/somepage.html' and '#somepage.html'. But what about:
some page
Does this need to receive the base url as well?

This comment has been minimized.

Copy link
@scottjehl

scottjehl Oct 27, 2010

unless I'm misunderstanding your question, it's those two types that don't get the relative base, while any others do. Some somepage.html would be covered, ya.

This comment has been minimized.

Copy link
@JeffreyWay

JeffreyWay Oct 27, 2010

Contributor

Hey Scott - So odd; I've deleted that comment three times now. Deleted it a few moments after originally posting it last night. Trying it again! UPDATE - must be a Github bug. Every time I delete the thread, and refresh the page, it shows back up again.

This comment has been minimized.

Copy link
@scottjehl

scottjehl Oct 27, 2010

ok - no prob. Changes are in. I'm working on one more - #foo shouldn't go straight to hash change, in case of errors.

href = getBaseURL() + href;
}

changePage(href, pageTransition, forceBack, changeHashOnSuccess);
}
return this;
};

// ajaxify all navigable links
jQuery( "a:not([href='#']):not([target]):not([rel='external']):not([href^='mailto:'])" ).live( "click", function(event) {
jQuery( this ).ajaxClick();
return false;
event.preventDefault();
});

// turn on/off page loading message.
Expand Down Expand Up @@ -199,7 +191,7 @@
from = toIsArray ? to[0] : $.activePage,
to = toIsArray ? to[1] : to,
url = fileUrl = $.type(to) === "string" ? to.replace( /^#/, "" ) : null,
back = (back !== undefined) ? back : (forceBack || ( urlStack.length > 1 && urlStack[ urlStack.length - 2 ].url === url )),
back = (back !== undefined) ? back : ( urlStack.length > 1 && urlStack[ urlStack.length - 2 ].url === url ),
transition = (transition !== undefined) ? transition : ( pageTransition || "slide" );

//unset pageTransition, forceBack
Expand Down

1 comment on commit e736cae

@scottjehl
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thx guys - these updates are rolled in now. http://github.com/jquery/jquery-mobile/commits/master

Please sign in to comment.