1

J'ai une liste de tous div avec un ensemble et égale hauteur/largeur qui sont float:left de sorte qu'ils sont assis côte à côte et se replient si ce parent est plus petit que le combiné avec des éléments.Navigation au clavier haut/bas/gauche/droite avec jQuery?

Assez standard. est de créer une liste des icônes bootstrap twitter, il donne quelque chose comme ceci: enter image description here

J'ai ajouté la navigation au clavier suivant/précédent en utilisant le code ci-dessous, mais vous remarquerez que les touches fléchées haut/bas sont mappé pour appeler les fonctions gauche/droite. Qu'est-ce que je ne sais pas comment faire est de faire la navigation haut/bas?

JsFiddle

(function ($) { 
    $.widget("ui.iconSelect", { 

     // default options 
     options: { 

     }, 

     $select: null, 

     $wrapper: null, 

     $list: null, 

     $filter: null, 

     $active: null, 

     icons: {}, 

     keys: { 
      left: 37, 
      up: 38, 
      right: 39, 
      down: 40 

     }, 

     //initialization function 
     _create: function() { 

      var that = this; 
      that.$select = that.element; 

      that.$wrapper = $('<div class="select-icon" tabindex="0"></div>'); 
      that.$filter = $('<input class="span12" tabindex="-1" placeholder="Filter by class name..."/>').appendTo(that.$wrapper); 
      that.$list = $('<div class="select-icon-list"></div>').appendTo(that.$wrapper); 


      //build the list of icons 
      that.element.find('option').each(function() { 
       var $option = $(this); 
       var icon = $option.val(); 

       that.icons[icon] = $('<a data-class="' + icon + '"><i class="icon ' + icon + '"></i></a>'); 

       if ($option.is(':selected')) { 
        that.icons[icon].addClass('selected active'); 
       } 

       that.$list.append(that.icons[icon]); 
      }); 

      that.$wrapper.insertBefore(that.$select); 
      that.$select.addClass('hide'); 



      that._setupArrowKeysHandler(); 
      that._setupClickHandler(); 
      that._setupFilter(); 
      that.focus('selected'); 
     }, 

     focus: function (type) { 
      var that = this; 
      if (that.$active === null || that.$active.length == 0) { 
       if (type == 'first') { 
        that.$active = that.$list.find('a:visible:first'); 
       } else if (type == 'last') { 
        that.$active = that.$list.find('a:visible:last'); 
       } else if (type == 'selected') { 
        that.$active = that.$list.find('a.selected:visible:first'); 
        that.focus('first'); 
       } 
      } 
      that.$active.addClass('active'); 
      var toScroll = ((that.$list.scrollTop() + that.$active.position().top)-that.$list.height()/2)+that.$active.height()/2; 
      //that.$list.scrollTop((that.$list.scrollTop() + top)-that.$list.height()/2); 
      that.$list.stop(true).animate({ 
       scrollTop: toScroll, 
       queue: false, 
       easing: 'linear' 
      }, 200); 

      if (type === 'selected') { 
       return false; 
      } 

      that.$select.val(that.$active.data('class')); 
      that.$select.trigger('change'); 

     }, 

     _setupArrowKeysHandler: function() { 
      var that = this; 

      that.$wrapper.on('keydown', function (e) { 
       switch (e.which) { 
        case that.keys.left: 
         that.moveLeft(); 
         break; 
        case that.keys.up: 
         that.moveUp(); 
         break; 
        case that.keys.right: 
         that.moveRight(); 
         break; 
        case that.keys.down: 
         that.moveDown(); 
         break; 
        case 16: 
         return true; 
        case 9: 
         return true; 
        break; 
        default: 
         that.$filter.focus(); 
         return true; 
       } 
       return false; 
      }); 
     }, 

     _setupFilter: function(){ 
      var that = this; 

      that.$filter.on('keydown keyup keypress paste cut change', function(e){ 
       that.filter(that.$filter.val()); 
      }); 
     }, 

     _setupClickHandler: function() { 
      var that = this; 
      that.$list.on('click', 'a', function() { 
       that.$wrapper.focus(); 
       that.$active.removeClass('active'); 
       that.$active = $(this); 
       that.focus('first'); 
      }); 
     }, 

     moveUp: function() { 
      var that = this; 
      return that.moveLeft(); 
     }, 

     moveDown: function() { 
      var that = this; 
      return that.moveRight(); 
     }, 

     moveLeft: function() { 
      var that = this; 
      that.$active.removeClass('active'); 
      that.$active = that.$active.prevAll(':visible:first'); 
      that.focus('last'); 
      return false; 
     }, 

     moveRight: function() { 
      var that = this; 
      that.$active.removeClass('active'); 
      that.$active = that.$active.nextAll(':visible:first'); 
      that.focus('first'); 
      return false; 
     }, 

     filter: function(word){ 
      var that = this; 
      var regexp = new RegExp(word.toLowerCase()); 
      var found = false; 
      $.each(that.icons, function(i, $v){ 
       found = regexp.test(i); 
       if(found && !$v.is(':visible')){ 
        $v.show(); 
       } else if(!found && $v.is(':visible')){ 
        $v.hide(); 
       } 
      }); 
     } 

    }); 
})(jQuery); 
+0

vous pouvez appeler la fonction gauche/droite aussi souvent que de nombreux éléments sont dans chaque rangée - serait le plus facile sans même jeter un oeil à votre code;) Je vais le faire maintenant ... – luk2302

+0

@ luk2302, Solution possible oui , mais comment comptez-vous combien d'éléments sont dans la rangée? Je suppose que je pourrais faire '$ wrapper.width() mod $ element.width()' mais l'approche globale me semble plutôt hacky. J'ai regardé dans http://www.zehnet.de/2010/11/19/document-elementfrompoint-a-jquery-solution/ mais je ne peux pas savoir comment faire le point par rapport à l'emballage ... – Hailwood

+0

Quel est le problème avec l'utilisation du code que vous avez fourni dans le lien. Si vous collez simplement le code et ajoutez le vôtre, cela devrait fonctionner: vous pouvez obtenir l'élément ci-dessus via '$ .elementFromPoint ($ (ce. $ actif) .offset(). left, $ (that. $ active) .offset() .top-10); Pour le dessous, il faudrait ajouter 10 + la hauteur d'un objet lui-même, mais c'est corrigé. Je ne sais pas comment changer l'attribut actif dans votre code, donc je ne fournis pas de réponse, juste un commentaire. – luk2302

Répondre

2

Peut-être quelque chose comme ceci: http://jsfiddle.net/QFzCY/

var blocksPerRow = 4; 

$("body").on("keydown", function(e){ 
    var thisIndex = $(".selected").index(); 
    var newIndex = null; 
    if(e.keyCode === 38) { 
     // up 
     newIndex = thisIndex - blocksPerRow; 
    } 
    else if(e.keyCode === 40) { 
     // down 
     newIndex = thisIndex + blocksPerRow;  
    } 
    if(newIndex !== null) { 
     $(".test").eq(newIndex).addClass("selected").siblings().removeClass("selected"); 
    }  
}); 

Fondamentalement, vous définissez le nombre d'éléments, il y a une ligne, puis trouver l'indice actuel et soustraient ou ajouter ce montant à sélectionnez l'élément suivant via le nouvel index.

Si vous avez besoin de savoir combien de blocs par ligne il y a, vous pouvez le faire:

var offset = null; 
var blocksPerRow = 0; 
$(".test").each(function(){ 
    if(offset === null) { 
     offset = $(this).offset().top; 
    } 
    else if($(this).offset().top !== offset) { 
     return false; 
    } 
    blocksPerRow++; 
}); 

Pour traiter vos cas de « bord », vous pouvez faire:

if(newIndex >= $(".test").length) { 
    newIndex = $(".test").length - newIndex; 
} 
+0

Cela semble bon, mais comment traiteriez-vous les cas de bord «littéralement», aka, si l'utilisateur est sur la ligne du bas, et appuie, nous voulons sélectionner l'élément relatif sur la ligne supérieure, et même pour monter ? – Hailwood

+0

Réponse mise à jour avec votre cas 'edge'. – mibbler

+0

Un cas de bord supplémentaire, comme vous pouvez le voir dans la démo, nous avons aussi une boîte de filtre, donc si l'utilisateur a filtré les éléments, nous devons exclure ceux-ci ... – Hailwood

1
moveUp: function() { 
     var that = this; 
     var index = $(this).index(); 
     var containerWidth = parseInt($('.select-icon-list').innerWidth(), 10); 
     var iconWidth = parseInt($('.select-icon-list > a').width(), 10); 
     var noOfCols = Math.floor(containerWidth/iconWidth); 
     var newIndex = ((index - noOfCols) < 0) ? index : (index - noOfCols); 
     var elem = $('.select-icon-list > a')[index]; 
    }, 

Cache tout ce qui reste statique.

+0

Cela semble bon, mais comment traiteriez-vous les cas de bord «littéralement», aka, si l'utilisateur est sur la ligne du bas, et appuie, nous voulons sélectionner l'élément relatif sur la ligne supérieure, et même pour monter ? – Hailwood

+0

Je ne fais que prévenir de tels cas de bord avec '((index - noOfCols) <0)? index: (index - noOfCols) 'et restent sur le même élément. – sabithpocker

Questions connexes