Skip to content

Commit

Permalink
Merge branch 'locations_autocomplete' into next-release
Browse files Browse the repository at this point in the history
  • Loading branch information
kclair committed Mar 16, 2011
2 parents d00c482 + e208371 commit e5df799
Show file tree
Hide file tree
Showing 24 changed files with 279 additions and 132 deletions.
31 changes: 28 additions & 3 deletions app/controllers/autocomplete_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,20 +86,45 @@ def senders
render_entities_to_json(senders)
end

def locations
if params[:country].blank? or params[:country] == 'Country'
locations = []
elsif params[:query] == ""
# we could preload if we had the country, but this is still expensive if there are a lot of places
# perhaps we could do a count first and preload if it's a reasonable amount, or preload cities witha high population?
#locations = GeoPlace.find(:all, :conditions => ["geo_country_id = ?", params[:country]])
locations = []
else
country = GeoCountry.find(params[:country])
locations = country.geo_places.named_like(params[:query]).largest(10)
end
render_locations_to_json(locations)
end

private

def render_entities_to_json(entities)
render :json => {
:query => params[:query],
:suggestions => entities.collect{|entity|display_on_two_lines(entity)},
:suggestions => entities.collect{|e|display_on_two_lines(e.display_name, h(e.name))},
:data => entities.collect{|e|e.avatar_id||0}
}
end

def render_locations_to_json(locations)
render :json => {
:query => params[:query],
:suggestions => locations.collect{|loc|display_on_two_lines(loc.name, loc.geo_admin_code.name)},
:data => locations.collect{|loc|loc.id}
}
end


# this should be in a helper somewhere, but i don't know how to generate
# json response in the view.
def display_on_two_lines(entity)
"<em>%s</em>%s" % [entity.display_name, ('<br/>' + h(entity.name) if entity.display_name != entity.name)]
def display_on_two_lines(first, second)
"<em>%s</em>%s" % [first, ('<br/>' + second if second != first)]
#"<em>%s</em>%s" % [entity.display_name, ('<br/>' + h(entity.name) if entity.display_name != entity.name)]
end

end
2 changes: 1 addition & 1 deletion app/controllers/groups/directory_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class Groups::DirectoryController < Groups::BaseController

helper 'locations'
helper 'locations', 'autocomplete'
layout 'directory'
before_filter :set_group_type

Expand Down
16 changes: 9 additions & 7 deletions app/controllers/groups/profiles_controller.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
class Groups::ProfilesController < Groups::BaseController
permissions 'groups/requests'

helper 'profile', 'groups', 'locations', 'groups/permissions'
helper 'profile', 'groups', 'locations', 'groups/permissions', 'autocomplete'
before_filter :fetch_data, :login_required

def show
Expand Down Expand Up @@ -30,13 +30,15 @@ def update
@profile.photo.destroy; @profile.photo = nil
elsif params[:clear_video]
@profile.video.destroy; @profile.video = nil
elsif params[:location_only]
@profile.update_location(params)
else
@profile.save_from_params params['profile']
if @profile.valid?
flash_message_now :success
else
flash_message_now :object => @profile
end
@profile.save_from_params params['profile']
if @profile.valid?
flash_message_now :success
else
flash_message_now :object => @profile
end
end
end

Expand Down
80 changes: 26 additions & 54 deletions app/controllers/locations_controller.rb
Original file line number Diff line number Diff line change
@@ -1,71 +1,43 @@
class LocationsController < ApplicationController

def all_admin_codes_options
helper 'autocomplete'
permissions 'profile'

# def all_admin_codes_options
def country_dropdown_onchange
return unless request.xhr?
# can select 'Country' which isn't really a country, and that should reset the form
if params[:country_code] == "Country"
geo_admin_codes = []
else
geo_admin_codes = GeoCountry.find_by_id(params[:country_code]).geo_admin_codes
end
geo_admin_codes = (params[:show_admin_codes] and params[:country_code] != 'Country') ?
GeoCountry.find_by_id(params[:country_code]).geo_admin_codes : []
# do not try to update models unless there is a current profile (ie don't update models when in search)
update_model_with_country(params[:country_code]) if @profile = Profile.find_by_id(params[:profile_id])
render :update do |page|
page.replace 'state_dropdown', :partial => '/locations/state_dropdown', :locals => {:display=>'inline', :name => params[:select_state_name], :geo_admin_codes => geo_admin_codes}
page.show 'state_dropdown'
# these messy next three lines reload the autocomplete js with the newly selected country
page << "$$('option.newselected').collect(function(el){el.removeClassName('newselected')});"
page << "$('select_country_id').select('[value=\"#{params[:country_code]}\"]')[0].addClassName('newselected');"
page.replace 'autocomplete_js', :partial => '/locations/autocomplete_js'
if params[:show_admin_codes]
page.replace 'state_dropdown', :partial => '/locations/state_dropdown', :locals => {:display=>'inline', :name => params[:select_state_name], :geo_admin_codes => geo_admin_codes}
page.show 'state_dropdown'
end
page.show 'city_text'
page['city_text_field'].value = ''
page['city_id_field'].value = ''
page.show 'submit_loc' if params[:show_submit] == 'true'
#page.show 'submit_loc' if params[:show_submit] == 'true'
end
end

def city_lookup
city = params[:city]
country_id = params[:country_id]
admin_code_id = params[:admin_code_id]
if params[:city_id_field] =~ /\S+/
name = params[:city_id_field]+'[city_id]'
else
name = 'city_id'
end
html = ''
if city.empty?
render :update do |page|
page["city_id_field"].value=''
end
return
end
return if country_id.empty?
@places = GeoPlace.with_names_matching(city, country_id, params)
if @places.empty?
render :update do |page|
page.replace_html 'city_results_box', "No cities matching '#{city}' found."
page.show 'city_results_box'
end
elsif @places.size == 1
return_single_city(@places[0])
else
render :update do |page|
page.replace_html 'city_results_box', :partial => '/locations/link_to_city_id', :locals => {:name => params[:city_id_name]}
page.show 'city_results_box'
end
def update_city_id
return unless request.xhr?
render :update do |page|
page["city_id_field"].value= params[:city_id]
end
end

def select_city_id
city_id = params[:city_id]
return_single_city(GeoPlace.find(city_id))
end

private

def return_single_city(geoplace)
html_for_text_box = geoplace.name.capitalize
html = "<input type='hidden' value='#{geoplace.id}' name='#{params[:city_id_name]}' id='city_id_field' />"
render :update do |page|
page["admin_code_#{geoplace.geo_admin_code.id}"].selected = true
page['city_text_field'].value = html_for_text_box
page.replace_html 'city_results', html
page.hide 'city_results_box'
end
def update_model_with_country(id)
return unless may_edit_location_profile?(@profile.entity)
@profile.update_location({:country_id => id})
end

end
8 changes: 7 additions & 1 deletion app/controllers/profile_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ class ProfileController < ApplicationController

before_filter :fetch_profile, :login_required
stylesheet 'profile'
helper 'me/base', 'locations'
helper 'me/base', 'locations', 'autocomplete'
#permissions 'profiles'
verify :method => :post, :only => :update
layout 'header'
Expand All @@ -20,6 +20,12 @@ def edit
end
end
end

def edit_location
return unless request.xhr?
@profile.update_location(params)
render :nothing => true
end

# ajax
def add_location
Expand Down
51 changes: 46 additions & 5 deletions app/helpers/autocomplete_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,25 @@ module AutocompleteHelper
#
def autocomplete_entity_tag(field_id, options={})
options[:url] ||= '/autocomplete/entities'
# sometimes we might want to make some fancy serviceURL involving some js
serviceurl = options[:serviceurl] || "serviceUrl:'#{options[:url]}'"
options[:onselect] ||= 'null'
options[:renderer] ||= render_entity_row_function
options[:selectvalue] ||= extract_value_from_entity_row_function
preload = options[:nopreload] ? false : true
auto_complete_js = %Q[
#{options[:additional_js]}
new Autocomplete('#{field_id}', {
serviceUrl:'#{options[:url]}',
#{serviceurl},
minChars:2,
maxHeight:400,
width:300,
width:340,
onSelect: #{options[:onselect]},
message: '#{escape_javascript(options[:message])}',
container: '#{options[:container]}',
preloadedOnTop: true,
rowRenderer: #{render_entity_row_function},
selectValue: #{extract_value_from_entity_row_function}
preloadedOnTop: #{preload},
rowRenderer: #{options[:renderer]},
selectValue: #{options[:selectvalue]}
}, #{autocomplete_id_number});
]
javascript_tag(auto_complete_js)
Expand All @@ -44,6 +50,32 @@ def autocomplete_friends_tag(field_id, options={})
autocomplete_entity_tag(field_id, options.merge(:url => '/autocomplete/friends'))
end

def autocomplete_locations_tag(field_id, options={})
if @profile and @profile.entity.is_a?(Group)
remote_url = {:controller => 'groups/profiles', :action => 'edit', :id => @profile.entity}
elsif @profile
remote_url = {:controller => 'profile', :action => 'edit_location', :id => @profile.type}
else
remote_url = {:controller => 'locations', :action => 'update_city_id'}
end
find_selected_country_js = "function getCountry() { if ($$('option.newselected')[0]) { return $$('option.newselected')[0].readAttribute('value'); } else { return $('select_country_id').getValue(); } }"
add_action = {
:url => remote_url,
:with => %{'location_only=1&country_id='+getCountry()+'&city_id=' + data }
#:loading => spinner_icon_on('plus', add_button_id),
#:complete => spinner_icon_off('plus', add_button_id)
}
after_update_function = "function(value, data) {#{remote_function(add_action)}; }"# if @profile
autocomplete_entity_tag(field_id,
options.merge(:serviceurl => "serviceUrl:'/autocomplete/locations/?country='+getCountry()",
:renderer => render_location_row_function,
:additional_js => find_selected_country_js,
:selectvalue => extract_value_from_locations_row_function,
:onselect => after_update_function,
:nopreload => true )
)
end

private

def autocomplete_id_number
Expand All @@ -59,9 +91,18 @@ def render_entity_row_function
%Q[function(value, re, data) {return '<p class=\"name_icon xsmall\" style=\"background-image: url(/avatars/'+data+'/xsmall.jpg)\">' + value.replace(/^<em>(.*)<\\/em>(<br\\/>(.*))?$/gi, function(m, m1, m2, m3){return '<em>' + Autocomplete.highlight(m1,re) + '</em>' + (m3 ? '<br/>' + Autocomplete.highlight(m3, re) : '')}) + '</p>';}]
end

def render_location_row_function
%Q[function(value, re, data) {return value.replace(/^<em>(.*)<\\/em>(<br\\/>(.*))?$/gi, function(m, m1, m2, m3){return '<em>' + Autocomplete.highlight(m1,re) + '</em>' + (m3 ? ', ' + Autocomplete.highlight(m3, re) : '')});}]
end

# called to convert the row data into a value
def extract_value_from_entity_row_function
%Q[function(value){ var reEntity = new RegExp; if (value.match(/<br\\/>/)) { reEntity = /.*<br\\/>(\\S+).*/g; }else { reEntity = /<em>(.*)<\\/em>.*/g; } return value.replace(reEntity,'$1');}]
end

def extract_value_from_locations_row_function
%Q[function(value){ var reEntity = new RegExp; if (value.match(/<br\\/>/)) { reEntity = /<em>(.*)<\\/em><br\\/>(.*)/g; return value.replace(reEntity,'$1, $2');}else { reEntity = /<em>(.*)<\\/em>.*/g; return value.replace(reEntity, '$1'); }}]
end


end
2 changes: 1 addition & 1 deletion app/helpers/layout_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def language_direction
EXTRA_JS = {:extra => ['dragdrop', 'builder', 'slider']}

# needed whenever we want controls for editing a wiki
WIKI_JS = {:wiki => ['wiki/html_editor', 'wiki/textile_editor', 'wiki/wiki_editing', 'wiki/xinha/XinhaCore']}
WIKI_JS = {:wiki => ['wiki/html_editor', 'wiki/textile_editor', 'wiki/wiki_editing', 'wiki/xinha/XinhaLoader']}

JS_BUNDLES = [MAIN_JS, EXTRA_JS, WIKI_JS]

Expand Down
52 changes: 34 additions & 18 deletions app/helpers/locations_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,29 @@ module LocationsHelper

# <%= select('group','location', GeoCountry.find(:all).to_select(:name, :code), {:include_blank => true}) %>
def country_dropdown(object=nil, method=nil, options={})
profile_id_param = @profile ? "profile_id=#{@profile.id}&" : nil
name = _field_name('country_id', object, method)
show_submit = options[:show_submit] || false
onchange = remote_function(
:url => {:controller => '/locations', :action => 'all_admin_codes_options'},
:with => "'select_state_name='+$('select_state_id').name+'&show_submit=#{show_submit}&country_code='+value",
:url => {:controller => '/locations', :action => 'country_dropdown_onchange'},
:with => "'#{profile_id_param}country_code='+value",
:loading => show_spinner('country'),
:complete => hide_spinner('country')
)
choices = [ I18n.t(:location_country).capitalize].concat(GeoCountry.find(:all).to_select(:name, :id))
opts = (object.nil? and method.nil? and params[:country_id]) ? {:selected => params[:country_id]} : {}
render :partial => '/locations/country_dropdown', :locals => {:object => object, :method => method, :onchange => onchange, :name=>name, :choices => choices, :opts => opts}
choices = country_choices
render :partial => '/locations/country_dropdown', :locals => {:object => object, :method => method, :onchange => onchange, :name=>name, :choices => choices, :opts => {} }
end

def country_dropdown_for_search
name = _field_name('country_id')
onchange = remote_function(
:url => {:controller => '/locations', :action => 'country_dropdown_onchange'},
:with => "'show_admin_codes=1&country_code='+value",
:loading => show_spinner('country'),
:complete => hide_spinner('country')
)
choices = country_choices
opts = params[:country_id] ? {:selected => params[:country_id]} : {}
render :partial => '/locations/country_dropdown', :locals => {:object => nil, :method => nil, :onchange => onchange, :name=>name, :choices => choices, :opts => opts}
end

def state_dropdown(object=nil, method=nil, country_id=nil, options={})
Expand All @@ -32,18 +44,18 @@ def state_dropdown(object=nil, method=nil, country_id=nil, options={})
def city_text_field(object=nil, method=nil, options = {})
display = _display_value(params[:country_id])
name = _field_name('city_name', object, method)
spinner = options[:spinner]
onblur = remote_function(
:url => {:controller => '/locations', :action => 'city_lookup'},
:with => "'city_id_name='+$('city_id_field').name+'&country_id='+$('select_country_id').value+'&admin_code_id='+$('select_state_id').value+'&city='+value",
:loading => show_spinner('city'),
:complete => hide_spinner('city')
)
if params[:city_id] =~ /\d+/
city = GeoPlace.find(params[:city_id])
end
value = city.nil? ? {} : {:value => city.name}
options = {:onblur => onblur, :name => name, :id=> 'city_text_field'}.merge(value)
#spinner = options[:spinner]
#onblur = remote_function(
# :url => {:controller => '/locations', :action => 'city_lookup'},
# :with => "'city_id_name='+$('city_id_field').name+'&country_id='+$('select_country_id').value+'&admin_code_id='+$('select_state_id').value+'&city='+value",
# :loading => show_spinner('city'),
# :complete => hide_spinner('city')
#)
#if params[:city_id] =~ /\d+/
# city = GeoPlace.find(params[:city_id])
#end
#value = city.nil? ? {} : {:value => city.name}
options = {:name => name, :id=> 'city_text_field'} #.merge(value)
render :partial => '/locations/city_text_field', :locals => {:display => display, :object=>object, :method=>method, :options => options}
end

Expand Down Expand Up @@ -74,6 +86,10 @@ def friendly_location(entity)

private

def country_choices
[ I18n.t(:location_country).capitalize].concat(GeoCountry.find(:all).to_select(:name, :id))
end

def _field_name(altname, object=nil, method=nil)
if !object.nil? and !method.nil?
object + "[#{method}]"
Expand Down
Loading

0 comments on commit e5df799

Please sign in to comment.