Created
May 31, 2011 18:21
-
-
Save citrus/1001016 to your computer and use it in GitHub Desktop.
custom variant selection in spree
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<% option_count = 0 %> | |
<%= form_for :order, :url => populate_orders_url do |f| %> | |
<% if @product.has_variants? %> | |
<div id="product-variants"> | |
<% if defined?(@options) && !@options.empty? %> | |
<% @options.each_with_index do |option,index| %> | |
<% option_count += 1 %> | |
<% name = option[0].name.downcase %> | |
<div class="product-options"> | |
<h2>Choose Your <%= name.capitalize %></h2> | |
<%= link_to "(clear)", "#clear", :class => 'clear' %> | |
<%= hidden_field_tag "option_type[#{index}][]", option[0].id, :class => 'option_type hidden' %> | |
<ul id="product-<%= name %>" class="list-<%= index %>"> | |
<%= render :partial => 'product_options', :locals => { :option_type => option[0], :options => option[1] } %> | |
</ul> | |
<br class="clear"/> | |
</div> | |
<% end %> | |
<% end %> | |
</div> | |
<% end %> | |
<% if 0 < option_count && @product.has_stock? || Spree::Config[:allow_backorders] %> | |
<div class="leftie"> | |
<p class="quantity">Quantity</p> | |
<div class="frameSmall"> | |
<%= text_field_tag (@product.has_variants? ? :quantity : "variants[#{@product.master.id}]"), 1, :class => "numbers", :size => 3 %> | |
</div> | |
</div> | |
<div class="rightie"> | |
<%= hidden_field_tag 'product_permalink', @product.permalink %> | |
<button type="submit" class="add-to-cart">Add To Cart</button> | |
</div> | |
<br class="clear"/> | |
<% else %> | |
<h4 class="out-of-stock">> <%= t('out_of_stock') %> <</h4> | |
<% end %> | |
<% end %> | |
<% content_for :head do %> | |
<%= javascript_include_tag 'product_options' %> | |
<% end %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<% product ||= @product %> | |
<% options ||= nil %> | |
<% if options.nil? %> | |
<li class="empty"> | |
<h5>No options..</h5> | |
</li> | |
<% elsif options.empty? %> | |
<li class="empty"> | |
<h5>Please select an option above first..</h5> | |
</li> | |
<% else %> | |
<% options.each_with_index do |option_value,index| %> | |
<% if @option_value && @variants %> | |
<% | |
a = OptionValueVariant.includes(:variant).where(:variant_id => @variants.collect(&:id), :option_value_id => [@option_value.id, option_value.id]).collect(&:variant_id) | |
b = Hash.new(0) | |
a.each{ |v| b[v.to_s.strip] += 1 } | |
var = @variants.find(b.invert.values_at(2)).first rescue nil | |
%> | |
<% else %> | |
<% var = @product.variants.joins(:option_value_variants).where("option_value_variants.option_value_id" => option_value.id).first %> | |
<% var.count_on_hand = 999 %> | |
<% end %> | |
<li> | |
<% if var %> | |
<% if var.count_on_hand == 0 %> | |
<%= image_tag "out_of_stock.png", :alt => "Out of Stock", :class => "out_of_stock" %> | |
<% end %> | |
<script type="text/javascript"> | |
//<![CDATA[ | |
Optys.prices[<%= var.id %>] = [<%= var.price %>, <%= var.wholesale_price if var.is_wholesaleable? %>, <%= var.count_on_hand %>]; | |
//]]> | |
</script> | |
<% end %> | |
<label class="<%= var && var.count_on_hand == 0 ? 'out-of-stock' : 'in-stock' %>"> | |
<span class="radio"> | |
<%= hidden_field_tag "variants[][#{var.id}", var.id, :class => 'hidden' if var %> | |
<%= radio_button_tag "options[#{product.id}][#{option_type.id}]", option_value.id, false %> | |
<%= link_to (option_value.has_image? ? image_tag(option_value.image.url, :alt => option_value.name) : content_tag(:span, option_value.name.html_safe)), "#select", :class => 'radio' %> | |
</span> | |
</label> | |
</li> | |
<% end %> | |
<% end %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var Optys = { | |
prices: [] | |
}; | |
;(function($){ | |
function formatted_price(price, label) { | |
var p = parseFloat(price) || 0.0; | |
var str = label ? label + ": $" : "$" | |
str = str + p.toFixed(2); | |
return str; | |
} | |
$.extend(Optys, { | |
selected_options: {}, | |
init: function(evt) { | |
$.preloadImages('/images/spinner.gif'); | |
Optys.count = $('#product-variants .product-options').length; | |
Optys.toggle_button(false); | |
$('#product-variants a.clear').live('click', function(evt) { | |
evt.preventDefault(); | |
var p = $(this).hide().parent(); | |
p.find('ul li label').css('opacity', 1); | |
p.find('span').css('background-position', '0 0'); | |
Optys.clear_after(parseInt((p.find('ul').attr('class').match(/[0-9]+/) || [0])[0])); | |
}); | |
$('#product-variants a.radio').live('mouseover', function(evt) { | |
if (!Optys.selection || $(this).data('selected')) return; | |
$(this).parents('li').css('opacity', 1); | |
}).live('mouseout', function(evt) { | |
if (!Optys.selection || $(this).data('selected')) return; | |
$(this).parents('li').css('opacity', 0.25); | |
}).live('click', function(evt) { | |
evt.preventDefault(); | |
if (Optys.loading) return; | |
var a = $(this).data('selected', true); | |
var v = a.siblings('input.hidden'); | |
var div = a.parents('div.product-options'); | |
var ul = div.find('ul'); | |
var index = parseInt((ul.attr('class').match(/[0-9]+/) || [0])[0]) + 1; | |
var vid = v.val(); | |
var prices = Optys.prices[v.val()]; | |
if (vid && prices) { | |
//if (parseInt(prices[2]) < 1) { | |
// evt.preventDefault(); | |
// | |
// | |
// return false; | |
//} | |
var p = $('.price_msrp'); | |
if (!p.length) { | |
$('#product-title .price').text(formatted_price(prices[0])); | |
} else { | |
p.text(formatted_price(prices[0], 'msrp')) | |
} | |
$('.price_wholesale').text(formatted_price(prices[1], 'wholesale')); | |
} | |
Optys.loading = true; | |
Optys.selection = this; | |
var radio = a.siblings('input[type=radio]').attr('checked', true); | |
var otid = div.find('input[type=hidden]').val(); | |
var ovid = div.find('input[type=radio]:checked').val(); | |
var url = "/shop/"+$('#product_permalink').attr('value')+"/variant"; | |
div.find('a.clear').show(); | |
ul.find('li label').css('opacity', 0.25); | |
ul.find('span.radio').css('background-position', '0 0'); | |
a.parents('span').css('background-position', '0 bottom'); | |
a.tipsy('hide').parents('label').css('opacity', 1); | |
Optys.selected_options[otid] = ovid; | |
Optys.clear_after(index); | |
var list = $('#product-variants .list-' + index); | |
if (list.length) { | |
list.addClass('list-loaded').empty().append('<li><p><img src="/images/spinner.gif" alt="loading.." class="option-loading" /> Loading...</p></li>'); | |
var url = "/shop/"+$('#product_permalink').attr('value')+"/options"; | |
$.get(url, { | |
p: ul.attr('id'), | |
n: list.attr('id'), | |
ntid: list.parent().find('input[type=hidden]').val(), | |
otid: otid, | |
ovid: ovid | |
}, function(result) { | |
list.html(result); | |
Optys.index = index; | |
Optys.loading = false; | |
}); | |
} | |
}).tipsy({ gravity: 'e', html: true, live: true, opacity: 1, offset: -3, title: function(evt) { | |
var img = $(this).find('img'); | |
if (!img.length) return ''; | |
$('.tipsy-inner').css('background', '#fff url(/images/spinner.gif) center center no-repeat'); | |
var image = '<img src="'+img.attr('src').replace('/small/', '/large/')+'" alt="loading" class="option-preview"/>' | |
var title = '<b>' + img.attr('alt') + '</b>'; | |
var vari = $(this).siblings('input.hidden').val(); | |
return image + title + (Optys.prices[vari][2] == 0 ? '<span>out of stock</span>' : ''); | |
}}); | |
}, | |
toggle_button: function(enabled) { | |
if (enabled) { | |
$('.add-to-cart').removeClass('disabled').addClass('enabled').unbind('click'); | |
} else { | |
$('.add-to-cart').removeClass('enabled').addClass('disabled').click(function(evt) { evt.preventDefault(); }); | |
} | |
}, | |
clear_after: function(index) { | |
Optys.index = index; | |
function get_list(i) { | |
return $('#product-variants .list-' + (i + 1) + '.list-loaded').empty(); | |
} | |
var ul = get_list(index); | |
var i = index; | |
while(ul.length) { | |
if (!ul.find('li.empty').length) { | |
ul.empty(); | |
ul.parent().find('a.clear').hide(); | |
ul.append('<li class="empty">Please select an option above..</li>'); | |
} | |
ul = get_list(i); | |
i++; | |
if (99 < i) break; | |
} | |
Optys.reset(); | |
}, | |
reset: function() { | |
Optys.selection = null; | |
Optys.loading = false; | |
Optys.toggle_button(Optys.index == Optys.count); | |
} | |
}); | |
$(document).ready(Optys.init); | |
})(jQuery); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# just the important stuff | |
def show | |
@product = Product.find_by_permalink!(params[:id]) | |
return unless @product | |
get_options | |
@variants = Variant.active.find_all_by_product_id(@product.id, | |
:include => [:option_values, :images]) | |
@product_properties = ProductProperty.find_all_by_product_id(@product.id, | |
:include => [:property]) | |
@selected_variant = @variants.detect { |v| v.available? } | |
referer = request.env['HTTP_REFERER'] | |
if referer && referer.match(HTTP_REFERER_REGEXP) | |
@taxon = Taxon.find_by_permalink($1) | |
end | |
end | |
def options | |
@product = Product.find_by_permalink(params[:id]) | |
if params[:p] | |
prev_name = params[:p].sub('product-', '') | |
end | |
if params[:n] | |
name = params[:n].sub('product-', '') | |
end | |
@index = params[:i].to_i | |
get_options | |
render :partial => 'product_options', :locals => { :option_type => @next_option_type, :options => @options[@index][1], :product => @product, :name => name, :last_name => prev_name, :variants => @variants } | |
end | |
def get_options | |
return if @product.nil? | |
@options = [] | |
@index ||= 0 | |
@values = nil | |
option_type = @product.option_types.find(params[:otid]) rescue @product.option_types.first | |
if option_type | |
@next_option_type = @product.option_types.find(params[:ntid]) rescue nil | |
if @next_option_type && params[:ovid] | |
@option_value = option_type.option_values.find(params[:ovid]) | |
@variants = @option_value.variants.select('variants.id').where('deleted_at IS NULL').where(:product_id => @product.id) | |
else | |
@next_option_type = option_type | |
@variants = @product.variants | |
end | |
vids = @variants.collect(&:id) | |
@values = OptionValue.joins(:option_value_variants).where("option_value_variants.product_id = ? AND option_value_variants.variant_id IN (?) AND option_values.option_type_id = ?", @product.id, vids, @next_option_type.id).order("option_values.position ASC").uniq | |
end | |
@product.option_types.each_with_index do |op, index| | |
@values ||= @product.option_values.where(:option_type_id => op.id).uniq | |
@options << [op, index == @index ? @values : []] | |
end | |
@options | |
end | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# just the important stuff | |
resources :products, :path => 'shop' do | |
member do | |
get :options | |
end | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment