This changeset adds the ability to drag and drop actions between contexts and ajaxomagically update the action's context in the backend. I've tested it in Firefox and Safari, but not on other browsers.

When you start dragging an action, the other contexts collapse to provide easier targets for dropping. After the drop, the contexts return to their previously states of collapsed/expanded.



git-svn-id: http://www.rousette.org.uk/svn/tracks-repos/trunk@275 a4c988fc-2ded-0310-b66e-134b36920a42
This commit is contained in:
lukemelia 2006-07-03 00:22:28 +00:00
parent 060f1e9a97
commit 9263249e77
6 changed files with 163 additions and 28 deletions

View file

@ -189,6 +189,23 @@ class TodoController < ApplicationController
@saved = @item.save
end
def update_context
self.init
@item = check_user_return_item
context = Context.find(params['context_id']);
if @user == context.user
@original_item_context_id = @item.context_id
@item.context_id = context.id
@item.context = context
@saved = @item.save
render :action => 'update_action'
else
render :update do |page|
page.replace_html "info", content_tag("div", "Error updating the context of the dragged item. Item and context user mis-match: #{@item.user.name} and #{@context.user.name}! - refresh the page to see them.", "class" => "warning")
end
end
end
def deferred_update_action
#self.init
@ -289,7 +306,7 @@ class TodoController < ApplicationController
end
end
end
protected
def check_user_return_item

View file

@ -1,11 +1,20 @@
if @saved
item_container_id = "item-#{@item.id}-container"
logger.info("@item.context_id = #{@item.context_id}")
logger.info("@original_item_context.id = #{@original_item_context_id}")
if @item.context_id == @original_item_context_id
page.replace_html "item-#{@item.id}-container", :partial => 'todo/item'
page.visual_effect :highlight, "item-#{@item.id}-container", :duration => 3
page.replace_html item_container_id, :partial => 'todo/item'
page.visual_effect :highlight, item_container_id, :duration => 3
else
page["item-#{@item.id}-container"].remove
page.call "todoItems.expandNextActionListingByContext", "c#{@item.context_id}items", true
page.insert_html :bottom, "c#{@item.context_id}items", :partial => 'todo/item'
page.visual_effect :highlight, "item-#{@item.id}-container", :duration => 3
page.delay(0.5) do
page.call "todoItems.ensureContainerHeight", "c#{@original_item_context_id}items"
page.call "todoItems.ensureContainerHeight", "c#{@item.context_id}items"
page.call "todoItems.makeItemDraggable", item_container_id
page.visual_effect :highlight, item_container_id, :duration => 3
end
end
else
page.hide "info"

View file

@ -6,7 +6,11 @@ Ajax.Responders.register({
onComplete: function() {
if($('busy') && Ajax.activeRequestCount==0)
Element.hide('busy');
}
},
// uncomment the next three lines for easier debugging with FireBug
// onException: function(source, exception) {
// console.error(exception);
// }
});
/**

View file

@ -11,20 +11,42 @@ var todoItems = {
addNextActionListingToggles: function()
{
this.contextCollapseCookieManager = new CookieManager();
var toggleElems = document.getElementsByClassName('container_toggle');
toggleElems.each(function(toggleElem){
$$('.container_toggle').each(function(toggleElem){
Event.observe(toggleElem, 'click', todoItems.toggleNextActionListing);
toggleElem.onclick = function() {return false;}; //workaround for Event.stop problem with Safari 2.0.3. See http://particletree.com/notebook/eventstop/
});
todoItems.setNextActionListingTogglesToCookiedState();
},
setNextActionListingTogglesToCookiedState: function()
{
contextCollapseCookieManager = new CookieManager();
$$('.container_toggle').each(function(toggleElem){
containerElem = todoItems.findNearestParentByClassName(toggleElem, "container");
collapsedCookie = contextCollapseCookieManager.getCookie(todoItems.buildCookieName(containerElem));
if (collapsedCookie)
itemsElem = todoItems.findItemsElem(toggleElem);
isExpanded = Element.visible(itemsElem);
if (collapsedCookie && isExpanded)
{
itemsElem = todoItems.findItemsElem(toggleElem);
todoItems.collapseNextActionListing(toggleElem, itemsElem);
}
else if (!collapsedCookie && !isExpanded)
{
todoItems.expandNextActionListing(toggleElem, itemsElem);
}
});
},
collapseAllNextActionListing: function(except)
{
$$('.container_toggle').each(function(toggleElem){
if (toggleElem != except)
itemsElem = todoItems.findItemsElem(toggleElem);
isExpanded = Element.visible(itemsElem);
if (isExpanded)
{
todoItems.collapseNextActionListing(toggleElem, itemsElem);
}
});
},
ensureVisibleWithEffectAppear: function(elemId)
{
@ -58,31 +80,51 @@ var todoItems = {
contextCollapseCookieManager.clearCookie(todoItems.buildCookieName(containerElem))
}
},
expandNextActionListing: function(toggleElem, itemsElem)
findToggleElemForContext : function(contextElem)
{
Effect.BlindDown(itemsElem, { duration: 0.4 });
childElems = $A($(contextElem).getElementsByTagName('a'));
return childElems.detect(function(childElem) { return childElem.className == 'container_toggle' });
},
expandNextActionListing: function(toggleElem, itemsElem, skipAnimation)
{
itemsElem = $(itemsElem)
if (skipAnimation == true) {
itemsElem.style.display = 'block';
}
else
{
Effect.BlindDown(itemsElem, { duration: 0.4 });
}
toggleElem.setAttribute('title', 'Collapse');
imgElem = todoItems.findFirstImgElementWithSrcContaining(toggleElem, 'expand.png');
imgElem = todoItems.findToggleImgElem(toggleElem);
imgElem.src = imgElem.src.replace('expand','collapse');
imgElem.setAttribute('title','Collapse');
},
ensureContainerHeight: function(itemsElem)
{
itemsElem = $(itemsElem);
Element.setStyle(itemsElem, {height : ''});
Element.setStyle(itemsElem, {overflow : ''});
},
expandNextActionListingByContext: function(itemsElem, skipAnimation)
{
contextElem = todoItems.findNearestParentByClassName($(itemsElem), "context");
toggleElem = todoItems.findToggleElemForContext(contextElem);
todoItems.expandNextActionListing(toggleElem, itemsElem, skipAnimation);
},
collapseNextActionListing: function(toggleElem, itemsElem)
{
Effect.BlindUp(itemsElem, { duration: 0.4});
toggleElem.setAttribute('title', 'Expand');
imgElem = todoItems.findFirstImgElementWithSrcContaining(toggleElem, 'collapse.png');
imgElem = todoItems.findToggleImgElem(toggleElem);
imgElem.src = imgElem.src.replace('collapse','expand');
imgElem.setAttribute('title','Expand');
},
findFirstImgElementWithSrcContaining: function(searchRootElem, srcString)
findToggleImgElem: function(toggleElem)
{
childImgElems = $A(searchRootElem.getElementsByTagName('img'));
return childImgElems.detect(function(childImgElem) { return childImgElem.src.indexOf(srcString) != -1 });
childImgElems = $A(toggleElem.getElementsByTagName('img'));
return childImgElems[0];
},
buildCookieName: function(containerElem)
{
tracks_login = contextCollapseCookieManager.getCookie('tracks_login');
@ -110,6 +152,67 @@ var todoItems = {
return document.getElementsByClassName('toggle_target',containerElem)[0];
else
return null;
},
addItemDragDrop: function()
{
$$('.item-container').each(function(containerElem){
todoItems.makeItemDraggable(containerElem);
});
$$('.context').each(function(contextElem){
todoItems.makeContextDroppable(contextElem);
});
},
makeItemDraggable: function(itemContainerElem)
{
new Draggable($(itemContainerElem).id,
{
handle:'description',
starteffect:todoItems.startDraggingItem,
endeffect:todoItems.stopDraggingItem,
revert:true
});
},
makeContextDroppable: function(contextElem)
{
Droppables.add($(contextElem).id,
{
accept:'item-container',
hoverclass:'item-container-drop-target',
onDrop: todoItems.itemDrop,
zindex: 1000
});
},
startDraggingItem:function(draggable)
{
parentContainer = todoItems.findNearestParentByClassName(draggable, 'container');
draggable.parentContainer = parentContainer;
toggleElem = document.getElementsByClassName('container_toggle',parentContainer)[0];
todoItems.collapseAllNextActionListing(toggleElem);
},
stopDraggingItem:function(draggable)
{
todoItems.setNextActionListingTogglesToCookiedState();
},
itemDrop:function(draggableElement, droppableElement) {
if (draggableElement.parentContainer == droppableElement) {
return; //same destination as original, nothing to be done
}
itemElementId = draggableElement.id
todoId = draggableElement.id.match(/\d+/)[0];
contextId = droppableElement.id.match(/\d+/)[0];
Draggables.drags.each(function(drag) {
if (drag.element == draggableElement) {
drag.destroy();
}
})
new Ajax.Request('/todo/update_context', {
asynchronous:true,
evalScripts:true,
parameters:"id=" + todoId + "&context_id=" + contextId
})
}
}
Event.observe(window, "load", todoItems.addNextActionListingToggles);
Event.observe(window, "load", todoItems.addItemDragDrop);

View file

@ -1,13 +1,12 @@
function toggleAll(className) {
var elems = document.getElementsByClassName(className);
for (var i = 0; i < elems.length; i++) {
if (elems[i].style.display == 'block')
document.getElementsByClassName(className).each(function(elem){
if (elem.style.display == 'block')
{
elems[i].style.display = 'none';
elem.style.display = 'none';
}
else
{
elems[i].style.display = 'block';
elem.style.display = 'block';
}
}
});
}

View file

@ -129,6 +129,7 @@ a.show_notes:hover {background-image: url(../images/notes_on.png); background-re
opacity: .75;
color: #eee;
width: 100%;
z-index:1100;
}
#date {
@ -202,7 +203,9 @@ h2 a:hover {
padding:2px;
clear: left;
}
.item-container-drop-target {
border:2px inset black;
}
.container a.icon {
float: left;
vertical-align: middle;