Merge branch 'outfit_thumbnails'
7
Gemfile
|
@ -41,6 +41,13 @@ gem 'newrelic_rpm'
|
||||||
|
|
||||||
gem 'neopets', :git => 'git://github.com/matchu/neopets.git'
|
gem 'neopets', :git => 'git://github.com/matchu/neopets.git'
|
||||||
|
|
||||||
|
gem "mini_magick", "~> 3.4"
|
||||||
|
|
||||||
|
gem "fog", "~> 1.1.2"
|
||||||
|
gem "carrierwave", "~> 0.5.8"
|
||||||
|
|
||||||
|
gem "parallel", "~> 0.5.17"
|
||||||
|
|
||||||
group :development_async do
|
group :development_async do
|
||||||
# async wrappers
|
# async wrappers
|
||||||
gem 'eventmachine', :git => 'git://github.com/eventmachine/eventmachine.git'
|
gem 'eventmachine', :git => 'git://github.com/eventmachine/eventmachine.git'
|
||||||
|
|
26
Gemfile.lock
|
@ -86,6 +86,8 @@ GEM
|
||||||
arel (2.0.10)
|
arel (2.0.10)
|
||||||
bcrypt-ruby (2.1.4)
|
bcrypt-ruby (2.1.4)
|
||||||
builder (2.1.2)
|
builder (2.1.2)
|
||||||
|
carrierwave (0.5.8)
|
||||||
|
activesupport (~> 3.0)
|
||||||
character-encodings (0.4.1)
|
character-encodings (0.4.1)
|
||||||
chronic (0.6.7)
|
chronic (0.6.7)
|
||||||
closure-compiler (1.1.4)
|
closure-compiler (1.1.4)
|
||||||
|
@ -100,11 +102,23 @@ GEM
|
||||||
eventmachine
|
eventmachine
|
||||||
erubis (2.6.6)
|
erubis (2.6.6)
|
||||||
abstract (>= 1.0.0)
|
abstract (>= 1.0.0)
|
||||||
|
excon (0.9.6)
|
||||||
factory_girl (2.3.2)
|
factory_girl (2.3.2)
|
||||||
activesupport
|
activesupport
|
||||||
factory_girl_rails (1.4.0)
|
factory_girl_rails (1.4.0)
|
||||||
factory_girl (~> 2.3.0)
|
factory_girl (~> 2.3.0)
|
||||||
railties (>= 3.0.0)
|
railties (>= 3.0.0)
|
||||||
|
fog (1.1.2)
|
||||||
|
builder
|
||||||
|
excon (~> 0.9.0)
|
||||||
|
formatador (~> 0.2.0)
|
||||||
|
mime-types
|
||||||
|
multi_json (~> 1.0.3)
|
||||||
|
net-scp (~> 1.0.4)
|
||||||
|
net-ssh (>= 2.1.3)
|
||||||
|
nokogiri (~> 1.5.0)
|
||||||
|
ruby-hmac
|
||||||
|
formatador (0.2.1)
|
||||||
haml (3.0.25)
|
haml (3.0.25)
|
||||||
hoptoad_notifier (2.4.11)
|
hoptoad_notifier (2.4.11)
|
||||||
activesupport
|
activesupport
|
||||||
|
@ -122,13 +136,20 @@ GEM
|
||||||
treetop (~> 1.4.8)
|
treetop (~> 1.4.8)
|
||||||
memcache-client (1.8.5)
|
memcache-client (1.8.5)
|
||||||
mime-types (1.17.2)
|
mime-types (1.17.2)
|
||||||
|
mini_magick (3.4)
|
||||||
|
subexec (~> 0.2.1)
|
||||||
msgpack (0.4.6)
|
msgpack (0.4.6)
|
||||||
|
multi_json (1.0.4)
|
||||||
mysql2 (0.2.6)
|
mysql2 (0.2.6)
|
||||||
|
net-scp (1.0.4)
|
||||||
|
net-ssh (>= 1.99.1)
|
||||||
|
net-ssh (2.3.0)
|
||||||
newrelic_rpm (3.3.3)
|
newrelic_rpm (3.3.3)
|
||||||
nokogiri (1.5.3)
|
nokogiri (1.5.3)
|
||||||
open4 (1.3.0)
|
open4 (1.3.0)
|
||||||
openneo-auth-signatory (0.1.0)
|
openneo-auth-signatory (0.1.0)
|
||||||
ruby-hmac
|
ruby-hmac
|
||||||
|
parallel (0.5.17)
|
||||||
polyglot (0.3.3)
|
polyglot (0.3.3)
|
||||||
rack (1.2.5)
|
rack (1.2.5)
|
||||||
rack-fiber_pool (0.9.2)
|
rack-fiber_pool (0.9.2)
|
||||||
|
@ -189,6 +210,7 @@ GEM
|
||||||
sinatra (1.2.8)
|
sinatra (1.2.8)
|
||||||
rack (~> 1.1)
|
rack (~> 1.1)
|
||||||
tilt (>= 1.2.2, < 2.0)
|
tilt (>= 1.2.2, < 2.0)
|
||||||
|
subexec (0.2.1)
|
||||||
swf_converter (0.0.3)
|
swf_converter (0.0.3)
|
||||||
thor (0.14.6)
|
thor (0.14.6)
|
||||||
tilt (1.3.3)
|
tilt (1.3.3)
|
||||||
|
@ -213,6 +235,7 @@ PLATFORMS
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
RocketAMF!
|
RocketAMF!
|
||||||
addressable
|
addressable
|
||||||
|
carrierwave (~> 0.5.8)
|
||||||
character-encodings (~> 0.4.1)
|
character-encodings (~> 0.4.1)
|
||||||
compass (~> 0.10.1)
|
compass (~> 0.10.1)
|
||||||
devise (~> 1.1.5)
|
devise (~> 1.1.5)
|
||||||
|
@ -221,10 +244,12 @@ DEPENDENCIES
|
||||||
em-synchrony!
|
em-synchrony!
|
||||||
eventmachine!
|
eventmachine!
|
||||||
factory_girl_rails (~> 1.0)
|
factory_girl_rails (~> 1.0)
|
||||||
|
fog (~> 1.1.2)
|
||||||
haml (~> 3.0.18)
|
haml (~> 3.0.18)
|
||||||
hoptoad_notifier
|
hoptoad_notifier
|
||||||
jammit (~> 0.5.3)
|
jammit (~> 0.5.3)
|
||||||
memcache-client (~> 1.8.5)
|
memcache-client (~> 1.8.5)
|
||||||
|
mini_magick (~> 3.4)
|
||||||
msgpack (~> 0.4.3)
|
msgpack (~> 0.4.3)
|
||||||
mysql2 (< 0.3)
|
mysql2 (< 0.3)
|
||||||
mysqlplus!
|
mysqlplus!
|
||||||
|
@ -232,6 +257,7 @@ DEPENDENCIES
|
||||||
newrelic_rpm
|
newrelic_rpm
|
||||||
nokogiri (~> 1.5.2)
|
nokogiri (~> 1.5.2)
|
||||||
openneo-auth-signatory (~> 0.1.0)
|
openneo-auth-signatory (~> 0.1.0)
|
||||||
|
parallel (~> 0.5.17)
|
||||||
rack-fiber_pool
|
rack-fiber_pool
|
||||||
rails (= 3.0.5)
|
rails (= 3.0.5)
|
||||||
rdiscount (~> 1.6.5)
|
rdiscount (~> 1.6.5)
|
||||||
|
|
|
@ -2,18 +2,11 @@ class OutfitsController < ApplicationController
|
||||||
before_filter :find_authorized_outfit, :only => [:update, :destroy]
|
before_filter :find_authorized_outfit, :only => [:update, :destroy]
|
||||||
|
|
||||||
def create
|
def create
|
||||||
Rails.logger.debug "Signed in?: #{user_signed_in?}"
|
|
||||||
Rails.logger.debug "User 1: #{current_user.inspect}"
|
|
||||||
@outfit = Outfit.build_for_user(current_user, params[:outfit])
|
@outfit = Outfit.build_for_user(current_user, params[:outfit])
|
||||||
Rails.logger.debug "User 2: #{current_user.inspect}"
|
|
||||||
if @outfit.save
|
if @outfit.save
|
||||||
Rails.logger.debug "User 3: #{current_user.inspect}"
|
render :json => @outfit
|
||||||
render :json => @outfit.id
|
|
||||||
Rails.logger.debug "User 4: #{current_user.inspect}"
|
|
||||||
else
|
else
|
||||||
Rails.logger.debug "User 5: #{current_user.inspect}"
|
|
||||||
render_outfit_errors
|
render_outfit_errors
|
||||||
Rails.logger.debug "User 6: #{current_user.inspect}"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -82,7 +75,7 @@ class OutfitsController < ApplicationController
|
||||||
|
|
||||||
def update
|
def update
|
||||||
if @outfit.update_attributes(params[:outfit])
|
if @outfit.update_attributes(params[:outfit])
|
||||||
render :json => true
|
render :json => @outfit
|
||||||
else
|
else
|
||||||
render_outfit_errors
|
render_outfit_errors
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,12 @@
|
||||||
module ApplicationHelper
|
module ApplicationHelper
|
||||||
|
def absolute_url(path_or_url)
|
||||||
|
if path_or_url.include?('://') # already an absolute URL
|
||||||
|
path_or_url
|
||||||
|
else # a relative path
|
||||||
|
request.protocol + request.host_with_port + path_or_url
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def add_body_class(class_name)
|
def add_body_class(class_name)
|
||||||
@body_class ||= ''
|
@body_class ||= ''
|
||||||
@body_class << " #{class_name}"
|
@body_class << " #{class_name}"
|
||||||
|
@ -101,6 +109,23 @@ module ApplicationHelper
|
||||||
hidden_field_tag 'origin', value, :id => nil
|
hidden_field_tag 'origin', value, :id => nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def open_graph(properties)
|
||||||
|
if @open_graph
|
||||||
|
@open_graph.merge! properties
|
||||||
|
else
|
||||||
|
@open_graph = properties
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def open_graph_tags
|
||||||
|
if @open_graph
|
||||||
|
@open_graph.inject('') do |output, property|
|
||||||
|
key, value = property
|
||||||
|
output + tag(:meta, :property => "og:#{key}", :content => value)
|
||||||
|
end.html_safe
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def return_to_field_tag
|
def return_to_field_tag
|
||||||
hidden_field_tag :return_to, request.fullpath
|
hidden_field_tag :return_to, request.fullpath
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,9 +13,22 @@ class Outfit < ActiveRecord::Base
|
||||||
|
|
||||||
scope :wardrobe_order, order('starred DESC', :name)
|
scope :wardrobe_order, order('starred DESC', :name)
|
||||||
|
|
||||||
|
mount_uploader :image, OutfitImageUploader
|
||||||
|
|
||||||
|
before_save :update_enqueued_image
|
||||||
|
after_commit :enqueue_image!
|
||||||
|
|
||||||
def as_json(more_options={})
|
def as_json(more_options={})
|
||||||
serializable_hash :only => [:id, :name, :pet_state_id, :starred],
|
serializable_hash :only => [:id, :name, :pet_state_id, :starred],
|
||||||
:methods => [:color_id, :species_id, :worn_and_unworn_item_ids]
|
:methods => [:color_id, :species_id, :worn_and_unworn_item_ids,
|
||||||
|
:image_versions, :image_enqueued, :image_layers_hash]
|
||||||
|
end
|
||||||
|
|
||||||
|
def image_versions
|
||||||
|
{}.tap do |versions|
|
||||||
|
versions[:large] = image.url
|
||||||
|
image.versions.each { |name, version| versions[name] = version.url }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def closet_item_ids
|
def closet_item_ids
|
||||||
|
@ -65,8 +78,44 @@ class Outfit < ActiveRecord::Base
|
||||||
self.item_outfit_relationships = new_rels
|
self.item_outfit_relationships = new_rels
|
||||||
end
|
end
|
||||||
|
|
||||||
def worn_item_ids
|
# Returns the array of SwfAssets representing each layer of the output image,
|
||||||
worn_and_unworn_item_ids[:worn]
|
# ordered from bottom to top. Careful: this method is memoized, so if the
|
||||||
|
# image layers change after its first call we'll get bad results.
|
||||||
|
def image_layers
|
||||||
|
@image_layers ||= visible_assets_with_images.sort { |a, b| a.zone.depth <=> b.zone.depth }
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates and writes the thumbnail images for this outfit iff the new image
|
||||||
|
# would be different than the current one. (Writes to file in development,
|
||||||
|
# S3 in production.) If the image is updated, updates the image layers hash
|
||||||
|
# and runs #save! on the record, so any other changes will also be saved.
|
||||||
|
def write_image!
|
||||||
|
if image_layers_dirty?
|
||||||
|
Tempfile.open(['outfit_image', '.png']) do |image|
|
||||||
|
create_image! image
|
||||||
|
self.image_layers_hash = generate_image_layers_hash
|
||||||
|
self.image = image
|
||||||
|
self.image_enqueued = false
|
||||||
|
save!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.image
|
||||||
|
end
|
||||||
|
|
||||||
|
# Enqueue an image write iff the new image would be different than the
|
||||||
|
# current one.
|
||||||
|
def enqueue_image!
|
||||||
|
Resque.enqueue(OutfitImageUpdate, id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_enqueued_image
|
||||||
|
self.image_enqueued = (image_layers_dirty?)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def s3_key(size)
|
||||||
|
URI.encode("#{id}/#{size.join 'x'}.png")
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.build_for_user(user, params)
|
def self.build_for_user(user, params)
|
||||||
|
@ -82,5 +131,87 @@ class Outfit < ActiveRecord::Base
|
||||||
outfit.attributes = params
|
outfit.attributes = params
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
# Creates a 600x600 PNG image of this outfit, writing to the given output
|
||||||
|
# file.
|
||||||
|
def create_image!(output)
|
||||||
|
unless image_layers.empty?
|
||||||
|
temp_image_files = Parallel.map(image_layers, :in_threads => 8) do |swf_asset|
|
||||||
|
image_file = Tempfile.open(['outfit_layer', '.png'])
|
||||||
|
write_temp_swf_asset_image!(swf_asset, image_file)
|
||||||
|
image_file.close
|
||||||
|
image_file
|
||||||
|
end
|
||||||
|
|
||||||
|
# Here we do some awkwardness to get the exact ImageMagick command we
|
||||||
|
# want, though it's still less awkward than handling the command
|
||||||
|
# ourselves. Give all of the temporary images as input, flatten them and
|
||||||
|
# write them to the output path.
|
||||||
|
command = MiniMagick::CommandBuilder.new('convert')
|
||||||
|
temp_image_files.each { |image_file| command.push image_file.path }
|
||||||
|
command.layers 'flatten'
|
||||||
|
command.push output.path
|
||||||
|
|
||||||
|
# Though the above command really is sufficient, we still need a dummy
|
||||||
|
# image to handle execution.
|
||||||
|
output_image = MiniMagick::Image.new(output.path)
|
||||||
|
output_image.run(command)
|
||||||
|
|
||||||
|
temp_image_files.each(&:unlink)
|
||||||
|
else
|
||||||
|
output.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def visible_assets
|
||||||
|
biology_assets = pet_state.swf_assets
|
||||||
|
object_assets = SwfAsset.object_assets.
|
||||||
|
fitting_body_id(pet_state.pet_type.body_id).for_item_ids(worn_item_ids)
|
||||||
|
|
||||||
|
# Now for fun with bitmasks! Rather than building a bunch of integer arrays
|
||||||
|
# here, we instead go low-level and use bit-level operations. Build the
|
||||||
|
# bitmask by parsing the binary string (reversing it to get the lower zone
|
||||||
|
# numbers on the right), then OR them all together to get the mask
|
||||||
|
# representing all the restricted zones. (Note to self: why not just store
|
||||||
|
# in this format in the first place?)
|
||||||
|
restrictors = biology_assets + worn_items
|
||||||
|
restricted_zones_mask = restrictors.inject(0) do |mask, restrictor|
|
||||||
|
mask | restrictor.zones_restrict.reverse.to_i(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Now, check each asset's zone is not restricted in the bitmask using
|
||||||
|
# bitwise operations: shift 1 to the zone_id position, then AND it with
|
||||||
|
# the restricted zones mask. If we get 0, then the bit for that zone ID was
|
||||||
|
# not turned on, so the zone is not restricted and this asset is visible.
|
||||||
|
all_assets = biology_assets + object_assets
|
||||||
|
all_assets.select { |a| (1 << (a.zone_id - 1)) & restricted_zones_mask == 0 }
|
||||||
|
end
|
||||||
|
|
||||||
|
def visible_assets_with_images
|
||||||
|
visible_assets.select(&:has_image?)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Generate 8-char hex digest representing visible image layers for this outfit.
|
||||||
|
# Hash function should be decently collision-resistant.
|
||||||
|
def generate_image_layers_hash
|
||||||
|
@generated_image_layers_hash ||=
|
||||||
|
Digest::MD5.hexdigest(image_layers.map(&:id).join(',')).first(8)
|
||||||
|
end
|
||||||
|
|
||||||
|
def image_layers_dirty?
|
||||||
|
generate_image_layers_hash != self.image_layers_hash
|
||||||
|
end
|
||||||
|
|
||||||
|
IMAGE_BASE_SIZE = [600, 600]
|
||||||
|
def write_temp_swf_asset_image!(swf_asset, file)
|
||||||
|
key = swf_asset.s3_key(IMAGE_BASE_SIZE)
|
||||||
|
bucket = SwfAsset::IMAGE_BUCKET
|
||||||
|
data = bucket.get(key)
|
||||||
|
file.binmode # write in binary mode
|
||||||
|
file.truncate(0) # clear the file
|
||||||
|
file.write data # write the new data
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
15
app/models/outfit_image_update.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
class OutfitImageUpdate
|
||||||
|
@queue = :outfit_image_updates
|
||||||
|
|
||||||
|
def self.perform(id)
|
||||||
|
Outfit.find(id).write_image!
|
||||||
|
end
|
||||||
|
|
||||||
|
# Represents an outfit image update for an outfit that existed before this
|
||||||
|
# feature was built. Its queue has a lower priority, so new outfits will
|
||||||
|
# be updated before retroactively converted outfits.
|
||||||
|
class Retroactive < OutfitImageUpdate
|
||||||
|
@queue = :retroactive_outfit_image_updates
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
39
app/models/outfit_image_uploader.rb
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
require 'carrierwave/processing/mime_types'
|
||||||
|
|
||||||
|
class OutfitImageUploader < CarrierWave::Uploader::Base
|
||||||
|
include CarrierWave::MimeTypes
|
||||||
|
include CarrierWave::MiniMagick
|
||||||
|
|
||||||
|
# Settings for S3 storage. Will only be used on production.
|
||||||
|
fog_directory 'impress-outfit-images'
|
||||||
|
fog_attributes 'Cache-Control' => "max-age=#{15.minutes}",
|
||||||
|
'Content-Type' => 'image/png'
|
||||||
|
|
||||||
|
process :set_content_type
|
||||||
|
|
||||||
|
version :medium do
|
||||||
|
process :resize_to_fill => [300, 300]
|
||||||
|
end
|
||||||
|
|
||||||
|
version :small, :from_version => :medium do
|
||||||
|
process :resize_to_fill => [150, 150]
|
||||||
|
end
|
||||||
|
|
||||||
|
def filename
|
||||||
|
"preview.png"
|
||||||
|
end
|
||||||
|
|
||||||
|
def store_dir
|
||||||
|
"outfits/#{partition_dir}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# 123006789 => "123/006/789"
|
||||||
|
def partition_dir
|
||||||
|
partitions.map { |partition| "%03d" % partition }.join('/')
|
||||||
|
end
|
||||||
|
|
||||||
|
# 123006789 => [123, 6, 789]
|
||||||
|
def partitions
|
||||||
|
[6, 3, 0].map { |n| model.id / 10**n % 1000 }
|
||||||
|
end
|
||||||
|
end
|
|
@ -15,8 +15,14 @@ class SwfAsset < ActiveRecord::Base
|
||||||
|
|
||||||
set_inheritance_column 'inheritance_type'
|
set_inheritance_column 'inheritance_type'
|
||||||
|
|
||||||
|
IMAGE_SIZES = {
|
||||||
|
:small => [150, 150],
|
||||||
|
:medium => [300, 300],
|
||||||
|
:large => [600, 600]
|
||||||
|
}
|
||||||
|
|
||||||
include SwfConverter
|
include SwfConverter
|
||||||
converts_swfs :size => [600, 600], :output_sizes => [[150, 150], [300, 300], [600, 600]]
|
converts_swfs :size => IMAGE_SIZES[:large], :output_sizes => IMAGE_SIZES.values
|
||||||
|
|
||||||
def local_swf_path
|
def local_swf_path
|
||||||
LOCAL_ASSET_DIR.join(local_path_within_outfit_swfs)
|
LOCAL_ASSET_DIR.join(local_path_within_outfit_swfs)
|
||||||
|
@ -75,6 +81,21 @@ class SwfAsset < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def image_version
|
||||||
|
converted_at.to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
def image_url(size=IMAGE_SIZES[:large])
|
||||||
|
host = ASSET_HOSTS[:swf_asset_images]
|
||||||
|
size_key = size.join('x')
|
||||||
|
|
||||||
|
"http://#{host}/#{s3_path}/#{size_key}.png?#{image_version}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def images
|
||||||
|
IMAGE_SIZES.values.map { |size| {:size => size, :url => image_url(size)} }
|
||||||
|
end
|
||||||
|
|
||||||
def convert_swf_if_not_converted!
|
def convert_swf_if_not_converted!
|
||||||
if needs_conversion?
|
if needs_conversion?
|
||||||
convert_swf!
|
convert_swf!
|
||||||
|
@ -161,7 +182,7 @@ class SwfAsset < ActiveRecord::Base
|
||||||
:zones_restrict => zones_restrict,
|
:zones_restrict => zones_restrict,
|
||||||
:is_body_specific => body_specific?,
|
:is_body_specific => body_specific?,
|
||||||
:has_image => has_image?,
|
:has_image => has_image?,
|
||||||
:s3_path => s3_path
|
:images => images
|
||||||
}
|
}
|
||||||
if options[:for] == 'wardrobe'
|
if options[:for] == 'wardrobe'
|
||||||
json[:local_path] = local_url
|
json[:local_path] = local_url
|
||||||
|
|
|
@ -3,12 +3,13 @@
|
||||||
|
|
||||||
@import "partials/context_button"
|
@import "partials/context_button"
|
||||||
@import "partials/icon"
|
@import "partials/icon"
|
||||||
|
@import "partials/outfit"
|
||||||
@import star
|
@import star
|
||||||
|
|
||||||
$object-padding: 6px
|
$object-padding: 6px
|
||||||
$nc-icon-size: 16px
|
$nc-icon-size: 16px
|
||||||
|
|
||||||
$preview-dimension: 400px
|
$preview-dimension: 380px
|
||||||
$sidebar-margin: 20px
|
$sidebar-margin: 20px
|
||||||
$sidebar-width: 400px
|
$sidebar-width: 400px
|
||||||
$sidebar-unit-horizontal-padding: 24px
|
$sidebar-unit-horizontal-padding: 24px
|
||||||
|
@ -21,88 +22,23 @@ $outfit-header-padding: 24px
|
||||||
$outfit-content-width: $sidebar-unit-inner-width - $outfit-thumbnail-size - $outfit-thumbnail-margin - 32px
|
$outfit-content-width: $sidebar-unit-inner-width - $outfit-thumbnail-size - $outfit-thumbnail-margin - 32px
|
||||||
$outfit-content-inner-width: $outfit-content-width - $outfit-header-padding
|
$outfit-content-inner-width: $outfit-content-width - $outfit-header-padding
|
||||||
|
|
||||||
|
=user-select($select)
|
||||||
|
select: unquote($select)
|
||||||
|
+experimental(user-select, $select, -moz, -webkit, not -o, not -ms, -khtml, official)
|
||||||
|
|
||||||
=active-mode
|
=active-mode
|
||||||
color: $text-color
|
color: $text-color
|
||||||
font-weight: bold
|
font-weight: bold
|
||||||
|
|
||||||
=outfit
|
=sidebar-navbar-unselected
|
||||||
+outfit-star-shifted
|
background: transparent
|
||||||
padding: .25em 0
|
border-bottom: 1px solid $soft-border-color
|
||||||
//.outfit-thumbnail
|
font-weight: normal
|
||||||
float: left
|
|
||||||
height: $outfit-thumbnail-size
|
=sidebar-navbar-selected
|
||||||
margin-right: $outfit-thumbnail-margin
|
background: white
|
||||||
overflow: hidden
|
border-bottom-color: white
|
||||||
position: relative
|
font-weight: bold
|
||||||
width: $outfit-thumbnail-size
|
|
||||||
img
|
|
||||||
height: $outfit-thumbnail-original-size
|
|
||||||
left: -$outfit-thumbnail-original-size / 4
|
|
||||||
position: absolute
|
|
||||||
top: -$outfit-thumbnail-original-size / 4
|
|
||||||
width: $outfit-thumbnail-original-size
|
|
||||||
.outfit-delete
|
|
||||||
+reset-awesome-button
|
|
||||||
+opacity(.5)
|
|
||||||
font-size: 150%
|
|
||||||
float: right
|
|
||||||
line-height: 1
|
|
||||||
margin-top: -.125em
|
|
||||||
padding: .125em .25em
|
|
||||||
&:hover
|
|
||||||
+opacity(1)
|
|
||||||
background: $module-bg-color
|
|
||||||
header
|
|
||||||
display: block
|
|
||||||
padding-left: $outfit-header-padding
|
|
||||||
h4
|
|
||||||
cursor: pointer
|
|
||||||
display: inline
|
|
||||||
&:hover
|
|
||||||
text-decoration: underline
|
|
||||||
h4, .outfit-rename-field
|
|
||||||
font-size: 115%
|
|
||||||
.outfit-rename-button, .outfit-rename-form
|
|
||||||
display: none
|
|
||||||
.outfit-rename-button
|
|
||||||
+opacity(.75)
|
|
||||||
font-size: 75%
|
|
||||||
margin-left: 1em
|
|
||||||
.outfit-url
|
|
||||||
+opacity(.5)
|
|
||||||
background: transparent
|
|
||||||
border-width: 0
|
|
||||||
width: $outfit-content-inner-width
|
|
||||||
&:hover
|
|
||||||
+opacity(1)
|
|
||||||
border-width: 1px
|
|
||||||
.outfit-delete-confirmation
|
|
||||||
display: none
|
|
||||||
font-size: 75%
|
|
||||||
span
|
|
||||||
color: red
|
|
||||||
a
|
|
||||||
margin: 0 .25em
|
|
||||||
&.active
|
|
||||||
background: $module-bg-color
|
|
||||||
&.confirming-deletion
|
|
||||||
.outfit-delete
|
|
||||||
visibility: hidden
|
|
||||||
.outfit-url
|
|
||||||
display: none
|
|
||||||
.outfit-delete-confirmation
|
|
||||||
display: block
|
|
||||||
&.renaming
|
|
||||||
h4
|
|
||||||
display: none
|
|
||||||
.outfit-rename-form
|
|
||||||
display: inline
|
|
||||||
&:hover
|
|
||||||
.outfit-rename-button
|
|
||||||
display: none
|
|
||||||
&:hover
|
|
||||||
.outfit-rename-button
|
|
||||||
display: inline
|
|
||||||
|
|
||||||
=sidebar-view-child
|
=sidebar-view-child
|
||||||
margin:
|
margin:
|
||||||
|
@ -144,7 +80,7 @@ body.outfits-edit
|
||||||
position: left center
|
position: left center
|
||||||
repeat: no-repeat
|
repeat: no-repeat
|
||||||
padding-left: 20px
|
padding-left: 20px
|
||||||
#save-outfit, #save-outfit-not-signed-in, #save-current-outfit, #save-outfit-copy, #save-outfit-finish
|
#save-outfit, #save-outfit-not-signed-in, #save-current-outfit, #save-outfit-finish
|
||||||
+loud-awesome-button-color
|
+loud-awesome-button-color
|
||||||
#current-outfit-permalink, #shared-outfit-permalink
|
#current-outfit-permalink, #shared-outfit-permalink
|
||||||
display: none
|
display: none
|
||||||
|
@ -207,11 +143,14 @@ body.outfits-edit
|
||||||
&.image-active
|
&.image-active
|
||||||
#preview-mode-image
|
#preview-mode-image
|
||||||
+active-mode
|
+active-mode
|
||||||
#report-broken-image
|
#preview-mode-note, #report-broken-image
|
||||||
display: block
|
display: block
|
||||||
&.can-download
|
// Phasing out the image download section. Not confident enough yet to
|
||||||
#preview-download-image
|
// *remove* it, depending on user feedback, but that's a TODO for down
|
||||||
display: inline-block
|
// the road if hiding goes well.
|
||||||
|
// &.can-download
|
||||||
|
// #preview-download-image
|
||||||
|
// display: inline-block
|
||||||
#preview-mode-toggle
|
#preview-mode-toggle
|
||||||
+border-radius(.5em)
|
+border-radius(.5em)
|
||||||
border: 1px solid $module-border-color
|
border: 1px solid $module-border-color
|
||||||
|
@ -249,34 +188,27 @@ body.outfits-edit
|
||||||
em
|
em
|
||||||
font-style: normal
|
font-style: normal
|
||||||
text-decoration: underline
|
text-decoration: underline
|
||||||
#report-broken-image
|
#preview-mode-note, #report-broken-image
|
||||||
display: none
|
display: none
|
||||||
|
|
||||||
#preview-sidebar
|
#preview-sidebar
|
||||||
+border-radius(10px)
|
|
||||||
border: 1px solid $soft-border-color
|
|
||||||
float: left
|
float: left
|
||||||
height: $preview-dimension
|
height: $preview-dimension
|
||||||
margin-left: $sidebar-margin
|
margin-left: $sidebar-margin
|
||||||
margin-bottom: 1em
|
margin-bottom: 1em
|
||||||
overflow: auto
|
width: $container_width - $preview-dimension - $sidebar-margin
|
||||||
width: $container_width - $preview-dimension - $sidebar-margin - 2px
|
|
||||||
&.viewing-outfits
|
&.viewing-outfits
|
||||||
#preview-closet
|
#preview-closet
|
||||||
display: none
|
display: none
|
||||||
#preview-outfits
|
#preview-outfits
|
||||||
display: block
|
display: block
|
||||||
&.viewing-saving-outfit
|
&.sharing
|
||||||
height: auto
|
|
||||||
max-height: 100%
|
|
||||||
#preview-closet
|
#preview-closet
|
||||||
display: none
|
display: none
|
||||||
#preview-saving-outfit
|
#preview-sharing
|
||||||
display: block
|
display: block
|
||||||
.sidebar-view
|
.sidebar-view
|
||||||
h2
|
margin: 1.5em 0
|
||||||
margin:
|
|
||||||
bottom: .25em
|
|
||||||
left: $sidebar-unit-horizontal-padding
|
|
||||||
#preview-closet
|
#preview-closet
|
||||||
h2
|
h2
|
||||||
margin-bottom: 0
|
margin-bottom: 0
|
||||||
|
@ -378,7 +310,6 @@ body.outfits-edit
|
||||||
width: 100%
|
width: 100%
|
||||||
#preview-sidebar
|
#preview-sidebar
|
||||||
float: right
|
float: right
|
||||||
height: 100%
|
|
||||||
margin: 0
|
margin: 0
|
||||||
position: relative
|
position: relative
|
||||||
width: $sidebar-width
|
width: $sidebar-width
|
||||||
|
@ -461,20 +392,284 @@ body.outfits-edit
|
||||||
#preview-outfits
|
#preview-outfits
|
||||||
display: none
|
display: none
|
||||||
text-align: left
|
text-align: left
|
||||||
|
|
||||||
|
$outfit-inner-size: 110px
|
||||||
|
$outfit-margin: 1px
|
||||||
|
$outfit-outer-size: $outfit-inner-size + ($outfit-margin * 2)
|
||||||
> ul
|
> ul
|
||||||
|
+outfits-list
|
||||||
+sidebar-view-child
|
+sidebar-view-child
|
||||||
background: image-url("loading.gif") no-repeat center top
|
background: image-url("loading.gif") no-repeat center top
|
||||||
display: block
|
display: none
|
||||||
font-family: $main-font
|
font-family: $main-font
|
||||||
list-style: none
|
margin: 0 auto 1em
|
||||||
margin:
|
|
||||||
bottom: 1em
|
|
||||||
min-height: 16px
|
min-height: 16px
|
||||||
> li
|
width: $outfit-outer-size * 3
|
||||||
+outfit
|
|
||||||
&.loaded
|
&.loaded
|
||||||
background: transparent
|
background: transparent
|
||||||
|
|
||||||
|
> li
|
||||||
|
height: $outfit-inner-size
|
||||||
|
margin: $outfit-margin
|
||||||
|
width: $outfit-inner-size
|
||||||
|
|
||||||
|
$outfit-header-h-padding: 4px
|
||||||
|
$outfit-header-v-padding: 2px
|
||||||
|
$outfit-header-inner-width: $outfit-inner-size - (2 * $outfit-header-h-padding)
|
||||||
|
$outfit-header-inner-height: 12px
|
||||||
|
$outfit-header-outer-height: $outfit-header-inner-height + (2 * $outfit-header-v-padding)
|
||||||
|
header, footer, .outfit-delete-confirmation
|
||||||
|
font-size: $outfit-header-inner-height
|
||||||
|
padding: $outfit-header-v-padding $outfit-header-h-padding
|
||||||
|
width: $outfit-header-inner-width
|
||||||
|
|
||||||
|
header
|
||||||
|
+opacity(0.75)
|
||||||
|
bottom: 0
|
||||||
|
cursor: pointer
|
||||||
|
|
||||||
|
footer, .outfit-delete-confirmation
|
||||||
|
display: none
|
||||||
|
|
||||||
|
.outfit-delete-confirmation
|
||||||
|
+outfit-banner
|
||||||
|
+outfit-banner-background(rgb(255, 50, 50))
|
||||||
|
text-align: center
|
||||||
|
top: 0
|
||||||
|
|
||||||
|
span
|
||||||
|
font-weight: bold
|
||||||
|
|
||||||
|
$outfit-thumbnail-size: 150px
|
||||||
|
$outfit-thumbnail-h-offset: ($outfit-inner-size - $outfit-thumbnail-size) / 2
|
||||||
|
$outfit-thumbnail-v-offset: $outfit-thumbnail-h-offset - ($outfit-header-outer-height / 4)
|
||||||
|
.outfit-thumbnail-wrapper
|
||||||
|
+opacity(.5)
|
||||||
|
background:
|
||||||
|
image: url(/images/outfits/small_default.png)
|
||||||
|
position: center center
|
||||||
|
size: $outfit-inner-size $outfit-inner-size
|
||||||
|
cursor: pointer
|
||||||
|
height: $outfit-thumbnail-size
|
||||||
|
left: $outfit-thumbnail-h-offset
|
||||||
|
position: absolute
|
||||||
|
top: $outfit-thumbnail-v-offset
|
||||||
|
width: $outfit-thumbnail-size
|
||||||
|
z-index: 1
|
||||||
|
|
||||||
|
.outfit-thumbnail
|
||||||
|
display: none
|
||||||
|
|
||||||
|
.outfit-star
|
||||||
|
bottom: 0
|
||||||
|
margin-right: 4px
|
||||||
|
|
||||||
|
.outfit-delete
|
||||||
|
float: right
|
||||||
|
|
||||||
|
.outfit-rename-button
|
||||||
|
float: left
|
||||||
|
|
||||||
|
.outfit-rename-button, .outfit-delete
|
||||||
|
font-size: 85%
|
||||||
|
text-decoration: none
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
text-decoration: underline
|
||||||
|
|
||||||
|
.outfit-rename-form
|
||||||
|
display: none
|
||||||
|
|
||||||
|
input
|
||||||
|
background: transparent
|
||||||
|
border: 1px solid white
|
||||||
|
width: 6em
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
header
|
||||||
|
+opacity(1)
|
||||||
|
|
||||||
|
.outfit-thumbnail
|
||||||
|
+opacity(0.75)
|
||||||
|
|
||||||
|
footer
|
||||||
|
display: block
|
||||||
|
|
||||||
|
&.active
|
||||||
|
header
|
||||||
|
+opacity(1)
|
||||||
|
font-weight: bold
|
||||||
|
|
||||||
|
.outfit-thumbnail
|
||||||
|
+opacity(1)
|
||||||
|
|
||||||
|
&.confirming-deletion
|
||||||
|
footer
|
||||||
|
display: none
|
||||||
|
|
||||||
|
.outfit-delete-confirmation
|
||||||
|
display: block
|
||||||
|
|
||||||
|
&.renaming
|
||||||
|
.outfit-name
|
||||||
|
display: none
|
||||||
|
|
||||||
|
.outfit-rename-form
|
||||||
|
display: inline
|
||||||
|
|
||||||
|
&.thumbnail-available
|
||||||
|
background: transparent
|
||||||
|
|
||||||
|
.outfit-thumbnail-wrapper
|
||||||
|
background-image: none
|
||||||
|
|
||||||
|
.outfit-thumbnail
|
||||||
|
display: block
|
||||||
|
|
||||||
|
&.loading
|
||||||
|
.outfit-star
|
||||||
|
background-image: image-url("loading_outfit_pane.gif")
|
||||||
|
|
||||||
|
#preview-outfits-not-logged-in
|
||||||
|
text-align: center
|
||||||
|
overflow-x: hidden
|
||||||
|
|
||||||
|
img
|
||||||
|
border:
|
||||||
|
color: $module-border-color
|
||||||
|
style: solid
|
||||||
|
width: 1px 0
|
||||||
|
|
||||||
|
figure
|
||||||
|
display: block
|
||||||
|
margin: 0 0 1em 0
|
||||||
|
padding: 0
|
||||||
|
|
||||||
|
figcaption
|
||||||
|
display: block
|
||||||
|
font-weight: bold
|
||||||
|
|
||||||
|
p
|
||||||
|
+sidebar-view-child
|
||||||
|
font-size: 85%
|
||||||
|
|
||||||
|
#preview-outfits-log-in
|
||||||
|
+awesome-button
|
||||||
|
+loud-awesome-button-color
|
||||||
|
|
||||||
|
#preview-sharing
|
||||||
|
display: none
|
||||||
|
|
||||||
|
#preview-sharing-urls
|
||||||
|
+sidebar-view-child
|
||||||
|
display: none
|
||||||
|
margin:
|
||||||
|
bottom: 1em
|
||||||
|
top: 1em
|
||||||
|
|
||||||
|
li
|
||||||
|
display: block
|
||||||
|
padding: .25em 0
|
||||||
|
width: 100%
|
||||||
|
|
||||||
|
label
|
||||||
|
display: block
|
||||||
|
font-weight: bold
|
||||||
|
|
||||||
|
input
|
||||||
|
display: block
|
||||||
|
width: 100%
|
||||||
|
|
||||||
|
#preview-sharing-url-formats
|
||||||
|
+sidebar-view-child
|
||||||
|
+user-select(none)
|
||||||
|
// remove whitespace between inline-block elements
|
||||||
|
display: none
|
||||||
|
font-size: 0
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
li
|
||||||
|
+inline-block
|
||||||
|
|
||||||
|
border: 1px solid $module-border-color
|
||||||
|
border-left-width: 0
|
||||||
|
border-right-color: $soft-border-color
|
||||||
|
color: $soft-text-color
|
||||||
|
cursor: pointer
|
||||||
|
font-size: 12px
|
||||||
|
padding: 0 2em
|
||||||
|
|
||||||
|
&.active
|
||||||
|
background: $module-bg-color
|
||||||
|
color: inherit
|
||||||
|
font-weight: bold
|
||||||
|
|
||||||
|
&:first-child
|
||||||
|
+border-top-left-radius(5px)
|
||||||
|
+border-bottom-left-radius(5px)
|
||||||
|
border-left-width: 1px
|
||||||
|
|
||||||
|
&:last-child
|
||||||
|
+border-top-right-radius(5px)
|
||||||
|
+border-bottom-right-radius(5px)
|
||||||
|
border-right-color: $module-border-color
|
||||||
|
|
||||||
|
#preview-sharing-thumbnail-wrapper
|
||||||
|
border: 1px solid $soft-border-color
|
||||||
|
display: block
|
||||||
|
height: 150px
|
||||||
|
margin: 1em auto 0
|
||||||
|
position: relative
|
||||||
|
width: 150px
|
||||||
|
|
||||||
|
#preview-sharing-thumbnail-loading
|
||||||
|
height: 100%
|
||||||
|
left: 0
|
||||||
|
position: absolute
|
||||||
|
top: 0
|
||||||
|
width: 100%
|
||||||
|
|
||||||
|
span
|
||||||
|
color: $soft-text-color
|
||||||
|
font-size: 85%
|
||||||
|
margin-top: -0.75em
|
||||||
|
position: absolute
|
||||||
|
text-align: center
|
||||||
|
top: 50%
|
||||||
|
width: 100%
|
||||||
|
|
||||||
|
#preview-sharing-thumbnail, #preview-sharing-thumbnail-generating
|
||||||
|
display: none
|
||||||
|
|
||||||
|
#preview-sharing-beta-note
|
||||||
|
+sidebar-view-child
|
||||||
|
+warning
|
||||||
|
font-size: 85%
|
||||||
|
margin-top: 1em
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
&.urls-loaded
|
||||||
|
#preview-sharing-thumbnail-saving
|
||||||
|
display: none
|
||||||
|
|
||||||
|
#preview-sharing-urls, #preview-sharing-url-formats, #preview-sharing-thumbnail-generating
|
||||||
|
display: block
|
||||||
|
|
||||||
|
&.urls-loaded.thumbnail-loaded
|
||||||
|
#preview-sharing-thumbnail-loading
|
||||||
|
display: none
|
||||||
|
|
||||||
|
#preview-sharing-thumbnail
|
||||||
|
display: block
|
||||||
|
|
||||||
|
&.urls-loaded.thumbnail-available
|
||||||
|
#preview-sharing-thumbnail-loading
|
||||||
|
+opacity(0.85)
|
||||||
|
|
||||||
|
#preview-sharing-thumbnail
|
||||||
|
display: block
|
||||||
|
|
||||||
.preview-sidebar-nav
|
.preview-sidebar-nav
|
||||||
float: right
|
float: right
|
||||||
font-size: 85%
|
font-size: 85%
|
||||||
|
@ -482,6 +677,49 @@ body.outfits-edit
|
||||||
right: $sidebar-unit-horizontal-padding
|
right: $sidebar-unit-horizontal-padding
|
||||||
top: 1em
|
top: 1em
|
||||||
|
|
||||||
|
$sidebar-border-radius: 10px
|
||||||
|
$sidebar-navbar-inner-width: $sidebar-width - 2px
|
||||||
|
$sidebar-navbar-child-outer-width: floor($sidebar-navbar-inner-width / 3)
|
||||||
|
|
||||||
|
#preview-sidebar
|
||||||
|
#preview-sidebar-navbar-closet
|
||||||
|
+sidebar-navbar-selected
|
||||||
|
|
||||||
|
&.viewing-outfits, &.sharing
|
||||||
|
#preview-sidebar-navbar-closet
|
||||||
|
+sidebar-navbar-unselected
|
||||||
|
|
||||||
|
&.viewing-outfits #preview-sidebar-navbar-outfits, &.sharing #preview-sidebar-navbar-sharing
|
||||||
|
+sidebar-navbar-selected
|
||||||
|
|
||||||
|
#preview-sidebar-navbar
|
||||||
|
+border-radius($sidebar-border-radius $sidebar-border-radius 0 0)
|
||||||
|
+clearfix
|
||||||
|
+header-text
|
||||||
|
background: $module-bg-color
|
||||||
|
border: 1px solid $soft-border-color
|
||||||
|
border-bottom: 0
|
||||||
|
font-size: 150%
|
||||||
|
|
||||||
|
> div
|
||||||
|
+sidebar-navbar-unselected
|
||||||
|
cursor: pointer
|
||||||
|
float: left
|
||||||
|
border-left: 1px solid $soft-border-color
|
||||||
|
padding: .5em 0
|
||||||
|
text-align: center
|
||||||
|
width: $sidebar-navbar-child-outer-width
|
||||||
|
|
||||||
|
&:first-child
|
||||||
|
border-left: 0
|
||||||
|
|
||||||
|
#preview-sidebar-content
|
||||||
|
+border-radius(0 0 $sidebar-border-radius $sidebar-border-radius)
|
||||||
|
border: 1px solid $soft-border-color
|
||||||
|
border-top: 0
|
||||||
|
height: 300px
|
||||||
|
overflow: auto
|
||||||
|
|
||||||
#save-success, #save-error, #outfit-not-found, #preview-sidebar-donation-request
|
#save-success, #save-error, #outfit-not-found, #preview-sidebar-donation-request
|
||||||
+sidebar-view-child
|
+sidebar-view-child
|
||||||
display: none
|
display: none
|
||||||
|
@ -507,25 +745,10 @@ body.outfits-edit
|
||||||
+opacity(.5)
|
+opacity(.5)
|
||||||
display: none
|
display: none
|
||||||
|
|
||||||
#new-outfit
|
|
||||||
+outfit
|
|
||||||
+sidebar-view-child
|
|
||||||
display: none
|
|
||||||
h4
|
|
||||||
display: inline
|
|
||||||
&:hover
|
|
||||||
text-decoration: none
|
|
||||||
.outfit-star
|
|
||||||
margin-top: .5em
|
|
||||||
|
|
||||||
#new-outfit-name
|
#new-outfit-name
|
||||||
font: inherit
|
font: inherit
|
||||||
line-height: 1
|
line-height: 1
|
||||||
|
|
||||||
#preview-saving-outfit
|
|
||||||
display: none
|
|
||||||
padding-bottom: 1em
|
|
||||||
|
|
||||||
#pet-type-form, #pet-state-form, #preview-swf, #preview-search-form
|
#pet-type-form, #pet-state-form, #preview-swf, #preview-search-form
|
||||||
position: relative
|
position: relative
|
||||||
|
|
||||||
|
@ -541,7 +764,7 @@ body.outfits-edit
|
||||||
display: none
|
display: none
|
||||||
|
|
||||||
form#save-outfit-form
|
form#save-outfit-form
|
||||||
+outfit
|
+outfit-star-shifted
|
||||||
display: none
|
display: none
|
||||||
margin-right: 0
|
margin-right: 0
|
||||||
padding: 0
|
padding: 0
|
||||||
|
@ -572,8 +795,11 @@ body.outfits-edit
|
||||||
display: none
|
display: none
|
||||||
#save-current-outfit, #save-outfit-copy
|
#save-current-outfit, #save-outfit-copy
|
||||||
display: inline-block
|
display: inline-block
|
||||||
#current-outfit-permalink
|
// Phasing out permalink. Shared outfit links have been straight-up
|
||||||
display: inline-block
|
// removed, but this may stay depending on user feedback. Otherwise,
|
||||||
|
// removing it is TODO down the road.
|
||||||
|
// #current-outfit-permalink
|
||||||
|
// display: inline-block
|
||||||
&.saving-outfit
|
&.saving-outfit
|
||||||
#save-outfit-form
|
#save-outfit-form
|
||||||
display: block
|
display: block
|
||||||
|
@ -581,6 +807,10 @@ body.outfits-edit
|
||||||
display: none
|
display: none
|
||||||
.preview-search-form-your-items
|
.preview-search-form-your-items
|
||||||
+inline-block
|
+inline-block
|
||||||
|
#preview-outfits-not-logged-in
|
||||||
|
display: none
|
||||||
|
#preview-outfits-list
|
||||||
|
display: block
|
||||||
|
|
||||||
&.user-not-signed-in
|
&.user-not-signed-in
|
||||||
#save-outfit-not-signed-in
|
#save-outfit-not-signed-in
|
||||||
|
|
|
@ -1,27 +1,55 @@
|
||||||
|
@import "partials/outfit"
|
||||||
@import star
|
@import star
|
||||||
|
|
||||||
|
$outfit-inner-height: 150px
|
||||||
|
$outfit-inner-width: 150px
|
||||||
|
$outfit-banner-h-padding: 4px
|
||||||
|
$outfit-banner-v-padding: 2px
|
||||||
|
$outfit-banner-inner-width: $outfit-inner-width - (2 * $outfit-banner-h-padding)
|
||||||
|
|
||||||
body.outfits-index
|
body.outfits-index
|
||||||
#outfits
|
#outfits
|
||||||
list-style: none
|
+outfits-list
|
||||||
|
|
||||||
li
|
> li
|
||||||
+outfit-star
|
height: $outfit-inner-height
|
||||||
clear: left
|
margin: 2px
|
||||||
float: left
|
width: $outfit-inner-width
|
||||||
margin-bottom: .5em
|
|
||||||
|
|
||||||
h4
|
header, footer
|
||||||
float: left
|
padding: $outfit-banner-v-padding $outfit-banner-h-padding
|
||||||
width: 12em
|
width: $outfit-banner-inner-width
|
||||||
|
|
||||||
.outfit-edit-link, form
|
footer
|
||||||
float: left
|
display: none
|
||||||
font-size: 85%
|
|
||||||
margin-left: 1em
|
|
||||||
|
|
||||||
.outfit-edit-link
|
.outfit-edit-link
|
||||||
+awesome-button
|
float: left
|
||||||
|
text-decoration: none
|
||||||
|
|
||||||
|
form
|
||||||
|
float: right
|
||||||
|
|
||||||
|
.outfit-delete-button
|
||||||
|
margin: 0
|
||||||
|
padding: 0
|
||||||
|
|
||||||
|
.outfit-edit-link, .outfit-delete-button
|
||||||
|
&:hover
|
||||||
|
text-decoration: underline
|
||||||
|
|
||||||
|
.outfit-star
|
||||||
|
cursor: auto
|
||||||
|
|
||||||
|
.outfit-name
|
||||||
|
text-decoration: none
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
text-decoration: underline
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
footer
|
||||||
|
display: block
|
||||||
|
|
||||||
.outfit-delete-button
|
.outfit-delete-button
|
||||||
margin: 0
|
+reset-awesome-button
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
background-image: image-url("star.png")
|
background-image: image-url("star.png")
|
||||||
&.loading .outfit-star
|
&.loading .outfit-star
|
||||||
background-image: image-url("loading.gif")
|
background-image: image-url("loading.gif")
|
||||||
&.loading.active .outfit-star
|
|
||||||
background-image: image-url("loading_current_outfit.gif")
|
|
||||||
|
|
||||||
=outfit-star-shifted
|
=outfit-star-shifted
|
||||||
+outfit-star
|
+outfit-star
|
||||||
|
|
37
app/stylesheets/partials/_outfit.sass
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
=outfit
|
||||||
|
+inline-block
|
||||||
|
+outfit-star
|
||||||
|
overflow: hidden
|
||||||
|
position: relative
|
||||||
|
|
||||||
|
header, footer
|
||||||
|
+outfit-banner
|
||||||
|
+outfit-banner-background(black)
|
||||||
|
|
||||||
|
header
|
||||||
|
bottom: 0
|
||||||
|
|
||||||
|
footer
|
||||||
|
top: 0
|
||||||
|
|
||||||
|
a
|
||||||
|
color: white
|
||||||
|
|
||||||
|
=outfits-list
|
||||||
|
// remove whitespace between inline-block elements
|
||||||
|
font-size: 0
|
||||||
|
list-style: none
|
||||||
|
|
||||||
|
> li
|
||||||
|
+outfit
|
||||||
|
font-size: 14px
|
||||||
|
|
||||||
|
=outfit-banner
|
||||||
|
color: white
|
||||||
|
left: 0
|
||||||
|
position: absolute
|
||||||
|
z-index: 2
|
||||||
|
|
||||||
|
=outfit-banner-background($color)
|
||||||
|
background: $color
|
||||||
|
background: rgba($color, 0.75)
|
|
@ -12,7 +12,7 @@
|
||||||
%ul#report-assets
|
%ul#report-assets
|
||||||
- @swf_assets.each do |swf_asset|
|
- @swf_assets.each do |swf_asset|
|
||||||
%li
|
%li
|
||||||
= link_to image_tag(swf_asset.s3_url([150, 150])), swf_asset.url
|
= link_to image_tag(swf_asset.image_url([150, 150])), swf_asset.url
|
||||||
- unless swf_asset.image_pending_repair?
|
- unless swf_asset.image_pending_repair?
|
||||||
= form_tag(:action => :create) do
|
= form_tag(:action => :create) do
|
||||||
= hidden_field_tag 'swf_asset_remote_id', swf_asset.remote_id
|
= hidden_field_tag 'swf_asset_remote_id', swf_asset.remote_id
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
= yield :stylesheets
|
= yield :stylesheets
|
||||||
= stylesheet_link_tag "compiled/screen"
|
= stylesheet_link_tag "compiled/screen"
|
||||||
= yield :meta
|
= yield :meta
|
||||||
|
= open_graph_tags
|
||||||
= csrf_meta_tag
|
= csrf_meta_tag
|
||||||
= signed_in_meta_tag
|
= signed_in_meta_tag
|
||||||
%body{:class => body_class}
|
%body{:class => body_class}
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
= outfit_li_for(outfit) do
|
= outfit_li_for(outfit) do
|
||||||
.outfit-star
|
- if outfit.image?
|
||||||
%h4= link_to outfit.name, outfit
|
= link_to image_tag(outfit.image.small.url), outfit
|
||||||
= link_to_edit_outfit 'Edit', outfit, :class => 'outfit-edit-link'
|
|
||||||
= button_to('Delete', outfit, :method => 'delete', :class => 'outfit-delete-button', :confirm => "Are you sure you want to delete the outfit #{outfit.name}?")
|
%header
|
||||||
|
.outfit-star
|
||||||
|
= link_to outfit.name, outfit, :class => 'outfit-name'
|
||||||
|
|
||||||
|
%footer
|
||||||
|
= link_to_edit_outfit 'edit', outfit, :class => 'outfit-edit-link'
|
||||||
|
= button_to 'delete', outfit, :method => 'delete', :class => 'outfit-delete-button', :confirm => "Are you sure you want to delete the outfit #{outfit.name}?"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,14 +17,10 @@
|
||||||
#save-outfit-wrapper
|
#save-outfit-wrapper
|
||||||
%a#current-outfit-permalink{:target => '_blank'}
|
%a#current-outfit-permalink{:target => '_blank'}
|
||||||
= image_tag 'link_go.png', :alt => 'Permalink', :title => 'Permalink to current outfit'
|
= image_tag 'link_go.png', :alt => 'Permalink', :title => 'Permalink to current outfit'
|
||||||
%a#shared-outfit-permalink{:target => '_blank'}
|
|
||||||
= image_tag 'link_go.png', :alt => 'Permalink', :title => 'Permalink to shared outfit'
|
|
||||||
%input#shared-outfit-url.outfit-url{:type => 'text'}
|
|
||||||
%button#share-outfit Share outfit
|
|
||||||
%button#save-outfit Save outfit
|
%button#save-outfit Save outfit
|
||||||
%button#save-outfit-not-signed-in Log in to save
|
%button#save-outfit-not-signed-in Log in to save
|
||||||
|
%button#save-outfit-copy Save as…
|
||||||
%button#save-current-outfit Save "<span>current outfit</span>"
|
%button#save-current-outfit Save "<span>current outfit</span>"
|
||||||
%button#save-outfit-copy Save a copy
|
|
||||||
%form#save-outfit-form
|
%form#save-outfit-form
|
||||||
.outfit-star
|
.outfit-star
|
||||||
%input#save-outfit-name{:type => 'text', :placeholder => 'Outfit name'}
|
%input#save-outfit-name{:type => 'text', :placeholder => 'Outfit name'}
|
||||||
|
@ -62,30 +58,67 @@
|
||||||
%em donate
|
%em donate
|
||||||
at least $5 to help upgrade the server. Thanks!
|
at least $5 to help upgrade the server. Thanks!
|
||||||
#preview-sidebar
|
#preview-sidebar
|
||||||
#outfit-not-found Outfit not found
|
%nav#preview-sidebar-navbar
|
||||||
#save-success Outfit successfully saved
|
#preview-sidebar-navbar-closet Closet
|
||||||
#save-error
|
#preview-sidebar-navbar-sharing Sharing
|
||||||
#preview-closet.sidebar-view
|
#preview-sidebar-navbar-outfits Outfits
|
||||||
%a#preview-sidebar-nav-outfits.preview-sidebar-nav{:href => '#'} Your outfits
|
#preview-sidebar-content
|
||||||
%h2 Closet
|
#outfit-not-found Outfit not found
|
||||||
%ul
|
#save-success Outfit successfully saved
|
||||||
%p#fullscreen-copyright
|
#save-error
|
||||||
Images © 2000-2010 Neopets, Inc. All Rights Reserved.
|
#preview-closet.sidebar-view
|
||||||
Used With Permission
|
%ul
|
||||||
#preview-outfits.sidebar-view
|
%p#fullscreen-copyright
|
||||||
%a#preview-sidebar-nav-closet.preview-sidebar-nav{:href => "#"} ← Back to Closet
|
Images © 2000-2010 Neopets, Inc. All Rights Reserved.
|
||||||
%h2 Your outfits
|
Used With Permission
|
||||||
%ul
|
#preview-outfits.sidebar-view
|
||||||
#preview-saving-outfit.sidebar-view
|
%ul#preview-outfits-list
|
||||||
%a#preview-sidebar-nav-cancel-save.preview-sidebar-nav{:href => '#'} ← Cancel
|
#preview-outfits-not-logged-in
|
||||||
%h2 Saving new outfit
|
%figure
|
||||||
#new-outfit
|
= image_tag 'outfits_welcome.png'
|
||||||
%form#new-outfit-form
|
%figcaption Ready to become a pro designer?
|
||||||
%header
|
:markdown
|
||||||
.outfit-star
|
We know how hard it can be to keep track of your ideas,
|
||||||
%h4
|
especially if you end up having a lot of them.
|
||||||
%input#new-outfit-name{:type => 'text', :placeholder => 'Outfit name'}
|
**But Dress to Impress makes it easy.**
|
||||||
%button{:type => 'submit'} Save
|
|
||||||
|
Once you have an idea for an outfit, you can **build it,
|
||||||
|
save it, and view it again later**, either to update your
|
||||||
|
design or finally make your dream a reality.
|
||||||
|
|
||||||
|
**Thousands of users have already saved tens of thousands of
|
||||||
|
outfits — will you be next?**
|
||||||
|
|
||||||
|
= link_to 'Log in to save this outfit', login_path_with_return_to, :id => 'preview-outfits-log-in'
|
||||||
|
#preview-sharing.sidebar-view
|
||||||
|
#preview-sharing-thumbnail-wrapper
|
||||||
|
#preview-sharing-thumbnail-loading
|
||||||
|
= image_tag 'outfits/small_loading.gif'
|
||||||
|
%span#preview-sharing-thumbnail-saving Saving…
|
||||||
|
%span#preview-sharing-thumbnail-generating Generating…
|
||||||
|
%img#preview-sharing-thumbnail
|
||||||
|
%p#preview-sharing-beta-note
|
||||||
|
We're currently beta testing outfit image generation. It might be
|
||||||
|
slow or not work at all, and we might have to take it down.
|
||||||
|
Still, we're really excited about this feature, and we hope you
|
||||||
|
are, too!
|
||||||
|
%ul#preview-sharing-urls
|
||||||
|
%li
|
||||||
|
%label{:for => 'preview-sharing-permalink-url'} Outfit page
|
||||||
|
%input#preview-sharing-permalink-url.outfit-url{:type => 'text'}
|
||||||
|
%li
|
||||||
|
%label{:for => 'preview-sharing-large-image-url'} Large image
|
||||||
|
%input#preview-sharing-large-image-url.outfit-url{:type => 'text'}
|
||||||
|
%li
|
||||||
|
%label{:for => 'preview-sharing-medium-image-url'} Medium image
|
||||||
|
%input#preview-sharing-medium-image-url.outfit-url{:type => 'text'}
|
||||||
|
%li
|
||||||
|
%label{:for => 'preview-sharing-small-image-url'} Small image
|
||||||
|
%input#preview-sharing-small-image-url.outfit-url{:type => 'text'}
|
||||||
|
%ul#preview-sharing-url-formats
|
||||||
|
%li.active{'data-format' => 'plain'} Plain
|
||||||
|
%li{'data-format' => 'html'} HTML
|
||||||
|
%li{'data-format' => 'bbcode'} BBCode
|
||||||
%form#preview-search-form
|
%form#preview-search-form
|
||||||
%header
|
%header
|
||||||
%h2 Add an item
|
%h2 Add an item
|
||||||
|
@ -132,18 +165,20 @@
|
||||||
%script#outfit-template{:type => 'text/x-jquery-tmpl'}
|
%script#outfit-template{:type => 'text/x-jquery-tmpl'}
|
||||||
<li class="outfit-${id}{{if starred}} starred{{/if}}">
|
<li class="outfit-${id}{{if starred}} starred{{/if}}">
|
||||||
%header
|
%header
|
||||||
%button.outfit-delete ×
|
|
||||||
.outfit-star
|
.outfit-star
|
||||||
%h4 ${name}
|
%span.outfit-name ${name}
|
||||||
%a.outfit-rename-button{:href => '#'} rename
|
|
||||||
%form.outfit-rename-form
|
%form.outfit-rename-form
|
||||||
%input.outfit-rename-field{:type => 'text'}
|
%input.outfit-rename-field{:type => 'text'}
|
||||||
%input.outfit-url{:type => 'text', :value => "http://#{request.host}/outfits/${id}"}
|
%footer
|
||||||
|
%a.outfit-rename-button{:href => '#'} rename
|
||||||
|
%a.outfit-delete{:href => '#'} delete
|
||||||
|
.outfit-thumbnail-wrapper
|
||||||
|
%img.outfit-thumbnail
|
||||||
.outfit-delete-confirmation
|
.outfit-delete-confirmation
|
||||||
%span Delete forever?
|
%span Delete?
|
||||||
%a.outfit-delete-confirmation-yes{:href => '#'} yes
|
%a.outfit-delete-confirmation-yes{:href => '#'} yes
|
||||||
\/
|
\/
|
||||||
%a.outfit-delete-confirmation-no{:href => '#'} no, thanks
|
%a.outfit-delete-confirmation-no{:href => '#'} no
|
||||||
</li>
|
</li>
|
||||||
- content_for :javascripts do
|
- content_for :javascripts do
|
||||||
= include_javascript_libraries :jquery, :swfobject, :jquery_tmpl
|
= include_javascript_libraries :jquery, :swfobject, :jquery_tmpl
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
- title(@outfit.name || "Shared outfit")
|
- title(@outfit.name || "Shared outfit")
|
||||||
- content_for :before_title, campaign_progress
|
- content_for :before_title, campaign_progress
|
||||||
|
|
||||||
|
- open_graph :type => 'openneo-impress:outfit', :title => yield(:title),
|
||||||
|
:url => outfit_url(@outfit)
|
||||||
|
- if @outfit.image?
|
||||||
|
- open_graph :image => absolute_url(@outfit.image.url)
|
||||||
|
|
||||||
= link_to_edit_outfit(@outfit, :class => 'button', :id => 'outfit-wardrobe-link') do
|
= link_to_edit_outfit(@outfit, :class => 'button', :id => 'outfit-wardrobe-link') do
|
||||||
Edit
|
Edit
|
||||||
- unless user_signed_in? && @outfit.user == current_user
|
- unless user_signed_in? && @outfit.user == current_user
|
||||||
|
|
3
config/initializers/asset_hosts.rb
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
ASSET_HOSTS = {
|
||||||
|
:swf_asset_images => 'd1i4vx4g4uxw7j.cloudfront.net'
|
||||||
|
}
|
20
config/initializers/carrierwave.rb
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# By default, we'll have CarrierWave use S3 only on production. (Since each
|
||||||
|
# asset image has only One True Image no matter the environment, we'll override
|
||||||
|
# this to use S3 on all environments for those images only.)
|
||||||
|
|
||||||
|
CarrierWave.configure do |config|
|
||||||
|
if Rails.env.production?
|
||||||
|
s3_config = YAML.load_file Rails.root.join('config', 'aws_s3.yml')
|
||||||
|
access_key_id = s3_config['access_key_id']
|
||||||
|
secret_access_key = s3_config['secret_access_key']
|
||||||
|
|
||||||
|
config.storage = :fog
|
||||||
|
config.fog_credentials = {
|
||||||
|
:provider => 'AWS',
|
||||||
|
:aws_access_key_id => access_key_id,
|
||||||
|
:aws_secret_access_key => secret_access_key
|
||||||
|
}
|
||||||
|
else
|
||||||
|
config.storage = :file
|
||||||
|
end
|
||||||
|
end
|
9
db/migrate/20120308205324_add_image_to_outfits.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
class AddImageToOutfits < ActiveRecord::Migration
|
||||||
|
def self.up
|
||||||
|
add_column :outfits, :image, :string
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.down
|
||||||
|
remove_column :outfits, :image
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,9 @@
|
||||||
|
class AddImageLayersHashToOutfit < ActiveRecord::Migration
|
||||||
|
def self.up
|
||||||
|
add_column :outfits, :image_layers_hash, :string, :length => 8
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.down
|
||||||
|
remove_column :outfits, :image_layers_hash
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,9 @@
|
||||||
|
class AddImageEnqueuedToOutfits < ActiveRecord::Migration
|
||||||
|
def self.up
|
||||||
|
add_column :outfits, :image_enqueued, :boolean, :null => false, :default => false
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.down
|
||||||
|
remove_column :outfits, :image_enqueued
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended to check this file into your version control system.
|
# It's strongly recommended to check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(:version => 20120521164652) do
|
ActiveRecord::Schema.define(:version => 20120725232903) do
|
||||||
|
|
||||||
create_table "auth_servers", :force => true do |t|
|
create_table "auth_servers", :force => true do |t|
|
||||||
t.string "short_name", :limit => 10, :null => false
|
t.string "short_name", :limit => 10, :null => false
|
||||||
|
@ -116,8 +116,10 @@ ActiveRecord::Schema.define(:version => 20120521164652) do
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.string "name"
|
t.string "name"
|
||||||
t.boolean "starred", :default => false, :null => false
|
t.boolean "starred", :default => false, :null => false
|
||||||
t.string "image"
|
t.string "image"
|
||||||
|
t.string "image_layers_hash"
|
||||||
|
t.boolean "image_enqueued", :default => false, :null => false
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "outfits", ["pet_state_id"], :name => "index_outfits_on_pet_state_id"
|
add_index "outfits", ["pet_state_id"], :name => "index_outfits_on_pet_state_id"
|
||||||
|
|
11
lib/tasks/outfits.rake
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
namespace :outfits do
|
||||||
|
desc 'Retroactively enqueue image updates for outfits saved to user accounts'
|
||||||
|
task :retroactively_enqueue => :environment do
|
||||||
|
outfits = Outfit.select([:id]).where('image IS NULL AND user_id IS NOT NULL')
|
||||||
|
puts "Enqueuing #{outfits.count} outfits"
|
||||||
|
outfits.find_each do |outfit|
|
||||||
|
Resque.enqueue(OutfitImageUpdate::Retroactive, outfit.id)
|
||||||
|
end
|
||||||
|
puts "Successfully enqueued."
|
||||||
|
end
|
||||||
|
end
|
BIN
public/images/loading_outfit_pane.gif
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
public/images/outfits/default.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
public/images/outfits/medium_default.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
public/images/outfits/small_default.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
public/images/outfits/small_loading.gif
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
public/images/outfits_welcome.png
Normal file
After Width: | Height: | Size: 76 KiB |
|
@ -57,7 +57,7 @@ Partial.ItemSet = function ItemSet(wardrobe, selector) {
|
||||||
var item, no_assets, li, no_assets_message;
|
var item, no_assets, li, no_assets_message;
|
||||||
for(var i = 0, l = specific_items.length; i < l; i++) {
|
for(var i = 0, l = specific_items.length; i < l; i++) {
|
||||||
item = specific_items[i];
|
item = specific_items[i];
|
||||||
no_assets = item.couldNotLoadAssetsFitting(wardrobe.outfit.getPetType());
|
no_assets = item.couldNotLoadAssetsFitting(wardrobe.outfits.getPetType());
|
||||||
li = $('li.object-' + item.id).toggleClass('no-assets', no_assets);
|
li = $('li.object-' + item.id).toggleClass('no-assets', no_assets);
|
||||||
(function (li) {
|
(function (li) {
|
||||||
no_assets_message = li.find('span.no-assets-message');
|
no_assets_message = li.find('span.no-assets-message');
|
||||||
|
@ -103,8 +103,8 @@ Partial.ItemSet = function ItemSet(wardrobe, selector) {
|
||||||
}
|
}
|
||||||
li.append(img).append(controls).append(info_link).append(item.name).appendTo(ul);
|
li.append(img).append(controls).append(info_link).append(item.name).appendTo(ul);
|
||||||
}
|
}
|
||||||
setClosetItems(wardrobe.outfit.getClosetItems());
|
setClosetItems(wardrobe.outfits.getClosetItems());
|
||||||
setOutfitItems(wardrobe.outfit.getWornItems());
|
setOutfitItems(wardrobe.outfits.getWornItems());
|
||||||
}
|
}
|
||||||
|
|
||||||
$('span.no-assets-message').live('mouseover', function () {
|
$('span.no-assets-message').live('mouseover', function () {
|
||||||
|
@ -117,9 +117,9 @@ Partial.ItemSet = function ItemSet(wardrobe, selector) {
|
||||||
no_assets_full_message.removeAttr('style');
|
no_assets_full_message.removeAttr('style');
|
||||||
});
|
});
|
||||||
|
|
||||||
wardrobe.outfit.bind('updateItemAssets', function () { setHasAssets(wardrobe.outfit.getWornItems()) });
|
wardrobe.outfits.bind('updateItemAssets', function () { setHasAssets(wardrobe.outfits.getWornItems()) });
|
||||||
wardrobe.outfit.bind('updateWornItems', setOutfitItems);
|
wardrobe.outfits.bind('updateWornItems', setOutfitItems);
|
||||||
wardrobe.outfit.bind('updateClosetItems', setClosetItems);
|
wardrobe.outfits.bind('updateClosetItems', setClosetItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
Partial.ItemSet.CONTROL_SETS = {};
|
Partial.ItemSet.CONTROL_SETS = {};
|
||||||
|
@ -151,12 +151,12 @@ Partial.ItemSet.setWardrobe = function (wardrobe) {
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle_fn.closeted = {};
|
toggle_fn.closeted = {};
|
||||||
toggle_fn.closeted[true] = $.proxy(wardrobe.outfit, 'closetItem');
|
toggle_fn.closeted[true] = $.proxy(wardrobe.outfits, 'closetItem');
|
||||||
toggle_fn.closeted[false] = $.proxy(wardrobe.outfit, 'unclosetItem');
|
toggle_fn.closeted[false] = $.proxy(wardrobe.outfits, 'unclosetItem');
|
||||||
|
|
||||||
toggle_fn.worn = {};
|
toggle_fn.worn = {};
|
||||||
toggle_fn.worn[true] = $.proxy(wardrobe.outfit, 'wearItem');
|
toggle_fn.worn[true] = $.proxy(wardrobe.outfits, 'wearItem');
|
||||||
toggle_fn.worn[false] = $.proxy(wardrobe.outfit, 'unwearItem');
|
toggle_fn.worn[false] = $.proxy(wardrobe.outfits, 'unwearItem');
|
||||||
|
|
||||||
Partial.ItemSet.setWardrobe = $.noop;
|
Partial.ItemSet.setWardrobe = $.noop;
|
||||||
}
|
}
|
||||||
|
@ -164,14 +164,16 @@ Partial.ItemSet.setWardrobe = function (wardrobe) {
|
||||||
View.Closet = function (wardrobe) {
|
View.Closet = function (wardrobe) {
|
||||||
var item_set = new Partial.ItemSet(wardrobe, '#preview-closet ul');
|
var item_set = new Partial.ItemSet(wardrobe, '#preview-closet ul');
|
||||||
|
|
||||||
wardrobe.outfit.bind('updateClosetItems', $.proxy(item_set, 'setItems'));
|
wardrobe.outfits.bind('updateClosetItems', $.proxy(item_set, 'setItems'));
|
||||||
}
|
}
|
||||||
|
|
||||||
View.Fullscreen = function (wardrobe) {
|
View.Fullscreen = function (wardrobe) {
|
||||||
var full = $(document.body).hasClass('fullscreen'), win = $(window),
|
var full = $(document.body).hasClass('fullscreen'), win = $(window),
|
||||||
preview_el = $('#preview'), search_el = $('#preview-search-form'),
|
preview_el = $('#preview'), search_el = $('#preview-search-form'),
|
||||||
preview_swf = $('#preview-swf'), sidebar_el = $('#preview-sidebar'),
|
preview_swf = $('#preview-swf'), sidebar_el = $('#preview-sidebar'),
|
||||||
footer = $('#footer'), jwindow = $(window), overrideFull = false;
|
sidebar_content_el = $('#preview-sidebar-content'),
|
||||||
|
sidebar_navbar_el = $('#preview-sidebar-navbar'), footer = $('#footer'),
|
||||||
|
jwindow = $(window), overrideFull = false;
|
||||||
|
|
||||||
function fit() {
|
function fit() {
|
||||||
if(!overrideFull) {
|
if(!overrideFull) {
|
||||||
|
@ -182,6 +184,7 @@ View.Fullscreen = function (wardrobe) {
|
||||||
if(!full) {
|
if(!full) {
|
||||||
preview_swf.removeAttr('style').css('visibility', 'visible');
|
preview_swf.removeAttr('style').css('visibility', 'visible');
|
||||||
preview_el.removeAttr('style');
|
preview_el.removeAttr('style');
|
||||||
|
sidebar_content_el.removeAttr('style');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,6 +216,12 @@ View.Fullscreen = function (wardrobe) {
|
||||||
preview_swf.css(size.next);
|
preview_swf.css(size.next);
|
||||||
|
|
||||||
preview_el.height(available.height);
|
preview_el.height(available.height);
|
||||||
|
|
||||||
|
// Now that preview is fit, we fit the sidebar's content element, which
|
||||||
|
// also has to deal with the constraint of its navbar's height.
|
||||||
|
var sidebar_content_height = available.height -
|
||||||
|
sidebar_navbar_el.outerHeight() - 1; // 1px bottom border
|
||||||
|
sidebar_content_el.height(sidebar_content_height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$('#preview').data('fit', fit);
|
$('#preview').data('fit', fit);
|
||||||
|
@ -273,32 +282,32 @@ View.Hash = function (wardrobe) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(new_data.color !== data.color || new_data.species !== data.species) {
|
if(new_data.color !== data.color || new_data.species !== data.species) {
|
||||||
wardrobe.outfit.setPetTypeByColorAndSpecies(new_data.color, new_data.species);
|
wardrobe.outfits.setPetTypeByColorAndSpecies(new_data.color, new_data.species);
|
||||||
}
|
}
|
||||||
if(new_data.closet) {
|
if(new_data.closet) {
|
||||||
if(!arraysMatch(new_data.closet, data.closet)) {
|
if(!arraysMatch(new_data.closet, data.closet)) {
|
||||||
wardrobe.outfit.setClosetItemsByIds(new_data.closet.slice(0));
|
wardrobe.outfits.setClosetItemsByIds(new_data.closet.slice(0));
|
||||||
}
|
}
|
||||||
} else if(new_data.objects && !arraysMatch(new_data.objects, data.closet)) {
|
} else if(new_data.objects && !arraysMatch(new_data.objects, data.closet)) {
|
||||||
wardrobe.outfit.setClosetItemsByIds(new_data.objects.slice(0));
|
wardrobe.outfits.setClosetItemsByIds(new_data.objects.slice(0));
|
||||||
} else {
|
} else {
|
||||||
wardrobe.outfit.setClosetItemsByIds([]);
|
wardrobe.outfits.setClosetItemsByIds([]);
|
||||||
}
|
}
|
||||||
if(new_data.objects) {
|
if(new_data.objects) {
|
||||||
if(!arraysMatch(new_data.objects, data.objects)) {
|
if(!arraysMatch(new_data.objects, data.objects)) {
|
||||||
wardrobe.outfit.setWornItemsByIds(new_data.objects.slice(0));
|
wardrobe.outfits.setWornItemsByIds(new_data.objects.slice(0));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
wardrobe.outfit.setWornItemsByIds([]);
|
wardrobe.outfits.setWornItemsByIds([]);
|
||||||
}
|
}
|
||||||
if(new_data.name != data.name && new_data.name) {
|
if(new_data.name != data.name && new_data.name) {
|
||||||
wardrobe.base_pet.setName(new_data.name);
|
wardrobe.base_pet.setName(new_data.name);
|
||||||
}
|
}
|
||||||
if(new_data.state != data.state) {
|
if(new_data.state != data.state) {
|
||||||
wardrobe.outfit.setPetStateById(new_data.state);
|
wardrobe.outfits.setPetStateById(new_data.state);
|
||||||
}
|
}
|
||||||
if(new_data.outfit != data.outfit) {
|
if(new_data.outfit != data.outfit) {
|
||||||
wardrobe.outfit.setId(new_data.outfit);
|
wardrobe.outfits.setId(new_data.outfit);
|
||||||
}
|
}
|
||||||
if(new_data.search != data.search || new_data.search_offset != data.search_offset) {
|
if(new_data.search != data.search || new_data.search_offset != data.search_offset) {
|
||||||
wardrobe.search.setItemsByQuery(new_data.search, {offset: new_data.search_offset});
|
wardrobe.search.setItemsByQuery(new_data.search, {offset: new_data.search_offset});
|
||||||
|
@ -350,27 +359,27 @@ View.Hash = function (wardrobe) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function singleOutfitResponse(event_name, response) {
|
function singleOutfitResponse(event_name, response) {
|
||||||
wardrobe.outfit.bind(event_name, function () {
|
wardrobe.outfits.bind(event_name, function () {
|
||||||
if(!wardrobe.outfit.in_transaction) response.apply(this, arguments);
|
if(!wardrobe.outfits.in_transaction) response.apply(this, arguments);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
singleOutfitResponse('updateClosetItems', function (items) {
|
singleOutfitResponse('updateClosetItems', function (items) {
|
||||||
var item_ids = items.map('id');
|
var item_ids = items.mapProperty('id');
|
||||||
if(!arraysMatch(item_ids, data.closet)) {
|
if(!arraysMatch(item_ids, data.closet)) {
|
||||||
changeQuery({closet: item_ids});
|
changeQuery({closet: item_ids});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
singleOutfitResponse('updateWornItems', function (items) {
|
singleOutfitResponse('updateWornItems', function (items) {
|
||||||
var item_ids = items.map('id'), changes = {};
|
var item_ids = items.mapProperty('id'), changes = {};
|
||||||
if(!arraysMatch(item_ids, data.objects)) {
|
if(!arraysMatch(item_ids, data.objects)) {
|
||||||
changes.objects = item_ids;
|
changes.objects = item_ids;
|
||||||
}
|
}
|
||||||
if(arraysMatch(item_ids, data.closet) || arraysMatch(item_ids, data.objects)) {
|
if(arraysMatch(item_ids, data.closet) || arraysMatch(item_ids, data.objects)) {
|
||||||
changes.closet = undefined;
|
changes.closet = undefined;
|
||||||
} else {
|
} else {
|
||||||
changes.closet = wardrobe.outfit.getClosetItems().map('id');
|
changes.closet = wardrobe.outfits.getClosetItems().mapProperty('id');
|
||||||
}
|
}
|
||||||
if(changes.objects || changes.closet) changeQuery(changes);
|
if(changes.objects || changes.closet) changeQuery(changes);
|
||||||
});
|
});
|
||||||
|
@ -390,7 +399,7 @@ View.Hash = function (wardrobe) {
|
||||||
});
|
});
|
||||||
|
|
||||||
singleOutfitResponse('updatePetState', function (pet_state) {
|
singleOutfitResponse('updatePetState', function (pet_state) {
|
||||||
var pet_type = wardrobe.outfit.getPetType();
|
var pet_type = wardrobe.outfits.getPetType();
|
||||||
if(pet_state.id != data.state && pet_type && (data.state || pet_state.id != pet_type.pet_state_ids[0])) {
|
if(pet_state.id != data.state && pet_type && (data.state || pet_state.id != pet_type.pet_state_ids[0])) {
|
||||||
changeQuery({state: pet_state.id});
|
changeQuery({state: pet_state.id});
|
||||||
}
|
}
|
||||||
|
@ -402,7 +411,7 @@ View.Hash = function (wardrobe) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
wardrobe.outfit.bind('loadOutfit', function (outfit) {
|
wardrobe.outfits.bind('loadOutfit', function (outfit) {
|
||||||
changeQuery({
|
changeQuery({
|
||||||
closet: outfit.getClosetItemIds(),
|
closet: outfit.getClosetItemIds(),
|
||||||
color: outfit.pet_type.color_id,
|
color: outfit.pet_type.color_id,
|
||||||
|
@ -413,7 +422,7 @@ View.Hash = function (wardrobe) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
wardrobe.outfit.bind('outfitNotFound', function (outfit) {
|
wardrobe.outfits.bind('outfitNotFound', function (outfit) {
|
||||||
var new_id = outfit ? outfit.id : undefined;
|
var new_id = outfit ? outfit.id : undefined;
|
||||||
changeQuery({outfit: new_id});
|
changeQuery({outfit: new_id});
|
||||||
});
|
});
|
||||||
|
@ -430,8 +439,6 @@ View.Hash = function (wardrobe) {
|
||||||
|
|
||||||
View.Outfits = function (wardrobe) {
|
View.Outfits = function (wardrobe) {
|
||||||
var current_outfit_permalink_el = $('#current-outfit-permalink'),
|
var current_outfit_permalink_el = $('#current-outfit-permalink'),
|
||||||
shared_outfit_permalink_el = $('#shared-outfit-permalink'),
|
|
||||||
shared_outfit_url_el = $('#shared-outfit-url'),
|
|
||||||
new_outfit_form_el = $('#save-outfit-form'),
|
new_outfit_form_el = $('#save-outfit-form'),
|
||||||
new_outfit_name_el = $('#save-outfit-name'),
|
new_outfit_name_el = $('#save-outfit-name'),
|
||||||
outfits_el = $('#preview-outfits'),
|
outfits_el = $('#preview-outfits'),
|
||||||
|
@ -451,13 +458,6 @@ View.Outfits = function (wardrobe) {
|
||||||
return $('li.outfit-' + outfit.id);
|
return $('li.outfit-' + outfit.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function navLinkTo(callback) {
|
|
||||||
return function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function navigateTo(will_be_viewing) {
|
function navigateTo(will_be_viewing) {
|
||||||
var currently_viewing = sidebar_el.attr('class');
|
var currently_viewing = sidebar_el.attr('class');
|
||||||
if(currently_viewing != will_be_viewing) previously_viewing = currently_viewing;
|
if(currently_viewing != will_be_viewing) previously_viewing = currently_viewing;
|
||||||
|
@ -476,14 +476,21 @@ View.Outfits = function (wardrobe) {
|
||||||
/* Nav */
|
/* Nav */
|
||||||
|
|
||||||
function showCloset() {
|
function showCloset() {
|
||||||
|
sharing.onHide();
|
||||||
navigateTo('');
|
navigateTo('');
|
||||||
}
|
}
|
||||||
|
|
||||||
function showOutfits() {
|
function showOutfits() {
|
||||||
wardrobe.user.loadOutfits();
|
sharing.onHide();
|
||||||
|
wardrobe.outfits.loadOutfits();
|
||||||
navigateTo('viewing-outfits');
|
navigateTo('viewing-outfits');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showSharing() {
|
||||||
|
sharing.onShow();
|
||||||
|
navigateTo('sharing');
|
||||||
|
}
|
||||||
|
|
||||||
function showNewOutfitForm() {
|
function showNewOutfitForm() {
|
||||||
new_outfit_name_el.val('');
|
new_outfit_name_el.val('');
|
||||||
new_outfit_form_el.removeClass('starred').stopLoading();
|
new_outfit_form_el.removeClass('starred').stopLoading();
|
||||||
|
@ -495,9 +502,13 @@ View.Outfits = function (wardrobe) {
|
||||||
save_outfit_wrapper_el.removeClass('saving-outfit');
|
save_outfit_wrapper_el.removeClass('saving-outfit');
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#preview-sidebar-nav-outfits').click(navLinkTo(showOutfits));
|
$('#preview-sidebar-navbar-closet').click(showCloset);
|
||||||
|
$('#preview-sidebar-navbar-sharing').click(function () {
|
||||||
$('#preview-sidebar-nav-closet').click(navLinkTo(showCloset));
|
sharing.startLoading();
|
||||||
|
wardrobe.outfits.share();
|
||||||
|
showSharing();
|
||||||
|
});
|
||||||
|
$('#preview-sidebar-navbar-outfits').click(showOutfits);
|
||||||
|
|
||||||
$('#save-outfit, #save-outfit-copy').click(showNewOutfitForm);
|
$('#save-outfit, #save-outfit-copy').click(showNewOutfitForm);
|
||||||
|
|
||||||
|
@ -509,39 +520,64 @@ View.Outfits = function (wardrobe) {
|
||||||
|
|
||||||
/* Outfits list */
|
/* Outfits list */
|
||||||
|
|
||||||
|
var list_image_subscriptions = {};
|
||||||
|
|
||||||
|
function listSubscribeToImage(outfit) {
|
||||||
|
list_image_subscriptions[outfit.id] = wardrobe.image_subscriptions.subscribe(outfit);
|
||||||
|
}
|
||||||
|
|
||||||
|
function listUnsubscribeFromImage(outfit) {
|
||||||
|
if(outfit.id in list_image_subscriptions) {
|
||||||
|
if(list_image_subscriptions[outfit.id] !== null) {
|
||||||
|
wardrobe.image_subscriptions.unsubscribe(list_image_subscriptions[outfit.id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete list_image_subscriptions[outfit.id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$('#outfit-template').template('outfitTemplate');
|
$('#outfit-template').template('outfitTemplate');
|
||||||
|
|
||||||
wardrobe.user.bind('outfitsLoaded', function (outfits) {
|
wardrobe.outfits.bind('outfitsLoaded', function (outfits) {
|
||||||
var outfit_els = $.tmpl('outfitTemplate', outfits);
|
var outfit_els = $.tmpl('outfitTemplate', outfits);
|
||||||
outfits_list_el.html('').append(outfit_els).addClass('loaded');
|
outfits_list_el.html('').append(outfit_els).addClass('loaded');
|
||||||
updateActiveOutfit();
|
updateActiveOutfit();
|
||||||
|
|
||||||
|
for(var i = 0; i < outfits.length; i++) {
|
||||||
|
listSubscribeToImage(outfits[i]);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
wardrobe.user.bind('addOutfit', function (outfit, i) {
|
wardrobe.outfits.bind('addOutfit', function (outfit, i) {
|
||||||
var next_child = outfits_list_el.children().not('.hiding').eq(i),
|
var next_child = outfits_list_el.children().not('.hiding').eq(i),
|
||||||
outfit_el = $.tmpl('outfitTemplate', outfit);
|
outfit_el = $.tmpl('outfitTemplate', outfit.clone());
|
||||||
if(next_child.length) {
|
if(next_child.length) {
|
||||||
outfit_el.insertBefore(next_child);
|
outfit_el.insertBefore(next_child);
|
||||||
} else {
|
} else {
|
||||||
outfit_el.appendTo(outfits_list_el);
|
outfit_el.appendTo(outfits_list_el);
|
||||||
}
|
}
|
||||||
updateActiveOutfit();
|
updateActiveOutfit();
|
||||||
outfit_el.hide().show('normal');
|
|
||||||
|
var naturalWidth = outfit_el.css('width');
|
||||||
|
log("Natural width is", naturalWidth, outfit_el.width());
|
||||||
|
outfit_el.width(0).animate({width: naturalWidth}, 'normal');
|
||||||
|
listSubscribeToImage(outfit);
|
||||||
});
|
});
|
||||||
|
|
||||||
wardrobe.user.bind('removeOutfit', function (outfit, i) {
|
wardrobe.outfits.bind('removeOutfit', function (outfit, i) {
|
||||||
var outfit_el = outfits_list_el.children().not('.hiding').eq(i);
|
var outfit_el = outfits_list_el.children().not('.hiding').eq(i);
|
||||||
outfit_el.addClass('hiding').stop(true).hide('normal', function () { outfit_el.remove() });
|
outfit_el.addClass('hiding').stop(true).animate({width: 0}, 'normal', function () { outfit_el.remove() });
|
||||||
|
listUnsubscribeFromImage(outfit);
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#preview-outfits h4').live('click', function () {
|
$('#preview-outfits li header, #preview-outfits li .outfit-thumbnail-wrapper').live('click', function () {
|
||||||
wardrobe.outfit.load($(this).tmplItem().data.id);
|
wardrobe.outfits.load($(this).tmplItem().data.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
$('a.outfit-rename-button').live('click', function (e) {
|
$('a.outfit-rename-button').live('click', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var li = $(this).closest('li').addClass('renaming'),
|
var li = $(this).closest('li').addClass('renaming'),
|
||||||
name = li.find('h4').text();
|
name = li.find('span.outfit-name').text();
|
||||||
li.find('input.outfit-rename-field').val(name).focus();
|
li.find('input.outfit-rename-field').val(name).focus();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -550,7 +586,7 @@ View.Outfits = function (wardrobe) {
|
||||||
li = el.closest('li').removeClass('renaming');
|
li = el.closest('li').removeClass('renaming');
|
||||||
if(new_name != outfit.name) {
|
if(new_name != outfit.name) {
|
||||||
li.startLoading();
|
li.startLoading();
|
||||||
wardrobe.user.renameOutfit(outfit, new_name);
|
wardrobe.outfits.renameOutfit(outfit, new_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -568,7 +604,8 @@ View.Outfits = function (wardrobe) {
|
||||||
this.blur();
|
this.blur();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('button.outfit-delete').live('click', function (e) {
|
$('a.outfit-delete').live('click', function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
$(this).closest('li').addClass('confirming-deletion');
|
$(this).closest('li').addClass('confirming-deletion');
|
||||||
});
|
});
|
||||||
|
@ -576,9 +613,9 @@ View.Outfits = function (wardrobe) {
|
||||||
$('a.outfit-delete-confirmation-yes').live('click', function (e) {
|
$('a.outfit-delete-confirmation-yes').live('click', function (e) {
|
||||||
var outfit = $(this).tmplItem().data;
|
var outfit = $(this).tmplItem().data;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
wardrobe.user.destroyOutfit(outfit);
|
wardrobe.outfits.destroyOutfit(outfit);
|
||||||
if(wardrobe.outfit.getOutfit().id == outfit.id) {
|
if(wardrobe.outfits.getOutfit().id == outfit.id) {
|
||||||
wardrobe.outfit.setId(null);
|
wardrobe.outfits.setId(null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -587,16 +624,25 @@ View.Outfits = function (wardrobe) {
|
||||||
$(this).closest('li').removeClass('confirming-deletion');
|
$(this).closest('li').removeClass('confirming-deletion');
|
||||||
});
|
});
|
||||||
|
|
||||||
stars.live('click', function () {
|
stars.live('click', function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
var el = $(this);
|
var el = $(this);
|
||||||
el.closest('li').startLoading();
|
el.closest('li').startLoading();
|
||||||
wardrobe.user.toggleOutfitStar(el.tmplItem().data);
|
wardrobe.outfits.toggleOutfitStar(el.tmplItem().data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function pathToUrl(path) {
|
||||||
|
var host = document.location.protocol + "//" + document.location.host;
|
||||||
|
if(document.location.port) host += ":" + document.location.port;
|
||||||
|
return host + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateOutfitPermalink(outfit) {
|
||||||
|
return pathToUrl("/outfits/" + outfit.id);
|
||||||
|
}
|
||||||
|
|
||||||
function setOutfitPermalink(outfit, outfit_permalink_el, outfit_url_el) {
|
function setOutfitPermalink(outfit, outfit_permalink_el, outfit_url_el) {
|
||||||
var url = document.location.protocol + "//" + document.location.host;
|
var url = generateOutfitPermalink(outfit);
|
||||||
if(document.location.port) url += ":" + document.location.port;
|
|
||||||
url += "/outfits/" + outfit.id;
|
|
||||||
outfit_permalink_el.attr('href', url);
|
outfit_permalink_el.attr('href', url);
|
||||||
if(outfit_url_el) outfit_url_el.val(url);
|
if(outfit_url_el) outfit_url_el.val(url);
|
||||||
}
|
}
|
||||||
|
@ -605,10 +651,6 @@ View.Outfits = function (wardrobe) {
|
||||||
setOutfitPermalink(outfit, current_outfit_permalink_el);
|
setOutfitPermalink(outfit, current_outfit_permalink_el);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSharedOutfitPermalink(outfit) {
|
|
||||||
setOutfitPermalink(outfit, shared_outfit_permalink_el, shared_outfit_url_el);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setActiveOutfit(outfit) {
|
function setActiveOutfit(outfit) {
|
||||||
outfits_list_el.find('li.active').removeClass('active');
|
outfits_list_el.find('li.active').removeClass('active');
|
||||||
if(outfit.id) {
|
if(outfit.id) {
|
||||||
|
@ -620,33 +662,210 @@ View.Outfits = function (wardrobe) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateActiveOutfit() {
|
function updateActiveOutfit() {
|
||||||
setActiveOutfit(wardrobe.outfit.getOutfit());
|
setActiveOutfit(wardrobe.outfits.getOutfit());
|
||||||
}
|
}
|
||||||
|
|
||||||
wardrobe.outfit.bind('setOutfit', setActiveOutfit);
|
wardrobe.outfits.bind('setOutfit', setActiveOutfit);
|
||||||
wardrobe.outfit.bind('outfitNotFound', setActiveOutfit);
|
wardrobe.outfits.bind('outfitNotFound', setActiveOutfit);
|
||||||
|
|
||||||
wardrobe.user.bind('outfitRenamed', function (outfit) {
|
wardrobe.outfits.bind('outfitRenamed', function (outfit) {
|
||||||
if(outfit.id == wardrobe.outfit.getId()) {
|
if(outfit.id == wardrobe.outfits.getId()) {
|
||||||
save_current_outfit_name_el.text(outfit.name);
|
save_current_outfit_name_el.text(outfit.name);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function outfitElement(outfit) {
|
||||||
|
return outfits_el.find('li.outfit-' + outfit.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
wardrobe.outfits.bind('saveSuccess', function (outfit) {
|
||||||
|
listSubscribeToImage(outfit);
|
||||||
|
});
|
||||||
|
|
||||||
|
wardrobe.image_subscriptions.bind('imageEnqueued', function (outfit) {
|
||||||
|
if(outfit.id in list_image_subscriptions) {
|
||||||
|
log("List sees imageEnqueued for", outfit);
|
||||||
|
outfitElement(outfit).removeClass('thumbnail-loaded');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
wardrobe.image_subscriptions.bind('imageReady', function (outfit) {
|
||||||
|
if(outfit.id in list_image_subscriptions) {
|
||||||
|
log("List sees imageReady for", outfit);
|
||||||
|
listUnsubscribeFromImage(outfit);
|
||||||
|
|
||||||
|
var src = outfit.image_versions.small + '?' + (new Date()).getTime();
|
||||||
|
outfitElement(outfit).addClass('thumbnail-loaded').addClass('thumbnail-available').
|
||||||
|
find('img.outfit-thumbnail').attr('src', src);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Sharing */
|
||||||
|
|
||||||
|
var sharing = new function Sharing() {
|
||||||
|
var WRAPPER = $('#preview-sharing');
|
||||||
|
var sharing_url_els = {
|
||||||
|
permalink: $('#preview-sharing-permalink-url'),
|
||||||
|
large_image: $('#preview-sharing-large-image-url'),
|
||||||
|
medium_image: $('#preview-sharing-medium-image-url'),
|
||||||
|
small_image: $('#preview-sharing-small-image-url'),
|
||||||
|
};
|
||||||
|
var format_selector_els = $('#preview-sharing-url-formats li');
|
||||||
|
var thumbnail_el = $('#preview-sharing-thumbnail');
|
||||||
|
|
||||||
|
var formats = {
|
||||||
|
plain: {
|
||||||
|
image: function (url) { return url },
|
||||||
|
text: function (url) { return url }
|
||||||
|
},
|
||||||
|
html: {
|
||||||
|
image: function (url, permalink) {
|
||||||
|
return '<a href="' + permalink + '"><img src="' + url + '" /></a>';
|
||||||
|
},
|
||||||
|
text: function (url) {
|
||||||
|
return '<a href="' + url + '">Dress to Impress</a>';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bbcode: {
|
||||||
|
image: function (url, permalink) {
|
||||||
|
return '[URL=' + permalink + '][IMG]' + url + '[/IMG][/URL]';
|
||||||
|
},
|
||||||
|
text: function (url) {
|
||||||
|
return '[URL=' + url + ']Dress to Impress[/URL]';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var format = formats.plain;
|
||||||
|
var urls = {permalink: null, small_image: null, medium_image: null,
|
||||||
|
large_image: null};
|
||||||
|
|
||||||
|
format_selector_els.click(function () {
|
||||||
|
var selector_el = $(this);
|
||||||
|
format_selector_els.removeClass('active');
|
||||||
|
selector_el.addClass('active');
|
||||||
|
log("Setting sharing URL format:", selector_el.attr('data-format'));
|
||||||
|
format = formats[selector_el.attr('data-format')];
|
||||||
|
formatUrls();
|
||||||
|
});
|
||||||
|
|
||||||
|
var image_subscription = null;
|
||||||
|
function unsubscribeFromImage() {
|
||||||
|
wardrobe.image_subscriptions.unsubscribe(image_subscription);
|
||||||
|
image_subscription = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function subscribeToImage(outfit) {
|
||||||
|
image_subscription = wardrobe.image_subscriptions.subscribe(outfit);
|
||||||
|
}
|
||||||
|
|
||||||
|
function subscribeToImageIfVisible(outfit) {
|
||||||
|
if(outfit && sidebar_el.hasClass('sharing')) {
|
||||||
|
subscribeToImage(outfit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var current_shared_outfit = {id: null};
|
||||||
|
this.setOutfit = function (outfit) {
|
||||||
|
// If outfit has no ID but we're already on the Sharing tab (e.g. user is
|
||||||
|
// on Sharing but goes back in history to a no-ID outfit), we can't
|
||||||
|
// exactly do anything with it but submit it for sharing.
|
||||||
|
if(!outfit.id) {
|
||||||
|
sharing.startLoading();
|
||||||
|
wardrobe.outfits.share(outfit);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// But if the outfit does have a valid ID, we're good to go. If it's the
|
||||||
|
// same as the currently shared outfit ID, then don't even change
|
||||||
|
// anything. If it's new, then change everything.
|
||||||
|
if(outfit.id != current_shared_outfit.id) {
|
||||||
|
// The current shared outfit needs to be a clone, or else modifications
|
||||||
|
// to the active outfit will show up here, too, and then our comparison
|
||||||
|
// to discover if this is a new outfit ID or not fails.
|
||||||
|
current_shared_outfit = outfit.clone();
|
||||||
|
urls.permalink = generateOutfitPermalink(outfit);
|
||||||
|
urls.small_image = pathToUrl(outfit.image_versions.small);
|
||||||
|
urls.medium_image = pathToUrl(outfit.image_versions.medium);
|
||||||
|
urls.large_image = pathToUrl(outfit.image_versions.large);
|
||||||
|
formatUrls();
|
||||||
|
WRAPPER.removeClass('thumbnail-available');
|
||||||
|
subscribeToImageIfVisible(current_shared_outfit);
|
||||||
|
}
|
||||||
|
WRAPPER.addClass('urls-loaded');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.startLoading = function () {
|
||||||
|
WRAPPER.removeClass('urls-loaded');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.onHide = function () {
|
||||||
|
unsubscribeFromImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.onShow = function () {
|
||||||
|
subscribeToImageIfVisible(wardrobe.outfits.getOutfit());
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatUrls() {
|
||||||
|
formatImageUrl('small_image');
|
||||||
|
formatImageUrl('medium_image');
|
||||||
|
formatImageUrl('large_image');
|
||||||
|
formatTextUrl('permalink');
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatTextUrl(key) {
|
||||||
|
formatUrl(key, format.text(urls[key]));
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatImageUrl(key) {
|
||||||
|
formatUrl(key, format.image(urls[key], urls.permalink));
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatUrl(key, url) {
|
||||||
|
sharing_url_els[key].val(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
wardrobe.image_subscriptions.bind('imageEnqueued', function (outfit) {
|
||||||
|
if(outfit.id == current_shared_outfit.id) {
|
||||||
|
log("Sharing thumbnail enqueued for outfit", outfit);
|
||||||
|
WRAPPER.removeClass('thumbnail-loaded');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
wardrobe.image_subscriptions.bind('imageReady', function (outfit) {
|
||||||
|
if(outfit.id == current_shared_outfit.id) {
|
||||||
|
log("Sharing thumbnail ready for outfit", outfit);
|
||||||
|
var src = outfit.image_versions.small + '?' + outfit.image_layers_hash;
|
||||||
|
thumbnail_el.attr('src', src);
|
||||||
|
WRAPPER.addClass('thumbnail-loaded');
|
||||||
|
WRAPPER.addClass('thumbnail-available');
|
||||||
|
unsubscribeFromImage(outfit);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
wardrobe.outfits.bind('updateSuccess', function (outfit) {
|
||||||
|
if(sidebar_el.hasClass('sharing')) {
|
||||||
|
subscribeToImage(outfit);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
wardrobe.outfits.bind('setOutfit', function (outfit) {
|
||||||
|
log("Sharing sees the setOutfit signal, and will set", outfit);
|
||||||
|
sharing.setOutfit(outfit);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/* Saving */
|
/* Saving */
|
||||||
|
|
||||||
save_current_outfit_el.click(function () {
|
save_current_outfit_el.click(function () {
|
||||||
wardrobe.outfit.update();
|
wardrobe.outfits.update();
|
||||||
});
|
});
|
||||||
|
|
||||||
new_outfit_form_el.submit(function (e) {
|
new_outfit_form_el.submit(function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
new_outfit_form_el.startLoading();
|
new_outfit_form_el.startLoading();
|
||||||
wardrobe.outfit.create({starred: new_outfit_form_el.hasClass('starred'), name: new_outfit_name_el.val()});
|
wardrobe.outfits.create({starred: new_outfit_form_el.hasClass('starred'), name: new_outfit_name_el.val()});
|
||||||
});
|
|
||||||
|
|
||||||
$('#share-outfit').click(function () {
|
|
||||||
save_outfit_wrapper_el.startLoading();
|
|
||||||
wardrobe.outfit.share();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
new_outfit_form_el.find('div.outfit-star').click(function () {
|
new_outfit_form_el.find('div.outfit-star').click(function () {
|
||||||
|
@ -664,32 +883,31 @@ View.Outfits = function (wardrobe) {
|
||||||
save_error_el.text(text).notify();
|
save_error_el.text(text).notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
wardrobe.outfit.bind('saveSuccess', function (outfit) {
|
wardrobe.outfits.bind('saveSuccess', function (outfit) {
|
||||||
save_success_el.notify();
|
save_success_el.notify();
|
||||||
});
|
});
|
||||||
|
|
||||||
wardrobe.outfit.bind('createSuccess', function (outfit) {
|
wardrobe.outfits.bind('createSuccess', function (outfit) {
|
||||||
wardrobe.user.addOutfit(outfit);
|
|
||||||
showOutfits();
|
showOutfits();
|
||||||
hideNewOutfitForm();
|
hideNewOutfitForm();
|
||||||
});
|
});
|
||||||
|
|
||||||
wardrobe.outfit.bind('updateSuccess', function (outfit) {
|
function shareComplete(outfit) {
|
||||||
wardrobe.user.updateOutfit(outfit);
|
|
||||||
});
|
|
||||||
|
|
||||||
wardrobe.outfit.bind('shareSuccess', function (outfit) {
|
|
||||||
save_outfit_wrapper_el.stopLoading().addClass('shared-outfit');
|
save_outfit_wrapper_el.stopLoading().addClass('shared-outfit');
|
||||||
setSharedOutfitPermalink(outfit);
|
sharing.setOutfit(outfit);
|
||||||
});
|
showSharing();
|
||||||
|
}
|
||||||
|
|
||||||
|
wardrobe.outfits.bind('shareSuccess', shareComplete);
|
||||||
|
wardrobe.outfits.bind('shareSkipped', shareComplete);
|
||||||
|
|
||||||
function clearSharedOutfit() {
|
function clearSharedOutfit() {
|
||||||
save_outfit_wrapper_el.removeClass('shared-outfit');
|
save_outfit_wrapper_el.removeClass('shared-outfit');
|
||||||
}
|
}
|
||||||
|
|
||||||
wardrobe.outfit.bind('updateClosetItems', clearSharedOutfit);
|
wardrobe.outfits.bind('updateClosetItems', clearSharedOutfit);
|
||||||
wardrobe.outfit.bind('updateWornItems', clearSharedOutfit);
|
wardrobe.outfits.bind('updateWornItems', clearSharedOutfit);
|
||||||
wardrobe.outfit.bind('updatePetState', clearSharedOutfit);
|
wardrobe.outfits.bind('updatePetState', clearSharedOutfit);
|
||||||
|
|
||||||
function saveFailure(outfit, response) {
|
function saveFailure(outfit, response) {
|
||||||
var errors = response.errors;
|
var errors = response.errors;
|
||||||
|
@ -712,16 +930,16 @@ View.Outfits = function (wardrobe) {
|
||||||
liForOutfit(outfit).stopLoading();
|
liForOutfit(outfit).stopLoading();
|
||||||
}
|
}
|
||||||
|
|
||||||
wardrobe.outfit.bind('saveFailure', saveFailure);
|
wardrobe.outfits.bind('saveFailure', saveFailure);
|
||||||
wardrobe.user.bind('saveFailure', saveFailure)
|
wardrobe.outfits.bind('saveFailure', saveFailure)
|
||||||
wardrobe.outfit.bind('shareFailure', function (outfit, response) {
|
wardrobe.outfits.bind('shareFailure', function (outfit, response) {
|
||||||
save_outfit_wrapper_el.stopLoading();
|
save_outfit_wrapper_el.stopLoading();
|
||||||
saveFailure(outfit, response);
|
saveFailure(outfit, response);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Error */
|
/* Error */
|
||||||
|
|
||||||
wardrobe.outfit.bind('outfitNotFound', function () {
|
wardrobe.outfits.bind('outfitNotFound', function () {
|
||||||
outfit_not_found_el.notify();
|
outfit_not_found_el.notify();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -733,7 +951,7 @@ View.PetStateForm = function (wardrobe) {
|
||||||
button_query = form_query + ' button';
|
button_query = form_query + ' button';
|
||||||
$(button_query).live('click', function (e) {
|
$(button_query).live('click', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
wardrobe.outfit.setPetStateById(+$(this).data('value'));
|
wardrobe.outfits.setPetStateById(+$(this).data('value'));
|
||||||
});
|
});
|
||||||
|
|
||||||
function updatePetState(pet_state) {
|
function updatePetState(pet_state) {
|
||||||
|
@ -743,7 +961,7 @@ View.PetStateForm = function (wardrobe) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wardrobe.outfit.bind('petTypeLoaded', function (pet_type) {
|
wardrobe.outfits.bind('petTypeLoaded', function (pet_type) {
|
||||||
var ids = pet_type.pet_state_ids, i, id, li, button, label;
|
var ids = pet_type.pet_state_ids, i, id, li, button, label;
|
||||||
ul.children().remove();
|
ul.children().remove();
|
||||||
if(ids.length == 1) {
|
if(ids.length == 1) {
|
||||||
|
@ -761,18 +979,18 @@ View.PetStateForm = function (wardrobe) {
|
||||||
button.appendTo(li);
|
button.appendTo(li);
|
||||||
li.appendTo(ul);
|
li.appendTo(ul);
|
||||||
}
|
}
|
||||||
updatePetState(wardrobe.outfit.getPetState());
|
updatePetState(wardrobe.outfits.getPetState());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
wardrobe.outfit.bind('updatePetState', updatePetState);
|
wardrobe.outfits.bind('updatePetState', updatePetState);
|
||||||
}
|
}
|
||||||
|
|
||||||
View.PetTypeForm = function (wardrobe) {
|
View.PetTypeForm = function (wardrobe) {
|
||||||
var form = $('#pet-type-form'), dropdowns = {}, loaded = false;
|
var form = $('#pet-type-form'), dropdowns = {}, loaded = false;
|
||||||
form.submit(function (e) {
|
form.submit(function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
wardrobe.outfit.setPetTypeByColorAndSpecies(
|
wardrobe.outfits.setPetTypeByColorAndSpecies(
|
||||||
+dropdowns.color.val(), +dropdowns.species.val()
|
+dropdowns.color.val(), +dropdowns.species.val()
|
||||||
);
|
);
|
||||||
}).children('select').each(function () {
|
}).children('select').each(function () {
|
||||||
|
@ -803,12 +1021,12 @@ View.PetTypeForm = function (wardrobe) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
loaded = true;
|
loaded = true;
|
||||||
updatePetType(wardrobe.outfit.getPetType());
|
updatePetType(wardrobe.outfits.getPetType());
|
||||||
});
|
});
|
||||||
|
|
||||||
wardrobe.outfit.bind('updatePetType', updatePetType);
|
wardrobe.outfits.bind('updatePetType', updatePetType);
|
||||||
|
|
||||||
wardrobe.outfit.bind('petTypeNotFound', function () {
|
wardrobe.outfits.bind('petTypeNotFound', function () {
|
||||||
$('#pet-type-not-found').show('normal').delay(3000).hide('fast');
|
$('#pet-type-not-found').show('normal').delay(3000).hide('fast');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -865,7 +1083,7 @@ View.ReportBrokenImage = function (wardrobe) {
|
||||||
var baseURL = link.attr('data-base-url');
|
var baseURL = link.attr('data-base-url');
|
||||||
|
|
||||||
function updateLink() {
|
function updateLink() {
|
||||||
var assets = wardrobe.outfit.getVisibleAssets();
|
var assets = wardrobe.outfits.getVisibleAssets();
|
||||||
var url = baseURL + "?";
|
var url = baseURL + "?";
|
||||||
|
|
||||||
for(var i = 0; i < assets.length; i++) {
|
for(var i = 0; i < assets.length; i++) {
|
||||||
|
@ -876,9 +1094,9 @@ View.ReportBrokenImage = function (wardrobe) {
|
||||||
link.attr('href', url);
|
link.attr('href', url);
|
||||||
}
|
}
|
||||||
|
|
||||||
wardrobe.outfit.bind('updateWornItems', updateLink);
|
wardrobe.outfits.bind('updateWornItems', updateLink);
|
||||||
wardrobe.outfit.bind('updateItemAssets', updateLink);
|
wardrobe.outfits.bind('updateItemAssets', updateLink);
|
||||||
wardrobe.outfit.bind('updatePetState', updateLink);
|
wardrobe.outfits.bind('updatePetState', updateLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
View.Search = function (wardrobe) {
|
View.Search = function (wardrobe) {
|
||||||
|
|
|
@ -7,4 +7,4 @@ var main_wardrobe = new Wardrobe(), View = Wardrobe.getStandardView({
|
||||||
});
|
});
|
||||||
main_wardrobe.registerViews(View);
|
main_wardrobe.registerViews(View);
|
||||||
main_wardrobe.initialize();
|
main_wardrobe.initialize();
|
||||||
main_wardrobe.outfit.loadData(INITIAL_OUTFIT_DATA);
|
main_wardrobe.outfits.loadData(INITIAL_OUTFIT_DATA);
|
||||||
|
|
|
@ -7,9 +7,6 @@ function arraysMatch(array1, array2) {
|
||||||
return array1 == array2;
|
return array1 == array2;
|
||||||
}
|
}
|
||||||
temp = [];
|
temp = [];
|
||||||
if ( (!array1[0]) || (!array2[0]) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (array1.length != array2.length) {
|
if (array1.length != array2.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +25,7 @@ function arraysMatch(array1, array2) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Array.prototype.map = function (property) {
|
Array.prototype.mapProperty = function (property) {
|
||||||
return $.map(this, function (element) {
|
return $.map(this, function (element) {
|
||||||
return element[property];
|
return element[property];
|
||||||
});
|
});
|
||||||
|
@ -79,8 +76,19 @@ function Wardrobe() {
|
||||||
function Asset(newData) {
|
function Asset(newData) {
|
||||||
var asset = this;
|
var asset = this;
|
||||||
|
|
||||||
|
function size_key(size) {
|
||||||
|
return size[0] + 'x' + size[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.image_urls_by_size_key = {};
|
||||||
|
var image;
|
||||||
|
for(var i = 0; i < newData.images.length; i++) {
|
||||||
|
image = newData.images[i];
|
||||||
|
this.image_urls_by_size_key[size_key(image.size)] = image.url;
|
||||||
|
}
|
||||||
|
|
||||||
this.imageURL = function (size) {
|
this.imageURL = function (size) {
|
||||||
return Wardrobe.IMAGE_CONFIG.base_url + this.s3_path + "/" + size[0] + "x" + size[1] + ".png";
|
return this.image_urls_by_size_key[size_key(size)];
|
||||||
}
|
}
|
||||||
|
|
||||||
this.update = function (data) {
|
this.update = function (data) {
|
||||||
|
@ -268,17 +276,24 @@ function Wardrobe() {
|
||||||
closet_item_ids = new_ids.unworn.concat(new_ids.worn);
|
closet_item_ids = new_ids.unworn.concat(new_ids.worn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(typeof data != 'undefined') {
|
function loadAttributes(data) {
|
||||||
this.color_id = data.color_id;
|
outfit.color_id = data.color_id;
|
||||||
this.id = data.id;
|
outfit.id = data.id;
|
||||||
this.name = data.name;
|
outfit.name = data.name;
|
||||||
this.pet_state_id = data.pet_state_id;
|
outfit.pet_state_id = data.pet_state_id;
|
||||||
this.starred = data.starred;
|
outfit.starred = data.starred;
|
||||||
this.species_id = data.species_id;
|
outfit.species_id = data.species_id;
|
||||||
this.setWornAndUnwornItemIds(data.worn_and_unworn_item_ids);
|
outfit.image_versions = data.image_versions;
|
||||||
|
outfit.image_enqueued = data.image_enqueued;
|
||||||
|
outfit.image_layers_hash = data.image_layers_hash;
|
||||||
|
outfit.setWornAndUnwornItemIds(data.worn_and_unworn_item_ids);
|
||||||
new_record = false;
|
new_record = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(typeof data != 'undefined') {
|
||||||
|
loadAttributes(data);
|
||||||
|
}
|
||||||
|
|
||||||
this.closet_items = [];
|
this.closet_items = [];
|
||||||
this.worn_items = [];
|
this.worn_items = [];
|
||||||
|
|
||||||
|
@ -327,11 +342,11 @@ function Wardrobe() {
|
||||||
new_items = [], new_worn_item_ids = [];
|
new_items = [], new_worn_item_ids = [];
|
||||||
if(added_item) {
|
if(added_item) {
|
||||||
// now that we've loaded, check for conflicts on the added item
|
// now that we've loaded, check for conflicts on the added item
|
||||||
item_zones = added_item.getAssetsFitting(outfit.pet_type).map('zone_id');
|
item_zones = added_item.getAssetsFitting(outfit.pet_type).mapProperty('zone_id');
|
||||||
item_zones_length = item_zones.length;
|
item_zones_length = item_zones.length;
|
||||||
for(var i = 0; i < outfit.worn_items.length; i++) {
|
for(var i = 0; i < outfit.worn_items.length; i++) {
|
||||||
existing_item = outfit.worn_items[i];
|
existing_item = outfit.worn_items[i];
|
||||||
existing_item_zones = existing_item.getAssetsFitting(outfit.pet_type).map('zone_id');
|
existing_item_zones = existing_item.getAssetsFitting(outfit.pet_type).mapProperty('zone_id');
|
||||||
passed = true;
|
passed = true;
|
||||||
if(existing_item != added_item) {
|
if(existing_item != added_item) {
|
||||||
for(var j = 0; j < item_zones_length; j++) {
|
for(var j = 0; j < item_zones_length; j++) {
|
||||||
|
@ -369,23 +384,6 @@ function Wardrobe() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendUpdate(outfit_data, success, failure) {
|
|
||||||
$.ajax({
|
|
||||||
url: '/outfits/' + outfit.id,
|
|
||||||
type: 'post',
|
|
||||||
data: {'_method': 'put', outfit: outfit_data},
|
|
||||||
success: function () {
|
|
||||||
Outfit.cache[outfit.id] = outfit;
|
|
||||||
success(outfit);
|
|
||||||
},
|
|
||||||
error: function (xhr) {
|
|
||||||
if(typeof failure !== 'undefined') {
|
|
||||||
failure(outfit, $.parseJSON(xhr.responseText));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.closetItem = function (item, updateClosetItemsCallback) {
|
this.closetItem = function (item, updateClosetItemsCallback) {
|
||||||
if(!hasItemInCloset(item)) {
|
if(!hasItemInCloset(item)) {
|
||||||
this.closet_items.push(item);
|
this.closet_items.push(item);
|
||||||
|
@ -416,6 +414,14 @@ function Wardrobe() {
|
||||||
return visible_assets;
|
return visible_assets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.isIdenticalTo = function (other) {
|
||||||
|
return other && // other exists
|
||||||
|
this.constructor == other.constructor && // other is an outfit
|
||||||
|
this.getPetStateId() == other.getPetStateId() &&
|
||||||
|
arraysMatch(this.getWornItemIds(), other.getWornItemIds()) &&
|
||||||
|
arraysMatch(this.getClosetItemIds(), other.getClosetItemIds());
|
||||||
|
}
|
||||||
|
|
||||||
this.rename = function (new_name, success, failure) {
|
this.rename = function (new_name, success, failure) {
|
||||||
this.updateAttributes({name: new_name}, success, failure);
|
this.updateAttributes({name: new_name}, success, failure);
|
||||||
}
|
}
|
||||||
|
@ -522,6 +528,9 @@ function Wardrobe() {
|
||||||
new_outfit.id = outfit.id;
|
new_outfit.id = outfit.id;
|
||||||
new_outfit.name = outfit.name;
|
new_outfit.name = outfit.name;
|
||||||
new_outfit.starred = outfit.starred;
|
new_outfit.starred = outfit.starred;
|
||||||
|
new_outfit.image_enqueued = outfit.image_enqueued;
|
||||||
|
new_outfit.image_versions = outfit.image_versions;
|
||||||
|
new_outfit.image_layers_hash = outfit.image_layers_hash;
|
||||||
return new_outfit;
|
return new_outfit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,6 +549,13 @@ function Wardrobe() {
|
||||||
outfit.setWornAndUnwornItemIds(new_ids);
|
outfit.setWornAndUnwornItemIds(new_ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateFromSaveResponse(data) {
|
||||||
|
outfit.id = data.id;
|
||||||
|
outfit.image_versions = data.image_versions;
|
||||||
|
outfit.image_enqueued = data.image_enqueued;
|
||||||
|
outfit.image_layers_hash = data.image_layers_hash;
|
||||||
|
}
|
||||||
|
|
||||||
this.destroy = function (success) {
|
this.destroy = function (success) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/outfits/' + outfit.id + '.json',
|
url: '/outfits/' + outfit.id + '.json',
|
||||||
|
@ -554,10 +570,11 @@ function Wardrobe() {
|
||||||
url: '/outfits',
|
url: '/outfits',
|
||||||
type: 'post',
|
type: 'post',
|
||||||
data: {outfit: getAttributes()},
|
data: {outfit: getAttributes()},
|
||||||
|
dataType: 'json',
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
new_record = false;
|
new_record = false;
|
||||||
outfit.id = data;
|
updateFromSaveResponse(data);
|
||||||
Outfit.cache[data] = outfit;
|
Outfit.cache[outfit.id] = outfit;
|
||||||
success(outfit);
|
success(outfit);
|
||||||
},
|
},
|
||||||
error: function (xhr) {
|
error: function (xhr) {
|
||||||
|
@ -566,6 +583,32 @@ function Wardrobe() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.reload = function (success) {
|
||||||
|
Outfit.load(this.id, function (new_outfit) {
|
||||||
|
loadAttributes(new_outfit);
|
||||||
|
success(outfit);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendUpdate(outfit_data, success, failure) {
|
||||||
|
$.ajax({
|
||||||
|
url: '/outfits/' + outfit.id,
|
||||||
|
type: 'post',
|
||||||
|
data: {'_method': 'put', outfit: outfit_data},
|
||||||
|
dataType: 'json',
|
||||||
|
success: function (data) {
|
||||||
|
updateFromSaveResponse(data);
|
||||||
|
Outfit.cache[outfit.id] = outfit;
|
||||||
|
success(outfit);
|
||||||
|
},
|
||||||
|
error: function (xhr) {
|
||||||
|
if(typeof failure !== 'undefined') {
|
||||||
|
failure(outfit, $.parseJSON(xhr.responseText));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.updateAttributes = function (attributes, success, failure) {
|
this.updateAttributes = function (attributes, success, failure) {
|
||||||
var outfit_data = {};
|
var outfit_data = {};
|
||||||
for(var key in attributes) {
|
for(var key in attributes) {
|
||||||
|
@ -583,20 +626,24 @@ function Wardrobe() {
|
||||||
if(typeof Outfit.cache[id] !== 'undefined') {
|
if(typeof Outfit.cache[id] !== 'undefined') {
|
||||||
callback(Outfit.cache[id]);
|
callback(Outfit.cache[id]);
|
||||||
} else {
|
} else {
|
||||||
$.ajax({
|
Outfit.load(id, callback);
|
||||||
url: '/outfits/' + id + '.json',
|
|
||||||
success: function (data) {
|
|
||||||
var outfit = new Outfit(data);
|
|
||||||
Outfit.cache[id] = outfit;
|
|
||||||
callback(outfit);
|
|
||||||
},
|
|
||||||
error: function () {
|
|
||||||
callback(null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Outfit.load = function (id, callback) {
|
||||||
|
$.ajax({
|
||||||
|
url: '/outfits/' + id + '.json',
|
||||||
|
success: function (data) {
|
||||||
|
var outfit = new Outfit(data);
|
||||||
|
Outfit.cache[id] = outfit;
|
||||||
|
callback(outfit);
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
callback(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Outfit.loadForCurrentUser = function (success) {
|
Outfit.loadForCurrentUser = function (success) {
|
||||||
var outfits = [];
|
var outfits = [];
|
||||||
$.getJSON('/users/current-user/outfits.json', function (data) {
|
$.getJSON('/users/current-user/outfits.json', function (data) {
|
||||||
|
@ -788,8 +835,13 @@ function Wardrobe() {
|
||||||
|
|
||||||
Controller.all = {};
|
Controller.all = {};
|
||||||
|
|
||||||
Controller.all.Outfit = function OutfitController() {
|
Controller.all.Outfits = function OutfitsController() {
|
||||||
var controller = this, outfit = new Outfit;
|
// TODO: clean up the merge of outfits and user controller. Some is already
|
||||||
|
// done, but I'm sure there's tons of redundant code still lying around.
|
||||||
|
|
||||||
|
/* Current outfit management */
|
||||||
|
|
||||||
|
var controller = this, outfit = new Outfit, last_shared_outfit = null;
|
||||||
|
|
||||||
this.in_transaction = false;
|
this.in_transaction = false;
|
||||||
|
|
||||||
|
@ -862,6 +914,7 @@ function Wardrobe() {
|
||||||
}
|
}
|
||||||
outfit.create(
|
outfit.create(
|
||||||
function (outfit) {
|
function (outfit) {
|
||||||
|
insertOutfit(outfit);
|
||||||
controller.events.trigger('saveSuccess', outfit);
|
controller.events.trigger('saveSuccess', outfit);
|
||||||
controller.events.trigger('createSuccess', outfit);
|
controller.events.trigger('createSuccess', outfit);
|
||||||
controller.events.trigger('setOutfit', outfit);
|
controller.events.trigger('setOutfit', outfit);
|
||||||
|
@ -920,12 +973,24 @@ function Wardrobe() {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.share = function () {
|
this.share = function () {
|
||||||
var sharedOutfit = outfit.clone();
|
if(outfit.id) {
|
||||||
sharedOutfit.anonymous = true;
|
// If this is a user-saved outfit (user is logged in), no need to
|
||||||
sharedOutfit.create(
|
// re-share it. Skip to using the current outfit.
|
||||||
controller.event('shareSuccess'),
|
controller.events.trigger('shareSkipped', outfit);
|
||||||
controller.event('shareFailure')
|
} else if(outfit.isIdenticalTo(last_shared_outfit)) {
|
||||||
);
|
// If the outfit hasn't changed since last time we shared it, no need to
|
||||||
|
// re-share it. Skip to using the last shared outfit.
|
||||||
|
controller.events.trigger('shareSkipped', last_shared_outfit);
|
||||||
|
} else {
|
||||||
|
// Otherwise, this is a fresh outfit that needs to be shared. Try, and
|
||||||
|
// report success or failure.
|
||||||
|
last_shared_outfit = outfit.clone();
|
||||||
|
last_shared_outfit.anonymous = true;
|
||||||
|
last_shared_outfit.create(
|
||||||
|
controller.event('shareSuccess'),
|
||||||
|
controller.event('shareFailure')
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.unclosetItem = function (item) {
|
this.unclosetItem = function (item) {
|
||||||
|
@ -943,6 +1008,7 @@ function Wardrobe() {
|
||||||
this.update = function () {
|
this.update = function () {
|
||||||
outfit.update(
|
outfit.update(
|
||||||
function (outfit) {
|
function (outfit) {
|
||||||
|
updateUserOutfit(outfit);
|
||||||
controller.events.trigger('saveSuccess', outfit),
|
controller.events.trigger('saveSuccess', outfit),
|
||||||
controller.events.trigger('updateSuccess', outfit)
|
controller.events.trigger('updateSuccess', outfit)
|
||||||
},
|
},
|
||||||
|
@ -958,6 +1024,159 @@ function Wardrobe() {
|
||||||
controller.event('updateItemAssets')
|
controller.event('updateItemAssets')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* User outfits management */
|
||||||
|
|
||||||
|
var outfits = [], outfits_loaded = false;
|
||||||
|
|
||||||
|
function compareOutfits(a, b) {
|
||||||
|
if(a.starred) {
|
||||||
|
if(!b.starred) return -1;
|
||||||
|
} else if(b.starred) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(a.name < b.name) return -1;
|
||||||
|
else if(a.name == b.name) return 0;
|
||||||
|
else return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function insertOutfit(outfit) {
|
||||||
|
for(var i = 0; i < outfits.length; i++) {
|
||||||
|
if(compareOutfits(outfit, outfits[i]) < 0) {
|
||||||
|
outfits.splice(i, 0, outfit);
|
||||||
|
controller.events.trigger('addOutfit', outfit, i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
controller.events.trigger('addOutfit', outfit, outfits.length);
|
||||||
|
outfits.push(outfit);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortOutfits(outfits) {
|
||||||
|
outfits.sort(compareOutfits);
|
||||||
|
}
|
||||||
|
|
||||||
|
function yankOutfit(outfit) {
|
||||||
|
var i;
|
||||||
|
for(i = 0; i < outfits.length; i++) {
|
||||||
|
if(outfit.id == outfits[i].id) {
|
||||||
|
outfits.splice(i, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
controller.events.trigger('removeOutfit', outfit, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.destroyOutfit = function (outfit) {
|
||||||
|
outfit.destroy(function () {
|
||||||
|
yankOutfit(outfit);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadOutfits = function () {
|
||||||
|
if(!outfits_loaded) {
|
||||||
|
Outfit.loadForCurrentUser(function (new_outfits) {
|
||||||
|
outfits = new_outfits;
|
||||||
|
outfits_loaded = true;
|
||||||
|
sortOutfits(outfits);
|
||||||
|
controller.events.trigger('outfitsLoaded', outfits);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.renameOutfit = function (outfit, new_name) {
|
||||||
|
var old_name = outfit.name;
|
||||||
|
outfit.rename(new_name, function () {
|
||||||
|
yankOutfit(outfit);
|
||||||
|
insertOutfit(outfit);
|
||||||
|
controller.events.trigger('outfitRenamed', outfit);
|
||||||
|
}, function (outfit_copy, response) {
|
||||||
|
outfit.name = old_name;
|
||||||
|
controller.events.trigger('saveFailure', outfit_copy, response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.toggleOutfitStar = function (outfit) {
|
||||||
|
outfit.toggleStar(function () {
|
||||||
|
yankOutfit(outfit);
|
||||||
|
insertOutfit(outfit);
|
||||||
|
controller.events.trigger('outfitStarToggled', outfit);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateUserOutfit(outfit) {
|
||||||
|
for(var i = 0; i < outfits.length; i++) {
|
||||||
|
if(outfits[i].id == outfit.id) {
|
||||||
|
outfits[i] = outfit.clone();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Controller.all.ImageSubscriptions = function ImagesSubscriptionsController() {
|
||||||
|
var outfitSubscriptionTotals = {};
|
||||||
|
var DELAY = 5000;
|
||||||
|
var controller = this;
|
||||||
|
|
||||||
|
function checkSubscription(outfit_id) {
|
||||||
|
Outfit.find(outfit_id, function (outfit) {
|
||||||
|
log("Checking image for", outfit);
|
||||||
|
outfit.reload(function () {
|
||||||
|
if(outfitSubscriptionTotals[outfit_id] > 0) {
|
||||||
|
if(outfit.image_enqueued) {
|
||||||
|
log("Outfit image still enqueued; will try again soon", outfit);
|
||||||
|
setTimeout(function () { checkSubscription(outfit_id) }, DELAY);
|
||||||
|
} else {
|
||||||
|
// Unsubscribe everyone from this outfit and fire ready events
|
||||||
|
delete outfitSubscriptionTotals[outfit_id];
|
||||||
|
controller.events.trigger('imageReady', outfit);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log("Outfit was unsubscribed", outfit);
|
||||||
|
delete outfitSubscriptionTotals[outfit_id];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.subscribe = function (outfit) {
|
||||||
|
if(outfit.image_enqueued) {
|
||||||
|
if(outfit.id in outfitSubscriptionTotals) {
|
||||||
|
// The subscription is already running. Just mark that one more
|
||||||
|
// consumer is interested in it, and they'll all get a response soon.
|
||||||
|
outfitSubscriptionTotals[outfit.id] += 1;
|
||||||
|
} else {
|
||||||
|
// This is a new subscription! Let's start checking it.
|
||||||
|
outfitSubscriptionTotals[outfit.id] = 1;
|
||||||
|
checkSubscription(outfit.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regardless, trigger the enqueued event for the new consumer's sake.
|
||||||
|
controller.events.trigger('imageEnqueued', outfit);
|
||||||
|
} else {
|
||||||
|
// Otherwise, never bother checking: skip straight to the ready phase.
|
||||||
|
// Give it an instant timeout so that we're sure the consumer is ready
|
||||||
|
// for the event. (It can be tricky when the consumer assigns this
|
||||||
|
// return value somewhere to know if it cares about the event, so the
|
||||||
|
// event can't fire before the return.)
|
||||||
|
setTimeout(function () {
|
||||||
|
controller.events.trigger('imageReady', outfit)
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return outfit;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.unsubscribe = function (outfit) {
|
||||||
|
if(outfit && outfit.id in outfitSubscriptionTotals) {
|
||||||
|
if(outfitSubscriptionTotals[outfit.id] > 1) {
|
||||||
|
outfitSubscriptionTotals[outfit.id] -= 1;
|
||||||
|
} else {
|
||||||
|
delete outfitSubscriptionTotals[outfit.id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller.all.BasePet = function BasePetController() {
|
Controller.all.BasePet = function BasePetController() {
|
||||||
|
@ -1028,96 +1247,6 @@ function Wardrobe() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller.all.User = function UserController() {
|
|
||||||
var controller = this, outfits = [], outfits_loaded = false;
|
|
||||||
|
|
||||||
function compareOutfits(a, b) {
|
|
||||||
if(a.starred) {
|
|
||||||
if(!b.starred) return -1;
|
|
||||||
} else if(b.starred) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(a.name < b.name) return -1;
|
|
||||||
else if(a.name == b.name) return 0;
|
|
||||||
else return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function insertOutfit(outfit) {
|
|
||||||
for(var i = 0; i < outfits.length; i++) {
|
|
||||||
if(compareOutfits(outfit, outfits[i]) < 0) {
|
|
||||||
outfits.splice(i, 0, outfit);
|
|
||||||
controller.events.trigger('addOutfit', outfit, i);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
controller.events.trigger('addOutfit', outfit, outfits.length);
|
|
||||||
outfits.push(outfit);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sortOutfits(outfits) {
|
|
||||||
outfits.sort(compareOutfits);
|
|
||||||
}
|
|
||||||
|
|
||||||
function yankOutfit(outfit) {
|
|
||||||
var i;
|
|
||||||
for(i = 0; i < outfits.length; i++) {
|
|
||||||
if(outfit.id == outfits[i].id) {
|
|
||||||
outfits.splice(i, 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
controller.events.trigger('removeOutfit', outfit, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.addOutfit = insertOutfit;
|
|
||||||
|
|
||||||
this.destroyOutfit = function (outfit) {
|
|
||||||
outfit.destroy(function () {
|
|
||||||
yankOutfit(outfit);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.loadOutfits = function () {
|
|
||||||
if(!outfits_loaded) {
|
|
||||||
Outfit.loadForCurrentUser(function (new_outfits) {
|
|
||||||
outfits = new_outfits;
|
|
||||||
outfits_loaded = true;
|
|
||||||
sortOutfits(outfits);
|
|
||||||
controller.events.trigger('outfitsLoaded', outfits);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.renameOutfit = function (outfit, new_name) {
|
|
||||||
var old_name = outfit.name;
|
|
||||||
outfit.rename(new_name, function () {
|
|
||||||
yankOutfit(outfit);
|
|
||||||
insertOutfit(outfit);
|
|
||||||
controller.events.trigger('outfitRenamed', outfit);
|
|
||||||
}, function (outfit_copy, response) {
|
|
||||||
outfit.name = old_name;
|
|
||||||
controller.events.trigger('saveFailure', outfit_copy, response);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.toggleOutfitStar = function (outfit) {
|
|
||||||
outfit.toggleStar(function () {
|
|
||||||
yankOutfit(outfit);
|
|
||||||
insertOutfit(outfit);
|
|
||||||
controller.events.trigger('outfitStarToggled', outfit);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.updateOutfit = function (outfit) {
|
|
||||||
for(var i = 0; i < outfits.length; i++) {
|
|
||||||
if(outfits[i].id == outfit.id) {
|
|
||||||
outfits[i] = outfit.clone();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var underscored_name;
|
var underscored_name;
|
||||||
|
|
||||||
for(var name in Controller.all) {
|
for(var name in Controller.all) {
|
||||||
|
@ -1196,13 +1325,13 @@ Wardrobe.getStandardView = function (options) {
|
||||||
var outfit_events = ['updateWornItems', 'updateClosetItems', 'updateItemAssets', 'updatePetType', 'updatePetState'];
|
var outfit_events = ['updateWornItems', 'updateClosetItems', 'updateItemAssets', 'updatePetType', 'updatePetState'];
|
||||||
for(var i = 0; i < outfit_events.length; i++) {
|
for(var i = 0; i < outfit_events.length; i++) {
|
||||||
(function (event) {
|
(function (event) {
|
||||||
wardrobe.outfit.bind(event, function (obj) {
|
wardrobe.outfits.bind(event, function (obj) {
|
||||||
log(event, obj);
|
log(event, obj);
|
||||||
});
|
});
|
||||||
})(outfit_events[i]);
|
})(outfit_events[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
wardrobe.outfit.bind('petTypeNotFound', function (pet_type) {
|
wardrobe.outfits.bind('petTypeNotFound', function (pet_type) {
|
||||||
log(pet_type.toString() + ' not found');
|
log(pet_type.toString() + ' not found');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1246,7 +1375,7 @@ Wardrobe.getStandardView = function (options) {
|
||||||
var assets, assets_for_swf;
|
var assets, assets_for_swf;
|
||||||
if(update_pending_flash) return false;
|
if(update_pending_flash) return false;
|
||||||
if(preview_swf && preview_swf.setAssets) {
|
if(preview_swf && preview_swf.setAssets) {
|
||||||
assets = wardrobe.outfit.getVisibleAssets();
|
assets = wardrobe.outfits.getVisibleAssets();
|
||||||
preview_swf.setAssets(assets);
|
preview_swf.setAssets(assets);
|
||||||
} else {
|
} else {
|
||||||
update_pending_flash = true;
|
update_pending_flash = true;
|
||||||
|
@ -1303,10 +1432,11 @@ Wardrobe.getStandardView = function (options) {
|
||||||
|
|
||||||
// Get a copy of the visible assets, then sort them in ascending zone
|
// Get a copy of the visible assets, then sort them in ascending zone
|
||||||
// order.
|
// order.
|
||||||
var assets = wardrobe.outfit.getVisibleAssets().slice(0);
|
var assets = wardrobe.outfits.getVisibleAssets().slice(0);
|
||||||
assets.sort(function (a, b) {
|
assets.sort(function (a, b) {
|
||||||
return a.depth - b.depth;
|
return a.depth - b.depth;
|
||||||
});
|
});
|
||||||
|
console.log(assets.mapProperty('id'));return;
|
||||||
|
|
||||||
for(var i = 0; i < assets.length; i++) {
|
for(var i = 0; i < assets.length; i++) {
|
||||||
url += "," + encodeURIComponent(assets[i].imageURL(size));
|
url += "," + encodeURIComponent(assets[i].imageURL(size));
|
||||||
|
@ -1316,7 +1446,7 @@ Wardrobe.getStandardView = function (options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateAssets = function () {
|
this.updateAssets = function () {
|
||||||
var assets = wardrobe.outfit.getVisibleAssets(), asset,
|
var assets = wardrobe.outfits.getVisibleAssets(), asset,
|
||||||
availableAssets = [];
|
availableAssets = [];
|
||||||
pendingAssets = {};
|
pendingAssets = {};
|
||||||
pendingAssetsCount = 0;
|
pendingAssetsCount = 0;
|
||||||
|
@ -1375,10 +1505,9 @@ Wardrobe.getStandardView = function (options) {
|
||||||
for(var i in sizes) {
|
for(var i in sizes) {
|
||||||
if(!sizes.hasOwnProperty(i)) continue;
|
if(!sizes.hasOwnProperty(i)) continue;
|
||||||
size = sizes[i];
|
size = sizes[i];
|
||||||
size[2] = size[0] * size[1];
|
|
||||||
inserted = false;
|
inserted = false;
|
||||||
for(var i in SIZES_SMALL_TO_LARGE) {
|
for(var i in SIZES_SMALL_TO_LARGE) {
|
||||||
if(SIZES_SMALL_TO_LARGE[i][2] > size[2]) {
|
if(SIZES_SMALL_TO_LARGE[i][0] * SIZES_SMALL_TO_LARGE[i][1] > size[0] * size[1]) {
|
||||||
SIZES_SMALL_TO_LARGE.splice(i, 0, size);
|
SIZES_SMALL_TO_LARGE.splice(i, 0, size);
|
||||||
inserted = true;
|
inserted = true;
|
||||||
break;
|
break;
|
||||||
|
@ -1476,9 +1605,9 @@ Wardrobe.getStandardView = function (options) {
|
||||||
preview.adapter.updateAssets();
|
preview.adapter.updateAssets();
|
||||||
}
|
}
|
||||||
|
|
||||||
wardrobe.outfit.bind('updateWornItems', updateAssets);
|
wardrobe.outfits.bind('updateWornItems', updateAssets);
|
||||||
wardrobe.outfit.bind('updateItemAssets', updateAssets);
|
wardrobe.outfits.bind('updateItemAssets', updateAssets);
|
||||||
wardrobe.outfit.bind('updatePetState', updateAssets);
|
wardrobe.outfits.bind('updatePetState', updateAssets);
|
||||||
|
|
||||||
function useAdapter(name) {
|
function useAdapter(name) {
|
||||||
preview.adapter = new Adapter[name]();
|
preview.adapter = new Adapter[name]();
|
||||||
|
|
BIN
public/outfits/000/19/medium_thumb.png
Normal file
After Width: | Height: | Size: 121 KiB |
BIN
public/outfits/000/19/small_thumb.png
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
public/outfits/000/19/thumb.png
Normal file
After Width: | Height: | Size: 299 KiB |