How to make Keyboard navigation left/up/right/down (like for photo gallery) feature for jQuery Tabs with history? Demo without keyboard feature in http://dl.dropbox.com/u/6594481/tabs/index.html
Needed functions:
- on keyboard
top/downmake select and CSS showactivenested ajax tabs from 1-st to last level - on keyboard
left/rightchangeback/forwardcontent ofactivenested ajax tabs tab - an extra option, make
activenested ajax tab on ‘cursor-on’ on concrete nested ajax tabs level
Read more detailed question with example pictures in https://stackoverflow.com/questions/2975003/jquery-tools-to-make-keyboard-and-cookies-feature-for-ajaxed-tabs-with-history
/**
* @license
* jQuery Tools @VERSION Tabs- The basics of UI design.
*
* NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.
*
* http://flowplayer.org/tools/tabs/
*
* Since: November 2008
* Date: @DATE
*/
(function($) {
// static constructs
$.tools = $.tools || {version: '@VERSION'};
$.tools.tabs = {
conf: {
tabs: 'a',
current: 'current',
onBeforeClick: null,
onClick: null,
effect: 'default',
initialIndex: 0,
event: 'click',
rotate: false,
// 1.2
history: false
},
addEffect: function(name, fn) {
effects[name] = fn;
}
};
var effects = {
// simple "toggle" effect
'default': function(i, done) {
this.getPanes().hide().eq(i).show();
done.call();
},
/*
configuration:
- fadeOutSpeed (positive value does "crossfading")
- fadeInSpeed
*/
fade: function(i, done) {
var conf = this.getConf(),
speed = conf.fadeOutSpeed,
panes = this.getPanes();
if (speed) {
panes.fadeOut(speed);
} else {
panes.hide();
}
panes.eq(i).fadeIn(conf.fadeInSpeed, done);
},
// for basic accordions
slide: function(i, done) {
this.getPanes().slideUp(200);
this.getPanes().eq(i).slideDown(400, done);
},
/**
* AJAX effect
*/
ajax: function(i, done) {
this.getPanes().eq(0).load(this.getTabs().eq(i).attr("href"), done);
}
};
var w;
/**
* Horizontal accordion
*
* @deprecated will be replaced with a more robust implementation
*/
$.tools.tabs.addEffect("horizontal", function(i, done) {
// store original width of a pane into memory
if (!w) { w = this.getPanes().eq(0).width(); }
// set current pane's width to zero
this.getCurrentPane().animate({width: 0}, function() { $(this).hide(); });
// grow opened pane to it's original width
this.getPanes().eq(i).animate({width: w}, function() {
$(this).show();
done.call();
});
});
function Tabs(root, paneSelector, conf) {
var self = this,
trigger = root.add(this),
tabs = root.find(conf.tabs),
panes = paneSelector.jquery ? paneSelector : root.children(paneSelector),
current;
// make sure tabs and panes are found
if (!tabs.length) { tabs = root.children(); }
if (!panes.length) { panes = root.parent().find(paneSelector); }
if (!panes.length) { panes = $(paneSelector); }
// public methods
$.extend(this, {
click: function(i, e) {
var tab = tabs.eq(i);
if (typeof i == 'string' && i.replace("#", "")) {
tab = tabs.filter("[href*=" + i.replace("#", "") + "]");
i = Math.max(tabs.index(tab), 0);
}
if (conf.rotate) {
var last = tabs.length -1;
if (i < 0) { return self.click(last, e); }
if (i > last) { return self.click(0, e); }
}
if (!tab.length) {
if (current >= 0) { return self; }
i = conf.initialIndex;
tab = tabs.eq(i);
}
// current tab is being clicked
if (i === current) { return self; }
// possibility to cancel click action
e = e || $.Event();
e.type = "onBeforeClick";
trigger.trigger(e, [i]);
if (e.isDefaultPrevented()) { return; }
// call the effect
effects[conf.effect].call(self, i, function() {
// onClick callback
e.type = "onClick";
trigger.trigger(e, [i]);
});
// default behaviour
current = i;
tabs.removeClass(conf.current);
tab.addClass(conf.current);
return self;
},
getConf: function() {
return conf;
},
getTabs: function() {
return tabs;
},
getPanes: function() {
return panes;
},
getCurrentPane: function() {
return panes.eq(current);
},
getCurrentTab: function() {
return tabs.eq(current);
},
getIndex: function() {
return current;
},
next: function() {
return self.click(current + 1);
},
prev: function() {
return self.click(current - 1);
}
});
// callbacks
$.each("onBeforeClick,onClick".split(","), function(i, name) {
// configuration
if ($.isFunction(conf[name])) {
$(self).bind(name, conf[name]);
}
// API
self[name] = function(fn) {
$(self).bind(name, fn);
return self;
};
});
if (conf.history && $.fn.history) {
$.tools.history.init(tabs);
conf.event = 'history';
}
// setup click actions for each tab
tabs.each(function(i) {
$(this).bind(conf.event, function(e) {
self.click(i, e);
return e.preventDefault();
});
});
// cross tab anchor link
panes.find("a[href^=#]").click(function(e) {
self.click($(this).attr("href"), e);
});
// open initial tab
if (location.hash) {
self.click(location.hash);
} else {
if (conf.initialIndex === 0 || conf.initialIndex > 0) {
self.click(conf.initialIndex);
}
}
}
// jQuery plugin implementation
$.fn.tabs = function(paneSelector, conf) {
// return existing instance
var el = this.data("tabs");
if (el) { return el; }
if ($.isFunction(conf)) {
conf = {onBeforeClick: conf};
}
// setup conf
conf = $.extend({}, $.tools.tabs.conf, conf);
this.each(function() {
el = new Tabs($(this), paneSelector, conf);
$(this).data("tabs", el);
});
return conf.api ? el: this;
};
}) (jQuery);
/**
* @license
* jQuery Tools @VERSION History "Back button for AJAX apps"
*
* NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.
*
* http://flowplayer.org/tools/toolbox/history.html
*
* Since: Mar 2010
* Date: @DATE
*/
(function($) {
var hash, iframe, links, inited;
$.tools = $.tools || {version: '@VERSION'};
$.tools.history = {
init: function(els) {
if (inited) { return; }
// IE
if ($.browser.msie && $.browser.version < '8') {
// create iframe that is constantly checked for hash changes
if (!iframe) {
iframe = $("<iframe/>").attr("src", "javascript:false;").hide().get(0);
$("body").append(iframe);
setInterval(function() {
var idoc = iframe.contentWindow.document,
h = idoc.location.hash;
if (hash !== h) {
$.event.trigger("hash", h);
}
}, 100);
setIframeLocation(location.hash || '#');
}
// other browsers scans for location.hash changes directly without iframe hack
} else {
setInterval(function() {
var h = location.hash;
if (h !== hash) {
$.event.trigger("hash", h);
}
}, 100);
}
links = !links ? els : links.add(els);
els.click(function(e) {
var href = $(this).attr("href");
if (iframe) { setIframeLocation(href); }
// handle non-anchor links
if (href.slice(0, 1) != "#") {
location.href = "#" + href;
return e.preventDefault();
}
});
inited = true;
}
};
function setIframeLocation(h) {
if (h) {
var doc = iframe.contentWindow.document;
doc.open().close();
doc.location.hash = h;
}
}
// global histroy change listener
$(window).bind("hash", function(e, h) {
if (h) {
links.filter(function() {
var href = $(this).attr("href");
return href == h || href == h.replace("#", "");
}).trigger("history", [h]);
} else {
links.eq(0).trigger("history", [h]);
}
hash = h;
window.location.hash = hash;
});
// jQuery plugin implementation
$.fn.history = function(fn) {
$.tools.history.init(this);
// return jQuery
return this.bind("history", fn);
};
})(jQuery);
$(function() {
$("#list").tabs("#content > div", {effect: 'ajax', history: true});
});
Here is how I would add the keyboard functionality to your code.
But, I want to add that after looking at pretty much the same question you posted two days prior to this one, that this site is set up to help you find problems in your code, not to write it all for you. If you want someone to write all the code, hire someone to do it or you’ll probably have to learn how to do it yourself (with troubleshooting help from us as needed).
Anyway, I set up this demo to help you get started. Hopefully there are enough comments that you can understand what I was doing and you can take it from there.