diff --git a/tracks/app/views/context/_context.rhtml b/tracks/app/views/context/_context.rhtml new file mode 100644 index 00000000..fac5d2a6 --- /dev/null +++ b/tracks/app/views/context/_context.rhtml @@ -0,0 +1,16 @@ +<% @not_done = context.find_not_done_todos %> +
+

+<% if collapsible -%> + <%= image_tag("collapse.png") %> +<% end -%> + <%= link_to( sanitize("#{context.name}"), { :controller => "context", :action => "show", :name => urlize(context.name) }, { :title => "Go to the #{context.name} context page" } ) %> +

+
+
+ <%= render :partial => "shared/empty", + :locals => { :message => "Currently there are no uncompleted actions in this context"} %> +
+<%= render :partial => "todo/item", :collection => @not_done, :locals => { :project => false } %> +
+
diff --git a/tracks/app/views/context/_empty.rhtml b/tracks/app/views/context/_empty.rhtml deleted file mode 100644 index f92ff187..00000000 --- a/tracks/app/views/context/_empty.rhtml +++ /dev/null @@ -1 +0,0 @@ -

<%= message %>

\ No newline at end of file diff --git a/tracks/app/views/project/_project.rhtml b/tracks/app/views/project/_project.rhtml new file mode 100644 index 00000000..27e10bf6 --- /dev/null +++ b/tracks/app/views/project/_project.rhtml @@ -0,0 +1,24 @@ +<% @not_done = project.find_not_done_todos -%> +
+

+ <% if collapsible %> + <%= image_tag("collapse.png") %> + <% end %> + <%= sanitize("#{project.name}") %> +

+ <% if @project.description -%> +
<%= sanitize(@project.description) %>
+ <% end -%> + + <% if @project.done? -%> +

Project has been marked as completed

+ <% end -%> +
+
+ <%= render :partial => "shared/empty", + :locals => { :message => "Currently there are no uncompleted actions in this project"} %> +
+ + <%= render :partial => "todo/item", :collection => @not_done, :locals => { :project => true } %> +
+
diff --git a/tracks/app/views/shared/_empty.rhtml b/tracks/app/views/shared/_empty.rhtml new file mode 100644 index 00000000..f2f2cb9f --- /dev/null +++ b/tracks/app/views/shared/_empty.rhtml @@ -0,0 +1,3 @@ +
+

<%= message %>

+
diff --git a/tracks/app/views/todo/_completed.rhtml b/tracks/app/views/todo/_completed.rhtml new file mode 100644 index 00000000..7e9747d2 --- /dev/null +++ b/tracks/app/views/todo/_completed.rhtml @@ -0,0 +1,18 @@ +<% suffix = append_descriptor ? append_descriptor : '' %> +
+

+ <% if collapsible %> + <%= image_tag("collapse.png") %> + <% end %> + Completed actions <%= append_descriptor ? append_descriptor : '' %> +

+
+ +
+ <%= render :partial => "shared/empty", + :locals => { :message => "Currently there are no completed actions " + suffix } %> +
+ + <%= render :partial => "todo/item", :collection => done %> +
+
\ No newline at end of file diff --git a/tracks/public/javascripts/todo-items.js b/tracks/public/javascripts/todo-items.js new file mode 100644 index 00000000..83a9fc9a --- /dev/null +++ b/tracks/public/javascripts/todo-items.js @@ -0,0 +1,174 @@ +/* + * ToDo Items + * + * Requires the prototype.js library + * + * Use the following markup to include the library: + * + */ + +addEvent(window, "load", addNextActionListingToggles); +addEvent(window, "load", addAjaxToDoItemCheckmarkHandling); + +function addNextActionListingToggles() +{ + var toggleElems = document.getElementsByClassName('container_toggle'); + for(var i = 0; i < toggleElems.length; i++) + { + addEvent(toggleElems[i], "click", toggleNextActionListing); + } +} + +function addAjaxToDoItemCheckmarkHandling() +{ + var itemCheckboxes = document.getElementsByClassName('item-checkbox'); + for(var i = 0; i < itemCheckboxes.length; i++) + { + addEvent(itemCheckboxes[i], "click", toggleTodoItemChecked); + } +} + +function addOneAjaxToDoItemCheckmarkHandling(elem) +{ + addEvent(document.getElementsByClassName('item-checkbox',elem)[0], "click", toggleTodoItemChecked); +} + +function hideContainerIfEmpty(containerElemId) +{ + if (document.getElementsByClassName('item-container',$(containerElemId)).length == 0) + { + new Effect.Fade(containerElemId) + } + +} + +function getMarkUndoneTargetElem() +{ + return document.getElementsByClassName('container')[0]; +} + +function ensureVisibleWithEffectAppear(elemId) +{ + if ($(elemId).style.display == 'none') + { + new Effect.Appear(elemId,{duration:0.4}); + } +} + +function toggleTodoItemChecked() +{ + var itemContainerElem = findNearestParentByClassName(this, 'item-container'); + var itemContainerElemId = itemContainerElem.getAttribute('id'); + var checkboxForm = this.form; + var markingAsDone = this.checked; + var targetElemId = markingAsDone ? 'completed' : getMarkUndoneTargetElem().getAttribute('id'); + new Ajax.Updater( + targetElemId, + checkboxForm.action, + { + asynchronous:true, + evalScripts:true, + insertion:markingAsDone ? Insertion.Top : Insertion.Bottom, + onLoading:function(request){ Form.disable(checkboxForm); ensureVisibleWithEffectAppear(targetElemId); }, + onSuccess:function(request){ fadeAndRemoveItem(itemContainerElemId); }, + onComplete:function(request){ new Effect.Highlight(itemContainerElemId,{}); addOneAjaxToDoItemCheckmarkHandling($(itemContainerElemId)); hideContainerIfEmpty('new_actions'); }, + parameters:Form.serialize(checkboxForm) + }); + return false; +} + +function fadeAndRemoveItem(itemContainerElemId) +{ + var fadingElemId = itemContainerElemId + '-fading'; + $(itemContainerElemId).setAttribute('id',fadingElemId); + Element.removeClassName($(fadingElemId),'item-container'); + new Effect.Fade(fadingElemId,{afterFinish:function(effect) { Element.remove(fadingElemId); }, duration:0.4}); +} + +function toggleNextActionListing() +{ + var itemsElem = findItemsElem(this); + if (Element.visible(itemsElem)) + Effect.BlindUp(itemsElem, { duration: 0.4}); + else + Effect.BlindDown(itemsElem, { duration: 0.4 }); + this.setAttribute('title', (this.style.display == 'none') ? 'Expand' : 'Collapse'); + var childImgElems = this.getElementsByTagName('img'); + for(var i = 0; i < childImgElems.length; i++) + { + if (childImgElems[i].src.indexOf('collapse.png') != -1) + { + childImgElems[i].src = childImgElems[i].src.replace('collapse','expand'); + childImgElems[i].setAttribute('title','Expand'); + //SetCookie(idname, "collapsed"); + } + else if (childImgElems[i].src.indexOf('expand.png') != -1) + { + childImgElems[i].src = childImgElems[i].src.replace('expand','collapse'); + childImgElems[i].setAttribute('title','Collapse'); + //SetCookie(idname, "expanded"); + } + } + return false; +} + +function findNearestParentByClassName(elem, parentClassName) +{ + var parentElem = elem.parentNode; + while(parentElem) + { + if (Element.hasClassName(parentElem, parentClassName)) + { + return parentElem; + } + parentElem = parentElem.parentNode; + } + return null; +} + +function findItemsElem(toggleElem) +{ + var containerElem = findNearestParentByClassName(toggleElem, "container"); + if (containerElem) + return document.getElementsByClassName('toggle_target',containerElem)[0]; + else + return null; +} + +// This is a cross-browser function for event addition. +function addEvent(obj, evType, fn) +{ + if (obj.addEventListener) + { + obj.addEventListener(evType, fn, false); + return true; + } + else if (obj.attachEvent) + { + var r = obj.attachEvent("on" + evType, fn); + return r; + } + else + { + alert("Event handler could not be attached"); + return false; + } +} + +function removeEvent(obj, evType, fn) +{ + if (obj.removeEventListener) + { + obj.removeEventListener(evType, fn, false); + return true; + } + else if (obj.detachEvent) + { + var r = obj.detachEvent("on"+evType, fn); + return r; + } + else + { + alert("Handler could not be removed"); + } +} \ No newline at end of file