diff --git a/tracks/app/controllers/application.rb b/tracks/app/controllers/application.rb
index 52d4b533..bc4c1610 100644
--- a/tracks/app/controllers/application.rb
+++ b/tracks/app/controllers/application.rb
@@ -28,7 +28,7 @@ class ApplicationController < ActionController::Base
def set_charset
headers["Content-Type"] ||= "text/html; charset=UTF-8"
end
-
+
def set_session_expiration
# http://wiki.rubyonrails.com/rails/show/HowtoChangeSessionOptions
unless session == nil
@@ -56,13 +56,13 @@ class ApplicationController < ActionController::Base
def rescue_action(exception)
log_error(exception) if logger
- respond_to do |wants|
- wants.html do
+ respond_to do |format|
+ format.html do
notify :warning, "An error occurred on the server."
render :action => "index"
end
- wants.js { render :action => 'error' }
- wants.xml { render :text => 'An error occurred on the server.' + $! }
+ format.js { render :action => 'error' }
+ format.xml { render :text => 'An error occurred on the server.' + $! }
end
end
diff --git a/tracks/app/controllers/contexts_controller.rb b/tracks/app/controllers/contexts_controller.rb
index b92d7107..d18883ed 100644
--- a/tracks/app/controllers/contexts_controller.rb
+++ b/tracks/app/controllers/contexts_controller.rb
@@ -41,9 +41,9 @@ class ContextsController < ApplicationController
end
@saved = @context.save
@context_not_done_counts = { @context.id => 0 }
- respond_to do |wants|
- wants.js
- wants.xml do
+ respond_to do |format|
+ format.js
+ format.xml do
if @context.new_record? && params_are_invalid
render_failure "Expected post format is valid xml like so: context name."
elsif @context.new_record?
diff --git a/tracks/app/controllers/mobile_controller.rb b/tracks/app/controllers/mobile_controller.rb
deleted file mode 100644
index 90459347..00000000
--- a/tracks/app/controllers/mobile_controller.rb
+++ /dev/null
@@ -1,89 +0,0 @@
-class MobileController < ApplicationController
-
- layout 'mobile'
-
- before_filter :init, :except => :update
-
- # Plain list of all next actions, paginated 6 per page
- # Sorted by due date, then creation date
- #
- def index
- @page_title = @desc = "All actions"
- @todos_pages, @todos = paginate( :todos, :order => 'due IS NULL, due ASC, created_at ASC',
- :conditions => ['user_id = ? and state = ?', @user.id, "active"],
- :per_page => 6 )
- @count = @all_todos.reject { |x| !x.active? || x.context.hide? }.size
- end
-
- def detail
- @item = check_user_return_item
- @place = @item.context.id
- end
-
- def update
- if params[:id]
- @item = check_user_return_item
- @item.update_attributes params[:todo]
- if params[:todo][:state] == "1"
- @item.state = "completed"
- else
- @item.state = "active"
- end
- else
- params[:todo][:user_id] = @user.id
- @item = Todo.new(params[:todo]) if params[:todo]
- end
-
- if @item.save
- redirect_to :action => 'index'
- else
- self.init
- if params[:id]
- render :partial => 'mobile_edit'
- else
- render :action => 'show_add_form'
- end
- end
- end
-
- def show_add_form
- # Just render the view
- end
-
- def filter
- @type = params[:type]
- case params[:type]
- when 'context'
- @context = Context.find( params[:context][:id] )
- @page_title = @desc = "#{@context.name}"
- @todos = Todo.find( :all, :order => 'due IS NULL, due ASC, created_at ASC',
- :conditions => ['user_id = ? and state = ? and context_id = ?', @user.id, "active", @context.id] )
- @count = @all_todos.reject { |x| x.completed? || x.context_id != @context.id }.size
- when 'project'
- @project = Project.find( params[:project][:id] )
- @page_title = @desc = "#{@project.name}"
- @todos = Todo.find( :all, :order => 'due IS NULL, due ASC, created_at ASC',
- :conditions => ['user_id = ? and state = ? and project_id = ?', @user.id, "active", @project.id] )
- @count = @all_todos.reject { |x| x.completed? || x.project_id != @project.id }.size
- end
- end
-
- protected
-
- def check_user_return_item
- item = Todo.find( params['id'] )
- if @user == item.user
- return item
- else
- notify :warning, "Item and session user mis-match: #{item.user.name} and #{@user.name}!"
- render_text ""
- end
- end
-
- def init
- @contexts = @user.contexts.find(:all, :order => 'position ASC')
- @projects = @user.projects.find_in_state(:all, :active, :order => 'position ASC')
- @all_todos = @user.todos.find(:all, :conditions => ['state = ? or state = ?', "active", "completed"])
- end
-
-end
diff --git a/tracks/app/controllers/notes_controller.rb b/tracks/app/controllers/notes_controller.rb
index 03447eb7..c2e7fbdd 100644
--- a/tracks/app/controllers/notes_controller.rb
+++ b/tracks/app/controllers/notes_controller.rb
@@ -3,9 +3,9 @@ class NotesController < ApplicationController
def index
@all_notes = @user.notes
@page_title = "TRACKS::All notes"
- respond_to do |wants|
- wants.html
- wants.xml { render :xml => @all_notes.to_xml( :except => :user_id ) }
+ respond_to do |format|
+ format.html
+ format.xml { render :xml => @all_notes.to_xml( :except => :user_id ) }
end
end
diff --git a/tracks/app/controllers/projects_controller.rb b/tracks/app/controllers/projects_controller.rb
index f9bee11f..cae0a7d2 100644
--- a/tracks/app/controllers/projects_controller.rb
+++ b/tracks/app/controllers/projects_controller.rb
@@ -53,9 +53,9 @@ class ProjectsController < ApplicationController
@project_not_done_counts = { @project.id => 0 }
@active_projects_count = @user.projects.count(:conditions => "state = 'active'")
@contexts = @user.contexts
- respond_to do |wants|
- wants.js
- wants.xml do
+ respond_to do |format|
+ format.js
+ format.xml do
if @project.new_record? && params_are_invalid
render_failure "Expected post format is valid xml like so: project name."
elsif @project.new_record?
diff --git a/tracks/app/controllers/todos_controller.rb b/tracks/app/controllers/todos_controller.rb
index 36575c90..2925f76d 100644
--- a/tracks/app/controllers/todos_controller.rb
+++ b/tracks/app/controllers/todos_controller.rb
@@ -2,13 +2,17 @@ class TodosController < ApplicationController
helper :todos
- append_before_filter :init, :except => [ :destroy, :completed, :completed_archive, :check_deferred ]
- append_before_filter :get_todo_from_params, :only => [ :edit, :toggle_check, :show, :update, :destroy ]
skip_before_filter :login_required, :only => [:index]
prepend_before_filter :login_or_feed_token_required, :only => [:index]
+ append_before_filter :init, :except => [ :destroy, :completed, :completed_archive, :check_deferred ]
+ append_before_filter :get_todo_from_params, :only => [ :edit, :toggle_check, :show, :update, :destroy ]
+
+ prepend_before_filter :enable_mobile_content_negotiation
+ after_filter :restore_content_type_for_mobile
+
session :off, :only => :index, :if => Proc.new { |req| is_feed_request(req) }
- layout 'standard'
+ layout proc{ |controller| controller.mobile? ? "mobile" : "standard" }
def index
@projects = @user.projects.find(:all, :include => [ :todos ])
@@ -17,20 +21,29 @@ class TodosController < ApplicationController
@contexts_to_show = @contexts.reject {|x| x.hide? }
respond_to do |format|
- format.html &render_todos_html
- format.xml { render :action => 'list.rxml', :layout => false }
+ format.html &render_todos_html
+ format.m &render_todos_mobile
+ format.xml { render :action => 'list.rxml', :layout => false }
format.rss &render_rss_feed
format.atom &render_atom_feed
format.text &render_text_feed
format.ics &render_ical_feed
end
end
-
+
+ def new
+ @projects = @user.projects.find(:all)
+ @contexts = @user.contexts.find(:all)
+ respond_to do |format|
+ format.m { render :action => "new_mobile" }
+ end
+ end
+
def create
@todo = @user.todos.build
p = params['request'] || params
- if p['todo']['show_from']
+ if p['todo']['show_from'] && !mobile?
p['todo']['show_from'] = parse_date_per_user_prefs(p['todo']['show_from'])
end
@@ -60,34 +73,46 @@ class TodosController < ApplicationController
end
if @todo.due?
- @todo.due = parse_date_per_user_prefs(p['todo']['due'])
+ @todo.due = parse_date_per_user_prefs(p['todo']['due']) unless mobile?
else
@todo.due = ""
end
@saved = @todo.save
if @saved
- @todo.tag_with(params[:tag_list],@user)
+ @todo.tag_with(params[:tag_list],@user) if params[:tag_list]
@todo.reload
end
- respond_to do |wants|
- wants.html { redirect_to :action => "index" }
- wants.js do
+ respond_to do |format|
+ format.html { redirect_to :action => "index" }
+ format.m do
if @saved
- determine_down_count
+ redirect_to :action => "index", :format => :m
+ else
+ render :action => "new", :format => :m
end
+ end
+ format.js do
+ determine_down_count if @saved
render :action => 'create'
end
- wants.xml { render :xml => @todo.to_xml( :root => 'todo', :except => :user_id ) }
+ format.xml { render :xml => @todo.to_xml( :root => 'todo', :except => :user_id ) }
end
end
def edit
+ @projects = @user.projects.find(:all)
+ @contexts = @user.contexts.find(:all)
end
def show
respond_to do |format|
+ format.m do
+ @projects = @user.projects.find(:all)
+ @contexts = @user.contexts.find(:all)
+ render :action => 'show_mobile'
+ end
format.xml { render :xml => @todo.to_xml( :root => 'todo', :except => :user_id ) }
end
end
@@ -120,7 +145,7 @@ class TodosController < ApplicationController
end
def update
- @todo.tag_with(params[:tag_list],@user)
+ @todo.tag_with(params[:tag_list],@user) if params[:tag_list]
@original_item_context_id = @todo.context_id
@original_item_project_id = @todo.project_id
@original_item_was_deferred = @todo.deferred?
@@ -160,6 +185,10 @@ class TodosController < ApplicationController
params['todo']['show_from'] = parse_date_per_user_prefs(params['todo']['show_from'])
end
+ if params['done'] == '1' && !@todo.completed?
+ @todo.complete!
+ end
+
@saved = @todo.update_attributes params["todo"]
@context_changed = @original_item_context_id != @todo.context_id
@todo_was_activated_from_deferred_state = @original_item_was_deferred && @todo.active?
@@ -167,6 +196,16 @@ class TodosController < ApplicationController
@project_changed = @original_item_project_id != @todo.project_id
if (@project_changed && !@original_item_project_id.nil?) then @remaining_undone_in_project = @user.projects.find(@original_item_project_id).not_done_todo_count; end
determine_down_count
+ respond_to do |format|
+ format.js
+ format.m do
+ if @saved
+ redirect_to formatted_todos_path(:m)
+ else
+ render :action => "edit", :format => :m
+ end
+ end
+ end
end
def destroy
@@ -175,9 +214,9 @@ class TodosController < ApplicationController
@project_id = @todo.project_id
@saved = @todo.destroy
- respond_to do |wants|
+ respond_to do |format|
- wants.html do
+ format.html do
if @saved
notify :notice, "Successfully deleted next action", 2.0
redirect_to :action => 'index'
@@ -185,9 +224,9 @@ class TodosController < ApplicationController
notify :error, "Failed to delete the action", 2.0
redirect_to :action => 'index'
end
- end
+ end
- wants.js do
+ format.js do
if @saved
determine_down_count
source_view do |from|
@@ -199,7 +238,7 @@ class TodosController < ApplicationController
render
end
- wants.xml { render :text => '200 OK. Action deleted.', :status => 200 }
+ format.xml { render :text => '200 OK. Action deleted.', :status => 200 }
end
end
@@ -236,6 +275,16 @@ class TodosController < ApplicationController
end
end
+ def filter_to_context
+ context = @user.contexts.find(params['context']['id'])
+ redirect_to formatted_context_todos_path(context, :m)
+ end
+
+ def filter_to_project
+ project = @user.projects.find(params['project']['id'])
+ redirect_to formatted_project_todos_path(project, :m)
+ end
+
# /todos/tag/[tag_name] shows all the actions tagged with tag_name
#
def tag
@@ -266,15 +315,47 @@ class TodosController < ApplicationController
end
- private
+ # Here's the concept behind this "mobile content negotiation" hack:
+ # In addition to the main, AJAXy Web UI, Tracks has a lightweight
+ # low-feature 'mobile' version designed to be suitablef or use
+ # from a phone or PDA. It makes some sense that tne pages of that
+ # mobile version are simply alternate representations of the same
+ # Todo resources. The implementation goal was to treat mobile
+ # as another format and be able to use respond_to to render both
+ # versions. Unfortunately, I ran into a lot of trouble simply
+ # registering a new mime type 'text/html' with format :m because
+ # :html already is linked to that mime type and the new
+ # registration was forcing all html requests to be rendered in
+ # the mobile view. The before_filter and after_filter hackery
+ # below accomplishs that implementation goal by using a 'fake'
+ # mime type during the processing and then setting it to
+ # 'text/html' in an 'after_filter' -LKM 2007-04-01
+ def mobile?
+ return params[:format] == 'm' || response.content_type == MOBILE_CONTENT_TYPE
+ end
+ def enable_mobile_content_negotiation
+ if mobile?
+ request.accepts.unshift(Mime::Type::lookup(MOBILE_CONTENT_TYPE))
+ end
+ end
+
+ def restore_content_type_for_mobile
+ if mobile?
+ response.content_type = 'text/html'
+ end
+ end
+
+ private
+
+
def get_todo_from_params
@todo = @user.todos.find(params['id'])
end
def init
@source_view = params['_source_view'] || 'todo'
- init_data_for_sidebar
+ init_data_for_sidebar unless mobile?
init_todos
end
@@ -321,13 +402,13 @@ class TodosController < ApplicationController
def with_parent_resource_scope(&block)
if (params[:context_id])
- context = @user.contexts.find_by_params(params)
- Todo.with_scope :find => {:conditions => ['todos.context_id = ?', context.id]} do
+ @context = @user.contexts.find_by_params(params)
+ Todo.with_scope :find => {:conditions => ['todos.context_id = ?', @context.id]} do
yield
end
elsif (params[:project_id])
- project = @user.projects.find_by_params(params)
- Todo.with_scope :find => {:conditions => ['todos.project_id = ?', project.id]} do
+ @project = @user.projects.find_by_params(params)
+ Todo.with_scope :find => {:conditions => ['todos.project_id = ?', @project.id]} do
yield
end
else
@@ -350,12 +431,26 @@ class TodosController < ApplicationController
with_feed_query_scope do
with_parent_resource_scope do
with_limit_scope do
+
+ if mobile?
+
+ @todos, @page = @user.todos.paginate(:all,
+ :conditions => ['state = ?', 'active' ], :include => [:context],
+ :order => 'due IS NULL, due ASC, todos.created_at ASC',
+ :page => params[:page], :per_page => 6)
+ @pagination_params = { :format => :m }
+ @pagination_params[:context_id] = @context.to_param if @context
+ @pagination_params[:project_id] = @project.to_param if @project
+
+ else
+
+ # Exclude hidden projects from count on home page
+ @todos = @user.todos.find(:all, :conditions => ['todos.state = ? or todos.state = ?', 'active', 'complete'], :include => [ :project, :context, :tags ])
- # Exclude hidden projects from count on home page
- @todos = @user.todos.find(:all, :conditions => ['todos.state = ? or todos.state = ?', 'active', 'complete'], :include => [ :project, :context, :tags ])
-
- # Exclude hidden projects from the home page
- @not_done_todos = @user.todos.find(:all, :conditions => ['todos.state = ?', 'active'], :order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC", :include => [ :project, :context, :tags ])
+ # Exclude hidden projects from the home page
+ @not_done_todos = @user.todos.find(:all, :conditions => ['todos.state = ?', 'active'], :order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC", :include => [ :project, :context, :tags ])
+
+ end
end
end
@@ -415,6 +510,23 @@ class TodosController < ApplicationController
render
end
end
+
+ def render_todos_mobile
+ lambda do
+ @page_title = "All actions"
+ if @context
+ @page_title += " in context #{@context.name}"
+ @down_count = @context.not_done_todo_count
+ elsif @project
+ @page_title += " in project #{@project.name}"
+ @down_count = @project.not_done_todo_count
+ else
+ determine_down_count
+ end
+
+ render :action => 'index_mobile'
+ end
+ end
def render_rss_feed
lambda do
diff --git a/tracks/app/helpers/todos_helper.rb b/tracks/app/helpers/todos_helper.rb
index 7c26ed62..77d79673 100644
--- a/tracks/app/helpers/todos_helper.rb
+++ b/tracks/app/helpers/todos_helper.rb
@@ -185,6 +185,11 @@ module TodosHelper
split_notes = notes.split(/\n/)
joined_notes = split_notes.join("\\n")
end
+
+ def formatted_pagination(total, per_page)
+ s = will_paginate(@down_count, 6)
+ (s.gsub /(<\/[^<]+>)/, '\1 ').chomp(' ')
+ end
private
diff --git a/tracks/app/views/mobile/_mobile_actions.rhtml b/tracks/app/views/mobile/_mobile_actions.rhtml
deleted file mode 100644
index a19d5278..00000000
--- a/tracks/app/views/mobile/_mobile_actions.rhtml
+++ /dev/null
@@ -1,35 +0,0 @@
-<%= render_flash %>
-<% if @todos.length == 0 -%>
-
There are no incomplete actions in this <%= @type %>
-<% else -%>
-
-<% for todo in @todos -%>
--
- <%= link_to "»", :controller => 'mobile', :action => 'detail', :id => todo.id %>
- <% if todo.due? -%>
- <%= due_date_mobile(todo.due) %>
- <% end -%>
- <%= todo.description %>
- (<%= todo.context.name %>)
-<% end -%>
-
-
- <% if !@todos_pages.nil? -%>
- <% if @todos_pages.length > 1 -%>
-
- Pages: <%= pagination_links( @todos_pages, :always_show_anchors => true ) %>
- <% end -%>
- <% end -%>
-<% end -%>
-
-<% form_tag( { :action => "filter", :type => "context" } ) do -%>
-<%= collection_select( "context", "id", @contexts, "id", "name",
- { :include_blank => true } ) %>
-<%= submit_tag( value = "Go" ) %>
-<% end -%>
-
-<% form_tag( {:action => "filter", :type => "project" }) do -%>
-<%= collection_select( "project", "id", @projects, "id", "name",
- { :include_blank => true } ) %>
-<%= submit_tag( value = "Go" ) %>
-<% end -%>
\ No newline at end of file
diff --git a/tracks/app/views/mobile/detail.rhtml b/tracks/app/views/mobile/detail.rhtml
deleted file mode 100644
index 091bee4e..00000000
--- a/tracks/app/views/mobile/detail.rhtml
+++ /dev/null
@@ -1,4 +0,0 @@
-<% form_tag :action => 'update', :id => @item.id do -%>
- <%= render :partial => 'mobile_edit' %>
-<% end -%>
-<%= button_to "Back", :controller => 'mobile', :action => 'index' %>
\ No newline at end of file
diff --git a/tracks/app/views/mobile/filter.rhtml b/tracks/app/views/mobile/filter.rhtml
deleted file mode 100644
index 23c6f607..00000000
--- a/tracks/app/views/mobile/filter.rhtml
+++ /dev/null
@@ -1,6 +0,0 @@
-<%= @count.to_s %> <%= @desc %>
-<%= link_to "+", :controller => 'mobile', :action => 'add_action' %>
-
-<%= render :partial => 'mobile_actions' %>
-
-<%= link_to "View All", :controller => 'mobile', :action => 'index' %>
\ No newline at end of file
diff --git a/tracks/app/views/mobile/index.rhtml b/tracks/app/views/mobile/index.rhtml
deleted file mode 100644
index 8fab21bd..00000000
--- a/tracks/app/views/mobile/index.rhtml
+++ /dev/null
@@ -1,5 +0,0 @@
-<%= @count.to_s %> <%= @desc %>
-<%= link_to "+", :controller => 'mobile', :action => 'add_action' %>
-
-<%= render :partial => 'mobile_actions' %>
-<%= link_to "Logout", :controller => 'login', :action => 'logout' %>
\ No newline at end of file
diff --git a/tracks/app/views/mobile/show_add_form.rhtml b/tracks/app/views/mobile/show_add_form.rhtml
deleted file mode 100644
index 33530d0f..00000000
--- a/tracks/app/views/mobile/show_add_form.rhtml
+++ /dev/null
@@ -1,4 +0,0 @@
-<% form_tag :action => 'update' do %>
- <%= render :partial => 'mobile_edit' %>
-<% end -%>
-<%= button_to "Back", :controller => 'mobile', :action => 'index' %>
\ No newline at end of file
diff --git a/tracks/app/views/shared/_footer.rhtml b/tracks/app/views/shared/_footer.rhtml
index bb7dc81b..7a78c069 100644
--- a/tracks/app/views/shared/_footer.rhtml
+++ b/tracks/app/views/shared/_footer.rhtml
@@ -1,3 +1,3 @@
diff --git a/tracks/app/views/mobile/_mobile_edit.rhtml b/tracks/app/views/todos/_edit_mobile.rhtml
similarity index 87%
rename from tracks/app/views/mobile/_mobile_edit.rhtml
rename to tracks/app/views/todos/_edit_mobile.rhtml
index 23648735..1ef0c8e7 100644
--- a/tracks/app/views/mobile/_mobile_edit.rhtml
+++ b/tracks/app/views/todos/_edit_mobile.rhtml
@@ -2,8 +2,8 @@
<%= error_messages_for("todo") %>
<% this_year = user_time.to_date.strftime("%Y").to_i -%>
-
-<%= check_box( "todo", "state", "tabindex" => 1) %>
+
+<%= check_box_tag("done", 1, @todo && @todo.completed?, "tabindex" => 1) %>
<%= text_field( "todo", "description", "tabindex" => 2) %>
@@ -18,4 +18,3 @@
<%= date_select("todo", "show_from", :order => [:day, :month, :year],
:start_year => this_year, :include_blank => true) %>
-
\ No newline at end of file
diff --git a/tracks/app/views/todos/_mobile_actions.rhtml b/tracks/app/views/todos/_mobile_actions.rhtml
new file mode 100644
index 00000000..7f0bcec9
--- /dev/null
+++ b/tracks/app/views/todos/_mobile_actions.rhtml
@@ -0,0 +1,33 @@
+<%= render_flash %>
+<% if @todos.length == 0 -%>
+ There are no incomplete actions in this <%= @type %>
+<% else -%>
+
+ <% for todo in @todos -%>
+ -
+ <%= link_to "»", formatted_todo_path(todo, :m) %>
+ <% if todo.due? -%>
+ <%= due_date_mobile(todo.due) %>
+ <% end -%>
+ <%= todo.description %>
+ (<%= todo.context.name %>)
+
+ <% end -%>
+
+ <% if @down_count > 6 -%>
+
+ Pages: <%= formatted_pagination(@down_count, 6) %>
+ <% end -%>
+<% end -%>
+
+<% form_tag( formatted_filter_to_context_todos_path(:m), :method => :post ) do -%>
+<%= collection_select( "context", "id", @contexts, "id", "name",
+ { :include_blank => true } ) %>
+<%= submit_tag( "Go", :id => 'change_context' ) %>
+<% end -%>
+
+<% form_tag( formatted_filter_to_project_todos_path(:m), :method => :post ) do -%>
+<%= collection_select( "project", "id", @projects, "id", "name",
+ { :include_blank => true } ) %>
+<%= submit_tag( "Go", :id => 'change_project' ) %>
+<% end -%>
\ No newline at end of file
diff --git a/tracks/app/views/todos/index_mobile.rhtml b/tracks/app/views/todos/index_mobile.rhtml
new file mode 100644
index 00000000..94b91b1a
--- /dev/null
+++ b/tracks/app/views/todos/index_mobile.rhtml
@@ -0,0 +1,6 @@
+<%= @down_count %> <%= @page_title %>
+<%= link_to "+", formatted_new_todo_path(:m) %>
+
+<%= render :partial => 'mobile_actions' %>
+
+<%= link_to "Logout", :controller => 'login', :action => 'logout' %>
\ No newline at end of file
diff --git a/tracks/app/views/todos/new_mobile.rhtml b/tracks/app/views/todos/new_mobile.rhtml
new file mode 100644
index 00000000..9ce1090a
--- /dev/null
+++ b/tracks/app/views/todos/new_mobile.rhtml
@@ -0,0 +1,5 @@
+<% form_tag formatted_todos_path(:m), :method => :post do %>
+ <%= render :partial => 'edit_mobile' %>
+
+<% end -%>
+<%= link_to "Back", formatted_todos_path(:m) %>
\ No newline at end of file
diff --git a/tracks/app/views/todos/show_mobile.rhtml b/tracks/app/views/todos/show_mobile.rhtml
new file mode 100644
index 00000000..8d9a04f7
--- /dev/null
+++ b/tracks/app/views/todos/show_mobile.rhtml
@@ -0,0 +1,5 @@
+<% form_tag formatted_todo_path(@todo, :m), :method => :put do %>
+ <%= render :partial => 'edit_mobile' %>
+
+<% end -%>
+<%= link_to "Back", formatted_todos_path(:m) %>
\ No newline at end of file
diff --git a/tracks/config/environment.rb.tmpl b/tracks/config/environment.rb.tmpl
index 8feebe5e..b08d5543 100644
--- a/tracks/config/environment.rb.tmpl
+++ b/tracks/config/environment.rb.tmpl
@@ -80,3 +80,6 @@ if (AUTHENTICATION_SCHEMES.include? 'open_id')
#requires ruby-openid gem to be installed
end
+
+MOBILE_CONTENT_TYPE = 'tracks/mobile'
+Mime::Type.register(MOBILE_CONTENT_TYPE, :m)
diff --git a/tracks/config/routes.rb b/tracks/config/routes.rb
index 6dff7603..f516d944 100644
--- a/tracks/config/routes.rb
+++ b/tracks/config/routes.rb
@@ -1,10 +1,6 @@
ActionController::Routing::Routes.draw do |map|
UJS::routes
- # Mobile/lite version
- map.connect 'mobile', :controller => 'mobile', :action => 'index'
- map.connect 'mobile/add_action', :controller => 'mobile', :action => 'show_add_form'
-
# Login Routes
map.connect 'login', :controller => 'login', :action => 'login'
map.connect 'logout', :controller => 'login', :action => 'logout'
@@ -13,30 +9,33 @@ ActionController::Routing::Routes.draw do |map|
:member => {:change_password => :get, :update_password => :post,
:change_auth_type => :get, :update_auth_type => :post, :complete => :get,
:refresh_token => :post }
- map.with_options :controller => "users" do |users|
- users.signup 'signup', :action => "new"
- end
+ map.with_options :controller => "users" do |users|
+ users.signup 'signup', :action => "new"
+ end
# Context Routes
map.resources :contexts, :collection => {:order => :post} do |contexts|
- contexts.resources :todos
+ contexts.resources :todos, :name_prefix => "context_"
end
# Projects Routes
map.resources :projects, :collection => {:order => :post} do |projects|
- projects.resources :todos
+ projects.resources :todos, :name_prefix => "project_"
end
# ToDo Routes
map.resources :todos,
:member => {:toggle_check => :post},
- :collection => {:check_deferred => :post}
+ :collection => {:check_deferred => :post, :filter_to_context => :post, :filter_to_project => :post}
map.with_options :controller => "todos" do |todos|
todos.home '', :action => "index"
todos.tickler 'tickler', :action => "list_deferred"
todos.done 'done', :action => "completed"
todos.done_archive 'done/archive', :action => "completed_archive"
todos.tag 'todos/tag/:name', :action => "tag"
+ todos.mobile 'mobile', :action => "index", :format => 'm'
+ todos.mobile_abbrev 'm', :action => "index", :format => 'm'
+ todos.mobile_abbrev_new 'm/new', :action => "new", :format => 'm'
end
# Notes Routes
diff --git a/tracks/db/schema.rb b/tracks/db/schema.rb
index e755499f..95666273 100644
--- a/tracks/db/schema.rb
+++ b/tracks/db/schema.rb
@@ -6,7 +6,7 @@ ActiveRecord::Schema.define(:version => 31) do
create_table "contexts", :force => true do |t|
t.column "name", :string, :default => "", :null => false
- t.column "hide", :boolean, :default => false
+ t.column "hide", :integer, :limit => 4, :default => 0, :null => false
t.column "position", :integer, :default => 0, :null => false
t.column "user_id", :integer, :default => 0, :null => false
t.column "created_at", :datetime
diff --git a/tracks/lib/login_system.rb b/tracks/lib/login_system.rb
index 22932baa..28cd8e00 100644
--- a/tracks/lib/login_system.rb
+++ b/tracks/lib/login_system.rb
@@ -114,6 +114,7 @@ module LoginSystem
def access_denied
respond_to do |format|
format.html { redirect_to :controller=>"login", :action =>"login" }
+ format.m { redirect_to :controller=>"login", :action =>"login" }
format.js { render :partial => 'login/redirect_to_login' }
format.xml { basic_auth_denied }
format.rss { basic_auth_denied }
diff --git a/tracks/lib/source_view.rb b/tracks/lib/source_view.rb
index 9f649235..a6dbee09 100644
--- a/tracks/lib/source_view.rb
+++ b/tracks/lib/source_view.rb
@@ -27,7 +27,7 @@ module Tracks
end
def source_view
- responder = Tracks::SourceViewSwitching::Responder.new(params[:_source_view])
+ responder = Tracks::SourceViewSwitching::Responder.new(params[:_source_view] || @source_view)
block_given? ? yield(responder) : responder
end
diff --git a/tracks/test/functional/mobile_controller_test.rb b/tracks/test/functional/mobile_controller_test.rb
deleted file mode 100644
index be2210c4..00000000
--- a/tracks/test/functional/mobile_controller_test.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-require File.dirname(__FILE__) + '/../test_helper'
-require 'mobile_controller'
-
-# Re-raise errors caught by the controller.
-class MobileController; def rescue_action(e) raise e end; end
-
-class MobileControllerTest < Test::Unit::TestCase
- fixtures :users, :preferences, :projects, :contexts, :todos
-
- def setup
- @controller = MobileController.new
- @request = ActionController::TestRequest.new
- @response = ActionController::TestResponse.new
- end
-
- def test_get_index_when_not_logged_in
- get :index
- assert_redirected_to :controller => 'login', :action => 'login'
- end
-
- def test_create_todo
- @count = Todo.find(:all)
- @request.session['user_id'] = users(:admin_user).id
- xhr :post, :update, "todo"=>{"context_id"=>"1", "project_id"=>"2", "notes"=>"", "description"=>"Invest in spam stock offer", "due"=>"01/01/2007", "show_from"=>"", "state"=>"0"}
- @todos = Todo.find(:all)
- assert_equal @count.size+1, @todos.size
- t = Todo.find(:first, :conditions => ['description = ?', "Invest in spam stock offer"])
- assert_equal "Invest in spam stock offer", t.description
- assert_equal Date.parse("01/01/2007"), t.due
- assert_equal users(:admin_user).id, t.user_id
- assert_equal 1, t.context_id
- assert_equal 2, t.project_id
- assert_equal "active", t.state
- end
-
- def test_update_todo
- t = Todo.find(1)
- @request.session['user_id'] = users(:admin_user).id
- xhr :post, :update, :id => 1, :_source_view => 'todo', "todo"=>{"context_id"=>"1", "project_id"=>"2", "id"=>"1", "notes"=>"", "description"=>"Call Warren Buffet to find out how much he makes per day", "due"=>"11/30/2006"}
- t = Todo.find(1)
- assert_equal "Call Warren Buffet to find out how much he makes per day", t.description
- assert_equal Date.parse("11/30/2006"), t.due
- assert_equal users(:admin_user).id, t.user_id
- assert_equal "active", t.state
- end
-
- def test_complete_todo
- t = Todo.find(1)
- @request.session['user_id'] = users(:admin_user).id
- xhr :post, :update, :id => 1, :_source_view => 'todo', "todo"=>{"context_id"=>"1", "project_id"=>"2", "id"=>"1", "notes"=>"", "description"=>"Call Bill Gates to find out how much he makes per day", "state"=>"1"}
- t = Todo.find(1)
- assert_equal "completed", t.state
- end
-end
diff --git a/tracks/test/functional/todos_controller_test.rb b/tracks/test/functional/todos_controller_test.rb
index ed573b93..ad410fc0 100644
--- a/tracks/test/functional/todos_controller_test.rb
+++ b/tracks/test/functional/todos_controller_test.rb
@@ -242,5 +242,34 @@ class TodosControllerTest < Test::Unit::TestCase
assert !(/ /.match(@response.body))
#puts @response.body
end
+
+ def test_mobile_index_uses_text_html_content_type
+ @request.session['user_id'] = users(:admin_user).id
+ get :index, { :format => "m" }
+ assert_equal 'text/html; charset=utf-8', @response.headers["Content-Type"]
+ end
+
+ def test_mobile_index_assigns_down_count
+ @request.session['user_id'] = users(:admin_user).id
+ get :index, { :format => "m" }
+ assert_equal 10, assigns['down_count']
+ end
+
+ def test_mobile_create_action
+ @request.session['user_id'] = users(:admin_user).id
+ post :create, {"format"=>"m", "todo"=>{"context_id"=>"2",
+ "due(1i)"=>"2007", "due(2i)"=>"1", "due(3i)"=>"2",
+ "show_from(1i)"=>"", "show_from(2i)"=>"", "show_from(3i)"=>"",
+ "project_id"=>"1",
+ "notes"=>"test notes", "description"=>"test_mobile_create_action", "state"=>"0"}}
+ t = Todo.find_by_description("test_mobile_create_action")
+ assert_not_nil t
+ assert_equal 2, t.context_id
+ assert_equal 1, t.project_id
+ assert t.active?
+ assert_equal 'test notes', t.notes
+ assert_nil t.show_from
+ assert_equal Date.new(2007,1,2).to_s, t.due.to_s
+ end
end
diff --git a/tracks/test/selenium/mobile/create_new_action.rsel b/tracks/test/selenium/mobile/create_new_action.rsel
new file mode 100644
index 00000000..613823b3
--- /dev/null
+++ b/tracks/test/selenium/mobile/create_new_action.rsel
@@ -0,0 +1,18 @@
+setup :fixtures => :all
+login :as => 'admin'
+
+open '/m'
+wait_for_text 'css=h1 span.count', '10'
+
+click_and_wait "link=+"
+
+type "todo_notes", "test notes"
+type "todo_description", "test name"
+select "todo_context_id", "label=call"
+select "todo_project_id", "label=Make more money than Billy Gates"
+select "todo_due_3i", "label=1"
+select "todo_due_2i", "label=January"
+select "todo_due_1i", "label=2007"
+click_and_wait "//input[@value='Create']"
+
+wait_for_text 'css=h1 span.count', '11'
diff --git a/tracks/test/selenium/mobile/mark_done.rsel b/tracks/test/selenium/mobile/mark_done.rsel
new file mode 100644
index 00000000..82a9e3a6
--- /dev/null
+++ b/tracks/test/selenium/mobile/mark_done.rsel
@@ -0,0 +1,11 @@
+setup :fixtures => :all
+login :as => 'admin'
+
+open '/m'
+wait_for_text 'css=h1 span.count', '10'
+
+open_and_wait '/todos/6.m'
+click "done"
+click_and_wait "//input[@value='Update']"
+
+wait_for_text 'css=h1 span.count', '9'
diff --git a/tracks/test/selenium/mobile/navigation.rsel b/tracks/test/selenium/mobile/navigation.rsel
new file mode 100644
index 00000000..25e987cb
--- /dev/null
+++ b/tracks/test/selenium/mobile/navigation.rsel
@@ -0,0 +1,25 @@
+setup :fixtures => :all
+login :as => 'admin'
+
+open '/m'
+wait_for_title "All actions"
+wait_for_text 'css=h1 span.count', '10'
+
+click_and_wait "link=2"
+verify_title "All actions"
+wait_for_text 'css=h1 span.count', '10'
+
+select "context_id", "label=agenda"
+click_and_wait "change_context"
+verify_title "All actions in context agenda"
+wait_for_text 'css=h1 span.count', '5'
+
+select "context_id", "label=call"
+click_and_wait "change_context"
+verify_title "All actions in context call"
+wait_for_text 'css=h1 span.count', '3'
+
+select "project_id", "label=Build a working time machine"
+click_and_wait "change_project"
+verify_title "All actions in project Build a working time machine"
+wait_for_text 'css=h1 span.count', '2'
diff --git a/tracks/vendor/plugins/will_paginate/README b/tracks/vendor/plugins/will_paginate/README
new file mode 100644
index 00000000..720f594a
--- /dev/null
+++ b/tracks/vendor/plugins/will_paginate/README
@@ -0,0 +1,58 @@
+WillPaginate
+
+Ruby port by: PJ Hyett
+Original PHP source: http://www.strangerstudios.com/sandbox/pagination/diggstyle.php
+Contributors: K. Adam Christensen, Chris Wanstrath, Dr. Nic Williams
+
+Example usage:
+
+app/models/post.rb
+
+ class Post < ActiveRecord::Base
+ cattr_reader :per_page
+ @@per_page = 50
+ end
+
+app/controller/posts_controller.rb
+
+ def index
+ @board = Board.find(params[:id])
+ @posts, @page = Post.paginate_all_by_board_id(@board.id, :page => params[:page])
+ end
+
+app/views/posts/index.rhtml
+
+ <%= will_paginate(@board.topic_count, Post.per_page) %>
+
+
+Copy the following css into your stylesheet for a good start:
+
+.pagination {
+ padding: 3px;
+ margin: 3px;
+}
+.pagination a {
+ padding: 2px 5px 2px 5px;
+ margin: 2px;
+ border: 1px solid #aaaadd;
+ text-decoration: none;
+ color: #000099;
+}
+.pagination a:hover, .pagination a:active {
+ border: 1px solid #000099;
+ color: #000;
+}
+.pagination span.current {
+ padding: 2px 5px 2px 5px;
+ margin: 2px;
+ border: 1px solid #000099;
+ font-weight: bold;
+ background-color: #000099;
+ color: #FFF;
+}
+.pagination span.disabled {
+ padding: 2px 5px 2px 5px;
+ margin: 2px;
+ border: 1px solid #eee;
+ color: #ddd;
+}
diff --git a/tracks/vendor/plugins/will_paginate/init.rb b/tracks/vendor/plugins/will_paginate/init.rb
new file mode 100644
index 00000000..54e73916
--- /dev/null
+++ b/tracks/vendor/plugins/will_paginate/init.rb
@@ -0,0 +1,4 @@
+require 'will_paginate'
+require 'finder'
+ActionView::Base.send(:include, WillPaginate)
+ActiveRecord::Base.send(:include, WillPaginate::Finder)
diff --git a/tracks/vendor/plugins/will_paginate/lib/finder.rb b/tracks/vendor/plugins/will_paginate/lib/finder.rb
new file mode 100644
index 00000000..27983d44
--- /dev/null
+++ b/tracks/vendor/plugins/will_paginate/lib/finder.rb
@@ -0,0 +1,28 @@
+module WillPaginate
+ module Finder
+ def self.included(base)
+ base.extend ClassMethods
+ class << base
+ define_method(:per_page) { 30 } unless respond_to? :per_page
+ end
+ end
+
+ module ClassMethods
+ def method_missing_with_will_paginate(method_id, *args, &block)
+ unless match = /^paginate/.match(method_id.to_s)
+ return method_missing_without_will_paginate(method_id, *args, &block)
+ end
+
+ options = args.last.is_a?(Hash) ? args.pop : {}
+ page = (page = options.delete(:page).to_i).zero? ? 1 : page
+ limit_per_page = options.delete(:per_page) || per_page
+ args << options
+
+ with_scope :find => { :offset => (page - 1) * limit_per_page, :limit => limit_per_page } do
+ [send(method_id.to_s.sub(/^paginate/, 'find'), *args), page]
+ end
+ end
+ alias_method_chain :method_missing, :will_paginate
+ end
+ end
+end
diff --git a/tracks/vendor/plugins/will_paginate/lib/will_paginate.rb b/tracks/vendor/plugins/will_paginate/lib/will_paginate.rb
new file mode 100644
index 00000000..fdf4c11c
--- /dev/null
+++ b/tracks/vendor/plugins/will_paginate/lib/will_paginate.rb
@@ -0,0 +1,43 @@
+module WillPaginate
+ def will_paginate(total_count, per_page, page = @page)
+ adjacents = 2
+ prev_page = page - 1
+ next_page = page + 1
+ last_page = (total_count / per_page.to_f).ceil
+ lpm1 = last_page - 1
+
+ returning '' do |pgn|
+ if last_page > 1
+ pgn << %{'
+ end
+ end
+ end
+end