7

I was asked to create a grid of squares, where each square may or may not contain a link and these links should be able to be moved about the grid.

I figured that draggable/droppable would be the way to go and it works fine, however, now we want to be able to have the draggables swap about if one is dropped on top of another. So it looks now like sortable would have been the way to go. However, sortable looks more like it's meant for lists whereas I haven't written it like a list.

Is there an easy way to make what I have so far work, or do I need to totally rewrite this using sortable? I'm new to javascript, it took me a while to get this far, and I'm not asking for code but I dread the thought of having to figure the whole thing out again! any opinions?

Here's a fiddle of my code: http://jsfiddle.net/kvVkT/

and the code:

html

<div id="gridcontainer">
    <div id="-2:-2" class="droppable occupied">
        <a href="" id ="508" class="bookmark draggable white" title="white" "target="_blank">1</a>
    </div>
    <div id="-2:-1" class="droppable">2</div>
    <div style="clear:both"></div>
    <div id="-2:0" class="droppable">3</div>
    <div id="-2:1" class="droppable occupied">
        <a href="" id ="567" class="bookmark draggable white" title="white" "target="_blank">4</a>
    </div>
    <div style="clear:both"></div>
</div>

css

#gridcontainer{position:relative;padding:25px;color:#ff0004;background:#ffffff;}
.droppable{width:65px; height:65px;float:left; margin:5px;background:#000000;}
.bookmark {float:left;width:65px; height:65px;display:block;position:absolute;}
.position{float:left;width:65px; height:65px;display:block;}
.position:hover{background-image:url(../img/tilehover.png);}
.bookmark.ui-draggable-dragging {-moz-box-shadow: 0 0 5px #d9d9d9; -webkit-box-shadow: 0 0 5px #d9d9d9; box-shadow: 0 0 5px #d9d9d9;}
.draggable{ background:#888888;}
[draggable] {
  -moz-user-select: none;
  -khtml-user-select: none;
  -webkit-user-select: none;
  user-select: none;
}

javascript

$('.draggable').draggable({ start: function() {$('#dropdownAddTile').slideDown();},  stop: function() {$('#dropdownAddTile').slideUp();}, containment: '#container', snap:'.droppable', snapMode:'inner', revert:'invalid',snapTolerance: 32});
$('.droppable').droppable({drop: handleDropEvent, accept: function(e){if(e.hasClass('draggable')) { if (!$(this).hasClass('occupied')) {return true; }}}});
function handleDropEvent( event, ui ) {
      event.preventDefault();
      var draggable = ui.draggable;
      var droppable = $(this);
      var droppableId = $(this).attr("id");
      var draggableId = ui.draggable.attr("id");
      $('.draggable').draggable({containment: '#container', snap:'.droppable', snapMode:'inner', revert:'invalid',snapTolerance: 32});
      $('.droppable').droppable({drop: handleDropEvent, accept: function(e){if(e.hasClass('draggable')) { if (!$(this).hasClass('occupied')) {return true; }}}});
      var initPosit = ui.draggable.parent().attr('id');
      //save new position
      $.post("tiles/updateTilePosition", { draggableId:draggableId, droppableId: droppableId }).done(function(data) {
         //alert(data);
      })
      $(this).addClass('occupied');
      ui.draggable.parent().removeClass('occupied');
      if($(ui.draggable).parent() !==$(this)){
            $(ui.draggable).appendTo($( this ));
      }
}

Any opinions gratefully received

Zaphod Beeblebrox
  • 552
  • 3
  • 10
  • 35
  • What are the dimensions of the grid? Max columns/rows? Are you able to move only the links or can the divs move within the grid? – Dom Apr 22 '13 at 19:38
  • Also, does any of the code have to stay as is? Or can I edit any aspect of it? – Dom Apr 22 '13 at 19:52
  • @Dom, thanks for taking alook, and sorry for the delay in spotting your reply, I'm in UK. To answer your questions. The grid can have rows or columns added to it by the user. That's why each droppable has ids like 1:4. You can change any aspect of the code as long as it works! At the moment you can only move the links around but if it needed to be divs I guess that's ok as long as they are still somehow clickable links and they can be moved around – Zaphod Beeblebrox Apr 23 '13 at 10:21
  • I posted a solution, let me know if it's what you are looking for. – Dom Apr 24 '13 at 14:51

1 Answers1

6

First, never use IDs that begin with a number or a symbol. According to this solution:

ID and NAME tokens must begin with a letter ([A-Za-z]) and may be followed by any number of letters, digits ([0-9]), hyphens ("-"), underscores ("_"), colons (":"), and periods (".").


Now let's clean up some of your code. For your current situation, I recommend using .draggable() and .droppable().

I started from scratch, but kept the draggable & droppable options used in your jsfiddle. Here is what I came up with (feel free to change any aspect of it):

DEMO: http://jsfiddle.net/dirtyd77/Y8dLz/
http://fiddle.jshell.net/dirtyd77/Y8dLz/show/

JAVASCRIPT:

$(function () {
    $('#container div').draggable({
        containment: "#container",
        helper: 'clone',
        snap: true,
        snapMode: 'inner',
        snapTolerance: 32,
        revert: 'invalid'
    });

    $('#container div').droppable({
        hoverClass: 'ui-state-highlight',
        drop: function (event, ui) {
            var _drop = $(this), 
                _drag = $(ui.draggable),
                _dropChildren = _drop.children(), //original drop children
                _dragChilden = _drag.children(); //original drag children

            if(_dropChildren.length > 0){
                _dropChildren.appendTo(_drag);
            }

            _dragChilden.appendTo(_drop);
        }
    });
});

HTML:

<div id="container">    
    <div>
        <a href="#somelink1" class="link1">Link 1</a>
    </div>  

    <div></div>

    <div>
        <a href="#somelink2" class="link2">Link 2</a>
    </div>

    <div></div>

    <div>
        <a href="#somelink3" class="link3">Link 3</a>
    </div>

    <div>
        <a href="#somelink1" class="link1">Link 4</a>
        <a href="#somelink3" class="link3">Link 5</a>
    </div>
</div>

CSS:

div:not(#container) {
    border:1px solid orange;
}
#container {
    padding:20px;
    margin:10px;
    float: left; /* needed for containment option */
    width: 336px;
    height: auto;
    border:1px solid green;
}
#container div {
    margin: 4px;
    padding: 0px;
    float: left;
    width: 100px;
    height: 90px;
    text-align: center;
}
.link1{
    color: purple;   
}
.link2{
    color: red;   
}
.link3{
    color: green;   
}

I hope this is what you're looking for! Please let me know if you need any further explanation or have any additional questions! Happy coding!

Community
  • 1
  • 1
Dom
  • 32,648
  • 12
  • 45
  • 77