Butter: Bug 434 Status

For the past couple of days, I have been working on bug 434 in Butter, which is to allow users to move multiple track events at the same time. This is definitely not as straightforward as it seems.

Initially, I was thinking that since the dragging behaviour already exists in the track event, I could just have a loop that goes through all of the selected track events, and trigger the dragging behaviour on each one. After trying various things in the code, I realized that making this trigger happen wasn’t obvious.

I started doing some searches, and ended up reading this post on StackOverflow. I implemented something similar to the selected answer, which is to implement the helper function in jQuery’s draggable to return all of the elements to be dragged appended to one container. The suggestion in the post was this:

$('#dragSource li').draggable({
  helper: function(){
    var selected = $('#dragSource input:checked').parents('li');
    if (selected.length === 0) {
      selected = $(this);
    }
    var container = $('
').attr('id', 'draggingContainer'); container.append(selected.clone()); return container; } });

This person also put up a demo on JSBin, and it seemed like this is exactly what I wanted. But, after trying it in Butter, it ended up having unsuitable behaviour. Everything that was appended to the div appeared on top of each other, and that means that the track events were losing their place when they were being dragged. I could have done some styling with the container div so that the track events would keep their position, but this seemed like a hack that wouldn’t work.

Moving on, I found this post on the jQuery UI Google Group, which says to capture the mousedown event on the container, and then from there trigger the even on the draggables, which should start the dragging operations on all of the events. The code for that looks like this:

$(".draggable").draggable();

$("#container").mousedown(function(e) {
    $(".draggable").trigger(e);
});
​

This works for the first draggable element in the HTML, but not for the rest. There is also an error thrown in the console (I deleted much of error here because it’s too long):

jQuery.event.dispatch
jQuery.event.add.elemData.handle.eventHandle
jQuery.event.trigger
jQuery.fn.extend.trigger
jQuery.extend.each
jQuery.fn.jQuery.each
jQuery.fn.extend.trigger
(anonymous function)
jQuery.event.dispatch
jQuery.event.add.elemData.handle.eventHandle
jQuery.event.trigger
jQuery.fn.extend.trigger
jQuery.extend.eachjquery-1.7.1.js:658

.....

jQuery.event.trigger
jQuery.fn.extend.trigger
jQuery.extend.each
jQuery.fn.jQuery.each
jQuery.fn.extend.trigger
(anonymous function)

Changing the code up a bit would just give me another error, saying that there is too much recursion. So I tried to do this:

$(".draggable").draggable();

$("#container").mousedown(function(e) {
    $(".draggable").trigger(e);
});

$(".draggable").mousedown(function(e) {
    e.stopPropagation();
});

This does not throw an error, but again there is the issue that the dragging operation only works on the first draggable in the HTML.

Similarly, I found this bug filed in jQuery three years ago. It suggested writing the code like this:

$('#draggable').one('mousedown', function(e) {
    $("#draggable").draggable().trigger(e);
});

This didn’t work either, since the mousedown event was only captured once.

I then found another discussion on the jQuery forum, where rdworth mentions that jQuery uses the simulate plugin, and linked to examples of how it’s used in the jQuery unit tests. This looked like it was a bit overboard for what we’re trying to do, so I needed to find something else.

I was trying to stay away from introducing another external plugin to Butter, but it seems that I need to. I found this multidraggable jQuery UI plugin. I tried it out, and it works, but the one problem is that it doesn’t let the developer choose which elements are to be dragged. The way the elements are selected to be dragged is done within the plugin itself, using a control-click. This is an issue because Butter has it’s own way of deciding which track events are selected.

Finally, I found another plugin by ThreeDubMedia, which provides both drag and drop plugins. These plugins are set up to give the developer a lot of control, which is good for our case. I now have some code that moves multiple track events, but now that the jQuery UI draggable plugin is not being used, other areas need to be rewritten. For example, the scrolling feature that’s available automatically with the jQuery UI draggable plugin doesn’t seem to exist in the plugin provided by ThreeDubMedia, which means code for that has to be created.

So far, this is what I have:

function drag ( ev, dd ) {
    $( this ).css({
        top: dd.offsetY,
        left: dd.offsetX
    });
}

$( _element ).css({
    zIndex: 9001
});
$( _element ).drag( "init", function() {
    return $( "div[selected=true]" );
}).drag( "end", movedCallback ).drag(drag, {
    relative: true
}).resizable({ 
    autoHide: false, 
    containment: "parent", 
    handles: "e, w", 
    scroll: false,
    stop: movedCallback
});

Oh, and I also found an accidental global variable, _selectedEvents, in src/timeline/media.js. I will also fix that in the patch I submit.

Advertisements
This entry was posted in Open Source. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s