views:

125

answers:

4

I have made my own custom tabbed content script and it works great. The only thing missing is being able to book mark different sections.

I know the URL needs re-writing somehow. At the moment I am using preventDefault to stop the page refreshing, this also stops the URL from changing.

I have also tried manually re-writing the URL but nothing happens as I guess it needs some form of hooks to detect the entered URL.

Thanks in advance, Henry.

EDIT: Javascript: http://pastebin.com/1yhzxkUi HTML: http://pastebin.com/WH1CbRZJ

+2  A: 

If you're talking about changing the URL to suit AJAX operations on the page, then I'm doing a similar thing at the moment.

Have a look at http://www.asual.com/jquery/address/

It's a plugin for jQuery and is useful to keep the address navigation buttons working when you change tabs, etc (or, you can just change the URL without affecting the history).

It has events to hook into for when the URL changes externally (i.e. someone pasting the address) or internally. Then you can pick up the values from the parameters and update accordingly.

A simple usage example:

// Sets the tabId
$.address.parameter("tabId", tabId);

// Sets up the event to catch the URL parameter
$.address.externalChange(function(event) {
    var tabId = $.address.parameter("tabId");

    if(tabId){
        $("#tab" + tabId).show();
    }
});
Jonathon
That's pretty much exactly what I need. The tabs example changes the URL and allows next/prev buttons to work. I need to incorporate this into my tabs.My tabs are not using Ajax by the way, they just show/hide content within an unordered list.Thanks =]
Henryz
I've added an example to show how to use it. The content doesn't have to be loaded by AJAX, you just do what you want within the 'externalChange' event handler.
Jonathon
A: 

You can always check this plugin: jQuery BBQ (Back Button & Querry) to add a #hash to be bookmarked, like Facebook do.

Isern Palaus
+1  A: 

To store the history of a page, the most popular and full featured/supported way is using hashchanges. This means that say you go from yoursite/page.html#page1 to yoursite/page.html#page2 you can track that change, and because we are using hashes it can be picked up by bookmarks and back and forward buttons.

You can find a great way to bind to hash changes using the jQuery History project http://www.balupton.com/projects/jquery-history

There is also a full featured AJAX extension for it, allowing you to easily integrate Ajax requests to your states/hashes to transform your website into a full featured Web 2.0 Application: http://www.balupton.com/projects/jquery-ajaxy

They both provide great documentation on their demo pages to explain what is happening and what is going on.

Here is an example of using jQuery History (as taken from the demo site):

// Bind a handler for ALL hash/state changes
$.History.bind(function(state){
    // Update the current element to indicate which state we are now on
    $current.text('Our current state is: ['+state+']');
    // Update the page"s title with our current state on the end
    document.title = document_title + ' | ' + state;
});

// Bind a handler for state: apricots
$.History.bind('/apricots',function(state){
    // Update Menu
    updateMenu(state);
    // Show apricots tab, hide the other tabs
    $tabs.hide();
    $apricots.stop(true,true).fadeIn(200);
});

And an example of jQuery Ajaxy (as taken from the demo site):

        'page': {
            selector: '.ajaxy-page',
            matches: /^\/pages\/?/,
            request: function(){
                // Log what is happening
                window.console.debug('$.Ajaxy.configure.Controllers.page.request', [this,arguments]);
                // Adjust Menu
                $menu.children('.active').removeClass('active');
                // Hide Content
                $content.stop(true,true).fadeOut(400);
                // Return true
                return true;
            },
            response: function(){
                // Prepare
                var Ajaxy = $.Ajaxy; var data = this.State.Response.data; var state = this.state;
                // Log what is happening
                window.console.debug('$.Ajaxy.configure.Controllers.page.response', [this,arguments], data, state);
                // Adjust Menu
                $menu.children(':has(a[href*="'+state+'"])').addClass('active').siblings('.active').removeClass('active');
                // Show Content
                var Action = this;
                $content.html(data.content).fadeIn(400,function(){
                    Action.documentReady($content);
                });
                // Return true
                return true;

And if you ever want to get the querystring params (so yoursite/page.html#page1?a.b=1&a.c=2) you can just use:

$.History.bind(function(state){
    var params = state.queryStringToJSON(); // would give you back {a:{b:1,c:2}}
}

So check out those demo links to see them in action, and for all installation and usage details.


Edit: After seeing your code, this is all you would have to do to use it with jQuery History.

Change:

$('.tabbed_content .tabs li a').live('click',
    function (e){
        e.preventDefault();
        switchTab($(this));
    });

To:

// Bind a handler for ALL hash/state changes
$.History.bind(function(state){
    switchTab(state);
});

Or if you plan to use jQuery History for other areas too, then we would want to ensure that we only call switchTab for our tabs and not all hashes:

// Bind a handler for ALL hash/state changes
$.History.bind(function(state){
    if ( $('.tabbed_content > .content > li[id='+state+']').length ) switchTab(state);
});

We no longer use a onclick event, instead we bind to jQuery History as that will detect the hashchange. This is the most important concept to understand, as for instance if we bookmark the site then go back to it, we never clicked it. So instead we change our clicks to bind to the hashchange. As when we click it, bookmark it, back or forward, the hashchange will always fire :-)

balupton
Hi Balupton, thanks for taking the time to help me with my problem. I am using the suggested method above and it changes my URL and allows me to use the prev/next buttons but it breaks the tabs.Instead of passing 'this' as a parameter I using 'state', this seems to break it.Sorry if that sounds a bit novice, I only started jQuery a week ago.Thanks, Henry.
Henryz
Hey mate, can you post your updated code or a link to a live copy? Furthermore you can add me on Skype (username balupton) and we can debug in real time :-)
balupton
Oh I see where your problem is. Change `strTarget = $(objClickedTab).attr('href');` to `strTarget = $('#'+objClickedTab).attr('href');`
balupton
A: 

Using hash links allows for bookmarkable/sharable links to trigger JavaScript code, instead of reloading the page. Ben Almans jQuery hashchange event allows you to bind an event handler to the hashchange event, this plugin works with older browsers that don't support this normally. An event handler bound to hashchange can read the hash part of the url, and call any function.

// register event handler
function bindHashchange() {

    $(window).bind('hashchange', function(event) {
        event.preventDefault();
        var label = location.hash.substring(1);
        handleLabel(label);
    });

    // trigger event so handler will be run when page is opened first time
    // otherwise handler will only run when clicking on hash links
    $(window).trigger('hashchange');
}

// read and handle hash part of url
function handleLabel(label) {

    if ( label.length > 0 ) {
        // using label from url
        switchPage(label);
    } else {
        // use the default label, if no hash link was present
        switchPage('start');
    }
}

// in this case, load hidden <div>'s into a <div id="content">
function switchPage(label) {
    if ( label == 'start ) {
        $('div#content').html($('div#start'));
    } else if ( label == 'some_other_page' ) {
        // do something else
    }
}

This other event handler can process 2 arguments separated by a dot ('.') in the same url.

function processHash() {

    var str = location.hash.substring(1);
    var pos = $.inArray('.', str);

    var label = '';
    var arg = '';

    if ( pos > -1 ) {
        label = str.substring(0, pos);
    } else {
        label = str.substring(0);
    }

    if ( pos > 1 ) {
        arg = str.substring(pos+1);
    }

    if ( label.length == 0 ) {
        // the default page to open of label is empty
        loadContent('start');
    } else {
        // load page, and pass an argument
        loadContent(label, arg);
    }
}

If regular expressions are used, any combination of characters can be parsed.

var registry = {};

// split on character '.'
var args = label.split(/\./g);

for ( i in args ) {
    var arg = args[i];

    // split on character '='
    var temp = arg.split('=');
    var name = temp[0];
    var value = temp[1];

    // store argument in registry
    registry[name] = value;
}
// registry is loaded, ready to run application that depends on arguments

This will transform the url:

mysite/#company.page=items.color=red

Into the following JavaScript Object:

Object { company=undefined, page="items", color="red"}

Then it is only a matter of running jQuery's show() or hide() functions on your selected elements.

This could be transformed into non-jQuery JavaScript, but then you would lose the functionality that Ben Alman delivers, which is crucial for a portable solution.

thnee