Dynamically load autocompletes

This cuts something like 100ms off of page load times!

Closes #1011
This commit is contained in:
Eric Allen 2010-04-02 13:23:24 -04:00
parent 8de74939ea
commit 9ab69adb38
10 changed files with 30 additions and 24 deletions

View file

@ -123,6 +123,11 @@ class ApplicationController < ActionController::Base
formatted_date formatted_date
end end
def for_autocomplete(coll)
coll.map {|item| "#{item.name}|#{item.id}"}.join("\n")
end
# Uses RedCloth to transform text using either Textile or Markdown Need to # Uses RedCloth to transform text using either Textile or Markdown Need to
# require redcloth above RedCloth 3.0 or greater is needed to use Markdown, # require redcloth above RedCloth 3.0 or greater is needed to use Markdown,
# otherwise it only handles Textile # otherwise it only handles Textile

View file

@ -22,6 +22,7 @@ class ContextsController < ApplicationController
format.rss &render_contexts_rss_feed format.rss &render_contexts_rss_feed
format.atom &render_contexts_atom_feed format.atom &render_contexts_atom_feed
format.text { render :action => 'index', :layout => false, :content_type => Mime::TEXT } format.text { render :action => 'index', :layout => false, :content_type => Mime::TEXT }
format.autocomplete { render :text => for_autocomplete(@active_contexts + @hidden_contexts)}
end end
end end

View file

@ -26,6 +26,7 @@ class ProjectsController < ApplicationController
format.rss &render_rss_feed format.rss &render_rss_feed
format.atom &render_atom_feed format.atom &render_atom_feed
format.text &render_text_feed format.text &render_text_feed
format.autocomplete { render :text => for_autocomplete(@projects) }
end end
end end
end end

View file

@ -526,6 +526,13 @@ class TodosController < ApplicationController
} }
end end
end end
def tags
@tags = Tag.all
respond_to do |format|
format.autocomplete { render :text => for_autocomplete(@tags) }
end
end
def defer def defer
@source_view = params['_source_view'] || 'todo' @source_view = params['_source_view'] || 'todo'

View file

@ -276,20 +276,6 @@ module TodosHelper
return "c#{todo.context_id}empty-nd" return "c#{todo.context_id}empty-nd"
end end
def project_names_for_autocomplete
array_or_string_for_javascript( ['None'] + current_user.projects.active.collect{|p| escape_javascript(p.name) } )
end
def context_names_for_autocomplete
# #return array_or_string_for_javascript(['Create a new context']) if
# @contexts.empty?
array_or_string_for_javascript( current_user.contexts.collect{|c| escape_javascript(c.name) } )
end
def tag_names_for_autocomplete
array_or_string_for_javascript( Tag.all.collect{|c| escape_javascript(c.name) } )
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, :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

View file

@ -14,11 +14,8 @@
<%= javascript_tag "var SOURCE_VIEW = '#{@source_view}';" %> <%= javascript_tag "var SOURCE_VIEW = '#{@source_view}';" %>
<%= javascript_tag "var TAG_NAME = '#{@tag_name}';" if @tag_name %> <%= javascript_tag "var TAG_NAME = '#{@tag_name}';" if @tag_name %>
<script type="text/javascript"> <script type="text/javascript">
var contextNames = <%= context_names_for_autocomplete rescue '[]' %>;
var projectNames = <%= project_names_for_autocomplete rescue '[]' %>;
var defaultContexts = <%= default_contexts_for_autocomplete rescue '{}' %>; var defaultContexts = <%= default_contexts_for_autocomplete rescue '{}' %>;
var defaultTags = <%= default_tags_for_autocomplete rescue '{}' %>; var defaultTags = <%= default_tags_for_autocomplete rescue '{}' %>;
var tagNames = <%= tag_names_for_autocomplete rescue '[]' %>;
var dateFormat = '<%= date_format_for_date_picker %>'; var dateFormat = '<%= date_format_for_date_picker %>';
var weekStart = '<%= current_user.prefs.week_starts %>'; var weekStart = '<%= current_user.prefs.week_starts %>';
function relative_to_root(path) { return '<%= root_url %>'+path; }; function relative_to_root(path) { return '<%= root_url %>'+path; };

View file

@ -1,4 +1,5 @@
# Add new mime types for use in respond_to blocks: # Add new mime types for use in respond_to blocks:
# Mime::Type.register "text/richtext", :rtf # Mime::Type.register "text/richtext", :rtf
# Mime::Type.register "application/x-mobile", :mobile # Mime::Type.register "application/x-mobile", :mobile
Mime::Type.register_alias "text/html", :m Mime::Type.register_alias "text/html", :m
Mime::Type.register_alias "text/plain", :autocomplete

View file

@ -44,6 +44,9 @@ ActionController::Routing::Routes.draw do |map|
# routed to mobile view of tags. # routed to mobile view of tags.
todos.tag 'todos/tag/:name.m', :action => "tag", :format => 'm' todos.tag 'todos/tag/:name.m', :action => "tag", :format => 'm'
todos.tag 'todos/tag/:name', :action => "tag", :name => /.*/ todos.tag 'todos/tag/:name', :action => "tag", :name => /.*/
todos.tags 'tags.autocomplete', :action => "tags", :format => 'autocomplete'
todos.auto_complete_for_predecessor 'auto_complete_for_predecessor', :action => 'auto_complete_for_predecessor'
todos.calendar 'calendar.ics', :action => "calendar", :format => 'ics' todos.calendar 'calendar.ics', :action => "calendar", :format => 'ics'
todos.calendar 'calendar', :action => "calendar" todos.calendar 'calendar', :action => "calendar"

View file

@ -187,11 +187,16 @@ function project_defaults(){
function enable_rich_interaction(){ function enable_rich_interaction(){
$('input.Date').datepicker({'dateFormat': dateFormat, 'firstDay': weekStart}); $('input.Date').datepicker({'dateFormat': dateFormat, 'firstDay': weekStart});
/* Autocomplete */ /* Autocomplete */
$('input[name=context_name]').autocomplete(contextNames, {matchContains: true}); $('input[name=context_name]').autocomplete(
$('input[name=project[default_context_name]]').autocomplete(contextNames, {matchContains: true}); relative_to_root('contexts.autocomplete'), {matchContains: true});
$('input[name=project_name]').autocomplete(projectNames, {matchContains: true}); $('input[name=project[default_context_name]]').autocomplete(
$('input[name=tag_list]:not(.ac_input)').autocomplete(tagNames, {multiple: true,multipleSeparator:',',matchContains:true}); relative_to_root('contexts.autocomplete'), {matchContains: true});
$('input[name=predecessor_list]:not(.ac_input)').autocomplete('/todos/auto_complete_for_predecessor', $('input[name=project_name]').autocomplete(
relative_to_root('projects.autocomplete'), {matchContains: true});
$('input[name=tag_list]:not(.ac_input)').autocomplete(
relative_to_root('tags.autocomplete'), {multiple: true,multipleSeparator:',',matchContains:true});
$('input[name=predecessor_list]:not(.ac_input)').autocomplete(
relative_to_root('auto_complete_for_predecessor'),
{multiple: true,multipleSeparator:','}); {multiple: true,multipleSeparator:','});
/* have to bind on keypress because of limitataions of live() */ /* have to bind on keypress because of limitataions of live() */

View file

@ -364,7 +364,7 @@ $.Autocompleter = function(input, options) {
// limit abortion to this input // limit abortion to this input
port: "autocomplete" + input.name, port: "autocomplete" + input.name,
dataType: options.dataType, dataType: options.dataType,
type: 'POST', type: 'GET',
url: options.url, url: options.url,
data: $.extend({ data: $.extend({
q: lastWord(term), q: lastWord(term),