<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -401,7 +401,15 @@ class ApplicationController &lt; ActionController::Base
                         :user =&gt; current_user)
     title = highlight_all(title, highlight_keys)
 
-    html = { :class =&gt; &quot;tooltip#{task.css_classes}&quot;, :title =&gt; title }
+    html = { 
+      :class =&gt; &quot;tooltip tasklink #{task.css_classes}&quot;, 
+      :title =&gt; title
+    }
+
+    if @ajax_task_links
+      html[:onclick] = &quot;showTaskInPage(#{ task.task_num }); return false;&quot;
+    end
+
     text = truncate ? task.name : self.class.helpers.truncate(task.name, :length =&gt; 80)
     text = highlight_all(text, highlight_keys)
     </diff>
      <filename>app/controllers/application_controller.rb</filename>
    </modified>
    <modified>
      <diff>@@ -209,6 +209,9 @@ class TasksController &lt; ApplicationController
   def edit
     @task = current_user.company.tasks.find_by_task_num(params[:id])
 
+    @ajax_task_links = request.xhr? # want to use ajax task loads if this page was loaded by ajax
+      
+
     if @task.nil? or !current_user.can_view_task?(@task)
       flash['notice'] = _(&quot;You don't have access to that task, or it doesn't exist.&quot;)
       redirect_from_last
@@ -1115,9 +1118,6 @@ class TasksController &lt; ApplicationController
     task.due_at = tz.utc_to_local(@task.due_at) unless task.due_at.nil?
     @tags = {}
 
-    @logs = WorkLog.find(:all, :order =&gt; &quot;work_logs.started_at desc,work_logs.id desc&quot;, :conditions =&gt; [&quot;work_logs.task_id = ? #{&quot;AND (work_logs.comment = 1 OR work_logs.log_type=6)&quot; if session[:only_comments].to_i == 1}&quot;, task.id], :include =&gt; [:user, :task, :project])
-    @logs ||= []
-
     @projects = User.find(current_user.id).projects.find(:all, :order =&gt; 'name', :conditions =&gt; [&quot;completed_at IS NULL&quot;]).collect {|c| [ &quot;#{c.name} / #{c.customer.name}&quot;, c.id ] if current_user.can?(c, 'create')  }.compact unless current_user.projects.nil?
 
     @notify_targets = current_projects.collect{ |p| p.users.collect(&amp;:name) }.flatten.uniq
@@ -1166,7 +1166,8 @@ class TasksController &lt; ApplicationController
   def list_init
     # Subscribe to the juggernaut channel for Task updates
     session[:channels] += [&quot;tasks_#{current_user.company_id}&quot;]
-    @tasks = current_task_filter.tasks
+    # @tasks = current_task_filter.tasks
+    @ajax_task_links = true
   end
 
 end</diff>
      <filename>app/controllers/tasks_controller.rb</filename>
    </modified>
    <modified>
      <diff>@@ -213,10 +213,6 @@ module ApplicationHelper
     text
   end
 
-#   def link_to_task(task)
-#     &quot;&lt;strong&gt;#{task.issue_num}&lt;/strong&gt; &lt;a href=\&quot;/tasks/edit/#{task.task_num}\&quot; class=\&quot;tooltip#{task.css_classes}\&quot; title=\&quot;#{task.to_tip({ :duration_format =&gt; current_user.duration_format, :workday_duration =&gt; current_user.workday_duration, :days_per_week =&gt; current_user.days_per_week, :user =&gt; current_user })}\&quot;&gt;#{h(truncate(task.name, :length =&gt; 80))}&lt;/a&gt;&quot;
-#   end
-
   def milestone_classes(m)
     return &quot; complete_milestone&quot; unless m.completed_at.nil?
 </diff>
      <filename>app/helpers/application_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,5 @@
 class Keyword &lt; ActiveRecord::Base
-  belongs_to :task_filter
+  belongs_to :task_filter, :touch =&gt; true
   belongs_to :company
   
   validates_presence_of :company</diff>
      <filename>app/models/keyword.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2,7 +2,7 @@
 
 class Notification &lt; ActiveRecord::Base
   belongs_to :user
-  belongs_to :task
+  belongs_to :task, :touch =&gt; true
 
   named_scope :unread, :conditions =&gt; { :unread =&gt; true }
 end</diff>
      <filename>app/models/notification.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1043,7 +1043,7 @@ class Task &lt; ActiveRecord::Base
     
     user_notifications = notifications.select { |n| n.user == user }
     user_notifications.each do |n|
-      n.update_attribute(:unread, !read)
+      n.update_attributes(:unread =&gt; !read)
     end
   end
 </diff>
      <filename>app/models/task.rb</filename>
    </modified>
    <modified>
      <diff>@@ -102,14 +102,24 @@ class TaskFilter &lt; ActiveRecord::Base
     end
   end
 
+  def cache_key
+    key = super
+    last_task_update = user.company.tasks.maximum(:updated_at,
+                                                  :conditions =&gt; conditions,
+                                                  :include =&gt; to_include)
+    &quot;#{ key }/#{ last_task_update.to_i }/#{ user.id }&quot;
+  end
+
   private
 
   def to_include
-    to_include = [ :users, :tags, :sheets, :todos, :dependencies, 
-                   :milestone, :notifications, :watchers, 
-                   :customers, :task_property_values ]
-    to_include &lt;&lt; { :company =&gt; :properties }
-    to_include &lt;&lt; { :project =&gt; :customer }
+    to_include = [ :project, :users, :notifications, :watchers ]
+
+    to_include &lt;&lt; :tags if qualifiers.for(&quot;Tag&quot;).any?
+    to_include &lt;&lt; :task_property_values if qualifiers.for(&quot;PropertyValue&quot;).any?
+    to_include &lt;&lt; :customers if qualifiers.for(&quot;Customer&quot;).any?
+
+    return to_include
   end
 
   def set_company_from_user</diff>
      <filename>app/models/task_filter.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,12 +1,15 @@
 class TaskFilterQualifier &lt; ActiveRecord::Base
   attr_accessor :task_num
 
-  belongs_to :task_filter
+  belongs_to :task_filter, :touch =&gt; true
   belongs_to :qualifiable, :polymorphic =&gt; true
   validates_presence_of :qualifiable
 
   before_validation :set_qualifiable_from_task_num
 
+  named_scope :for, lambda { |type|
+    { :conditions =&gt; { :qualifiable_type =&gt; type } } }
+
   private
 
   def set_qualifiable_from_task_num</diff>
      <filename>app/models/task_filter_qualifier.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
 # A user who is assigned to a task 
 class TaskOwner &lt; ActiveRecord::Base
   belongs_to :user
-  belongs_to :task
+  belongs_to :task, :touch =&gt; true
 
   named_scope :unread, :conditions =&gt; { :unread =&gt; true }
 end</diff>
      <filename>app/models/task_owner.rb</filename>
    </modified>
    <modified>
      <diff>@@ -19,7 +19,7 @@ class WorkLog &lt; ActiveRecord::Base
   has_many    :work_log_notifications, :dependent =&gt; :destroy
   has_many    :users, :through =&gt; :work_log_notifications
 
-  named_scope :comments, :conditions =&gt; [ &quot;work_logs.comment = 1 or work_logs.log_type = 6&quot; ]
+  named_scope :comments, :conditions =&gt; [ &quot;work_logs.comment = ? or work_logs.log_type = ?&quot;, true, 6 ]
 
   validates_presence_of :started_at
 </diff>
      <filename>app/models/work_log.rb</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,9 @@
   &lt;% end %&gt;
   
   &lt;% if dependency.done? %&gt;
-    &lt;img src=&quot;/images/tick.png&quot; border=0&gt;&lt;% else %&gt; &lt;% end %&gt;&lt;%= link_to_task(dependency) %&gt;
-    &lt;input name=&quot;dependencies[]&quot; type=&quot;hidden&quot; value=&quot;&lt;%=dependency.task_num%&gt;&quot;&gt;
-    &lt;span class=&quot;divider&quot;&gt;&lt;/span&gt;
+    &lt;img src=&quot;/images/tick.png&quot; border=0&gt;
+  &lt;% end %&gt;
+  &lt;%= link_to_task(dependency) %&gt;
+  &lt;%= hidden_field_tag :dependencies, dependency.task_num, :index =&gt; nil %&gt;
+  &lt;span class=&quot;divider&quot;&gt;&lt;/span&gt;
 &lt;/div&gt;</diff>
      <filename>app/views/tasks/_dependency.html.erb</filename>
    </modified>
    <modified>
      <diff>@@ -43,5 +43,3 @@
   });
   jQuery('#comment').focus();
 &lt;/script&gt;
-
-</diff>
      <filename>app/views/tasks/_form.html.erb</filename>
    </modified>
    <modified>
      <diff>@@ -1,3 +1,5 @@
+&lt;% cache(current_task_filter) do -%&gt;
+
 &lt;%= render(:partial =&gt; &quot;search_filter&quot;, :locals =&gt; { :redirect_params =&gt; { :tag =&gt; params[:tag] }}) %&gt;
 
 &lt;div id=&quot;task_list&quot;&gt;
@@ -19,9 +21,12 @@
       &lt;/tr&gt;
     &lt;/thead&gt;
     &lt;tbody&gt;
-      &lt;%= render :partial =&gt; &quot;task_row_v2&quot;, :collection =&gt; @tasks %&gt;
+      &lt;%= render :partial =&gt; &quot;task_row_v2&quot;, :collection =&gt; current_task_filter.tasks %&gt;
     &lt;/tbody&gt;
   &lt;/table&gt;
 &lt;/div&gt;
 
 &lt;%= sortable_table(&quot;#list&quot;, session[:filter_sort]) -%&gt;
+&lt;%= javascript_tag &quot;jQuery('.date_to_words').dateToWords()&quot; %&gt;
+
+&lt;% end -%&gt;</diff>
      <filename>app/views/tasks/_task_list_v2.html.erb</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,6 @@
 &lt;% task = task_row_v2 -%&gt;
+
+&lt;% cache([ task, current_user.id ]) do -%&gt;
 &lt;% customer = (task.customers.first || task.project.customer) -%&gt;
 
 &lt;%= task_row_tr_tag(task) %&gt;
@@ -45,7 +47,7 @@
 
   &lt;td class=&quot;tooltip&quot; title=&quot;&lt;%= task_tooltip([ [ &quot;Due Date&quot;, formatted_date_for_current_user(task.due_date) ] ]) %&gt;&quot;&gt;
     &lt;span class=&quot;sort_hint&quot;&gt;&lt;%= task.due_date %&gt;&lt;/span&gt;
-    &lt;%= &quot;#{ due_in_words(task) }&quot;.gsub(&quot;\[&quot;, &quot;&quot;).gsub(&quot;\]&quot;, &quot;&quot;) %&gt;
+    &lt;span class=&quot;date_to_words&quot;&gt;&lt;%= task.due_at.to_date if task.due_at %&gt;&lt;/span&gt;
   &lt;/td&gt;
 
   &lt;td&gt;
@@ -57,3 +59,5 @@
   &lt;/td&gt;
 
 &lt;/tr&gt;
+
+&lt;% end -%&gt;</diff>
      <filename>app/views/tasks/_task_row_v2.html.erb</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,8 @@
-&lt;% form_tag({ :action =&gt; 'update', :id =&gt; @task}, { :multipart =&gt; &quot;true&quot;, :id =&gt; &quot;taskform&quot; }) do %&gt;
-  &lt;%= render :partial =&gt; &quot;form&quot; %&gt;
-&lt;% end %&gt;
+&lt;% cache([ &quot;edit_form&quot;, @task, current_user.id ]) do -%&gt;
+
+  &lt;% form_tag({ :action =&gt; 'update', :id =&gt; @task}, { :multipart =&gt; &quot;true&quot;, :id =&gt; &quot;taskform&quot; }) do %&gt;
+    &lt;%= render :partial =&gt; &quot;form&quot; %&gt;
+  &lt;% end %&gt;
+
+&lt;% end -%&gt;
 </diff>
      <filename>app/views/tasks/edit.html.erb</filename>
    </modified>
    <modified>
      <diff>@@ -11,7 +11,8 @@ config.whiny_nils = true
 
 # Show full error reports and disable caching
 config.action_controller.consider_all_requests_local = true
-config.action_controller.perform_caching             = false
+config.action_controller.perform_caching             = false 
+#config.action_controller.perform_caching             = true 
 config.action_view.debug_rjs                         = false
 
 # Don't care if the mailer can't send</diff>
      <filename>config/environments/development.rb</filename>
    </modified>
    <modified>
      <diff>@@ -194,20 +194,70 @@ jQuery(document).ready(function() {
 	    ui.element.css(&quot;width&quot;, &quot;&quot;);
 	}
     });
+
+
 });
 
+jQuery.fn.dateToWords = function() {
+    return this.each(function() {
+	dateToWords(jQuery(this))
+    });
+}
+
+function dateToWords(elem) {
+    var date = elem.text();
+    var text = date;
+    var className = null;
+
+    date = jQuery.datepicker.parseDate(&quot;yy-mm-dd&quot;, date)
+
+    if (date != null) {
+	var diff = (((new Date()).getTime() - date.getTime()) / 1000);
+	var dayDiff = Math.floor(diff / 86400);
+
+	if (isNaN(dayDiff)) {
+	    text = date;
+	}
+	else if (dayDiff == -1) {
+	    text = &quot;Tomorrow&quot;;
+	    className = &quot;due_tomorrow&quot;;
+	}
+	else if (dayDiff == 0) {
+	    text = &quot;Today&quot;;
+	    className = &quot;due&quot;;
+	}
+	else if (dayDiff == 1) {
+	    text = &quot;Yesterday&quot;
+	    className = &quot;due_overdue&quot;;
+	}
+	else if (dayDiff &lt; 0) {
+	    dayDiff = Math.abs(dayDiff);
+	    text = dayDiff + &quot; days&quot;
+	    className = dayDiff &gt;= 7 ? &quot;due_distant&quot; : &quot;due_soon&quot;;
+	}
+	else if (dayDiff &gt; 0) {
+	    text = dayDiff + &quot; days ago&quot;
+	    className = &quot;due_overdue&quot;;
+	}
+    }
+
+    elem.addClass(className);
+    elem.text(text);
+}
+
+
 /*
   Loads the task information for the task taskNum and displays 
 it in the current page.
 */
 function showTaskInPage(taskNum) {
     jQuery(&quot;#task_list tr.selected&quot;).removeClass(&quot;selected&quot;);
-	jQuery(&quot;#task_list #task_row_&quot; + taskNum).addClass(&quot;selected&quot;);
+    jQuery(&quot;#task_list #task_row_&quot; + taskNum).addClass(&quot;selected&quot;);
 
-	jQuery(&quot;#task&quot;).fadeOut();
+    jQuery(&quot;#task&quot;).fadeOut();
     jQuery.get(&quot;/tasks/edit/&quot; + taskNum, {}, function(data) {
-		jQuery(&quot;#task&quot;).html(data);
-		jQuery(&quot;#task&quot;).fadeIn('slow');
+	jQuery(&quot;#task&quot;).html(data);
+	jQuery(&quot;#task&quot;).fadeIn('slow');
     });
 }
 
@@ -860,4 +910,5 @@ function setPageTarget(evt, selected) {
 
     jQuery(&quot;#page_notable_id&quot;).val(id);
     jQuery(&quot;#page_notable_type&quot;).val(type);
-}
\ No newline at end of file
+}
+</diff>
      <filename>public/javascripts/application.js</filename>
    </modified>
    <modified>
      <diff>@@ -33,42 +33,6 @@ class TasksControllerTest &lt; ActionController::TestCase
     assert_response :success
   end
 
-  test &quot;/list_old should render :success&quot; do
-    company = companies(&quot;cit&quot;)
-
-    # need to create a task to ensure the task partials get rendered
-    task = Task.new(:name =&gt; &quot;Test&quot;, :project_id =&gt; company.projects.last.id)
-    task.company = company
-    task.save!
-
-    get :list_old
-    assert_response :success
-
-    # ensure at least 1 task was rendered
-    group = assigns[&quot;groups&quot;].first
-    assert group.length &gt; 0
-  end
-
-  test &quot;/list_old should works with tags&quot; do
-    company = companies(&quot;cit&quot;)
-    user = company.users.first
-    @request.session[:filter_user] = [ user.id.to_s ]
-
-    # need to create a task to ensure the task partials get rendered
-    task = Task.new(:name =&gt; &quot;Test&quot;, :project_id =&gt; company.projects.last.id)
-    task.company = company
-    task.set_tags = &quot;tag1&quot;
-    task.task_owners.build(:user =&gt; user)
-    task.save!
-
-    get :list_old, :tag =&gt; &quot;tag1&quot;
-    assert_response :success
-
-    # ensure at least 1 task was rendered
-    group = assigns[&quot;groups&quot;].first
-    assert group.length &gt; 0
-  end
-
   test &quot;/list should render :success&quot; do
     company = companies(&quot;cit&quot;)
 
@@ -79,8 +43,8 @@ class TasksControllerTest &lt; ActionController::TestCase
 
     get :list
     assert_response :success
-
-    assert assigns[&quot;tasks&quot;].include?(task)
+    assert TaskFilter.system_filter(@user).tasks.include?(task)
+#    assert assigns[&quot;tasks&quot;].include?(task)
   end
 
   test &quot;/update should render form ok when failing update&quot; do</diff>
      <filename>test/functional/tasks_controller_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -25,7 +25,8 @@ class TaskFilterQualifierTest &lt; ActiveSupport::TestCase
 
     should &quot;set task from task_num if use can view task&quot; do
       @qualifier.task_num = @task.task_num
-      @qualifier.save!
+#      @qualifier.save!
+      @qualifier.valid?
       assert_equal @task, @qualifier.qualifiable
     end
 </diff>
      <filename>test/unit/task_filter_qualifier_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -29,6 +29,8 @@ def self.config
 end
 
 def self.send(data,chan = [&quot;default&quot;])
+  return if RAILS_ENV==&quot;test&quot;
+
   begin
     @socket = TCPSocket.new(config[&quot;PUSH_HOST&quot;], config[&quot;PUSH_PORT&quot;])
     fc = { :message =&gt; data, :secret =&gt; config[&quot;PUSH_SECRET&quot;], :broadcast =&gt; 1, :channels =&gt; chan}</diff>
      <filename>vendor/plugins/juggernaut/lib/juggernaut.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>6d55c48d89c6cbeead9765d9092fbc575ccc8764</id>
    </parent>
    <parent>
      <id>393eb68bf1771265c9d4b1db84688e9379c48989</id>
    </parent>
  </parents>
  <author>
    <name>Ari Maniatis</name>
    <email>ari@ish.com.au</email>
  </author>
  <url>http://github.com/ari/clockingit/commit/d04aeb29660e801536b1e6ef6efb7e73d8b8f11c</url>
  <id>d04aeb29660e801536b1e6ef6efb7e73d8b8f11c</id>
  <committed-date>2009-11-05T02:04:20-08:00</committed-date>
  <authored-date>2009-11-05T02:04:20-08:00</authored-date>
  <message>Merge branch 'master' of git://github.com/bradx3/clockingit</message>
  <tree>097c8b61040d6cc866f3e9a2c013ec3624f0711c</tree>
  <committer>
    <name>Ari Maniatis</name>
    <email>ari@ish.com.au</email>
  </committer>
</commit>
