mirror of
https://github.com/TracksApp/tracks.git
synced 2026-01-11 11:48:51 +01:00
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:
parent
060f1e9a97
commit
9263249e77
6 changed files with 163 additions and 28 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
// }
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue