From fcd20d89ba9a274ad81dbde00a766a84362f60b5 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Thu, 6 Dec 2012 13:08:10 +1100 Subject: [PATCH] Switch customer autocomplete in admin backend to use Select2 --- .../app/assets/javascripts/admin/admin.js.erb | 1 + .../javascripts/admin/checkouts/edit.js | 139 ++++++------------ .../javascripts/admin/handlebar_extensions.js | 9 ++ .../admin/variant_autocomplete.js.erb | 3 +- .../customer_details/_autocomplete.js.erb | 19 +++ .../orders/customer_details/edit.html.erb | 7 +- core/app/views/spree/admin/search/users.rabl | 48 +++--- .../spree/admin/shared/_translations.html.erb | 2 + .../spree/admin/variants/_autocomplete.js.erb | 4 +- core/config/locales/en.yml | 1 + .../admin/orders/customer_details_spec.rb | 10 +- core/spec/support/capybara_ext.rb | 18 +-- 12 files changed, 116 insertions(+), 145 deletions(-) create mode 100644 core/app/assets/javascripts/admin/handlebar_extensions.js create mode 100644 core/app/views/spree/admin/orders/customer_details/_autocomplete.js.erb diff --git a/core/app/assets/javascripts/admin/admin.js.erb b/core/app/assets/javascripts/admin/admin.js.erb index da33c941ef6..7f887faddd1 100644 --- a/core/app/assets/javascripts/admin/admin.js.erb +++ b/core/app/assets/javascripts/admin/admin.js.erb @@ -1,4 +1,5 @@ //= require_self +//= require admin/handlebar_extensions //= require admin/variant_autocomplete //= require admin/taxon_autocomplete //= require admin/spree-select2 diff --git a/core/app/assets/javascripts/admin/checkouts/edit.js b/core/app/assets/javascripts/admin/checkouts/edit.js index 5f50ecce508..c4f0d5936c3 100644 --- a/core/app/assets/javascripts/admin/checkouts/edit.js +++ b/core/app/assets/javascripts/admin/checkouts/edit.js @@ -1,108 +1,59 @@ -$(document).ready(function(){ - - add_address = function(addr){ - var html = ""; - if(addr!=undefined){ - html += addr['firstname'] + " " + addr['lastname'] + ", "; - html += addr['address1'] + ", " + addr['address2'] + ", "; - html += addr['city'] + ", "; - - if(addr['state_id']!=null){ - html += addr['state']['name'] + ", "; - }else{ - html += addr['state_name'] + ", "; - } - - html += addr['country']['name']; - } - return html; - } - - format_user_autocomplete = function(item){ - var data = item.data - var html = "

" + data['email'] +"

"; - html += "Billing: "; - html += add_address(data['bill_address']); - html += ""; - - html += "Shipping: "; - html += add_address(data['ship_address']); - html += ""; - - return html - } - - prep_user_autocomplete_data = function(data){ - return $.map(eval(data['users']), function(row) { - return { - data: row, - value: row['email'], - result: row['email'] - } - }); +$(document).ready(function() { + window.customerTemplate = Handlebars.compile($('#customer_autocomplete_template').text()); + + formatCustomerResult = function(customer) { + return customerTemplate({ + customer: customer, + bill_address: customer.bill_address, + ship_address: customer.ship_address + }) } if ($("#customer_search").length > 0) { - $("#customer_search").autocomplete({ - minChars: 5, - delay: 500, - source: function(request, response) { - var params = { q: $('#customer_search').val(), - authenticity_token: AUTH_TOKEN } - $.get(Spree.routes.user_search + '&' + jQuery.param(params), function(data) { - result = prep_user_autocomplete_data(data) - response(result); - }); + $("#customer_search").select2({ + placeholder: Spree.translations.choose_a_customer, + ajax: { + url: Spree.routes.user_search, + datatype: 'json', + data: function(term, page) { + return { q: term } + }, + results: function(data, page) { + return { results: data } + } }, - focus: function(event, ui) { - $('#customer_search').val(ui.item.label); - $(ui).addClass('ac_over'); - return false; - }, - select: function(event, ui) { - $('#customer_search').val(ui.item.label); - _.each(['bill', 'ship'], function(addr_name){ - var addr = ui.item.data[addr_name + '_address']; - if(addr!=undefined){ - $('#order_' + addr_name + '_address_attributes_firstname').val(addr['firstname']); - $('#order_' + addr_name + '_address_attributes_lastname').val(addr['lastname']); - $('#order_' + addr_name + '_address_attributes_company').val(addr['company']); - $('#order_' + addr_name + '_address_attributes_address1').val(addr['address1']); - $('#order_' + addr_name + '_address_attributes_address2').val(addr['address2']); - $('#order_' + addr_name + '_address_attributes_city').val(addr['city']); - $('#order_' + addr_name + '_address_attributes_zipcode').val(addr['zipcode']); - $('#order_' + addr_name + '_address_attributes_state_id').val(addr['state_id']); - $('#order_' + addr_name + '_address_attributes_country_id').val(addr['country_id']); - $('#order_' + addr_name + '_address_attributes_phone').val(addr['phone']); + formatResult: formatCustomerResult, + formatSelection: function (customer) { + _.each(['bill_address', 'ship_address'], function(address) { + var data = customer[address]; + if(data != undefined) { + $('#order_' + address + '_attributes_firstname').val(data['firstname']); + $('#order_' + address + '_attributes_lastname').val(data['lastname']); + $('#order_' + address + '_attributes_company').val(data['company']); + $('#order_' + address + '_attributes_address1').val(data['address1']); + $('#order_' + address + '_attributes_address2').val(data['address2']); + $('#order_' + address + '_attributes_city').val(data['city']); + $('#order_' + address + '_attributes_zipcode').val(data['zipcode']); + $('#order_' + address + '_attributes_state_id').select2("val", data['state_id']); + $('#order_' + address + '_attributes_country_id').select2("val", data['country_id']); + $('#order_' + address + '_attributes_phone').val(data['phone']); } }); - $('#order_email').val(ui.item.data['email']); - $('#user_id').val(ui.item.data['id']); + $('#order_email').val(customer.email); + $('#user_id').val(customer.id); $('#guest_checkout_true').prop("checked", false); $('#guest_checkout_false').prop("checked", true); $('#guest_checkout_false').prop("disabled", false); - return true; - } - }).data("autocomplete")._renderItem = function(ul, item) { - $(ul).addClass('ac_results'); - html = format_user_autocomplete(item); - return $("
  • ") - .data("item.autocomplete", item) - .append("" + html + "") - .appendTo(ul); - } - - $("#customer_search").data("autocomplete")._resizeMenu = function() { - var ul = this.menu.element; - ul.outerWidth(this.element.outerWidth()); - } - + return customer.email; + } + }) } - var show_billing = function(show) { - if(show) { + + $('input#order_use_billing').click(function() { + if(!$(this).is(':checked')) { $('#shipping').show(); $('#shipping input').prop("disabled", false); $('#shipping select').prop("disabled", false); @@ -111,10 +62,6 @@ $(document).ready(function(){ $('#shipping input').prop("disabled", true); $('#shipping select').prop("disabled", true); } - } - - $('input#order_use_billing').click(function() { - show_billing(!$(this).is(':checked')); }); $('#guest_checkout_true').change(function() { diff --git a/core/app/assets/javascripts/admin/handlebar_extensions.js b/core/app/assets/javascripts/admin/handlebar_extensions.js new file mode 100644 index 00000000000..02f372bb005 --- /dev/null +++ b/core/app/assets/javascripts/admin/handlebar_extensions.js @@ -0,0 +1,9 @@ +//= require handlebars +Handlebars.registerHelper("t", function(key) { + if (Spree.translations[key]) { + return Spree.translations[key] + } else { + console.error("No translation found for " + key + ". Does it exist within spree/admin/shared/_translations.html.erb?") + } +}); + diff --git a/core/app/assets/javascripts/admin/variant_autocomplete.js.erb b/core/app/assets/javascripts/admin/variant_autocomplete.js.erb index ebc7389bea7..94b6be68dae 100644 --- a/core/app/assets/javascripts/admin/variant_autocomplete.js.erb +++ b/core/app/assets/javascripts/admin/variant_autocomplete.js.erb @@ -1,4 +1,3 @@ -//= require handlebars <%#encoding: UTF-8%> // variant autocompletion @@ -10,7 +9,7 @@ formatVariantResult = function(variant) { if (variant["images"][0] != undefined) { variant.image = variant.images[0].image.mini_url } - return variantTemplate({ variant: variant, translations: Spree.translations }) + return variantTemplate({ variant: variant }) } $.fn.variantAutocomplete = function() { diff --git a/core/app/views/spree/admin/orders/customer_details/_autocomplete.js.erb b/core/app/views/spree/admin/orders/customer_details/_autocomplete.js.erb new file mode 100644 index 00000000000..9484fa0dbb3 --- /dev/null +++ b/core/app/views/spree/admin/orders/customer_details/_autocomplete.js.erb @@ -0,0 +1,19 @@ + diff --git a/core/app/views/spree/admin/orders/customer_details/edit.html.erb b/core/app/views/spree/admin/orders/customer_details/edit.html.erb index 19dfdc29198..0de3565e338 100644 --- a/core/app/views/spree/admin/orders/customer_details/edit.html.erb +++ b/core/app/views/spree/admin/orders/customer_details/edit.html.erb @@ -11,15 +11,16 @@ <% end %> <% if @order.cart? %> -
    +
    <%= t(:customer_search) %> - <%= label_tag :customer_search, t(:enter_at_least_five_letters) %> - <%= text_field_tag :customer_search, nil, :class => 'fullwidth title' %> + <%= hidden_field_tag :customer_search, nil, :class => 'fullwidth title' %> + <%= render :partial => "spree/admin/orders/customer_details/autocomplete", :formats => :js %>
    <% end %> + <%= render :partial => 'spree/shared/error_messages', :locals => { :target => @order } %> <%= form_for @order, :url => admin_order_customer_url(@order) do |f| %> diff --git a/core/app/views/spree/admin/search/users.rabl b/core/app/views/spree/admin/search/users.rabl index 6e6d3932f05..a8bf45eae3a 100644 --- a/core/app/views/spree/admin/search/users.rabl +++ b/core/app/views/spree/admin/search/users.rabl @@ -1,32 +1,30 @@ -object false -child @users => :users do - attributes :email, :id - address_fields = [:firstname, :lastname, - :address1, :address2, - :city, :zipcode, - :phone, :state_name, - :state_id, :country_id, - :company] +collection(@users) +attributes :email, :id +address_fields = [:firstname, :lastname, + :address1, :address2, + :city, :zipcode, + :phone, :state_name, + :state_id, :country_id, + :company] - child :ship_address => :ship_address do - attributes *address_fields - child :state do - attributes :name - end +child :ship_address => :ship_address do + attributes *address_fields + child :state do + attributes :name + end - child :country do - attributes :name - end + child :country do + attributes :name end +end - child :bill_address => :bill_address do - attributes *address_fields - child :state do - attributes :name - end +child :bill_address => :bill_address do + attributes *address_fields + child :state do + attributes :name + end - child :country do - attributes :name - end + child :country do + attributes :name end end diff --git a/core/app/views/spree/admin/shared/_translations.html.erb b/core/app/views/spree/admin/shared/_translations.html.erb index e2c2f5b8669..f9703abbc71 100644 --- a/core/app/views/spree/admin/shared/_translations.html.erb +++ b/core/app/views/spree/admin/shared/_translations.html.erb @@ -6,6 +6,8 @@ :abbr_day_names => I18n.t(:abbr_day_names, :scope => :date), :add => I18n.t(:add), :are_you_sure_delete => I18n.t(:are_you_sure_delete), + :bill_address => I18n.t(:bill_address), + :choose_a_customer => I18n.t(:choose_a_customer), :confirm_delete => I18n.t(:confirm_delete), :cut => I18n.t(:cut), :destroy => I18n.t(:destroy), diff --git a/core/app/views/spree/admin/variants/_autocomplete.js.erb b/core/app/views/spree/admin/variants/_autocomplete.js.erb index 16e86647e33..33594915465 100644 --- a/core/app/views/spree/admin/variants/_autocomplete.js.erb +++ b/core/app/views/spree/admin/variants/_autocomplete.js.erb @@ -13,8 +13,8 @@
    {{variant.name}}
    {{#if variant.option_values}} diff --git a/core/config/locales/en.yml b/core/config/locales/en.yml index c17eabbe539..3bdb511f552 100644 --- a/core/config/locales/en.yml +++ b/core/config/locales/en.yml @@ -321,6 +321,7 @@ en: charges: Charges checkout: Checkout cheque: Cheque + choose_a_customer: "Choose a customer" city: City clone: Clone code: Code diff --git a/core/spec/requests/admin/orders/customer_details_spec.rb b/core/spec/requests/admin/orders/customer_details_spec.rb index aaaeb9375ec..eff59796d8a 100644 --- a/core/spec/requests/admin/orders/customer_details_spec.rb +++ b/core/spec/requests/admin/orders/customer_details_spec.rb @@ -23,9 +23,9 @@ create(:order_with_inventory_unit_shipped, :completed_at => "2011-02-01 12:36:15") ship_address = create(:address, :country => country, :state => state) bill_address = create(:address, :country => country, :state => state) - create(:user, :email => 'foobar@example.com', - :ship_address => ship_address, - :bill_address => bill_address) + @user = create(:user, :email => 'foobar@example.com', + :ship_address => ship_address, + :bill_address => bill_address) visit spree.admin_path click_link "Orders" @@ -35,9 +35,7 @@ context "editing an order", :js => true do it "should be able to populate customer details for an existing order" do click_link "Customer Details" - fill_in "customer_search", :with => "foobar" - sleep(3) - page.execute_script %Q{ $('.ui-menu-item a').last().click(); } + select2("#select-customer", "foobar") ["ship_address", "bill_address"].each do |address| find_field("order_#{address}_attributes_firstname").value.should == "John" diff --git a/core/spec/support/capybara_ext.rb b/core/spec/support/capybara_ext.rb index abf0ca2cd71..774c5dd2b1b 100644 --- a/core/spec/support/capybara_ext.rb +++ b/core/spec/support/capybara_ext.rb @@ -16,17 +16,13 @@ def column_text(num) end def select2(within, value) - script = %Q{ - $('#{within} .select2-search-field input').val('#{value}') - $('#{within} .select2-search-field input').keydown(); - } - page.execute_script(script) - - # Wait for list to populate... - wait_until do - page.find(".select2-highlighted").visible? - end - page.execute_script("$('.select2-highlighted').mouseup();") + # Forced narcolepsy, thanks to JavaScript + sleep(1) + page.execute_script "$('#{within} .select2-choice').mousedown();" + sleep(1) + page.execute_script "$('.select2-focused').val('foobar').trigger('keyup-change');" + sleep(1) + page.execute_script "$('.select2-highlighted').mouseup();" end end