make project settings editable from the project page

We're using the edit form instead of several separate fields to edit settings
This commit is contained in:
Reinier Balt 2009-04-18 23:50:12 +02:00
parent 66833829a0
commit b990f8a015
14 changed files with 150 additions and 169 deletions

View file

@ -13,7 +13,7 @@ require 'time'
# run because this tag went looking for the taggings table that did not exist
# when you feshly create a new database Old comment: We need this in development
# mode, or you get 'method missing' errors
#
#
# Tag
class CannotAccessContext < RuntimeError; end
@ -86,7 +86,7 @@ class ApplicationController < ActionController::Base
# Returns a count of next actions in the given context or project The result
# is count and a string descriptor, correctly pluralised if there are no
# actions or multiple actions
#
#
def count_undone_todos_phrase(todos_parent, string="actions")
count = count_undone_todos(todos_parent)
if count == 1
@ -110,7 +110,7 @@ class ApplicationController < ActionController::Base
# Convert a date object to the format specified in the user's preferences in
# config/settings.yml
#
#
def format_date(date)
if date
date_format = prefs.date_format
@ -124,7 +124,7 @@ class ApplicationController < ActionController::Base
# Uses RedCloth to transform text using either Textile or Markdown Need to
# require redcloth above RedCloth 3.0 or greater is needed to use Markdown,
# otherwise it only handles Textile
#
#
def markdown(text)
RedCloth.new(text).to_html
end

View file

@ -9,14 +9,15 @@ class ProjectsController < ApplicationController
session :off, :only => :index, :if => Proc.new { |req| ['rss','atom','txt'].include?(req.parameters[:format]) }
def index
@projects = current_user.projects(true)
@source_view = params['_source_view'] || 'project_list'
@projects = current_user.projects
if params[:projects_and_actions]
projects_and_actions
else
@contexts = current_user.contexts(true)
@contexts = current_user.contexts
init_not_done_counts(['project'])
if params[:only_active_with_no_next_actions]
@projects = @projects.select { |p| p.active? && count_undone_todos(p) == 0 }
@projects = current_user.projects.active.select { |p| count_undone_todos(p) == 0 }
end
init_project_hidden_todo_counts(['project'])
respond_to do |format|
@ -31,7 +32,7 @@ class ProjectsController < ApplicationController
end
def projects_and_actions
@projects = @projects.active
@projects = current_user.projects.active
respond_to do |format|
format.text {
render :action => 'index_text_projects_and_actions', :layout => false, :content_type => Mime::TEXT
@ -40,24 +41,19 @@ class ProjectsController < ApplicationController
end
def show
@contexts = current_user.contexts(true)
init_data_for_sidebar unless mobile?
@projects = current_user.projects
@contexts = current_user.contexts
@page_title = "TRACKS::Project: #{@project.name}"
@project.todos.send :with_scope, :find => { :include => [:context] } do
@not_done = @project.not_done_todos(:include_project_hidden_todos => true)
@deferred = @project.deferred_todos.sort_by { |todo| todo.show_from }
@done = @project.done_todos
end
@max_completed = current_user.prefs.show_number_completed
init_data_for_sidebar unless mobile?
@page_title = "TRACKS::Project: #{@project.name}"
@not_done = @project.not_done_todos_including_hidden
@deferred = @project.deferred_todos
@done = @project.todos.find_in_state(:all, :completed, :order => "todos.completed_at DESC", :limit => current_user.prefs.show_number_completed, :include => [:context])
@count = @not_done.size
@down_count = @count + @deferred.size
@next_project = current_user.projects.next_from(@project)
@previous_project = current_user.projects.previous_from(@project)
@default_project_context_name_map = build_default_project_context_name_map(@projects).to_json
@default_project_context_name_map = build_default_project_context_name_map(current_user.projects).to_json
respond_to do |format|
format.html
format.m &render_project_mobile
@ -70,7 +66,7 @@ class ProjectsController < ApplicationController
# -u username:password
# -d '<request><project><name>new project_name</name></project></request>'
# http://our.tracks.host/projects
#
#
def create
if params[:format] == 'application/xml' && params['exception']
render_failure "Expected post format is valid xml like so: <request><project><name>project name</name></project></request>."
@ -102,7 +98,7 @@ class ProjectsController < ApplicationController
end
# Edit the details of the project
#
#
def update
params['project'] ||= {}
if params['project']['state']
@ -121,10 +117,10 @@ class ProjectsController < ApplicationController
if boolean_param('wants_render')
if (@project.hidden?)
@project_project_hidden_todo_counts = Hash.new
@project_project_hidden_todo_counts[@project.id] = @project.reload().not_done_todo_count(:include_project_hidden_todos => true)
@project_project_hidden_todo_counts[@project.id] = @project.reload().not_done_todos_including_hidden.count
else
@project_not_done_counts = Hash.new
@project_not_done_counts[@project.id] = @project.reload().not_done_todo_count(:include_project_hidden_todos => true)
@project_not_done_counts[@project.id] = @project.reload().not_done_todos_including_hidden.count
end
@contexts = current_user.contexts
@active_projects_count = current_user.projects.active.count
@ -159,7 +155,6 @@ class ProjectsController < ApplicationController
end
def edit
@contexts = current_user.contexts
respond_to do |format|
format.js
end
@ -205,11 +200,11 @@ class ProjectsController < ApplicationController
lambda do
@page_title = "TRACKS::List Projects"
@count = current_user.projects.size
@active_projects = @projects.active
@hidden_projects = @projects.hidden
@completed_projects = @projects.completed
@no_projects = @projects.empty?
@projects.cache_note_counts
@active_projects = current_user.projects.active
@hidden_projects = current_user.projects.hidden
@completed_projects = current_user.projects.completed
@no_projects = current_user.projects.empty?
current_user.projects.cache_note_counts
@new_project = current_user.projects.build
render
end
@ -297,4 +292,4 @@ class ProjectsController < ApplicationController
project_description
end
end
end

View file

@ -659,8 +659,8 @@ class TodosController < ApplicationController
end
from.project do
unless @todo.project_id == nil
@down_count = current_user.projects.find(@todo.project_id).not_done_todo_count(:include_project_hidden_todos => true)
@deferred_count = current_user.projects.find(@todo.project_id).deferred_todo_count
@down_count = current_user.projects.find(@todo.project_id).not_done_todos_including_hidden.count
@deferred_count = current_user.projects.find(@todo.project_id).deferred_todos.count
end
end
from.deferred do

View file

@ -1,6 +1,18 @@
class Project < ActiveRecord::Base
has_many :todos, :dependent => :delete_all, :include => :context
has_many :todos, :dependent => :delete_all, :include => [:context,:tags]
has_many :not_done_todos_including_hidden,
:include => [:context,:tags,:project],
:class_name => 'Todo',
:order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC",
:conditions => ["(todos.state = ? OR todos.state = ?)", 'active', 'project_hidden']
has_many :deferred_todos,
:include => [:context,:tags,:project],
:class_name => 'Todo',
:conditions => ["todos.state = ? ", "deferred"],
:order => "show_from"
has_many :notes, :dependent => :delete_all, :order => "created_at DESC"
belongs_to :default_context, :class_name => "Context", :foreign_key => "default_context_id"
belongs_to :user
@ -16,7 +28,7 @@ class Project < ActiveRecord::Base
acts_as_list :scope => 'user_id = #{user_id} AND state = \'#{state}\''
acts_as_state_machine :initial => :active, :column => 'state'
extend NamePartFinder
include Tracks::TodoList
#include Tracks::TodoList
state :active
state :hidden, :enter => :hide_todos, :exit => :unhide_todos

View file

@ -78,6 +78,8 @@ class User < ActiveRecord::Base
has_many :todos,
:order => 'todos.completed_at DESC, todos.created_at DESC',
:dependent => :delete_all
has_many :project_hidden_todos,
:conditions => ['(state = ? OR state = ?)', 'project_hidden', 'active']
has_many :recurring_todos,
:order => 'recurring_todos.completed_at DESC, recurring_todos.created_at DESC',
:dependent => :delete_all

View file

@ -1,34 +1,27 @@
<% #@not_done = project.not_done_todos -%>
<div id="p<%= project.id %>" class="container project">
<div class="container">
<h2>
<% if collapsible %>
<a href="#" class="container_toggle" id="toggle_p<%= project.id %>"><%= image_tag("collapse.png") %></a>
<% end %>
<span class="in_place_editor_field" id="project_name_in_place_editor"><%= project.name %></span>
<%= in_place_editor 'project_name_in_place_editor', {
:url => { :controller => 'projects', :action => 'update', :id => project.id, :field => 'name', :update_project_name => true, :escape => false} ,
:options=>"{method:'put'}", :script => true} %>
<% if collapsible -%>
<a href="#" class="container_toggle" id="toggle_p<%= project.id %>"><%= image_tag("collapse.png") %></a>
<% end -%>
<%= project.name -%>
</h2>
<% unless project.description.blank? -%>
<div class="project_description"><%= sanitize(project.description) %></div>
<% end -%>
<% if project.completed? -%>
<p class="project_completed">Project has been marked as completed</p>
<% elsif project.completed? -%>
<p class="project_completed">Project has been marked as hidden</p>
<% end -%>
<div id="<%= dom_id(project, "container")%>">
<%= render :partial => "projects/project_settings", :locals => { :project => project, :collapsible => collapsible } %>
</div>
</div>
<div class="container">
<h2>Actions in this project</h2>
<div id="p<%= project.id %>items" class="items toggle_target">
<div id="p<%= project.id %>empty-nd" style="display:<%= @not_done.empty? ? 'block' : 'none'%>;">
<div class="message"><p>Currently there are no incomplete actions in this project</p></div>
</div>
<%= render :partial => "todos/todo", :collection => @not_done, :locals => { :parent_container_type => "project" } %>
<% if @not_done.empty?
<% if @not_done.empty?
# fix (hack) for #713
set_behavior_for_star_icon
set_behavior_for_toggle_checkbox
end
-%>
</div><!-- [end:items] -->
</div><!-- [end:p<%= project.id %>] -->
</div>
</div>

View file

@ -1,8 +1,10 @@
<%
project = project_form
project = project_form
%>
<% form_tag project_path(project), { :id => dom_id(project, 'edit_form'), :class => "inline-form "+dom_id(project, 'edit_form')+"-edit-project-form", :method => :put } do -%>
<%= source_view_tag( @source_view ) -%>
<label for="project_name">Name:</label><br/>
<%= text_field :project, 'name', :class => 'project-name' %><br/>
@ -11,7 +13,7 @@
<label for="project_done">Project status:</label><br/>
<% ['active', 'hidden', 'completed'].each do | state | %>
<%= radio_button(:project, 'state', state) %> <%= state.titlecase %>
<%= radio_button(:project, 'state', state) %> <%= state.titlecase %>
<% end %><br/>
<label for="project[default_context_name]">Default Context</label><br/>
@ -38,11 +40,9 @@
</div>
<br/><br/>
<% end -%>
<% end -%>
<%= apply_behavior "."+dom_id(project, 'edit_form')+"-edit-project-form", make_remote_form(
:before => "$('"+dom_id(project, 'submit')+"').startWaiting();",
:condition => "!$('"+dom_id(project, 'submit')+"').isWaiting()",
:external => false) %>
:condition => "!$('"+dom_id(project, 'submit')+"').isWaiting()",
:external => false) %>

View file

@ -1,14 +1,14 @@
<% project = project_listing
suppress_drag_handle ||= false
suppress_edit_button ||= false
suppress_drag_handle ||= false
suppress_edit_button ||= false
-%>
<div id="<%= dom_id(project, "container") %>" class="list">
<div id="<%= dom_id(project) %>" class="project sortable_row" style="display:''">
<% unless suppress_drag_handle -%>
<div class="position">
<span class="handle">DRAG</span>
</div>
<% end -%>
<span class="handle">DRAG</span>
</div>
<% end -%>
<div class="data">
<%= link_to_project( project ) %><%= " (" + count_undone_todos_and_notes_phrase(project,"actions") + ")" %>
</div>
@ -17,22 +17,25 @@
<a class="delete_project_button"
href="<%= formatted_project_path(project, :js) %>"
title="delete the project '<%= project.name %>'"><%= image_tag( "blank.png",
:title => "Delete project",
:class=>"delete_item") %></a>
<%= apply_behavior "a.delete_project_button:click", { :prevent_default => true, :external => true } do |page, element|
page.confirming "'Are you sure that you want to ' + this.title + '?'" do
element.up('.project').start_waiting
page << remote_to_href(:method => 'delete')
end
end -%>
<% unless suppress_edit_button -%>
<a class="edit_project_button" id="<%= dom_id(project, 'editbutton') %>" href="<%= formatted_edit_project_path(project, :js) %>" title="delete the project '<%= project.name %>'"><%= image_tag( "blank.png", :title => "Edit project", :class=>"edit_item") %></a>
<%= apply_behavior 'a.edit_project_button:click', { :prevent_default => true, :external => true } do |page, element|
element.up('div.project').start_waiting
page << remote_to_href(:method => 'get')
end
-%>
<% end -%>
:title => "Delete project",
:class=>"delete_item") %></a>
<%= apply_behavior "a.delete_project_button:click", { :prevent_default => true, :external => true } do |page, element|
page.confirming "'Are you sure that you want to ' + this.title + '?'" do
element.up('.project').start_waiting
page << remote_to_href(:method => 'delete')
end
end -%>
<% unless suppress_edit_button -%>
<%= link_to_remote(
image_tag( "blank.png", :title => "Edit project", :class=>"edit_item"),
:url => {:controller => 'projects', :action => 'edit', :id => project.id},
:method => 'get',
:with => "'_source_view=#{@source_view}'",
:before => "$('#{dom_id(project)}').startWaiting();",
:complete => "$('#{dom_id(project)}').stopWaiting();"
) %>
<% end -%>
</div>
</div>
@ -40,7 +43,7 @@
</div>
</div>
<% if controller.action_name == 'create' %>
<script>
new Effect.Appear('<%= dom_id(project) %>');
</script>
<script>
new Effect.Appear('<%= dom_id(project) %>');
</script>
<% end %>

View file

@ -0,0 +1,31 @@
<div id="<%= dom_id(project) %>" class="project">
<% unless project.description.blank? -%>
<div class="project_description"><%= sanitize(project.description) %></div>
<% end -%>
<p>This project
<% if project.completed? -%>has been marked as completed
<% elsif project.hidden? -%>has been marked as hidden
<% else -%>is active
<% end -%>
with <% if project.default_context.nil? -%>
no default context
<% else -%>
a default context of <%= project.default_context.name -%>
<% end -%>
and with <% if project.default_tags.nil? || project.default_tags.blank? -%>
no default tags.
<% else -%>
'<%= project.default_tags -%>' as the default tags.
<% end -%>
<%= link_to_remote(
"Edit Project Settings",
:url => {:controller => 'projects', :action => 'edit', :id => project.id},
:method => 'get',
:with => "'_source_view=#{@source_view}'",
:before => "$('#{dom_id(project)}').startWaiting();",
:complete => "$('#{dom_id(project)}').stopWaiting();"
) %>
</p>
</div>
<div id="<%= dom_id(project, 'edit') %>" class="edit-form" style="display:none;">
</div>

View file

@ -1,5 +1,4 @@
page[dom_id(@project, 'edit')].replace_html :partial => 'project_form', :locals => { :project_form => @project }
page[@project].hide
page[@project].stop_waiting
page[dom_id(@project, 'edit')].show
page[dom_id(@project, 'edit_form')].down('input.project-name').focus
page[dom_id(@project, 'edit')].replace_html :partial => 'project_form', :locals => { :project_form => @project }
page[@project].hide
page[dom_id(@project, 'edit')].show
page[dom_id(@project, 'edit_form')].down('input.project-name').focus

View file

@ -21,7 +21,6 @@
</div>
</div>
<div id="new-note" style="display:none;">
<% form_remote_tag :url => notes_path,
:method => :post,
@ -35,69 +34,9 @@
<input type="submit" value="Add note" name="add-new-note" tabindex="2" />
<% end -%>
</div>
<div class="container">
<div id="project_status">
<h2>Status</h2>
<div>
<% ['active', 'hidden', 'completed'].each do | state | %>
<% span_class = @project.current_state.to_s == state ? 'active_state' : 'inactive_state' %>
<span class="<%= state %>"><%= radio_button(:project, 'state', state) %> <span class="<%= span_class %>"><%= state.titlecase %></span></span>
<% end %>
<% apply_behavior "#project_status input:click",
remote_function(:url => project_path(@project), :method => :put,
:with => "'wants_render=false&update_status=true&project[state]='+this.value" )
%>
</div>
</div>
</div>
<div class="container">
<div id="default_context">
<h2>Default Context</h2>
<div>
<% form_remote_tag( :url => project_path(@project), :method => :put,
:html=> { :id => 'set-default-context-action',
:name => 'default_context',
:class => 'inline-form' },
:before => "$('default_context_submit').startWaiting()",
:loaded => "$('default_context_submit').stopWaiting()") do -%>
<%= hidden_field_tag("update_default_context", true) %>
<%= text_field_tag("project[default_context_name]",
@project.default_context.name,
{ :tabindex => 9,:size => 25 }) %>
<%= submit_tag "Set Default Context for this Project", { :tabindex => 10, :id => "default_context_submit" } %>
<%= render :partial => 'default_context_autocomplete' %>
<% end -%>
</div>
</div>
</div>
<div class="container">
<div id="default_tags">
<h2>Default Tags</h2>
<div>
<% form_remote_tag( :url => project_path(@project), :method => :put,
:html=> { :id => 'set-default-tags-action',
:name => 'default_tags',
:class => 'inline-form' },
:before => "$('default_tags_submit').startWaiting()",
:loaded => "$('default_tags_submit').stopWaiting()") do -%>
<%= hidden_field_tag("update_default_tags", true) %>
<%= text_field_tag("project[default_tags]",
@project.default_tags,
{ :tabindex => 11,:size => 25 }) %>
<%= submit_tag "Set Default Tags for this Project", { :tabindex => 12, :id => "default_tags_submit"} %>
<% end -%>
</div>
</div>
</div>
</div>
</div>
<div id="input_box">
<%= render :partial => "shared/add_new_item_form" %>
<%= render :file => "sidebar/sidebar.html.erb" %>
</div><!-- End of input box -->
</div><!-- End of input box -->

View file

@ -1,16 +1,22 @@
status_message = 'Project saved'
page.notify :notice, status_message, 5.0
if @state_changed
page[dom_id(@project, 'container')].remove
page.insert_html :bottom, "list-#{@project.state}-projects", :partial => 'project_listing', :object => @project
else
page.replace_html dom_id(@project, 'container'), :partial => 'project_listing', :object => @project
end
page.sortable "list-#{@project.state}-projects", get_listing_sortable_options("list-#{@project.state}-projects")
page.replace_html "active-projects-count", @active_projects_count
page.replace_html "hidden-projects-count", @hidden_projects_count
page.replace_html "completed-projects-count", @completed_projects_count
if source_view_is :project_list
if @state_changed
page[dom_id(@project, 'container')].remove
page.insert_html :bottom, "list-#{@project.state}-projects", :partial => 'project_listing', :object => @project
else
page.replace_html dom_id(@project, 'container'), :partial => 'project_listing', :object => @project
end
page.sortable "list-#{@project.state}-projects", get_listing_sortable_options("list-#{@project.state}-projects")
page.replace_html "active-projects-count", @active_projects_count
page.replace_html "hidden-projects-count", @hidden_projects_count
page.replace_html "completed-projects-count", @completed_projects_count
page.set_element_visible("list-hidden-projects-container", @hidden_projects_count > 0)
page.set_element_visible("list-active-projects-container", @active_projects_count > 0)
page.set_element_visible("list-completed-projects-container", @completed_projects_count > 0)
page.set_element_visible("list-hidden-projects-container", @hidden_projects_count > 0)
page.set_element_visible("list-active-projects-container", @active_projects_count > 0)
page.set_element_visible("list-completed-projects-container", @completed_projects_count > 0)
else
page[dom_id(@project, 'edit')].hide
page.replace_html dom_id(@project, 'container'), :partial => 'project_settings', :locals => { :project => @project }
page[dom_id(@project)].show
end

View file

@ -37,4 +37,4 @@ parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag'
<div class="placeholder"> </div>
<% end -%>
</div>
</div>
</div>

View file

@ -49,6 +49,7 @@ end
config.gem "flexmock"
config.gem "ZenTest"
config.gem "hpricot"
config.gem "hoe"
config.gem "rspec", :lib => false, :version => ">=1.2.2"
config.gem "rspec-rails", :lib => false, :version => ">=1.2.2"