--- admin_menu.js 2008-09-09 01:02:26.000000000 +0200 +++ /Volumes/www-1/php/drupal-6.6/sites/all/modules/admin_menu/admin_menu.js 2008-11-08 20:00:27.000000000 +0100 @@ -35,4 +35,129 @@ $(document).ready(function() { uls.css({left: '-999em', display: 'none'}); }, 400); }); + + (function(){ + + var adminMenu = jQuery("#admin-menu"); + + var tree = jQuery.map(adminMenu.find("> ul > li.expandable"), function(element, index){ + var _this = jQuery(element); + var tree = { + li: _this, + a: _this.find("> a") + }; + + var children; + if((children = _this.find("> ul > li")).length) { + tree.children = jQuery.map(children, arguments.callee); + } + return tree; + }); + + + (function (array, parent, parentIndex, level){ // create object parents + var level = level || 1; + for (var i = 0; i < array.length; i++){ + var object = array[i]; + object.level = level; + + if(object.children){ + arguments.callee(object.children, object, i, level+1); + } + + if(parent) object.parent = parent; + object.parentIndex = parentIndex || i; + object.index = i; + }; + })(tree); + + + var active = false; + var current; + + jQuery(document).bind("keydown", function(event) { + // is key left, top, right, down or escape is presed + if(!(event.keyCode == 37 || event.keyCode == 38 || event.keyCode == 39 || event.keyCode == 40 || event.keyCode == 27)) return true; + + // does this key activates or disables keyboard navigation + if(event.keyCode == 27) { + active = !active; + if(!active){ + adminMenu.find("li.expandable").trigger("mouseleave"); + current.li.removeClass("focused"); + current.a.blur(); + current = undefined; + return false; + } + } + if(!active) return false; + + // select first element on initialization + if(!current) current = tree[0]; + + // placeholder + var next; + + switch(event.keyCode){ + case 37: // key left presed + if(current.level == 1 && tree[current.parentIndex-1]) { // first level rules + next = tree[current.parentIndex-1]; + } else if(current.level > 2){ // third+ levels rules + next = current.parent; + } else { // second level rules + next = tree[current.parent.parentIndex-1]; + } + break; + + case 38: // key up presed + if(current.level == 1) { + next = current.children[current.children.length-1]; + } else if(!(current.level == 2 && current.index == 0)) { // first level rules + next = current.parent.children[current.index-1]; + } else if(current.level == 2 && current.index == 0){ + next = current.parent; + } + break; + + case 39: // key right presed + if(current.level == 1 && tree[current.parentIndex+1]) { // first level rules + next = tree[current.parentIndex+1]; + } else if (current.children){ + next = current.children[0]; + } else if(current.level == 2) { + next = tree[current.parent.parentIndex+1]; + } + break; + + case 40: // key down presed + if(current.level == 1 && tree[current.parentIndex].children) { // first level rules + next = tree[current.parentIndex].children[0]; + } else { + next = current.parent.children[current.index+1]; + } + break; + } + // fallback if next is not set + if(!next) next = current; + + current.li.removeClass("focused"); + + if((next.level < current.level) || (!next.children && next.level == current.level)) { + current.li.trigger("mouseleave"); + } + + next.li.addClass("focused"); + next.a.focus(); + next.li.trigger("mouseenter"); + + current = next; + + event.preventDefault(); + event.cancelBubble = true; + if (event.stopPropagation) event.stopPropagation(); + return false; + + }); + + })(); });