spree_mobile_views 0.50.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. data/.gitignore +9 -0
  2. data/LICENSE +23 -0
  3. data/README.md +15 -0
  4. data/Rakefile +75 -0
  5. data/Versionfile +1 -0
  6. data/app/controllers/products_controller_decorator.rb +4 -0
  7. data/app/helpers/base_helper_decorator.rb +16 -0
  8. data/app/mobile_views/checkout/_address.html.erb +116 -0
  9. data/app/mobile_views/checkout/_delivery.html.erb +24 -0
  10. data/app/mobile_views/checkout/_payment.html.erb +27 -0
  11. data/app/mobile_views/checkout/edit.html.erb +14 -0
  12. data/app/mobile_views/checkout/payment/_gateway.html.erb +32 -0
  13. data/app/mobile_views/layouts/spree_application.html.erb +57 -0
  14. data/app/mobile_views/orders/_form.html.erb +18 -0
  15. data/app/mobile_views/orders/_line_item.html.erb +41 -0
  16. data/app/mobile_views/orders/edit.html.erb +43 -0
  17. data/app/mobile_views/products/_cart_form.html.erb +52 -0
  18. data/app/mobile_views/products/index.html.erb +5 -0
  19. data/app/mobile_views/products/search.html.erb +11 -0
  20. data/app/mobile_views/products/show.html.erb +30 -0
  21. data/app/mobile_views/shared/_order_details.html.erb +50 -0
  22. data/app/mobile_views/shared/_products.html.erb +9 -0
  23. data/app/mobile_views/taxons/index.html.erb +8 -0
  24. data/app/mobile_views/taxons/show.html.erb +9 -0
  25. data/config/routes.rb +3 -0
  26. data/lib/spree_mobile_views.rb +62 -0
  27. data/lib/spree_mobile_views_hooks.rb +3 -0
  28. data/lib/tasks/install.rake +25 -0
  29. data/lib/tasks/spree_mobile_views.rake +1 -0
  30. data/public/stylesheets/mobile.css +36 -0
  31. data/spec/spec_helper.rb +30 -0
  32. data/spree_mobile_views.gemspec +22 -0
  33. metadata +108 -0
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ \#*
2
+ *~
3
+ .#*
4
+ .DS_Store
5
+ .idea
6
+ .project
7
+ tmp
8
+ nbproject
9
+ *.swp
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Redistribution and use in source and binary forms, with or without modification,
2
+ are permitted provided that the following conditions are met:
3
+
4
+ * Redistributions of source code must retain the above copyright notice,
5
+ this list of conditions and the following disclaimer.
6
+ * Redistributions in binary form must reproduce the above copyright notice,
7
+ this list of conditions and the following disclaimer in the documentation
8
+ and/or other materials provided with the distribution.
9
+ * Neither the name of the Rails Dog LLC nor the names of its
10
+ contributors may be used to endorse or promote products derived from this
11
+ software without specific prior written permission.
12
+
13
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
14
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
15
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
16
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,15 @@
1
+ SpreeMobileViews
2
+ ================
3
+
4
+ Adds support of mobile devices to Spree stores through jQuery Mobile.
5
+
6
+
7
+ Installation
8
+ ============
9
+
10
+ 1. Add following line to Gemfile: `gem 'spree_mobile_views'`
11
+ 1. Run `bundle install`
12
+ 1. Run `rake spree_mobile_views:install:assets`
13
+
14
+
15
+ Copyright (c) 2011 Roman Smirnov, released under the New BSD License
data/Rakefile ADDED
@@ -0,0 +1,75 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/packagetask'
5
+ require 'rake/gempackagetask'
6
+
7
+ gemfile = File.expand_path('../spec/test_app/Gemfile', __FILE__)
8
+ if File.exists?(gemfile) && (%w(spec cucumber).include?(ARGV.first.to_s) || ARGV.size == 0)
9
+ require 'bundler'
10
+ ENV['BUNDLE_GEMFILE'] = gemfile
11
+ Bundler.setup
12
+
13
+ require 'rspec'
14
+ require 'rspec/core/rake_task'
15
+ RSpec::Core::RakeTask.new
16
+
17
+ require 'cucumber/rake/task'
18
+ Cucumber::Rake::Task.new do |t|
19
+ t.cucumber_opts = %w{--format progress}
20
+ end
21
+ end
22
+
23
+ desc "Default Task"
24
+ task :default => [:spec, :cucumber ]
25
+
26
+ spec = eval(File.read('spree_mobile_views.gemspec'))
27
+
28
+ Rake::GemPackageTask.new(spec) do |p|
29
+ p.gem_spec = spec
30
+ end
31
+
32
+ desc "Release to gemcutter"
33
+ task :release => :package do
34
+ require 'rake/gemcutter'
35
+ Rake::Gemcutter::Tasks.new(spec).define
36
+ Rake::Task['gem:push'].invoke
37
+ end
38
+
39
+ desc "Default Task"
40
+ task :default => [ :spec ]
41
+
42
+ desc "Regenerates a rails 3 app for testing"
43
+ task :test_app do
44
+ require '../spree/lib/generators/spree/test_app_generator'
45
+ class SpreeMobileViewTestAppGenerator < Spree::Generators::TestAppGenerator
46
+
47
+ def install_gems
48
+ inside "test_app" do
49
+ run 'rake spree_core:install'
50
+ run 'rake spree_mobile_views:install'
51
+ end
52
+ end
53
+
54
+ def migrate_db
55
+ run_migrations
56
+ end
57
+
58
+ protected
59
+ def full_path_for_local_gems
60
+ <<-gems
61
+ gem 'spree_core', :path => \'#{File.join(File.dirname(__FILE__), "../spree/", "core")}\'
62
+ gem 'spree_mobile_views', :path => \'#{File.dirname(__FILE__)}\'
63
+ gems
64
+ end
65
+
66
+ end
67
+ SpreeMobileViewTestAppGenerator.start
68
+ end
69
+
70
+ namespace :test_app do
71
+ desc 'Rebuild test and cucumber databases'
72
+ task :rebuild_dbs do
73
+ system("cd spec/test_app && rake db:drop db:migrate RAILS_ENV=test && rake db:drop db:migrate RAILS_ENV=cucumber")
74
+ end
75
+ end
data/Versionfile ADDED
@@ -0,0 +1 @@
1
+ "0.50.x" => { :branch => "master" }
@@ -0,0 +1,4 @@
1
+ ProductsController.class_eval do
2
+ def search
3
+ end
4
+ end
@@ -0,0 +1,16 @@
1
+ Spree::BaseHelper.module_eval do
2
+
3
+ def link_to_cart(text = t('cart'))
4
+ if current_order.nil? or current_order.line_items.empty?
5
+ text = "#{text}: (#{t('empty')})"
6
+ else
7
+ text = "#{text}: (#{current_order.item_count}) #{order_price(current_order)}"
8
+ end
9
+ link_to text, cart_path, :class => css_class(cart_path)
10
+ end
11
+
12
+ def css_class(path)
13
+ current_page?(path) ? "ui-btn-active" : ""
14
+ end
15
+
16
+ end
@@ -0,0 +1,116 @@
1
+ <fieldset id='billing' data-role="fieldcontain">
2
+ <%= form.fields_for :bill_address do |bill_form| %>
3
+ <legend><%= t("billing_address")%></legend>
4
+ <div class="inner">
5
+ <p id="bfname" class="field">
6
+ <%= bill_form.label :firstname, [t(:first_name), '<span class="req">*</span>'].join(' ').html_safe %>
7
+ <%= bill_form.text_field :firstname, :class => 'required' %>
8
+ </p>
9
+ <p id="blname" class="field">
10
+ <%= bill_form.label :lastname, [t(:last_name), '<span class="req">*</span>'].join(' ').html_safe %>
11
+ <%= bill_form.text_field :lastname, :class => 'required' %>
12
+ </p>
13
+ <p id="baddress" class="field">
14
+ <%= bill_form.label :address1, [t(:street_address), '<span class="req">*</span>'].join(' ').html_safe %>
15
+ <%= bill_form.text_field :address1, :class => 'required' %>
16
+ </p>
17
+ <p id="baddress2" class="field">
18
+ <%= bill_form.label :address2, t(:street_address_2) %>
19
+ <%= bill_form.text_field :address2 %>
20
+ </p>
21
+ <p id="bcity" class="field">
22
+ <%= bill_form.label :city, [t(:city), '<span class="req">*</span>'].join(' ').html_safe %>
23
+ <%= bill_form.text_field :city, :class => 'required' %>
24
+ </p>
25
+ <% if Spree::Config[:address_requires_state] %>
26
+ <p class="field">
27
+ <span id="bstate">
28
+ <% have_states = !@order.bill_address.country.states.empty? %>
29
+ <%= bill_form.label :state_name, [t(:state), '<span class="req">*</span>'].join(' ').html_safe %>
30
+ <%= bill_form.text_field :state_name, :class => 'required' %>
31
+ </span>
32
+ </p>
33
+ <% end %>
34
+ <p id="bzip" class="field">
35
+ <%= bill_form.label :zipcode, [t(:zip), '<span class="req">*</span>'].join(' ').html_safe %>
36
+ <%= bill_form.text_field :zipcode, :class => 'required' %>
37
+ </p>
38
+ <p id="bcountry" class="field">
39
+ <%= bill_form.label :country_id, [t(:country), '<span class="req">*</span>'].join(' ').html_safe %><br />
40
+ <%= bill_form.collection_select :country_id, available_countries, :id, :name, {}, {:class => 'required'} %>
41
+ </p>
42
+ <p id="bphone" class="field">
43
+ <%= bill_form.label :phone, [t(:phone), '<span class="req">*</span>'].join(' ').html_safe %>
44
+ <%= bill_form.text_field :phone, :class => 'required' %>
45
+ </p>
46
+ <% if Spree::Config[:alternative_billing_phone] %>
47
+ <p id="baltphone">
48
+ <%= bill_form.label :alternative_phone, t(:alternative_phone) %>
49
+ <%= bill_form.text_field :alternative_phone %>
50
+ </p>
51
+ <% end %>
52
+ </div>
53
+ <% end %>
54
+ </fieldset>
55
+ <fieldset id='shipping' data-role="fieldcontain">
56
+ <%= form.fields_for :ship_address do |ship_form| %>
57
+ <legend><%= t("shipping_address")%></legend>
58
+ <p class="field checkbox">
59
+ <label for="order_use_billing" id="use_billing">
60
+ <%= check_box_tag 'order[use_billing]', '1', (!(@order.bill_address.empty? && @order.ship_address.empty?) && @order.bill_address.eql?(@order.ship_address)) %> <%= t("use_billing_address") %>
61
+ </label>
62
+ </p>
63
+ <div class="inner">
64
+ <p id="sfname" class="field">
65
+ <%= ship_form.label :firstname, [t(:first_name), '<span class="req">*</span>'].join(' ').html_safe %>
66
+ <%= ship_form.text_field :firstname, :class => 'required' %>
67
+ </p>
68
+ <p id="slname" class="field">
69
+ <%= ship_form.label :lastname, [t(:last_name), '<span class="req">*</span>'].join(' ').html_safe %>
70
+ <%= ship_form.text_field :lastname, :class => 'required' %>
71
+ </p>
72
+ <p id="saddress" class="field">
73
+ <%= ship_form.label :address1, [t(:street_address), '<span class="req">*</span>'].join(' ').html_safe %>
74
+ <%= ship_form.text_field :address1, :class => 'required' %>
75
+ </p>
76
+ <p id="saddress2" class="field">
77
+ <%= ship_form.label :address2, t(:street_address_2) %>
78
+ <%= ship_form.text_field :address2 %>
79
+ </p>
80
+ <p id="scity" class="field">
81
+ <%= ship_form.label :city, [t(:city), '<span class="req">*</span>'].join(' ').html_safe %>
82
+ <%= ship_form.text_field :city, :class => 'required' %>
83
+ </p>
84
+ <% if Spree::Config[:address_requires_state] %>
85
+ <p class="field">
86
+ <span id="sstate">
87
+ <% have_states = !@order.ship_address.country.states.empty? %>
88
+ <%= ship_form.label :state_name, [t(:state), '<span class="req">*</span>'].join(' ').html_safe %>
89
+ <%= ship_form.text_field :state_name, :class => 'required' %>
90
+ </span>
91
+ </p>
92
+ <% end %>
93
+ <p id="szip" class="field">
94
+ <%= ship_form.label :zipcode, [t(:zip), '<span class="req">*</span>'].join(' ').html_safe %>
95
+ <%= ship_form.text_field :zipcode, :class => 'required' %>
96
+ </p>
97
+ <p id="scountry" class="field">
98
+ <%= ship_form.label :country_id, [t(:country), '<span class="req">*</span>'].join(' ').html_safe %><br />
99
+ <%= ship_form.collection_select :country_id, available_countries, :id, :name, {}, {:class => 'required'} %>
100
+ </p>
101
+ <p id="sphone" class="field">
102
+ <%= ship_form.label :phone, [t(:phone), '<span class="req">*</span>'].join(' ').html_safe %>
103
+ <%= ship_form.text_field :phone, :class => 'required' %>
104
+ </p>
105
+ <% if Spree::Config[:alternative_shipping_phone] %>
106
+ <p id="saltphone">
107
+ <%= ship_form.label :alternative_phone, t(:alternative_phone) %>
108
+ <%= ship_form.text_field :alternative_phone %>
109
+ </p>
110
+ <% end %>
111
+ </div>
112
+ <% end %>
113
+ </fieldset>
114
+
115
+ <input type="submit" value="<%=t("save_and_continue") %>" />
116
+
@@ -0,0 +1,24 @@
1
+ <fieldset id='shipping_method'>
2
+ <legend><%= t("shipping_method") %></legend>
3
+ <div data-role="fieldcontain">
4
+ <fieldset data-role="controlgroup">
5
+ <% @order.rate_hash.each do |shipping_method| %>
6
+ <%= form.label(['shipping_method_id', shipping_method[:id].to_s].join('_'),
7
+ "#{shipping_method[:name]} #{number_to_currency(shipping_method[:cost])}") %>
8
+ <%= radio_button(:order, :shipping_method_id, shipping_method[:id]) %>
9
+ <% end %>
10
+ </p>
11
+ </fieldset>
12
+ </div>
13
+ <% if Spree::Config[:shipping_instructions] && @order.rate_hash.present? %>
14
+ <div data-role="fieldcontain">
15
+ <%= form.label :special_instructions, t("shipping_instructions") %><br />
16
+ <%= form.text_area :special_instructions, :cols => 40, :rows => 7 %>
17
+ </div>
18
+ <% end %>
19
+ </fieldset>
20
+
21
+ <div class="form-buttons">
22
+ <input type="submit" value="<%=t("save_and_continue") %>"/>
23
+ </div>
24
+
@@ -0,0 +1,27 @@
1
+ <fieldset id="payment">
2
+ <legend><%= t("payment_information") %></legend>
3
+ <%= hook :checkout_payment_step, {:form => form} do %>
4
+ <div data-role="fieldcontain">
5
+ <fieldset data-role="controlgroup">
6
+ <% @order.available_payment_methods.each do |method| %>
7
+ <%= form.label "payments_attributes__payment_method_id_#{method.id}", t(method.name, :scope => :payment_methods, :default => method.name) %>
8
+ <%= radio_button_tag "order[payments_attributes][][payment_method_id]", method.id, method == @order.payment_method %>
9
+ <% end %>
10
+ </fieldset>
11
+ </div>
12
+ <div id="payment-methods">
13
+ <% @order.available_payment_methods.each do |method| %>
14
+ <fieldset>
15
+ <%= render "checkout/payment/#{method.method_type}", :payment_method => method %>
16
+ </fieldset>
17
+ </li>
18
+ <% end %>
19
+ </div>
20
+ <br style='clear:both;' />
21
+ <%= hook :coupon_code_field, {:form => form} %>
22
+ <% end %>
23
+ </fieldset>
24
+
25
+ <div class="form-buttons">
26
+ <input type="submit" class="continue button primary" value="<%=t("save_and_continue") %>" />
27
+ </div>
@@ -0,0 +1,14 @@
1
+ <div id="checkout">
2
+ <h1><%= t("checkout")%></h1>
3
+ <%= checkout_progress %>
4
+ <br clear="left" />
5
+ <%= render "shared/error_messages", :target => @order %>
6
+ <%= hook :checkout_summary_box do %>
7
+ <div id="checkout-summary">
8
+ <%= render 'summary', :order => @order %>
9
+ </div>
10
+ <% end %>
11
+ <%= form_for @order, :url => update_checkout_path(@order.state), :html => { :id => "checkout_form_#{@order.state}" } do |form| %>
12
+ <%= render @order.state, :form => form %>
13
+ <% end %>
14
+ </div>
@@ -0,0 +1,32 @@
1
+ <legend><%= payment_method.name %><legend>
2
+ <%= image_tag "creditcard.gif", :id => 'creditcard-image' %>
3
+ <% param_prefix = "payment_source[#{payment_method.id}]" %>
4
+
5
+ <div data-role="fieldcontain">
6
+ <%= label_tag "#{param_prefix}_number", t("card_number") %>
7
+ <% options_hash = Rails.env.production? ? {:autocomplete => "off"} : {} %>
8
+ <%= text_field_tag "#{param_prefix}[number]", '', options_hash.merge(:id => 'card_number', :class => 'required', :size => 19, :maxlength => 19) %>
9
+ <span class="req">*</span>
10
+ &nbsp;
11
+ <span id="card_type" style="display:none;">
12
+ ( <span id="looks_like" ><%= t('card_type_is') %> <span id="type"></span></span>
13
+ <span id="unrecognized"><%= t('unrecognized_card_type') %></span>
14
+ )
15
+ </span>
16
+ </div>
17
+ <div data-role="fieldcontain">
18
+ <label for=""><%= t("expiration") %></label><br />
19
+ <%= select_month(Date.today, :prefix => param_prefix, :field_name => 'month', :use_month_numbers => true, :class => 'required') %>
20
+ <%= select_year(Date.today, :prefix => param_prefix, :field_name => 'year', :start_year => Date.today.year, :end_year => Date.today.year + 15, :class => 'required') %>
21
+ <span class="req">*</span>
22
+ </div>
23
+ <div data-role="fieldcontain">
24
+ <label for=""><%= t("card_code") %></label><br />
25
+ <%= text_field_tag "#{param_prefix}[verification_value]", '', options_hash.merge(:id => 'card_code', :class => 'required', :size => 5) %>
26
+ <span class="req">*</span>
27
+ <a href="/content/cvv" target="_blank" onclick="window.open(this.href,'cvv_info','left=20,top=20,width=500,height=500,toolbar=0,resizable=0,scrollbars=1');return false">
28
+ (<%= t("whats_this") %>)
29
+ </a>
30
+ </div>
31
+ <%= hidden_field param_prefix, 'first_name', :value => @order.billing_firstname %>
32
+ <%= hidden_field param_prefix, 'last_name', :value => @order.billing_lastname %>
@@ -0,0 +1,57 @@
1
+ <html>
2
+ <head>
3
+ <title><%= title %></title>
4
+ <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a4/jquery.mobile-1.0a4.min.css" />
5
+ <script src="http://code.jquery.com/jquery-1.5.2.min.js"></script>
6
+ <script src="http://code.jquery.com/mobile/1.0a4/jquery.mobile-1.0a4.min.js"></script>
7
+ <%= javascript_include_tag 'rails' %>
8
+ <%= stylesheet_link_tag 'mobile' %>
9
+ <%= csrf_meta_tag %>
10
+ </head>
11
+ <body>
12
+ <div data-role="page">
13
+ <div data-role="header">
14
+ <h1><%= title %></h1>
15
+ <div data-role="navbar">
16
+ <ul>
17
+ <li><%= link_to t(:home), root_path, :class => css_class(root_path) %></li>
18
+ <li><%= link_to t(:search), search_path, :class => css_class(search_path) %></li>
19
+ <% if current_user %>
20
+ <li><%= link_to t('my_account'), account_path, :class => css_class(account_path) %></li>
21
+ <li><%= link_to t('logout'), destroy_user_session_path %></li>
22
+ <% else %>
23
+ <li><%= link_to t('log_in'), login_path, :class => css_class(login_path) %></li>
24
+ <% end %>
25
+ <li><%= link_to_cart %></li>
26
+ </ul>
27
+ </div>
28
+
29
+ <% [:notice, :error].each do |message_type| %>
30
+ <% if flash[message_type] %>
31
+ <script>
32
+ $("<div class='ui-loader ui-overlay-shadow <%= (message_type == :error) ? 'ui-body-a' : 'ui-body-e' %> ui-corner-all'><h1><%= flash[message_type] %></h1></div>")
33
+ .css({ "display": "block", "opacity": 0.96, "top": $(window).scrollTop() + 100 })
34
+ .appendTo( $.mobile.pageContainer )
35
+ .delay( 2500 )
36
+ .fadeOut( 400, function(){
37
+ $(this).remove();
38
+ });
39
+ </script>
40
+ <noscript>
41
+ <div data-role="navbar">
42
+ <%= flash[message_type] %>
43
+ </div>
44
+ </noscript>
45
+ <% end %>
46
+ <% end %>
47
+
48
+ </div>
49
+ <div data-role="content">
50
+ <%= yield %>
51
+ </div>
52
+ <div data-role="footer">
53
+ <%= render 'shared/footer'%>
54
+ </div>
55
+ </div>
56
+ </body>
57
+ </html>
@@ -0,0 +1,18 @@
1
+ <%= render "shared/error_messages", :target => @order %>
2
+ <table id="cart-detail" data-role="listview">
3
+ <thead>
4
+ <tr class="ui-bar-b">
5
+ <%= hook :cart_items_headers do %>
6
+ <th colspan="2"><%= t("item") %></th>
7
+ <th><%= t("price") %></th>
8
+ <th><%= t("qty") %></th>
9
+ <th><%= t("total") %></th>
10
+ <% end %>
11
+ </tr>
12
+ </thead>
13
+ <tbody id="line_items">
14
+ <%= order_form.fields_for :line_items do |item_form| %>
15
+ <%= render 'line_item', :variant => item_form.object.variant, :line_item => item_form.object, :item_form => item_form %>
16
+ <% end %>
17
+ </tbody>
18
+ </table>
@@ -0,0 +1,41 @@
1
+ <tr class="<%= cycle('', 'alt') %>">
2
+ <td>
3
+ <%- locals = {:item_form => item_form, :variant => variant, :line_item => line_item} %>
4
+ <%= hook :cart_item_image, locals do %>
5
+ <% if variant.images.length == 0 %>
6
+ <%= small_image(variant.product) %>
7
+ <% else %>
8
+ <%= image_tag variant.images.first.attachment.url(:small) %>
9
+ <% end %>
10
+ <% end %>
11
+ </td>
12
+ <td>
13
+ <%= hook :cart_item_description, locals do %>
14
+ <p><%= link_to variant.product.name, product_path(variant.product) %></p>
15
+ <p><%= variant_options variant %></p>
16
+ <p><%= truncate(variant.product.description, :length => 70, :omission => "...") %></p>
17
+ <% end %>
18
+ </td>
19
+ <td>
20
+ <%= hook :cart_item_price, locals do %>
21
+ <%= product_price(line_item) %>
22
+ <% end %>
23
+ </td>
24
+ <td>
25
+ <%= hook :cart_item_quantity, locals do %>
26
+ <%= item_form.text_field :quantity, :size => 3, :class => "line_item_quantity" %>
27
+ <% end %>
28
+ </td>
29
+
30
+ <td>
31
+ <%= hook :cart_item_total, locals do %>
32
+ <%= format_price(product_price(line_item, :format_as_currency => false) * line_item.quantity) unless line_item.quantity.nil? %>
33
+ <% end %>
34
+ </td>
35
+ <td style='display:none'>
36
+ <%= hook :cart_item_delete, locals do %>
37
+ <%= link_to(image_tag('/images/admin/icons/delete.png'), '#', :class => 'delete') %>
38
+ <% end %>
39
+ </td>
40
+
41
+ </tr>
@@ -0,0 +1,43 @@
1
+ <% if @order.line_items.empty? %>
2
+
3
+ <%= hook :empty_cart do %>
4
+ <p><%= t("your_cart_is_empty.") %></p>
5
+ <p><%= link_to t("continue_shopping"), products_path, :class => 'button continue' %></p>
6
+ <% end %>
7
+
8
+ <% else %>
9
+ <%= hook :outside_cart_form do %>
10
+ <%= form_for(@order, :url => update_cart_path, :html=>{:id=>'updatecart'}) do |order_form| %>
11
+ <%= hook :inside_cart_form do %>
12
+
13
+ <%= hook :cart_items do %>
14
+ <%= render :partial => 'form', :locals => {:order_form => order_form} %>
15
+ <% end %>
16
+
17
+ <div id="subtotal">
18
+ <h3><%= "#{t("subtotal")}: #{order_price(@order)}" %></h3>
19
+ </div>
20
+ <fieldset class="ui-grid-a">
21
+ <div class="ui-block-a">
22
+ <%= order_form.submit t('update'), "data-role" => "button", "data-icon" => "refresh" %>
23
+ </div>
24
+ <div class="ui-block-b">
25
+ <%= link_to t("checkout"), checkout_path, "data-role" => "button", "data-icon" => "gear" %>
26
+ </div>
27
+ <div class="ui-block-a">
28
+ <%= link_to t("continue_shopping"), root_path, "data-role" => "button", "data-icon" => "back" %>
29
+ </div>
30
+ </fieldset>
31
+ <% end %>
32
+ <% end %>
33
+ <% end %>
34
+
35
+ <%= form_tag empty_cart_path, :method => :put do %>
36
+ <fieldset class="ui-grid-a">
37
+ <div class="ui-block-a">
38
+ <input type="submit" value="<%= t('empty_cart') %>" data-icon="delete" />
39
+ </div>
40
+ </fieldset>
41
+ <% end %>
42
+
43
+ <% end %>
@@ -0,0 +1,52 @@
1
+ <%= form_for :order, :url => populate_orders_path do |f| %>
2
+ <%= hook :inside_product_cart_form do %>
3
+
4
+ <% if product_price(@product) %>
5
+ <%= hook :product_price do %>
6
+ <p class="prices">
7
+ <%= t("price") %>:
8
+ <span class="price selling"><strong><%= product_price(@product) %></strong></span>
9
+ </p>
10
+ <% end %>
11
+ <% end %>
12
+
13
+ <% if @product.has_variants? %>
14
+ <div data-role="fieldcontain" id="product-variants">
15
+ <h4><%= t('variants') %></h4>
16
+ <fieldset data-role="controlgroup">
17
+ <% has_checked = false
18
+ @product.variants.active.each_with_index do |v,index|
19
+ next if v.option_values.empty? || (!v.in_stock && !Spree::Config[:show_zero_stock_products])
20
+ checked = !has_checked && (v.in_stock || Spree::Config[:allow_backorders])
21
+ has_checked = true if checked %>
22
+
23
+ <%= radio_button_tag "products[#{@product.id}]", v.id, checked, :disabled => !v.in_stock && !Spree::Config[:allow_backorders] %>
24
+ <label for="products_<%= [@product.id, v.id].join('_') %>">
25
+ <%= variant_options v %>
26
+
27
+ <% if variant_price_diff v %>
28
+ <span class="price diff"><%= variant_price_diff v %></span>
29
+ <% end %>
30
+ </label>
31
+ <% end%>
32
+ </fieldset>
33
+ </div>
34
+ <% end%>
35
+
36
+ <% if @product.has_stock? || Spree::Config[:allow_backorders] %>
37
+ <fieldset class="ui-grid-a">
38
+ <div class="ui-block-a">
39
+ <%= text_field_tag (@product.has_variants? ? :quantity : "variants[#{@product.master.id}]"), 1, :class => "title", :size => 3 %>
40
+ </div>
41
+ <div class="ui-block-a">
42
+ <button type='submit' data-icon="plus">
43
+ <%= t('add_to_cart') %>
44
+ </button>
45
+ </div>
46
+ </fieldset>
47
+ <% else %>
48
+ <%= content_tag('strong', t('out_of_stock')) %>
49
+ <% end %>
50
+
51
+ <% end %>
52
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <% if current_page?('/') %>
2
+ <%= render :template => "taxons/index" %>
3
+ <% else %>
4
+ <%= render :partial => "shared/products" %>
5
+ <% end %>
@@ -0,0 +1,11 @@
1
+ <%= form_tag products_url, :method => :get do %>
2
+ <div class="ui-grid-b">
3
+ <div data-role="fieldcontain">
4
+ <%= text_field_tag :keywords, params[:keywords], 'type' => 'search' %>
5
+ </div>
6
+ <div class="ui-block-a">&nbsp;</div>
7
+ <div class="ui-block-b">
8
+ <%= submit_tag t(:search), :name => nil %>
9
+ </div>
10
+ </div>
11
+ <% end %>
@@ -0,0 +1,30 @@
1
+ <div data-role="content">
2
+ <table>
3
+ <tr>
4
+ <td id="main-image">
5
+ <%= render 'image' %>
6
+ </td>
7
+ </tr>
8
+ <tr>
9
+ <td>
10
+ <%= hook :cart_form do %>
11
+ <div id="cart-form">
12
+ <%= render 'cart_form' %>
13
+ </div>
14
+ <% end %>
15
+ </td>
16
+ </tr>
17
+ <tr>
18
+ <td colspan="2">
19
+ <div id="product-description">
20
+ <%= hook :product_description do %>
21
+ <%= product_description(@product) rescue t("product_has_no_description") %>
22
+ <% end %>
23
+ <%= hook :product_properties do %>
24
+ <%= render 'properties' %>
25
+ <% end %>
26
+ </div>
27
+ </td>
28
+ </tr>
29
+ </table>
30
+ </div>
@@ -0,0 +1,50 @@
1
+ <table class="index" data-role="listview">
2
+ <tbody id='line-items'>
3
+ <tr class="ui-bar-b">
4
+ <%= hook :order_details_line_items_headers do %>
5
+ <th><%= t('item_description') %></th>
6
+ <th class="price"><%= t('price') %></th>
7
+ <th class="qty"><%= t('qty') %></th>
8
+ <th class="total"><span><%= t('total') %></span></th>
9
+ <% end %>
10
+ </tr>
11
+
12
+ <% @order.line_items.each do |item| %>
13
+ <tr>
14
+ <%- locals = {:item => item} %>
15
+ <%= hook :order_details_line_item_row, locals do %>
16
+ <td width="300"><%=item.variant.product.name%> <%= "(" + variant_options(item.variant) + ")" unless item.variant .option_values.empty? %></td>
17
+ <td class="price"><%= number_to_currency item.price %></td>
18
+ <td class="qty"><%=item.quantity%></td>
19
+ <td class="total"><span><%= number_to_currency (item.price * item.quantity)%></span></td>
20
+ <% end %>
21
+ </tr>
22
+ <% end %>
23
+ </tbody>
24
+ <%= hook :order_details_subtotal do %>
25
+ <tbody id='subtotal'>
26
+ <tr class="total" id="subtotal-row">
27
+ <td colspan="3"><b><%= t('subtotal') %>:</b></td>
28
+ <td class="total"><span><%= number_to_currency @order.item_total %></span></td>
29
+ </tr>
30
+ </tbody>
31
+ <% end %>
32
+ <%= hook :order_details_adjustments do %>
33
+ <tbody id="order-charges">
34
+ <% @order.adjustments.each do |adjustment| %>
35
+ <tr class="total">
36
+ <td colspan="3"><strong><%= adjustment.label %></strong></td>
37
+ <td class="total"><span><%= number_to_currency adjustment.amount %></span></td>
38
+ </tr>
39
+ <% end %>
40
+ </tbody>
41
+ <% end %>
42
+ <%= hook :order_details_total do %>
43
+ <tbody id='order-total'>
44
+ <tr class="total">
45
+ <td colspan="3"><b><%= t('order_total') %>:</b></td>
46
+ <td class="total"><span id="order_total"><%= number_to_currency @order.total %></span></td>
47
+ </tr>
48
+ </tbody>
49
+ <% end %>
50
+ </table>
@@ -0,0 +1,9 @@
1
+ <ul data-role="listview">
2
+ <% @products.each do |product| %>
3
+ <li>
4
+ <%= product_image(product)%>
5
+ <h3><%= link_to product.name, product %></h3>
6
+ <p><%= truncate(product.description, :length => 70, :omission => "...") %></p>
7
+ </li>
8
+ <% end %>
9
+ </ul>
@@ -0,0 +1,8 @@
1
+ <% get_taxonomies.each do |taxonomy| %>
2
+ <ul data-role="listview" data-inset="true">
3
+ <li data-role="list-divider"><%= taxonomy.name %></li>
4
+ <% taxonomy.root.children.each do |taxon| %>
5
+ <li><%= link_to taxon.name, seo_url(taxon) %></li>
6
+ <% end %>
7
+ </ul>
8
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <% if @taxon.children.present? %>
2
+ <ul data-role="listview">
3
+ <% @taxon.children.each do |taxon| %>
4
+ <li><%= link_to taxon.name, seo_url(taxon) %></li>
5
+ <% end %>
6
+ </ul>
7
+ <% else %>
8
+ <%= render :partial => "shared/products" %>
9
+ <% end %>
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ Rails.application.routes.draw do
2
+ match "/search" => "products#search", :as => :search
3
+ end
@@ -0,0 +1,62 @@
1
+ require 'spree_core'
2
+ require 'spree_mobile_views_hooks'
3
+
4
+ module SpreeMobileViews
5
+ class Engine < Rails::Engine
6
+
7
+ config.autoload_paths += %W(#{config.root}/lib)
8
+
9
+ def self.activate
10
+ Dir.glob(File.join(File.dirname(__FILE__), "../app/**/*_decorator*.rb")) do |c|
11
+ Rails.env.production? ? require(c) : load(c)
12
+ end
13
+ end
14
+
15
+ config.to_prepare &method(:activate).to_proc
16
+ end
17
+ end
18
+
19
+
20
+ module SpreeBase
21
+ module InstanceMethods
22
+ protected
23
+ MOBILE_USER_AGENTS = 'palm|blackberry|nokia|phone|midp|mobi|symbian|chtml|ericsson|minimo|' +
24
+ 'audiovox|motorola|samsung|telit|upg1|windows ce|ucweb|astel|plucker|' +
25
+ 'x320|x240|j2me|sgh|portable|sprint|docomo|kddi|softbank|android|mmp|' +
26
+ 'pdxgw|netfront|xiino|vodafone|portalmmm|sagem|mot-|sie-|ipod|up\\.b|' +
27
+ 'webos|amoi|novarra|cdm|alcatel|pocket|ipad|iphone|mobileexplorer|mobile'
28
+
29
+ def mobile_device?
30
+ if cookies[:mobile_param]
31
+ cookies[:mobile_param] == "1"
32
+ else
33
+ request.user_agent.to_s.downcase =~ Regexp.new(MOBILE_USER_AGENTS)
34
+ end
35
+ end
36
+
37
+ def prepare_for_mobile
38
+ cookies[:mobile_param] = params[:mobile] if params[:mobile]
39
+ end
40
+
41
+ def prepend_view_path_if_mobile
42
+ if mobile_device?
43
+ prepend_view_path File.join(File.dirname(__FILE__), '..', 'app', 'mobile_views')
44
+ prepend_view_path File.join(Rails.root, 'app', 'mobile_views')
45
+ end
46
+ end
47
+ end
48
+
49
+ class << self
50
+
51
+ def included_with_mobile_views(receiver)
52
+ included_without_mobile_views(receiver)
53
+
54
+ receiver.send :helper_method, 'mobile_device?'
55
+ receiver.send :before_filter, 'prepare_for_mobile'
56
+ receiver.send :before_filter, 'prepend_view_path_if_mobile'
57
+ end
58
+
59
+ alias_method_chain :included, :mobile_views
60
+
61
+ end
62
+ end
@@ -0,0 +1,3 @@
1
+ class SpreeMobileViewsHooks < Spree::ThemeSupport::HookListener
2
+ # custom hooks go here
3
+ end
@@ -0,0 +1,25 @@
1
+ namespace :spree_mobile_views do
2
+ desc "Copies all migrations and assets (NOTE: This will be obsolete with Rails 3.1)"
3
+ task :install do
4
+ Rake::Task['spree_mobile_views:install:migrations'].invoke
5
+ Rake::Task['spree_mobile_views:install:assets'].invoke
6
+ end
7
+
8
+ namespace :install do
9
+ desc "Copies all migrations (NOTE: This will be obsolete with Rails 3.1)"
10
+ task :migrations do
11
+ source = File.join(File.dirname(__FILE__), '..', '..', 'db')
12
+ destination = File.join(Rails.root, 'db')
13
+ Spree::FileUtilz.mirror_files(source, destination)
14
+ end
15
+
16
+ desc "Copies all assets (NOTE: This will be obsolete with Rails 3.1)"
17
+ task :assets do
18
+ source = File.join(File.dirname(__FILE__), '..', '..', 'public')
19
+ destination = File.join(Rails.root, 'public')
20
+ puts "INFO: Mirroring assets from #{source} to #{destination}"
21
+ Spree::FileUtilz.mirror_files(source, destination)
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1 @@
1
+ # add custom rake tasks here
@@ -0,0 +1,36 @@
1
+ #cart-form input { max-width: 250px; }
2
+ #cart-detail .ui-li-desc { white-space: normal; }
3
+ dt { font-weight: bold; }
4
+ #line_items input { width: 3em; }
5
+ #line_items td { padding: 3px; background: #EEE; }
6
+ #updatecart #subtotal { text-align: right; margin-right: 0.5em; }
7
+ .min-width-480px label.ui-input-text { width: 60%; }
8
+ .min-width-480px .ui-input-search { width: 90%; }
9
+ #checkout fieldset { margin-top: 2em; }
10
+ #checkout fieldset legend { font-weight: bold; }
11
+ #billing input, #shipping input { width: 100%; }
12
+ span.req { color: #D11; }
13
+
14
+ ol.progress-steps {
15
+ list-style: none;
16
+ margin: 0;
17
+ padding: 0;
18
+ line-height: 1em;
19
+ font-size: 12px;
20
+ }
21
+
22
+ ol.progress-steps li {
23
+ float: left;
24
+ padding: 6px;
25
+ }
26
+
27
+ ol.progress-steps li.current-first, ol.progress-steps li.current {
28
+ color: white;
29
+ background-image: url(../images/step-progress/current-first.gif);
30
+ }
31
+
32
+ /* Margins */
33
+ form { margin: 0; }
34
+ #line_items p { margin: 0; }
35
+ #footer { margin: 0em 0.5em; }
36
+ .ui-listview-inset { margin: 1em 0.5em; }
@@ -0,0 +1,30 @@
1
+ # This file is copied to ~/spec when you run 'ruby script/generate rspec'
2
+ # from the project root directory.
3
+ ENV["RAILS_ENV"] ||= 'test'
4
+ require File.expand_path("../test_app/config/environment", __FILE__)
5
+ require 'rspec/rails'
6
+
7
+ # Requires supporting files with custom matchers and macros, etc,
8
+ # in ./support/ and its subdirectories.
9
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
10
+
11
+ RSpec.configure do |config|
12
+ # == Mock Framework
13
+ #
14
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
15
+ #
16
+ # config.mock_with :mocha
17
+ # config.mock_with :flexmock
18
+ # config.mock_with :rr
19
+ config.mock_with :rspec
20
+
21
+ config.fixture_path = "#{::Rails.root}/spec/fixtures"
22
+
23
+ #config.include Devise::TestHelpers, :type => :controller
24
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
25
+ # examples within a transaction, comment the following line or assign false
26
+ # instead of true.
27
+ config.use_transactional_fixtures = true
28
+ end
29
+
30
+ @configuration ||= AppConfiguration.find_or_create_by_name("Default configuration")
@@ -0,0 +1,22 @@
1
+ Gem::Specification.new do |s|
2
+ s.platform = Gem::Platform::RUBY
3
+ s.name = 'spree_mobile_views'
4
+ s.version = '0.50.0'
5
+ s.summary = 'Adds support of mobile devices to Spree stores'
6
+ s.description = 'Works through jQuery Mobile'
7
+ s.required_ruby_version = '>= 1.8.7'
8
+
9
+ s.author = 'Roman Smirnov'
10
+ s.email = 'roman@railsdog.com'
11
+ # s.homepage = 'http://www.rubyonrails.org'
12
+ # s.rubyforge_project = 'actionmailer'
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.require_path = 'lib'
17
+ s.requirements << 'none'
18
+
19
+ s.has_rdoc = true
20
+
21
+ s.add_dependency('spree_core', '>= 0.50.0')
22
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spree_mobile_views
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 50
8
+ - 0
9
+ version: 0.50.0
10
+ platform: ruby
11
+ authors:
12
+ - Roman Smirnov
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-04-03 00:00:00 +04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: spree_core
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ - 50
30
+ - 0
31
+ version: 0.50.0
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ description: Works through jQuery Mobile
35
+ email: roman@railsdog.com
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files: []
41
+
42
+ files:
43
+ - .gitignore
44
+ - LICENSE
45
+ - README.md
46
+ - Rakefile
47
+ - Versionfile
48
+ - app/controllers/products_controller_decorator.rb
49
+ - app/helpers/base_helper_decorator.rb
50
+ - app/mobile_views/checkout/_address.html.erb
51
+ - app/mobile_views/checkout/_delivery.html.erb
52
+ - app/mobile_views/checkout/_payment.html.erb
53
+ - app/mobile_views/checkout/edit.html.erb
54
+ - app/mobile_views/checkout/payment/_gateway.html.erb
55
+ - app/mobile_views/layouts/spree_application.html.erb
56
+ - app/mobile_views/orders/_form.html.erb
57
+ - app/mobile_views/orders/_line_item.html.erb
58
+ - app/mobile_views/orders/edit.html.erb
59
+ - app/mobile_views/products/_cart_form.html.erb
60
+ - app/mobile_views/products/index.html.erb
61
+ - app/mobile_views/products/search.html.erb
62
+ - app/mobile_views/products/show.html.erb
63
+ - app/mobile_views/shared/_order_details.html.erb
64
+ - app/mobile_views/shared/_products.html.erb
65
+ - app/mobile_views/taxons/index.html.erb
66
+ - app/mobile_views/taxons/show.html.erb
67
+ - config/routes.rb
68
+ - lib/spree_mobile_views.rb
69
+ - lib/spree_mobile_views_hooks.rb
70
+ - lib/tasks/install.rake
71
+ - lib/tasks/spree_mobile_views.rake
72
+ - public/stylesheets/mobile.css
73
+ - spec/spec_helper.rb
74
+ - spree_mobile_views.gemspec
75
+ has_rdoc: true
76
+ homepage:
77
+ licenses: []
78
+
79
+ post_install_message:
80
+ rdoc_options: []
81
+
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ segments:
89
+ - 1
90
+ - 8
91
+ - 7
92
+ version: 1.8.7
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ segments:
98
+ - 0
99
+ version: "0"
100
+ requirements:
101
+ - none
102
+ rubyforge_project:
103
+ rubygems_version: 1.3.6
104
+ signing_key:
105
+ specification_version: 3
106
+ summary: Adds support of mobile devices to Spree stores
107
+ test_files: []
108
+