show owned/wanted icons and search filters

This commit is contained in:
Emi Matchu 2011-07-22 16:18:15 -04:00
parent b1670b1595
commit 6d155ecaf1
8 changed files with 101 additions and 40 deletions

View file

@ -48,15 +48,26 @@ module ItemsHelper
end end
end end
def closeted_icon_for(item) def closeted_icons_for(item)
if item.closeted? content = ''.html_safe
image_tag(
'closeted.png', if item.owned?
content << image_tag(
'owned.png',
:title => 'You own this', :title => 'You own this',
:alt => 'Closet', :alt => 'Own'
:class => 'closeted-icon'
) )
end end
if item.wanted?
content << image_tag(
'wanted.png',
:title => 'You want this',
:alt => 'Want'
)
end
content_tag :div, content, :class => 'closeted-icons'
end end
def list_zones(zones, method=:label) def list_zones(zones, method=:label)

View file

@ -10,7 +10,7 @@ class Item < ActiveRecord::Base
has_many :swf_assets, :through => :parent_swf_asset_relationships, :source => :object_asset, has_many :swf_assets, :through => :parent_swf_asset_relationships, :source => :object_asset,
:conditions => {:type => SwfAssetType} :conditions => {:type => SwfAssetType}
attr_writer :closeted, :current_body_id attr_writer :current_body_id, :owned, :wanted
NCRarities = [0, 500] NCRarities = [0, 500]
PAINTBRUSH_SET_DESCRIPTION = 'This item is part of a deluxe paint brush set!' PAINTBRUSH_SET_DESCRIPTION = 'This item is part of a deluxe paint brush set!'
@ -46,13 +46,21 @@ class Item < ActiveRecord::Base
scope :with_closet_hangers, joins(:closet_hangers) scope :with_closet_hangers, joins(:closet_hangers)
def closeted? def closeted?
!!@closeted @owned || @wanted
end end
def nc? def nc?
NCRarities.include?(rarity_index) NCRarities.include?(rarity_index)
end end
def owned?
@owned
end
def wanted?
@wanted
end
def restricted_zones def restricted_zones
unless @restricted_zones unless @restricted_zones
@restricted_zones = [] @restricted_zones = []
@ -639,7 +647,10 @@ class Item < ActiveRecord::Base
def self.search_filter_block(options, positive, &block) def self.search_filter_block(options, positive, &block)
Proc.new { |str, user, scope| Proc.new { |str, user, scope|
condition = block.arity == 1 ? block.call(str) : block.call(str, user) condition = block.arity == 1 ? block.call(str) : block.call(str, user)
condition = "!(#{condition.to_sql})" unless positive unless positive
condition = condition.to_sql if condition.respond_to?(:to_sql)
condition = "!(#{condition})"
end
scope = scope.send(options[:scope]) if options[:scope] scope = scope.send(options[:scope]) if options[:scope]
scope.where(condition) scope.where(condition)
} }
@ -667,25 +678,45 @@ class Item < ActiveRecord::Base
filter filter
end end
def self.validate_user_condition(adjective, user) USER_ADJECTIVES = {
unless adjective == "owns" 'own' => true,
'owns' => true,
'owned' => true,
'want' => false,
'wants' => false,
'wanted' => false,
'all' => nil,
'items' => nil
}
def self.parse_user_adjective(adjective, user)
unless USER_ADJECTIVES.has_key?(adjective)
raise SearchError, "We don't understand user:#{adjective}. " + raise SearchError, "We don't understand user:#{adjective}. " +
"Did you mean user:owns?" "Find items you own with user:owns, items you want with user:wants, or " +
"both with user:all"
end end
unless user unless user
raise SearchError, "It looks like you're not logged in, so you don't own any items." raise SearchError, "It looks like you're not logged in, so you don't own any items."
end end
USER_ADJECTIVES[adjective]
end end
single_search_filter :user, :full => lambda { |adjective, user, scope| search_filter :user do |adjective, user|
validate_user_condition(adjective, user) # Though joins may seem more efficient here for the positive case, we need
scope.joins(:closet_hangers).where(ClosetHanger.arel_table[:user_id].eq(user.id)) # to be able to handle cases like "user:owns user:wants", which breaks on
} # the JOIN approach. Just have to look up the IDs in advance.
single_search_filter :not_user do |adjective, user| owned_value = parse_user_adjective(adjective, user)
validate_user_condition(adjective, user) hangers = ClosetHanger.arel_table
arel_table[:id].not_in(user.closeted_items.map(&:id)) items = user.closeted_items
items = items.where(ClosetHanger.arel_table[:owned].eq(owned_value)) unless owned_value.nil?
item_ids = items.map(&:id)
# Though it's best to do arel_table[:id].in(item_ids), it breaks in this
# version of Arel, and other conditions will overwrite this one. Since IDs
# are guaranteed to be integers, let's just build our own string condition
# and be done with it.
"id IN (#{item_ids.join(',')})"
end end
search_filter :only do |species_name| search_filter :only do |species_name|

View file

@ -49,8 +49,14 @@ class User < ActiveRecord::Base
# versa, and everything stays a lovely O(n) # versa, and everything stays a lovely O(n)
items_by_id = {} items_by_id = {}
items.each { |item| items_by_id[item.id] = item } items.each { |item| items_by_id[item.id] = item }
closeted_item_ids = closeted_items.where(:id => items_by_id.keys).map(&:id) closet_hangers.where(:item_id => items_by_id.keys).each do |hanger|
closeted_item_ids.each { |id| items_by_id[id].closeted = true } item = items_by_id[hanger.item_id]
if hanger.owned?
item.owned = true
else
item.wanted = true
end
end
end end
def self.find_or_create_from_remote_auth_data(user_data) def self.find_or_create_from_remote_auth_data(user_data)

View file

@ -178,19 +178,25 @@ ul.buttons
// (quantity form in user items) // (quantity form in user items)
+opacity(1) +opacity(1)
.nc-icon, .closeted-icon .nc-icon, .closeted-icons
+opacity(1) +opacity(1)
height: $nc-icon-size background: rgba(255, 255, 255, 0.75)
line-height: 1
position: absolute position: absolute
top: $object-img-size - $nc-icon-size top: $object-img-size - $nc-icon-size
width: $nc-icon-size
&:hover &:hover
+opacity(0.5) +opacity(0.5)
background: transparent
.nc-icon, .closeted-icons img
display: inline
height: $nc-icon-size
width: $nc-icon-size
.nc-icon .nc-icon
right: ($object-width - $object-img-size) / 2 + $object-padding right: ($object-width - $object-img-size) / 2 + $object-padding
.closeted-icon .closeted-icons
left: ($object-width - $object-img-size) / 2 + $object-padding left: ($object-width - $object-img-size) / 2 + $object-padding
dt dt

View file

@ -2,5 +2,5 @@
= image_tag item.thumbnail_url, :alt => item.description, :title => item.description = image_tag item.thumbnail_url, :alt => item.description, :title => item.description
= item.name = item.name
= nc_icon_for(item) = nc_icon_for(item)
= closeted_icon_for(item) = closeted_icons_for(item)

View file

Before

Width:  |  Height:  |  Size: 537 B

After

Width:  |  Height:  |  Size: 537 B

BIN
public/images/wanted.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 671 B

View file

@ -304,43 +304,50 @@ ul.buttons li, ul.buttons li form {
-khtml-opacity: 1; -khtml-opacity: 1;
} }
/* line 181, ../../../app/stylesheets/_layout.sass */ /* line 181, ../../../app/stylesheets/_layout.sass */
.object .nc-icon, .object .closeted-icon { .object .nc-icon, .object .closeted-icons {
-moz-opacity: 1; -moz-opacity: 1;
-webkit-opacity: 1; -webkit-opacity: 1;
-o-opacity: 1; -o-opacity: 1;
-khtml-opacity: 1; -khtml-opacity: 1;
height: 16px; background: rgba(255, 255, 255, 0.75);
line-height: 1;
position: absolute; position: absolute;
top: 64px; top: 64px;
width: 16px;
} }
/* line 187, ../../../app/stylesheets/_layout.sass */ /* line 187, ../../../app/stylesheets/_layout.sass */
.object .nc-icon:hover, .object .closeted-icon:hover { .object .nc-icon:hover, .object .closeted-icons:hover {
-moz-opacity: 0.5; -moz-opacity: 0.5;
-webkit-opacity: 0.5; -webkit-opacity: 0.5;
-o-opacity: 0.5; -o-opacity: 0.5;
-khtml-opacity: 0.5; -khtml-opacity: 0.5;
background: transparent;
} }
/* line 190, ../../../app/stylesheets/_layout.sass */ /* line 191, ../../../app/stylesheets/_layout.sass */
.object .nc-icon, .object .closeted-icons img {
display: inline;
height: 16px;
width: 16px;
}
/* line 196, ../../../app/stylesheets/_layout.sass */
.object .nc-icon { .object .nc-icon {
right: 18px; right: 18px;
} }
/* line 193, ../../../app/stylesheets/_layout.sass */ /* line 199, ../../../app/stylesheets/_layout.sass */
.object .closeted-icon { .object .closeted-icons {
left: 18px; left: 18px;
} }
/* line 196, ../../../app/stylesheets/_layout.sass */ /* line 202, ../../../app/stylesheets/_layout.sass */
dt { dt {
font-weight: bold; font-weight: bold;
} }
/* line 199, ../../../app/stylesheets/_layout.sass */ /* line 205, ../../../app/stylesheets/_layout.sass */
dd { dd {
margin: 0 0 1.5em 1em; margin: 0 0 1.5em 1em;
} }
/* line 202, ../../../app/stylesheets/_layout.sass */ /* line 208, ../../../app/stylesheets/_layout.sass */
#home-link { #home-link {
font-family: Delicious, Helvetica, Arial, Verdana, sans-serif; font-family: Delicious, Helvetica, Arial, Verdana, sans-serif;
font-size: 175%; font-size: 175%;
@ -351,21 +358,21 @@ dd {
position: absolute; position: absolute;
top: 0; top: 0;
} }
/* line 212, ../../../app/stylesheets/_layout.sass */ /* line 218, ../../../app/stylesheets/_layout.sass */
#home-link:hover { #home-link:hover {
background: #eeffee; background: #eeffee;
text-decoration: none; text-decoration: none;
} }
/* line 215, ../../../app/stylesheets/_layout.sass */ /* line 221, ../../../app/stylesheets/_layout.sass */
#home-link span:before { #home-link span:before {
content: "<< "; content: "<< ";
} }
/* line 219, ../../../app/stylesheets/_layout.sass */ /* line 225, ../../../app/stylesheets/_layout.sass */
.pagination a, .pagination span { .pagination a, .pagination span {
margin: 0 0.5em; margin: 0 0.5em;
} }
/* line 221, ../../../app/stylesheets/_layout.sass */ /* line 227, ../../../app/stylesheets/_layout.sass */
.pagination .current { .pagination .current {
font-weight: bold; font-weight: bold;
} }