Keyboard navigation for jQuery tabs

How to make Keyboard left / up / right / down navigation (e.g. for photo galleries) a function for jQuery history tabs? Demo without keyboard function in http://dl.dropbox.com/u/6594481/tabs/index.html

Required Features:

  • on the top/down keyboard make a choice and CSS show active ajax sub tabs from 1st to last level
  • on the left/right keyboard, change back/forward contents of the tab of the tab of the active tab of the nested tabs ajax
  • an additional option, insert the active tab sub tab ajax on the "cursor-on" at a specific sub tab level ajax.

Read a more detailed question with sample images at 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 width to zero this.getCurrentPane().animate({width: 0}, function() { $(this).hide(); }); // grow opened pane to it 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}); });​ 
+1
source share
2 answers

This is how I would add keyboard functionality to your code.

But I want to add that after looking at about the same question that you posted two days before, this site is set up to help you find problems in your code, rather than writing everything for you. If you want someone to write all the code, hire someone to do this, or you may have to learn how to do it yourself (help us help if necessary).

Anyway, I created this demo to help you get started. Hopefully there are enough comments that you can understand what I'm doing, and you can take them from there.

 $(function() { var list = $('#list'), imgPerRow = -1, loop = true; // find first image y-offset to find the number of images per row var topOffset = list.find('img:eq(0)').offset().top, numTabs = list.find('a').length - 1, current, newCurrent; function changeTab(diff){ current = list.find('a.current').index(); newCurrent = (loop) ? (current + diff + numTabs + 1) % (numTabs + 1) : current + diff; if (loop) { if (newCurrent > numTabs) { newCurrent = 0; } if (newCurrent < 0) { newCurrent = numTabs; } } else { if (newCurrent > numTabs) { newCurrent = numTabs; } if (newCurrent < 0) { newCurrent = 0; } } // don't trigger change if tab hasn't changed (for non-looping mode) if (current != newCurrent) { list.find('a').eq(newCurrent).trigger('click'); // trigger click on tab } } list // set up tabs .tabs("#content > div", {effect: 'ajax', history: true}) // find number of images on first row .find('img').each(function(i){ if (imgPerRow < 0 && $(this).offset().top > topOffset ) { imgPerRow = i; } }); // Set up arrow keys // Set to document for demo, probably better to use #list in the final version. $(document).bind('keyup', function(e){ var key = e.which; if (key > 36 && key < 41) { if (key == 37) { changeTab(-1); } // Left if (key == 38) { changeTab(-imgPerRow); } // Up if (key == 39) { changeTab(+1); } // Right if (key == 40) { changeTab(+imgPerRow); } // Down e.preventDefault(); } }); // toggle looping through tabs $(':button').click(function(){ loop = !loop; $('#loopStatus').text(loop); }); }); 
+2
source

You can associate actions with keystrokes with

 $.keyup(function(e) { key = e.which; if (key == 37) //code for left arrow key { ... } }); 

A quick google search gave me this list of key codes: http://www.cambiaresearch.com/c4/702b8cd1-e5b0-42e6-83ac-25f0306e3e25/Javascript-Char-Codes-Key-Codes.aspx

0
source

Source: https://habr.com/ru/post/1312195/


All Articles