0

I've read this answer here Guide for writing arrowkey navigation on focusable elements? but its not elaborate enough for a newbie like me to understand.

I need something on the lines like that, I have a 4x4 grid with divs in my DOM. I want to be able to move around a selector and then be able to select focused div with enter.

Edit: Pasted some code,

This is what I was trying when I realized I was on the total wrong track:

function arrowKeys(input){
    var keyCode = input.keyCode;
    var border = document.getElementById(keyid);
    var removeBorder = border.removeAttribute("style");

    if(keyCode == 38 || keyCode == 39 || keyCode == 40 || keyCode == 37){
        var addborder = border.setAttribute("style", "border:2px solid red");
        border.addborder;
        if(keyCode == 38){
            removeBorder;
            keyid = keyid - 4;
            border.addborder;
            console.log(keyid + " upp");
        }
        if (keyCode == 39){
            removeBorder;
            keyid++;
            border.addborder;
            console.log(keyid + " right");
        }
        if(keyCode == 40){      // right arrowkey
            removeBorder;   
            keyid = keyid + 4;
            border.addborder;
            console.log(keyid + " down");
        }
        if (keyCode == 37){     // left arrowkey
            removeBorder;
            keyid--;
            border.addborder;
            console.log(keyid + " left");
        }
    }
}

I figured you need to use an array something on the lines like this,

var navigationMap = [[1,2,3,4][5,6,7,8][9,10,11,12][13,14,15,16]];

But there Im stuck what so ever..

Community
  • 1
  • 1
Camathon
  • 514
  • 2
  • 5
  • 22
  • Show the HTML you want to navigate. – jfriend00 Mar 27 '13 at 23:14
  • If you're a beginner, I really don't think this is a problem that should be tackled out of the gate. There are a LOT of things you need to learn before doing so. The first is key-events (`.onkeydown`, `.onkeyup`) or just event-handling in general. Next, you have DOM traversal and CSS manipulation with JavaScript... Then, you have either event-creation or a requirement to write a program (object-oriented or component-oriented or anything else) to keep track of what divs you want, and any custom-events you need... There's a LOT that goes into making something like this work well. – Norguard Mar 27 '13 at 23:15
  • @jfriend00 Its a memory, and the divs being created with javascript. – Camathon Mar 27 '13 at 23:21
  • @Norguard Part of the challenge of being a beginner is to learn new things imo :-) I suppose I forgot to mention I have a DOM setup with CSS I "just" want to add arrow-key navigation to navigate and select my memory cards! – Camathon Mar 27 '13 at 23:22
  • @Cammy I totally agree that it's to learn new things, and it's good to have projects in mind. But your code above sort of illustrates my point: it's really not bad, and you're really not on the wrong track, necessarily... ...but you're working with a lot of different ideas (input, what that input means, how to turn that into action, how to show the user the result of that action, and how to store your items), and you're trying to do it all within a single step. So bugs in one, or a misunderstanding of one, is going to create a roadblock for all of them. Breaking it into pieces should help. – Norguard Mar 27 '13 at 23:30
  • @Cammy What is the document-structure that you're navigating? Is it just flat (ie: all `
    ` elements are side-by-side)?
    – Norguard Mar 27 '13 at 23:32
  • @Norguard Somehow it makes me really happy that you fully understand my problem, and I couldnt have said it better myself. I know I might be trying too much but I sorta have to! This is what it looks like atm http://dl.dropbox.com/u/135732603/Memory/Index.html – Camathon Mar 27 '13 at 23:40
  • @Cammy if all of this other stuff is yours, you're off to a good start. I'll see what I can do to give you a helping hand. My first thought is "why not make each card a little bit more intelligent?". – Norguard Mar 27 '13 at 23:58
  • @Norguard It is indeed, I made sure the memory works correct without bugs first before trying to add this function.. Intelligent cards, hmm – Camathon Mar 28 '13 at 00:23
  • @Cammy - honestly, we can't help if we don't know the structure the elements you're trying to navigate. It doesn't matter if the DOM elements are created dynamically or via static HTML. We need to know what the DOM structure of your grid is in order to know how to figure out which element is right/left or up/down from the current one. – jfriend00 Mar 28 '13 at 00:48
  • @jfriend00 Yes I understand that :P I linked my code here: dl.dropbox.com/u/135732603/Memory/Index.html – Camathon Mar 28 '13 at 01:04
  • @Cammy - hey, did you see that I wrote a working solution for you in my answer, complete with a working jsFiddle? – jfriend00 Mar 29 '13 at 03:22

2 Answers2

1

Here's a way to do this using plain javascript. The first part of the code is some cross browser functions to add event handlers and add/remove classes. You'll notice that I add/remove a class to show the active item rather than directly adding/removing a style. This puts the style in the CSS rather than in the javascript which is generally a good idea.

Working demo: http://jsfiddle.net/jfriend00/yMMxX/

(function() {
    // refined add event cross browser
    function addEvent(elem, event, fn) {
        if (typeof elem === "string") {
            elem = document.getElementById(elem);
        }

        // avoid memory overhead of new anonymous functions for every event handler that's installed
        // by using local functions
        function listenHandler(e) {
            var ret = fn.apply(this, arguments);
            if (ret === false) {
                e.stopPropagation();
                e.preventDefault();
            }
            return(ret);
        }

        function attachHandler() {
            // set the this pointer same as addEventListener when fn is called
            // and make sure the event is passed to the fn also so that works the same too
            var ret = fn.call(elem, window.event);   
            if (ret === false) {
                window.event.returnValue = false;
                window.event.cancelBubble = true;
            }
            return(ret);
        }

        if (elem.addEventListener) {
            elem.addEventListener(event, listenHandler, false);
        } else {
            elem.attachEvent("on" + event, attachHandler);
        }
    }



    function addClass(elem, cls) {
        var oldCls = elem.className;
        if (oldCls) {
            oldCls += " ";
        }
        elem.className = oldCls + cls;
    }

    function removeClass(elem, cls) {
        var str = " " + elem.className + " ";
        elem.className = str.replace(" " + cls + " ", " ").replace(/^\s+|\s+$/g, "");
    }


    function findItem(items, target) {
        for (var i = 0; i < items.length; i++) {
            if (items[i] === target) {
                return(i);
            }
        }
        return(-1);
    }

    var keys = {up: 38, down: 40, left: 37, right: 39};
    var cards = document.getElementById("game-board").getElementsByClassName("card");
    addEvent(document, "keydown", function(e) { 
        // get key press in cross browser way
        var code = e.which || e.keyCode;
        // number of items across
        var width = 4;
        var increment, index, newIndex, active;

        switch(code) {
            case keys.up:
                increment = -width;
                break;
            case keys.down:
                increment = width;
                break;
            case keys.left:
                increment = -1;
                break;
            case keys.right:
                increment = 1;
                break;
            default:
                increment = 0;
                break;
        }
        if (increment !== 0) {
            active = document.getElementById("game-board").getElementsByClassName("active")[0];
            index = findItem(cards, active);
            newIndex = index + increment;
            if (newIndex >= 0 && newIndex < cards.length) {
                removeClass(active, "active");
                addClass(cards[newIndex], "active");
            }
            // prevent default handling of up, down, left, right keys
            return false;
        }
    });
})();
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Sorry, I've been afk over easter :) (happy late easter to you btw!) Its a nice solution, nothing I would have come up with on my own being a beginner. Ill point out the things I dont know; .apply, stopPropagation(); and preventDefault();, call, cancelBubble, well here i started realsing its alot, also this is strange to me ".replace(/^\s+|\s+$/g, "");". However I thank you alot :) and will studdy this untill I understand fully whats going on! – Camathon Apr 01 '13 at 15:11
0

i've done this with jQuery. You can wire up to the event with something like this:

  $(".some-css-class-on-your-divs").keydown(function (e)
  {
    HandleKeyDown(e, $(this));
  })

then handle the event with another javascript method

function HandleKeyDown(event, jqNode)
{
  event = event || window.event;
  var charCode = event.charCode || event.keyCode;


  if (charCode == 40)
  { // down arrow key
      ///  do your thing here
  }
   // charcode 38 is up, and so on
}
Doug
  • 642
  • 1
  • 4
  • 14
  • I would do this with jQuery, but for this assignment Im only allowed to use vanilla javascript. I'll try to tweek it though :-) thanks! – Camathon Mar 27 '13 at 23:29