Draggable File Container

Drag/Drop for moving nested DIV 'clips' to a 'editor' droppable

by Phil Glau

HTML

<div id="container">
    <div id="clips">
        <div id="clip1345" class='clip'>
            <img class='clip_image' src='http://ridiculousprods.com/i/multi_merge_clip.png' />
            <div class='length'>00:01:24</div>
            <div class='name wordwrap'>A001_C003_0101AE_REALLY_LONG_EXTRA_NAME.mp4</div>
        </div>
        <div id="clip1346" class='clip'>
            <img class='clip_image' src='http://ridiculousprods.com/i/multi_merge_clip.png' />
            <div class='length'>00:02:23</div>
            <div class='name wordwrap'>A001_C003_0101AE.mp4</div>
        </div>
        <div id="clip1347" class='clip'>
            <img class='clip_image' src='http://ridiculousprods.com/i/multi_merge_clip.png' />
            <div class='length'>00:03:05</div>
            <div class='name wordwrap'>A001_C003_0101AF.mp4</div>
        </div>
        <div id="clip1348" class='clip'>
            <img class='clip_image' src='http://ridiculousprods.com/i/multi_merge_clip.png' />
            <div class='length'>00:01:05</div>
            <div class='name wordwrap'>A001_C003_0101AG.mp4</div>
        </div>
        <div id="clip1349" class='clip'>
            <img class='clip_image' src='http://ridiculousprods.com/i/multi_merge_clip.png' />
            <div class='length'>00:02:15</div>
            <div class='name wordwrap'>A001_C003_0101AH.mp4</div>
        </div>
    </div>
    <div id="clusters"></div>
    <div id="total_time">00:00:00</div>
</div>

CSS

/* styling for the clips with icons/names/lengths */
 .clip_image {
    width: 80px;
    height: auto;
    float:left;
}
.length {
    float: left;
    padding: 10px;
}
.name {
    clear: both;
    font-size: 10pt;
    padding-top: 2px;
}
/* helper styling to force word wrap on long names */
 .wordwrap {
    white-space: pre-wrap;
    /* CSS3 */
    white-space: -moz-pre-wrap;
    /* Firefox */
    white-space: -pre-wrap;
    /* Opera <7 */
    white-space: -o-pre-wrap;
    /* Opera 7 */
    word-wrap: break-word;
    /* IE */
}
.clip {
    -webkit-border-radius: 8px;
    -moz-border-radius: 8px;
    border-radius: 8px;
    background-color: #DDDDDD;
    padding: 5px;
    font-family: Verdana, Geneva, sans-serif;
    text-align: center;
    background-color: rgb(221, 221, 221);
    border-top-left-radius: 8px;
    border-top-right-radius: 8px;
    border-bottom-right-radius: 8px;
    border-bottom-left-radius: 8px;
    width: 176px;
    height: auto;
    margin: 7px;
    box-shadow: 0 0 .5em rgba(0, 0, 0, .8);
    float: left;
}
#container {
    margin: 10px 10px;
    text-align: center;
    -moz-user-select: none;
    -webkit-user-select: none;
    user-select: none;
}
/* general definition of the containers for holding the clips */
 #clips {
    margin: 0 0;
    /* yellowish backgroun for clip container */
    background: #ffd;
    width: 610px;
    height: 320px;
    padding: 1px;
    border: 2px solid #333;
    -moz-border-radius: 10px;
    -webkit-border-radius: 10px;
    border-radius: 10px;
    -moz-box-shadow: 0 0 .3em rgba(0, 0, 0, .8);
    -webkit-box-shadow: 0 0 .3em rgba(0, 0, 0, .8);
    box-shadow: 0 0 .3em rgba(0, 0, 0, .8);
    float: left;
}
#total_time {
    float: clear;
}
#clusters {
    width: 210px;
    height: 320px;
    margin-left: 10px;
    padding: 1px;
    border: 2px solid #333;
    -moz-border-radius: 10px;
    -webkit-border-radius: 10px;
    border-radius: 10px;
    -moz-box-shadow: 0 0 .3em rgba(0, 0, 0, .8);
   ...

JavaScript

// key = temp_id, value = length in seconds
var temp_ids = {
    1345: 84,
    1346: 143,
    1347: 185,
    1348: 65,
    1349: 135
};
var editTime = 0;

for (key in temp_ids) {
    $("#clip" + key).data('temp_id', key).data('lenSec', temp_ids[key]).draggable({
        //        containment: '#container',
        stack: '#clips div',
        cursor: 'move',
        revert: true,
    });
}

$("#clusters").droppable({
    accept: '#clips div', // only accept if originating from Clips Bin
    drop: dropToEditor
});

$("#clips").droppable({
    accept: '#clusters div', // only accept if coming from Edit Line
    drop: putBackInBin
});

function putBackInBin(e, ui) {
    var dropped = ui.draggable;
    dropped.draggable('option', 'revert', false);
    var droppedOn = $(this);
    editTime -= dropped.data('lenSec');
    $("#total_time").text(secToTime(editTime));
    $(dropped).children('.clip_image').show();
    $(dropped).children('.length').show();
    $(dropped).detach().css({
        top: 0,
        left: 0
    }).appendTo(droppedOn);
    // turn on reversion so that subsequent drags 'revert' to the clusters div
    // unless dropped back on to the clip bin.
    dropped.draggable('option', 'revert', true);
}

function dropToEditor(e, ui) {
    var dropped = ui.draggable;
    var helper = ui.helper;
    var droppedOn = $(this);
    // turn of reversion so that it can snap into the drop container
    editTime += dropped.data('lenSec');
    $("#total_time").text(secToTime(editTime));

    // remove the selection from the item being dragged. Selection will
    // remain on other items if multi-selected.
    $(helper).removeClass("selected");
    var selected = $(".selected");

    if (selected.length > 1) {
        moveSelected(droppedOn, selected);
    } else {
        moveItem(droppedOn, dropped);
    }
    /*

    $(dropped).children('.clip_image').hide();
    $(dropped).children('.length').hide();
    $(dropped).detach().css({
        top: 0,
        left: 0
   ...