Making this blog work as an app on the iPhone (part 3)

The story so far (one, two) is that I’ve simplified the content of this blog for viewing on the iPhone, I’ve added code that recognizes when the phone’s orientation is changed from portrait to landscape (and vice versa), and I’ve added the necessary elements to the head element to indicate that this site can be viewed as a Web Clip. With the current state of play though, the moment you touch on a link, Safari fires up to display the page.

iPhoneTo change this behavior we’re going to make use of the basic structure of my markup. In essence within my body element I have two divs: one named header, the other wrapper. What I shall do is, in effect, fix up each and every anchor element within the wrapper div to load the wrapper div of the requested URL. The header div will remain the same and will not change in appearance. Of course, once I’ve loaded a new wrapper div, I’ll have to change each anchor element to fix up its click behavior, just as before.

That’s the basics, but there are a couple of wrinkles. If an href attribute points to a page outside of my domain I want the old behavior to apply (that is, the URL should be loaded by Safari, not by this Web Clip). The other one is how to get back to the Home page if I click on a link – the Safari chrome with its Back button has gone.

The first part then is the fix up code. This is actually pretty straightforward with jQuery.

  var fixupLinks = function () {
    $("#wrapper a").on("click", function (ev) {
      var url = ev.target.href,
          re = /blog\.boyet\.com/i;
      if (url && url.match(re)) {
        ev.preventDefault();
        loadPage(url, false);
      }
    });
  };

So we get all the anchor links inside the wrapper div and to each we add a click event handler. (I’m using the new jQuery on() syntax here for a change – available from 1.7 onwards – I prefer the way it reads.) The event handler grabs the href attribute from the target element (which is an anchor element, obviously), and then checks to see if it is for blog.boyet.com using an pretty standard “ignore case” regular expression. If it is, the default behavior of the event is suppressed and a new function is called (loadPage) to load the URL.

So, the fun stuff happens in loadPage(). Let’s see that one now.

  var loadPage = function (url, isHomePage) {
    window.scrollTo(0,0);
    $("#wrapper").load(url + " #wrapper", fixupLinks);
    if (!isHomePage) {
      $("#header").one("click", function (e) {
        loadPage("http://blog.boyet.com/", true);
      });
    }
  };

This is a bit more complicated, but not overly so. We see that the second parameter is a boolean indicating whether the URL for for the home page or not. The reason, as we’ll see, is that we don’t want to have “Back button” functionality for the home page (“You’re on the home page, click here to return to the home page” doesn’t sound too well planned). The first thing that happens is that we scroll the page to the top. If we didn’t do this, when we load the new div, we’ll remain at the same relative window position which might, after all, be half way down the page. The user would much more prefer to be positioned at the top of the page after clicking a link rather than half way down.

Next we make use of jQuery’s load() function to load the URL. This is called on the selector we wish to use as the recipient of the new page (hence the wrapper div). The load() function has some special behavior: if we follow the URL by a space and a selector (so “http://example.com/something.html #container”), jQuery will just load the contents of that selector from the URL. In essence, what this code says is “replace the contents of wrapper with the contents of wrapper from this other page”. (There is some secondary behavior here as well: any script blocks in the replacement markup are ignored – which is also what we would like.) The second parameter to load() is a function to execute once the content has been loaded: in our case we want to fix up the anchor elements in the same manner as before.

After that all happens, if the new content is not for the home page, we shall make the header div clickable. I’m using a “one shot” click event handler here (note the function name is one()) so that I don’t have to explicitly unbind the click event handler when it’s used (in an earlier version of the code I didn’t do this and the header got more and more click event handlers tacked on, so that in the end I was firing five or six click events every time I touched the header). The event handler loads the home page and so the whole header acts as the site’s Back button.

The final thing to tie it all up is to make sure fixupLinks() is called when the home page is initially displayed. It’s is a simple matter to add this to a jQuery document.ready() function.

Looks very nice now, I must say. Except…

There is still an issue. It’s fairly obvious once you think about it: the “Back” functionality I implemented is a misnomer since it’s more of a “Go to home page” function. So if I have a post that refers to another, clicking the header on the second post returns to the home page and not to the first post. Yuk. In the next installment I shall have to build a URL stack so that the Back button (and I’ll have to have a real button methinks) works as you’d expect.

Album cover for The Fame MonsterNow playing:
Lady Gaga - Dance In The Dark
(from The Fame Monster)


 


Loading similar posts...   Loading links to posts on similar topics...

No Responses

Feel free to add a comment...

Leave a response

Note: some MarkDown is allowed, but HTML is not. Expand to show what's available.

  •  Emphasize with italics: surround word with underscores _emphasis_
  •  Emphasize strongly: surround word with double-asterisks **strong**
  •  Link: surround text with square brackets, url with parentheses [text](url)
  •  Inline code: surround text with backticks `IEnumerable`
  •  Unordered list: start each line with an asterisk, space * an item
  •  Ordered list: start each line with a digit, period, space 1. an item
  •  Insert code block: start each line with four spaces
  •  Insert blockquote: start each line with right-angle-bracket, space > Now is the time...
Preview of response