Merged branches/TRY-BSAG-ajax back to the trunk.

...and we're back!


git-svn-id: http://www.rousette.org.uk/svn/tracks-repos/trunk@86 a4c988fc-2ded-0310-b66e-134b36920a42
This commit is contained in:
bsag 2005-05-28 14:08:44 +00:00
parent 71bbb06d3e
commit 8406a482d5
46 changed files with 4049 additions and 1213 deletions

View file

@ -2,6 +2,7 @@
# Likewise will all the methods added be available for all controllers. # Likewise will all the methods added be available for all controllers.
require_dependency "login_system" require_dependency "login_system"
require 'date' require 'date'
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
@ -9,6 +10,11 @@ class ApplicationController < ActionController::Base
helper :application helper :application
include LoginSystem include LoginSystem
# Contstants from settings.yml
DATE_FORMAT = app_configurations["formats"]["date"]
WEEK_STARTS_ON = app_configurations["formats"]["week_starts"]
NO_OF_ACTIONS = app_configurations["formats"]["hp_completed"]
def count_shown_items(hidden) def count_shown_items(hidden)
count = 0 count = 0
sub = 0 sub = 0
@ -18,4 +24,9 @@ class ApplicationController < ActionController::Base
total = Todo.find_all("done=0").length - sub total = Todo.find_all("done=0").length - sub
end end
# Returns all the errors on the page for an object...
def errors_for( obj )
error_messages_for( obj ) unless instance_eval("@#{obj}").nil?
end
end end

View file

@ -1,126 +1,144 @@
class ContextController < ApplicationController class ContextController < ApplicationController
helper :context helper :context
model :project model :project
model :todo
before_filter :login_required before_filter :login_required
caches_action :list
layout "standard" layout "standard"
# Main method for listing contexts
# Set page title, and collect existing contexts in @contexts
#
def index def index
list list
render_action "list" render_action "list"
end end
# Main method for listing contexts
# Set page title, and collect existing contexts in @contexts
#
def list def list
@page_title = "TRACKS::List Contexts" @page_title = "TRACKS::List Contexts"
@contexts = Context.find_all( conditions = nil, "position ASC", limit = nil ) @contexts = Context.find(:all, :conditions => nil, :order => "position ASC", :limit => nil )
end end
# Filter the projects to show just the one passed in the URL
# Called by a form button # e.g. <home>/project/show/<project_name> shows just <project_name>.
# Parameters from form fields should be passed to create new context
#
def add_context
expire_action(:controller => "context", :action => "list")
context = Context.new
context.attributes = @params["new_context"]
if context.save
flash["confirmation"] = "Succesfully created context \"#{context.name}\""
redirect_to( :action => "list" )
else
flash["warning"] = "Couldn't add new context \"#{context.name}\""
redirect_to( :action => "list" )
end
end
def new
expire_action(:controller => "context", :action => "list")
context = Context.new
context.attributes = @params["new_context"]
if context.save
flash["confirmation"] = "Succesfully created context \"#{context.name}\""
redirect_to( :action => "list" )
else
flash["warning"] = "Couldn't add new context \"#{context.name}\""
redirect_to( :action => "list" )
end
end
def edit
expire_action(:controller => "context", :action => "list")
@context = Context.find(@params['id'])
@page_title = "TRACKS::Edit context: #{@context.name.capitalize}"
end
def update
@context = Context.find(@params['context']['id'])
@context.attributes = @params['context']
if @context.save
flash["confirmation"] = "Context \"#{@context.name}\" was successfully updated"
redirect_to :action => 'list'
else
flash["warning"] = "Context \"#{@context.name}\" could not be updated"
redirect_to :action => 'list'
end
end
# Filter the contexts to show just the one passed in the URL
# e.g. <home>/context/show/<context_name> shows just <context_name>.
# #
def show def show
@context = Context.find_by_name(@params["id"].humanize) @context = Context.find_by_name(@params["name"].humanize)
@projects = Project.find_all @places = Context.find(:all)
@page_title = "TRACKS::Context: #{@context.name.capitalize}" @projects = Project.find(:all)
@not_done = Todo.find_all( "context_id=#{@context.id} AND done=0", "due DESC, created ASC" ) @page_title = "TRACKS::Context: #{@context.name}"
@not_done = Todo.find(:all, :conditions => "done=0 AND context_id=#{@context.id}",
:order => "due IS NULL, due ASC, created ASC")
@done = Todo.find(:all, :conditions => "done=1 AND context_id=#{@context.id}",
:order => "completed DESC")
@count = Todo.count( "context_id=#{@context.id} AND done=0" ) @count = Todo.count( "context_id=#{@context.id} AND done=0" )
end end
# Creates a new context via Ajax helpers
#
def new_context
@context = Context.new(@params['context'])
if @context.save
render_partial( 'context_listing', @context )
else
flash["warning"] = "Couldn't add new context"
render_text "#{flash["warning"]}"
end
end
# Edit the details of the context
#
def update
context = Context.find(params[:id])
context.attributes = @params["context"]
if context.save
render_partial 'context_listing', context
else
flash["warning"] = "Couldn't update new context"
render_text ""
end
end
# Edit the details of the action in this context
#
def update_action
@places = Context.find(:all)
@projects = Project.find(:all)
action = Todo.find(params[:id])
action.attributes = @params["item"]
if action.due?
action.due = Date.strptime(@params["item"]["due"], DATE_FORMAT)
else
action.due = ""
end
if action.save
render_partial 'show_items', action
else
flash["warning"] = "Couldn't update the action"
render_text ""
end
end
# Called by a form button # Called by a form button
# Parameters from form fields are passed to create new action # Parameters from form fields are passed to create new action
# in the selected context. #
def add_item def add_item
expire_action(:controller => "context", :action => "list") @projects = Project.find( :all )
@places = Context.find( :all )
item = Todo.new item = Todo.new
item.attributes = @params["new_item"] item.attributes = @params["new_item"]
where = Context.find_by_id(item.context_id)
back_to = urlize(where.name) if item.due?
item.due = Date.strptime(@params["new_item"]["due"], DATE_FORMAT)
else
item.due = ""
end
if item.save if item.save
flash["confirmation"] = "Succesfully added action \"#{item.description}\" to context" render_partial 'show_items', item
redirect_to( :controller => "context", :action => "show", :name => "#{back_to}")
else else
flash["warning"] = "Could not add action \"#{item.description}\" to context" flash["warning"] = "Couldn't add next action \"#{item.description}\""
redirect_to( :controller => "context", :action => "show", :name => "#{back_to}" ) render_text ""
end end
end end
# Fairly self-explanatory; deletes the context # Fairly self-explanatory; deletes the context
# If the context contains actions, you'll get a warning dialogue. # If the context contains actions, you'll get a warning dialogue.
# If you choose to go ahead, any actions in the context will also be deleted. # If you choose to go ahead, any actions in the context will also be deleted.
def destroy def destroy
expire_action(:controller => "context", :action => "list") this_context = Context.find(params[:id])
context = Context.find( @params['id'] ) if this_context.destroy
if context.destroy render_text ""
flash["confirmation"] = "Succesfully deleted context \"#{context.name}\""
redirect_to( :action => "list" )
else else
flash["warning"] = "Couldn't delete context \"#{context.name}\"" flash["warning"] = "Couldn't delete context \"#{context.name}\""
redirect_to( :action => "list" ) redirect_to( :controller => "context", :action => "list" )
end end
end end
# Delete a next action in a context
#
def destroy_action
item = Todo.find(params[:id])
if item.destroy
render_text ""
else
flash["warning"] = "Couldn't delete next action \"#{item.description}\""
redirect_to :action => "list"
end
end
# Toggles the 'done' status of the action
#
def toggle_check
@places = Context.find(:all)
@projects = Project.find(:all)
item = Todo.find(params[:id])
item.toggle!('done')
render_partial 'show_items', item
end
end end

View file

@ -5,7 +5,6 @@ class ProjectController < ApplicationController
model :todo model :todo
before_filter :login_required before_filter :login_required
caches_action :list
layout "standard" layout "standard"
def index def index
@ -18,105 +17,129 @@ class ProjectController < ApplicationController
# #
def list def list
@page_title = "TRACKS::List Projects" @page_title = "TRACKS::List Projects"
@projects = Project.find_all @projects = Project.find(:all, :conditions => nil, :order => "position ASC")
end end
# Filter the projects to show just the one passed in the URL # Filter the projects to show just the one passed in the URL
# e.g. <home>/project/show/<project_id> shows just <project_id>. # e.g. <home>/project/show/<project_name> shows just <project_name>.
# #
def show def show
@project = Project.find_by_name(@params["name"].humanize) @project = Project.find_by_name(@params["name"].humanize)
@places = Context.find_all @places = Context.find(:all)
@projects = Project.find(:all)
@page_title = "TRACKS::Project: #{@project.name}" @page_title = "TRACKS::Project: #{@project.name}"
@not_done = Todo.find_all( "project_id=#{@project.id} AND done=0", "due DESC, created ASC" ) @not_done = Todo.find(:all, :conditions => "done=0 AND project_id=#{@project.id}",
@count = Todo.count( "project_id=#{@project.id} AND done=0" ) :order => "due IS NULL, due ASC, created ASC")
@done = Todo.find(:all, :conditions => "done=1 AND project_id=#{@project.id}",
:order => "completed DESC")
@count = @not_done.length
end end
def new_project
def edit @project = Project.new(@params['project'])
expire_action(:controller => "project", :action => "list")
@project = Project.find(@params['id'])
@page_title = "TRACKS::Edit project: #{@project.name.capitalize}"
end
def update
@project = Project.find(@params['project']['id'])
@project.attributes = @params['project']
if @project.save if @project.save
flash["confirmation"] = "Project \"#{@project.name}\" was successfully updated" render_partial( 'project_listing', @project )
redirect_to :action => 'list'
else else
flash["warning"] = "Project \"#{@project.name}\" could not be updated" flash["warning"] = "Couldn't update new project"
redirect_to :action => 'list' render_text ""
end end
end end
# Edit the details of the project
# Called by a form button
# Parameters from form fields should be passed to create new project
# #
def add_project def update
expire_action(:controller => "project", :action => "list") project = Project.find(params[:id])
project = Project.new project.attributes = @params["project"]
project.name = @params["new_project"]["name"]
if project.save if project.save
flash["confirmation"] = "Succesfully added project \"#{project.name}\"" render_partial 'project_listing', project
redirect_to( :action => "list" )
else else
flash["warning"] = "Couldn't add project \"#{project.name}\"" flash["warning"] = "Couldn't update new project"
redirect_to( :action => "list" ) render_text ""
end end
end end
def new # Edit the details of the action in this project
expire_action(:controller => "project", :action => "list") #
project = Project.new def update_action
project.name = @params["new_project"]["name"] @places = Context.find(:all)
@projects = Project.find(:all)
action = Todo.find(params[:id])
action.attributes = @params["item"]
if project.save if action.due?
flash["confirmation"] = "Succesfully added project \"#{project.name}\"" action.due = Date.strptime(@params["item"]["due"], DATE_FORMAT)
redirect_to( :action => "list" )
else else
flash["warning"] = "Couldn't add project \"#{project.name}\"" action.due = ""
redirect_to( :action => "list" )
end
end end
if action.save
render_partial 'show_items', action
else
flash["warning"] = "Couldn't update the action"
render_text ""
end
end
# Called by a form button # Called by a form button
# Parameters from form fields should be passed to create new item # Parameters from form fields are passed to create new action
# #
def add_item def add_item
expire_action(:controller => "project", :action => "list") @projects = Project.find( :all )
@places = Context.find( :all )
item = Todo.new item = Todo.new
item.attributes = @params["new_item"] item.attributes = @params["new_item"]
back_to = item.project_id if item.due?
item.due = Date.strptime(@params["new_item"]["due"], DATE_FORMAT)
else
item.due = ""
end
if item.save if item.save
flash["confirmation"] = "Successfully added next action \"#{item.description}\" to project" render_partial 'show_items', item
redirect_to( :controller => "project", :action => "show", :id => "#{back_to}" )
else else
flash["warning"] = "Couldn't add next action \"#{item.description}\" to project" flash["warning"] = "Couldn't add next action \"#{item.description}\""
redirect_to( :controller => "project", :action => "show", :id => "#{back_to}" ) render_text ""
end end
end end
# Delete a project
#
def destroy def destroy
expire_action(:controller => "project", :action => "list") this_project = Project.find( @params['id'] )
project = Project.find( @params['id'] ) if this_project.destroy
if project.destroy render_text ""
flash["confirmation"] = "Succesfully deleted project \"#{project.name}\""
redirect_to( :action => "list" )
else else
flash["warning"] = "Couldn't delete project \"#{project.name}\"" flash["warning"] = "Couldn't delete project \"#{project.name}\""
redirect_to( :action => "list" ) redirect_to( :controller => "project", :action => "list" )
end end
end end
# Delete a next action in a project
#
def destroy_action
item = Todo.find(@params['id'])
if item.destroy
#flash["confirmation"] = "Next action \"#{item.description}\" was successfully deleted"
render_text ""
else
flash["warning"] = "Couldn't delete next action \"#{item.description}\""
redirect_to :action => "list"
end
end
# Toggles the 'done' status of the action
#
def toggle_check
@places = Context.find(:all)
@projects = Project.find(:all)
item = Todo.find(@params['id'])
item.toggle!('done')
render_partial 'show_items', item
end
end end

View file

@ -4,27 +4,25 @@ class TodoController < ApplicationController
model :context, :project model :context, :project
before_filter :login_required before_filter :login_required
caches_action :list, :completed, :completed_archive
layout "standard" layout "standard"
# Main method for listing tasks
# Set page title, and fill variables with contexts and done and not-done tasks
# Number of completed actions to show is determined by a setting in settings.yml
#
def index def index
list list
render_action "list" render_action "list"
end end
# Main method for listing tasks
# Set page title, and fill variables with contexts and done and not-done tasks
# Number of completed actions to show is determined by a setting in settings.yml
#
def list def list
@page_title = "TRACKS::List tasks" @page_title = "TRACKS::List tasks"
@no_of_actions = app_configurations["formats"]["hp_completed"] @projects = Project.find( :all )
@projects = Project.find_all @places = Context.find( :all )
@places = Context.find_all @shown_places = Context.find( :all, :conditions => "hide=0", :order => "position ASC" )
@shown_places = Context.find_all_by_hide( "0", "position ASC") @hidden_places = Context.find( :all, :conditions => "hide=1", :order => "position ASC" )
@hidden_places = Context.find_all_by_hide( "1", "position ASC" ) @done = Todo.find( :all, :conditions => "done=1", :order => "completed DESC",
@done = Todo.find_all_by_done( 1, "completed DESC", @no_of_actions ) :limit => NO_OF_ACTIONS )
# Set count badge to number of not-done, not hidden context items # Set count badge to number of not-done, not hidden context items
@count = count_shown_items( @hidden_places ) @count = count_shown_items( @hidden_places )
@ -59,53 +57,56 @@ class TodoController < ApplicationController
end end
# Called by a form button # Called by a form button
# Parameters from form fields should be passed to create new item # Parameters from form fields are passed to create new action
# # in the selected context.
def add_item def add_item
expire_action(:controller => "todo", :action => "list") @projects = Project.find( :all )
@item = Todo.new @places = Context.find( :all )
@item.attributes = @params["item"]
if @item.save item = Todo.new
flash["confirmation"] = "Next action \"#{@item.description}\" was successfully added" item.attributes = @params["new_item"]
redirect_to( :action => "list" )
if item.due?
item.due = Date.strptime(@params["new_item"]["due"], DATE_FORMAT)
else else
flash["warning"] = "Couldn't add the action \"#{@item.description}\"" item.due = ""
redirect_to( :action => "list" )
end
end end
if item.save
def edit render_partial 'show_items', item
expire_action(:controller => "todo", :action => "list")
@item = Todo.find(@params['id'])
@belongs = @item.project_id
@projects = Project.find_all
@places = Context.find_all
@page_title = "TRACKS::Edit task: #{@item.description}"
end
def update
expire_action(:controller => "todo", :action => "list")
@item = Todo.find(@params['item']['id'])
@item.attributes = @params['item']
if @item.save
flash["confirmation"] = "Next action \"#{@item.description}\" was successfully updated"
redirect_to :action => 'list'
else else
flash["warning"] = "Next action \"#{@item.description}\" could not be updated" flash["warning"] = "Couldn't add next action \"#{item.description}\""
redirect_to :action => 'list' render_text ""
end end
end end
# Edit the details of an action
#
def update_action
@places = Context.find(:all)
@projects = Project.find(:all)
action = Todo.find(params[:id])
action.attributes = @params["item"]
if action.due?
action.due = Date.strptime(@params["item"]["due"], DATE_FORMAT)
else
action.due = ""
end
def destroy if action.save
expire_action(:controller => "todo", :action => "list") render_partial 'show_items', action
else
flash["warning"] = "Couldn't update the action"
render_text ""
end
end
# Delete a next action in a context
#
def destroy_action
item = Todo.find(@params['id']) item = Todo.find(@params['id'])
if item.destroy if item.destroy
flash["confirmation"] = "Next action \"#{item.description}\" was successfully deleted" render_text ""
redirect_to :action => "list"
else else
flash["warning"] = "Couldn't delete next action \"#{item.description}\"" flash["warning"] = "Couldn't delete next action \"#{item.description}\""
redirect_to :action => "list" redirect_to :action => "list"
@ -115,21 +116,13 @@ class TodoController < ApplicationController
# Toggles the 'done' status of the action # Toggles the 'done' status of the action
# #
def toggle_check def toggle_check
expire_action(:controller => "todo", :action => "list") @projects = Project.find(:all)
expire_action(:controller => "todo", :action => "completed") @places = Context.find(:all)
expire_action(:controller => "todo", :action => "completed_archive")
item = Todo.find(@params['id']) item = Todo.find(@params['id'])
item.toggle!('done') item.toggle!('done')
render_partial 'show_items', item
if item.save
flash["confirmation"] = "Next action \"#{item.description}\" marked as completed"
redirect_to( :action => "list" )
else
flash["warning"] = "Couldn't mark action \"#{item.description}\" as completed"
redirect_to( :action => "list" )
end
end end
end end

View file

@ -5,8 +5,11 @@ module ApplicationHelper
# in config/settings.yml # in config/settings.yml
# #
def format_date(date) def format_date(date)
date_fmt = app_configurations["formats"]["date"] if date
formatted_date = date.strftime("#{date_fmt}") formatted_date = date.strftime("#{ApplicationController::DATE_FORMAT}")
else
formatted_date = ''
end
end end
# Uses RedCloth to transform text using either Textile or Markdown # Uses RedCloth to transform text using either Textile or Markdown
@ -52,4 +55,5 @@ module ApplicationHelper
"<span class=\"green\">" + format_date(due) + "</span> " "<span class=\"green\">" + format_date(due) + "</span> "
end end
end end
end end

View file

@ -8,4 +8,5 @@ class Project < ActiveRecord::Base
validates_presence_of :name, :message => "project must have a name" validates_presence_of :name, :message => "project must have a name"
validates_length_of :name, :maximum => 255, :message => "project name must be less than %d" validates_length_of :name, :maximum => 255, :message => "project name must be less than %d"
validates_uniqueness_of :name, :message => "already exists" validates_uniqueness_of :name, :message => "already exists"
end end

View file

@ -0,0 +1,14 @@
<%
@context = context_form
%>
<!-- %= error_messages_for 'context' % -->
<div class="position">
<%= @context.position %>
</div>
<div class="data">
<label for="context_name">Name</label>
<%= text_field 'context', 'name', :class => 'context-name' %>
<label for="context_hide">Hidden?</label>
<%= check_box 'context', 'hide', :class => 'context-hide' %>
</div>
<% @context = nil %>

View file

@ -0,0 +1,50 @@
<% context = context_listing %>
<div id="context-<%= context.id %>-container" class="container">
<!-- %= error_messages_for 'context' % -->
<div id="context-<%= context.id %>-display" class="list">
<% if context.position % 2 == 0 %>
<div id="context-<%= context.id %>" class="even_row" style="display:'';">
<% else %>
<div id="context-<%= context.id %>" class="odd_row" style="display:'';">
<% end %>
<div class="position">
<%= context.position.to_s %>
</div>
<div class="data">
<%= link_to( "#{context.name}", :action => "show", :name => urlize(context.name) ) %><%= " (" + Todo.count( "context_id=#{context.id} AND done=0" ).to_s + " actions)" %>
</div>
<div class="buttons">
<% if context.hide == 1 %>
<input type="checkbox" value="1" checked="checked" disabled="true" />
<% else %>
<input type="checkbox" value="0" disabled="true" />
<% end %>
<%= link_to_function(image_tag( "edit", :title => "Edit item", :width=>"10", :height=>"10", :border=>"0"), "Element.toggle('context-#{context.id}','context-#{context.id}-edit-form'); new Effect.Appear('context-#{context.id}-edit-form'); Form.focus_first('form-context-#{context.id}');" ) + " " +
link_to_remote( image_tag("delete", :title =>"Delete this context"),
:update => "context-#{context.id}-container",
:loading => "new Effect.Squish('context-#{context.id}-container')",
:url => { :controller => "context", :action => "destroy", :id => context.id }, :confirm => "Are you sure that you want to delete the context \'#{context.name}\'?" ) %>
</div>
</div><!-- [end:context-context.id] -->
</div><!-- [end:context-context.id-display] -->
<div id="context-<%= context.id %>-edit-form" class="edit-form" style="display:none;">
<%= form_remote_tag :url => { :controller => 'context', :action => 'update', :id => context.id },
:html => { :id => "form-context-#{context.id}", :class => "inline-form" },
:update => "context-#{context.id}-container",
:complete => "new Effect.Appear('context-#{context.id}-container');" %>
<%= render_partial 'context_form', context %>
<div class="buttons">
<input type="submit" value="Update" />
<a href="javascript:void(0);" onclick="Element.toggle('context-<%= context.id %>','context-<%= context.id %>-edit-form');Form.reset('form-context-<%= context.id %>');">Cancel</a>
</div>
<%= end_form_tag %>
</div><!-- [end:context-context.id-edit-form] -->
</div><!-- [end:context-context.id-container] -->
<% if controller.action_name == 'new_context' %>
<script>
new Effect.Appear('context-<%= context.id %>');
</script>
<% end %>

View file

@ -1,26 +0,0 @@
<% @item = not_done %>
<tr>
<td valign="top">
<%=
link = url_for( :controller => 'todo', :action => 'toggle_check', :id => "#{@item.id}" ); check_box( "item", "done", :onclick => "document.location.href='#{link}'" )
%>
</td>
<td valign="top" width="30">
<%=
link_to(image_tag( "edit", :title => "Edit item", :width=>"10", :height=>"10", :border=>"0"), { :controller =>"todo", :action => "edit", :id => @item.id } ) + " " + link_to(image_tag( "delete", :title => "Delete item", :width=>"10", :height=>"10", :border=>"0" ), { :controller => "todo", :action => "destroy", :id => @item.id}, :confirm => "Are you sure you want to delete this entry: #{@item.description}" ) + " "
%>
</td>
<td valign="top"><%= due_date( @item.due ) %>
<%= @item.description %>
<% if @item.project_id %>
<%= link_to( "[P]", { :controller => "project", :action => "show", :name => urlize(@item.project.name) }, :title => "View project: #{@item.project.name}" ) %>
<% end %>
<% if @item.notes? %>
<%= "<a href=\"javascript:toggle('" + @item.id.to_s + "')\" title=\"Show notes\">" +
image_tag( "notes", :width=>"10", :height=>"10", :border=>"0") + "</a>"
%>
<% m_notes = markdown( @item.notes ) %>
<%= "<div class=\"notes\" id=\"" + @item.id.to_s + "\">" + m_notes + "</div>" %>
<% end %>
</td>
</tr>

View file

@ -0,0 +1,84 @@
<% item = show_items %>
<% if !item.done? %>
<div id="item-<%= item.id %>-container">
<%= form_remote_tag( :url => url_for( :controller => "context", :action => "toggle_check", :id => item.id ),
:html => { :id=> "checkbox-notdone-#{item.id}", :class => "inline-form" },
:update => "completed",
:position => "top",
:loading => "Form.disable('checkbox-notdone-#{item.id}');",
:complete => "new Effect.Squish('item-#{item.id}-container', true);"
) %>
<div id="item-<%= item.id %>">
<div class="big-box">
<input type="checkbox" name="item_id" value="<%= item.id %>" onclick="document.forms['checkbox-notdone-<%= item.id %>'].onsubmit();" />
<%=
link_to_function(image_tag( "edit", :title => "Edit item", :width=>"10", :height=>"10", :border=>"0"), "Element.toggle('item-#{item.id}','action-#{item.id}-edit-form'); new Effect.Appear('action-#{item.id}-edit-form'); Form.focusFirstElement('form-action-#{item.id}');" ) + " " +
link_to_remote( image_tag("delete", :title =>"Delete this action"),
:update => "item-#{item.id}-container",
:loading => "new Effect.Squish('item-#{item.id}-container')",
:url => { :controller => "context", :action => "destroy_action", :id => item.id }, :confirm => "Are you sure that you want to delete the action \'#{item.description}\'?" ) + " "
%>
</div>
<div class="description">
<%= due_date( item.due ) %>
<%= item.description %>
<% if item.project_id %>
<%= link_to( "[P]", { :controller => "project", :action => "show", :name => urlize(item.project.name) }, :title => "View project: #{item.project.name}" ) %>
<% end %>
<% if item.notes? %>
<%= "<a href=\"javascript:Element.toggle('" + item.id.to_s + "')\" title=\"Show notes\">" + image_tag( "notes", :width=>"10", :height=>"10", :border=>"0") + "</a>" %>
<% m_notes = markdown( item.notes ) %>
<%= "<div class=\"notes\" id=\"" + item.id.to_s + "\" style=\"display:none\">" + m_notes + "</div>" %>
<% end %>
</div>
</div><!-- [end:item-item.id] -->
<%= end_form_tag %>
<div id="action-<%= item.id %>-edit-form" class="edit-form" style="display:none;">
<%= form_remote_tag :url => { :controller => 'context', :action => 'update_action', :id => item.id },
:html => { :id => "form-action-#{item.id}", :class => "inline-form" },
:update => "item-#{item.id}-container",
:complete => "new Effect.Appear('item-#{item.id}-container');" %>
<%= render_partial 'todo/action_edit_form', item %>
<%= end_form_tag %>
</div><!-- [end:action-item.id-edit-form] -->
</div><!-- [end:item-item.id-container] -->
<% else %>
<div id="done-item-<%= item.id %>-container">
<%= form_remote_tag( :url => url_for( :controller => "context", :action => "toggle_check", :id => item.id ),
:html => { :id=> "checkbox-done-#{item.id}", :class => "inline-form" },
:update => "next_actions",
:position => "bottom",
:loading => "Form.disable('checkbox-done-#{item.id}');",
:complete => "new Effect.Squish('done-item-#{item.id}-container', true);"
) %>
<div id="done-item-<%= item.id %>">
<div class="big-box">
<input type="checkbox" name="item_id" value="<%= item.id %>" checked="checked" onclick="document.forms['checkbox-done-<%= item.id %>'].onsubmit();" />
<%=
link_to_remote( image_tag("delete", :title =>"Delete this action"),
:update => "done-item-#{item.id}-container",
:loading => "new Effect.Squish('done-item-#{item.id}-container')",
:url => { :controller => "context", :action => "destroy_action", :id => item.id }, :confirm => "Are you sure that you want to delete the action \'#{item.description}\'?" ) + " "
%>
</div><!-- [end:big-box] -->
<div class="description">
<span class="grey"><%= format_date( item.completed ) %></span>
<%= item.description %>
<% if item.project_id %>
<%= link_to( "[P]", { :controller => "project", :action => "show", :name => urlize(item.project.name) }, :title => "View project: #{item.project.name}" ) %>
<% end %>
<% if item.notes? %>
<%= "<a href=\"javascript:Element.toggle('" + item.id.to_s + "')\" title=\"Show notes\">" + image_tag( "notes", :width=>"10", :height=>"10", :border=>"0") + "</a>" %>
<% m_notes = markdown( item.notes ) %>
<%= "<div class=\"notes\" id=\"" + item.id.to_s + "\" style=\"display:none\">" + m_notes + "</div>" %>
<% end %>
</div><!-- [end:description] -->
</div><!-- [end:item-item.id] -->
<%= end_form_tag %>
</div><!-- [end:item-item.id-container] -->
<% end %>
<% item = nil %>

View file

@ -1,13 +0,0 @@
<div id="display_box">
<h2>Edit context</h2>
<%= error_messages_for 'context' %>
<%= start_form_tag :controller=>"context", :action=>"update", :id=>@context.id %>
<%= render_partial "edit_context", "@context" %>
<input type="submit" value="Update" />
<%= end_form_tag %>
<%= link_to 'Cancel', :action => 'list' %>
</div>
<% if @flash["confirmation"] %><div class="confirmation"><%= @flash["confirmation"] %></div><% end %>
<% if @flash["warning"] %><div class="warning"><%= @flash["warning"] %></div><% end %>

View file

@ -1,45 +1,36 @@
<div id="display_box"> <div id="full_width_display">
<table class="list" cellspacing="0" cellpadding="5" width="450" border="0"> <div id="list-contexts">
<% row = 1 %> <% for context in @contexts %>
<% for @context in @contexts %> <%= render_partial( 'context_listing', context ) %>
<% if row % 2 == 0 %>
<tr class="even_row">
<% else %>
<tr class="odd_row">
<% end %> <% end %>
<td align="right" width="20"><%= @context.position.to_s %></td>
<!-- <td width="390"><%= link_to( "#{@context.name.capitalize}", :action => "show", :id => @context.id ) %></td> -->
<td width="390"><%= link_to( "#{@context.name.capitalize}", :action => "show", :name => urlize(@context.name) ) %></td>
<td>
<% if @context.hide == 1 %>
hidden
<% else %>
shown
<% end %>
</td>
<td width="40">
<%= link_to(image_tag( "edit", :title => "Edit item", :width=>"10", :height=>"10", :border=>"0"), { :action => "edit", :id => @context.id } ) + " " + link_to(image_tag( "delete", :title => "Delete item", :width=>10, :height=>10, :border=>0 ), { :action => "destroy", :id => @context.id}, :confirm => "Are you sure you want to delete the context \"#{@context.name}?\" Any todos in this context will be deleted." ) %>
</td>
</tr>
<% row += 1 %>
<% end %>
</table>
</div><!- End of display_box -->
<div id="input_box">
<%= start_form_tag :controller=>'context', :action=>'new' %>
<label for="new_context_name">New context</label><br />
<%= text_field("new_context", "name") %>
<br />
<label for="new_context_one_front">Hide from front page?</label>
<%= check_box( "new_context", "hide" ) %>
<br />
<br />
<input type="submit" value="Add context">
<%= end_form_tag %>
</div> </div>
<% if @flash["confirmation"] %><div class="confirmation"><%= @flash["confirmation"] %></div><% end %> <br />
<% if @flash["warning"] %><div class="warning"><%= @flash["warning"] %></div><% end %> <a href="javascript:void(0)" onClick="Element.toggle('context_new'); Form.focus_first('context-form');" accesskey="n" title="Create a new context [Alt+n]">Create new context &#187;</a>
<div id="context_new" class="context_new" style="display:none">
<!--[form:context]-->
<%= form_remote_tag :url => { :action => "new_context" },
:update=> "list-contexts",
:position=> "bottom",
:loading => "context.reset()",
:complete => "Form.focus_first('context-form');",
:html=> { :id=>'context-form', :name=>'context', :class => 'inline-form' } %>
<%= hidden_field( "context", "id" ) %>
<label for="context_name">Context name</label>
<%= text_field( "context", "name" ) %>
<label for="new_context_on_front">Hide from front page?</label>
<%= check_box( "context", "hide" ) %>
<input type="submit" value="Add" />
<%= end_form_tag %>
<!--[eoform:context]-->
</div>
<% if @flash["confirmation"] %>
<div class="confirmation"><%= @flash["confirmation"] %></div>
<% end %>
<% if @flash["warning"] %>
<div class="warning"><%= @flash["warning"] %></div>
<% end %>
</div><!- End of display_box -->

View file

@ -1,49 +1,81 @@
<div id="display_box"> <div id="display_box">
<div class="contexts"> <div class="contexts">
<h2><%= @context.name.capitalize %></h2> <h2><%= @context.name %></h2>
<table class="next_actions" cellspacing="2" cellpadding="0" border="0">
<%= render_collection_of_partials "not_done", @not_done %> <div id="next_actions">
</table> <% if @not_done.empty? %>
</div> <p>There are no next actions yet in this context</p>
<p>Other Contexts: <% else %>
<% for other_context in Context.find_all %> <% for item in @not_done %>
<%= link_to( other_context.name.capitalize, { :controller => "context", :action => "show", :name => urlize(other_context.name) } ) + " | " %> <%= render_partial "show_items", item %>
<% end %> <% end %>
</p> <% end %>
</div><!- End of display_box --> </div><!-- [end:next_actions] -->
</div><!-- [end:contexts] -->
<div class="contexts">
<h2>Completed actions in this context</h2>
<div id="completed">
<% if @done.empty? %>
<p>There are no completed next actions yet in this context</p>
<% else %>
<% for done_item in @done %>
<%= render_partial "show_items", done_item %>
<% end %>
<% end %>
</div>
</div><!-- [end:contexts] -->
</div><!-- [end:display_box] -->
<div id="input_box"> <div id="input_box">
<%= form_tag( :controller => "context", :action => "add_item") %>
<%= link_to_function( "Add the next action in this context &#187;", "Element.toggle('context_new_action'); Form.focusFirstElement('context-form-new-action');", {:title => "Add the next action [Alt+n]", :accesskey => "n"}) %>
<div id="context_new_action" class="context_new" style="display:none">
<!--[form:context]-->
<%= form_remote_tag :url => { :action => "add_item" },
:update=> "next_actions",
:position=> "bottom",
:loading => "context.reset()",
:complete => "Form.focusFirstElement('context-form-new-action');",
:html=> { :id=>'context-form-new-action', :name=>'context', :class => 'inline-form' } %>
<%= hidden_field( "new_item", "context_id", "value" => "#{@context.id}") %> <%= hidden_field( "new_item", "context_id", "value" => "#{@context.id}") %>
<label for="new_item_description">Next action in this context</label><br /> <label for="new_item_description">Description</label><br />
<%= text_field( "new_item", "description" ) %> <%= text_field( "new_item", "description", "size" => 25, "tabindex" => 1 ) %><br />
<br />
<label for="new_item_notes">Notes</label><br /> <label for="new_item_notes">Notes</label><br />
<%= text_area( "new_item", "notes", "cols" => 40, "rows" => 15 ) %> <%= text_area( "new_item", "notes", "cols" => 25, "rows" => 10, "tabindex" => 2 ) %><br />
<br />
<label for="new_item_project_id">Project</label><br /> <label for="new_item_project_id">Project</label><br />
<select name="new_item[project_id]" id="new_item_project_id"> <select name="item[project_id]" id="item_project_id" tabindex="3">
<option value="" selected>None</option> <option selected="selected"></option>
<%= options_from_collection_for_select(@projects, "id", "name") %> <%= options_from_collection_for_select(@projects, "id", "name") %>
</select><br /> </select><br />
<label for="item_due" tab>Due</label><br /> <label for="item_due">Due</label><br />
<%= text_field( "item", "due", "tabindex" => 5, "cols" => 10 ) %> <%= text_field("new_item", "due", "size" => 10, "class" => "Date", "onFocus" => "Calendar.setup", "tabindex" => 4) %>
<img src="/images/calendar.gif" onclick="showCal('','',document.forms[0].item_due,2,true,9)" style="cursor:pointer;cursor:hand" /> <br /><br />
<div id="calDiv" style="display:none"> <input type="submit" value="Add item" tabindex="5">
<div id="calTopBar">CLOSE <span onclick="document.getElementById('calDiv').style.display='none';" id="calClose">X</span></div> <%= end_form_tag %><!--[eoform:context]-->
<table width="100%" id="calNav"> <script type="text/javascript">
<tr><td id="calNavPY"></td><td id="calNavPM"></td><td id="calNavMY" width="100"></td><td id="calNavNM"></td><td id="calNavNY"></td></tr> Calendar.setup({ ifFormat:"<%= ApplicationController::DATE_FORMAT %>",firstDay:<%= ApplicationController::WEEK_STARTS_ON %>,showOthers:true,range:[2004, 2010],step:1,inputField:"new_item_due",cache:true,align:"TR" })
</table> </script>
<table id="calTbl" width="100%" cellspacing="0">
<thead><tr style="background-color:#eaeaea"><td>Sun</td><td>Mon</td><td>Tue</td><td>Wed</td><td>Thu</td><td>Fri</td><td>Sat</td></tr></thead> </div><!-- [end:context-new-action] -->
<tbody></tbody>
</table> <h3>Active Contexts:</h3>
</div> <ul>
<br /> <% for other_context in Context.find(:all, :conditions => "hide=0", :order => "position ASC") %>
<br /> <li><%= link_to( other_context.name, { :controller => "context", :action => "show", :name => urlize(other_context.name) } ) + " (" + Todo.count( "project_id=#{other_context.id} AND done=0" ).to_s + " actions)" %></li>
<input type="submit" value="Add item"> <% end %>
</form> </ul>
<h3>Hidden Contexts:</h3>
<ul>
<% for other_context in Context.find(:all, :conditions => "hide=1", :order => "position ASC") %>
<li><%= link_to( other_context.name, { :controller => "context", :action => "show", :name => urlize(other_context.name) } ) + " (" + Todo.count( "project_id=#{other_context.id} AND done=0" ).to_s + " actions)" %></li>
<% end %>
</ul>
</div><!-- End of input box --> </div><!-- End of input box -->
<% if @flash["confirmation"] %><div class="confirmation"><%= @flash["confirmation"] %></div><% end %> <% if @flash["confirmation"] %><div class="confirmation"><%= @flash["confirmation"] %></div><% end %>

View file

@ -8,7 +8,7 @@ xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
xml.title(i.description) xml.title(i.description)
@link = url_for(:controller => 'context', :action => 'show', :id => "#{i.context_id}") @link = url_for(:controller => 'context', :action => 'show', :id => "#{i.context_id}")
xml.link("http://#{@request.host}:#{@request.port}#{@link}") xml.link("http://#{@request.host}:#{@request.port}#{@link}")
xml.description(i.context['name'].capitalize) xml.description(i.context['name'])
end end
} }
end end

View file

@ -3,29 +3,23 @@
<head> <head>
<%= stylesheet_link_tag "standard" %> <%= stylesheet_link_tag "standard" %>
<%= javascript_include_tag "toggle_notes" %> <%= javascript_include_tag "toggle_notes" %>
<%= javascript_include_tag "calendar" %> <%= javascript_include_tag "prototype" %>
<%= javascript_include_tag "prototype-ex" %>
<%= stylesheet_link_tag 'calendar-system.css' %>
<%= javascript_include_tag 'calendar', 'calendar-en', 'calendar-setup' %>
<link rel="shortcut icon" href="<%= url_for(:controller => 'favicon.ico') %>" /> <link rel="shortcut icon" href="<%= url_for(:controller => 'favicon.ico') %>" />
<title><%= @page_title %></title> <title><%= @page_title %></title>
<script>
var date = new Date();
var curr_dy = date.getDate();
var curr_mn = date.getMonth();
var curr_yr = date.getFullYear();
var DOMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
var lDOMonth = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
var moty = ["January","February","March","April","May","June","July","August","September","October","November","December"];
</script>
</head> </head>
<body onload="javascript:toggleAll('notes','none'); toggleAllImages();"> <body>
<div> <div>
<h1> <h1>
<% if @count %> <% if @count %>
<span class="badge"><%= @count %></span> <span class="badge"><%= @count %></span>
<% end %> <% end %>
<%= today = Time.now; datestamp = today.strftime("%A, %d %B %Y") %></h1> <%= Time.now.strftime("%A, %d %B %Y") %></h1>
</div> </div>
<div id="navcontainer"> <div id="navcontainer">
<ul id="navlist"> <ul id="navlist">

View file

@ -8,10 +8,10 @@
<% end %> <% end %>
<label for="user_login">Login:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label> <label for="user_login">Login:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label>
<input type="text" name="user_login" id="user_login" size="30" value=""/><br/> <input type="text" name="user_login" id="user_login" size="20" value=""/><br/>
<label for="user_password">Password:</label> <label for="user_password">Password:</label>
<input type="password" name="user_password" id="user_password" size="30"/> <input type="password" name="user_password" id="user_password" size="20"/>
<br/> <br/>
<input type="submit" name="login" value="Login &#187;" class="primary" /> <input type="submit" name="login" value="Login &#187;" class="primary" />

View file

@ -6,26 +6,26 @@
<h3>Sign up as the admin user</h3> <h3>Sign up as the admin user</h3>
<%= render_errors @user %><br/> <%= render_errors @user %><br/>
<label for="user_login">Desired login:</label><br/> <label for="user_login">Desired login:</label><br/>
<%= text_field "user", "login", :size => 30 %><br/> <%= text_field "user", "login", :size => 20 %><br/>
<label for="user_password">Choose password:</label><br/> <label for="user_password">Choose password:</label><br/>
<%= password_field "user", "password", :size => 30 %><br/> <%= password_field "user", "password", :size => 20 %><br/>
<label for="user_password_confirmation">Confirm password:</label><br/> <label for="user_password_confirmation">Confirm password:</label><br/>
<%= password_field "user", "password_confirmation", :size => 30 %><br/> <%= password_field "user", "password_confirmation", :size => 20 %><br/>
<label for="user_word">Secret word (different to password):</label><br /> <label for="user_word">Secret word (different to password):</label><br />
<%= password_field "user", "word", :size => 30 %><br /> <%= password_field "user", "word", :size => 20 %><br />
<input type="submit" value="Signup &#187;" class="primary" /> <input type="submit" value="Signup &#187;" class="primary" />
<% elsif (@session['user'] && @session['user']['is_admin'] == 1) %> <% elsif (@session['user'] && @session['user']['is_admin'] == 1) %>
<%= hidden_field "user", "is_admin", "value" => 0 %> <%= hidden_field "user", "is_admin", "value" => 0 %>
<h3>Sign up a new user</h3> <h3>Sign up a new user</h3>
<%= render_errors @user %><br/> <%= render_errors @user %><br/>
<label for="user_login">Desired login:</label><br/> <label for="user_login">Desired login:</label><br/>
<%= text_field "user", "login", :size => 30 %><br/> <%= text_field "user", "login", :size => 20 %><br/>
<label for="user_password">Choose password:</label><br/> <label for="user_password">Choose password:</label><br/>
<%= password_field "user", "password", :size => 30 %><br/> <%= password_field "user", "password", :size => 20 %><br/>
<label for="user_password_confirmation">Confirm password:</label><br/> <label for="user_password_confirmation">Confirm password:</label><br/>
<%= password_field "user", "password_confirmation", :size => 30 %><br/> <%= password_field "user", "password_confirmation", :size => 20 %><br/>
<label for="user_word">Secret word (different to password):</label><br /> <label for="user_word">Secret word (different to password):</label><br />
<%= password_field "user", "word", :size => 30 %><br /> <%= password_field "user", "word", :size => 20 %><br />
<input type="submit" value="Signup &#187;" class="primary" /> <input type="submit" value="Signup &#187;" class="primary" />
<% else %> <% else %>
<h3>Signup</h3> <h3>Signup</h3>

View file

@ -1,26 +0,0 @@
<% @item = not_done %>
<tr>
<td valign="top">
<%=
link = url_for(:controller => 'todo', :action => 'toggle_check', :id => "#{@item.id}")
check_box( "item", "done", :onclick => "document.location.href='#{link}'" )
%>
</td>
<td valign="top" width="30">
<%=
link_to(image_tag( "edit", :title => "Edit item", :width=>"10", :height=>"10", :border=>"0"), { :controller => "todo", :action => "edit", :id => @item.id } ) + " " +
link_to(image_tag( "delete", :title => "Delete item", :width=>"10", :height=>"10", :border=>"0"), { :controller => "todo", :action => "destroy", :id => @item.id}, :confirm => "Are you sure you want to delete this entry: #{@item.description}" ) + " "
%>
</td>
<td valign="top"><%= due_date( @item.due ) %>
<%= @item.description %>
<% if @item.project_id %>
<%= link_to( "[C]", { :controller => "context", :action => "show", :name => urlize(@item.context.name) }, :title => "View context: #{@item.context.name.capitalize}" ) %>
<% end %>
<% if @item.notes? %>
<%= "<a href=\"javascript:toggle('" + @item.id.to_s + "')\" title=\"Show notes\">" + image_tag( "notes", :width=>"10", :height=>"10", :border=>"0") + "</a>" %>
<% m_notes = markdown( @item.notes ) %>
<%= "<div class=\"notes\" id=\"" + @item.id.to_s + "\">" + m_notes + "</div>" %>
<% end %>
</td>
</tr>

View file

@ -0,0 +1,12 @@
<%
@project = project_form
%>
<!-- %= error_messages_for 'project' % -->
<div class="position">
<%= @project.position %>
</div>
<div class="data">
<label for="project_name">Name</label>
<%= text_field 'project', 'name', :class => 'project-name' %>
</div>
<% @project = nil %>

View file

@ -0,0 +1,43 @@
<% project = project_listing %>
<div id="project-<%= project.id %>-container">
<!-- %= error_messages_for 'project' % -->
<div id="project-<%= project.id %>-display" class="list">
<% if project.position % 2 == 0 %>
<div id="project-<%= project.id %>" class="even_row" style="display:'';">
<% else %>
<div id="project-<%= project.id %>" class="odd_row" style="display:'';">
<% end %>
<div class="position">
<%= project.position.to_s %>
</div>
<div class="data">
<%= link_to( "#{project.name}", :action => "show", :name => urlize(project.name) ) %><%= " (" + Todo.count( "project_id=#{project.id} AND done=0" ).to_s + " actions)" %>
</div>
<div class="buttons">
<%= link_to_function(image_tag( "edit", :title => "Edit item", :width=>"10", :height=>"10", :border=>"0"), "Element.toggle('project-#{project.id}','project-#{project.id}-edit-form'); new Effect.Appear('project-#{project.id}-edit-form'); Form.focus_first('form-project-#{project.id}');" ) + " " +
link_to_remote( image_tag("delete", :title =>"Delete this project"),
:update => "project-#{project.id}-container",
:loading => "new Effect.Squish('project-#{project.id}-container')",
:url => { :controller => "project", :action => "destroy", :id => project.id }, :confirm => "Are you sure that you want to delete the project \'#{project.name}\'?" ) %>
</div>
</div><!-- [end:project-project.id] -->
</div><!-- [end:project-project.id-display] -->
<div id="project-<%= project.id %>-edit-form" class="edit-form" style="display:none;">
<%= form_remote_tag :url => { :controller => 'project', :action => 'update', :id => project.id },
:html => { :id => "form-project-#{project.id}", :class => "inline-form" },
:update => "project-#{project.id}-container",
:complete => "new Effect.Appear('project-#{project.id}-container');" %>
<%= render_partial 'project_form', project %>
<div class="buttons">
<input type="submit" value="Update" />
<a href="javascript:void(0);" onclick="Element.toggle('project-<%= project.id %>','project-<%= project.id %>-edit-form');Form.reset('form-project-<%= project.id %>');">Cancel</a>
</div>
<%= end_form_tag %>
</div><!-- [end:project-project.id-edit-form] -->
</div><!-- [end:project-project.id-container] -->
<% if controller.action_name == 'new_project' %>
<script>
new Effect.Appear('project-<%= project.id %>');
</script>
<% end %>

View file

@ -0,0 +1,84 @@
<% item = show_items %>
<% if !item.done? %>
<div id="item-<%= item.id %>-container">
<%= form_remote_tag( :url => url_for( :controller => "project", :action => "toggle_check", :id => item.id ),
:html => { :id=> "checkbox-notdone-#{item.id}", :class => "inline-form" },
:update => "completed",
:position => "top",
:loading => "Form.disable('checkbox-notdone-#{item.id}');",
:complete => "new Effect.Squish('project-item-#{item.id}-container', true);"
) %>
<div id="item-<%= item.id %>">
<div class="big-box">
<input type="checkbox" name="item_id" value="<%= item.id %>" onclick="document.forms['checkbox-notdone-<%= item.id %>'].onsubmit();" />
<%=
link_to_function(image_tag( "edit", :title => "Edit item", :width=>"10", :height=>"10", :border=>"0"), "Element.toggle('item-#{item.id}','action-#{item.id}-edit-form'); new Effect.Appear('action-#{item.id}-edit-form'); Form.focusFirstElement('form-action-#{item.id}');" ) + " " +
link_to_remote( image_tag("delete", :title =>"Delete this action"),
:update => "item-#{item.id}-container",
:loading => "new Effect.Squish('item-#{item.id}-container')",
:url => { :controller => "project", :action => "destroy_action", :id => item.id }, :confirm => "Are you sure that you want to delete the action \'#{item.description}\'?" ) + " "
%>
</div>
<div class="description">
<%= due_date( item.due ) %>
<%= item.description %>
<% if item.context_id %>
<%= link_to( "[C]", { :controller => "context", :action => "show", :name => urlize(item.context.name) }, :title => "View context: #{item.context.name}" ) %>
<% end %>
<% if item.notes? %>
<%= "<a href=\"javascript:Element.toggle('" + item.id.to_s + "')\" title=\"Show notes\">" + image_tag( "notes", :width=>"10", :height=>"10", :border=>"0") + "</a>" %>
<% m_notes = markdown( item.notes ) %>
<%= "<div class=\"notes\" id=\"" + item.id.to_s + "\" style=\"display:none\">" + m_notes + "</div>" %>
<% end %>
</div>
</div><!-- [end:item-item.id] -->
<%= end_form_tag %>
<div id="action-<%= item.id %>-edit-form" class="edit-form" style="display:none;">
<%= form_remote_tag :url => { :controller => 'project', :action => 'update_action', :id => item.id },
:html => { :id => "form-action-#{item.id}", :class => "inline-form" },
:update => "item-#{item.id}-container",
:complete => "new Effect.Appear('item-#{item.id}-container');" %>
<%= render_partial 'todo/action_edit_form', item %>
<%= end_form_tag %>
</div><!-- [end:action-item.id-edit-form] -->
</div><!-- [end:item-item.id-container] -->
<% else %>
<div id="done-item-<%= item.id %>-container">
<%= form_remote_tag( :url => url_for( :controller => "project", :action => "toggle_check", :id => item.id ),
:html => { :id=> "checkbox-done-#{item.id}", :class => "inline-form" },
:update => "next_actions",
:position => "bottom",
:loading => "Form.disable('checkbox-done-#{item.id}');",
:complete => "new Effect.Squish('done-item-#{item.id}-container', true);"
) %>
<div id="done-item-<%= item.id %>">
<div class="big-box">
<input type="checkbox" name="item_id" value="<%= item.id %>" checked="checked" onclick="document.forms['checkbox-done-<%= item.id %>'].onsubmit();" />
<%=
link_to_remote( image_tag("delete", :title =>"Delete this action"),
:update => "done-item-#{item.id}-container",
:loading => "new Effect.Squish('done-item-#{item.id}-container')",
:url => { :controller => "project", :action => "destroy_action", :id => item.id }, :confirm => "Are you sure that you want to delete the action \'#{item.description}\'?" ) + " "
%>
</div><!-- [end:big-box] -->
<div class="description">
<span class="grey"><%= format_date( item.completed ) %></span>
<%= item.description %>
<% if item.project_id %>
<%= link_to( "[C]", { :controller => "context", :action => "show", :name => urlize(item.context.name) }, :title => "View context: #{item.context.name}" ) %>
<% end %>
<% if item.notes? %>
<%= "<a href=\"javascript:Element.toggle('" + item.id.to_s + "')\" title=\"Show notes\">" + image_tag( "notes", :width=>"10", :height=>"10", :border=>"0") + "</a>" %>
<% m_notes = markdown( item.notes ) %>
<%= "<div class=\"notes\" id=\"" + item.id.to_s + "\" style=\"display:none\">" + m_notes + "</div>" %>
<% end %>
</div><!-- [end:description] -->
</div><!-- [end:item-item.id] -->
<%= end_form_tag %>
</div><!-- [end:item-item.id-container] -->
<% end %>
<% item = nil %>

View file

@ -1,12 +0,0 @@
<div id="display_box">
<h2>Edit project</h2>
<form action="<%= url_for(:controller => 'project', :action => 'update') %>" method="post">
<%= render_partial "edit_project", "@project" %>
<input type="submit" value="Update" />
</form>
<%= link_to 'Cancel', :action => 'list' %>
</div>
<% if @flash["confirmation"] %><div class="confirmation"><%= @flash["confirmation"] %></div><% end %>
<% if @flash["warning"] %><div class="warning"><%= @flash["warning"] %></div><% end %>

View file

@ -1,44 +1,33 @@
<div id="display_box"> <div id="full_width_display">
<table class="list" cellspacing="0" cellpadding="5" width="450" border="0"> <div id="list-projects">
<tr> <% for project in @projects %>
<th align="left">ID</th> <%= render_partial( 'project_listing', project ) %>
<th align="left">Name</th>
<th align="left">Next actions</th>
<th></th>
</tr>
<% row = 1 %>
<% for @project in @projects %>
<% if row % 2 == 0 %>
<tr class="even_row">
<% else %>
<tr class="odd_row">
<% end %> <% end %>
<td align="right" width="20"><%= @project.id.to_s %></td>
<td width="300"><%= link_to( "#{@project.name}", :action => "show", :name => urlize(@project.name) ) %></td>
<td width="70"><%= Todo.count( "project_id=#{@project.id} AND done=0" ).to_s %></td>
<td width="40">
<%= link_to(image_tag( "edit", :title => "Edit item", :width=>"10", :height=>"10", :border=>"0"), { :action => "edit", :id => @project.id } ) + " " +
link_to(image_tag( "delete", :title => "Delete item", :width=>"10", :height=>"10", :border=>"0"), { :action => "destroy", :id => @project.id}, :confirm => "Are you sure you want to delete this entry: #{@project.name}" ) + " "
%>
</td>
</tr>
<% row += 1 %>
<% end %>
</table>
</div><!- End of display_box -->
<div id="input_box">
<%= start_form_tag :controller => 'project', :action => 'new' %>
<form method="post" action="add_project">
<label for="new_project_name">New Project</label><br />
<%= text_field( "new_project", "name" ) %>
<br />
<br />
<input type="submit" value="Add project">
<%= end_form_tag %>
</div> </div>
<% if @flash["confirmation"] %><div class="confirmation"><%= @flash["confirmation"] %></div><% end %> <br />
<% if @flash["warning"] %><div class="warning"><%= @flash["warning"] %></div><% end %> <a href="javascript:void(0)" onClick="Element.toggle('project_new'); Form.focus_first('project-form');" accesskey="n" title="Create a new project [Alt+n]">Create new project &#187;</a>
<div id="project_new" class="project_new" style="display:none">
<!--[form:project]-->
<%= form_remote_tag :url => { :action => "new_project" },
:update=> "list-projects",
:position=> "bottom",
:loading => "project.reset()",
:complete => "Form.focus_first('project-form');",
:html=> { :id=>'project-form', :name=>'project', :class => 'inline-form' } %>
<label for="project_name">Name</label>
<%= text_field 'project', 'name' %>
<input type="submit" value="Add" />
<%= end_form_tag %>
<!--[eoform:project]-->
</div>
<% if @flash["confirmation"] %>
<div class="confirmation"><%= @flash["confirmation"] %></div>
<% end %>
<% if @flash["warning"] %>
<div class="warning"><%= @flash["warning"] %></div>
<% end %>
</div><!- End of display_box -->

View file

@ -3,53 +3,71 @@
<div class="contexts"> <div class="contexts">
<h2><%= @project.name %></h2> <h2><%= @project.name %></h2>
<% if @not_done == [] %> <div id="next_actions">
<% if @not_done.empty? %>
<p>There are no next actions yet in this project</p> <p>There are no next actions yet in this project</p>
<% else %> <% else %>
<% for item in @not_done %>
<%= render_partial "show_items", item %>
<% end %>
<% end %>
</div><!-- [end:next_actions] -->
</div><!-- [end:contexts] -->
<table class="next_actions" cellspacing="2" cellpadding="0" border="0"> <div class="contexts">
<%= render_collection_of_partials "not_done", @not_done %> <h2>Completed actions in this project</h2>
</table>
<div id="completed">
<% if @done.empty? %>
<p>There are no completed next actions yet in this project</p>
<% else %>
<% for done_item in @done %>
<%= render_partial "show_items", done_item %>
<% end %>
<% end %> <% end %>
</div> </div>
<p>Other Projects: </div><!-- [end:contexts] -->
<% for other_project in Project.find_all %>
<%= link_to( other_project.name.capitalize, { :controller => "project", :action => "show", :name => urlize(other_project.name) } ) + " | " %> </div><!-- [end:display_box] -->
<% end %>
</p>
</div><!-- End of display box -->
<div id="input_box"> <div id="input_box">
<%= form_tag( :controller => "project", :action => "add_item") %>
<%= link_to_function( "Add the next action in this project &#187;", "Element.toggle('project_new_action'); Form.focusFirstElement('project-form-new-action');", {:title => "Add the next action [Alt+n]", :accesskey => "n"}) %>
<div id="project_new_action" class="project_new" style="display:none">
<!--[form:project]-->
<%= form_remote_tag :url => { :action => "add_item" },
:update=> "next_actions",
:position=> "bottom",
:loading => "project.reset()",
:complete => "Form.focusFirstElement('project-form-new-action');",
:html=> { :id=>'project-form-new-action', :name=>'project', :class => 'inline-form' } %>
<%= hidden_field( "new_item", "project_id", "value" => "#{@project.id}") %> <%= hidden_field( "new_item", "project_id", "value" => "#{@project.id}") %>
<label for="new_item_description">Next action in this project</label><br /> <label for="new_item_description">Description</label><br />
<%= text_field( "new_item", "description" ) %> <%= text_field( "new_item", "description", "size" => 25, "tabindex" => 1 ) %><br />
<br />
<label for="new_item_notes">Notes</label><br /> <label for="new_item_notes">Notes</label><br />
<%= text_area( "new_item", "notes", "cols" => 40, "rows" => 15 ) %> <%= text_area( "new_item", "notes", "cols" => 25, "rows" => 10, "tabindex" => 2 ) %><br />
<br />
<label for="new_item_context_id">Context</label><br /> <label for="new_item_context_id">Context</label><br />
<select name="new_item[context_id]" id="new_item_context_id"> <select name="new_item[context_id]" id="new_item_context_id" tabindex="3">
<%= options_from_collection_for_select(@places, "id", "name" ) %> <%= options_from_collection_for_select(@places, "id", "name" ) %>
</select> </select><br />
<br /> <label for="item_due">Due</label><br />
<label for="item_due" tab>Due</label><br /> <%= text_field("new_item", "due", "size" => 10, "class" => "Date", "onFocus" => "Calendar.setup", "tabindex" => 4) %>
<%= text_field( "item", "due", "tabindex" => 5, "cols" => 10 ) %> <br /><br />
<img src="/images/calendar.gif" onclick="showCal('','',document.forms[0].item_due,2,true,9)" style="cursor:pointer;cursor:hand" /> <input type="submit" value="Add item" tabindex="5">
<div id="calDiv" style="display:none"> <%= end_form_tag %><!--[eoform:project]-->
<div id="calTopBar">CLOSE <span onclick="document.getElementById('calDiv').style.display='none';" id="calClose">X</span></div> <script type="text/javascript">
<table width="100%" id="calNav"> Calendar.setup({ ifFormat:"<%= ApplicationController::DATE_FORMAT %>",firstDay:<%= ApplicationController::WEEK_STARTS_ON %>,showOthers:true,range:[2004, 2010],step:1,inputField:"new_item_due",cache:true,align:"TR" })
<tr><td id="calNavPY"></td><td id="calNavPM"></td><td id="calNavMY" width="100"></td><td id="calNavNM"></td><td id="calNavNY"></td></tr> </script>
</table>
<table id="calTbl" width="100%" cellspacing="0"> </div><!-- [end:project-new-action] -->
<thead><tr style="background-color:#eaeaea"><td>Sun</td><td>Mon</td><td>Tue</td><td>Wed</td><td>Thu</td><td>Fri</td><td>Sat</td></tr></thead>
<tbody></tbody> <h3>Active Projects:</h3>
</table> <ul>
</div> <% for other_project in Project.find_all %>
<br /> <li><%= link_to( other_project.name, { :controller => "project", :action => "show", :name => urlize(other_project.name) } ) + " (" + Todo.count( "project_id=#{other_project.id} AND done=0" ).to_s + " actions)" %></li>
<br /> <% end %>
<input type="submit" value="Add item"> </ul>
</form>
</div><!-- End of input box --> </div><!-- End of input box -->
<% if @flash["confirmation"] %><div class="confirmation"><%= @flash["confirmation"] %></div><% end %> <% if @flash["confirmation"] %><div class="confirmation"><%= @flash["confirmation"] %></div><% end %>

View file

@ -0,0 +1,56 @@
<%
@item = action_edit_form
%>
<!-- %= error_messages_for 'item' % -->
<%= hidden_field( "item", "id" ) %>
<table>
<tr>
<td class="label"><label for="item_description">Next action</label></td>
<td><%= text_field( "item", "description", "tabindex" => 1 ) %></td>
</tr>
<tr>
<td class="label"><label for="item_notes">Notes</label></td>
<td><%= text_area( "item", "notes", "cols" => 20, "rows" => 5, "tabindex" => 2 ) %></td>
</tr>
<tr>
<td class="label"><label for="item_context_id">Context</label></td>
<td><select name="item[context_id]" id="item_context_id" tabindex="3">
<% for @place in @places %>
<% if @item %>
<% if @place.id == @item.context_id %>
<option value="<%= @place.id %>" selected="selected"><%= @place.name %></option>
<% else %>
<option value="<%= @place.id %>"><%= @place.name %></option>
<% end %>
<% else %>
<option value="<%= @place.id %>"><%= @place.name %></option>
<% end %>
<% end %>
</select></td>
</tr>
<tr>
<td class="label"><label for="item_project_id">Project</label></td>
<td>
<select name="item[project_id]" id="item_project_id" tabindex="4">
<% if !@item.project_id? %>
<option selected="selected"></option>
<%= options_from_collection_for_select(@projects, "id", "name") %>
<% else %>
<option></option>
<%= options_from_collection_for_select(@projects, "id", "name", @item.project_id) %>
<% end %>
</select>
</td>
</tr>
<tr>
<td class="label"><label for="item_due">Due</td>
<td><input name="item[due]" id="item_due" value="<%= format_date(@item.due) %>" size="10" tabindex="5" /></td>
</tr>
<tr>
<td><input type="submit" value="Update" tabindex="6" />
<a href="javascript:void(0);" onclick="Element.toggle('item-<%= @item.id %>','action-<%= @item.id %>-edit-form');Form.reset('form-action-<%= @item.id %>');">Cancel</a></td>
</tr>
</table>
<% @item = nil %>

View file

@ -1,25 +0,0 @@
<% @done_item = done %>
<tr>
<% if @done_item.completed %>
<td valign="top"><%= image_tag( "done", :width=>"16", :height=>"16", :border=>"0") %></td>
<td valign="top"><span class="grey"><%= format_date( @done_item.completed ) %></span></td>
<td valign="top"><%= " " + @done_item.description + " "%>
<% if @done_item.project_id %>
<%= "(" + @done_item.context['name'].capitalize + ", " + @done_item.project['name'] + ")" %>
<% else %>
<%= "(" + @done_item.context['name'].capitalize + ")" %>
<% end %>
<% if @done_item.due %>
<%= " - was due on " + format_date( @done_item.due ) %>
<% end %>
<% if @done_item.notes? %>
<%= "<a href=\"javascript:toggle('" + @done_item.id.to_s + "')\" title=\"Show notes\">" + image_tag( "notes", :width=>"10", :height=>"10", :border=>"0") + "</a>" %>
<% m_notes = markdown( @done_item.notes ) %>
<%= "<div class=\"notes\" id=\"" + @done_item.id.to_s + "\">" + m_notes + "</div>" %>
<% end %>
</td>
<% end %>
</tr>

View file

@ -1,55 +0,0 @@
<%= hidden_field( "item", "id" ) %>
<label for="item_description">Next action</label><br />
<%= text_field( "item", "description", "tabindex" => 1 ) %>
<br />
<label for="item_notes">Notes</label><br />
<%= text_area( "item", "notes", "tabindex" => 2, "cols" => 35, "rows" => 15 ) %>
<br />
<label for="item_context_id">Context</label><br />
<select name="item[context_id]" id="item_context_id" tabindex="3">
<% for @place in @places %>
<% if @item %>
<% if @place.id == @item.context_id %>
<option value="<%= @place.id %>" selected="selected"><%= @place.name.capitalize %></option>
<% else %>
<option value="<%= @place.id %>"><%= @place.name.capitalize %></option>
<% end %>
<% else %>
<option value="<%= @place.id %>"><%= @place.name.capitalize %></option>
<% end %>
<% end %>
</select>
<br />
<label for="new_item_project_id">Project</label><br />
<select name="item[project_id]" id="item_project_id" tabindex="4">
<% if @belongs == nil %>
<option value="" selected="selected">None</option>
<% else %>
<option value="">None</option>
<% end %>
<% for @project in @projects %>
<% if @project.id == @belongs %>
<option value="<%= @project.id %>" selected="selected"><%= @project.name %></option>
<% else %>
<option value="<%= @project.id %>"><%= @project.name %></option>
<% end %>
<% end %>
</select>
<br />
<label for="item_due" tab>Due</label><br />
<%= text_field( "item", "due", "tabindex" => 5, "cols" => 10 ) %>
<img src="/images/calendar.gif" onclick="showCal('','',document.forms[0].item_due,2,true,9)" style="cursor:pointer;cursor:hand" />
<div id="calDiv" style="display:none">
<div id="calTopBar">CLOSE <span onclick="document.getElementById('calDiv').style.display='none';" id="calClose">X</span></div>
<table width="100%" id="calNav">
<tr><td id="calNavPY"></td><td id="calNavPM"></td><td id="calNavMY" width="100"></td><td id="calNavNM"></td><td id="calNavNY"></td></tr>
</table>
<table id="calTbl" width="100%" cellspacing="0">
<thead><tr style="background-color:#eaeaea"><td>Sun</td><td>Mon</td><td>Tue</td><td>Wed</td><td>Thu</td><td>Fri</td><td>Sat</td></tr></thead>
<tbody></tbody>
</table>
</div>
<br />
<br />

View file

@ -1,21 +0,0 @@
<% @notdone_item = not_done %>
<tr id="action-<%= @notdone_item.id.to_s %>">
<td valign="top"><%= check_box( "item", "done", "onclick" => "markItemDone('action-#{@notdone_item.id}', '/todo/toggle_check/#{@notdone_item.id}', '#{@notdone_item.id}')" ) %></td>
<td valign="top" width="30">
<%= link_to(image_tag( "edit", :title => "Edit item", :width=>"10", :height=>"10", :border=>"0"), { :action => "edit", :id => @notdone_item.id } ) + " " +
link_to(image_tag( "delete", :title => "Delete item", :width=>"10", :height=>"10", :border=>"0"), { :action => "destroy", :id => @notdone_item.id }, :confirm => "Are you sure you want to delete this entry: #{@notdone_item.description}" ) + " " %>
</td>
<td valign="top"><%= due_date( @notdone_item.due ) %>
<%= @notdone_item.description %>
<% if @notdone_item.project_id %>
<%= link_to( "[P]", { :controller => "project", :action => "show", :name => urlize(@notdone_item.project.name) }, :title => "View project: #{@notdone_item.project.name}" ) %>
<% end %>
<% if @notdone_item.notes? %>
<%= "<a href=\"javascript:toggle('" + @notdone_item.id.to_s + "')\" title=\"Show notes\">" +
image_tag( "notes", :width=>"10", :height=>"10", :border=>"0") + "</a>"
%>
<% m_notes = markdown( @notdone_item.notes ) %>
<%= "<div class=\"notes\" id=\"" + @notdone_item.id.to_s + "\">" + m_notes + "</div>" %>
<% end %>
</td>
</tr>

View file

@ -0,0 +1,84 @@
<% item = show_items %>
<% if !item.done? %>
<div id="item-<%= item.id %>-container">
<%= form_remote_tag( :url => url_for( :controller => "todo", :action => "toggle_check", :id => item.id ),
:html => { :id=> "checkbox-notdone-#{item.id}", :class => "inline-form" },
:update => "completed",
:position => "top",
:loading => "Form.disable('checkbox-notdone-#{item.id}');",
:complete => "new Effect.Squish('item-#{item.id}-container', true);"
) %>
<div id="item-<%= item.id %>">
<div class="big-box">
<input type="checkbox" name="item_id" value="<%= item.id %>" onclick="document.forms['checkbox-notdone-<%= item.id %>'].onsubmit();" />
<%=
link_to_function(image_tag( "edit", :title => "Edit item", :width=>"10", :height=>"10", :border=>"0"), "Element.toggle('item-#{item.id}','action-#{item.id}-edit-form'); new Effect.Appear('action-#{item.id}-edit-form'); Form.focusFirstElement('form-action-#{item.id}')" ) + " " +
link_to_remote( image_tag("delete", :title =>"Delete this action"),
:update => "item-#{item.id}-container",
:loading => "new Effect.Squish('item-#{item.id}-container')",
:url => { :controller => "todo", :action => "destroy_action", :id => item.id }, :confirm => "Are you sure that you want to delete the action \'#{item.description}\'?" ) + " "
%>
</div>
<div class="description">
<%= due_date( item.due ) %>
<%= item.description %>
<% if item.project_id %>
<%= link_to( "[P]", { :controller => "project", :action => "show", :name => urlize(item.project.name) }, :title => "View project: #{item.project.name}" ) %>
<% end %>
<% if item.notes? %>
<%= "<a href=\"javascript:Element.toggle('" + item.id.to_s + "')\" title=\"Show notes\">" + image_tag( "notes", :width=>"10", :height=>"10", :border=>"0") + "</a>" %>
<% m_notes = markdown( item.notes ) %>
<%= "<div class=\"notes\" id=\"" + item.id.to_s + "\" style=\"display:none\">" + m_notes + "</div>" %>
<% end %>
</div>
</div><!-- [end:item-item.id] -->
<%= end_form_tag %>
<div id="action-<%= item.id %>-edit-form" class="edit-form" style="display:none;">
<%= form_remote_tag :url => { :controller => 'todo', :action => 'update_action', :id => item.id },
:html => { :id => "form-action-#{item.id}", :class => "inline-form" },
:update => "item-#{item.id}-container",
:complete => "new Effect.Appear('item-#{item.id}-container');" %>
<%= render_partial 'action_edit_form', item %>
<%= end_form_tag %>
</div><!-- [end:action-item.id-edit-form] -->
</div><!-- [end:item-item.id-container] -->
<% else %>
<div id="done-item-<%= item.id %>-container">
<%= form_remote_tag( :url => url_for( :controller => "todo", :action => "toggle_check", :id => item.id ),
:html => { :id=> "checkbox-done-#{item.id}", :class => "inline-form" },
:update => "new_actions",
:position => "bottom",
:loading => "Form.disable('checkbox-done-#{item.id}');",
:complete => "Element.toggle('new_actions');new Effect.Squish('done-item-#{item.id}-container', true);"
) %>
<div id="done-item-<%= item.id %>">
<div class="big-box">
<input type="checkbox" name="item_id" value="<%= item.id %>" checked="checked" onclick="document.forms['checkbox-done-<%= item.id %>'].onsubmit();" />
<%=
link_to_remote( image_tag("delete", :title =>"Delete this action"),
:update => "done-item-#{item.id}-container",
:loading => "new Effect.Squish('done-item-#{item.id}-container')",
:url => { :controller => "todo", :action => "destroy_action", :id => item.id }, :confirm => "Are you sure that you want to delete the action \'#{item.description}\'?" ) + " "
%>
</div><!-- [end:big-box] -->
<div class="description">
<span class="grey"><%= format_date( item.completed ) %></span>
<%= item.description %>
<% if item.project_id %>
<%= link_to( "[P]", { :controller => "project", :action => "show", :name => urlize(item.project.name) }, :title => "View project: #{item.project.name}" ) %>
<% end %>
<% if item.notes? %>
<%= "<a href=\"javascript:Element.toggle('" + item.id.to_s + "')\" title=\"Show notes\">" + image_tag( "notes", :width=>"10", :height=>"10", :border=>"0") + "</a>" %>
<% m_notes = markdown( item.notes ) %>
<%= "<div class=\"notes\" id=\"" + item.id.to_s + "\" style=\"display:none\">" + m_notes + "</div>" %>
<% end %>
</div><!-- [end:description] -->
</div><!-- [end:item-item.id] -->
<%= end_form_tag %>
</div><!-- [end:item-item.id-container] -->
<% end %>
<% item = nil %>

View file

@ -1,12 +0,0 @@
<div id="display_box">
<h2>Edit task</h2>
<form action="<%= url_for(:controller => 'todo', :action => 'update') %>" method="post">
<%= render_partial "todo/item", "@item" %>
<input type="submit" value="Update" />
</form>
<%= link_to 'Cancel', :action => 'list' %>
</div>
<% if @flash["confirmation"] %><div class="confirmation"><%= @flash["confirmation"] %></div><% end %>
<% if @flash["warning"] %><div class="warning"><%= @flash["warning"] %></div><% end %>

View file

@ -1,53 +1,94 @@
<div id="display_box"> <div id="display_box">
<% for @shown_place in @shown_places %>
<% @not_done = Todo.find_all("done=0 AND context_id=#{@shown_place.id}", "due IS NULL, due ASC, created ASC") %> <!-- begin div.new_actions -->
<% if !@not_done.empty? %> <div id="new_actions" class="new_actions" style="display:none">
<div class="contexts"> <h2>Fresh actions (hit refresh to sort)</h2>
<h2>
<a href="javascript:toggle('c<%=@shown_place.id%>');javascript:toggleImage('toggle_context_<%=@shown_place.id%>')">
<img src="/images/collapse.png" name="toggle_context_<%= @shown_place.id %>"/></a><%= link_to( "#{@shown_place.name.capitalize}", :controller => "context", :action => "show", :name => urlize(@shown_place.name) ) %></h2>
<div id="c<%= @shown_place.id %>">
<table class="next_actions" id="incomplete" cellspacing="2" cellpadding="0" border="0">
<%= render_collection_of_partials "not_done", @not_done %>
</table>
</div> </div>
</div><!-- End contexts --> <!-- end div.new_actions -->
<% end %>
<% end %> <% for @shown_place in @shown_places -%>
<% @not_done = Todo.find_all("done=0 AND context_id=#{@shown_place.id}", "due IS NULL, due ASC, created ASC") -%>
<% if !@not_done.empty? -%>
<div class="contexts">
<h2><a href="javascript:toggleSingle('c<%=@shown_place.id%>');javascript:toggleImage('toggle_context_<%=@shown_place.id%>')">
<img src="/images/collapse.png" name="toggle_context_<%= @shown_place.id %>"/></a><%= link_to( "#{@shown_place.name}", :controller => "context", :action => "show", :name => urlize(@shown_place.name) ) %></h2>
<div id="c<%= @shown_place.id %>" class="next_actions">
<% if @not_done.empty? -%>
<p>There are no next actions yet in this context</p>
<% else -%>
<% for item in @not_done -%>
<%= render_partial "show_items", item %>
<% end -%>
<% end -%>
</div><!-- [end:next_actions] -->
</div><!-- [end:contexts] -->
<% end -%>
<% end -%>
<div class="contexts"> <div class="contexts">
<h2>Just done</h2> <h2>Completed actions in this context</h2>
<table class="next_actions" id="holding" cellspacing="5" cellpadding="0" border="0">
<tr></tr> <div id="completed">
</table> <% if @done.empty? -%>
<p>There are no completed next actions yet in this context</p>
<% else -%>
<% for done_item in @done -%>
<%= render_partial "show_items", done_item %>
<% end -%>
<% end -%>
</div> </div>
</div><!-- [end:contexts] -->
<div class="contexts"> </div><!-- End of display_box -->
<h2>Last <%= @no_of_actions %> completed actions</h2>
<table class="next_actions" id="complete" cellspacing="5" cellpadding="0" border="0">
<%= render_collection_of_partials "done", @done %>
</table>
</div>
<p>Hidden contexts:
<% for @hidden_place in @hidden_places %>
<% num = count_items(@hidden_place) %>
<%= link_to @hidden_place.name.capitalize, :controller=>"context", :action=> "show", :name=> urlize(@hidden_place.name) %><%= ' ('+ num.to_s + ') ' + '|' %>
<% end %>
</p>
</div><!- End of display_box -->
<div id="input_box"> <div id="input_box">
<form method="post" action="add_item"> <%= link_to_function( "Add the next action in this context &#187;", "Element.toggle('todo_new_action');Element.toggle('new_actions');Form.focusFirstElement('todo-form-new-action');", {:title => "Add the next action [Alt+n]", :accesskey => "n"}) %>
<%= render_partial "todo/item", @item %>
<input type="submit" value="Add item">
</form>
</div> <div id="todo_new_action" class="context_new" style="display:none">
<!--[form:todo]-->
<%= form_remote_tag :url => { :action => "add_item" },
:update => "new_actions",
:position=> "bottom",
:loading => "context.reset()",
:complete => "Form.focusFirstElement('todo-form-new-action');",
:html=> { :id=>'todo-form-new-action', :name=>'todo', :class => 'inline-form' } %>
<label for="new_item_description">Description</label><br />
<%= text_field( "new_item", "description", "size" => 25, "tabindex" => 1 ) %><br />
<label for="new_item_notes">Notes</label><br />
<%= text_area( "new_item", "notes", "cols" => 25, "rows" => 10, "tabindex" => 2 ) %><br />
<label for="new_item_context_id">Context</label><br />
<%= collection_select( "new_item", "context_id", @places, "id", "name", {}, {"tabindex" => 3}) %><br />
<label for="new_item_project_id">Project</label><br />
<select name="new_item[project_id]" id="new_item_project_id" tabindex="4">
<option selected="selected"></option>
<%= options_from_collection_for_select(@projects, "id", "name") %>
</select><br />
<label for="item_due">Due</label><br />
<%= text_field("new_item", "due", "size" => 10, "class" => "Date", "onFocus" => "Calendar.setup", "tabindex" => 5) %>
<br /><br />
<input type="submit" value="Add item" tabindex="6">
<%= end_form_tag %><!--[eoform:todo]-->
<script type="text/javascript">
Calendar.setup({ ifFormat:"<%= ApplicationController::DATE_FORMAT %>",firstDay:<%= ApplicationController::WEEK_STARTS_ON %>,showOthers:true,range:[2004, 2010],step:1,inputField:"new_item_due",cache:true,align:"TR" })
</script>
</div><!-- [end:todo-new-action] -->
<h3>Active Projects:</h3>
<ul>
<% for project in @projects -%>
<li><%= link_to( project.name, { :controller => "project", :action => "show", :name => urlize(project.name) } ) + " (" + Todo.count( "project_id=#{project.id} AND done=0" ).to_s + " actions)" %></li>
<% end -%>
</ul>
<h3>Hidden Contexts:</h3>
<ul>
<% for other_context in Context.find(:all, :conditions => "hide=1", :order => "position ASC") %>
<li><%= link_to( other_context.name, { :controller => "context", :action => "show", :name => urlize(other_context.name) } ) + " (" + Todo.count( "context_id=#{other_context.id} AND done=0" ).to_s + " actions)" -%></li>
<% end -%>
</ul>
</div><!-- End of input box -->
<% if @flash["confirmation"] %><div class="confirmation"><%= @flash["confirmation"] %></div><% end %> <% if @flash["confirmation"] %><div class="confirmation"><%= @flash["confirmation"] %></div><% end %>

View file

@ -23,18 +23,19 @@ ActionController::Routing::Routes.draw do |map|
map.connect 'delete/todo/:id', :controller =>'todo', :action => 'destroy' map.connect 'delete/todo/:id', :controller =>'todo', :action => 'destroy'
# Context Routes # Context Routes
map.connect 'context/new_context', :controller => 'context', :action => 'new_context'
map.connect 'context/add_item', :controller => 'context', :action => 'add_item'
map.connect 'contexts', :controller => 'context', :action => 'list' map.connect 'contexts', :controller => 'context', :action => 'list'
map.connect 'add/context', :controller => 'context', :action => 'new'
map.connect 'context/:id', :controller=> 'context', :action => 'show'
map.connect 'context/:name', :controller => 'context', :action => 'show' map.connect 'context/:name', :controller => 'context', :action => 'show'
map.connect 'delete/context/:id', :controller => 'context', :action => 'destroy' map.connect 'context/:id', :controller=> 'context', :action => 'show'
# Projects Routes # Projects Routes
map.connect 'project/new_project', :controller => 'project', :action => 'new_project'
map.connect 'project/add_item/:id', :controller => 'project', :action => 'add_item'
map.connect 'project/toggle_check/:id', :controller => 'project', :action => 'toggle_check'
map.connect 'projects', :controller => 'project', :action => 'list' map.connect 'projects', :controller => 'project', :action => 'list'
map.connect 'add/project', :controller => 'project', :action => 'new'
map.connect 'project/:name', :controller => 'project', :action => 'show' map.connect 'project/:name', :controller => 'project', :action => 'show'
map.connect 'project/:id', :controller => 'project', :action => 'show' map.connect 'project/:id', :controller => 'project', :action => 'show'
map.connect 'delete/project/:id', :controller => 'project', :action => 'destroy'
# Feed Routes # Feed Routes
map.connect 'feed/:action/:name/:user', :controller => 'feed' map.connect 'feed/:action/:name/:user', :controller => 'feed'

View file

@ -1,5 +1,11 @@
# It's very important not to use TAB characters in this file
# Use two spaces instead of a TAB
# week_starts is the day you want the calendar to display first (0=Sunday, 1=Monday etc.)
# hp_completed is the number of completed items you want displayed on the home page
#
formats: formats:
date: %d/%m/%Y date: %d/%m/%Y
week_starts: 1
hp_completed: 5 hp_completed: 5
admin: admin:
email: butshesagirl@rousette.org.uk email: butshesagirl@rousette.org.uk

View file

@ -16,7 +16,7 @@ Project wiki: <http://www.rousette.org.uk/projects/wiki/>
1. Added back border="0" to images which I had mistakenly taken out (thanks, Adam Hughes) 1. Added back border="0" to images which I had mistakenly taken out (thanks, Adam Hughes)
2. Removed the section in config/environment.rb which requires Redcloth. This was causing errors because Rails now requires Redcloth itself. This means that you now need to have Redcloth installed as a gem (gem install redcloth) (thanks, Jim). 2. Removed the section in config/environment.rb which requires Redcloth. This was causing errors because Rails now requires Redcloth itself. This means that you now need to have Redcloth installed as a gem (gem install redcloth) (thanks, Jim).
3. Fixed SQLite dump format in db/tracks_1.0.2_sqlite.sql (thanks, Jim) 3. Fixed SQLite dump format in db/tracks_1.0.2_sqlite.sql (thanks, Jim)
4. Added a mini-calendar to the todo/list page. Needs some tidying up, but it provides a quick way to look up a date a few months ahead. Note that it doesn't insert the date: it's just for viewing. I modified the calendar a little bit from here: <http://www.pxl8.com/basic_calendar.html> 4. The new item forms on all pages now use a mini calendar which pops up when you click the due date field. Calendar is the GPL one from dynarch.com <http://www.dynarch.com/projects/calendar/>
5. Added some XMLHTTPRequest calls to speed up checking off an item as done. It grabs the checked item and appends it immediately to a 'holding' section (where you can uncheck it again if it was a mistake, or add a closing note). When you next refresh the page, it will be added to the 'Last 5 completed items' section. 5. Added some XMLHTTPRequest calls to speed up checking off an item as done. It grabs the checked item and appends it immediately to a 'holding' section (where you can uncheck it again if it was a mistake, or add a closing note). When you next refresh the page, it will be added to the 'Last 5 completed items' section.
6. [Contributed by Lolindrath] Toggling of contexts in /todo/list to collapse or expand their display via a small '+' or '-' graphic. This is independent of the shown/hidden setting for contexts, and is ideal for just hiding things on the fly to focus your view. 6. [Contributed by Lolindrath] Toggling of contexts in /todo/list to collapse or expand their display via a small '+' or '-' graphic. This is independent of the shown/hidden setting for contexts, and is ideal for just hiding things on the fly to focus your view.
7. [Contributed by Jim Ray] Jim added a host of fixes and bits of cleaning up, including a position column for contexts and projects to allow custom sorting, and changes to the links for pages to make them more human-readable. 7. [Contributed by Jim Ray] Jim added a host of fixes and bits of cleaning up, including a position column for contexts and projects to allow custom sorting, and changes to the links for pages to make them more human-readable.
@ -25,6 +25,9 @@ Project wiki: <http://www.rousette.org.uk/projects/wiki/>
10. [Contributed by Arnaud Limbourg, ticket:18] A new entry in settings.yml allows you to choose the number of completed actions you want to see on the /todo/list home page. Also sorts by due date (ascending) first, then creation date (descending) on /todo/list, /context/show/[name], and /project/show/[name] 10. [Contributed by Arnaud Limbourg, ticket:18] A new entry in settings.yml allows you to choose the number of completed actions you want to see on the /todo/list home page. Also sorts by due date (ascending) first, then creation date (descending) on /todo/list, /context/show/[name], and /project/show/[name]
11. Added a count of next actions to the /projects page, showing how many uncompleted next actions remain for each project. 11. Added a count of next actions to the /projects page, showing how many uncompleted next actions remain for each project.
12. [Patch by lolindrath] Sorting by date is now much smarter on /todo/list: Actions are sorted by ascending due date then ascending creation date, but non-due dated items sort to the bottom. This means that the most urgent items float to the top of each context list. 12. [Patch by lolindrath] Sorting by date is now much smarter on /todo/list: Actions are sorted by ascending due date then ascending creation date, but non-due dated items sort to the bottom. This means that the most urgent items float to the top of each context list.
13. Can now uncheck actions from the completed actions list, so that they dynamically appear back in the uncompleted actions area.
14. A tiny improvement: the toggling of the individual notes now uses Element.toggle from prototype.js, so it doesn't have to be an onLoad property of the body tag. This means that you don't get the notes flashing before they are hidden when you load or reload a page.
15. All the adding, updating, deleting and marking actions done is performed using Ajax, so happens without needing to refresh the page.
## Version 1.02 ## Version 1.02

View file

@ -1,289 +0,0 @@
require 'date'
require 'ParseDate'
module ICal
SECONDS_PER_DAY = 24 * 60 * 60
class ICalReader
@@iCalFolder = "/Users/jchappell/Library/Calendars"
def initialize(calendarName = nil)
@events = []
@iCalFiles = Dir[@@iCalFolder + "/*.ics"]
@iCalFiles.sort! {|x, y| x.downcase <=> y.downcase}
if calendarName then
fullName = @@iCalFolder + "/" + calendarName + ".ics"
@iCalFiles = @iCalFiles.select {|name| name == fullName}
end
end
def calendars
@iCalFiles.collect {|name| File.basename(name, ".ics")}
end
def readEvents
@events = []
@iCalFiles.each do |fileName|
lines = File.readlines(fileName);
inEvent = false
eventLines = []
lines.each do |line|
if line =~ /^BEGIN:VEVENT/ then
inEvent = true
eventLines = []
end
if inEvent
eventLines << line
if line =~ /^END:VEVENT/ then
inEvent = false
@events << parseEvent(eventLines)
end
end
end
end
@events
end
def parseEvent(lines)
event = ICalEvent.new()
startDate = nil
rule = nil
lines.each do |line|
if line =~ /^SUMMARY:(.*)/ then
event.summary = $1
elsif line =~ /^DTSTART;.*:(.*).*/ then
startDate = parseDate($1)
elsif line =~ /^EXDATE.*:(.*)/ then
event.addExceptionDate(parseDate($1))
elsif line =~ /^RRULE:(.*)/ then
rule = $1
end
end
event.startDate = startDate
event.addRecurrenceRule(rule)
event
end
def parseDate(dateStr)
# We constrain the year to 1970 because Time won't handle lesser years
# If it is less than 1970 then its probably a birthday or something
# in which case, we don't really care about the year
year = dateStr[0,4].to_i
year = 1970 if year < 1970
month = dateStr[4,2].to_i
day = dateStr[6,2].to_i
hour = dateStr[9,2].to_i
minute = dateStr[11,2].to_i
Time.local(year, month, day, hour, minute)
end
def events
readEvents if @events == []
@events
end
def selectEvents(&predicate)
#
# The start date of each event could be different due to recurring events
# Since we can assume the date is the same for all events, we just compare
# the times when sorting
#
now = Time.now
events.select(&predicate).sort do |event1, event2|
time1 = Time.local(now.year, now.month, now.day, event1.startDate.hour,
event1.startDate.min)
time2 = Time.local(now.year, now.month, now.day, event2.startDate.hour,
event2.startDate.min)
time1 <=> time2
end
end
def todaysEvents
#events.select {|event| event.startsToday? }
selectEvents {|event| event.startsToday? }
end
def tomorrowsEvents
#events.select {|event| event.startsTomorrow? }
selectEvents {|event| event.startsTomorrow?}
end
def eventsFor(date)
#events.select {|event| event.startsOn?(date)}
selectEvents {|event| event.startsOn?(date)}
end
end
class DateParser
# Given a date as a string, returns a Time object
def DateParser.parse(dateStr)
dateValues = ParseDate::parsedate(dateStr)
Time.local(*dateValues[0, 3])
end
def DateParser.format(date)
date.strftime("%m/%d/%Y")
end
end
class ICalEvent
def initialize
@exceptionDates = []
end
def <=>(otherEvent)
return @startDate <=> otherEvent.startDate
end
def addExceptionDate(date)
@exceptionDates << date
end
def addRecurrenceRule(rule)
@dateSet = DateSet.new(@startDate, rule)
end
def startsToday?
startsOn?(Time.now)
end
def startsTomorrow?
tomorrow = Time.now + SECONDS_PER_DAY;
startsOn?(tomorrow)
end
def startsOn?(date)
(startDate.year == date.year and startDate.month == date.month and
startDate.day == date.day) or @dateSet.includes?(date)
end
def to_s
"#{@startDate.strftime("%m/%d/%Y (%I:%M %p)")} - #{@summary}"
end
def startTime
@startDate
end
attr_accessor :startDate, :summary
end
class DateSet
def initialize(startDate, rule)
@startDate = startDate
@frequency = nil
@count = nil
@untilDate = nil
@byMonth = nil
@byDay = nil
parseRecurrenceRule(rule)
end
def parseRecurrenceRule(rule)
if rule =~ /FREQ=(.*?);/ then
@frequency = $1
end
if rule =~ /COUNT=(\d*)/ then
@count = $1.to_i
end
if rule =~ /UNTIL=(.*?);/ then
@untilDate = DateParser.parse($1)
#puts @untilDate
end
if rule =~ /INTERVAL=(\d*)/ then
@interval = $1.to_i
end
if rule =~ /BYMONTH=(.*?);/ then
@byMonth = $1
end
if rule =~ /BYDAY=(.*?);/ then
@byDay = $1
#puts "byDay = #{@byDay}"
end
end
def to_s
puts "#<DateSet: starts: #{@startDate.strftime("%m/%d/%Y")}, occurs: #{@frequency}, count: #{@count}, until: #{@until}, byMonth: #{@byMonth}, byDay: #{@byDay}>"
end
def includes?(date)
return true if date == @startDate
return false if @untilDate and date > @untilDate
case @frequency
when 'DAILY'
#if @untilDate then
# return (@startDate..@untilDate).include?(date)
#end
increment = @interval ? @interval : 1
d = @startDate
counter = 0
until d > date
if @count then
counter += 1
if counter >= @count
return false
end
end
d += (increment * SECONDS_PER_DAY)
if d.day == date.day and
d.year == date.year and
d.month == date.month then
return true
end
end
when 'WEEKLY'
return true if @startDate.wday == date.wday
when 'MONTHLY'
when 'YEARLY'
end
false
end
attr_reader :frequency
attr_accessor :startDate
end
if $0 == __FILE__ then
#reader = ICalReader.new("Test")
reader = ICalReader.new
puts
puts "Today"
puts "====="
puts reader.todaysEvents
puts
puts "Tomorrow"
puts "========"
puts reader.tomorrowsEvents
puts
puts "08/14/2003 Events"
puts "================="
puts reader.eventsFor(Time.local(2003, 8, 14))
puts
end
end

View file

@ -0,0 +1,127 @@
// ** I18N
// Calendar EN language
// Author: Mihai Bazon, <mihai_bazon@yahoo.com>
// Encoding: any
// Distributed under the same terms as the calendar itself.
// For translators: please use UTF-8 if possible. We strongly believe that
// Unicode is the answer to a real internationalized world. Also please
// include your contact information in the header, as can be seen above.
// full day names
Calendar._DN = new Array
("Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday");
// Please note that the following array of short day names (and the same goes
// for short month names, _SMN) isn't absolutely necessary. We give it here
// for exemplification on how one can customize the short day names, but if
// they are simply the first N letters of the full name you can simply say:
//
// Calendar._SDN_len = N; // short day name length
// Calendar._SMN_len = N; // short month name length
//
// If N = 3 then this is not needed either since we assume a value of 3 if not
// present, to be compatible with translation files that were written before
// this feature.
// short day names
Calendar._SDN = new Array
("Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat",
"Sun");
// First day of the week. "0" means display Sunday first, "1" means display
// Monday first, etc.
Calendar._FD = 0;
// full month names
Calendar._MN = new Array
("January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December");
// short month names
Calendar._SMN = new Array
("Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec");
// tooltips
Calendar._TT = {};
Calendar._TT["INFO"] = "About the calendar";
Calendar._TT["ABOUT"] =
"DHTML Date/Time Selector\n" +
"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-)
"For latest version visit: http://www.dynarch.com/projects/calendar/\n" +
"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." +
"\n\n" +
"Date selection:\n" +
"- Use the \xab, \xbb buttons to select year\n" +
"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" +
"- Hold mouse button on any of the above buttons for faster selection.";
Calendar._TT["ABOUT_TIME"] = "\n\n" +
"Time selection:\n" +
"- Click on any of the time parts to increase it\n" +
"- or Shift-click to decrease it\n" +
"- or click and drag for faster selection.";
Calendar._TT["PREV_YEAR"] = "Prev. year (hold for menu)";
Calendar._TT["PREV_MONTH"] = "Prev. month (hold for menu)";
Calendar._TT["GO_TODAY"] = "Go Today";
Calendar._TT["NEXT_MONTH"] = "Next month (hold for menu)";
Calendar._TT["NEXT_YEAR"] = "Next year (hold for menu)";
Calendar._TT["SEL_DATE"] = "Select date";
Calendar._TT["DRAG_TO_MOVE"] = "Drag to move";
Calendar._TT["PART_TODAY"] = " (today)";
// the following is to inform that "%s" is to be the first day of week
// %s will be replaced with the day name.
Calendar._TT["DAY_FIRST"] = "Display %s first";
// This may be locale-dependent. It specifies the week-end days, as an array
// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1
// means Monday, etc.
Calendar._TT["WEEKEND"] = "0,6";
Calendar._TT["CLOSE"] = "Close";
Calendar._TT["TODAY"] = "Today";
Calendar._TT["TIME_PART"] = "(Shift-)Click or drag to change value";
// date formats
Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d";
Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e";
Calendar._TT["WK"] = "wk";
Calendar._TT["TIME"] = "Time:";

View file

@ -0,0 +1,200 @@
/* Copyright Mihai Bazon, 2002, 2003 | http://dynarch.com/mishoo/
* ---------------------------------------------------------------------------
*
* The DHTML Calendar
*
* Details and latest version at:
* http://dynarch.com/mishoo/calendar.epl
*
* This script is distributed under the GNU Lesser General Public License.
* Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
*
* This file defines helper functions for setting up the calendar. They are
* intended to help non-programmers get a working calendar on their site
* quickly. This script should not be seen as part of the calendar. It just
* shows you what one can do with the calendar, while in the same time
* providing a quick and simple method for setting it up. If you need
* exhaustive customization of the calendar creation process feel free to
* modify this code to suit your needs (this is recommended and much better
* than modifying calendar.js itself).
*/
// $Id: calendar-setup.js,v 1.25 2005/03/07 09:51:33 mishoo Exp $
/**
* This function "patches" an input field (or other element) to use a calendar
* widget for date selection.
*
* The "params" is a single object that can have the following properties:
*
* prop. name | description
* -------------------------------------------------------------------------------------------------
* inputField | the ID of an input field to store the date
* displayArea | the ID of a DIV or other element to show the date
* button | ID of a button or other element that will trigger the calendar
* eventName | event that will trigger the calendar, without the "on" prefix (default: "click")
* ifFormat | date format that will be stored in the input field
* daFormat | the date format that will be used to display the date in displayArea
* singleClick | (true/false) wether the calendar is in single click mode or not (default: true)
* firstDay | numeric: 0 to 6. "0" means display Sunday first, "1" means display Monday first, etc.
* align | alignment (default: "Br"); if you don't know what's this see the calendar documentation
* range | array with 2 elements. Default: [1900, 2999] -- the range of years available
* weekNumbers | (true/false) if it's true (default) the calendar will display week numbers
* flat | null or element ID; if not null the calendar will be a flat calendar having the parent with the given ID
* flatCallback | function that receives a JS Date object and returns an URL to point the browser to (for flat calendar)
* disableFunc | function that receives a JS Date object and should return true if that date has to be disabled in the calendar
* onSelect | function that gets called when a date is selected. You don't _have_ to supply this (the default is generally okay)
* onClose | function that gets called when the calendar is closed. [default]
* onUpdate | function that gets called after the date is updated in the input field. Receives a reference to the calendar.
* date | the date that the calendar will be initially displayed to
* showsTime | default: false; if true the calendar will include a time selector
* timeFormat | the time format; can be "12" or "24", default is "12"
* electric | if true (default) then given fields/date areas are updated for each move; otherwise they're updated only on close
* step | configures the step of the years in drop-down boxes; default: 2
* position | configures the calendar absolute position; default: null
* cache | if "true" (but default: "false") it will reuse the same calendar object, where possible
* showOthers | if "true" (but default: "false") it will show days from other months too
*
* None of them is required, they all have default values. However, if you
* pass none of "inputField", "displayArea" or "button" you'll get a warning
* saying "nothing to setup".
*/
Calendar.setup = function (params) {
function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } };
param_default("inputField", null);
param_default("displayArea", null);
param_default("button", null);
param_default("eventName", "click");
param_default("ifFormat", "%Y/%m/%d");
param_default("daFormat", "%Y/%m/%d");
param_default("singleClick", true);
param_default("disableFunc", null);
param_default("dateStatusFunc", params["disableFunc"]); // takes precedence if both are defined
param_default("dateText", null);
param_default("firstDay", null);
param_default("align", "Br");
param_default("range", [1900, 2999]);
param_default("weekNumbers", true);
param_default("flat", null);
param_default("flatCallback", null);
param_default("onSelect", null);
param_default("onClose", null);
param_default("onUpdate", null);
param_default("date", null);
param_default("showsTime", false);
param_default("timeFormat", "24");
param_default("electric", true);
param_default("step", 2);
param_default("position", null);
param_default("cache", false);
param_default("showOthers", false);
param_default("multiple", null);
var tmp = ["inputField", "displayArea", "button"];
for (var i in tmp) {
if (typeof params[tmp[i]] == "string") {
params[tmp[i]] = document.getElementById(params[tmp[i]]);
}
}
if (!(params.flat || params.multiple || params.inputField || params.displayArea || params.button)) {
alert("Calendar.setup:\n Nothing to setup (no fields found). Please check your code");
return false;
}
function onSelect(cal) {
var p = cal.params;
var update = (cal.dateClicked || p.electric);
if (update && p.inputField) {
p.inputField.value = cal.date.print(p.ifFormat);
if (typeof p.inputField.onchange == "function")
p.inputField.onchange();
}
if (update && p.displayArea)
p.displayArea.innerHTML = cal.date.print(p.daFormat);
if (update && typeof p.onUpdate == "function")
p.onUpdate(cal);
if (update && p.flat) {
if (typeof p.flatCallback == "function")
p.flatCallback(cal);
}
if (update && p.singleClick && cal.dateClicked)
cal.callCloseHandler();
};
if (params.flat != null) {
if (typeof params.flat == "string")
params.flat = document.getElementById(params.flat);
if (!params.flat) {
alert("Calendar.setup:\n Flat specified but can't find parent.");
return false;
}
var cal = new Calendar(params.firstDay, params.date, params.onSelect || onSelect);
cal.showsOtherMonths = params.showOthers;
cal.showsTime = params.showsTime;
cal.time24 = (params.timeFormat == "24");
cal.params = params;
cal.weekNumbers = params.weekNumbers;
cal.setRange(params.range[0], params.range[1]);
cal.setDateStatusHandler(params.dateStatusFunc);
cal.getDateText = params.dateText;
if (params.ifFormat) {
cal.setDateFormat(params.ifFormat);
}
if (params.inputField && typeof params.inputField.value == "string") {
cal.parseDate(params.inputField.value);
}
cal.create(params.flat);
cal.show();
return false;
}
var triggerEl = params.button || params.displayArea || params.inputField;
triggerEl["on" + params.eventName] = function() {
var dateEl = params.inputField || params.displayArea;
var dateFmt = params.inputField ? params.ifFormat : params.daFormat;
var mustCreate = false;
var cal = window.calendar;
if (dateEl)
params.date = Date.parseDate(dateEl.value || dateEl.innerHTML, dateFmt);
if (!(cal && params.cache)) {
window.calendar = cal = new Calendar(params.firstDay,
params.date,
params.onSelect || onSelect,
params.onClose || function(cal) { cal.hide(); });
cal.showsTime = params.showsTime;
cal.time24 = (params.timeFormat == "24");
cal.weekNumbers = params.weekNumbers;
mustCreate = true;
} else {
if (params.date)
cal.setDate(params.date);
cal.hide();
}
if (params.multiple) {
cal.multiple = {};
for (var i = params.multiple.length; --i >= 0;) {
var d = params.multiple[i];
var ds = d.print("%Y%m%d");
cal.multiple[ds] = d;
}
}
cal.showsOtherMonths = params.showOthers;
cal.yearStep = params.step;
cal.setRange(params.range[0], params.range[1]);
cal.params = params;
cal.setDateStatusHandler(params.dateStatusFunc);
cal.getDateText = params.dateText;
cal.setDateFormat(dateFmt);
if (mustCreate)
cal.create();
cal.refresh();
if (!params.position)
cal.showAtElement(params.button || params.displayArea || params.inputField, params.align);
else
cal.showAt(params.position[0], params.position[1]);
return false;
};
return cal;
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,55 @@
/* Form extensions - prototype-ex by Matt McCray
<http://darthapo.com/repos/prototype-ex.html> */
Form.extend( {
disable: function( form ) {
var elements = Form.getElements( form );
for(var i=0; i<elements.length; i++)
{
elements[i].blur();
elements[i].disable = 'true';
}
},
focus_first: function( form )
{
form = $(form);
var elements = Form.getElements( form );
for( var i=0; i<elements.length; i++ ) {
var elem = elements[i];
if( elem.type != 'hidden' && !elem.disabled) {
Field.activate( elem );
break;
}
}
},
reset: function( form )
{
$(form).reset();
}
});
/*--------------------------------------------------------------------------*/
Field.extend({
select: function(element) {
$(element).select();
},
activate: function(element) {
$(element).focus();
$(element).select();
}
});
var Action = {
do_submit: function(form) {
// calling form.submit seems to override the onsubmit handler...
$(form).onsubmit();
},
};

View file

@ -1,15 +1,20 @@
/* Prototype: an object-oriented Javascript library, version 1.0.1 /* Prototype: an object-oriented Javascript library, version 1.2.1
* (c) 2005 Sam Stephenson <sam@conio.net> * (c) 2005 Sam Stephenson <sam@conio.net>
* *
* THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff
* against the source tree, available from the Prototype darcs repository.
*
* Prototype is freely distributable under the terms of an MIT-style license. * Prototype is freely distributable under the terms of an MIT-style license.
* For details, see http://prototype.conio.net/ *
*/ * For details, see the Prototype web site: http://prototype.conio.net/
*
/*--------------------------------------------------------------------------*/
Prototype = { var Prototype = {
Version: '1.0.1' Version: '1.2.1'
} }
Class = { var Class = {
create: function() { create: function() {
return function() { return function() {
this.initialize.apply(this, arguments); this.initialize.apply(this, arguments);
@ -17,7 +22,7 @@ Class = {
} }
} }
Abstract = new Object(); var Abstract = new Object();
Object.prototype.extend = function(object) { Object.prototype.extend = function(object) {
for (property in object) { for (property in object) {
@ -40,7 +45,13 @@ Function.prototype.bindAsEventListener = function(object) {
} }
} }
Try = { Number.prototype.toColorPart = function() {
var digits = this.toString(16);
if (this < 16) return '0' + digits;
return digits;
}
var Try = {
these: function() { these: function() {
var returnValue; var returnValue;
@ -56,14 +67,34 @@ Try = {
} }
} }
Toggle = { /*--------------------------------------------------------------------------*/
display: function() {
for (var i = 0; i < elements.length; i++) { var PeriodicalExecuter = Class.create();
var element = $(elements[i]); PeriodicalExecuter.prototype = {
element.style.display = initialize: function(callback, frequency) {
(element.style.display == 'none' ? '' : 'none'); this.callback = callback;
this.frequency = frequency;
this.currentlyExecuting = false;
this.registerCallback();
},
registerCallback: function() {
setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000);
},
onTimerEvent: function() {
if (!this.currentlyExecuting) {
try {
this.currentlyExecuting = true;
this.callback();
} finally {
this.currentlyExecuting = false;
} }
} }
this.registerCallback();
}
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
@ -85,27 +116,39 @@ function $() {
return elements; return elements;
} }
function getElementsByClassName(className, element) { /*--------------------------------------------------------------------------*/
var children = (element || document).getElementsByTagName('*');
var elements = new Array();
for (var i = 0; i < children.length; i++) { if (!Array.prototype.push) {
var child = children[i]; Array.prototype.push = function() {
var classNames = child.className.split(' '); var startLength = this.length;
for (var j = 0; j < classNames.length; j++) { for (var i = 0; i < arguments.length; i++)
if (classNames[j] == className) { this[startLength + i] = arguments[i];
elements.push(child); return this.length;
break;
}
} }
} }
return elements; if (!Function.prototype.apply) {
// Based on code from http://www.youngpup.net/
Function.prototype.apply = function(object, parameters) {
var parameterStrings = new Array();
if (!object) object = window;
if (!parameters) parameters = new Array();
for (var i = 0; i < parameters.length; i++)
parameterStrings[i] = 'x[' + i + ']';
object.__apply__ = this;
var result = eval('obj.__apply__(' +
parameterStrings[i].join(', ') + ')');
object.__apply__ = null;
return result;
}
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
Ajax = { var Ajax = {
getTransport: function() { getTransport: function() {
return Try.these( return Try.these(
function() {return new ActiveXObject('Msxml2.XMLHTTP')}, function() {return new ActiveXObject('Msxml2.XMLHTTP')},
@ -141,13 +184,17 @@ Ajax.Request.prototype = (new Ajax.Base()).extend({
if (this.options.method == 'get') if (this.options.method == 'get')
url += '?' + this.options.parameters + '&_='; url += '?' + this.options.parameters + '&_=';
this.transport.open(this.options.method, url, true); this.transport.open(this.options.method, url,
this.options.asynchronous);
if (this.options.asynchronous) { if (this.options.asynchronous) {
this.transport.onreadystatechange = this.onStateChange.bind(this); this.transport.onreadystatechange = this.onStateChange.bind(this);
setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
} }
this.transport.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
this.transport.setRequestHeader('X-Prototype-Version', Prototype.Version);
if (this.options.method == 'post') { if (this.options.method == 'post') {
this.transport.setRequestHeader('Connection', 'close'); this.transport.setRequestHeader('Connection', 'close');
this.transport.setRequestHeader('Content-type', this.transport.setRequestHeader('Content-type',
@ -191,14 +238,22 @@ Ajax.Updater.prototype = (new Ajax.Base()).extend({
}, },
updateContent: function() { updateContent: function() {
if (this.options.insertion) {
new this.options.insertion(this.container,
this.request.transport.responseText);
} else {
this.container.innerHTML = this.request.transport.responseText; this.container.innerHTML = this.request.transport.responseText;
if (this.onComplete) this.onComplete(this.request); }
if (this.onComplete) {
setTimeout((function() {this.onComplete(this.request)}).bind(this), 10);
}
} }
}); });
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
Field = { var Field = {
clear: function() { clear: function() {
for (var i = 0; i < arguments.length; i++) for (var i = 0; i < arguments.length; i++)
$(arguments[i]).value = ''; $(arguments[i]).value = '';
@ -212,12 +267,21 @@ Field = {
for (var i = 0; i < arguments.length; i++) for (var i = 0; i < arguments.length; i++)
if ($(arguments[i]).value == '') return false; if ($(arguments[i]).value == '') return false;
return true; return true;
},
select: function(element) {
$(element).select();
},
activate: function(element) {
$(element).focus();
$(element).select();
} }
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
Form = { var Form = {
serialize: function(form) { serialize: function(form) {
var elements = Form.getElements($(form)); var elements = Form.getElements($(form));
var queryComponents = new Array(); var queryComponents = new Array();
@ -241,6 +305,31 @@ Form = {
elements.push(tagElements[j]); elements.push(tagElements[j]);
} }
return elements; return elements;
},
disable: function(form) {
var elements = Form.getElements(form);
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
element.blur();
element.disable = 'true';
}
},
focusFirstElement: function(form) {
form = $(form);
var elements = Form.getElements(form);
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
if (element.type != 'hidden' && !element.disabled) {
Field.activate(element);
break;
}
}
},
reset: function(form) {
$(form).reset();
} }
} }
@ -269,12 +358,14 @@ Form.Element.Serializers = {
input: function(element) { input: function(element) {
switch (element.type.toLowerCase()) { switch (element.type.toLowerCase()) {
case 'hidden': case 'hidden':
case 'password':
case 'text': case 'text':
return Form.Element.Serializers.textarea(element); return Form.Element.Serializers.textarea(element);
case 'checkbox': case 'checkbox':
case 'radio': case 'radio':
return Form.Element.Serializers.inputSelector(element); return Form.Element.Serializers.inputSelector(element);
} }
return false;
}, },
inputSelector: function(element) { inputSelector: function(element) {
@ -288,12 +379,17 @@ Form.Element.Serializers = {
select: function(element) { select: function(element) {
var index = element.selectedIndex; var index = element.selectedIndex;
return [element.name, (index >= 0) ? element.options[index].value : '']; var value = element.options[index].value || element.options[index].text;
return [element.name, (index >= 0) ? value : ''];
} }
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
var $F = Form.Element.getValue;
/*--------------------------------------------------------------------------*/
Abstract.TimedObserver = function() {} Abstract.TimedObserver = function() {}
Abstract.TimedObserver.prototype = { Abstract.TimedObserver.prototype = {
initialize: function(element, frequency, callback) { initialize: function(element, frequency, callback) {
@ -334,3 +430,336 @@ Form.Observer.prototype = (new Abstract.TimedObserver()).extend({
} }
}); });
/*--------------------------------------------------------------------------*/
document.getElementsByClassName = function(className) {
var children = document.getElementsByTagName('*') || document.all;
var elements = new Array();
for (var i = 0; i < children.length; i++) {
var child = children[i];
var classNames = child.className.split(' ');
for (var j = 0; j < classNames.length; j++) {
if (classNames[j] == className) {
elements.push(child);
break;
}
}
}
return elements;
}
/*--------------------------------------------------------------------------*/
var Element = {
toggle: function() {
for (var i = 0; i < arguments.length; i++) {
var element = $(arguments[i]);
element.style.display =
(element.style.display == 'none' ? '' : 'none');
}
},
hide: function() {
for (var i = 0; i < arguments.length; i++) {
var element = $(arguments[i]);
element.style.display = 'none';
}
},
show: function() {
for (var i = 0; i < arguments.length; i++) {
var element = $(arguments[i]);
element.style.display = '';
}
},
remove: function(element) {
element = $(element);
element.parentNode.removeChild(element);
},
getHeight: function(element) {
element = $(element);
return element.offsetHeight;
}
}
var Toggle = new Object();
Toggle.display = Element.toggle;
/*--------------------------------------------------------------------------*/
Abstract.Insertion = function(adjacency) {
this.adjacency = adjacency;
}
Abstract.Insertion.prototype = {
initialize: function(element, content) {
this.element = $(element);
this.content = content;
if (this.adjacency && this.element.insertAdjacentHTML) {
this.element.insertAdjacentHTML(this.adjacency, this.content);
} else {
this.range = this.element.ownerDocument.createRange();
if (this.initializeRange) this.initializeRange();
this.fragment = this.range.createContextualFragment(this.content);
this.insertContent();
}
}
}
var Insertion = new Object();
Insertion.Before = Class.create();
Insertion.Before.prototype = (new Abstract.Insertion('beforeBegin')).extend({
initializeRange: function() {
this.range.setStartBefore(this.element);
},
insertContent: function() {
this.element.parentNode.insertBefore(this.fragment, this.element);
}
});
Insertion.Top = Class.create();
Insertion.Top.prototype = (new Abstract.Insertion('afterBegin')).extend({
initializeRange: function() {
this.range.selectNodeContents(this.element);
this.range.collapse(true);
},
insertContent: function() {
this.element.insertBefore(this.fragment, this.element.firstChild);
}
});
Insertion.Bottom = Class.create();
Insertion.Bottom.prototype = (new Abstract.Insertion('beforeEnd')).extend({
initializeRange: function() {
this.range.selectNodeContents(this.element);
this.range.collapse(this.element);
},
insertContent: function() {
this.element.appendChild(this.fragment);
}
});
Insertion.After = Class.create();
Insertion.After.prototype = (new Abstract.Insertion('afterEnd')).extend({
initializeRange: function() {
this.range.setStartAfter(this.element);
},
insertContent: function() {
this.element.parentNode.insertBefore(this.fragment,
this.element.nextSibling);
}
});
/*--------------------------------------------------------------------------*/
var Effect = new Object();
Effect.Highlight = Class.create();
Effect.Highlight.prototype = {
initialize: function(element) {
this.element = $(element);
this.start = 153;
this.finish = 255;
this.current = this.start;
this.fade();
},
fade: function() {
if (this.isFinished()) return;
if (this.timer) clearTimeout(this.timer);
this.highlight(this.element, this.current);
this.current += 17;
this.timer = setTimeout(this.fade.bind(this), 250);
},
isFinished: function() {
return this.current > this.finish;
},
highlight: function(element, current) {
element.style.backgroundColor = "#ffff" + current.toColorPart();
}
}
Effect.Fade = Class.create();
Effect.Fade.prototype = {
initialize: function(element) {
this.element = $(element);
this.start = 100;
this.finish = 0;
this.current = this.start;
this.fade();
},
fade: function() {
if (this.isFinished()) { this.element.style.display = 'none'; return; }
if (this.timer) clearTimeout(this.timer);
this.setOpacity(this.element, this.current);
this.current -= 10;
this.timer = setTimeout(this.fade.bind(this), 50);
},
isFinished: function() {
return this.current <= this.finish;
},
setOpacity: function(element, opacity) {
opacity = (opacity == 100) ? 99.999 : opacity;
element.style.filter = "alpha(opacity:"+opacity+")";
element.style.opacity = opacity/100 /*//*/;
}
}
Effect.Scale = Class.create();
Effect.Scale.prototype = {
initialize: function(element, percent) {
this.element = $(element);
this.startScale = 1.0;
this.startHeight = this.element.offsetHeight;
this.startWidth = this.element.offsetWidth;
this.currentHeight = this.startHeight;
this.currentWidth = this.startWidth;
this.finishScale = (percent/100) /*//*/;
if (this.element.style.fontSize=="") this.sizeEm = 1.0;
if (this.element.style.fontSize.indexOf("em")>0)
this.sizeEm = parseFloat(this.element.style.fontSize);
if(this.element.effect_scale) {
clearTimeout(this.element.effect_scale.timer);
this.startScale = this.element.effect_scale.currentScale;
this.startHeight = this.element.effect_scale.startHeight;
this.startWidth = this.element.effect_scale.startWidth;
if(this.element.effect_scale.sizeEm)
this.sizeEm = this.element.effect_scale.sizeEm;
}
this.element.effect_scale = this;
this.currentScale = this.startScale;
this.factor = this.finishScale - this.startScale;
this.options = arguments[2] || {};
this.scale();
},
scale: function() {
if (this.isFinished()) {
this.setDimensions(this.element, this.startWidth*this.finishScale, this.startHeight*this.finishScale);
if(this.sizeEm) this.element.style.fontSize = this.sizeEm*this.finishScale + "em";
if(this.options.complete) this.options.complete(this);
return;
}
if (this.timer) clearTimeout(this.timer);
if (this.options.step) this.options.step(this);
this.setDimensions(this.element, this.currentWidth, this.currentHeight);
if(this.sizeEm) this.element.style.fontSize = this.sizeEm*this.currentScale + "em";
this.currentScale += (this.factor/10) /*//*/;
this.currentWidth = this.startWidth * this.currentScale;
this.currentHeight = this.startHeight * this.currentScale;
this.timer = setTimeout(this.scale.bind(this), 50);
},
isFinished: function() {
return (this.factor < 0) ?
this.currentScale <= this.finishScale : this.currentScale >= this.finishScale;
},
setDimensions: function(element, width, height) {
element.style.width = width + 'px';
element.style.height = height + 'px';
}
}
Effect.Squish = Class.create();
Effect.Squish.prototype = {
initialize: function(element) {
this.element = $(element);
new Effect.Scale(this.element, 1, { complete: this.hide.bind(this) } );
},
hide: function() {
this.element.style.display = 'none';
}
}
Effect.Puff = Class.create();
Effect.Puff.prototype = {
initialize: function(element) {
this.element = $(element);
this.opacity = 100;
this.startTop = this.element.top || this.element.offsetTop;
this.startLeft = this.element.left || this.element.offsetLeft;
new Effect.Scale(this.element, 200, { step: this.fade.bind(this), complete: this.hide.bind(this) } );
},
fade: function(effect) {
topd = (((effect.currentScale)*effect.startHeight) - effect.startHeight)/2;
leftd = (((effect.currentScale)*effect.startWidth) - effect.startWidth)/2;
this.element.style.position='absolute';
this.element.style.top = this.startTop-topd + "px";
this.element.style.left = this.startLeft-leftd + "px";
this.opacity -= 10;
this.setOpacity(this.element, this.opacity);
if(navigator.appVersion.indexOf('AppleWebKit')>0) this.element.innerHTML += ''; //force redraw on safari
},
hide: function() {
this.element.style.display = 'none';
},
setOpacity: function(element, opacity) {
opacity = (opacity == 100) ? 99.999 : opacity;
element.style.filter = "alpha(opacity:"+opacity+")";
element.style.opacity = opacity/100 /*//*/;
}
}
Effect.Appear = Class.create();
Effect.Appear.prototype = {
initialize: function(element) {
this.element = $(element);
this.start = 0;
this.finish = 100;
this.current = this.start;
this.fade();
},
fade: function() {
if (this.isFinished()) return;
if (this.timer) clearTimeout(this.timer);
this.setOpacity(this.element, this.current);
this.current += 10;
this.timer = setTimeout(this.fade.bind(this), 50);
},
isFinished: function() {
return this.current > this.finish;
},
setOpacity: function(element, opacity) {
opacity = (opacity == 100) ? 99.999 : opacity;
element.style.filter = "alpha(opacity:"+opacity+")";
element.style.opacity = opacity/100 /*//*/;
element.style.display = '';
}
}
Effect.ContentZoom = Class.create();
Effect.ContentZoom.prototype = {
initialize: function(element, percent) {
this.element = $(element);
if (this.element.style.fontSize=="") this.sizeEm = 1.0;
if (this.element.style.fontSize.indexOf("em")>0)
this.sizeEm = parseFloat(this.element.style.fontSize);
if(this.element.effect_contentzoom) {
this.sizeEm = this.element.effect_contentzoom.sizeEm;
}
this.element.effect_contentzoom = this;
this.element.style.fontSize = this.sizeEm*(percent/100) + "em" /*//*/;
if(navigator.appVersion.indexOf('AppleWebKit')>0) { this.element.scrollTop -= 1; };
}
}

View file

@ -5,11 +5,12 @@ function toggleAll(itemname,state) {
} }
} }
function toggle(idname) { // Contributed by Andrew Williams
function toggleSingle(idname)
{
document.getElementById(idname).style.display = (document.getElementById(idname).style.display == 'none') ? 'block' : 'none'; document.getElementById(idname).style.display = (document.getElementById(idname).style.display == 'none') ? 'block' : 'none';
} }
// Contributed by Andrew Williams
function toggleAllImages() function toggleAllImages()
{ {
var cookies = document.cookie.split(';'); var cookies = document.cookie.split(';');
@ -23,18 +24,13 @@ function toggleAllImages()
var id = str.split('_')[2]; var id = str.split('_')[2];
if(getCookie(str) == 'collapsed') if(getCookie(str) == 'collapsed')
{ {
toggle('c'+id); toggleSingle('c'+id);
toggleImage('toggle_context_'+id); toggleImage('toggle_context_'+id);
} }
} }
} }
} }
function toggle(idname)
{
document.getElementById(idname).style.display = (document.getElementById(idname).style.display == 'none') ? 'block' : 'none';
}
function toggleImage(idname) function toggleImage(idname)
{ {
if(document.images) if(document.images)
@ -125,3 +121,4 @@ function markItemDone(rowId, uri, id) {
} }
req.send(encodeURIComponent("id") + '=' + encodeURIComponent(id)); req.send(encodeURIComponent("id") + '=' + encodeURIComponent(id));
}; };

View file

@ -0,0 +1,232 @@
/* The main calendar widget. DIV containing a table. */
div.calendar { position: relative; }
.calendar, .calendar table {
border: 1px solid #556;
font-size: 11px;
color: #000;
cursor: default;
background: #eef;
font-family: tahoma,verdana,sans-serif;
}
/* Header part -- contains navigation buttons and day names. */
.calendar .button { /* "<<", "<", ">", ">>" buttons have this class */
text-align: center; /* They are the navigation buttons */
padding: 2px; /* Make the buttons seem like they're pressing */
}
.calendar .nav {
background: #778 url(menuarrow.gif) no-repeat 100% 100%;
}
.calendar thead .title { /* This holds the current "month, year" */
font-weight: bold; /* Pressing it will take you to the current date */
text-align: center;
background: #fff;
color: #000;
padding: 2px;
}
.calendar thead .headrow { /* Row <TR> containing navigation buttons */
background: #778;
color: #fff;
}
.calendar thead .daynames { /* Row <TR> containing the day names */
background: #bdf;
}
.calendar thead .name { /* Cells <TD> containing the day names */
border-bottom: 1px solid #556;
padding: 2px;
text-align: center;
color: #000;
}
.calendar thead .weekend { /* How a weekend day name shows in header */
color: #a66;
}
.calendar thead .hilite { /* How do the buttons in header appear when hover */
background-color: #aaf;
color: #000;
border: 1px solid #04f;
padding: 1px;
}
.calendar thead .active { /* Active (pressed) buttons in header */
background-color: #77c;
padding: 2px 0px 0px 2px;
}
/* The body part -- contains all the days in month. */
.calendar tbody .day { /* Cells <TD> containing month days dates */
width: 2em;
color: #456;
text-align: right;
padding: 2px 4px 2px 2px;
}
.calendar tbody .day.othermonth {
font-size: 80%;
color: #bbb;
}
.calendar tbody .day.othermonth.oweekend {
color: #fbb;
}
.calendar table .wn {
padding: 2px 3px 2px 2px;
border-right: 1px solid #000;
background: #bdf;
}
.calendar tbody .rowhilite td {
background: #def;
}
.calendar tbody .rowhilite td.wn {
background: #eef;
}
.calendar tbody td.hilite { /* Hovered cells <TD> */
background: #def;
padding: 1px 3px 1px 1px;
border: 1px solid #bbb;
}
.calendar tbody td.active { /* Active (pressed) cells <TD> */
background: #cde;
padding: 2px 2px 0px 2px;
}
.calendar tbody td.selected { /* Cell showing today date */
font-weight: bold;
border: 1px solid #000;
padding: 1px 3px 1px 1px;
background: #fff;
color: #000;
}
.calendar tbody td.weekend { /* Cells showing weekend days */
color: #a66;
}
.calendar tbody td.today { /* Cell showing selected date */
font-weight: bold;
color: #00f;
}
.calendar tbody .disabled { color: #999; }
.calendar tbody .emptycell { /* Empty cells (the best is to hide them) */
visibility: hidden;
}
.calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */
display: none;
}
/* The footer part -- status bar and "Close" button */
.calendar tfoot .footrow { /* The <TR> in footer (only one right now) */
text-align: center;
background: #556;
color: #fff;
}
.calendar tfoot .ttip { /* Tooltip (status bar) cell <TD> */
background: #fff;
color: #445;
border-top: 1px solid #556;
padding: 1px;
}
.calendar tfoot .hilite { /* Hover style for buttons in footer */
background: #aaf;
border: 1px solid #04f;
color: #000;
padding: 1px;
}
.calendar tfoot .active { /* Active (pressed) style for buttons in footer */
background: #77c;
padding: 2px 0px 0px 2px;
}
/* Combo boxes (menus that display months/years for direct selection) */
.calendar .combo {
position: absolute;
display: none;
top: 0px;
left: 0px;
width: 4em;
cursor: default;
border: 1px solid #655;
background: #def;
color: #000;
font-size: 90%;
z-index: 100;
}
.calendar .combo .label,
.calendar .combo .label-IEfix {
text-align: center;
padding: 1px;
}
.calendar .combo .label-IEfix {
width: 4em;
}
.calendar .combo .hilite {
background: #acf;
}
.calendar .combo .active {
border-top: 1px solid #46a;
border-bottom: 1px solid #46a;
background: #eef;
font-weight: bold;
}
.calendar td.time {
border-top: 1px solid #000;
padding: 1px 0px;
text-align: center;
background-color: #f4f0e8;
}
.calendar td.time .hour,
.calendar td.time .minute,
.calendar td.time .ampm {
padding: 0px 3px 0px 4px;
border: 1px solid #889;
font-weight: bold;
background-color: #fff;
}
.calendar td.time .ampm {
text-align: center;
}
.calendar td.time .colon {
padding: 0px 2px 0px 3px;
font-weight: bold;
}
.calendar td.time span.hilite {
border-color: #000;
background-color: #667;
color: #fff;
}
.calendar td.time span.active {
border-color: #f00;
background-color: #000;
color: #0f0;
}

View file

@ -13,6 +13,7 @@ p {
padding: 2px; padding: 2px;
} }
img {border: 0px;}
a, a:link, a:active, a:visited { a, a:link, a:active, a:visited {
color: #cc3334; color: #cc3334;
@ -34,6 +35,12 @@ a:hover {
margin: 0px 15px 50px 15px; margin: 0px 15px 50px 15px;
} }
#full_width_display {
float: left;
width: 800px;
margin: 0px 15px 50px 15px;
}
#display_box_projects { #display_box_projects {
float: left; float: left;
width: 820px; width: 820px;
@ -95,6 +102,19 @@ a:hover {
text-shadow: rgba(0,0,0,.4) 0px 2px 5px; text-shadow: rgba(0,0,0,.4) 0px 2px 5px;
} }
.new_actions {
padding: 0px 5px 2px 5px;
background: #E7FDDE;
border: 1px solid #57A620;
padding: 5px;
margin-bottom: 15px;
}
.new_actions h2 {
padding: 0 px 5px 0px 5px;
color: #57A620;
}
h2 a, h2 a:link, h2 a:active, h2 a:visited { h2 a, h2 a:link, h2 a:active, h2 a:visited {
color: #fff; color: #fff;
text-decoration: none; text-decoration: none;
@ -125,13 +145,21 @@ h2 a:hover {
} }
#input_box ul {list-style-type: circle; font-size: 0.9em;}
.box { .box {
float: left; float: left;
width: 20px; width: 20px;
} }
.big-box {
float: left;
width: 55px;
vertical-align: middle;
}
.description { .description {
margin-left: 25px; margin-left: 60px;
margin-right: 10px; margin-right: 10px;
} }
@ -245,13 +273,45 @@ li {
.even_row { .even_row {
background: #fff; background: #fff;
padding: 5px 5px 5px 10px;
} }
.odd_row { .odd_row {
background: #EDF3FE; background: #EDF3FE;
padding: 5px 5px 5px 10px;
} }
.edit-form {
background: #ccc;
padding: 5px;
border-top: 1px solid #999;
border-bottom: 1px solid #999;
}
/* Right align labels in forms */
.label {
text-align: right;
}
input {
vertical-align: middle;
}
/* Positioning the 'cells' in the list */
.position {text-align: left; width: 5%; float: left;}
.data {text-align: left; width: 65%; float: left;}
.buttons {text-align: right; width: 25%; margin-left: 75%;}
table.list { table.list {
margin-top: 0px;
border-top: 1px solid #ccc;
border-left: 1px solid #ccc;
border-right: 1px solid #ccc;
background: #fff;
}
div#list-projects, div#list-contexts {
border: 1px solid #999; border: 1px solid #999;
} }
@ -268,11 +328,18 @@ form {
width: 313px; width: 313px;
} }
label { .inline-form {
font-weight: bold; border: none;
padding: 3px;
width: 100%;
} }
input { label {
font-weight: bold;
padding: 0px 0px;
}
input, select {
margin-bottom: 5px; margin-bottom: 5px;
} }
@ -288,59 +355,3 @@ input {
padding:0px 3px 0px 3px; padding:0px 3px 0px 3px;
margin:0px; margin:0px;
} }
/* Popup calendar styles */
#calNavPY, #calNavPM {border:1px #999 solid}
#calNavNM, #calNavNY { border:1px #999 solid}
#calNav td, #calNav td a {
text-align:center;
font-family:"Lucida Grande", Verdana, Geneva, Arial, sans-serif;
font-size:12px;
font-weight:bold;
background-color:#eaeaea;
text-decoration:none
}
#calNav td a,#calNav td a:visited,#calTbl td a,#calTbl td a:visited {color:#cc3334 }
#calNav td a:hover,#calTbl td a:hover { color:#fff; background:#cc3334; }
#calNav {margin-bottom:5px;width:100%}
#calTbl {width:100%}
#calTbl td {text-align:center;font-family:"Lucida Grande", Verdana, Geneva, Arial, sans-serif;font-size:11px;border:1px #ccc solid}
#calTbl thead td {
font-weight:bold;
background-color:#eaeaea;
padding: 2px;
border:1px #ccc solid
height: auto;
}
#calDiv {
border:1px solid #ccc;
padding:2px;
width:200px;
position:absolute;
z-index:276;
top:300px;
left:300px;
background-color:#fff
}
#calTopBar {
background-color:#ccc;
color:#fff;
padding:2px;
text-align:right;
font-family:"Lucida Grande", Verdana, Geneva, Arial, sans-serif;
font-size:11px;
font-weight:bold;
width:100%
}
#calClose {
padding:0px 2px;border:1px #fff solid;cursor:pointer;cursor:hand
}
#calPic {cursor:hand}

19
tracks/script/benchmarker Executable file
View file

@ -0,0 +1,19 @@
#!/usr/local/bin/ruby
if ARGV.empty?
puts "Usage: benchmarker times 'Person.expensive_way' 'Person.another_expensive_way' ..."
exit
end
require File.dirname(__FILE__) + '/../config/environment'
require 'benchmark'
include Benchmark
# Don't include compilation in the benchmark
ARGV[1..-1].each { |expression| eval(expression) }
bm(6) do |x|
ARGV[1..-1].each_with_index do |expression, idx|
x.report("##{idx + 1}") { ARGV[0].to_i.times { eval(expression) } }
end
end

7
tracks/script/console_sandbox Executable file
View file

@ -0,0 +1,7 @@
#!/usr/local/bin/ruby
ActiveRecord::Base.lock_mutex
ActiveRecord::Base.connection.begin_db_transaction
at_exit do
ActiveRecord::Base.connection.rollback_db_transaction
ActiveRecord::Base.unlock_mutex
end

17
tracks/script/profiler Executable file
View file

@ -0,0 +1,17 @@
#!/usr/local/bin/ruby
if ARGV.empty?
puts "Usage: profiler 'Person.expensive_method(10)' [times]"
exit
end
require File.dirname(__FILE__) + '/../config/environment'
require "profiler"
# Don't include compilation in the profile
eval(ARGV.first)
Profiler__::start_profile
(ARGV[1] || 1).to_i.times { eval(ARGV.first) }
Profiler__::stop_profile
Profiler__::print_profile($stdout)