diff --git a/tracks/app/views/context/_context.rhtml b/tracks/app/views/context/_context.rhtml
index 4fc2328a..b3f58962 100644
--- a/tracks/app/views/context/_context.rhtml
+++ b/tracks/app/views/context/_context.rhtml
@@ -2,7 +2,7 @@
<% if collapsible -%>
- <%= image_tag("collapse.png") %>
+ <%= 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" } ) %>
diff --git a/tracks/app/views/layouts/standard.rhtml b/tracks/app/views/layouts/standard.rhtml
index 7bdb7894..1fc2901a 100644
--- a/tracks/app/views/layouts/standard.rhtml
+++ b/tracks/app/views/layouts/standard.rhtml
@@ -6,6 +6,7 @@
<%= stylesheet_link_tag "print", :media => "print" %>
<%= javascript_include_tag "toggle_notes" %>
<%= javascript_include_tag :defaults %>
+ <%= javascript_include_tag "selector-addon-v1" %>
<%= stylesheet_link_tag 'calendar-system.css' %>
<%= javascript_include_tag 'calendar', 'calendar-en', 'calendar-setup' %>
<%= javascript_include_tag "accesskey-hints" %>
diff --git a/tracks/app/views/project/_project.rhtml b/tracks/app/views/project/_project.rhtml
index 9fbd4121..f1898682 100644
--- a/tracks/app/views/project/_project.rhtml
+++ b/tracks/app/views/project/_project.rhtml
@@ -3,7 +3,7 @@
diff --git a/tracks/app/views/todo/_completed.rhtml b/tracks/app/views/todo/_completed.rhtml
index 56a92e1a..db0df5b4 100644
--- a/tracks/app/views/todo/_completed.rhtml
+++ b/tracks/app/views/todo/_completed.rhtml
@@ -1,8 +1,8 @@
<% suffix = append_descriptor ? append_descriptor : '' -%>
-
+
diff --git a/tracks/public/javascripts/application.js b/tracks/public/javascripts/application.js
index ad53d973..40164b21 100644
--- a/tracks/public/javascripts/application.js
+++ b/tracks/public/javascripts/application.js
@@ -6,7 +6,8 @@ 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);
diff --git a/tracks/public/javascripts/selector-addon-v1.js b/tracks/public/javascripts/selector-addon-v1.js
new file mode 100644
index 00000000..796f8777
--- /dev/null
+++ b/tracks/public/javascripts/selector-addon-v1.js
@@ -0,0 +1,163 @@
+/************************************
+ *
+ * An add-on to Prototype 1.5 to speed up the $$ function in usual cases.
+ *
+ * http://www.sylvainzimmer.com/index.php/archives/2006/06/25/speeding-up-prototypes-selector/
+ *
+ * Authors:
+ * - Sylvain ZIMMER
+ *
+ * Changelog:
+ * v1 (2006/06/25)
+ * - Initial release
+ *
+ * License: AS-IS
+ *
+ * Trivia: Check out www.jamendo.com for some great Creative Commons music ;-)
+ *
+ ************************************/
+
+
+
+// We don't extend the Selector class because we want
+// to be able to use it if the expression is too complicated.
+var SelectorLiteAddon=Class.create();
+
+
+SelectorLiteAddon.prototype = {
+
+ // This is the constructor. It parses the stack of selectors.
+ initialize: function(stack) {
+
+ this.r=[]; //results
+ this.s=[]; //stack of selectors
+ this.i=0; //stack pointer
+
+ //Parse the selectors
+ for (var i=stack.length-1;i>=0;i--) {
+
+ //This is the parsed selector. Format is : [tagname, id, classnames]
+ var s=["*","",[]];
+
+ //The unparsed current selector
+ var t=stack[i];
+
+ //Parse the selector backwards
+ var cursor=t.length-1;
+ do {
+
+ var d=t.lastIndexOf("#");
+ var p=t.lastIndexOf(".");
+ cursor=Math.max(d,p);
+
+ //Found a tagName
+ if (cursor==-1) {
+ s[0]=t.toUpperCase();
+
+ //Found a className
+ } else if (d==-1 || p==cursor) {
+ s[2].push(t.substring(p+1));
+
+ //Found an ID
+ } else if (!s[1]) {
+ s[1]=t.substring(d+1);
+ }
+ t=t.substring(0,cursor);
+ } while (cursor>0);
+ this.s[i]=s;
+ }
+ },
+
+ //Returns a list of matched elements below a given root.
+ get:function(root) {
+ this.explore(root || document,this.i==(this.s.length-1));
+ return this.r;
+ },
+
+ //Recursive function where the actual search is being done.
+ // elt: current root element
+ // leaf: boolean, are we in a leaf of the search tree?
+ explore:function(elt,leaf) {
+
+ //Parsed selector
+ var s=this.s[this.i];
+
+ //Results
+ var r=[];
+
+ //Selector has an ID, use it!
+ if (s[1]) {
+
+ e=$(s[1]);
+ if (e && (s[0]=="*" || e.tagName==s[0]) && e.childOf(elt)) {
+ r=[e];
+ }
+
+ //Selector has no ID, search by tagname.
+ } else {
+ r=$A(elt.getElementsByTagName(s[0]));
+ }
+
+
+ //Filter the results by classnames.
+ //Todo: by attributes too?
+ //Sidenote: The performance hit is often here.
+
+ //Single className : that's fast!
+ if (s[2].length==1) { //single classname
+ r=r.findAll(function(o) {
+
+ //If the element has only one classname too, the test is simple!
+ if (o.className.indexOf(" ")==-1) {
+ return o.className==s[2][0];
+ } else {
+ return o.className.split(/\s+/).include(s[2][0]);
+ }
+ });
+
+ //Multipe classNames, a bit slower.
+ } else if (s[2].length>0) {
+ r=r.findAll(function(o) {
+
+ //If the elemtn has only one classname, we can drop it.
+ if (o.className.indexOf(" ")==-1) {
+ return false;
+ } else {
+
+ //Check that all required classnames are present.
+ var q=o.className.split(/\s+/);
+ return s[2].all(function(c) {
+ return q.include(c);
+ });
+ }
+ });
+ }
+
+
+ //Append the results if we're in a leaf
+ if (leaf) {
+ this.r=this.r.concat(r);
+
+ //Continue exploring the tree otherwise
+ } else {
+ ++this.i;
+ r.each(function(o) {
+ this.explore(o,this.i==(this.s.length-1));
+ }.bind(this));
+ }
+ }
+
+}
+
+
+//Overwrite the $$ function.
+var $$old=$$;
+
+var $$=function(a,b) {
+
+ //expression is too complicated, forward the call to prototype's function!
+ if (b || a.indexOf("[")>=0) return $$old.apply(this,arguments);
+
+ //Otherwise use our addon!
+ return new SelectorLiteAddon(a.split(/\s+/)).get();
+}
diff --git a/tracks/public/javascripts/todo-items.js b/tracks/public/javascripts/todo-items.js
index ae50494a..12e0d92f 100644
--- a/tracks/public/javascripts/todo-items.js
+++ b/tracks/public/javascripts/todo-items.js
@@ -13,26 +13,36 @@ ToDoItems.prototype = {
initialize: function()
{
this.initialized = true;
+ this.contextCollapseCookieManager = new CookieManager();
+ this.toggleItemsMap = {};
+ this.toggleContainerMap = {};
+ this.containerItemsMap = {};
},
addNextActionListingToggles: function()
{
this.containerToggles = $$('.container_toggle');
+ containerTogglesClick = this.toggleNextActionListing.bindAsEventListener(this);
for(i=0; i < this.containerToggles.length; i++)
{
- Event.observe(this.containerToggles[i], 'click', this.toggleNextActionListing.bindAsEventListener(this));
+ toggleElem = this.containerToggles[i];
+ containerElem = toggleElem.parentNode.parentNode
+ itemsElem = document.getElementsByClassName('toggle_target',containerElem)[0];
+ this.toggleContainerMap[toggleElem.id] = containerElem;
+ this.toggleItemsMap[toggleElem.id] = itemsElem;
+ this.containerItemsMap[containerElem.id] = itemsElem;
+ Event.observe(this.containerToggles[i], 'click', containerTogglesClick);
this.containerToggles[i].onclick = function() {return false;}; //workaround for Event.stop problem with Safari 2.0.3. See http://particletree.com/notebook/eventstop/
}
this.setNextActionListingTogglesToCookiedState();
},
setNextActionListingTogglesToCookiedState: function()
{
- contextCollapseCookieManager = new CookieManager();
for(i=0; i < this.containerToggles.length; i++)
{
toggleElem = this.containerToggles[i];
- containerElem = this.findNearestParentByClassName(toggleElem, "container");
- collapsedCookie = contextCollapseCookieManager.getCookie(this.buildCookieName(containerElem));
- itemsElem = this.findItemsElem(toggleElem);
+ containerElem = this.toggleContainerMap[toggleElem.id];
+ collapsedCookie = this.contextCollapseCookieManager.getCookie(this.buildCookieName(containerElem));
+ itemsElem = this.toggleItemsMap[toggleElem.id];
isExpanded = Element.visible(itemsElem);
if (collapsedCookie && isExpanded)
{
@@ -50,11 +60,13 @@ ToDoItems.prototype = {
{
toggleElem = this.containerToggles[i];
if (toggleElem != except)
- itemsElem = this.findItemsElem(toggleElem);
- isExpanded = Element.visible(itemsElem);
- if (isExpanded)
{
- this.collapseNextActionListing(toggleElem, itemsElem);
+ itemsElem = this.toggleItemsMap[toggleElem.id];
+ isExpanded = Element.visible(itemsElem);
+ if (isExpanded)
+ {
+ this.collapseNextActionListing(toggleElem, itemsElem);
+ }
}
}
},
@@ -76,17 +88,17 @@ ToDoItems.prototype = {
{
Event.stop(event);
toggleElem = Event.element(event).parentNode;
- itemsElem = this.findItemsElem(toggleElem);
- containerElem = this.findNearestParentByClassName(toggleElem, "container");
+ itemsElem = this.toggleItemsMap[toggleElem.id];
+ containerElem = this.toggleContainerMap[toggleElem.id];
if (Element.visible(itemsElem))
{
this.collapseNextActionListing(toggleElem, itemsElem);
- contextCollapseCookieManager.setCookie(this.buildCookieName(containerElem), true)
+ this.contextCollapseCookieManager.setCookie(this.buildCookieName(containerElem), true)
}
else
{
this.expandNextActionListing(toggleElem, itemsElem);
- contextCollapseCookieManager.clearCookie(this.buildCookieName(containerElem))
+ this.contextCollapseCookieManager.clearCookie(this.buildCookieName(containerElem))
}
},
findToggleElemForContext : function(contextElem)
@@ -136,7 +148,7 @@ ToDoItems.prototype = {
},
buildCookieName: function(containerElem)
{
- tracks_login = contextCollapseCookieManager.getCookie('tracks_login');
+ tracks_login = this.contextCollapseCookieManager.getCookie('tracks_login');
return 'tracks_'+tracks_login+'_context_' + containerElem.id + '_collapsed';
},
@@ -152,15 +164,6 @@ ToDoItems.prototype = {
parentElem = parentElem.parentNode;
}
return null;
- },
-
- findItemsElem : function(elem)
- {
- var containerElem = this.findNearestParentByClassName(elem, "container");
- if (containerElem)
- return document.getElementsByClassName('toggle_target',containerElem)[0];
- else
- return null;
}
}