Thursday, December 22, 2011

jQuery Mobile and Duplicated Page IDs

In the previous post, I touched upon how browsers safely handle duplicate IDs in a html file. Things seem to work fine for the three main uses of element IDs, i.e. linking to fragments, styling and referencing the element in javascript. The first element with matching ID is picked up and styling is done for all matches.


Now let us extend this test to the jQuery Mobile framework. You can launch the below multi-page code here.


 Launch 


<!DOCTYPE html>
<html>
  <head>
    <title>jQuery Mobile Duplicate IDs</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.css" /> 
    <script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
    <script src="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.js"></script>
  </head>
  <body>
    <div data-role="page" id="p1">
      <div data-role="content">
        <p><a href="#p2" data-role="button">duplicate page id</a></p>
      </div>
    </div>
    <div data-role="page" id="p2">
      <div data-role="content">
        <a data-role="button" data-rel="back" data-direction="reverse">1 1</a>
        <a href="#p1" data-role="button" data-rel="dialog">Open Dialog</a>
      </div>
    </div>
    <div data-role="page" id="p2">
      <div data-role="content">
        <a data-role="button" data-rel="back" data-direction="reverse"> 0 </a>
      </div>
    </div>
  </body>
</html>


On load, when you click on the button, ajax is used to navigate to the page with ID p2, but here there are two IDs that match. The framework is not expecting this, and correctly so. Things go haywire. You have the resulting page rendered with seemingly garbled text, Actually both pages are rendered, but in a weird way. You will see the first button from both the pages, at the same location, merging the texts "1  1" and "  0  " to show "101". Then there is the second button which gets hidden, but its text "Dialog" is shown.


It gets interesting when you click on the button "101" now shown, as you can see from the code, it should take you back to the page ID p1. But here, two pages were rendered, and the first occurring page div slides out and for a brief instant you can see the second page container, which also slides out.


If you use the browser code inspector, you will see the data-url attribute being automatically added to all page divs. Since no data-url was specified here, the page ID is copied as is. In this case, both data-urls are the same. You can try the above example with different page IDs but having the same data-url and the resultant output is the same. 


<div data-role="page" id="p2" data-url="durl1">
......
<div data-role="page" id="p3"  data-url="durl1" >

One final scenario, suppose if the page IDs are duplicated but each page has a different data-url specified. 


<div data-role="page" id="p2" data-url="durl1">
......
<div data-role="page"  id="p2"  data-url="durl2">

And now try to navigate to any page using the data-url. 

<a href="#durl1" data-role="button">Open Page 1</a>
<a href="#durl2" data-role="button">Open Page 2</a>

Bingo! Both links work just works fine.


So jQuery Mobile primarily uses data-url for page navigation and as long as they are unique, navigation works just fine. And it was a purely accidental discovery that having duplicate data-urls messes up the rendered content.


Now is this a valid bug? I feel the framework should gracefully handle this and render only the first instance of matching data-url. The behavior would then be consistent with how various browser engines handle duplicate IDs (from my previous post). But again is this an overkill? Should the framework focus on adding more features that work correctly on multiple devices/platforms/browsers or fix such scenarios. That is a call that the jQuery Mobile developer community has to take.

Using duplicate IDs in HTML

Well today I'm being a bit controversial. Let us see what the HTML5 spec says about unique IDs in a HTML file.
The id attribute specifies its element's unique identifier (ID). The value must be unique amongst all the IDs in the element's home subtree and must contain at least one character. The value must not contain any space characters.
An element's unique identifier can be used for a variety of purposes, most notably as a way to link to specific parts of a document using fragment identifiers, as a way to target an element when scripting, and as a way to style a specific element from CSS.
Yes its been mentioned almost everywhere on the planet that ID must be unique. Now let us look at the below code,


Launch


dup.css


#p2 {
  background-color: yellow; 
}

dup-id.html

<!DOCTYPE html>
<html>
  <head>
    <title>Duplicate ID Tester</title>
<link rel="stylesheet" href="dup.css" />
  </head>
  <body>
<p><a href="#p1">1</a></p>
<p><a href="#p2">2</a></p>
<p><a href="#p2">3</a></p>
    <div id="p1">
<p>ID IS 1</p>
</div>
    <div id="p2">
<p>ID IS 2</p>
</div>
    <div id="p2">
<p>ID IS 3</p>
</div>
<p>Now lets get ID 2 again using javascript</p>
<script>
document.write(document.getElementById("p2").innerHTML);
</script>
  </body>
</html>

I've committed a big sin in this HTML code. Yes there are 2 div elements that use the same ID "p2". What should happen when you render this page now? I have tried this code on the famous five (Chrome, Firefox, IE, Safari and Opera) and also on the Android, Opera Mobile and Firefox Mobile browsers, and they all behave exactly the same way. You will actually see that the three major criteria mentioned in the HTML5 spec, seem to work just fine.
  • Linking to a document fragment: Reduce your browser size and click on link 2, it will navigate to the first div with the ID p2
  • Styling: Both the divs with the ID p2 are styled
  • Targeting the element using JavaScript: You will see that the text (ID IS 2) of the first div with ID p2 is printed using javascript at the end of the html doc.
To summarize, linking and picking up the first element with matching ID is done and all matching elements are styled. 


But the question is, why do browsers behave this well in spite of the spec mandating the ID to be unique? The answer is that browsers have come away from the strict mode and are more relaxed in the way they handle bad code (even more so now with HTML5). They are quite developer friendly and try to render as much as possible and fail gracefully where possible. Yes, that is the way to go!


But still a word of caution, it is not recommended to use duplicate IDs as it is against the spec and the browsers could change their implementation anytime. A hundred different things could go wrong in your code and you will spend hours figuring out what the issue is.

Monday, December 19, 2011

jQuery Mobile Page Caching demo

In my previous post, I outlined how to prefetch links to make jQuery mobile app load your pages faster. The ui-loader spinning animation was not shown as you navigate from one page to another.

Launch
 - The previous example with prefetch


But, as also mentioned, it has certain limitations,
  • If there are more pages, more http requests are sent out and more bandwidth is required to prefetch
  • If a page hasn't been fully prefetched, the ui-loader spinner animation comes up till the page is fully loaded. Try to click fast and you will see
  • Once you visit a prefetched page, navigating away from the page will remove the page from DOM. So this is not same as caching the page. The next visit to the page will again need the page to be fetched.
So the obvious solution seems to be to cache the frequently visited pages in the DOM. This way, every link doesn't have to be prefetched on every visit to the page. This is easily done in jQuery Mobile by adding the attribute data-dom-cache="true" to the page div container of the page that you want to cache. 


You could also cache a specific page programmatically by using this call


    pageContainerElement.page({ domCache: true });

If you want to cache all pages visited, you could turn on DOM caching using the below code (but keep an eye on the DOM size as it could grow very fast)


    $.mobile.page.prototype.options.domCache = true;

You can now observe how caching works with the code inspector open (CTRL+SHIFT+I) in your browser. As you navigate, the visited page is not removed from the DOM and after the first visit, it remains put! You will remember in the previous post, the page div used to get added to the DOM and then removed on every page visit.

Let us visit the code...

Launch - Example with prefetch and DOM cache enabled


mainpage-domcache.html
<!DOCTYPE html>
<html>
  <head>
    <title>Main Page</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.css" /> 
    <script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
    <script src="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.js"></script>

    <!-- Use only if you want to cache all visited pages -->
    <script>
      $.mobile.page.prototype.options.domCache = true;
    </script>
  </head>
  <body>
    <div id="page1" data-role="page">
      <div data-role="header">
        <h1>Header of Main Page</h1>
      </div>
      <div data-role="content">
        <p><a href="secondpage-domcache.html" data-role="button" data-prefetch>Go to Page 2</a></p>
      </div>
    </div>
  </body>
</html>

secondpage-domcache.html (to cache single page)
<title>Second Page</title>
<div id="page2" data-role="page" data-dom-cache="true">
  <div data-role="header">
    <h1>Header of Page 2</h1>
  </div>
  <div data-role="content">
    <p><a href="#" data-role="button" data-rel="back">Go Back</a></p>
  </div>
</div>

Here you will see that the spinning loader doesn't show up. The page is already there in the DOM after the first visit! You can click the links fast and see it still works fine. You can exclude the script to cache everything and try this code with multiple pages and see how caching works.

Just as in real life, there is a flip side to everything positive. Here, you have to be careful how big your DOM grows, as pages keep adding to it. You have to code for the clean up of older pages or pages you no longer need in cache. Mobile devices have limited memory and a bloating DOM could cause misery. So take care !

jQuery Mobile Prefetching pages demo

Using a single-page template for your mobile app makes your app faster and lighter. But you have to fetch each page during navigation and you end up seeing the ui-loader spinning icon animation every time. It can get to your nerves. 


Launch - Example without prefetch


The above example, from my previous post shows how the spinning icon comes up each time you navigate from the main page to page 2. I will not list the code here as its already listed in an earlier post.


In a multi-page template whereas, the entire set of pages are already loaded into the DOM and the navigation is much faster. A similar behavior can be obtained in a single-page application by prefetching pages. This is done by just adding the attribute data-prefetch to all the links that you want to prefetch. As soon as the page loads, it starts fetching these links and loads it into the DOM. You can observe this behavior with the code inspector open (CTRL+SHIFT+I) in your browser. Now navigating to one of these links happens immediately and the spinning loader is no longer shown.


You could also prefetch a link programmatically by using this JavaScript call
    $.mobile.loadPage( pageUrl );

The below code shows how data-prefetch works. You can launch it in a separate browser tab.


Launch - Example with prefetch


mainpage.html
<!DOCTYPE html>
<html>
  <head>
    <title>Main Page</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.css" /> 
    <script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
    <script src="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.js"></script>
  </head>
  <body>
    <div id="page1" data-role="page">
      <div data-role="header">
        <h1>Header of Main Page</h1>
      </div>
      <div data-role="content">
        <p><a href="secondpage.html" data-role="button" data-prefetch>Go to Page 2</a></p>
      </div>
    </div>
  </body>
</html>

secondpage.html
<title>Second Page</title>
<div id="page2" data-role="page">
  <div data-role="header">
    <h1>Header of Page 2</h1>
  </div>
  <div data-role="content">
    <p><a href="#" data-role="button" data-rel="back">Go Back</a></p>
  </div>
</div>

Here you will see that the spinning loader doesn't show up. (Of course you can click very fast and try to load before the prefetch occurs, the loader shows up only then.)


Great isn't it. But few things you have to take care,
  • If there are more pages, more http requests are sent out and more bandwidth is required to prefetch
  • If a page hasn't been fully prefetched, the ui-loader spinner comes up and the page is shown only after the page is completely fetched
  • This is not same as the browser cache. Once you navigate to a prefetched page, and then navigate to another page, the prefetched page is removed from the DOM.
So use this judiciously to make your jQuery Mobile app navigation smoother to the user.


In my next post I will show how to cache a jQuery Mobile page in DOM and thus avoid the issue of multiple prefetch.

Sunday, December 18, 2011

jQuery Mobile Page Transitions with data-ajax=false

In my earlier post here, I outlined the various page transitions that are available in jQuery Mobile. 


In single-page template documents, jQM uses Ajax to smoothly transition between pages and when not possible, the framework does a simple HTTP request to pull in the page. Situations where Ajax transitions are not used are:


When a page loaded is:

  1. from an external domain
  2. data-ajax="false" attribute is used
  3. rel="external" is specified
  4. target attribute is specified

This is also well documented (with examples).


In multi-page template documents, jQM needs Ajax to transition between the multiple page containers. Now lets play with this a bit. Let us try to override this with the data-ajax attribute and see what happens.


Consider below code, you can click on the link below to launch it in a separate browser tab:
Launch


<!DOCTYPE html>
<html>
  <head>
    <title>jQuery Mobile Transitions Demo with data-ajax="false"</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.css" /> 
    <script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
    <script src="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.js"></script>
  </head>
  <body>
    <div data-role="page" id="page1">
 <div data-role="content">
        <p><a href="#page2" data-transition="flip" data-role="button">data-transition="flip"</a></p>
        <p><a href="#page2" data-transition="flip" data-role="button" data-ajax="false" data-theme="e">data-transition="flip" data-ajax="false"</a></p>
        <p><a href="#page2" data-rel="dialog" data-role="button">data-rel="dialog"</a></p>
        <p><a href="#page2" data-rel="dialog" data-role="button" data-transition="pop" data-ajax="false" data-theme="e">data-rel="dialog" data-ajax="false"</a></p>
        <p><a href="#page3" data-role="button">data-role="dialog"</a></p>
        <p><a href="#page3" data-role="button" data-ajax="false" data-theme="e">data-role="dialog" data-ajax="false"</a></p>
        <p><a href="#page3" data-role="button" data-rel="dialog">data-rel="dialog" data-role="dialog"</a></p>
        <p><a href="#page3" data-role="button" data-rel="dialog" data-ajax="false" data-theme="e">data-rel="dialog" data-role="dialog" data-ajax="false"</a></p>
      </div>
    </div>
    <div data-role="page" id="page2">
      <div data-role="content">
        <a data-role="button" data-rel="back" data-direction="reverse">Back</a>
      </div>
    </div>
    <div data-role="dialog" id="page3">
      <div data-role="content">
        <a data-role="button" data-rel="back" data-direction="reverse">Back</a>
      </div>
    </div>
  </body>
</html>


When you launch the above code in a browser, you will note one link works properly followed by another link that doesn't. These links are invoked with data-ajax="false" and highlighted here with a yellow theme. You can also open the code inspector (by CTRL+SHIFT+I) and observe how the DOM behaves as you try out the various scenarios.


The entire behavior of transitions in a multi-page template document with data-ajax="false" is not documented at present (see documentation link given earlier). From the above code you will note the following behavior when data-ajax="false" is specified,

  • DOM is not reloaded everytime since this is a multi-page template document
  • Only the default slide transition works, even if you specify any other data-transition (2nd button)
  • If a Dialog is launched by data-rel="dialog", again only slide transition works (not the default pop), even if you specify data-transition="pop" (4th button)
  • If a Dialog is launched using data-role="dialog", then the transition used is "pop" and any value set in the data-transition attribute is ignored (6th button)
  • If a Dialog is launched using data-role="dialog", setting the data-rel="dialog" might not be required (7th button)

It is not yet clear if the above behavior is as expected and implemented so, and if only the documentation of jQM needs to be updated. Or maybe JQM should ignore data-ajax="false" in a multi-page template scenario. I have now logged a bug against jQuery Mobile and await feedback on the same https://github.com/jquery/jquery-mobile/issues/3296.

Friday, December 16, 2011

Minimal required code in HTML5

I've encountered this question repeatedly of late.

"What are the tags required at bare minimum for a html file?"

Earlier there were a bunch of mandatory tags that were required for any html file. At bare minimum, the recommended structure was: (ref: http://www.w3.org/TR/html4/struct/global.html)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<HTML>
  <HEAD>
    <TITLE>A small HTML</TITLE>
  </HEAD>
  <BODY>
    <P>Small HTML file!</P>
  </BODY>
</HTML>

Yes, using capitals for the tags was the way to go! Those were the days of the purists and strict was the way to be. Now open your notepad and copy the above code, save the file as old.html and launch it in Chrome or Firefox. You will see only one line "Small HTML file!" shown. Now launch the developer tools in Chrome or Inspect Element in Firefox. This can be done by pressing CTRL+SHIFT+I in both the browsers. You will see the html code rendered by the browser now shown in the inspector. The code matches with the above code.

Now lets look at how things stand today. Welcome HTML5!

<!DOCTYPE html>
Smallest HTML file!

Type the above code in notepad and save it as new.html. Yes just two lines, actually the first line is recommended for HTML5, but for basic stuff even that is not necessary. You can even skip that line for this particular exercise. Now save and open the file in your browser. Voila, the text is there, now open the code inspector. You will see the missing tags have been automatically added by the browser. This is what the code inspector should show:

<!DOCTYPE html>
<html>
  <head></head>
  <body>Smallest HTML file!</body>
</html>

Great isn't it. Things have been vastly simplified and made easier for the developer. DOCTYPE's earlier used to cause allergic reactions in me. Now it requires just one word "html". 

There is one more thing that I wish to highlight. I see so many HTML5 pages still showing this code while using JavaScript,

<SCRIPT type="text/javascript" src="....">

This can simply be

<script src="....">

There is no need to specify the type attribute. JavaScript is the default. And yes please use small case where possible. Easier on the eyes and the brain!

There are many more wonderful simplifications done in the HTML5 semantics. And there are entire chapters dedicated to this topic in various HTML5 books. But somehow, I keep encountering the above quite often off late and so the post.

Thursday, December 15, 2011

jQuery Mobile single-page vs multi-page template

[Updated 2012/02/09]
In my recent posts I mentioned about jQuery Mobile single-page and multi-page templates, so what exactly are the differences between them?


Single Page Template:

Launch - example from previous post, notice the address shown as you navigate
  • Lighter and cleaner. Each page is a separate html file and more modular. 
  • Better fallback if JavaScript is not supported. So works well on more platforms, you could even target grade C browsers 
  • On first load, the start page is loaded into the DOM. An internal reference is always held to this. Any new page loaded is added to the DOM. Any previously shown page is removed from the DOM. The start page is always in the DOM.
  • The DOM size is relatively smaller
  • Optional to use the "page" data-role element in the code
  • Can turn off Ajax Navigation between pages using data-ajax="false"
  • Recommend to use the <title> tag for page titles
  • The <title> tag always gets precedence during page loads
  • Consumes more bandwidth as each page navigation generates a new request
  • Navigating back to a previously loaded page will again generate a fresh request (with DOM caching you can avoid reloading of the same pages multiple times)
  • First load is faster, but every subsequent page has to be fetched
  • Suitable for larger applications and situations where you want to target as many platforms as possible including platforms which lack JavaScript support



Multi Page Template:

Launch - example from previous post, notice the address shown as you navigate
  • Heavier. All the pages are in a single html file.
  • Needs JavaScript support as Ajax Navigation is used
  • Multiple page containers are present, and only the first one is shown when page loads
  • Large applications with many pages will increase the DOM size
  • The "page" data-role element is required
  • Using data-ajax="false" for internal pages ignores the data-transition attribute, by default slide is used
  • Recommend to use the data-title attribute for all page titles
  • On first load, <title> tag is used and subsequent transitions data-title is used for page titles
  • Since all pages are already loaded, no additional requests are generated for navigating between pages
  • First load is slower as the file size is larger, but subsequent page navigation is fast
  • Suitable for relatively smaller applications and situations where you know the capabilities of your target platforms including presence of JavaScript support

jQuery Mobile Recommendations for Page Title


In my previous two posts, I outlined how page titles are picked up in jQuery Mobile in a single-page and in a multi-page template scenario.


Read them here: 
jQuery Mobile data-title behavior with multi-page template
jQuery Mobile data-title behavior in single-page template


Though its a very trivial thing, it is important that the right titles are shown on your pages as you navigate through your mobile HTML5 app.


So we see that there are 3 options available to set the page title, 

  1. The <title> tag
  2. The data-title attribute of the page container
  3. The header text in the header container

Now the question is which one to use? 
And here are my recommendations,

  1. For the landing page for any app, use the <title> tag, that always is the primary one to use. The document.title gets populated first and use the same.
  2. For multi-page template, use data-title for every page container, including the first container in the document. After first load, every subsequent Ajax transition uses this attribute.
  3. For single-page template, do not use the data-title attribute, every individual html page will have its own <title> tag and let that take precedence by default. Lack of JavaScript support, or not using Ajax transitions (via data-ajax="false"), will still show the correct title from the <title> tag.
  4. The header container (data-role="header") text should better be used for the page header and not the title. No point in having the same title and header, its plain non-intuitive!

So what do you think?

jQuery Mobile data-title behavior in single-page template

In my previous post, I had visited the behavior of the jQuery Mobile library data-title attribute under different scenarios when using a multi-page template. In this post, I will outline the behavior when using a single-page template.
Consider the below single-page template code. Click here to launch the below code in a separate browser.
Launch

mainpage-title.html



<!DOCTYPE html>
<html>
  <head>
    <title>Main Page</title>

    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.css" /> 
    <script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
    <script src="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.js"></script>
  </head>
  <body>
    <div id="page1" data-role="page" data-title="Mainpage data-title">
      <div data-role="header">
        <h1>Header of Main Page</h1>
      </div>
      <div data-role="content">
        <p><a href="secondpage-title.html" data-role="button">Go to Page 2</a></p>
      </div>
    </div>
  </body>
</html>

secondpage-title.html

<title>Second Page</title>
<div id="page2" data-role="page" data-title="Page 2 data-title">
  <div data-role="header">
<h1>Header of Page 2</h1>
  </div>
  <div data-role="content">
<p><a data-role="button" data-rel="back">Go Back</a></p>
  </div>
</div>

This is a working example. Play with it to see how the page transitions occur. Now lets go through the similar scenarios as in previous article:

  1. When you first load this html, main page is displayed, you will first see the title as "Main Page". The <title> tag (document.title) always gets precedence.
  2. If the <title> tag is not present, you will get the address of the page shown as the title.
  3. Now click on the "Go to Page 2" button, you will slide into page 2 and the title is shown as "Page 2 data-title", you will see this is a minimal html file. HTML5 makes semantics much more simpler. Browser knows what to do. Again here, since Ajax transition was used, the data-title is picked up and not the document.title which was "Second Page".
  4. From page 2, click on the "Go Back" button, now main page will open and the title is shown as "Main Page", itself and not the data-title text. This is different from multi-page template behavior. Now why did that happen? The reason here is, when Main page was first loaded, document.title gets populated, which gets precedence and is used. Now every visit to this page uses the same document.title value instead of what is there in data-title attribute. But since page 2 (newly loaded) was via Ajax, the data-title gets picked up first and not the <title> tag. This is the way it is implemented.
  5. Now in the code, remove the data-title attribute for page 2, navigate to page 2, you will see the title shown as "Second Page", now the <title> is picked up.
  6. If <title> was missing in page 2, "Header of Page 2" is displayed, the text from the header.
  7. Now in the code, remove the data-title attribute for main page, navigate to main page from page 2, you will see the title again being shown from the data-title tag this time. So the title is shown as "Mainpage data-title".
  8. Now in the code, remove the entire "header" div from page 2, and also remove the data-title from page 2, now if you navigate into page 2 from the main page, then the current title of main page is used.
So when you compare the behavior of page titles from single-page to multi-page templates, the order of precedence is different while picking the title of page 2 from the <title> tag (as outlined in point 4 above).

Wednesday, December 14, 2011

jQuery Mobile page transitions simple demo

jQuery Mobile has amazing Ajax page transitions available by default. This blog post gives a quick example to demonstrate the same.

Click here to launch the below code in a separate browser.
Launch

<!DOCTYPE html>
<html>
  <head>
    <title>Transitions Demo</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet"
href="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css" />
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script> <script src="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>
  </head>
  <body>
    <div id="page1" data-role="page">
      <div data-role="header">
        <h1>Pick your transition</h1>
      </div>
      <div data-role="content">
        <p><a href="#page2" data-role="button" data-transition="slide">Slide</a></p>
        <p><a href="#page2" data-role="button" data-transition="slideup">Slideup</a></p>
        <p><a href="#page2" data-role="button" data-transition="slidedown">Slidedown</a></p>
        <p><a href="#page2" data-role="button" data-transition="pop">Pop</a></p>
        <p><a href="#page2" data-role="button" data-transition="fade">Fade</a></p>
        <p><a href="#page2" data-role="button" data-transition="flip">Flip</a></p>
      </div>
    </div>
    <div id="page2" data-role="page">
      <div data-role="header">
        <h1>Reverse the transition now</h1>
      </div>
      <div data-role="content">
<p><a href="#" data-role="button" data-rel="back" 
data-direction="reverse">Reverse</a></p>
      </div>
    </div>
  </body>
</html>


So there are 6 page transitions are available by default and the data-transition attribute specifies the same.
  1. Slide
  2. Slideup
  3. Slidedown
  4. Pop (best for dialogs)
  5. Fade
  6. Flip
I've also included an option to reverse the most recent page transition and this is done using the data-rel and data-direction attribute as shown. As shown in the docs, adding a data-rel="dialog" attribute to the anchor link will open the page as a dialog.

Simple isn't it. Enjoy !!

Tuesday, December 13, 2011

jQuery Mobile data-title behavior with multi-page template

The jQuery Mobile library comes with wonderful Ajax page transition capabilities. But you have to keep a look on the Page title as you navigate between the various pages and I have tried to document the behavior under different scenarios in this blog.

Consider the below code, click the below link to launch the code in a separate window.
Launch

<!DOCTYPE html>
<html>
  <head>
    <title>Main Page</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.css" /> 
    <script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
    <script src="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.js"></script>
  </head>
  <body>
    <div id="page1" data-role="page" data-title="page 1 data-title">
      <div data-role="header">
        <h1>H1 Header of Page 1</h1>
      </div>
      <div data-role="content">
        <p><a href="#page2" data-role="button">Go to page 2</a></p>
        <p><a href="#dialog" data-role="button" data-ajax="false">Open Dialog</a></p>
      </div>
    </div>
    <div id="page2" data-role="page" data-title="page 2 data-title">
      <div data-role="header">
        <h1>H1 Header of Page 2</h1>
      </div>
      <div data-role="content">
        <p><a href="#page1" data-role="button">Go to page 1</a></p>
      </div>
    </div>
    <div id="dialog" data-role="dialog" data-title="dialog data-title">
      <div data-role="header">
        <h1>H1 Header of Dialog</h1>
      </div>
      <div data-role="content">
        <p><a href="#" data-rel="back" data-role="button">Back</a></p>
      </div>
    </div>
  </body>
</html>


This is a working example. Play with it to see how the page transitions occur. Now lets go through the various scenarios:
  1. When you first load this html, page 1 is displayed, you will first see the title as "Main Page". The <title> tag (document.title) always gets precedence.
  2. If the <title> tag is not present, you will get the address of the page shown as the title.
  3. Now click on the "Go to page 2" button, you will slide into page 2 and the title is shown as "page 2 data-title", ah so the data-title attribute is now working. So whenever an Ajax transition is used, the data-title is picked.
  4. From page 2, click on the "Go to page 1" button, now page 1 will open and the title is shown as "page 1 data-title", ignoring the <title> tag even if it is present or not. Again Ajax transition. But not always !!!
  5. Now in the code, remove the data-title attribute for page 2, navigate to page 2, you will see the title shown as "H1 Header of Page 2". So if the data-title attribute is missing, the text from the header is picked up.
  6. Now in the code, remove the data-title attribute for page 1, navigate to page 1 from page 2, you will see the title again being shown from the <title> tag, if the <title> tag was not present, then the title is shown as "H1 Header of Page 1".
  7. Now in the code, remove the entire "header" div from page 2, and also remove the data-title from page 2, now if you navigate into page 2 from page 1, if page 1 had <title> then that text is shown as the page 2 title, if page 1 didn't have the <title> tag, then the current title of page 1 is carried to page 2.
One could add a data-role="dialog" and view the same sort of behavior with dialogs. Dialogs also support data-title attribute. As per jQuery Mobile docs, even the headers (data-role="header") support the data-title attribute, but for some reason I just couldn't get it to work.

I feel point 6 above and the non working header data-title attributes are bugs in jQuery Mobile 1.0. Have to cross check further and log the same against jQuery Mobile.

5:30pm Updated:
For point 6 above: It is working as expected and not a bug. The internal implementation of jQuery mobile is that, the multiple pages are loaded and stacked, when a specific page link is clicked, jQuery Mobile gets that specific internal page and transition it into view. Here, page 1 was already available with document.title set to Main Page, so the same was shown in spite of Ajax navigation. If the <title> tag was not present, then the header text is used.

I have now logged a bug against jQuery Mobile for the data-title attribute under the Header: https://github.com/jquery/jquery-mobile/issues/3259

Read the next part of this post on how these scenarios play out in a single-page template.

Monday, October 31, 2011

autofocus to multiple controls in HTML5

The HTML5 spec says:

There must not be more than one element in the document with the autofocus attribute specified.



Excellent, so what happens if you set multiple elements with the autofocus attribute? And in various browsers? Results below ...


Autofocus not supported:


IE9 


First Element gets the focus:


IE 10 preview, FF


The last element gets the focus:


Chrome, Opera, Safari

Though its up to the User Agents to implement the behavior, I prefer the Webkit implementation of this feature compared to that of Mozilla and Trident. 


Why? 


HTML5 says that browsers should gracefully degrade. They should try to render whatever possible. Not being strict that is. So if a browser stops with the first autofocus, one will never know if there were more than one autofocus elements in the document. But, if the browser renders and sets every autofocus as it parses the document, thus stopping at the last autofocus, the developer will immediately know something is amiss and correct/remove the unwanted autofocus. An added advantage one can thus get with webkit.