mirror of
https://github.com/TracksApp/tracks.git
synced 2025-12-23 18:50:12 +01:00
get dependency add/remove from new_action_form running
This commit is contained in:
parent
92fdef2b1b
commit
1f67d2a603
7 changed files with 93 additions and 95 deletions
|
|
@ -36,7 +36,6 @@ class ApplicationController < ActionController::Base
|
||||||
before_filter :set_locale
|
before_filter :set_locale
|
||||||
prepend_before_filter :login_required
|
prepend_before_filter :login_required
|
||||||
prepend_before_filter :enable_mobile_content_negotiation
|
prepend_before_filter :enable_mobile_content_negotiation
|
||||||
# after_filter :set_locale
|
|
||||||
after_filter :set_charset
|
after_filter :set_charset
|
||||||
|
|
||||||
include ActionView::Helpers::TextHelper
|
include ActionView::Helpers::TextHelper
|
||||||
|
|
@ -137,8 +136,8 @@ class ApplicationController < ActionController::Base
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def auto_complete_result2(entries, phrase = nil)
|
def format_dependencies_as_json_for_auto_complete(entries)
|
||||||
json_elems = "[{" + entries.map {|item| "\"id\" : \"#{item.id}\", \"value\" : \"#{item.specification()}\""}.join("},{") + "}]"
|
json_elems = "[{" + entries.map {|item| "\"value\" : \"#{item.id}\", \"label\" : \"#{item.specification()}\""}.join("},{") + "}]"
|
||||||
return json_elems == "[{}]" ? "" : json_elems
|
return json_elems == "[{}]" ? "" : json_elems
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ class TodosController < ApplicationController
|
||||||
def create
|
def create
|
||||||
@source_view = params['_source_view'] || 'todo'
|
@source_view = params['_source_view'] || 'todo'
|
||||||
@default_context = current_user.contexts.find_by_name(params['default_context_name'])
|
@default_context = current_user.contexts.find_by_name(params['default_context_name'])
|
||||||
@default_project = current_user.projects.find_by_name(params['default_project_name'])
|
@default_project = current_user.projects.find_by_name(params['default_project_name']) unless params['default_project_name'].blank?
|
||||||
|
|
||||||
@tag_name = params['_tag_name']
|
@tag_name = params['_tag_name']
|
||||||
|
|
||||||
|
|
@ -248,6 +248,7 @@ class TodosController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_predecessor
|
def remove_predecessor
|
||||||
|
puts "@@@ start remove_predecessor"
|
||||||
@source_view = params['_source_view'] || 'todo'
|
@source_view = params['_source_view'] || 'todo'
|
||||||
@todo = current_user.todos.find(params['id'])
|
@todo = current_user.todos.find(params['id'])
|
||||||
@predecessor = current_user.todos.find(params['predecessor'])
|
@predecessor = current_user.todos.find(params['predecessor'])
|
||||||
|
|
@ -648,7 +649,7 @@ class TodosController < ApplicationController
|
||||||
get_todo_from_params
|
get_todo_from_params
|
||||||
# Begin matching todos in current project
|
# Begin matching todos in current project
|
||||||
@items = current_user.todos.find(:all,
|
@items = current_user.todos.find(:all,
|
||||||
:select => 'description, project_id, context_id, created_at',
|
:include => [:context, :project],
|
||||||
:conditions => [ '(todos.state = ? OR todos.state = ? OR todos.state = ?) AND ' +
|
:conditions => [ '(todos.state = ? OR todos.state = ? OR todos.state = ?) AND ' +
|
||||||
'NOT (id = ?) AND lower(description) LIKE ? AND project_id = ?',
|
'NOT (id = ?) AND lower(description) LIKE ? AND project_id = ?',
|
||||||
'active', 'pending', 'deferred',
|
'active', 'pending', 'deferred',
|
||||||
|
|
@ -660,7 +661,7 @@ class TodosController < ApplicationController
|
||||||
)
|
)
|
||||||
if @items.empty? # Match todos in other projects
|
if @items.empty? # Match todos in other projects
|
||||||
@items = current_user.todos.find(:all,
|
@items = current_user.todos.find(:all,
|
||||||
:select => 'description, project_id, context_id, created_at',
|
:include => [:context, :project],
|
||||||
:conditions => [ '(todos.state = ? OR todos.state = ? OR todos.state = ?) AND ' +
|
:conditions => [ '(todos.state = ? OR todos.state = ? OR todos.state = ?) AND ' +
|
||||||
'NOT (id = ?) AND lower(description) LIKE ?',
|
'NOT (id = ?) AND lower(description) LIKE ?',
|
||||||
'active', 'pending', 'deferred',
|
'active', 'pending', 'deferred',
|
||||||
|
|
@ -672,7 +673,7 @@ class TodosController < ApplicationController
|
||||||
else
|
else
|
||||||
# New todo - TODO: Filter on project
|
# New todo - TODO: Filter on project
|
||||||
@items = current_user.todos.find(:all,
|
@items = current_user.todos.find(:all,
|
||||||
:select => 'description, project_id, context_id, created_at',
|
:include => [:context, :project],
|
||||||
:conditions => [ '(todos.state = ? OR todos.state = ? OR todos.state = ?) AND lower(description) LIKE ?',
|
:conditions => [ '(todos.state = ? OR todos.state = ? OR todos.state = ?) AND lower(description) LIKE ?',
|
||||||
'active', 'pending', 'deferred',
|
'active', 'pending', 'deferred',
|
||||||
'%' + params[:term].downcase + '%' ],
|
'%' + params[:term].downcase + '%' ],
|
||||||
|
|
@ -680,7 +681,7 @@ class TodosController < ApplicationController
|
||||||
:limit => 10
|
:limit => 10
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
render :inline => auto_complete_result2(@items)
|
render :inline => format_dependencies_as_json_for_auto_complete(@items)
|
||||||
end
|
end
|
||||||
|
|
||||||
def convert_to_project
|
def convert_to_project
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,6 @@ module TodosHelper
|
||||||
page.todo { return !@todo.hidden? }
|
page.todo { return !@todo.hidden? }
|
||||||
page.deferred { return @todo.deferred? || @todo.pending? }
|
page.deferred { return @todo.deferred? || @todo.pending? }
|
||||||
page.context {
|
page.context {
|
||||||
logger.debug "ci=#{@todo.context_id} dci=#{@default_context.id} th=#{@todo.hidden?} tch=#{@todo.context.hidden?}"
|
|
||||||
return @todo.context_id==@default_context.id && ( (@todo.hidden? && @todo.context.hidden?) || (!@todo.hidden?) )
|
return @todo.context_id==@default_context.id && ( (@todo.hidden? && @todo.context.hidden?) || (!@todo.hidden?) )
|
||||||
}
|
}
|
||||||
page.tag {
|
page.tag {
|
||||||
|
|
@ -266,7 +265,7 @@ module TodosHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def default_contexts_for_autocomplete
|
def default_contexts_for_autocomplete
|
||||||
projects = current_user.projects.find(:all, :conditions => ['default_context_id is not null'])
|
projects = current_user.projects.find(:all, :include => [:context], :conditions => ['default_context_id is not null'])
|
||||||
Hash[*projects.map{ |p| [p.name, p.default_context.name] }.flatten].to_json
|
Hash[*projects.map{ |p| [p.name, p.default_context.name] }.flatten].to_json
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,84 +108,41 @@ class Todo < ActiveRecord::Base
|
||||||
|
|
||||||
# Returns a string with description <context, project>
|
# Returns a string with description <context, project>
|
||||||
def specification
|
def specification
|
||||||
project_name = project.is_a?(NullProject) ? "(none)" : project.name
|
project_name = self.project.is_a?(NullProject) ? "(none)" : self.project.name
|
||||||
return "\'#{description}\' <\'#{context.title}\'; \'#{project_name}\'>"
|
return "\'#{self.description}\' <\'#{self.context.title}\'; \'#{project_name}\'>"
|
||||||
end
|
|
||||||
|
|
||||||
def todo_from_specification(specification)
|
|
||||||
# Split specification into parts: description <context, project>
|
|
||||||
parts = specification.scan(RE_PARTS)
|
|
||||||
return nil unless parts.length == 1
|
|
||||||
return nil unless parts[0].length == 3
|
|
||||||
todo_description = parts[0][0]
|
|
||||||
context_name = parts[0][1]
|
|
||||||
project_name = parts[0][2]
|
|
||||||
|
|
||||||
# find the project
|
|
||||||
project_id = nil;
|
|
||||||
unless project_name == "(none)"
|
|
||||||
project = Project.first(:conditions => {
|
|
||||||
:user_id => self.user.id,
|
|
||||||
:name => project_name
|
|
||||||
})
|
|
||||||
project_id = project.id unless project.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
todos = Todo.all(
|
|
||||||
:joins => :context,
|
|
||||||
:conditions => {
|
|
||||||
:description => todo_description,
|
|
||||||
:user_id => self.user.id,
|
|
||||||
:contexts => {:name => context_name},
|
|
||||||
:project_id => project_id
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return nil if todos.empty?
|
|
||||||
|
|
||||||
# TODO: what todo if there are more than one todo that fit the specification
|
|
||||||
return todos[0]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate
|
def validate
|
||||||
if !show_from.blank? && show_from < user.date
|
if !show_from.blank? && show_from < user.date
|
||||||
errors.add("show_from", I18n.t('models.todo.error_date_must_be_future'))
|
errors.add("show_from", I18n.t('models.todo.error_date_must_be_future'))
|
||||||
end
|
end
|
||||||
errors.add(:description, "may not contain \" characters") if /\"/.match(description)
|
errors.add(:description, "may not contain \" characters") if /\"/.match(self.description)
|
||||||
unless @predecessor_array.nil? # Only validate predecessors if they changed
|
unless @predecessor_array.nil? # Only validate predecessors if they changed
|
||||||
@predecessor_array.each do |specification|
|
@predecessor_array.each do |todo|
|
||||||
t = todo_from_specification(specification)
|
errors.add("Depends on:", "Adding '#{h(todo.specification)}' would create a circular dependency") if is_successor?(todo)
|
||||||
if t.nil?
|
|
||||||
errors.add("Depends on:", "Could not find action '#{h(specification)}'")
|
|
||||||
else
|
|
||||||
errors.add("Depends on:", "Adding '#{h(specification)}' would create a circular dependency") if is_successor?(t)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def save_predecessors
|
def save_predecessors
|
||||||
unless @predecessor_array.nil? # Only save predecessors if they changed
|
unless @predecessor_array.nil? # Only save predecessors if they changed
|
||||||
current_array = predecessors.map{|p| p.specification}
|
current_array = self.predecessors
|
||||||
remove_array = current_array - @predecessor_array
|
remove_array = current_array - @predecessor_array
|
||||||
add_array = @predecessor_array - current_array
|
add_array = @predecessor_array - current_array
|
||||||
|
|
||||||
@removed_predecessors = []
|
@removed_predecessors = []
|
||||||
# This is probably a bit naive code...
|
remove_array.each do |todo|
|
||||||
remove_array.each do |specification|
|
unless todo.nil?
|
||||||
t = todo_from_specification(specification)
|
@removed_predecessors << todo
|
||||||
unless t.nil?
|
self.predecessors.delete(todo)
|
||||||
@removed_predecessors << t
|
|
||||||
self.predecessors.delete(t)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# ... as is this?
|
|
||||||
add_array.each do |specification|
|
add_array.each do |todo|
|
||||||
t = todo_from_specification(specification)
|
unless todo.nil?
|
||||||
unless t.nil?
|
self.predecessors << todo unless self.predecessors.include?(todo)
|
||||||
self.predecessors << t unless self.predecessors.include?(t)
|
|
||||||
else
|
else
|
||||||
logger.error "Could not find #{specification}" # Unexpected since validation passed
|
logger.error "Could not find #{todo.description}" # Unexpected since validation passed
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -196,20 +153,22 @@ class Todo < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_predecessor(predecessor)
|
def remove_predecessor(predecessor)
|
||||||
|
puts "@@@ before delete"
|
||||||
# remove predecessor and activate myself
|
# remove predecessor and activate myself
|
||||||
predecessors.delete(predecessor)
|
self.predecessors.delete(predecessor)
|
||||||
|
puts "@@@ before activate"
|
||||||
self.activate!
|
self.activate!
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns true if t is equal to self or a successor of self
|
# Returns true if t is equal to self or a successor of self
|
||||||
def is_successor?(t)
|
def is_successor?(todo)
|
||||||
if self == t
|
if self == todo
|
||||||
return true
|
return true
|
||||||
elsif self.successors.empty?
|
elsif self.successors.empty?
|
||||||
return false
|
return false
|
||||||
else
|
else
|
||||||
self.successors.each do |item|
|
self.successors.each do |item|
|
||||||
if item.is_successor?(t)
|
if item.is_successor?(todo)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -314,12 +273,20 @@ class Todo < ActiveRecord::Base
|
||||||
|
|
||||||
def add_predecessor_list(predecessor_list)
|
def add_predecessor_list(predecessor_list)
|
||||||
return unless predecessor_list.kind_of? String
|
return unless predecessor_list.kind_of? String
|
||||||
@predecessor_array = predecessor_list.scan(RE_SPEC)
|
|
||||||
|
@predecessor_array=[]
|
||||||
|
|
||||||
|
predecessor_ids_array = predecessor_list.split(", ")
|
||||||
|
predecessor_ids_array.each do |todo_id|
|
||||||
|
predecessor = self.user.todos.find_by_id( todo_id.to_i ) unless todo_id.blank?
|
||||||
|
@predecessor_array << predecessor unless predecessor.nil?
|
||||||
|
end
|
||||||
|
|
||||||
return @predecessor_array
|
return @predecessor_array
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_predecessor(t)
|
def add_predecessor(t)
|
||||||
@predecessor_array = predecessors.map{|p| p.specification}
|
@predecessor_array = predecessors
|
||||||
@predecessor_array << t.specification
|
@predecessor_array << t.specification
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,17 +34,13 @@
|
||||||
<%= t.text_field("show_from", "size" => 12, "class" => "Date", "tabindex" => 7, "autocomplete" => "off") %>
|
<%= t.text_field("show_from", "size" => 12, "class" => "Date", "tabindex" => 7, "autocomplete" => "off") %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label for="predecessor_list"><%= Todo.human_attribute_name('predecessors')%></label>
|
<label for="predecessor_input"><%= Todo.human_attribute_name('predecessors')%></label>
|
||||||
<%= text_field_tag "predecessor_list", nil, :size => 30, :tabindex => 8 %>
|
|
||||||
|
|
||||||
<div class="predecessor_add_button_box">
|
|
||||||
<input class="predecessor_add_button" type="button" value="Add"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="selected_predecessors">
|
<div class="selected_predecessors">
|
||||||
<ul id="predecessor_ul" style="display:none">
|
<ul id="predecessor_ul" style="display:none">
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<%= t('common.add')%>: <%= text_field_tag "predecessor_input", nil, :size => 30, :tabindex => 8 %>
|
||||||
|
<%= hidden_field_tag "predecessor_list", ""%>
|
||||||
|
|
||||||
<%= source_view_tag( @source_view ) %>
|
<%= source_view_tag( @source_view ) %>
|
||||||
<%= hidden_field_tag :_tag_name, @tag_name.underscore.gsub(/\s+/,'_') if source_view_is :tag %>
|
<%= hidden_field_tag :_tag_name, @tag_name.underscore.gsub(/\s+/,'_') if source_view_is :tag %>
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ en:
|
||||||
logout: "Logout"
|
logout: "Logout"
|
||||||
cancel: "Cancel"
|
cancel: "Cancel"
|
||||||
ok: "Ok"
|
ok: "Ok"
|
||||||
|
add: "Add"
|
||||||
project: "Project"
|
project: "Project"
|
||||||
projects: "Projects"
|
projects: "Projects"
|
||||||
context: "Context"
|
context: "Context"
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ var TracksForm = {
|
||||||
});
|
});
|
||||||
|
|
||||||
$('input[class=predecessor_add_button]').live('click', function(){
|
$('input[class=predecessor_add_button]').live('click', function(){
|
||||||
var text = $('input[name=predecessor]').val();
|
var text = $('input[name=predecessor_list]').val();
|
||||||
if (text.length > 0) {
|
if (text.length > 0) {
|
||||||
$('ul#predecessor_ul').show();
|
$('ul#predecessor_ul').show();
|
||||||
if (text.length > 35) {
|
if (text.length > 35) {
|
||||||
|
|
@ -844,7 +844,7 @@ $(document).ajaxSend(function(event, request, settings) {
|
||||||
}
|
}
|
||||||
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||||
}
|
}
|
||||||
request.setRequestHeader("X-CSRF-Token", $('meta[name=csrf-token]').attr('content'));
|
request.setRequestHeader('X-CSRF-Token', $('meta[name=csrf-token]').attr('content'));
|
||||||
request.setRequestHeader("Accept", "text/javascript");
|
request.setRequestHeader("Accept", "text/javascript");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -992,10 +992,10 @@ function enable_rich_interaction(){
|
||||||
.autocomplete({
|
.autocomplete({
|
||||||
minLength: 0,
|
minLength: 0,
|
||||||
source: function( request, response ) {
|
source: function( request, response ) {
|
||||||
var last_term = extractLast( request.term );
|
term = request.term;
|
||||||
if (last_term != "" && last_term != " ")
|
if (term != "" && term != " ")
|
||||||
$.getJSON( relative_to_root('auto_complete_for_predecessor'), {
|
$.getJSON( relative_to_root('auto_complete_for_predecessor'), {
|
||||||
term: last_term
|
term: term
|
||||||
}, response );
|
}, response );
|
||||||
},
|
},
|
||||||
focus: function() {
|
focus: function() {
|
||||||
|
|
@ -1003,18 +1003,53 @@ function enable_rich_interaction(){
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
select: function( event, ui ) {
|
select: function( event, ui ) {
|
||||||
var terms = split( this.value );
|
// retrieve values from input fields
|
||||||
// remove the current input
|
todo_spec = ui.item.label
|
||||||
terms.pop();
|
todo_id = ui.item.value
|
||||||
// add the selected item
|
predecessor_list = $('input[name=predecessor_list]')
|
||||||
terms.push( ui.item.value );
|
id_list = split( predecessor_list.val() );
|
||||||
// add placeholder to get the comma-and-space at the end
|
|
||||||
//terms.push( "" );
|
// add the dependency to id list
|
||||||
this.value = terms.join( ", " );
|
id_list.push( todo_id );
|
||||||
|
predecessor_list.val( id_list.join( ", " ) );
|
||||||
|
|
||||||
|
// show the html for the list of deps
|
||||||
|
$('ul#predecessor_ul').show();
|
||||||
|
if (todo_spec.length > 35) { // cut off string
|
||||||
|
todo_spec = todo_spec.substring(0,35)+"...";
|
||||||
|
}
|
||||||
|
// show the new dep in list
|
||||||
|
var html = $('ul#predecessor_ul').html();
|
||||||
|
var new_li = "<li style=\"display:none\" id=\"pred_"+todo_id+"\"><input class=\"pred_remove_button\" id=\""+todo_id+"\" type=\"button\" value=\"x\"/> "+ todo_spec + "</li>";
|
||||||
|
$('ul#predecessor_ul').html(html + new_li);
|
||||||
|
$('li#pred_'+todo_id).slideDown(500);
|
||||||
|
|
||||||
|
$('input[name=predecessor_input]').val('');
|
||||||
|
$('input[name=predecessor_input]').focus();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('input[class=pred_remove_button]').live('click', function() {
|
||||||
|
predecessor_list = $('input[name=predecessor_list]');
|
||||||
|
id_list = split( predecessor_list.val() );
|
||||||
|
$("li#pred_"+this.id).slideUp(500).remove(); // remove from ul
|
||||||
|
|
||||||
|
// remove from array
|
||||||
|
new_list = new Array();
|
||||||
|
while (id_list.length > 0) {
|
||||||
|
elem = id_list.pop();
|
||||||
|
if (elem != this.id && elem != '' && elem != ' ') {
|
||||||
|
new_list.push ( elem );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update id list
|
||||||
|
predecessor_list.val( new_list.join(", ") );
|
||||||
|
|
||||||
|
return false; // prevent submit
|
||||||
|
})
|
||||||
|
|
||||||
/* have to bind on keypress because of limitations of live() */
|
/* have to bind on keypress because of limitations of live() */
|
||||||
$('input[name=project_name]').live('keypress', function(){
|
$('input[name=project_name]').live('keypress', function(){
|
||||||
$(this).bind('blur', project_defaults);
|
$(this).bind('blur', project_defaults);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue