mirror of
https://github.com/TracksApp/tracks.git
synced 2025-09-22 05:50:47 +02:00
refactor application.rb further and migrate recurring todos
next: get tests for recurring todos
This commit is contained in:
parent
484356fe07
commit
cafa774b4c
33 changed files with 688 additions and 571 deletions
|
@ -1,72 +1,72 @@
|
|||
class NotesController < ApplicationController
|
||||
|
||||
before_filter :set_source_view
|
||||
|
||||
def index
|
||||
@all_notes = current_user.notes.all
|
||||
@count = @all_notes.size
|
||||
@page_title = "TRACKS::All notes"
|
||||
@source_view = 'note_list'
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.xml { render :xml => @all_notes.to_xml( :except => :user_id ) }
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
@note = current_user.notes.find(params['id'])
|
||||
@page_title = "TRACKS::Note " + @note.id.to_s
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.m { render :action => 'note_mobile' }
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
@note = current_user.notes.build
|
||||
@note.attributes = params["note"]
|
||||
|
||||
@saved = @note.save
|
||||
|
||||
respond_to do |format|
|
||||
format.js
|
||||
format.xml do
|
||||
if @saved
|
||||
head :created, :location => note_url(@note), :text => "new note with id #{@note.id}"
|
||||
else
|
||||
render_failure @note.errors.full_messages.join(', ')
|
||||
end
|
||||
end
|
||||
format.html do
|
||||
render :text => 'unexpected request for html rendering'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
@note = current_user.notes.find(params['id'])
|
||||
@note.attributes = params["note"]
|
||||
@saved = @note.save
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.js
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@note = current_user.notes.find(params['id'])
|
||||
@note.destroy
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.js { @down_count = current_user.notes.size }
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def set_source_view
|
||||
@source_view = params['_source_view'] || 'note'
|
||||
end
|
||||
|
||||
end
|
||||
class NotesController < ApplicationController
|
||||
|
||||
before_filter :set_source_view
|
||||
|
||||
def index
|
||||
@all_notes = current_user.notes.all
|
||||
@count = @all_notes.size
|
||||
@page_title = "TRACKS::All notes"
|
||||
@source_view = 'note_list'
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.xml { render :xml => @all_notes.to_xml( :except => :user_id ) }
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
@note = current_user.notes.find(params['id'])
|
||||
@page_title = "TRACKS::Note " + @note.id.to_s
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.m { render :action => 'note_mobile' }
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
@note = current_user.notes.build
|
||||
@note.attributes = params["note"]
|
||||
|
||||
@saved = @note.save
|
||||
|
||||
respond_to do |format|
|
||||
format.js
|
||||
format.xml do
|
||||
if @saved
|
||||
head :created, :location => note_url(@note), :text => "new note with id #{@note.id}"
|
||||
else
|
||||
render_failure @note.errors.full_messages.join(', ')
|
||||
end
|
||||
end
|
||||
format.html do
|
||||
render :text => 'unexpected request for html rendering'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
@note = current_user.notes.find(params['id'])
|
||||
@note.attributes = params["note"]
|
||||
@saved = @note.save
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.js
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@note = current_user.notes.find(params['id'])
|
||||
@note.destroy
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.js { @down_count = current_user.notes.size }
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def set_source_view
|
||||
@source_view = params['_source_view'] || 'note'
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -6,15 +6,17 @@ class RecurringTodosController < ApplicationController
|
|||
append_before_filter :get_recurring_todo_from_param, :only => [:destroy, :toggle_check, :toggle_star, :edit, :update]
|
||||
|
||||
def index
|
||||
find_and_inactivate
|
||||
@page_title = t('todos.recurring_actions_title')
|
||||
|
||||
find_and_inactivate
|
||||
@recurring_todos = current_user.recurring_todos.active
|
||||
@completed_recurring_todos = current_user.recurring_todos.completed
|
||||
|
||||
@no_recurring_todos = @recurring_todos.size == 0
|
||||
@no_completed_recurring_todos = @completed_recurring_todos.size == 0
|
||||
@count = @recurring_todos.size
|
||||
|
||||
@page_title = t('todos.recurring_actions_title')
|
||||
@count = @recurring_todos.size
|
||||
|
||||
@new_recurring_todo = RecurringTodo.new
|
||||
end
|
||||
|
||||
def new
|
||||
|
@ -103,13 +105,13 @@ class RecurringTodosController < ApplicationController
|
|||
@recurring_todo.context_id = context.id
|
||||
end
|
||||
|
||||
@recurring_saved = @recurring_todo.save
|
||||
unless (@recurring_saved == false) || p.tag_list.blank?
|
||||
@saved = @recurring_todo.save
|
||||
unless (@saved == false) || p.tag_list.blank?
|
||||
@recurring_todo.tag_with(p.tag_list)
|
||||
@recurring_todo.tags.reload
|
||||
end
|
||||
|
||||
if @recurring_saved
|
||||
if @saved
|
||||
@message = "The recurring todo was saved"
|
||||
@todo_saved = create_todo_from_recurring_todo(@recurring_todo).nil? == false
|
||||
if @todo_saved
|
||||
|
@ -117,7 +119,8 @@ class RecurringTodosController < ApplicationController
|
|||
else
|
||||
@message += " / did not create todo"
|
||||
end
|
||||
@count = current_user.recurring_todos.active.count
|
||||
@down_count = current_user.recurring_todos.active.count
|
||||
@new_recurring_todo = RecurringTodo.new
|
||||
else
|
||||
@message = "Error saving recurring todo"
|
||||
end
|
||||
|
@ -139,7 +142,10 @@ class RecurringTodosController < ApplicationController
|
|||
|
||||
# delete the recurring todo
|
||||
@saved = @recurring_todo.destroy
|
||||
@remaining = current_user.recurring_todos.count
|
||||
|
||||
# count remaining recurring todos
|
||||
@active_remaining = current_user.recurring_todos.active.count
|
||||
@completed_remaining = current_user.recurring_todos.completed.count
|
||||
|
||||
respond_to do |format|
|
||||
|
||||
|
@ -162,11 +168,12 @@ class RecurringTodosController < ApplicationController
|
|||
def toggle_check
|
||||
@saved = @recurring_todo.toggle_completion!
|
||||
|
||||
@count = current_user.recurring_todos.active.count
|
||||
@remaining = @count
|
||||
@down_count = current_user.recurring_todos.active.count
|
||||
@active_remaining = @down_count
|
||||
@completed_remaining = 0
|
||||
|
||||
if @recurring_todo.active?
|
||||
@remaining = current_user.recurring_todos.completed.count
|
||||
@completed_remaining = current_user.recurring_todos.completed.count
|
||||
|
||||
# from completed back to active -> check if there is an active todo
|
||||
# current_user.todos.count(:all, {:conditions => ["state = ? AND recurring_todo_id = ?", 'active',params[:id]]})
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module SearchHelper
|
||||
|
||||
end
|
||||
module SearchHelper
|
||||
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<% if @saved -%>
|
||||
hide_empty_message();
|
||||
TracksPages.hide_errors();
|
||||
set_page_badge(<%= @down_count %>);
|
||||
TracksPages.set_page_badge(<%= @down_count %>);
|
||||
add_context("<%=@context.hidden? ? 'hidden' : 'active'%>");
|
||||
clear_form();
|
||||
<% else -%>
|
||||
|
|
|
@ -3,13 +3,12 @@ remove_deleted_context();
|
|||
ContextListPage.update_all_states_count(<%=@active_contexts_count%>, <%=@hidden_contexts_count%>)
|
||||
ContextListPage.show_or_hide_all_state_containers(<%= @show_active_contexts %>, <%= @show_hidden_contexts %>);
|
||||
|
||||
set_page_badge(<%=@down_count%>);
|
||||
page_notify('notice', "<%= t('contexts.context_deleted', :name=>@context.name)%>", 5);
|
||||
|
||||
TracksPages.set_page_badge(<%=@down_count%>);
|
||||
TracksPages.page_notify('notice', "<%= t('contexts.context_deleted', :name=>@context.name)%>", 5);
|
||||
|
||||
/* TODO: refactor and move function to application.js */
|
||||
function remove_deleted_context() {
|
||||
$('div#<%=dom_id(@context, "container")%>').slideUp(1000,
|
||||
function() {
|
||||
$('div#<%=dom_id(@context, "container")%>').slideUp(1000, function() {
|
||||
$('div#<%=dom_id(@context, "container")%>').remove();
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
<% if @saved -%>
|
||||
|
||||
page_notify('notice', '<%= t('contexts.save_status_message') %>', 5);
|
||||
TracksPages.page_notify('notice', '<%= t('contexts.save_status_message') %>', 5);
|
||||
|
||||
<% if @state_changed -%>
|
||||
remove_and_re_add_context();
|
||||
|
@ -9,7 +9,7 @@
|
|||
<% end -%>
|
||||
|
||||
<% else -%>
|
||||
show_errors();
|
||||
TracksPages.show_edit_errors(html_for_error_messages());
|
||||
<% end -%>
|
||||
|
||||
function remove_and_re_add_context() {
|
||||
|
@ -33,11 +33,6 @@ function replace_context_form_with_updated_context() {
|
|||
});
|
||||
}
|
||||
|
||||
function show_errors() {
|
||||
$('div#edit_error_status').html(html_for_error_messages());
|
||||
$('div#edit_error_status').show();
|
||||
}
|
||||
|
||||
function html_for_error_messages() {
|
||||
return "<%= escape_javascript(error_messages_for('context')) %>";
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
<% if @session_expired
|
||||
theHtml = escape_javascript(content_tag(
|
||||
:div,
|
||||
t('login.session_time_out', :link => link_to(t('login.log_in_again'), :controller => "login", :action => "login")),
|
||||
:"class" => "warning"))
|
||||
logger.debug("theHtml='#{theHtml}'")
|
||||
theLink = link_to(t('login.log_in_again'), :controller => "login", :action => "login")
|
||||
message = I18n.t('login.session_time_out', :link => theLink)
|
||||
theHtml = escape_javascript(content_tag(:div, message, :"class" => "warning"))
|
||||
-%>
|
||||
$('div#navcontainer').hide();
|
||||
$('div#content').html('<%=theHtml%>');
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
remove_deleted_note();
|
||||
set_page_badge(<%=@down_count%>);
|
||||
page_notify('notice', "<%= t('notes.deleted_note', :id => @note.id)%>", 5);
|
||||
TracksPages.set_page_badge(<%=@down_count%>);
|
||||
TracksPages.page_notify('notice', "<%= t('notes.deleted_note', :id => @note.id)%>", 5);
|
||||
|
||||
function remove_deleted_note() {
|
||||
$('div#note-<%=@note.id%>-wrapper').slideUp(1000,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<% if @saved -%>
|
||||
|
||||
TracksPages.hide_errors();
|
||||
page_notify('notice', 'Note <%=@note.id %> saved', 5);
|
||||
TracksPages.page_notify('notice', 'Note <%=@note.id %> saved', 5);
|
||||
replace_note_form_with_updated_note();
|
||||
|
||||
<% else -%>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<% else -%>
|
||||
TracksPages.hide_errors();
|
||||
hide_empty_message();
|
||||
set_page_badge(<%= @down_count %>);
|
||||
TracksPages.set_page_badge(<%= @down_count %>);
|
||||
update_active_projects_container();
|
||||
add_project();
|
||||
clear_form();
|
||||
|
@ -13,19 +13,23 @@
|
|||
TracksPages.show_errors(html_for_error_messages());
|
||||
<% end -%>
|
||||
|
||||
/* TODO: make this generic for all pages with lists */
|
||||
function hide_empty_message() {
|
||||
$('projects-empty-nd').hide();
|
||||
}
|
||||
|
||||
/* TODO: refactor and move this to application.js */
|
||||
function add_project() {
|
||||
$('#list-active-projects').append(html_for_project_listing());
|
||||
}
|
||||
|
||||
/* TODO: refactor and move this to application.js */
|
||||
function clear_form() {
|
||||
$('#project_form').clearForm();
|
||||
$('#project_form input:text:first').focus();
|
||||
}
|
||||
|
||||
/* TODO: refactor and move this to application.js */
|
||||
function update_active_projects_container() {
|
||||
ProjectListPage.set_state_container_visibility('active', true);
|
||||
ProjectListPage.update_state_count('active', <%=@active_projects_count%>);
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
remove_deleted_project();
|
||||
ProjectListPage.update_all_states_count(<%=@active_projects_count%>, <%=@hidden_projects_count%>, <%=@completed_projects_count%>)
|
||||
ProjectListPage.show_or_hide_all_state_containers(<%= @show_active_projects %>, <%= @show_hidden_projects %>, <%= @show_completed_projects %>);
|
||||
page_notify('notice', "Deleted project '<%= @project.name%>'", 5);
|
||||
set_page_badge(<%=@down_count%>);
|
||||
TracksPages.page_notify('notice', "Deleted project '<%= @project.name%>'", 5);
|
||||
TracksPages.set_page_badge(<%=@down_count%>);
|
||||
|
||||
/* TODO: refactor and move function to application.js */
|
||||
function remove_deleted_project() {
|
||||
$('div#<%=dom_id(@project, "container")%>').slideUp(1000,
|
||||
function() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<% if @saved -%>
|
||||
|
||||
page_notify('notice', '<%=t('projects.project_saved_status')%>', 5);
|
||||
TracksPages.page_notify('notice', '<%=t('projects.project_saved_status')%>', 5);
|
||||
|
||||
<% if source_view_is :project_list -%>
|
||||
|
||||
|
@ -27,23 +27,16 @@
|
|||
TracksForm.set_tag_list("<%= escape_javascript(@project.default_tags)%>");
|
||||
<% end %>
|
||||
|
||||
update_sidebar();
|
||||
TracksPages.update_sidebar(html_for_sidebar());
|
||||
|
||||
<% end %>
|
||||
|
||||
TracksForm.set_project_name_and_default_project_name("<%= escape_javascript(@project.name)%>");
|
||||
|
||||
<% else -%>
|
||||
show_errors();
|
||||
TracksPages.show_edit_errors(html_for_error_messages());
|
||||
<% end %>
|
||||
|
||||
enable_rich_interaction();
|
||||
|
||||
function show_errors() {
|
||||
$('div#edit_error_status').html(html_for_error_messages());
|
||||
$('div#edit_error_status').show();
|
||||
}
|
||||
|
||||
function remove_project_edit_form() {
|
||||
$('#<%=dom_id(@project, 'edit')%>').hide(500, function() {$('#<%=dom_id(@project, 'edit')%>').remove();} );
|
||||
}
|
||||
|
@ -53,10 +46,6 @@ function update_and_show_project_settings() {
|
|||
$('#<%=dom_id(@project)%>').show();
|
||||
}
|
||||
|
||||
function update_sidebar() {
|
||||
$('#sidebar').html(html_for_sidebar());
|
||||
}
|
||||
|
||||
function replace_project_form_with_updated_project() {
|
||||
$('#<%=dom_id(@project, 'container')%>').fadeOut(250, function() {
|
||||
<%
|
||||
|
@ -97,4 +86,4 @@ function html_for_project_settings() {
|
|||
|
||||
function html_for_error_messages() {
|
||||
return "<%= escape_javascript(error_messages_for('project')) %>";
|
||||
}
|
||||
}
|
|
@ -1,113 +1,113 @@
|
|||
<label>Edit Recurring Todo</label><br/>
|
||||
<div class="recurring_container">
|
||||
<% form_remote_tag(
|
||||
:url => recurring_todo_path(@recurring_todo), :method => :put,
|
||||
:html=> { :id=>'recurring-todo-form-edit-action', :name=>'recurring_todo', :class => 'inline-form' },
|
||||
:before => "$('#recurring_todo_edit_action_submit').block({message: null})",
|
||||
:complete => "$('#recurring_todo_edit_action_submit').unblock();$('#recurring-todo-form-edit-action').clearForm();") do
|
||||
|
||||
-%>
|
||||
<div id="edit_status"><%= error_messages_for("item", :object_name => 'action') %></div>
|
||||
|
||||
<div id="recurring_todo_form_container">
|
||||
<div id="recurring_todo">
|
||||
<label for="recurring_todo_description">Description</label><%=
|
||||
text_field_tag( "recurring_todo[description]", @recurring_todo.description, "size" => 30, "tabindex" => 1, "maxlength" => 100) -%>
|
||||
|
||||
<label for="recurring_todo_notes">Notes</label><%=
|
||||
text_area_tag( "recurring_todo[notes]", @recurring_todo.notes, {:cols => 29, :rows => 6, :tabindex => 2}) -%>
|
||||
|
||||
<label for="edit_recurring_todo_project_name">Project</label>
|
||||
<input id="edit_recurring_todo_project_name" name="project_name" autocomplete="off" tabindex="3" size="30" type="text" value="<%= @recurring_todo.project.nil? ? 'None' : @recurring_todo.project.name.gsub(/"/,""") %>" />
|
||||
<div class="page_name_auto_complete" id="edit_project_list" style="display:none"></div>
|
||||
<% #form_remote_tag(
|
||||
#url => recurring_todo_path(@recurring_todo), :method => :put,
|
||||
#:html=> { :id=>'recurring-todo-form-edit-action', :name=>'recurring_todo', :class => 'inline-form' },
|
||||
#:before => "$('#recurring_todo_edit_action_submit').block({message: null})",
|
||||
#:complete => "$('#recurring_todo_edit_action_submit').unblock();$('#recurring-todo-form-edit-action').clearForm();") do
|
||||
form_for(@recurring_todo, :html=> { :id=>'recurring-todo-form-edit-action', :name=>'recurring_todo', :class => 'inline-form' }) do |f|
|
||||
-%>
|
||||
<div id="edit_error_status"><%= error_messages_for("item", :object_name => 'action') %></div>
|
||||
|
||||
<label for="edit_recurring_todo_context_name">Context</label>
|
||||
<input id="edit_recurring_todo_context_name" name="context_name" autocomplete="off" tabindex="4" size="30" type="text" value="<%= @recurring_todo.context.name %>" />
|
||||
<div class="page_name_auto_complete" id="edit_context_list" style="display:none"></div>
|
||||
|
||||
<label for="edit_recurring_todo_tag_list">Tags (separate with commas)</label>
|
||||
<%= text_field_tag "edit_recurring_todo_tag_list", @recurring_todo.tag_list, :size => 30, :tabindex => 5 -%>
|
||||
</div>
|
||||
<div id="recurring_todo_form_container">
|
||||
<div id="recurring_todo">
|
||||
<label for="recurring_todo_description">Description</label><%=
|
||||
text_field_tag( "recurring_todo[description]", @recurring_todo.description, "size" => 30, "tabindex" => 1, "maxlength" => 100) -%>
|
||||
|
||||
<label for="recurring_todo_notes">Notes</label><%=
|
||||
text_area_tag( "recurring_todo[notes]", @recurring_todo.notes, {:cols => 29, :rows => 6, :tabindex => 2}) -%>
|
||||
|
||||
<label for="edit_recurring_todo_project_name">Project</label>
|
||||
<input id="edit_recurring_todo_project_name" name="project_name" autocomplete="off" tabindex="3" size="30" type="text" value="<%= @recurring_todo.project.nil? ? 'None' : @recurring_todo.project.name.gsub(/"/,""") %>" />
|
||||
<div class="page_name_auto_complete" id="edit_project_list" style="display:none"></div>
|
||||
|
||||
<label for="edit_recurring_todo_context_name">Context</label>
|
||||
<input id="edit_recurring_todo_context_name" name="context_name" autocomplete="off" tabindex="4" size="30" type="text" value="<%= @recurring_todo.context.name %>" />
|
||||
<div class="page_name_auto_complete" id="edit_context_list" style="display:none"></div>
|
||||
|
||||
<label for="edit_recurring_todo_tag_list">Tags (separate with commas)</label>
|
||||
<%= text_field_tag "edit_recurring_todo_tag_list", @recurring_todo.tag_list, :size => 30, :tabindex => 5 -%>
|
||||
</div>
|
||||
<div id="recurring_edit_period_id">
|
||||
<div id="recurring_edit_period">
|
||||
<label>Recurrence period</label><br/>
|
||||
<%= radio_button_tag('recurring_edit_todo[recurring_period]', 'daily', @recurring_todo.recurring_period == 'daily')%> Daily<br/>
|
||||
<%= radio_button_tag('recurring_edit_todo[recurring_period]', 'weekly', @recurring_todo.recurring_period == 'weekly')%> Weekly<br/>
|
||||
<%= radio_button_tag('recurring_edit_todo[recurring_period]', 'monthly', @recurring_todo.recurring_period == 'monthly')%> Monthly<br/>
|
||||
<%= radio_button_tag('recurring_edit_todo[recurring_period]', 'yearly', @recurring_todo.recurring_period == 'yearly')%> Yearly<br/>
|
||||
<% #behaviour is set in index because behaviours in partials are not generated -%>
|
||||
</div>
|
||||
<div id="recurring_timespan">
|
||||
<br/>
|
||||
<label for="recurring_todo[start_from]">Starts on </label><%=
|
||||
text_field_tag("recurring_todo_edit_start_from", format_date(@recurring_todo.start_from), "size" => 12, "class" => "Date", "tabindex" => 6, "autocomplete" => "off") %><br/>
|
||||
<br/>
|
||||
<label for="recurring_todo[ends_on]">Ends on:</label><br/>
|
||||
<%= radio_button_tag('recurring_todo[ends_on]', 'no_end_date', @recurring_todo.ends_on == 'no_end_date')%> No end date<br/>
|
||||
<%= radio_button_tag('recurring_todo[ends_on]', 'ends_on_number_of_times', @recurring_todo.ends_on == 'ends_on_number_of_times')%> Ends after <%= text_field_tag("recurring_todo[number_of_occurences]", @recurring_todo.number_of_occurences, "size" => 3, "tabindex" => 7) %> times<br/>
|
||||
<%= radio_button_tag('recurring_todo[ends_on]', 'ends_on_end_date', @recurring_todo.ends_on == 'ends_on_end_date')%> Ends on <%=
|
||||
text_field_tag('recurring_todo_edit_end_date', format_date(@recurring_todo.end_date), "size" => 12, "class" => "Date", "tabindex" => 8, "autocomplete" => "off") %><br/>
|
||||
</div></div>
|
||||
<div id="recurring_edit_daily" style="display:<%= @recurring_todo.recurring_period == 'daily' ? 'block' : 'none' %> ">
|
||||
<label>Settings for daily recurring actions</label><br/>
|
||||
<%= radio_button_tag('recurring_todo[daily_selector]', 'daily_every_x_day', !@recurring_todo.only_work_days)%> Every <%=
|
||||
text_field_tag( 'recurring_todo[daily_every_x_days]', @recurring_todo.daily_every_x_days, {"size" => 3, "tabindex" => 9}) %> day(s)<br/>
|
||||
<%= radio_button_tag('recurring_todo[daily_selector]', 'daily_every_work_day', @recurring_todo.only_work_days)%> Every work day<br/>
|
||||
</div>
|
||||
<div id="recurring_edit_period_id">
|
||||
<div id="recurring_edit_period">
|
||||
<label>Recurrence period</label><br/>
|
||||
<%= radio_button_tag('recurring_edit_todo[recurring_period]', 'daily', @recurring_todo.recurring_period == 'daily')%> Daily<br/>
|
||||
<%= radio_button_tag('recurring_edit_todo[recurring_period]', 'weekly', @recurring_todo.recurring_period == 'weekly')%> Weekly<br/>
|
||||
<%= radio_button_tag('recurring_edit_todo[recurring_period]', 'monthly', @recurring_todo.recurring_period == 'monthly')%> Monthly<br/>
|
||||
<%= radio_button_tag('recurring_edit_todo[recurring_period]', 'yearly', @recurring_todo.recurring_period == 'yearly')%> Yearly<br/>
|
||||
<% #behaviour is set in index because behaviours in partials are not generated -%>
|
||||
</div>
|
||||
<div id="recurring_edit_weekly" style="display:<%= @recurring_todo.recurring_period == 'weekly' ? 'block' : 'none' %>">
|
||||
<label>Settings for weekly recurring actions</label><br/>
|
||||
Returns every <%= text_field_tag('recurring_todo[weekly_every_x_week]', @recurring_todo.weekly_every_x_week, {"size" => 3, "tabindex" => 9}) %> week on<br/>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_monday]', 'm', @recurring_todo.on_monday ) %> Monday
|
||||
<%= check_box_tag('recurring_todo[weekly_return_tuesday]', 't', @recurring_todo.on_tuesday) %> Tuesday
|
||||
<%= check_box_tag('recurring_todo[weekly_return_wednesday]', 'w', @recurring_todo.on_wednesday) %> Wednesday
|
||||
<%= check_box_tag('recurring_todo[weekly_return_thursday]', 't', @recurring_todo.on_thursday) %> Thursday<br/>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_friday]', 'f', @recurring_todo.on_friday) %> Friday
|
||||
<%= check_box_tag('recurring_todo[weekly_return_saturday]', 's', @recurring_todo.on_saturday) %> Saturday
|
||||
<%= check_box_tag('recurring_todo[weekly_return_sunday]', 's', @recurring_todo.on_sunday) %> Sunday<br/>
|
||||
</div>
|
||||
<div id="recurring_edit_monthly" style="display:<%= @recurring_todo.recurring_period == 'monthly' ? 'block' : 'none' %>">
|
||||
<label>Settings for monthly recurring actions</label><br/>
|
||||
<%= radio_button_tag('recurring_todo[monthly_selector]', 'monthly_every_x_day', @recurring_todo.is_monthly_every_x_day || @recurring_todo.recurring_period == 'weekly')%> Day <%=
|
||||
text_field_tag('recurring_todo[monthly_every_x_day]', @recurring_todo.monthly_every_x_day, {"size" => 3, "tabindex" => 9}) %> on every <%=
|
||||
text_field_tag('recurring_todo[monthly_every_x_month]', @recurring_todo.monthly_every_x_month, {"size" => 3, "tabindex" => 10}) %> month<br/>
|
||||
<%= radio_button_tag('recurring_todo[monthly_selector]', 'monthly_every_xth_day', @recurring_todo.is_monthly_every_xth_day)%> The <%=
|
||||
select_tag('recurring_todo[monthly_every_xth_day]', options_for_select(@xth_day, @xth_day[@recurring_todo.monthly_every_xth_day(1)-1][1])) %> <%=
|
||||
select_tag('recurring_todo[monthly_day_of_week]' , options_for_select(@days_of_week, @recurring_todo.monthly_day_of_week), {}) %> of every <%=
|
||||
text_field_tag('recurring_todo[monthly_every_x_month2]', @recurring_todo.monthly_every_x_month2, {"size" => 3, "tabindex" => 11}) %> month<br/>
|
||||
</div>
|
||||
<div id="recurring_edit_yearly" style="display:<%= @recurring_todo.recurring_period == 'yearly' ? 'block' : 'none' %>">
|
||||
<label>Settings for yearly recurring actions</label><br/>
|
||||
<%= radio_button_tag('recurring_todo[yearly_selector]', 'yearly_every_x_day', @recurring_todo.recurrence_selector == 0)%> Every <%=
|
||||
select_tag('recurring_todo[yearly_month_of_year]', options_for_select(@months_of_year, @recurring_todo.yearly_month_of_year), {}) %> <%=
|
||||
text_field_tag('recurring_todo[yearly_every_x_day]', @recurring_todo.yearly_every_x_day, "size" => 3, "tabindex" => 9) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[yearly_selector]', 'yearly_every_xth_day', @recurring_todo.recurrence_selector == 1)%> The <%=
|
||||
select_tag('recurring_todo[yearly_every_xth_day]', options_for_select(@xth_day, @recurring_todo.yearly_every_xth_day), {}) %> <%=
|
||||
select_tag('recurring_todo[yearly_day_of_week]', options_for_select(@days_of_week, @recurring_todo.yearly_day_of_week), {}) %> of <%=
|
||||
select_tag('recurring_todo[yearly_month_of_year2]', options_for_select(@months_of_year, @recurring_todo.yearly_month_of_year2), {}) %><br/>
|
||||
</div>
|
||||
<div id="recurring_target">
|
||||
<label>Set recurrence on</label><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_target]', 'due_date', @recurring_todo.target == 'due_date')%> the date that the todo is due. Show the todo:
|
||||
<%= radio_button_tag('recurring_todo[recurring_show_always]', '1', @recurring_todo.show_always?)%> always
|
||||
<%= radio_button_tag('recurring_todo[recurring_show_always]', '0', !@recurring_todo.show_always?)%>
|
||||
<%= text_field_tag( 'recurring_todo[recurring_show_days_before]', @recurring_todo.show_from_delta, {"size" => 3, "tabindex" => 12}) %>
|
||||
days before the todo is due
|
||||
<br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_target]', 'show_from_date', @recurring_todo.target == 'show_from_date')%> the date todo comes from tickler (no due date set)<br/>
|
||||
<div id="recurring_timespan">
|
||||
<br/>
|
||||
<label for="recurring_todo[start_from]">Starts on </label><%=
|
||||
text_field_tag("recurring_todo_edit_start_from", format_date(@recurring_todo.start_from), "size" => 12, "class" => "Date", "tabindex" => 6, "autocomplete" => "off") %><br/>
|
||||
<br/>
|
||||
<label for="recurring_todo[ends_on]">Ends on:</label><br/>
|
||||
<%= radio_button_tag('recurring_todo[ends_on]', 'no_end_date', @recurring_todo.ends_on == 'no_end_date')%> No end date<br/>
|
||||
<%= radio_button_tag('recurring_todo[ends_on]', 'ends_on_number_of_times', @recurring_todo.ends_on == 'ends_on_number_of_times')%> Ends after <%= text_field_tag("recurring_todo[number_of_occurences]", @recurring_todo.number_of_occurences, "size" => 3, "tabindex" => 7) %> times<br/>
|
||||
<%= radio_button_tag('recurring_todo[ends_on]', 'ends_on_end_date', @recurring_todo.ends_on == 'ends_on_end_date')%> Ends on <%=
|
||||
text_field_tag('recurring_todo_edit_end_date', format_date(@recurring_todo.end_date), "size" => 12, "class" => "Date", "tabindex" => 8, "autocomplete" => "off") %><br/>
|
||||
</div></div>
|
||||
<div id="recurring_edit_daily" style="display:<%= @recurring_todo.recurring_period == 'daily' ? 'block' : 'none' %> ">
|
||||
<label>Settings for daily recurring actions</label><br/>
|
||||
<%= radio_button_tag('recurring_todo[daily_selector]', 'daily_every_x_day', !@recurring_todo.only_work_days)%> Every <%=
|
||||
text_field_tag( 'recurring_todo[daily_every_x_days]', @recurring_todo.daily_every_x_days, {"size" => 3, "tabindex" => 9}) %> day(s)<br/>
|
||||
<%= radio_button_tag('recurring_todo[daily_selector]', 'daily_every_work_day', @recurring_todo.only_work_days)%> Every work day<br/>
|
||||
</div>
|
||||
<div id="recurring_edit_weekly" style="display:<%= @recurring_todo.recurring_period == 'weekly' ? 'block' : 'none' %>">
|
||||
<label>Settings for weekly recurring actions</label><br/>
|
||||
Returns every <%= text_field_tag('recurring_todo[weekly_every_x_week]', @recurring_todo.weekly_every_x_week, {"size" => 3, "tabindex" => 9}) %> week on<br/>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_monday]', 'm', @recurring_todo.on_monday ) %> Monday
|
||||
<%= check_box_tag('recurring_todo[weekly_return_tuesday]', 't', @recurring_todo.on_tuesday) %> Tuesday
|
||||
<%= check_box_tag('recurring_todo[weekly_return_wednesday]', 'w', @recurring_todo.on_wednesday) %> Wednesday
|
||||
<%= check_box_tag('recurring_todo[weekly_return_thursday]', 't', @recurring_todo.on_thursday) %> Thursday<br/>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_friday]', 'f', @recurring_todo.on_friday) %> Friday
|
||||
<%= check_box_tag('recurring_todo[weekly_return_saturday]', 's', @recurring_todo.on_saturday) %> Saturday
|
||||
<%= check_box_tag('recurring_todo[weekly_return_sunday]', 's', @recurring_todo.on_sunday) %> Sunday<br/>
|
||||
</div>
|
||||
<div id="recurring_edit_monthly" style="display:<%= @recurring_todo.recurring_period == 'monthly' ? 'block' : 'none' %>">
|
||||
<label>Settings for monthly recurring actions</label><br/>
|
||||
<%= radio_button_tag('recurring_todo[monthly_selector]', 'monthly_every_x_day', @recurring_todo.is_monthly_every_x_day || @recurring_todo.recurring_period == 'weekly')%> Day <%=
|
||||
text_field_tag('recurring_todo[monthly_every_x_day]', @recurring_todo.monthly_every_x_day, {"size" => 3, "tabindex" => 9}) %> on every <%=
|
||||
text_field_tag('recurring_todo[monthly_every_x_month]', @recurring_todo.monthly_every_x_month, {"size" => 3, "tabindex" => 10}) %> month<br/>
|
||||
<%= radio_button_tag('recurring_todo[monthly_selector]', 'monthly_every_xth_day', @recurring_todo.is_monthly_every_xth_day)%> The <%=
|
||||
select_tag('recurring_todo[monthly_every_xth_day]', options_for_select(@xth_day, @xth_day[@recurring_todo.monthly_every_xth_day(1)-1][1])) %> <%=
|
||||
select_tag('recurring_todo[monthly_day_of_week]' , options_for_select(@days_of_week, @recurring_todo.monthly_day_of_week), {}) %> of every <%=
|
||||
text_field_tag('recurring_todo[monthly_every_x_month2]', @recurring_todo.monthly_every_x_month2, {"size" => 3, "tabindex" => 11}) %> month<br/>
|
||||
</div>
|
||||
<div id="recurring_edit_yearly" style="display:<%= @recurring_todo.recurring_period == 'yearly' ? 'block' : 'none' %>">
|
||||
<label>Settings for yearly recurring actions</label><br/>
|
||||
<%= radio_button_tag('recurring_todo[yearly_selector]', 'yearly_every_x_day', @recurring_todo.recurrence_selector == 0)%> Every <%=
|
||||
select_tag('recurring_todo[yearly_month_of_year]', options_for_select(@months_of_year, @recurring_todo.yearly_month_of_year), {}) %> <%=
|
||||
text_field_tag('recurring_todo[yearly_every_x_day]', @recurring_todo.yearly_every_x_day, "size" => 3, "tabindex" => 9) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[yearly_selector]', 'yearly_every_xth_day', @recurring_todo.recurrence_selector == 1)%> The <%=
|
||||
select_tag('recurring_todo[yearly_every_xth_day]', options_for_select(@xth_day, @recurring_todo.yearly_every_xth_day), {}) %> <%=
|
||||
select_tag('recurring_todo[yearly_day_of_week]', options_for_select(@days_of_week, @recurring_todo.yearly_day_of_week), {}) %> of <%=
|
||||
select_tag('recurring_todo[yearly_month_of_year2]', options_for_select(@months_of_year, @recurring_todo.yearly_month_of_year2), {}) %><br/>
|
||||
</div>
|
||||
<div id="recurring_target">
|
||||
<label>Set recurrence on</label><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_target]', 'due_date', @recurring_todo.target == 'due_date')%> the date that the todo is due. Show the todo:
|
||||
<%= radio_button_tag('recurring_todo[recurring_show_always]', '1', @recurring_todo.show_always?)%> always
|
||||
<%= radio_button_tag('recurring_todo[recurring_show_always]', '0', !@recurring_todo.show_always?)%>
|
||||
<%= text_field_tag( 'recurring_todo[recurring_show_days_before]', @recurring_todo.show_from_delta, {"size" => 3, "tabindex" => 12}) %>
|
||||
days before the todo is due
|
||||
<br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_target]', 'show_from_date', @recurring_todo.target == 'show_from_date')%> the date todo comes from tickler (no due date set)<br/>
|
||||
<br/>
|
||||
</div>
|
||||
<div class="recurring_submit_box">
|
||||
<div class="widgets">
|
||||
<button type="submit" class="positive" id="recurring_todo_edit_action_submit" tabindex="15">
|
||||
<%=image_tag("accept.png", :alt => "") %>
|
||||
Update
|
||||
</button>
|
||||
<button type="button" class="positive" id="recurring_todo_edit_action_cancel" tabindex="15">
|
||||
<%=image_tag("cancel.png", :alt => "") %>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
<div class="recurring_submit_box">
|
||||
<div class="widgets">
|
||||
<button type="submit" class="positive" id="recurring_todo_edit_action_submit" tabindex="15">
|
||||
<%=image_tag("accept.png", :alt => "") %>
|
||||
Update
|
||||
</button>
|
||||
<button type="button" class="positive" id="recurring_todo_edit_action_cancel" tabindex="15">
|
||||
<%=image_tag("cancel.png", :alt => "") %>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<%= recurring_todo_remote_delete_icon %> <%= recurring_todo_remote_edit_icon -%>
|
||||
|
||||
<%= recurring_todo_remote_star_icon %> <%= recurring_todo_remote_toggle_checkbox -%>
|
||||
<div class="description">
|
||||
<div class="rec_description">
|
||||
<span class="todo.descr"><%= sanitize(recurring_todo.description) %></span> <%= recurring_todo_tag_list %>
|
||||
<span class='recurrence_pattern'>
|
||||
[<%= recurrence_pattern_as_text(@recurring_todo) %>]
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
<div class="recurring_container">
|
||||
<% form_remote_tag(
|
||||
:url => recurring_todos_path, :method => :post,
|
||||
:html=> { :id=>'recurring-todo-form-new-action', :name=>'recurring_todo', :class => 'inline-form' },
|
||||
:before => "$('#recurring_todo_new_action_submit').block({message: null})") do
|
||||
<%
|
||||
form_for(@new_recurring_todo, :html=> { :id=>'recurring-todo-form-new-action', :name=>'recurring_todo', :class => 'inline-form' }) do
|
||||
#form_remote_tag(
|
||||
# :url => recurring_todos_path, :method => :post,
|
||||
# :html=> { :id=>'recurring-todo-form-new-action', :name=>'recurring_todo', :class => 'inline-form' },
|
||||
# :before => "$('#recurring_todo_new_action_submit').block({message: null})") do
|
||||
-%>
|
||||
<div id="new_status"><%= error_messages_for("item", :object_name => 'action') %></div>
|
||||
<div id="error_status"><%= error_messages_for("item", :object_name => 'action') %></div>
|
||||
|
||||
<div id="recurring_todo_form_container">
|
||||
<div id="recurring_todo">
|
||||
|
|
30
app/views/recurring_todos/create.js.erb
Normal file
30
app/views/recurring_todos/create.js.erb
Normal file
|
@ -0,0 +1,30 @@
|
|||
<% if @saved -%>
|
||||
RecurringTodosPage.toggle_overlay();
|
||||
add_recurring_todo_to_active_container();
|
||||
replace_form_with_empty_form();
|
||||
TracksPages.set_page_badge(<%= @down_count %>);
|
||||
<% else -%>
|
||||
TracksPages.show_errors(html_for_error_messages());
|
||||
<% end -%>
|
||||
|
||||
function replace_form_with_empty_form() {
|
||||
$('div.recurring_container').html(html_for_empty_form());
|
||||
}
|
||||
|
||||
function add_recurring_todo_to_active_container() {
|
||||
$('#recurring_todos_container').append(html_for_recurring_todo());
|
||||
$('#<%= dom_id(@recurring_todo)%>').effect('highlight', {}, 2000 );
|
||||
$('#recurring-todos-empty-nd').hide();
|
||||
}
|
||||
|
||||
function html_for_recurring_todo() {
|
||||
return "<%= @saved ? escape_javascript(render(:partial => @recurring_todo)) : "" %>";
|
||||
}
|
||||
|
||||
function html_for_empty_form() {
|
||||
return "<%= @saved ? escape_javascript(render(:partial => 'recurring_todo_form')) : "" %>";
|
||||
}
|
||||
|
||||
function html_for_error_messages() {
|
||||
return "<%= escape_javascript(error_messages_for('recurring_todo')) %>";
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
page.show 'new_status'
|
||||
page.replace_html 'new_status', "#{error_messages_for('recurring_todo')}"
|
||||
|
||||
page.notify :notice, @message, 5.0
|
||||
if @recurring_saved
|
||||
# reset form
|
||||
page['new-recurring-todo'].replace_html :partial => 'recurring_todo_form'
|
||||
# hide overlayed edit form
|
||||
page << "TracksForm.toggle_overlay();"
|
||||
# insert new recurring todo
|
||||
page.hide 'recurring-todos-empty-nd'
|
||||
page.insert_html :bottom,
|
||||
'recurring_todos_container',
|
||||
:partial => 'recurring_todos/recurring_todo', :locals => { :recurring_todo => @recurring_todo}
|
||||
page.visual_effect :highlight, dom_id(@recurring_todo), :duration => 3
|
||||
# update badge count
|
||||
page['badge_count'].replace_html @count
|
||||
end
|
22
app/views/recurring_todos/destroy.js.erb
Normal file
22
app/views/recurring_todos/destroy.js.erb
Normal file
|
@ -0,0 +1,22 @@
|
|||
<%- if @saved -%>
|
||||
show_empty_messages();
|
||||
TracksPages.page_notify('notice', '<%= escape_javascript(t('todos.recurring_deleted_success') + t(:todo_removed, :count => @number_of_todos)) %>', 5);
|
||||
remove_recurring_todo_from_page();
|
||||
<%- else -%>
|
||||
TracksPages.page_notify('error', '<%= t('todos.error_deleting_recurring', :description => @recurring_todo.description) %>', 8);
|
||||
<%- end -%>
|
||||
|
||||
function show_empty_messages() {
|
||||
<%- if @active_remaining == 0 -%>
|
||||
$('#recurring-todos-empty-nd').show();
|
||||
<%- end -%>
|
||||
<%- if @completed_remaining == 0 -%>
|
||||
$('#completed-empty-nd').show();
|
||||
<%- end -%>
|
||||
}
|
||||
|
||||
function remove_recurring_todo_from_page() {
|
||||
$('#<%=dom_id(@recurring_todo)%>').slideUp(1000, function() {
|
||||
$('#<%=dom_id(@recurring_todo)%>').remove();
|
||||
});
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
if @saved
|
||||
if @remaining == 0
|
||||
page.show 'recurring-todos-empty-nd'
|
||||
end
|
||||
page.notify :notice, t('todos.recurring_deleted_success') +
|
||||
t(:todo_removed, :count => @number_of_todos), 5.0
|
||||
page[@recurring_todo].remove
|
||||
page.visual_effect :fade, dom_id(@recurring_todo), :duration => 0.4
|
||||
else
|
||||
page.notify :error, t('todos.error_deleting_recurring', :description => @recurring_todo.description), 8.0
|
||||
end
|
9
app/views/recurring_todos/edit.js.erb
Normal file
9
app/views/recurring_todos/edit.js.erb
Normal file
|
@ -0,0 +1,9 @@
|
|||
$('#new-recurring-todo').hide();
|
||||
$('#edit-recurring-todo').html(html_for_edit_form());
|
||||
$('#edit-recurring-todo').show();
|
||||
RecurringTodosPage.toggle_overlay();
|
||||
enable_rich_interaction();
|
||||
|
||||
function html_for_edit_form() {
|
||||
return "<%= escape_javascript(render(:partial => 'edit_form')) %>"
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
page << "TracksForm.toggle_overlay();"
|
||||
page['new-recurring-todo'].hide
|
||||
page['edit-recurring-todo'].replace_html :partial => 'recurring_todos/edit_form'
|
||||
page['edit-recurring-todo'].show
|
||||
page << "enable_rich_interaction();"
|
|
@ -21,7 +21,7 @@
|
|||
</div>
|
||||
<div id="input_box">
|
||||
<div id="recurring_new_container">
|
||||
<a href='#' onclick="$('new-recurring-todo').show();$('edit-recurring-todo').hide();TracksForm.toggle_overlay()"><%= image_tag("add.png", {:alt => "[ADD]"})-%><%= t('todos.add_new_recurring') %></a>
|
||||
<a href='#' id="add-new-recurring-todo"><%= image_tag("add.png", {:alt => "[ADD]"})-%><%= t('todos.add_new_recurring') %></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
51
app/views/recurring_todos/toggle_check.js.erb
Normal file
51
app/views/recurring_todos/toggle_check.js.erb
Normal file
|
@ -0,0 +1,51 @@
|
|||
<%- if @saved -%>
|
||||
TracksPages.set_page_badge(<%= @down_count %>);
|
||||
remove_old_and_add_updated_recurring_todo();
|
||||
inform_if_new_todo_created();
|
||||
<%- else -%>
|
||||
TracksPages.page_notify('error', '<%= t('todos.error_completing_todo', :description => @recurring_todo.description) %>', 8);
|
||||
<%- end -%>
|
||||
|
||||
function inform_if_new_todo_created() {
|
||||
<%- unless @new_recurring_todo.nil? -%>
|
||||
TracksPages.page_notify('notice', '<%= t('todos.new_related_todo_created') %>', 5);
|
||||
<%- end -%>
|
||||
}
|
||||
|
||||
function remove_old_and_add_updated_recurring_todo() {
|
||||
$('#<%=dom_id(@recurring_todo)%>').slideUp(1000, function() {
|
||||
$('#<%=dom_id(@recurring_todo)%>').remove();
|
||||
show_empty_messages();
|
||||
|
||||
<%- if @recurring_todo.completed? -%>
|
||||
add_recurring_todo_to_completed_container();
|
||||
<%- else -%>
|
||||
add_recurring_todo_to_active_container();
|
||||
<%- end -%>
|
||||
});
|
||||
}
|
||||
|
||||
function add_recurring_todo_to_completed_container() {
|
||||
$('#completed_recurring_todos_container').append(html_for_recurring_todo());
|
||||
$('#<%= dom_id(@recurring_todo)%>').effect('highlight', {}, 2000 );
|
||||
$('#completed-empty-nd').hide();
|
||||
}
|
||||
|
||||
function add_recurring_todo_to_active_container() {
|
||||
$('#recurring_todos_container').append(html_for_recurring_todo());
|
||||
$('#<%= dom_id(@recurring_todo)%>').effect('highlight', {}, 2000 );
|
||||
$('#recurring-todos-empty-nd').hide();
|
||||
}
|
||||
|
||||
function show_empty_messages() {
|
||||
<%- if @active_remaining == 0 -%>
|
||||
$('#recurring-todos-empty-nd').show();
|
||||
<%- end -%>
|
||||
<%- if @completed_remaining == 0 -%>
|
||||
$('#completed-empty-nd').show();
|
||||
<%- end -%>
|
||||
}
|
||||
|
||||
function html_for_recurring_todo() {
|
||||
return "<%= @saved ? escape_javascript(render(:partial => @recurring_todo)) : "" %>";
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
if @saved
|
||||
page[@recurring_todo].remove
|
||||
page['badge_count'].replace_html @count
|
||||
|
||||
if @recurring_todo.completed?
|
||||
# show completed recurring todo
|
||||
page.insert_html :top, "completed_recurring_todos_container", :partial => 'recurring_todos/recurring_todo', :locals => { :recurring_todo => @recurring_todo }
|
||||
page.visual_effect :highlight, dom_id(@recurring_todo), :duration => 3
|
||||
|
||||
# set empty messages
|
||||
page.show 'recurring-todos-empty-nd' if @remaining == 0
|
||||
page.hide 'completed-empty-nd'
|
||||
else
|
||||
# recurring_todo is activated
|
||||
|
||||
# show completed recurring todo
|
||||
page.insert_html :top, "recurring_todos_container", :partial => 'recurring_todos/recurring_todo', :locals => { :recurring_todo => @recurring_todo }
|
||||
page.visual_effect :highlight, dom_id(@recurring_todo), :duration => 3
|
||||
|
||||
# inform user if a new todo has been created because of the activation
|
||||
page.notify :notice, t('todos.new_related_todo_created'), 3.0 unless @new_recurring_todo.nil?
|
||||
|
||||
# set empty messages
|
||||
page.show 'completed-empty-nd' if @remaining == 0
|
||||
page.hide 'recurring-todos-empty-nd'
|
||||
end
|
||||
|
||||
else
|
||||
page.notify :error, t('todos.error_completing_todo', :description => @recurring_todo.description), 8.0
|
||||
end
|
|
@ -1,3 +1,5 @@
|
|||
<% if @saved -%>
|
||||
$('div#recurring_todo_<%= @recurring_todo.id %> a.star_item img').toggleClass('starred_todo').toggleClass('unstarred_todo');
|
||||
<% end -%>
|
||||
<%- else -%>
|
||||
TracksPages.page_notify('error', '<%= t('todos.error_starring_recurring', :description => @recurring_todo.description) %>', 8);
|
||||
<%- end -%>
|
||||
|
|
38
app/views/recurring_todos/update.js.erb
Normal file
38
app/views/recurring_todos/update.js.erb
Normal file
|
@ -0,0 +1,38 @@
|
|||
<%- if @saved -%>
|
||||
RecurringTodosPage.toggle_overlay();
|
||||
TracksPages.page_notify('notice', text_for_status_message(), 5);
|
||||
replace_old_recurring_todo_with_updated();
|
||||
<%- else -%>
|
||||
TracksPages.show_edit_errors(html_for_error_messages());
|
||||
<%- end -%>
|
||||
|
||||
function replace_old_recurring_todo_with_updated() {
|
||||
$('#<%=dom_id(@recurring_todo)%>').fadeOut(250, function() {
|
||||
<%-
|
||||
# first add the updated recurring todo after the old one, then remove old one
|
||||
# using html() does not work, because it will replace the _content_ of
|
||||
# the container instead of the container itself, i.e. you will get
|
||||
# a container within a container which will break drag-and-drop sorting (when/if implemented)
|
||||
-%>
|
||||
$('#<%=dom_id(@recurring_todo)%>').after(html_for_updated_recurring_todo());
|
||||
$('#<%=dom_id(@recurring_todo)%>').remove();
|
||||
$('#<%=dom_id(@recurring_todo)%>').fadeIn(500);
|
||||
});
|
||||
}
|
||||
|
||||
function html_for_updated_recurring_todo() {
|
||||
return "<%= escape_javascript(render(:partial => @recurring_todo))%>";
|
||||
}
|
||||
|
||||
function text_for_status_message() {
|
||||
<%-
|
||||
status_message = t('todos.recurring_action_saved')
|
||||
status_message = t('todos.added_new_project') + ' / ' + status_message if @new_project_created
|
||||
status_message = t('todos.added_new_context') + ' / ' + status_message if @new_context_created
|
||||
-%>
|
||||
return "<%= status_message%>";
|
||||
}
|
||||
|
||||
function html_for_error_messages() {
|
||||
return "<%= escape_javascript(error_messages_for('recurring_todo')) %>";
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
if @saved
|
||||
# hide overlayed edit form
|
||||
page << "TracksForm.toggle_overlay();"
|
||||
|
||||
# show update message
|
||||
status_message = t('todos.recurring_action_saved')
|
||||
status_message = t('todos.added_new_project') + ' / ' + status_message if @new_project_created
|
||||
status_message = t('todos.added_new_context') + ' / ' + status_message if @new_context_created
|
||||
page.notify :notice, status_message, 5.0
|
||||
|
||||
# replace old recurring todo with updated todo
|
||||
page.replace dom_id(@recurring_todo), :partial => 'recurring_todos/recurring_todo', :locals => { :recurring_todo => @recurring_todo }
|
||||
page.visual_effect :highlight, dom_id(@recurring_todo), :duration => 3
|
||||
|
||||
else
|
||||
page.show 'edit_status'
|
||||
page.replace_html 'edit_status', "#{error_messages_for('recurring_todo')}"
|
||||
end
|
|
@ -18,7 +18,7 @@
|
|||
:html=> { :id=>'todo-form-new-action', :name=>'todo', :class => 'inline-form' },
|
||||
:before => "$('#todo_new_action_submit').block({message:null})",
|
||||
:complete => "$('#todo_new_action_submit').unblock()",
|
||||
:condition => "askIfNewContextProvided('')") do -%>
|
||||
:condition => "TodoItems.askIfNewContextProvided('')") do -%>
|
||||
|
||||
<div id="status"><%= error_messages_for("item", :object_name => 'action') %></div>
|
||||
|
||||
|
@ -75,7 +75,7 @@
|
|||
:html=> { :id=>'todo-form-multi-new-action', :name=>'todo', :class => 'inline-form' },
|
||||
:before => "$('#todo_multi_new_action_submit').block({message:null})",
|
||||
:complete => "$('#todo_multi_new_action_submit').unblock()",
|
||||
:condition => "askIfNewContextProvided('multi_')") do -%>
|
||||
:condition => "TodoItems.askIfNewContextProvided('multi_')") do -%>
|
||||
|
||||
<div id="multiple_status"><%= error_messages_for("item", :object_name => 'action') %></div>
|
||||
|
||||
|
|
|
@ -397,7 +397,8 @@ en:
|
|||
no_completed_recurring: "Currently there are no completed recurring todos"
|
||||
add_new_recurring: "Add a new recurring action"
|
||||
recurring_deleted_success: "The recurring action was deleted succesfully."
|
||||
error_deleting_recurring: "There was an error deleting the recurring todo {{description}}"
|
||||
error_deleting_recurring: "There was an error deleting the recurring todo \'{{description}}\'"
|
||||
error_starring_recurring: "Could not toggle the star of recurring todo \'{{description}}\'"
|
||||
recurrence_period: "Recurrence period"
|
||||
action_marked_complete: "The action <strong>'{{description}}'</strong> was marked as <strong>{{completed}}</strong>"
|
||||
action_marked_complete_error: "The action <strong>'{{description}}'</strong> was NOT marked as <strong>{{completed}} due to an error on the server.</strong>"
|
||||
|
@ -439,7 +440,7 @@ en:
|
|||
edit: "Edit"
|
||||
defer_date_after_due_date: "Defer date is after due date. Please edit and adjust due date before deferring."
|
||||
convert_to_project: "Make project"
|
||||
blocked_by: "Blocked by {{predecessors}"
|
||||
blocked_by: "Blocked by {{predecessors}}"
|
||||
depends_on: "Depends on"
|
||||
pending: "Pending"
|
||||
drag_action_title: "Drag onto another action to make it depend on that action"
|
||||
|
|
|
@ -22,3 +22,19 @@ Feature: Manage recurring todos
|
|||
Then I should see the form for "Yearly" recurrence pattern
|
||||
When I select "Daily" recurrence pattern
|
||||
Then I should see the form for "Daily" recurrence pattern
|
||||
|
||||
@selenium
|
||||
Scenario: I can mark a repeat pattern as starred
|
||||
Given this scenario is pending
|
||||
|
||||
@selenium
|
||||
Scenario: I can edit a repeat pattern
|
||||
Given this scenario is pending
|
||||
|
||||
@selenium
|
||||
Scenario: I can delete a repeat pattern
|
||||
Given this scenario is pending
|
||||
|
||||
@selenium
|
||||
Scenario: I can mark a repeat pattern as done
|
||||
Given this scenario is pending
|
||||
|
|
|
@ -102,9 +102,16 @@ var TracksPages = {
|
|||
$('div#error_status').html(html);
|
||||
$('div#error_status').show();
|
||||
},
|
||||
show_edit_errors: function(html) {
|
||||
$('div#edit_error_status').html(html);
|
||||
$('div#edit_error_status').show();
|
||||
},
|
||||
hide_errors: function() {
|
||||
$('div#error_status').hide();
|
||||
},
|
||||
update_sidebar: function(html) {
|
||||
$('#sidebar').html(html);
|
||||
},
|
||||
setup_nifty_corners: function() {
|
||||
Nifty("div#recurring_new_container","normal");
|
||||
Nifty("div#context_new_container","normal");
|
||||
|
@ -114,6 +121,16 @@ var TracksPages = {
|
|||
Nifty("div#todo_new_action_container","normal");
|
||||
Nifty("div#project_new_project_container","normal");
|
||||
},
|
||||
page_notify: function(type, message, fade_duration_in_sec) {
|
||||
flash = $('h4#flash');
|
||||
flash.html("<h4 id=\'flash\' class=\'alert "+type+"\'>"+message+"</h4>");
|
||||
flash = $('h4#flash');
|
||||
flash.show();
|
||||
flash.fadeOut(fade_duration_in_sec*1000);
|
||||
},
|
||||
set_page_badge: function(count) {
|
||||
$('#badge_count').html(count);
|
||||
},
|
||||
setup_behavior: function () {
|
||||
/* main menu */
|
||||
$('ul.sf-menu').superfish({
|
||||
|
@ -244,6 +261,27 @@ var TodoItemsContainer = {
|
|||
}
|
||||
|
||||
var TodoItems = {
|
||||
askIfNewContextProvided: function(source) {
|
||||
var givenContextName = $('#'+source+'todo_context_name').val();
|
||||
var contextNames = [];
|
||||
var contextNamesRequest = $.ajax({
|
||||
url: relative_to_root('contexts.autocomplete'),
|
||||
async: false,
|
||||
dataType: "text",
|
||||
data: "q="+givenContextName,
|
||||
success: function(result){
|
||||
lines = result.split("\n");
|
||||
for(var i = 0; i < lines.length; i++){
|
||||
contextNames.push(lines[i].split("|")[0]);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (givenContextName.length == 0) return true; // do nothing and depend on rails validation error
|
||||
for (var i = 0; i < contextNames.length; ++i) {
|
||||
if (contextNames[i] == givenContextName) return true;
|
||||
}
|
||||
return confirm('New context "' + givenContextName + '" will be also created. Are you sure?');
|
||||
},
|
||||
setup_behavior: function() {
|
||||
/* show the notes of a todo */
|
||||
$(".show_notes").live('click', function () {
|
||||
|
@ -264,14 +302,9 @@ var TodoItems = {
|
|||
return false;
|
||||
});
|
||||
|
||||
/* set behavior for toggle checkboxes */
|
||||
/* set behavior for toggle checkboxes for Recurring Todos */
|
||||
$(".item-container input.item-checkbox").live('click', function(ev){
|
||||
params = {
|
||||
_method: 'put'
|
||||
};
|
||||
if(typeof(TAG_NAME) !== 'undefined')
|
||||
params._tag_name = TAG_NAME;
|
||||
$.post(this.value, params, null, 'script');
|
||||
put_with_ajax_and_block_element(this.value, $(this));
|
||||
});
|
||||
|
||||
/* set behavior for edit icon */
|
||||
|
@ -562,26 +595,47 @@ var RecurringTodosPage = {
|
|||
el.style.visibility = (el.style.visibility == "visible") ? "hidden" : "visible";
|
||||
},
|
||||
setup_behavior: function() {
|
||||
$("#recurring_todo_new_action_cancel").click(function(){
|
||||
/* cancel button on new recurring todo form */
|
||||
$("#recurring_todo_new_action_cancel").live('click', function(){
|
||||
$('#recurring-todo-form-new-action input:text:first').focus();
|
||||
RecurringTodosPage.hide_all_recurring();
|
||||
$('#recurring_daily').show();
|
||||
RecurringTodosPage.toggle_overlay();
|
||||
});
|
||||
/* cancel button on edit recurring todo form */
|
||||
$("#recurring_todo_edit_action_cancel").live('click', function(){
|
||||
$('#recurring-todo-form-edit-action input:text:first').focus();
|
||||
RecurringTodosPage.hide_all_recurring();
|
||||
$('#recurring_daily').show();
|
||||
RecurringTodosPage.toggle_overlay();
|
||||
});
|
||||
/* change recurring period radio input on edit form */
|
||||
$("#recurring_edit_period input").live('click', function(){
|
||||
RecurringTodosPage.hide_all_edit_recurring();
|
||||
$('#recurring_edit_'+this.id.split('_')[5]).show();
|
||||
});
|
||||
/* change recurring period radio input on new form */
|
||||
$("#recurring_period input").live('click', function(){
|
||||
RecurringTodosPage.hide_all_recurring();
|
||||
$('#recurring_'+this.id.split('_')[4]).show();
|
||||
});
|
||||
/* add new recurring todo plus-button in sidebar */
|
||||
$("#add-new-recurring-todo").live('click', function(){
|
||||
$('#new-recurring-todo').show();
|
||||
$('#edit-recurring-todo').hide();
|
||||
RecurringTodosPage.toggle_overlay();
|
||||
});
|
||||
/* submit form when editing a recurring todo */
|
||||
$("#recurring_todo_edit_action_submit").live('click', function (ev) {
|
||||
submit_with_ajax_and_block_element('form#recurring-todo-form-edit-action', $(this));
|
||||
return false;
|
||||
});
|
||||
/* submit form for new recurring todo */
|
||||
$("#recurring_todo_new_action_submit").live('click', function (ev) {
|
||||
submit_with_ajax_and_block_element('form.#recurring-todo-form-new-action', $(this));
|
||||
return false;
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -591,6 +645,47 @@ var SearchPage = {
|
|||
}
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
/* generic Tracks functions */
|
||||
/**************************************/
|
||||
|
||||
function redirect_to(path) {
|
||||
window.location.href = path;
|
||||
}
|
||||
|
||||
function setup_auto_refresh(interval){
|
||||
field_touched = false;
|
||||
function refresh_page() {
|
||||
if(!field_touched){
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
setTimeout(refresh_page, interval);
|
||||
$(function(){
|
||||
$("input").live('keydown', function(){
|
||||
field_touched = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$.fn.clearForm = function() {
|
||||
return this.each(function() {
|
||||
var type = this.type, tag = this.tagName.toLowerCase();
|
||||
if (tag == 'form')
|
||||
return $(':input',this).clearForm();
|
||||
if (type == 'text' || type == 'password' || tag == 'textarea')
|
||||
this.value = '';
|
||||
else if (type == 'checkbox' || type == 'radio')
|
||||
this.checked = false;
|
||||
else if (tag == 'select')
|
||||
this.selectedIndex = -1;
|
||||
});
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
/* Tracks AJAX functions */
|
||||
/**************************************/
|
||||
|
||||
function generic_get_script_for_list(element, getter, param){
|
||||
$(element).load(relative_to_root(getter+'?'+param));
|
||||
}
|
||||
|
@ -639,16 +734,20 @@ function post_with_ajax_and_block_element(the_url, element_to_block) {
|
|||
$.ajax(default_ajax_options('POST', the_url, element_to_block));
|
||||
}
|
||||
|
||||
function put_with_ajax_and_block_element(the_url, element_to_block) {
|
||||
options = default_ajax_options('POST', the_url, element_to_block);
|
||||
options.data = '_method=put';
|
||||
if(typeof(TAG_NAME) !== 'undefined')
|
||||
options.data += "&_tag_name="+ encodeURIComponent (TAG_NAME);
|
||||
$.ajax(options);
|
||||
}
|
||||
|
||||
function delete_with_ajax_and_block_element(the_url, element_to_block) {
|
||||
$.ajax(default_ajax_options('DELETE', the_url, element_to_block));
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* Unobtrusive jQuery written by Eric Allen
|
||||
****************************************/
|
||||
|
||||
/* Set up authenticity token properly */
|
||||
$(document).ajaxSend(function(event, request, settings) {
|
||||
/* Set up authenticity token properly */
|
||||
if ( settings.type == 'POST' || settings.type == 'post' ) {
|
||||
if(typeof(AUTH_TOKEN) != 'undefined'){
|
||||
settings.data = (settings.data ? settings.data + "&" : "")
|
||||
|
@ -663,44 +762,20 @@ $(document).ajaxSend(function(event, request, settings) {
|
|||
request.setRequestHeader("Accept", "text/javascript");
|
||||
});
|
||||
|
||||
$.fn.clearForm = function() {
|
||||
return this.each(function() {
|
||||
var type = this.type, tag = this.tagName.toLowerCase();
|
||||
if (tag == 'form')
|
||||
return $(':input',this).clearForm();
|
||||
if (type == 'text' || type == 'password' || tag == 'textarea')
|
||||
this.value = '';
|
||||
else if (type == 'checkbox' || type == 'radio')
|
||||
this.checked = false;
|
||||
else if (tag == 'select')
|
||||
this.selectedIndex = -1;
|
||||
});
|
||||
};
|
||||
|
||||
function redirect_to(path) {
|
||||
window.location.href = path;
|
||||
}
|
||||
|
||||
function askIfNewContextProvided(source) {
|
||||
var givenContextName = $('#'+source+'todo_context_name').val();
|
||||
var contextNames = [];
|
||||
var contextNamesRequest = $.ajax({
|
||||
url: relative_to_root('contexts.autocomplete'),
|
||||
async: false,
|
||||
dataType: "text",
|
||||
data: "q="+givenContextName,
|
||||
success: function(result){
|
||||
lines = result.split("\n");
|
||||
for(var i = 0; i < lines.length; i++){
|
||||
contextNames.push(lines[i].split("|")[0]);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (givenContextName.length == 0) return true; // do nothing and depend on rails validation error
|
||||
for (var i = 0; i < contextNames.length; ++i) {
|
||||
if (contextNames[i] == givenContextName) return true;
|
||||
function setup_periodic_check(url_for_check, interval_in_sec, method) {
|
||||
ajaxMethod = "GET"
|
||||
if (method) {
|
||||
ajaxMethod = method;
|
||||
}
|
||||
return confirm('New context "' + givenContextName + '" will be also created. Are you sure?');
|
||||
|
||||
function check_remote() {
|
||||
$.ajax({
|
||||
type: ajaxMethod,
|
||||
url: url_for_check,
|
||||
dataType: 'script'
|
||||
});
|
||||
}
|
||||
setInterval(check_remote, interval_in_sec*1000);
|
||||
}
|
||||
|
||||
function update_order(event, ui){
|
||||
|
@ -724,8 +799,6 @@ function update_order(event, ui){
|
|||
'script');
|
||||
}
|
||||
|
||||
/* Unobtrusive jQuery behavior */
|
||||
|
||||
function project_defaults(){
|
||||
if($('body').hasClass('contexts')){
|
||||
// don't change the context
|
||||
|
@ -747,6 +820,8 @@ function project_defaults(){
|
|||
}
|
||||
|
||||
function enable_rich_interaction(){
|
||||
/* called after completion of all AJAX calls */
|
||||
|
||||
/* fix for #1036 where closing a edit form before the autocomplete was filled
|
||||
* resulted in a dropdown box that could not be removed. We remove all
|
||||
* autocomplete boxes the hard way */
|
||||
|
@ -757,6 +832,7 @@ function enable_rich_interaction(){
|
|||
'firstDay': weekStart,
|
||||
'showAnim': 'fold'
|
||||
});
|
||||
|
||||
/* Autocomplete */
|
||||
$('input[name=context_name]').autocomplete({
|
||||
source: relative_to_root('contexts.autocomplete')
|
||||
|
@ -771,7 +847,7 @@ function enable_rich_interaction(){
|
|||
relative_to_root('auto_complete_for_predecessor'),
|
||||
{multiple: true,multipleSeparator:','});
|
||||
|
||||
/* have to bind on keypress because of limitataions of live() */
|
||||
/* have to bind on keypress because of limitations of live() */
|
||||
$('input[name=project_name]').live('keypress', function(){
|
||||
$(this).bind('blur', project_defaults);
|
||||
});
|
||||
|
@ -861,51 +937,6 @@ function enable_rich_interaction(){
|
|||
});
|
||||
}
|
||||
|
||||
/* Auto-refresh */
|
||||
|
||||
function setup_auto_refresh(interval){
|
||||
field_touched = false;
|
||||
function refresh_page() {
|
||||
if(!field_touched){
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
setTimeout(refresh_page, interval);
|
||||
$(function(){
|
||||
$("input").live('keydown', function(){
|
||||
field_touched = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function page_notify(type, message, fade_duration_in_sec) {
|
||||
flash = $('h4#flash');
|
||||
flash.html("<h4 id=\'flash\' class=\'alert "+type+"\'>"+message+"</h4>");
|
||||
flash = $('h4#flash');
|
||||
flash.show();
|
||||
flash.fadeOut(fade_duration_in_sec*1000);
|
||||
}
|
||||
|
||||
function set_page_badge(count) {
|
||||
$('#badge_count').html(count);
|
||||
}
|
||||
|
||||
function setup_periodic_check(url_for_check, interval_in_sec, method) {
|
||||
ajaxMethod = "GET"
|
||||
if (method) {
|
||||
ajaxMethod = method;
|
||||
}
|
||||
|
||||
function check_remote() {
|
||||
$.ajax({
|
||||
type: ajaxMethod,
|
||||
url: url_for_check,
|
||||
dataType: 'script'
|
||||
});
|
||||
}
|
||||
setInterval(check_remote, interval_in_sec*100);
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
TracksPages.setup_nifty_corners();
|
||||
|
||||
|
@ -918,6 +949,6 @@ $(document).ready(function() {
|
|||
eval(this+'.setup_behavior();');
|
||||
});
|
||||
|
||||
/* Gets called from some AJAX callbacks, too */
|
||||
/* Gets called from all AJAX callbacks, too */
|
||||
enable_rich_interaction();
|
||||
});
|
||||
|
|
|
@ -379,11 +379,15 @@ input.item-checkbox {
|
|||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.description, .stale_l1, .stale_l2, .stale_l3 {
|
||||
.rec_description, .description, .stale_l1, .stale_l2, .stale_l3 {
|
||||
margin-left: 60px;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.rec_description {
|
||||
margin-left: 80px;
|
||||
}
|
||||
|
||||
.stale_l1 {
|
||||
background: #ffC;
|
||||
}
|
||||
|
|
|
@ -1,145 +1,145 @@
|
|||
require "#{File.dirname(__FILE__)}/../test_helper"
|
||||
require 'tempfile'
|
||||
|
||||
module Tracks
|
||||
class Config
|
||||
def self.salt
|
||||
"change-me"
|
||||
end
|
||||
def self.auth_schemes
|
||||
['database','ldap']
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class LdapAuthTest < ActionController::IntegrationTest
|
||||
|
||||
fixtures :users
|
||||
|
||||
RUN_LDAP_TESTS = ENV['RUN_TRACKS_LDAP_TESTS'] || false
|
||||
SLAPD_BIN = "/usr/libexec/slapd" #You may need to adjust this
|
||||
SLAPD_SCHEMA_DIR = "/etc/openldap/schema/" #You may need to adjust this
|
||||
SLAPD_TEST_PORT = 10389
|
||||
OUTPUT_DEBUG_INFO = false
|
||||
|
||||
begin
|
||||
require 'net/ldap' #requires ruby-net-ldap gem be installed
|
||||
require 'simple_ldap_authenticator'
|
||||
end if RUN_LDAP_TESTS
|
||||
|
||||
SimpleLdapAuthenticator.ldap_library = 'net/ldap'
|
||||
SimpleLdapAuthenticator.servers = %w'localhost'
|
||||
SimpleLdapAuthenticator.use_ssl = false
|
||||
SimpleLdapAuthenticator.login_format = 'cn=%s,dc=lukemelia,dc=com'
|
||||
SimpleLdapAuthenticator.port = 10389
|
||||
SimpleLdapAuthenticator.logger = RAILS_DEFAULT_LOGGER
|
||||
|
||||
def setup
|
||||
assert_equal "test", ENV['RAILS_ENV']
|
||||
assert_equal "change-me", Tracks::Config.salt
|
||||
|
||||
if RUN_LDAP_TESTS
|
||||
setup_ldap_server_conf
|
||||
start_ldap_server
|
||||
end
|
||||
end
|
||||
|
||||
def teardown
|
||||
stop_ldap_server if RUN_LDAP_TESTS
|
||||
end
|
||||
|
||||
def test_authenticate_against_ldap
|
||||
add_ldap_user_to_ldap_repository
|
||||
assert SimpleLdapAuthenticator.valid?('john', 'deere')
|
||||
user = User.authenticate('john', 'deere')
|
||||
assert_not_nil(user)
|
||||
assert_equal user.login, 'john'
|
||||
end
|
||||
|
||||
private :test_authenticate_against_ldap unless RUN_LDAP_TESTS
|
||||
|
||||
def setup_ldap_server_conf
|
||||
@slapd_conf = create_slapd_conf()
|
||||
open(@slapd_conf.path) { |f| f.read }
|
||||
unless File.exist?(SLAPD_BIN)
|
||||
assert false, "slapd could not be found at #{SLAPD_BIN}. Adjust the path in #{__FILE__}"
|
||||
end
|
||||
end
|
||||
|
||||
def start_ldap_server
|
||||
t = Thread.new(@slapd_conf.path) do |slapd_conf_path|
|
||||
puts "starting slapd..." if OUTPUT_DEBUG_INFO
|
||||
run_cmd %Q{/usr/libexec/slapd -f #{slapd_conf_path} -h "ldap://127.0.0.1:10389/" -d0}
|
||||
end
|
||||
sleep(2)
|
||||
run_cmd %Q{ldapsearch -H "ldap://127.0.0.1:10389/" -x -b '' -s base '(objectclass=*)' namingContexts}
|
||||
end
|
||||
|
||||
def add_ldap_user_to_ldap_repository
|
||||
ldif_file = create_ldif()
|
||||
run_cmd %Q{ldapadd -H "ldap://127.0.0.1:10389/" -f #{ldif_file.path} -cxv -D "cn=Manager,dc=lukemelia,dc=com" -w secret}
|
||||
puts `cat #{ldif_file.path}` if OUTPUT_DEBUG_INFO
|
||||
end
|
||||
|
||||
def stop_ldap_server
|
||||
pid = open(get_pid_file_path(@slapd_conf)) { |f| f.read }
|
||||
run_cmd "kill -TERM #{pid}"
|
||||
end
|
||||
|
||||
def create_slapd_conf
|
||||
slapd_conf = Tempfile.new("slapd.conf")
|
||||
slapd_conf.path
|
||||
data_dir = slapd_conf.path + '-data'
|
||||
pid_file = get_pid_file_path(slapd_conf)
|
||||
Dir.mkdir(data_dir)
|
||||
encrypted_password = `slappasswd -s secret`
|
||||
open(slapd_conf.path, 'w') do |f|
|
||||
f.puts %Q{include #{SLAPD_SCHEMA_DIR}core.schema
|
||||
pidfile #{pid_file}
|
||||
database ldbm
|
||||
suffix "dc=lukemelia,dc=com"
|
||||
rootdn "cn=Manager,dc=lukemelia,dc=com"
|
||||
rootpw #{encrypted_password}
|
||||
directory #{data_dir}
|
||||
|
||||
access to *
|
||||
by self write
|
||||
by users read
|
||||
by anonymous auth
|
||||
}
|
||||
end
|
||||
puts `cat #{slapd_conf.path}` if OUTPUT_DEBUG_INFO
|
||||
slapd_conf
|
||||
end
|
||||
|
||||
def create_ldif
|
||||
ldif_file = Tempfile.new("ldap_user.ldif")
|
||||
encrypted_password = `slappasswd -s deere`
|
||||
open(ldif_file.path, 'w') do |f|
|
||||
f.puts %Q{dn: dc=lukemelia,dc=com
|
||||
objectclass: dcObject
|
||||
objectclass: organization
|
||||
o: Luke Melia DotCom
|
||||
dc: lukemelia
|
||||
|
||||
dn: cn=john,dc=lukemelia,dc=com
|
||||
cn: john
|
||||
sn: john
|
||||
objectclass: person
|
||||
userPassword: #{encrypted_password}
|
||||
}
|
||||
end
|
||||
ldif_file
|
||||
end
|
||||
|
||||
def run_cmd(cmd)
|
||||
puts cmd if OUTPUT_DEBUG_INFO
|
||||
cmd_out = `#{cmd}`
|
||||
puts cmd_out if OUTPUT_DEBUG_INFO
|
||||
end
|
||||
|
||||
def get_pid_file_path(tempfile)
|
||||
tempfile.path + '.pid'
|
||||
end
|
||||
|
||||
end
|
||||
require "#{File.dirname(__FILE__)}/../test_helper"
|
||||
require 'tempfile'
|
||||
|
||||
module Tracks
|
||||
class Config
|
||||
def self.salt
|
||||
"change-me"
|
||||
end
|
||||
def self.auth_schemes
|
||||
['database','ldap']
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class LdapAuthTest < ActionController::IntegrationTest
|
||||
|
||||
fixtures :users
|
||||
|
||||
RUN_LDAP_TESTS = ENV['RUN_TRACKS_LDAP_TESTS'] || false
|
||||
SLAPD_BIN = "/usr/libexec/slapd" #You may need to adjust this
|
||||
SLAPD_SCHEMA_DIR = "/etc/openldap/schema/" #You may need to adjust this
|
||||
SLAPD_TEST_PORT = 10389
|
||||
OUTPUT_DEBUG_INFO = false
|
||||
|
||||
begin
|
||||
require 'net/ldap' #requires ruby-net-ldap gem be installed
|
||||
require 'simple_ldap_authenticator'
|
||||
end if RUN_LDAP_TESTS
|
||||
|
||||
SimpleLdapAuthenticator.ldap_library = 'net/ldap'
|
||||
SimpleLdapAuthenticator.servers = %w'localhost'
|
||||
SimpleLdapAuthenticator.use_ssl = false
|
||||
SimpleLdapAuthenticator.login_format = 'cn=%s,dc=lukemelia,dc=com'
|
||||
SimpleLdapAuthenticator.port = 10389
|
||||
SimpleLdapAuthenticator.logger = RAILS_DEFAULT_LOGGER
|
||||
|
||||
def setup
|
||||
assert_equal "test", ENV['RAILS_ENV']
|
||||
assert_equal "change-me", Tracks::Config.salt
|
||||
|
||||
if RUN_LDAP_TESTS
|
||||
setup_ldap_server_conf
|
||||
start_ldap_server
|
||||
end
|
||||
end
|
||||
|
||||
def teardown
|
||||
stop_ldap_server if RUN_LDAP_TESTS
|
||||
end
|
||||
|
||||
def test_authenticate_against_ldap
|
||||
add_ldap_user_to_ldap_repository
|
||||
assert SimpleLdapAuthenticator.valid?('john', 'deere')
|
||||
user = User.authenticate('john', 'deere')
|
||||
assert_not_nil(user)
|
||||
assert_equal user.login, 'john'
|
||||
end
|
||||
|
||||
private :test_authenticate_against_ldap unless RUN_LDAP_TESTS
|
||||
|
||||
def setup_ldap_server_conf
|
||||
@slapd_conf = create_slapd_conf()
|
||||
open(@slapd_conf.path) { |f| f.read }
|
||||
unless File.exist?(SLAPD_BIN)
|
||||
assert false, "slapd could not be found at #{SLAPD_BIN}. Adjust the path in #{__FILE__}"
|
||||
end
|
||||
end
|
||||
|
||||
def start_ldap_server
|
||||
t = Thread.new(@slapd_conf.path) do |slapd_conf_path|
|
||||
puts "starting slapd..." if OUTPUT_DEBUG_INFO
|
||||
run_cmd %Q{/usr/libexec/slapd -f #{slapd_conf_path} -h "ldap://127.0.0.1:10389/" -d0}
|
||||
end
|
||||
sleep(2)
|
||||
run_cmd %Q{ldapsearch -H "ldap://127.0.0.1:10389/" -x -b '' -s base '(objectclass=*)' namingContexts}
|
||||
end
|
||||
|
||||
def add_ldap_user_to_ldap_repository
|
||||
ldif_file = create_ldif()
|
||||
run_cmd %Q{ldapadd -H "ldap://127.0.0.1:10389/" -f #{ldif_file.path} -cxv -D "cn=Manager,dc=lukemelia,dc=com" -w secret}
|
||||
puts `cat #{ldif_file.path}` if OUTPUT_DEBUG_INFO
|
||||
end
|
||||
|
||||
def stop_ldap_server
|
||||
pid = open(get_pid_file_path(@slapd_conf)) { |f| f.read }
|
||||
run_cmd "kill -TERM #{pid}"
|
||||
end
|
||||
|
||||
def create_slapd_conf
|
||||
slapd_conf = Tempfile.new("slapd.conf")
|
||||
slapd_conf.path
|
||||
data_dir = slapd_conf.path + '-data'
|
||||
pid_file = get_pid_file_path(slapd_conf)
|
||||
Dir.mkdir(data_dir)
|
||||
encrypted_password = `slappasswd -s secret`
|
||||
open(slapd_conf.path, 'w') do |f|
|
||||
f.puts %Q{include #{SLAPD_SCHEMA_DIR}core.schema
|
||||
pidfile #{pid_file}
|
||||
database ldbm
|
||||
suffix "dc=lukemelia,dc=com"
|
||||
rootdn "cn=Manager,dc=lukemelia,dc=com"
|
||||
rootpw #{encrypted_password}
|
||||
directory #{data_dir}
|
||||
|
||||
access to *
|
||||
by self write
|
||||
by users read
|
||||
by anonymous auth
|
||||
}
|
||||
end
|
||||
puts `cat #{slapd_conf.path}` if OUTPUT_DEBUG_INFO
|
||||
slapd_conf
|
||||
end
|
||||
|
||||
def create_ldif
|
||||
ldif_file = Tempfile.new("ldap_user.ldif")
|
||||
encrypted_password = `slappasswd -s deere`
|
||||
open(ldif_file.path, 'w') do |f|
|
||||
f.puts %Q{dn: dc=lukemelia,dc=com
|
||||
objectclass: dcObject
|
||||
objectclass: organization
|
||||
o: Luke Melia DotCom
|
||||
dc: lukemelia
|
||||
|
||||
dn: cn=john,dc=lukemelia,dc=com
|
||||
cn: john
|
||||
sn: john
|
||||
objectclass: person
|
||||
userPassword: #{encrypted_password}
|
||||
}
|
||||
end
|
||||
ldif_file
|
||||
end
|
||||
|
||||
def run_cmd(cmd)
|
||||
puts cmd if OUTPUT_DEBUG_INFO
|
||||
cmd_out = `#{cmd}`
|
||||
puts cmd_out if OUTPUT_DEBUG_INFO
|
||||
end
|
||||
|
||||
def get_pid_file_path(tempfile)
|
||||
tempfile.path + '.pid'
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue