From 374c7e61477cfccbf7cd02d0491f743ba1833002 Mon Sep 17 00:00:00 2001 From: Matchu Date: Thu, 26 Jul 2012 23:47:22 -0400 Subject: [PATCH] Sharing now fully supports saved outfits, not just shared ones --- app/controllers/outfits_controller.rb | 2 +- app/models/outfit.rb | 11 +- app/stylesheets/outfits/_edit.sass | 12 +- ...725232903_add_image_enqueued_to_outfits.rb | 9 + db/schema.rb | 3 +- public/javascripts/outfits/edit.js | 272 +++++++------- public/javascripts/outfits/show.js | 2 +- public/javascripts/wardrobe.js | 354 +++++++++++------- public/stylesheets/compiled/screen.css | 108 +++--- 9 files changed, 456 insertions(+), 317 deletions(-) create mode 100644 db/migrate/20120725232903_add_image_enqueued_to_outfits.rb diff --git a/app/controllers/outfits_controller.rb b/app/controllers/outfits_controller.rb index e4236f5b..bc7a5e69 100644 --- a/app/controllers/outfits_controller.rb +++ b/app/controllers/outfits_controller.rb @@ -75,7 +75,7 @@ class OutfitsController < ApplicationController def update if @outfit.update_attributes(params[:outfit]) - render :json => true + render :json => @outfit else render_outfit_errors end diff --git a/app/models/outfit.rb b/app/models/outfit.rb index c7d6866a..f2930254 100644 --- a/app/models/outfit.rb +++ b/app/models/outfit.rb @@ -15,12 +15,13 @@ class Outfit < ActiveRecord::Base mount_uploader :image, OutfitImageUploader + before_save :update_enqueued_image after_commit :enqueue_image! def as_json(more_options={}) serializable_hash :only => [:id, :name, :pet_state_id, :starred], :methods => [:color_id, :species_id, :worn_and_unworn_item_ids, - :image_versions] + :image_versions, :image_enqueued, :image_layers_hash] end def image_versions @@ -94,6 +95,7 @@ class Outfit < ActiveRecord::Base create_image! image self.image_layers_hash = generate_image_layers_hash self.image = image + self.image_enqueued = false save! end end @@ -104,7 +106,12 @@ class Outfit < ActiveRecord::Base # Enqueue an image write iff the new image would be different than the # current one. def enqueue_image! - Resque.enqueue(OutfitImageUpdate, id) if image_layers_dirty? + Resque.enqueue(OutfitImageUpdate, id) + end + + def update_enqueued_image + self.image_enqueued = (image_layers_dirty?) + true end def s3_key(size) diff --git a/app/stylesheets/outfits/_edit.sass b/app/stylesheets/outfits/_edit.sass index 643cbe71..05fffa86 100644 --- a/app/stylesheets/outfits/_edit.sass +++ b/app/stylesheets/outfits/_edit.sass @@ -573,11 +573,14 @@ body.outfits-edit display: block height: 150px margin: 1em auto 0 + position: relative width: 150px #preview-sharing-thumbnail-loading height: 100% - position: relative + left: 0 + position: absolute + top: 0 width: 100% span @@ -605,6 +608,13 @@ body.outfits-edit #preview-sharing-thumbnail display: block + + &.urls-loaded.thumbnail-available + #preview-sharing-thumbnail-loading + +opacity(0.85) + + #preview-sharing-thumbnail + display: block .preview-sidebar-nav float: right diff --git a/db/migrate/20120725232903_add_image_enqueued_to_outfits.rb b/db/migrate/20120725232903_add_image_enqueued_to_outfits.rb new file mode 100644 index 00000000..e7d3b59f --- /dev/null +++ b/db/migrate/20120725232903_add_image_enqueued_to_outfits.rb @@ -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 diff --git a/db/schema.rb b/db/schema.rb index 556128eb..38a662ba 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20120716193946) do +ActiveRecord::Schema.define(:version => 20120725232903) do create_table "auth_servers", :force => true do |t| t.string "short_name", :limit => 10, :null => false @@ -119,6 +119,7 @@ ActiveRecord::Schema.define(:version => 20120716193946) do t.boolean "starred", :default => false, :null => false t.string "image" t.string "image_layers_hash" + t.boolean "image_enqueued", :default => false, :null => false end add_index "outfits", ["pet_state_id"], :name => "index_outfits_on_pet_state_id" diff --git a/public/javascripts/outfits/edit.js b/public/javascripts/outfits/edit.js index 7aa3183e..446fac72 100644 --- a/public/javascripts/outfits/edit.js +++ b/public/javascripts/outfits/edit.js @@ -57,7 +57,7 @@ Partial.ItemSet = function ItemSet(wardrobe, selector) { var item, no_assets, li, no_assets_message; for(var i = 0, l = specific_items.length; i < l; 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); (function (li) { 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); } - setClosetItems(wardrobe.outfit.getClosetItems()); - setOutfitItems(wardrobe.outfit.getWornItems()); + setClosetItems(wardrobe.outfits.getClosetItems()); + setOutfitItems(wardrobe.outfits.getWornItems()); } $('span.no-assets-message').live('mouseover', function () { @@ -117,9 +117,9 @@ Partial.ItemSet = function ItemSet(wardrobe, selector) { no_assets_full_message.removeAttr('style'); }); - wardrobe.outfit.bind('updateItemAssets', function () { setHasAssets(wardrobe.outfit.getWornItems()) }); - wardrobe.outfit.bind('updateWornItems', setOutfitItems); - wardrobe.outfit.bind('updateClosetItems', setClosetItems); + wardrobe.outfits.bind('updateItemAssets', function () { setHasAssets(wardrobe.outfits.getWornItems()) }); + wardrobe.outfits.bind('updateWornItems', setOutfitItems); + wardrobe.outfits.bind('updateClosetItems', setClosetItems); } Partial.ItemSet.CONTROL_SETS = {}; @@ -151,12 +151,12 @@ Partial.ItemSet.setWardrobe = function (wardrobe) { } toggle_fn.closeted = {}; - toggle_fn.closeted[true] = $.proxy(wardrobe.outfit, 'closetItem'); - toggle_fn.closeted[false] = $.proxy(wardrobe.outfit, 'unclosetItem'); + toggle_fn.closeted[true] = $.proxy(wardrobe.outfits, 'closetItem'); + toggle_fn.closeted[false] = $.proxy(wardrobe.outfits, 'unclosetItem'); toggle_fn.worn = {}; - toggle_fn.worn[true] = $.proxy(wardrobe.outfit, 'wearItem'); - toggle_fn.worn[false] = $.proxy(wardrobe.outfit, 'unwearItem'); + toggle_fn.worn[true] = $.proxy(wardrobe.outfits, 'wearItem'); + toggle_fn.worn[false] = $.proxy(wardrobe.outfits, 'unwearItem'); Partial.ItemSet.setWardrobe = $.noop; } @@ -164,7 +164,7 @@ Partial.ItemSet.setWardrobe = function (wardrobe) { View.Closet = function (wardrobe) { 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) { @@ -281,32 +281,32 @@ View.Hash = function (wardrobe) { } 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(!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)) { - wardrobe.outfit.setClosetItemsByIds(new_data.objects.slice(0)); + wardrobe.outfits.setClosetItemsByIds(new_data.objects.slice(0)); } else { - wardrobe.outfit.setClosetItemsByIds([]); + wardrobe.outfits.setClosetItemsByIds([]); } if(new_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 { - wardrobe.outfit.setWornItemsByIds([]); + wardrobe.outfits.setWornItemsByIds([]); } if(new_data.name != data.name && new_data.name) { wardrobe.base_pet.setName(new_data.name); } if(new_data.state != data.state) { - wardrobe.outfit.setPetStateById(new_data.state); + wardrobe.outfits.setPetStateById(new_data.state); } 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) { wardrobe.search.setItemsByQuery(new_data.search, {offset: new_data.search_offset}); @@ -358,8 +358,8 @@ View.Hash = function (wardrobe) { } function singleOutfitResponse(event_name, response) { - wardrobe.outfit.bind(event_name, function () { - if(!wardrobe.outfit.in_transaction) response.apply(this, arguments); + wardrobe.outfits.bind(event_name, function () { + if(!wardrobe.outfits.in_transaction) response.apply(this, arguments); }); } @@ -378,7 +378,7 @@ View.Hash = function (wardrobe) { if(arraysMatch(item_ids, data.closet) || arraysMatch(item_ids, data.objects)) { changes.closet = undefined; } else { - changes.closet = wardrobe.outfit.getClosetItems().mapProperty('id'); + changes.closet = wardrobe.outfits.getClosetItems().mapProperty('id'); } if(changes.objects || changes.closet) changeQuery(changes); }); @@ -398,7 +398,7 @@ View.Hash = function (wardrobe) { }); 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])) { changeQuery({state: pet_state.id}); } @@ -410,7 +410,7 @@ View.Hash = function (wardrobe) { } }); - wardrobe.outfit.bind('loadOutfit', function (outfit) { + wardrobe.outfits.bind('loadOutfit', function (outfit) { changeQuery({ closet: outfit.getClosetItemIds(), color: outfit.pet_type.color_id, @@ -421,7 +421,7 @@ View.Hash = function (wardrobe) { }); }); - wardrobe.outfit.bind('outfitNotFound', function (outfit) { + wardrobe.outfits.bind('outfitNotFound', function (outfit) { var new_id = outfit ? outfit.id : undefined; changeQuery({outfit: new_id}); }); @@ -475,15 +475,18 @@ View.Outfits = function (wardrobe) { /* Nav */ function showCloset() { + sharing.onHide(); navigateTo(''); } function showOutfits() { - wardrobe.user.loadOutfits(); + sharing.onHide(); + wardrobe.outfits.loadOutfits(); navigateTo('viewing-outfits'); } function showSharing() { + sharing.onShow(); navigateTo('sharing'); } @@ -501,7 +504,7 @@ View.Outfits = function (wardrobe) { $('#preview-sidebar-navbar-closet').click(showCloset); $('#preview-sidebar-navbar-sharing').click(function () { sharing.startLoading(); - wardrobe.outfit.share(); + wardrobe.outfits.share(); showSharing(); }); $('#preview-sidebar-navbar-outfits').click(showOutfits); @@ -518,13 +521,13 @@ View.Outfits = function (wardrobe) { $('#outfit-template').template('outfitTemplate'); - wardrobe.user.bind('outfitsLoaded', function (outfits) { + wardrobe.outfits.bind('outfitsLoaded', function (outfits) { var outfit_els = $.tmpl('outfitTemplate', outfits); outfits_list_el.html('').append(outfit_els).addClass('loaded'); updateActiveOutfit(); }); - 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), outfit_el = $.tmpl('outfitTemplate', outfit); if(next_child.length) { @@ -536,13 +539,13 @@ View.Outfits = function (wardrobe) { outfit_el.hide().show('normal'); }); - 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); outfit_el.addClass('hiding').stop(true).hide('normal', function () { outfit_el.remove() }); }); $('#preview-outfits h4').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) { @@ -557,7 +560,7 @@ View.Outfits = function (wardrobe) { li = el.closest('li').removeClass('renaming'); if(new_name != outfit.name) { li.startLoading(); - wardrobe.user.renameOutfit(outfit, new_name); + wardrobe.outfits.renameOutfit(outfit, new_name); } } @@ -583,9 +586,9 @@ View.Outfits = function (wardrobe) { $('a.outfit-delete-confirmation-yes').live('click', function (e) { var outfit = $(this).tmplItem().data; e.preventDefault(); - wardrobe.user.destroyOutfit(outfit); - if(wardrobe.outfit.getOutfit().id == outfit.id) { - wardrobe.outfit.setId(null); + wardrobe.outfits.destroyOutfit(outfit); + if(wardrobe.outfits.getOutfit().id == outfit.id) { + wardrobe.outfits.setId(null); } }); @@ -597,7 +600,7 @@ View.Outfits = function (wardrobe) { stars.live('click', function () { var el = $(this); el.closest('li').startLoading(); - wardrobe.user.toggleOutfitStar(el.tmplItem().data); + wardrobe.outfits.toggleOutfitStar(el.tmplItem().data); }); function pathToUrl(path) { @@ -631,14 +634,14 @@ View.Outfits = function (wardrobe) { } function updateActiveOutfit() { - setActiveOutfit(wardrobe.outfit.getOutfit()); + setActiveOutfit(wardrobe.outfits.getOutfit()); } - wardrobe.outfit.bind('setOutfit', setActiveOutfit); - wardrobe.outfit.bind('outfitNotFound', setActiveOutfit); + wardrobe.outfits.bind('setOutfit', setActiveOutfit); + wardrobe.outfits.bind('outfitNotFound', setActiveOutfit); - wardrobe.user.bind('outfitRenamed', function (outfit) { - if(outfit.id == wardrobe.outfit.getId()) { + wardrobe.outfits.bind('outfitRenamed', function (outfit) { + if(outfit.id == wardrobe.outfits.getId()) { save_current_outfit_name_el.text(outfit.name); } }); @@ -654,6 +657,7 @@ View.Outfits = function (wardrobe) { 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: { @@ -691,13 +695,51 @@ View.Outfits = function (wardrobe) { formatUrls(); }); + var image_subscription = null; + function unsubscribeFromImage() { + if(image_subscription !== null) { + wardrobe.image_subscriptions.unsubscribe(image_subscription); + image_subscription = null; + } + } + + function subscribeToImage(outfit) { + image_subscription = wardrobe.image_subscriptions.subscribe(outfit); + } + + function subscribeToImageIfVisible() { + if(current_shared_outfit && sidebar_el.hasClass('sharing')) { + subscribeToImage(current_shared_outfit); + } + } + + var current_shared_outfit = {id: null}; this.setOutfit = function (outfit) { - 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); - thumbnail.setUrl(urls.small_image); - formatUrls(); + // 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(); + } WRAPPER.addClass('urls-loaded'); } @@ -705,6 +747,14 @@ View.Outfits = function (wardrobe) { WRAPPER.removeClass('urls-loaded'); } + this.onHide = function () { + unsubscribeFromImage(); + } + + this.onShow = function () { + subscribeToImageIfVisible(); + } + function formatUrls() { formatImageUrl('small_image'); formatImageUrl('medium_image'); @@ -723,69 +773,45 @@ View.Outfits = function (wardrobe) { function formatUrl(key, url) { sharing_url_els[key].val(url); } - - var thumbnail = new function SharingThumbnail() { - var IMAGE = $('#preview-sharing-thumbnail'); - var RETRY_DELAY = 2000; // 2 seconds - var url = null; - var xhr = null; + + wardrobe.image_subscriptions.bind('imageEnqueued', function (outfit) { + log("Sharing thumbnail enqueued for outfit", outfit); - function abort() { - if(xhr && xhr.readystate != 4) { - log("Aborting sharing thumbnail XHR"); - xhr.abort(); - } - } + WRAPPER.removeClass('thumbnail-loaded'); + }); + + wardrobe.image_subscriptions.bind('imageReady', function (outfit) { + log("Sharing thumbnail ready for outfit", outfit); - function hide() { - WRAPPER.removeClass('thumbnail-loaded'); + var src = outfit.image_versions.small + '?' + outfit.image_layers_hash; + thumbnail_el.attr('src', src); + WRAPPER.addClass('thumbnail-loaded'); + WRAPPER.addClass('thumbnail-available'); + image_subscription = null; + }); + + wardrobe.outfits.bind('updateSuccess', function (outfit) { + if(sidebar_el.hasClass('sharing')) { + subscribeToImage(outfit); } - - function load() { - log("Loading sharing thumbnail", url); - xhr = $.ajax({ - type: 'HEAD', - cache: false, // in case some browser tries to cache a 404 - url: url, - success: show, - error: retry - }); - } - - function retry() { - log("Sharing thumbnail not found, retry in", RETRY_DELAY); - setTimeout(load, RETRY_DELAY); - } - - function show() { - log("Sharing thumbnail found"); - IMAGE.attr('src', url); - WRAPPER.addClass('thumbnail-loaded'); - } - - this.setUrl = function (newUrl) { - if(newUrl != url) { - abort(); - hide(); - url = newUrl; - load(); - } else { - log("Sharing thumbnail URLs are identical; no change."); - } - } - } + }); + + wardrobe.outfits.bind('setOutfit', function (outfit) { + log("Sharing sees the setOutfit signal, and will set", outfit); + sharing.setOutfit(outfit); + }); } /* Saving */ save_current_outfit_el.click(function () { - wardrobe.outfit.update(); + wardrobe.outfits.update(); }); new_outfit_form_el.submit(function (e) { e.preventDefault(); 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()}); }); new_outfit_form_el.find('div.outfit-star').click(function () { @@ -803,20 +829,14 @@ View.Outfits = function (wardrobe) { save_error_el.text(text).notify(); } - wardrobe.outfit.bind('saveSuccess', function (outfit) { + wardrobe.outfits.bind('saveSuccess', function (outfit) { save_success_el.notify(); - sharing.setOutfit(outfit); }); - wardrobe.outfit.bind('createSuccess', function (outfit) { - wardrobe.user.addOutfit(outfit); + wardrobe.outfits.bind('createSuccess', function (outfit) { showOutfits(); hideNewOutfitForm(); }); - - wardrobe.outfit.bind('updateSuccess', function (outfit) { - wardrobe.user.updateOutfit(outfit); - }); function shareComplete(outfit) { save_outfit_wrapper_el.stopLoading().addClass('shared-outfit'); @@ -824,16 +844,16 @@ View.Outfits = function (wardrobe) { showSharing(); } - wardrobe.outfit.bind('shareSuccess', shareComplete); - wardrobe.outfit.bind('shareSkipped', shareComplete); + wardrobe.outfits.bind('shareSuccess', shareComplete); + wardrobe.outfits.bind('shareSkipped', shareComplete); function clearSharedOutfit() { save_outfit_wrapper_el.removeClass('shared-outfit'); } - wardrobe.outfit.bind('updateClosetItems', clearSharedOutfit); - wardrobe.outfit.bind('updateWornItems', clearSharedOutfit); - wardrobe.outfit.bind('updatePetState', clearSharedOutfit); + wardrobe.outfits.bind('updateClosetItems', clearSharedOutfit); + wardrobe.outfits.bind('updateWornItems', clearSharedOutfit); + wardrobe.outfits.bind('updatePetState', clearSharedOutfit); function saveFailure(outfit, response) { var errors = response.errors; @@ -856,16 +876,16 @@ View.Outfits = function (wardrobe) { liForOutfit(outfit).stopLoading(); } - wardrobe.outfit.bind('saveFailure', saveFailure); - wardrobe.user.bind('saveFailure', saveFailure) - wardrobe.outfit.bind('shareFailure', function (outfit, response) { + wardrobe.outfits.bind('saveFailure', saveFailure); + wardrobe.outfits.bind('saveFailure', saveFailure) + wardrobe.outfits.bind('shareFailure', function (outfit, response) { save_outfit_wrapper_el.stopLoading(); saveFailure(outfit, response); }); /* Error */ - wardrobe.outfit.bind('outfitNotFound', function () { + wardrobe.outfits.bind('outfitNotFound', function () { outfit_not_found_el.notify(); }); } @@ -877,7 +897,7 @@ View.PetStateForm = function (wardrobe) { button_query = form_query + ' button'; $(button_query).live('click', function (e) { e.preventDefault(); - wardrobe.outfit.setPetStateById(+$(this).data('value')); + wardrobe.outfits.setPetStateById(+$(this).data('value')); }); function updatePetState(pet_state) { @@ -887,7 +907,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; ul.children().remove(); if(ids.length == 1) { @@ -905,18 +925,18 @@ View.PetStateForm = function (wardrobe) { button.appendTo(li); 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) { var form = $('#pet-type-form'), dropdowns = {}, loaded = false; form.submit(function (e) { e.preventDefault(); - wardrobe.outfit.setPetTypeByColorAndSpecies( + wardrobe.outfits.setPetTypeByColorAndSpecies( +dropdowns.color.val(), +dropdowns.species.val() ); }).children('select').each(function () { @@ -947,12 +967,12 @@ View.PetTypeForm = function (wardrobe) { }); }); 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'); }); } @@ -1009,7 +1029,7 @@ View.ReportBrokenImage = function (wardrobe) { var baseURL = link.attr('data-base-url'); function updateLink() { - var assets = wardrobe.outfit.getVisibleAssets(); + var assets = wardrobe.outfits.getVisibleAssets(); var url = baseURL + "?"; for(var i = 0; i < assets.length; i++) { @@ -1020,9 +1040,9 @@ View.ReportBrokenImage = function (wardrobe) { link.attr('href', url); } - wardrobe.outfit.bind('updateWornItems', updateLink); - wardrobe.outfit.bind('updateItemAssets', updateLink); - wardrobe.outfit.bind('updatePetState', updateLink); + wardrobe.outfits.bind('updateWornItems', updateLink); + wardrobe.outfits.bind('updateItemAssets', updateLink); + wardrobe.outfits.bind('updatePetState', updateLink); } View.Search = function (wardrobe) { diff --git a/public/javascripts/outfits/show.js b/public/javascripts/outfits/show.js index 99e081e7..16b0e728 100644 --- a/public/javascripts/outfits/show.js +++ b/public/javascripts/outfits/show.js @@ -7,4 +7,4 @@ var main_wardrobe = new Wardrobe(), View = Wardrobe.getStandardView({ }); main_wardrobe.registerViews(View); main_wardrobe.initialize(); -main_wardrobe.outfit.loadData(INITIAL_OUTFIT_DATA); +main_wardrobe.outfits.loadData(INITIAL_OUTFIT_DATA); diff --git a/public/javascripts/wardrobe.js b/public/javascripts/wardrobe.js index e13f86f1..4c9a77fe 100644 --- a/public/javascripts/wardrobe.js +++ b/public/javascripts/wardrobe.js @@ -275,17 +275,23 @@ function Wardrobe() { worn_item_ids = new_ids.worn; closet_item_ids = new_ids.unworn.concat(new_ids.worn); } + + function loadAttributes(data) { + outfit.color_id = data.color_id; + outfit.id = data.id; + outfit.name = data.name; + outfit.pet_state_id = data.pet_state_id; + outfit.starred = data.starred; + outfit.species_id = data.species_id; + 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; + } if(typeof data != 'undefined') { - this.color_id = data.color_id; - this.id = data.id; - this.name = data.name; - this.pet_state_id = data.pet_state_id; - this.starred = data.starred; - this.species_id = data.species_id; - this.image_versions = data.image_versions; - this.setWornAndUnwornItemIds(data.worn_and_unworn_item_ids); - new_record = false; + loadAttributes(data); } this.closet_items = []; @@ -378,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) { if(!hasItemInCloset(item)) { this.closet_items.push(item); @@ -539,6 +528,9 @@ function Wardrobe() { new_outfit.id = outfit.id; new_outfit.name = outfit.name; 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; } @@ -556,6 +548,13 @@ function Wardrobe() { new_ids.unworn = base_ids.unworn.slice(0); 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) { $.ajax({ @@ -574,8 +573,7 @@ function Wardrobe() { dataType: 'json', success: function (data) { new_record = false; - outfit.id = data.id; - outfit.image_versions = data.image_versions; + updateFromSaveResponse(data); Outfit.cache[outfit.id] = outfit; success(outfit); }, @@ -584,6 +582,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) { var outfit_data = {}; @@ -602,19 +626,23 @@ function Wardrobe() { if(typeof Outfit.cache[id] !== 'undefined') { callback(Outfit.cache[id]); } else { - $.ajax({ - url: '/outfits/' + id + '.json', - success: function (data) { - var outfit = new Outfit(data); - Outfit.cache[id] = outfit; - callback(outfit); - }, - error: function () { - callback(null); - } - }); + Outfit.load(id, callback); } } + + 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) { var outfits = []; @@ -807,7 +835,12 @@ function Wardrobe() { Controller.all = {}; - Controller.all.Outfit = function OutfitController() { + Controller.all.Outfits = function OutfitsController() { + // 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; @@ -881,6 +914,7 @@ function Wardrobe() { } outfit.create( function (outfit) { + insertOutfit(outfit); controller.events.trigger('saveSuccess', outfit); controller.events.trigger('createSuccess', outfit); controller.events.trigger('setOutfit', outfit); @@ -974,6 +1008,7 @@ function Wardrobe() { this.update = function () { outfit.update( function (outfit) { + updateUserOutfit(outfit); controller.events.trigger('saveSuccess', outfit), controller.events.trigger('updateSuccess', outfit) }, @@ -989,6 +1024,139 @@ function Wardrobe() { 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) { + 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) }, DELAY); + } else { + controller.unsubscribe(outfit); + controller.events.trigger('imageReady', outfit); + } + } else { + log("Outfit was unsubscribed", outfit); + delete outfitSubscriptionTotals[outfit.id]; + } + }); + } + + this.subscribe = function (outfit) { + if(!(outfit.id in outfitSubscriptionTotals)) { + outfitSubscriptionTotals[outfit.id] = 0; + } + outfitSubscriptionTotals[outfit.id] += 1; + + if(outfit.image_enqueued) { + // If the image is enqueued, trigger that event and start checking. + controller.events.trigger('imageEnqueued', outfit); + checkSubscription(outfit); + return outfit; + } else { + // Otherwise, never bother checking: skip straight to the ready phase. + controller.events.trigger('imageReady', outfit); + return null; + } + } + + this.unsubscribe = function (outfit) { + outfitSubscriptionTotals[outfit.id] -= 1; + } } Controller.all.BasePet = function BasePetController() { @@ -1059,96 +1227,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; for(var name in Controller.all) { @@ -1227,13 +1305,13 @@ Wardrobe.getStandardView = function (options) { var outfit_events = ['updateWornItems', 'updateClosetItems', 'updateItemAssets', 'updatePetType', 'updatePetState']; for(var i = 0; i < outfit_events.length; i++) { (function (event) { - wardrobe.outfit.bind(event, function (obj) { + wardrobe.outfits.bind(event, function (obj) { log(event, obj); }); })(outfit_events[i]); } - wardrobe.outfit.bind('petTypeNotFound', function (pet_type) { + wardrobe.outfits.bind('petTypeNotFound', function (pet_type) { log(pet_type.toString() + ' not found'); }); } @@ -1277,7 +1355,7 @@ Wardrobe.getStandardView = function (options) { var assets, assets_for_swf; if(update_pending_flash) return false; if(preview_swf && preview_swf.setAssets) { - assets = wardrobe.outfit.getVisibleAssets(); + assets = wardrobe.outfits.getVisibleAssets(); preview_swf.setAssets(assets); } else { update_pending_flash = true; @@ -1334,7 +1412,7 @@ Wardrobe.getStandardView = function (options) { // Get a copy of the visible assets, then sort them in ascending zone // order. - var assets = wardrobe.outfit.getVisibleAssets().slice(0); + var assets = wardrobe.outfits.getVisibleAssets().slice(0); assets.sort(function (a, b) { return a.depth - b.depth; }); @@ -1348,7 +1426,7 @@ Wardrobe.getStandardView = function (options) { } this.updateAssets = function () { - var assets = wardrobe.outfit.getVisibleAssets(), asset, + var assets = wardrobe.outfits.getVisibleAssets(), asset, availableAssets = []; pendingAssets = {}; pendingAssetsCount = 0; @@ -1507,9 +1585,9 @@ Wardrobe.getStandardView = function (options) { preview.adapter.updateAssets(); } - wardrobe.outfit.bind('updateWornItems', updateAssets); - wardrobe.outfit.bind('updateItemAssets', updateAssets); - wardrobe.outfit.bind('updatePetState', updateAssets); + wardrobe.outfits.bind('updateWornItems', updateAssets); + wardrobe.outfits.bind('updateItemAssets', updateAssets); + wardrobe.outfits.bind('updatePetState', updateAssets); function useAdapter(name) { preview.adapter = new Adapter[name](); diff --git a/public/stylesheets/compiled/screen.css b/public/stylesheets/compiled/screen.css index f2397114..9e3bd9ce 100644 --- a/public/stylesheets/compiled/screen.css +++ b/public/stylesheets/compiled/screen.css @@ -3085,15 +3085,18 @@ body.outfits-edit #preview-sharing #preview-sharing-thumbnail-wrapper { display: block; height: 150px; margin: 1em auto 0; + position: relative; width: 150px; } -/* line 578, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 579, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #preview-sharing #preview-sharing-thumbnail-loading { height: 100%; - position: relative; + left: 0; + position: absolute; + top: 0; width: 100%; } -/* line 583, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 586, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #preview-sharing #preview-sharing-thumbnail-loading span { color: #448844; font-size: 85%; @@ -3103,52 +3106,63 @@ body.outfits-edit #preview-sharing #preview-sharing-thumbnail-loading span { top: 50%; width: 100%; } -/* line 592, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 595, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #preview-sharing #preview-sharing-thumbnail, body.outfits-edit #preview-sharing #preview-sharing-thumbnail-generating { display: none; } -/* line 596, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 599, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #preview-sharing.urls-loaded #preview-sharing-thumbnail-saving { display: none; } -/* line 599, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 602, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #preview-sharing.urls-loaded #preview-sharing-urls, body.outfits-edit #preview-sharing.urls-loaded #preview-sharing-url-formats, body.outfits-edit #preview-sharing.urls-loaded #preview-sharing-thumbnail-generating { display: block; } -/* line 603, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 606, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #preview-sharing.urls-loaded.thumbnail-loaded #preview-sharing-thumbnail-loading { display: none; } -/* line 606, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 609, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #preview-sharing.urls-loaded.thumbnail-loaded #preview-sharing-thumbnail { display: block; } -/* line 609, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 613, ../../../app/stylesheets/outfits/_edit.sass */ +body.outfits-edit #preview-sharing.urls-loaded.thumbnail-available #preview-sharing-thumbnail-loading { + -moz-opacity: 0.85; + -webkit-opacity: 0.85; + -o-opacity: 0.85; + -khtml-opacity: 0.85; +} +/* line 616, ../../../app/stylesheets/outfits/_edit.sass */ +body.outfits-edit #preview-sharing.urls-loaded.thumbnail-available #preview-sharing-thumbnail { + display: block; +} +/* line 619, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit .preview-sidebar-nav { float: right; font-size: 85%; margin-right: 24px; margin-top: 1em; } -/* line 621, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 631, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #preview-sidebar #preview-sidebar-navbar-closet { background: white; border-bottom-color: white; font-weight: bold; } -/* line 625, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 635, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #preview-sidebar.viewing-outfits #preview-sidebar-navbar-closet, body.outfits-edit #preview-sidebar.sharing #preview-sidebar-navbar-closet { background: transparent; border-bottom: 1px solid #aaddaa; font-weight: normal; } -/* line 628, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 638, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #preview-sidebar.viewing-outfits #preview-sidebar-navbar-outfits, body.outfits-edit #preview-sidebar.sharing #preview-sidebar-navbar-sharing { background: white; border-bottom-color: white; font-weight: bold; } -/* line 631, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 641, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #preview-sidebar-navbar { -moz-border-radius: 10px 10px 0 0; -webkit-border-radius: 10px 10px 0 0; @@ -3168,7 +3182,7 @@ body.outfits-edit #preview-sidebar-navbar { body.outfits-edit #preview-sidebar-navbar { display: block; } -/* line 640, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 650, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #preview-sidebar-navbar > div { background: transparent; border-bottom: 1px solid #aaddaa; @@ -3180,11 +3194,11 @@ body.outfits-edit #preview-sidebar-navbar > div { text-align: center; width: 132px; } -/* line 649, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 659, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #preview-sidebar-navbar > div:first-child { border-left: 0; } -/* line 652, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 662, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #preview-sidebar-content { -moz-border-radius: 0 0 10px 10px; -webkit-border-radius: 0 0 10px 10px; @@ -3196,7 +3210,7 @@ body.outfits-edit #preview-sidebar-content { border-top: 0; overflow: auto; } -/* line 658, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 668, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #save-success, body.outfits-edit #save-error, body.outfits-edit #outfit-not-found, body.outfits-edit #preview-sidebar-donation-request { margin-left: 24px; margin-right: 24px; @@ -3204,7 +3218,7 @@ body.outfits-edit #save-success, body.outfits-edit #save-error, body.outfits-edi margin-top: 1em; text-align: center; } -/* line 665, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 675, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #preview-sidebar-donation-request { background: #e6efc2; border: 1px solid #c6d880; @@ -3212,23 +3226,23 @@ body.outfits-edit #preview-sidebar-donation-request { font-size: 85%; padding: 1em; } -/* line 670, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 680, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #preview-sidebar-donation-request-no-thanks { margin-left: 1em; } -/* line 673, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 683, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #save-success { background: #e6efc2; border: 1px solid #c6d880; color: #264409; } -/* line 676, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 686, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #save-error, body.outfits-edit #outfit-not-found { background: #fbe3e4; border: 1px solid #fbc2c4; color: #8a1f11; } -/* line 679, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 689, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #userbar-message { -moz-opacity: 0.5; -webkit-opacity: 0.5; @@ -3236,7 +3250,7 @@ body.outfits-edit #userbar-message { -khtml-opacity: 0.5; display: none; } -/* line 683, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 693, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #new-outfit { padding: 0.25em 0; margin-left: 24px; @@ -3422,28 +3436,28 @@ body.outfits-edit #new-outfit.renaming:hover .outfit-rename-button { body.outfits-edit #new-outfit:hover .outfit-rename-button { display: inline; } -/* line 687, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 697, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #new-outfit h4 { display: inline; } -/* line 689, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 699, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #new-outfit h4:hover { text-decoration: none; } -/* line 691, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 701, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #new-outfit .outfit-star { margin-top: 0.5em; } -/* line 694, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 704, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #new-outfit-name { font: inherit; line-height: 1; } -/* line 698, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 708, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #pet-type-form, body.outfits-edit #pet-state-form, body.outfits-edit #preview-swf, body.outfits-edit #preview-search-form { position: relative; } -/* line 701, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 711, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit .control-overlay { height: 100%; left: 0; @@ -3452,11 +3466,11 @@ body.outfits-edit .control-overlay { width: 100%; z-index: 5; } -/* line 709, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 719, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #preview-sidebar-nav-outfits, body.outfits-edit #save-outfit-signed-in { display: none; } -/* line 712, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 722, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit form#save-outfit-form { padding: 0.25em 0; display: none; @@ -3642,7 +3656,7 @@ body.outfits-edit form#save-outfit-form.renaming:hover .outfit-rename-button { body.outfits-edit form#save-outfit-form:hover .outfit-rename-button { display: inline; } -/* line 718, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 728, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit form#save-outfit-form .outfit-star, body.outfits-edit form#save-outfit-form input, body.outfits-edit form#save-outfit-form button { display: -moz-inline-box; -moz-box-orient: vertical; @@ -3656,46 +3670,46 @@ body.outfits-edit form#save-outfit-form .outfit-star, body.outfits-edit form#sav body.outfits-edit form#save-outfit-form .outfit-star, body.outfits-edit form#save-outfit-form input, body.outfits-edit form#save-outfit-form button { *display: inline; } -/* line 723, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 733, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit form#save-outfit-form .outfit-star { margin-top: 0.25em; } -/* line 726, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 736, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit .outfit-url { font-size: 75%; } -/* line 729, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 739, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #preview-search-form-error { background: #fbe3e4; border: 1px solid #fbc2c4; color: #8a1f11; padding: 0.25em 0.5em; } -/* line 734, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 744, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit.user-signed-in #preview-sidebar-nav-outfits { display: block; } -/* line 736, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 746, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit.user-signed-in #save-outfit { display: inline-block; } -/* line 740, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 750, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit.user-signed-in #save-outfit-wrapper.active-outfit #save-outfit { display: none; } -/* line 742, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 752, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit.user-signed-in #save-outfit-wrapper.active-outfit #save-current-outfit, body.outfits-edit.user-signed-in #save-outfit-wrapper.active-outfit #save-outfit-copy { display: inline-block; } -/* line 750, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 760, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit.user-signed-in #save-outfit-wrapper.saving-outfit #save-outfit-form { display: block; } -/* line 752, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 762, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit.user-signed-in #save-outfit-wrapper.saving-outfit #save-outfit, body.outfits-edit.user-signed-in #save-outfit-wrapper.saving-outfit #save-current-outfit, body.outfits-edit.user-signed-in #save-outfit-wrapper.saving-outfit #save-outfit-copy, body.outfits-edit.user-signed-in #save-outfit-wrapper.saving-outfit #current-outfit-permalink, body.outfits-edit.user-signed-in #save-outfit-wrapper.saving-outfit #shared-outfit-permalink, body.outfits-edit.user-signed-in #save-outfit-wrapper.saving-outfit #share-outfit, body.outfits-edit.user-signed-in #save-outfit-wrapper.saving-outfit #shared-outfit-url { display: none; } -/* line 754, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 764, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit.user-signed-in .preview-search-form-your-items { display: -moz-inline-box; -moz-box-orient: vertical; @@ -3707,23 +3721,23 @@ body.outfits-edit.user-signed-in .preview-search-form-your-items { body.outfits-edit.user-signed-in .preview-search-form-your-items { *display: inline; } -/* line 756, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 766, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit.user-signed-in #preview-outfits-not-logged-in { display: none; } -/* line 758, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 768, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit.user-signed-in #preview-outfits-list { display: block; } -/* line 762, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 772, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit.user-not-signed-in #save-outfit-not-signed-in { display: inline-block; } -/* line 766, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 776, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #save-outfit-wrapper.shared-outfit #shared-outfit-permalink, body.outfits-edit #save-outfit-wrapper.shared-outfit #shared-outfit-url { display: inline-block; } -/* line 768, ../../../app/stylesheets/outfits/_edit.sass */ +/* line 778, ../../../app/stylesheets/outfits/_edit.sass */ body.outfits-edit #save-outfit-wrapper.shared-outfit #current-outfit-permalink { display: none !important; }