Rationalised and streamlined the flash and error notifications, using a method outlined here by Andreas Aderhold:

http://blog.andreasaderhold.com/2006/07/rails-notifications

All flash messages now show up as an overlay on the right hand side of the navigation header, and also fade automatically, so that you don't have to refresh the page. Errors (i.e. validation errors) are shown as close to the originating form as possible.

Two new notify methods (one for controllers, and one for RJS templates) help construct the flash of whatever type you like. e.g.

In controllers:

notify :warning, "This is the message"

In RJS:

notify :warning, "This is the message", 5.0



git-svn-id: http://www.rousette.org.uk/svn/tracks-repos/trunk@351 a4c988fc-2ded-0310-b66e-134b36920a42
This commit is contained in:
bsag 2006-11-19 16:52:58 +00:00
parent fed0daa96d
commit 5d51ca84ba
49 changed files with 227 additions and 234 deletions

View file

@ -50,22 +50,6 @@ class ApplicationController < ActionController::Base
end
end
def redirect_with_notice( message, options = {})
options['flash_target'] = 'notice'
redirect_with_flash message, options
end
def redirect_with_flash( message, options )
flash[options['flash_target']] = message
options.delete 'flash_target'
redirect_to options
end
def redirect_with_warning( message, options = {})
options['flash_target'] = 'warning'
redirect_with_flash message, options
end
def render_failure message, status = 404
render :text => message, :status => status
end
@ -107,4 +91,12 @@ class ApplicationController < ActionController::Base
end
end
# Set the contents of the flash message from a controller
# Usage: notify :warning, "This is the message"
# Sets the flash of type 'warning' to "This is the message"
def notify(type, message)
flash[type] = message
logger.error("ERROR: #{message}") if type == :error
end
end

View file

@ -3,7 +3,7 @@ class ContextController < ApplicationController
helper :todo
prepend_before_filter :login_required
layout "standard"
layout "standard", :except => :date_preview
def index
list
@ -78,19 +78,17 @@ class ContextController < ApplicationController
@saved = @item.save
if @saved
# This reports real count +1 for some reason that I don't understand
# Almost identical code for add_item in projects reports correct num
@up_count = Todo.find(:all, :conditions => ["todos.user_id = ? and todos.done = ? and todos.context_id IN (?)", @user.id, false, @item.context_id]).size.to_s
@up_count = Todo.find(:all, :conditions => ["todos.user_id = ? and todos.state = ? and todos.context_id = ?", @user.id, 'active', @item.context_id]).size.to_s
end
return if request.xhr?
# fallback for standard requests
if @saved
flash[:notice] = 'Added new next action.'
notify :notice, 'Added new next action.'
redirect_to :controller => 'todo', :action => 'list'
else
flash[:warning] = 'The next action was not added. Please try again.'
notify :warning, 'The next action was not added. Please try again.'
redirect_to :controller => 'todo', :action => 'list'
end
@ -98,7 +96,7 @@ class ContextController < ApplicationController
if request.xhr? # be sure to include an error.rjs
render :action => 'error'
else
flash[:warning] = 'An error occurred on the server.'
notify :warning, 'An error occurred on the server.'
redirect_to :controller => 'todo', :action => 'list'
end
end
@ -113,7 +111,7 @@ class ContextController < ApplicationController
if @context.save
render :partial => 'context_listing', :object => @context
else
flash[:warning] = "Couldn't update new context"
notify :warning, "Couldn't update new context"
render :text => ""
end
end
@ -126,7 +124,7 @@ class ContextController < ApplicationController
if @context.destroy
render_text ""
else
flash[:warning] = "Couldn't delete context \"#{@context.name}\""
notify :warning, "Couldn't delete context \"#{@context.name}\""
redirect_to( :controller => "context", :action => "list" )
end
end
@ -156,7 +154,7 @@ class ContextController < ApplicationController
return @context
else
@context = nil # Should be nil anyway.
flash[:warning] = "Item and session user mis-match: #{@context.user_id} and #{@user.id}!"
notify :warning, "Item and session user mis-match: #{@context.user_id} and #{@user.id}!"
render_text ""
end
end
@ -167,7 +165,7 @@ class ContextController < ApplicationController
return @context
else
@context = nil
flash[:warning] = "Project and session user mis-match: #{@context.user_id} and #{@user.id}!"
notify :warning, "Project and session user mis-match: #{@context.user_id} and #{@user.id}!"
render_text ""
end
end
@ -177,7 +175,7 @@ class ContextController < ApplicationController
if @user == item.user
return item
else
flash[:warning] = "Item and session user mis-match: #{item.user.name} and #{@user.name}!"
notify :warning, "Item and session user mis-match: #{item.user.name} and #{@user.name}!"
render_text ""
end
end

View file

@ -79,7 +79,7 @@ class DeferredController < ApplicationController
respond_to do |wants|
wants.html do
flash[:notice] = 'Successfully deleted next action' if @saved
notify :notice, 'Successfully deleted next action' if @saved
redirect_to :action => "index"
end
wants.js do
@ -92,7 +92,7 @@ class DeferredController < ApplicationController
rescue
respond_to do |wants|
wants.html do
flash[:warning] = 'An error occurred on the server.'
notify :warning, 'An error occurred on the server.'
redirect_to :action => "index"
end
wants.js { render :action => 'error' }
@ -123,7 +123,7 @@ class DeferredController < ApplicationController
if @user == item.user
return item
else
flash[:warning] = "Item and session user mis-match: #{item.user.name} and #{@user.name}!"
notify :warning, "Item and session user mis-match: #{item.user.name} and #{@user.name}!"
render_text ""
end
end

View file

@ -14,12 +14,12 @@ class LoginController < ApplicationController
# of inactivity
session['noexpiry'] = params['user_noexpiry']
msg = (should_expire_sessions?) ? "will expire after 1 hour of inactivity." : "will not expire."
flash[:notice] = "Login successful: session #{msg}"
notify :notice, "Login successful: session #{msg}"
cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year }
redirect_back_or_default :controller => "todo", :action => "index"
else
@login = params['user_login']
flash[:warning] = "Login unsuccessful"
notify :warning, "Login unsuccessful"
end
end
end
@ -37,7 +37,7 @@ class LoginController < ApplicationController
# redirect to the server
redirect_to open_id_response.redirect_url((request.protocol + request.host_with_port + "/"), url_for(:action => 'complete'))
else
flash[:warning] = "Unable to find openid server for <q>#{params[:openid_url]}</q>"
notify :warning, "Unable to find openid server for <q>#{params[:openid_url]}</q>"
redirect_to :action => 'login'
end
end
@ -49,11 +49,11 @@ class LoginController < ApplicationController
# URL that we were verifying. We include it in the error
# message to help the user figure out what happened.
if open_id_response.identity_url
flash[:message] = "Verification of #{open_id_response.identity_url} failed. "
msg = "Verification of #{open_id_response.identity_url} failed. "
else
flash[:message] = "Verification failed. "
msg = "Verification failed. "
end
flash[:message] += open_id_response.msg.to_s
notify :error, open_id_response.msg.to_s + msg
when OpenID::SUCCESS
# Success means that the transaction completed without
@ -61,18 +61,18 @@ class LoginController < ApplicationController
# the verification.
@user = User.find_by_open_id_url(open_id_response.identity_url)
unless (@user.nil?)
flash[:message] = "You have successfully verified #{open_id_response.identity_url} as your identity."
notify :notice, "You have successfully verified #{open_id_response.identity_url} as your identity."
session['user_id'] = @user.id
redirect_back_or_default :controller => 'todo', :action => 'index'
else
flash[:warning] = "You have successfully verified #{open_id_response.identity_url} as your identity, but you do not have a Tracks account. Please ask your administrator to sign you up."
notify :warning, "You have successfully verified #{open_id_response.identity_url} as your identity, but you do not have a Tracks account. Please ask your administrator to sign you up."
end
when OpenID::CANCEL
flash[:message] = "Verification cancelled."
notify :warning, "Verification cancelled."
else
flash[:warning] = "Unknown response status: #{open_id_response.status}"
notify :warning, "Unknown response status: #{open_id_response.status}"
end
redirect_to :action => 'login' unless performed?
end
@ -107,7 +107,7 @@ class LoginController < ApplicationController
@user = User.authenticate(user.login, params['user']['password'])
@user.create_preference
@user.save
flash[:notice] = "Signup successful for user #{@user.login}."
notify :notice, "Signup successful for user #{@user.login}."
redirect_back_or_default :controller => "todo", :action => "index"
end
end
@ -124,7 +124,7 @@ class LoginController < ApplicationController
def logout
session['user_id'] = nil
reset_session
flash[:notice] = "You have been logged out of Tracks."
notify :notice, "You have been logged out of Tracks."
redirect_to :action => "login"
end

View file

@ -87,7 +87,7 @@ class MobileController < ApplicationController
if @user == item.user
return item
else
flash[:warning] = "Item and session user mis-match: #{item.user.name} and #{@user.name}!"
notify :warning, "Item and session user mis-match: #{item.user.name} and #{@user.name}!"
render_text ""
end
end

View file

@ -37,7 +37,7 @@ class NoteController < ApplicationController
if note.destroy
render :text => ''
else
flash[:warning] = "Couldn't delete note \"#{note.id.to_s}\""
notify :warning, "Couldn't delete note \"#{note.id.to_s}\""
render :text => ''
end
end
@ -48,7 +48,7 @@ class NoteController < ApplicationController
if note.save
render :partial => 'notes', :object => note
else
flash[:warning] = "Couldn't update note \"#{note.id.to_s}\""
notify :warning, "Couldn't update note \"#{note.id.to_s}\""
render :text => ''
end
end

View file

@ -5,7 +5,7 @@ class ProjectController < ApplicationController
helper :todo
prepend_before_filter :login_required
layout "standard"
layout "standard", :except => :date_preview
def index
list
@ -35,7 +35,7 @@ class ProjectController < ApplicationController
@page_title = "TRACKS::Project: #{@project.name}"
if @contexts.empty?
flash[:warning] = 'You must add at least one context before adding next actions.'
notify :warning, 'You must add at least one context before adding next actions.'
end
if @not_done.empty?
@ -103,17 +103,17 @@ class ProjectController < ApplicationController
@saved = @item.save
if @saved
@up_count = Todo.find(:all, :conditions => ["todos.user_id = ? and todos.done = ? and todos.project_id IN (?)", @user.id, false, @item.project_id]).size.to_s
@up_count = Todo.find(:all, :conditions => ["todos.user_id = ? and todos.state = ? and todos.project_id = ?", @user.id, 'active', @item.project_id]).size.to_s
end
return if request.xhr?
# fallback for standard requests
if @saved
flash[:notice] = 'Added new next action.'
notify :notice, 'Added new next action.'
redirect_to :controller => 'todo', :action => 'index'
else
flash[:warning] = 'The next action was not added. Please try again.'
notify :warning, 'The next action was not added. Please try again.'
redirect_to :controller => 'todo', :action => 'index'
end
@ -121,7 +121,7 @@ class ProjectController < ApplicationController
if request.xhr? # be sure to include an error.rjs
render :action => 'error'
else
flash[:warning] = 'An error occurred on the server.'
notify :warning, 'An error occurred on the server.'
redirect_to :controller => 'todo', :action => 'index'
end
end
@ -148,7 +148,7 @@ class ProjectController < ApplicationController
render :text => 'Success'
end
else
flash[:warning] = "Couldn't update project"
notify :warning, "Couldn't update project"
render :text => ''
end
end
@ -171,7 +171,7 @@ class ProjectController < ApplicationController
if @project.destroy
render :text => ''
else
flash[:warning] = "Couldn't delete project \"#{@project.name}\""
notify :warning, "Couldn't delete project \"#{@project.name}\""
redirect_to( :controller => "project", :action => "list" )
end
end
@ -201,7 +201,7 @@ class ProjectController < ApplicationController
return @project
else
@project = nil # Should be nil anyway
flash[:warning] = "Project and session user mis-match: #{@project.user_id} and #{@user.id}!"
notify :warning, "Project and session user mis-match: #{@project.user_id} and #{@user.id}!"
render :text => ''
end
end
@ -212,7 +212,7 @@ class ProjectController < ApplicationController
return @project
else
@project = nil
flash[:warning] = "Project and session user mis-match: #{@project.user_id} and #{@user.id}!"
notify :warning, "Project and session user mis-match: #{@project.user_id} and #{@user.id}!"
render :text => ''
end
end
@ -222,7 +222,7 @@ class ProjectController < ApplicationController
if @user == item.user
return item
else
flash[:warning] = "Item and session user mis-match: #{item.user.name} and #{@user.name}!"
notify :warning, "Item and session user mis-match: #{item.user.name} and #{@user.name}!"
render :text => ''
end
end

View file

@ -35,7 +35,7 @@ class TodoController < ApplicationController
@contexts_to_show = @contexts.reject {|x| x.hide? }
if @contexts.empty?
flash[:warning] = 'You must add at least one context before adding next actions.'
notify :warning, "You must add at least one context before adding next actions."
end
# Set count badge to number of not-done, not hidden context items
@ -90,7 +90,7 @@ class TodoController < ApplicationController
rescue
respond_to do |wants|
wants.html do
flash[:warning] = 'An error occurred on the server.'
notify :warning, "An error occurred on the server."
render :action => "index"
end
wants.js { render :action => 'error' }
@ -130,9 +130,12 @@ class TodoController < ApplicationController
return if request.xhr?
if @saved
redirect_with_notice "The action <strong>'#{@item.description}'</strong> was marked as <strong>#{@item.completed? ? 'complete' : 'incomplete' }</strong>", :action => "index"
# TODO: I think this will work, but can't figure out how to test it
notify :notice, "The action <strong>'#{@item.description}'</strong> was marked as <strong>#{@item.completed? ? 'complete' : 'incomplete' }</strong>"
redirect_to :action => "index"
else
redirect_with_notice "The action <strong>'#{@item.description}'</strong> was NOT marked as <strong>#{@item.completed? ? 'complete' : 'incomplete' } due to an error on the server.</strong>", :action => "index"
notify :notice, "The action <strong>'#{@item.description}'</strong> was NOT marked as <strong>#{@item.completed? ? 'complete' : 'incomplete' } due to an error on the server.</strong>", "index"
redirect_to :action => "index"
end
end
@ -166,7 +169,7 @@ class TodoController < ApplicationController
render :action => 'update'
else
render :update do |page|
page.replace_html "info", content_tag("div", "Error updating the context of the dragged item. Item and context user mis-match: #{@item.user.name} and #{@context.user.name}! - refresh the page to see them.", "class" => "warning")
page.notify :warning, content_tag("div", "Error updating the context of the dragged item. Item and context user mis-match: #{@item.user.name} and #{@context.user.name}! - refresh the page to see them."), 8.0
end
end
end
@ -183,7 +186,7 @@ class TodoController < ApplicationController
render :action => 'update'
else
render :update do |page|
page.replace_html "info", content_tag("div", "Error updating the project of the dragged item. Item and project user mis-match: #{@item.user.name} and #{@project.user.name}! - refresh the page to see them.", "class" => "warning")
page.notify :warning, content_tag("div", "Error updating the project of the dragged item. Item and project user mis-match: #{@item.user.name} and #{@project.user.name}! - refresh the page to see them."), 8.0
end
end
end
@ -198,9 +201,11 @@ class TodoController < ApplicationController
wants.html do
if @saved
redirect_with_notice 'Successfully deleted next action', :action => 'index'
notify :notice, "Successfully deleted next action", 2.0
redirect_to :action => 'index'
else
redirect_with_warning 'Failed to delete the action.', :action => 'index'
notify :error, "Failed to delete the action", 2.0
redirect_to :action => 'index'
end
end
@ -223,7 +228,7 @@ class TodoController < ApplicationController
rescue
respond_to do |wants|
wants.html do
flash[:warning] = 'An error occurred on the server.'
notify :error, 'An error occurred on the server.', 8.0
redirect_to :action => 'index'
end
wants.js { render :action => 'error' }
@ -255,7 +260,7 @@ class TodoController < ApplicationController
@error_message = 'Item and session user mis-match: #{item.user.name} and #{@user.name}!'
respond_to do |wants|
wants.html do
flash[:warning] = @error_message
notify :error, @error_message, 8.0
render :action => "index"
end
wants.js { render :action => 'error' }

View file

@ -75,6 +75,7 @@ class UserController < ApplicationController
redirect_to :controller => 'user', :action => 'preferences'
else
redirect_to :controller => 'user', :action => 'change_password'
notify :warning, "There was a problem saving the password. Please retry."
end
end
@ -92,17 +93,17 @@ class UserController < ApplicationController
# redirect to the server
redirect_to open_id_response.redirect_url((request.protocol + request.host_with_port + "/"), url_for(:action => 'complete'))
else
flash[:warning] = "Unable to find openid server for <q>#{params[:openid_url]}</q>"
notify :warning, "Unable to find openid server for <q>#{params[:openid_url]}</q>"
redirect_to :action => 'change_auth_type'
end
return
end
@user.auth_type = params[:user][:auth_type]
if @user.save
flash[:notice] = "Authentication type updated."
notify :notice, "Authentication type updated."
redirect_to :controller => 'user', :action => 'preferences'
else
flash[:warning] = "There was a problem updating your authentication type: #{ @user.errors.full_messages.join(', ')}"
notify :warning, "There was a problem updating your authentication type: #{ @user.errors.full_messages.join(', ')}"
redirect_to :controller => 'user', :action => 'change_auth_type'
end
end
@ -114,11 +115,11 @@ class UserController < ApplicationController
# URL that we were verifying. We include it in the error
# message to help the user figure out what happened.
if open_id_response.identity_url
flash[:message] = "Verification of #{open_id_response.identity_url} failed. "
msg = "Verification of #{open_id_response.identity_url} failed. "
else
flash[:message] = "Verification failed. "
msg = "Verification failed. "
end
flash[:message] += open_id_response.msg.to_s
notify :error, open_id_response.msg.to_s + msg
when OpenID::SUCCESS
# Success means that the transaction completed without
@ -127,17 +128,17 @@ class UserController < ApplicationController
@user.auth_type = 'open_id'
@user.open_id_url = open_id_response.identity_url
if @user.save
flash[:message] = "You have successfully verified #{open_id_response.identity_url} as your identity and set your authentication type to Open ID."
notify :notice, "You have successfully verified #{open_id_response.identity_url} as your identity and set your authentication type to Open ID."
else
flash[:warning] = "You have successfully verified #{open_id_response.identity_url} as your identity but there was a problem saving your authentication preferences."
notify :warning, "You have successfully verified #{open_id_response.identity_url} as your identity but there was a problem saving your authentication preferences."
end
redirect_to :action => 'preferences'
when OpenID::CANCEL
flash[:message] = "Verification cancelled."
notify :warning, "Verification cancelled."
else
flash[:warning] = "Unknown response status: #{open_id_response.status}"
notify :warning, "Unknown response status: #{open_id_response.status}"
end
redirect_to :action => 'change_auth_type' unless performed?
end
@ -146,6 +147,7 @@ class UserController < ApplicationController
def refresh_token
@user.crypt_word
@user.save
notify :notice, "New token successfully generated"
redirect_to :controller => 'user', :action => 'preferences'
end
@ -154,10 +156,10 @@ class UserController < ApplicationController
def do_change_password_for(user)
user.change_password(params[:updateuser][:password], params[:updateuser][:password_confirmation])
if user.save
flash[:notice] = "Password updated."
notify :notice, "Password updated."
return true
else
flash[:warning] = 'There was a problem saving the password. Please retry.'
notify :error, 'There was a problem saving the password. Please retry.'
return false
end
end

View file

@ -148,4 +148,13 @@ module ApplicationHelper
render :partial => 'shared/flash'
end
# Display a flash message in RJS templates
# Usage: page.notify :warning, "This is the message", 5.0
# Puts the message into a flash of type 'warning', fades over 5 secs
def notify(type, message, fade_duration)
type = type.to_s # symbol to string
page.replace 'flash', "<h4 id='flash' class='alert #{type}'>#{message}</h4>"
page.visual_effect :fade, 'flash', :duration => fade_duration
end
end

View file

@ -1,7 +1,5 @@
if @saved
page.show "status"
page.replace_html "status", content_tag("div", "Added new next action", "class" => "confirmation")
page.visual_effect :fade, 'status', :duration => 2
page.notify :notice, "Added new next action", 5.0
page['badge_count'].replace_html @up_count
page.send :record, "Form.reset('todo-form-new-action');Form.focusFirstElement('todo-form-new-action')"
page.send :record, "Form.reset('todo-form-new-action-lightbox');Form.focusFirstElement('todo-form-new-action-lightbox')"
@ -9,7 +7,6 @@ if @saved
page.visual_effect :highlight, "item-#{@item.id}-container", :duration => 3
page["c#{@item.context_id}empty-nd"].hide # If we are adding an new action, the uncompleted actions must be > 0
else
page.hide "status"
page.replace_html "status", content_tag("div", content_tag("h2", "#{pluralize(@item.errors.count, "error")} prohibited this record from being saved") + content_tag("p", "There were problems with the following fields:") + content_tag("ul", @item.errors.each_full { |msg| content_tag("li", msg) }), "id" => "ErrorExplanation", "class" => "ErrorExplanation")
page.visual_effect :appear, 'status', :duration => 0.5
page.show 'status'
page.replace_html 'status', "#{error_messages_for('item')}"
end

View file

@ -1,11 +1,9 @@
if @saved
page.hide "warning"
page.insert_html :bottom, "list-contexts", :partial => 'context_listing', :locals => { :context_listing => @context }
page.sortable "list-contexts", get_listing_sortable_options
page.call "Form.reset", "context-form"
page.call "Form.focusFirstElement", "context-form"
else
page.hide "warning"
page.replace_html "warning", content_tag("div", content_tag("h2", "#{pluralize(@context.errors.count, "error")} prohibited this record from being saved") + content_tag("p", "There were problems with the following fields:") + content_tag("ul", @context.errors.each_full { |msg| content_tag("li", msg) }), "id" => "ErrorExplanation", "class" => "ErrorExplanation")
page.visual_effect :appear, 'warning', :duration => 0.5
page.show 'status'
page.replace_html 'status', "#{error_messages_for('context')}"
end

View file

@ -1 +1 @@
page.replace_html "status", content_tag("div", "A server error has occurred", "class" => "warning")
page.notify :error, @error_message || "An error occurred on the server.", 8.0

View file

@ -1,6 +1,4 @@
<div id="display_box">
<%= render_flash %>
<div id="list-contexts">
<%= render :partial => 'context_listing', :collection => @contexts %>
</div>
@ -13,6 +11,9 @@
<div id="context_new" class="context_new" style="display:none">
<!--[form:context]-->
<%= form_remote_tag :url => { :action => "create" }, :html=> { :id=>'context-form', :name=>'context', :class => 'inline-form' } %>
<div id="status"><%= error_messages_for('context') %></div>
<%= hidden_field( "context", "id" ) %>
<label for="context_name">Context name</label>
<br />

View file

@ -1,7 +1,4 @@
<div id="display_box">
<%= render_flash %>
<%= render :partial => "context/context", :locals => { :context => @context, :collapsible => false } %>
<% unless @done.empty? -%>
<%= render :partial => "todo/completed", :locals => { :done => @done, :collapsible => false, :append_descriptor => "in this context (last #{@user.preference.show_number_completed})" } %>

View file

@ -1,13 +1,12 @@
page.hide "status"
if @saved
page.replace_html "status", content_tag("div", "Added new next action", "class" => "confirmation")
page.visual_effect :appear, 'status', :duration => 0.5
page.notify :notice, "Added new next action", 5.0
page.replace_html "badge_count", @up_count
page.send :record, "Form.reset('todo-form-new-action');Form.focusFirstElement('todo-form-new-action')"
page.insert_html :bottom, "tickler", :partial => 'deferred/item', :object => @item
page.visual_effect :highlight, "item-#{@item.id}-container", :duration => 3
page["tickler-empty-nd"].hide
else
page.replace_html "status", content_tag("div", content_tag("h2", "#{pluralize(@item.errors.count, "error")} prohibited this record from being saved") + content_tag("p", "There were problems with the following fields:") + content_tag("ul", @item.errors.each_full { |msg| content_tag("li", msg) }), "id" => "ErrorExplanation", "class" => "ErrorExplanation")
page.visual_effect :appear, 'status', :duration => 0.5
page.show 'status'
page.replace_html 'status', "#{error_messages_for('item')}"
end

View file

@ -5,5 +5,5 @@ if @saved
page.visual_effect :appear, "tickler-empty-nd", :duration => 0.4
end
else
page["status"].replace_html content_tag("div", content_tag("h2", "#{pluralize(@item.errors.count, "error")} prohibited this record from being saved") + content_tag("p", "There were problems with the following fields:") + content_tag("ul", @item.errors.each_full { |msg| content_tag("li", msg) }), "id" => "ErrorExplanation", "class" => "ErrorExplanation")
page.notify :error, "There was an error deleting the item #{@item.description}", 8.0
end

View file

@ -1 +1 @@
page["status"].replace_html "An error occurred on the server."
page.notify :error, @error_message || "An error occurred on the server.", 8.0

View file

@ -1,7 +1,5 @@
<div id="display_box">
<%= render_flash %>
<%= render :partial => "items" %>
</div><!-- End of display_box -->

View file

@ -9,6 +9,6 @@ if @saved
page.visual_effect :highlight, "item-#{@item.id}-container", :duration => 3
end
else
page.replace_html "info", content_tag("div", content_tag("div", "#{pluralize(@item.errors.count, "error")} prohibited this record from being saved", "id" => "warning", "class" => "warning") + content_tag("p", "There were problems with the following fields:") + content_tag("ul", @item.errors.each_full { |msg| content_tag("li", msg) }))
page.visual_effect :appear, 'info', :duration => 0.5
page.show 'status'
page.replace_html 'status', "#{error_messages_for('item')}"
end

View file

@ -1,7 +1,4 @@
<div id="display_box">
<%= render_flash %>
<div id="feeds">
<div id="feedlegend">
<h3>Legend:</h3>

View file

@ -3,6 +3,8 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<%= stylesheet_link_tag "scaffold" %>
<%= javascript_include_tag :defaults %>
<title><%= @page_title -%></title>
</head>

View file

@ -53,17 +53,19 @@
<li><%= navigation_link(image_tag("feed-icon", :size => "16X16", :border => 0), {:controller => "feed", :action => "index"}, :title => "See a list of available feeds" ) %></li>
</ul>
</div>
<%= render_flash %>
</div>
<div id="content">
<div id="info"></div>
<% unless @controller_name == 'feed' or session['noexpiry'] == "on" -%>
<%= periodically_call_remote( :url => {:controller => "login", :action => "check_expiry"},
:frequency => (5*60)) %>
<% end -%>
<%= periodically_call_remote( :url => {:controller => "deferred", :action => "check_tickler"},
:frequency => (10*60)) %>
<%= @content_for_layout %>
<%= yield %>
</div>
<div id="footer">

View file

@ -1,3 +1,4 @@
<%= render_flash %>
<% if @todos.length == 0 -%>
<p>There are no uncompleted actions in this <%= @type %></p>
<% else -%>

View file

@ -1,7 +1,5 @@
if @saved
page.show "status"
page.replace_html "status", content_tag("div", "Added new next action", "class" => "confirmation")
page.visual_effect :fade, 'status', :duration => 2
page.notify :notice, "Added new next action", 5.0
page['badge_count'].replace_html @up_count
page.send :record, "Form.reset('todo-form-new-action');Form.focusFirstElement('todo-form-new-action')"
page.send :record, "Form.reset('todo-form-new-action-lightbox');Form.focusFirstElement('todo-form-new-action-lightbox')"
@ -9,7 +7,6 @@ if @saved
page.visual_effect :highlight, "item-#{@item.id}-container", :duration => 3
page.hide "p#{@item.project_id}empty-nd" # If we are adding an new action, the uncompleted actions must be > 0
else
page.hide "status"
page.replace_html "status", content_tag("div", content_tag("h2", "#{pluralize(@item.errors.count, "error")} prohibited this record from being saved") + content_tag("p", "There were problems with the following fields:") + content_tag("ul", @item.errors.each_full { |msg| content_tag("li", msg) }), "id" => "ErrorExplanation", "class" => "ErrorExplanation")
page.visual_effect :appear, 'status', :duration => 0.5
page.show 'status'
page.replace_html 'status', "#{error_messages_for('item')}"
end

View file

@ -5,7 +5,6 @@ if @saved
page.call "Form.reset", "project-form"
page.call "Form.focusFirstElement", "project-form"
else
page.hide "warning"
page.replace_html "warning", content_tag("div", content_tag("h2", "#{pluralize(@project.errors.count, "error")} prohibited this record from being saved") + content_tag("p", "There were problems with the following fields:") + content_tag("ul", @project.errors.each_full { |msg| content_tag("li", msg) }), "id" => "ErrorExplanation", "class" => "ErrorExplanation")
page.visual_effect :appear, 'warning', :duration => 0.5
page.show 'status'
page.replace_html 'status', "#{error_messages_for('project')}"
end

View file

@ -1 +1 @@
page.replace_html "status", "A server error has occurred"
page.notify :error, @error_message || "An error occurred on the server.", 8.0

View file

@ -1,6 +1,4 @@
<div id="display_box">
<%= render_flash %>
<div id="list-projects">
<%= render :partial => 'project_listing', :collection => @projects %>
</div>
@ -13,6 +11,9 @@
<!--[form:project]-->
<%= form_remote_tag :url => { :action => "create" },
:html=> { :id=>'project-form', :name=>'project', :class => 'inline-form' } %>
<div id="status"><%= error_messages_for('project') %></div>
<label for="project_name">Name:</label>
<br />
<%= text_field 'project', 'name' %>

View file

@ -1,6 +1,4 @@
<div id="display_box">
<%= render_flash %>
<%= render :partial => "project/project", :locals => { :project => @project, :collapsible => false } %>
<% unless @done.empty? -%>

View file

@ -28,8 +28,7 @@
<% end -%>
<div id="todo_new_action" class="context_new" style="display:<%= hide_link ? 'block' : 'none'%>">
<div id="status">
</div>
<!--[form:todo]-->
<% if controller.controller_name == "deferred" -%>
<%= form_remote_tag(
@ -41,6 +40,8 @@
:html=> { :id=>'todo-form-new-action', :name=>'todo', :class => 'inline-form' }) %>
<% end -%>
<div id="status"><%= error_messages_for("item") %></div>
<label for="todo_description">Description</label><br />
<%= text_field( "todo", "description", "size" => 25, "tabindex" => 1) %><br />

View file

@ -1,7 +1,11 @@
<% for flash_key in [:notice, :warning, :message] %>
<% if flash.has_key?(flash_key) %>
<div id="<%= flash_key %>"><%= flash[flash_key] %></div>
<% else%>
<div id="<%= flash_key %>" style="display:none"><%= flash[flash_key] %></div>
<% end %>
<% end %>
<div id="message_holder">
<% if flash.empty? %>
<h4 id="flash" class="alert" style="display:none"></h4>
<% else %>
<% flash.each do |key,value| -%>
<h4 id="flash" class='alert <%= key %>'>
<%= value %>
</h4>
<% end -%>
<% end %>
</div>

View file

@ -1,4 +1,4 @@
<%= error_messages_for("item") %>
<div id="error_status"><%= error_messages_for("item") %></div>
<%= hidden_field( "item", "id" ) %>
<%= source_view_tag( @source_view ) %>

View file

@ -1,7 +1,5 @@
if @saved
page.show "status"
page.replace_html "status", content_tag("div", "Added new next action", "class" => "confirmation")
page.visual_effect :fade, 'status', :duration => 2
page.notify :notice, "Added new next action", 5.0
page['badge_count'].replace_html @up_count
page.send :record, "Form.reset('todo-form-new-action');Form.focusFirstElement('todo-form-new-action')"
page.send :record, "Form.reset('todo-form-new-action-lightbox');Form.focusFirstElement('todo-form-new-action-lightbox')"
@ -10,7 +8,6 @@ if @saved
page.visual_effect :highlight, "item-#{@item.id}-container", :duration => 3
page["c#{@item.context_id}empty-nd"].hide
else
page.hide "status"
page.replace_html "status", content_tag("div", content_tag("h2", "#{pluralize(@item.errors.count, "error")} prohibited this record from being saved") + content_tag("p", "There were problems with the following fields:") + content_tag("ul", @item.errors.each_full { |msg| content_tag("li", msg) }), "id" => "ErrorExplanation", "class" => "ErrorExplanation")
page.visual_effect :appear, 'status', :duration => 0.5
page.show 'status'
page.replace_html 'status', "#{error_messages_for('item')}"
end

View file

@ -7,5 +7,5 @@ if @saved
from.project { page["p#{@item.project_id}empty-nd"].show if @down_count == 0 }
end
else
page["status"].replace_html content_tag("div", content_tag("h2", "#{pluralize(@item.errors.count, "error")} prohibited this record from being saved") + content_tag("p", "There were problems with the following fields:") + content_tag("ul", @item.errors.each_full { |msg| content_tag("li", msg) }), "id" => "ErrorExplanation", "class" => "ErrorExplanation")
page.notify :error, "There was an error deleting the item #{@item.description}", 8.0
end

View file

@ -1 +1 @@
page["status"].replace_html @error_message || "An error occurred on the server."
page.notify :error, @error_message || "An error occurred on the server.", 8.0

View file

@ -1,7 +1,5 @@
<div id="display_box">
<%= render_flash %>
<%= render :partial => "context/context", :collection => @contexts_to_show,
:locals => { :collapsible => true } %>
<% unless @done.nil? -%>

View file

@ -1,7 +1,5 @@
<div id="display_box">
<%= render_flash %>
<%= render :partial => "tickler_items" %>
</div><!-- End of display_box -->

View file

@ -32,5 +32,5 @@ if @saved
page.hide "status"
page.replace_html "badge_count", @down_count
else
page.replace_html "status", content_tag("div", content_tag("h2", "#{pluralize(@item.errors.count, "error")} prohibited this record from being saved") + content_tag("p", "There were problems with the following fields:") + content_tag("ul", @item.errors.each_full { |msg| content_tag("li", msg) }), "id" => "ErrorExplanation", "class" => "ErrorExplanation")
page.replace_html "status", content_tag("div", content_tag("h2", "#{pluralize(@item.errors.count, "error")} prohibited this record from being saved") + content_tag("p", "There were problems with the following fields:") + content_tag("ul", @item.errors.each_full { |msg| content_tag("li", msg) }), "id" => "errorExplanation", "class" => "errorExplanation")
end

View file

@ -1,4 +1,3 @@
page.hide "info"
if @saved
item_container_id = "item-#{@item.id}-container"
if source_view_is_one_of [:todo, :context]
@ -41,6 +40,6 @@ if @saved
end
else
page.replace_html "info", content_tag("div", content_tag("div", "#{pluralize(@item.errors.count, "error")} prohibited this record from being saved", "id" => "warning", "class" => "warning") + content_tag("p", "There were problems with the following fields:") + content_tag("ul", @item.errors.each_full { |msg| content_tag("li", msg) }))
page.visual_effect :appear, 'info', :duration => 0.5
page.show 'error_status'
page.replace_html 'error_status', "#{error_messages_for('item')}"
end

View file

@ -2,8 +2,6 @@
<h2>Change authentication type</h2>
<%= render_flash %>
<%= error_messages_for 'user' %>
<p>Select your new authentication type and click 'Change Authentication Type' to replace your current settings.</p>

View file

@ -2,8 +2,6 @@
<h2><%= @page_title %></h2>
<%= render_flash %>
<%= error_messages_for 'user' %>
<p>Enter your new password in the fields below and click 'Change Password' to replace your current password with your new one.</p>

View file

@ -1,7 +1,5 @@
<div id="single_box" class="container context prefscontainer">
<%= render_flash %>
<h2>Your preferences</h2>
<ul id="prefs">

View file

@ -6,9 +6,9 @@ ActiveRecord::Schema.define(:version => 20) do
create_table "contexts", :force => true do |t|
t.column "name", :string, :default => "", :null => false
t.column "hide", :integer, :limit => 4, :default => 0, :null => false
t.column "position", :integer, :default => 0, :null => false
t.column "user_id", :integer, :default => 0, :null => false
t.column "hide", :boolean, :default => false
t.column "user_id", :integer, :default => 1
end
create_table "notes", :force => true do |t|
@ -56,7 +56,7 @@ ActiveRecord::Schema.define(:version => 20) do
create_table "projects", :force => true do |t|
t.column "name", :string, :default => "", :null => false
t.column "position", :integer, :default => 0, :null => false
t.column "user_id", :integer, :default => 0, :null => false
t.column "user_id", :integer, :default => 1
t.column "description", :text
t.column "state", :string, :limit => 20, :default => "active", :null => false
end
@ -71,22 +71,22 @@ ActiveRecord::Schema.define(:version => 20) do
create_table "todos", :force => true do |t|
t.column "context_id", :integer, :default => 0, :null => false
t.column "description", :string, :limit => 100, :default => "", :null => false
t.column "project_id", :integer
t.column "description", :string, :default => "", :null => false
t.column "notes", :text
t.column "created_at", :datetime
t.column "due", :date
t.column "completed_at", :datetime
t.column "project_id", :integer
t.column "user_id", :integer, :default => 0, :null => false
t.column "user_id", :integer, :default => 1
t.column "show_from", :date
t.column "state", :string, :limit => 20, :default => "immediate", :null => false
end
create_table "users", :force => true do |t|
t.column "login", :string, :limit => 80
t.column "password", :string, :limit => 40
t.column "login", :string, :limit => 80, :default => "", :null => false
t.column "password", :string, :limit => 40, :default => "", :null => false
t.column "word", :string
t.column "is_admin", :integer, :limit => 4, :default => 0, :null => false
t.column "is_admin", :boolean, :default => false, :null => false
t.column "first_name", :string
t.column "last_name", :string
t.column "auth_type", :string, :default => "database", :null => false

View file

@ -14,6 +14,14 @@ Ajax.Responders.register({
// }
});
/* fade flashes automatically */
Event.observe(window, 'load', function() {
$A(document.getElementsByClassName('alert')).each(function(o) {
o.opacity = 100.0
Effect.Fade(o, {duration: 8.0})
});
});
/**
* Provides a simple interface for creating, retrieving and clearing cookies.
* Adapted from Jonathan Buchanan's code at http://insin.woaf.net/code/javascript/cookiemanager.html

View file

@ -60,7 +60,32 @@ div.memo {
background: #ff9;
}
#notice {
/* Flash box styling */
h4.alert {
font-size: 0.8em;
font-weight:bold;
margin:0;
padding:5px;
text-align: center;
}
h4.warning {
border: 1px solid #ED2E38;
background-color: #F6979C;
color: #000000;
}
h4.error {
color:#fff;
background:#c00;
}
h4.notice {
border: 1px solid #007E00;
background-color: #c2ffc2;
color: #007E00;
}
/*#notice {
padding: 2px;
border: 1px solid #007E00;
background-color: #c2ffc2;
@ -68,6 +93,7 @@ div.memo {
margin-bottom: 15px;
text-align: center;
}
*/
#footer {
clear: both;
@ -79,23 +105,6 @@ div.memo {
padding: 0px;
}
#warning {
padding: 2px;
border: 1px solid #ED2E38;
background-color: #F6979C;
color: #000000;
margin: 15px 5px;
text-align: center;
}
#message {
padding: 2px;
border: 1px solid #CCC;
background-color: #D2D3D6;
color: #666;
margin: 15px 5px;
text-align: center;
}
/* Error message styles */
.fieldWithErrors {
@ -105,7 +114,6 @@ div.memo {
}
#errorExplanation {
width: 335px;
border: 2px solid #ff0000;
padding: 7px;
padding-bottom: 12px;
@ -131,8 +139,10 @@ div.memo {
#errorExplanation ul li {
font-size: 1em;
list-style: disc;
list-style-type: disc;
list-style-position: outside;
}
input.login_text {
width:200px;
}

View file

@ -143,7 +143,7 @@ a.show_notes:hover {background-image: url(../images/notes_on.png); background-re
text-align: right;
position: fixed;
right: 15px;
top: 20px;
top: 10px;
font-size: 0.9em;
}
@ -306,46 +306,41 @@ div#project_status > div {
}
a.footer_link {color: #cc3334; font-style: normal;}
a.footer_link:hover {color: #fff; background-color: #cc3334 !important;}
/* The alert box notifications */
#notice {
padding: 2px;
/* Flash box styling */
div#message_holder {
position: absolute;
z-index: 100;
left: 60%;
top: 30px;
right: 0px;
margin: 0px;
}
h4.alert {
font-size: 1em;
margin: 0px;
padding: 5px;
text-align: center;
}
h4.warning {
border: 1px solid #ED2E38;
background-color: #F6979C;
color: #000;
}
h4.error {
color:#fff;
background:#c00;
}
h4.notice {
border: 1px solid #007E00;
background-color: #c2ffc2;
color: #007E00;
margin: 15px 5px;
text-align: center;
}
.confirmation {
border: 1px solid #007E00;
background-color: #c2ffc2;
color: #007E00;
text-align: center;
}
#status .confirmation {
margin: 2px 5px;
}
#warning, .warning {
padding: 2px;
border: 1px solid #ED2E38;
background-color: #F6979C;
color: #000000;
margin: 15px 5px;
text-align: center;
}
#message, .message {
padding: 2px;
border: 1px solid #CCC;
background-color: #D2D3D6;
color: #666;
margin: 15px 5px;
text-align: center;
}
.warning p {color: #FFFFFF;}
/* *****/
.project_completed {
border: 1px solid #007E00;
@ -613,7 +608,6 @@ div.message {
}
#errorExplanation {
width: 335px;
border: 2px solid #ff0000;
padding: 7px;
padding-bottom: 12px;
@ -639,7 +633,8 @@ div.message {
#errorExplanation ul li {
font-size: 1em;
list-style: disc;
list-style-type: disc;
list-style-position: inside;
}
ul#prefs {list-style-type: disc; margin-left: 5px;}
@ -688,7 +683,7 @@ ul#prefs {list-style-type: disc; margin-left: 5px;}
}
#feeds li {
font-size:13px;
font-family: "Lucida Grande", Verdana, Geneva, Arial, sans-serif;
font-family: "Lucida Grande", Verdana, Geneva, Arial, sans-serif;
}
#feeds li h4 {
margin-top: 12px;

View file

@ -23,7 +23,6 @@ class ContextControllerTest < TodoContainerControllerTestBase
def test_create_context_with_ajax_success_rjs
ajax_create '@newcontext'
assert_rjs :hide, "warning"
assert_rjs :insert_html, :bottom, "list-contexts"
assert_rjs :sortable, 'list-contexts', { :tag => 'div', :handle => 'handle', :complete => visual_effect(:highlight, 'list-contexts'), :url => {:controller => 'context', :action => 'order'} }
# not yet sure how to write the following properly...
@ -37,9 +36,8 @@ class ContextControllerTest < TodoContainerControllerTestBase
def test_create_with_slash_in_name_fails_with_rjs
ajax_create 'foo/bar'
assert_rjs :hide, "warning"
assert_rjs :replace_html, 'warning', "<div class=\"ErrorExplanation\" id=\"ErrorExplanation\"><h2>1 error prohibited this record from being saved</h2><p>There were problems with the following fields:</p><ul>Name cannot contain the slash ('/') character</ul></div>"
assert_rjs :visual_effect, :appear, "warning", :duration => '0.5'
assert_rjs :show, 'status'
assert_rjs :update, 'status', "<div class=\"ErrorExplanation\" id=\"ErrorExplanation\"><h2>1 error prohibited this record from being saved</h2><p>There were problems with the following fields:</p><ul>Name cannot contain the slash ('/') character</ul></div>"
end
end

View file

@ -21,10 +21,10 @@ class MobileControllerTest < Test::Unit::TestCase
def test_create_item
@count = Todo.find(:all)
@request.session['user_id'] = users(:admin_user).id
xhr :post, :update, :_source_view => 'todo', "item"=>{"context_id"=>"1", "project_id"=>"2", "notes"=>"", "description"=>"Invest in spam stock offer", "due"=>"01/01/2007"}
xhr :post, :update, "item"=>{"context_id"=>"1", "project_id"=>"2", "notes"=>"", "description"=>"Invest in spam stock offer", "due"=>"01/01/2007", "show_from"=>"", "state"=>"0"}
@todos = Todo.find(:all)
assert_equal @count.size+1, @todos.size
t = Todo.find(15)
t = Todo.find(:first, :conditions => ['description = ?', "Invest in spam stock offer"])
assert_equal "Invest in spam stock offer", t.description
assert_equal Date.parse("01/01/2007"), t.due
assert_equal users(:admin_user).id, t.user_id

View file

@ -23,7 +23,6 @@ class ProjectControllerTest < TodoContainerControllerTestBase
def test_create_project_with_ajax_success_rjs
ajax_create 'My New Project'
assert_rjs :hide, "warning"
assert_rjs :insert_html, :bottom, "list-projects"
assert_rjs :sortable, 'list-projects', { :tag => 'div', :handle => 'handle', :complete => visual_effect(:highlight, 'list-projects'), :url => {:controller => 'project', :action => 'order'} }
# not yet sure how to write the following properly...
@ -37,9 +36,8 @@ class ProjectControllerTest < TodoContainerControllerTestBase
def test_create_with_slash_in_name_fails_with_rjs
ajax_create 'foo/bar'
assert_rjs :hide, "warning"
assert_rjs :replace_html, 'warning', "<div class=\"ErrorExplanation\" id=\"ErrorExplanation\"><h2>1 error prohibited this record from being saved</h2><p>There were problems with the following fields:</p><ul>Name cannot contain the slash ('/') character</ul></div>"
assert_rjs :visual_effect, :appear, "warning", :duration => '0.5'
assert_rjs :show, 'status'
assert_rjs :update, 'status', "<div class=\"ErrorExplanation\" id=\"ErrorExplanation\"><h2>1 error prohibited this record from being saved</h2><p>There were problems with the following fields:</p><ul>Name cannot contain the slash ('/') character</ul></div>"
end
def test_todo_state_is_project_hidden_after_hiding_project