impress/public/javascripts/outfits/edit.js
Matchu 4dd2bc9549 fix some outfits list bugs
I think I got the 0-width bug where the outfit never expands beyond
0px width, and there were also some issues with the fact that
image subscriptions pointed to the current outfit object, even
after that object had changed identity, so now we re-fetch from
the cache by ID.
2012-07-31 11:14:32 -04:00

1372 lines
44 KiB
JavaScript

$.fn.notify = function () {
return this.stop(true, true).show('slow').delay(5000).hide('fast');
}
$.fn.startLoading = function () {
return this.delay(1000).queue(function (next) {
$(this).addClass('loading');
next();
});
}
$.fn.stopLoading = function () {
return this.removeClass('loading').clearQueue();
}
var Partial = {}, main_wardrobe,
View = Wardrobe.getStandardView({
Preview: {
swf_url: '/swfs/preview.swf?v=0.12',
wrapper: $('#preview-swf'),
placeholder: $('#preview-swf-container'),
image_container: '#preview-image-container'
}
});
Partial.ItemSet = function ItemSet(wardrobe, selector) {
var item_set = this, ul = $(selector), items = [], setClosetItems,
setOutfitItems, setOutfitItemsControls, no_assets_full_message = $('#no-assets-full-message'),
container = $('#container');
Partial.ItemSet.setWardrobe(wardrobe);
function prepSetSpecificItems(type) {
return function (specific_items) {
var item, worn, li;
for(var i = 0; i < items.length; i++) {
item = items[i];
in_set = $.inArray(item, specific_items) != -1;
li = $('li.object-' + item.id).toggleClass(type, in_set).
data('item', item).data(type, in_set).children('ul').
children('li.control-set-for-' + type).remove().end()
[type == 'worn' ? 'prepend' : 'append']
(Partial.ItemSet.CONTROL_SETS[type][in_set].clone());
}
}
}
setClosetItems = prepSetSpecificItems('closeted');
setOutfitItemsControls = prepSetSpecificItems('worn');
setOutfitItems = function (specific_items) {
setOutfitItemsControls(specific_items);
setHasAssets(specific_items);
}
function setHasAssets(specific_items) {
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.outfits.getPetType());
li = $('li.object-' + item.id).toggleClass('no-assets', no_assets);
(function (li) {
no_assets_message = li.find('span.no-assets-message');
no_assets_message.remove();
if(no_assets) {
$('<span/>', {'class': 'no-assets-message', text: 'No data yet'}).appendTo(li);
}
})(li);
}
}
this.setItems = function (new_items) {
var item, li, controls, info_link;
items = new_items;
ul.children().remove();
for(var i = 0; i < items.length; i++) {
item = items[i];
li = $('<li/>', {'class': 'object object-' + item.id});
img = $('<img/>', {
'src': item.thumbnail_url,
'alt': item.description,
'title': item.description
});
controls = $('<ul/>');
info_link = $('<a/>', {
'class': 'object-info',
html: '<span>i</span>',
href: item.getURL(),
target: '_blank'
});
if(
typeof item.rarity_index != 'undefined' &&
(item.rarity_index == 500 || item.rarity_index == 0)
) {
$('<div/>', {'class': 'nc-icon', text: 'NC', title: 'NC'}).appendTo(li);
}
if(item.owned || item.wanted) {
var iconsWrapper = $('<div/>', {'class': 'closeted-icons'}).appendTo(li);
if(item.owned) {
$('<img/>', {alt: 'Own', title: 'You own this', src: '/images/owned.png'}).appendTo(iconsWrapper);
$('<img/>', {alt: 'Want', title: 'You want this', src: '/images/wanted.png'}).appendTo(iconsWrapper);
}
}
li.append(img).append(controls).append(info_link).append(item.name).appendTo(ul);
}
setClosetItems(wardrobe.outfits.getClosetItems());
setOutfitItems(wardrobe.outfits.getWornItems());
}
$('span.no-assets-message').live('mouseover', function () {
var el = $(this), o = el.offset();
no_assets_full_message.css({
left: o.left + (el.width() / 2) - (no_assets_full_message.width() / 2) - container.offset().left,
top: o.top + el.height() + 10
});
}).live('mouseout', function () {
no_assets_full_message.removeAttr('style');
});
wardrobe.outfits.bind('updateItemAssets', function () { setHasAssets(wardrobe.outfits.getWornItems()) });
wardrobe.outfits.bind('updateWornItems', setOutfitItems);
wardrobe.outfits.bind('updateClosetItems', setClosetItems);
}
Partial.ItemSet.CONTROL_SETS = {};
Partial.ItemSet.setWardrobe = function (wardrobe) {
var type, verb_set, toggle, live_class, full_class, toggle_fn = {};
for(var i = 0; i < 2; i++) {
type = i == 0 ? 'worn' : 'closeted';
verb_set = i == 0 ? ['Unwear', 'Wear'] : ['Uncloset', 'Closet'];
Partial.ItemSet.CONTROL_SETS[type] = {};
for(var j = 0; j < 2; j++) {
toggle = j == 0;
full_class = 'control-set control-set-for-' + type;
live_class = 'control-set-' + (toggle ? '' : 'not-') + type;
full_class += ' ' + live_class;
Partial.ItemSet.CONTROL_SETS[type][toggle] = $('<a/>', {
href: '#',
text: verb_set[toggle ? 0 : 1]
}).wrap('<li/>').parent().attr('class', full_class);
(function (type, toggle) {
$('li.' + live_class + ' a').live('click', function (e) {
var el = $(this), item = el.closest('.object').data('item');
toggle_fn[type][!toggle](item);
e.preventDefault();
});
})(type, toggle);
}
}
toggle_fn.closeted = {};
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.outfits, 'wearItem');
toggle_fn.worn[false] = $.proxy(wardrobe.outfits, 'unwearItem');
Partial.ItemSet.setWardrobe = $.noop;
}
View.Closet = function (wardrobe) {
var item_set = new Partial.ItemSet(wardrobe, '#preview-closet ul');
wardrobe.outfits.bind('updateClosetItems', $.proxy(item_set, 'setItems'));
}
View.Fullscreen = function (wardrobe) {
var full = $(document.body).hasClass('fullscreen'), win = $(window),
preview_el = $('#preview'), search_el = $('#preview-search-form'),
preview_swf = $('#preview-swf'), sidebar_el = $('#preview-sidebar'),
sidebar_content_el = $('#preview-sidebar-content'),
sidebar_navbar_el = $('#preview-sidebar-navbar'), footer = $('#footer'),
jwindow = $(window), overrideFull = false;
function fit() {
if(!overrideFull) {
var newFull = jwindow.height() > 500;
if(newFull != full) {
full = newFull;
$(document.body).toggleClass('fullscreen', full);
if(!full) {
preview_swf.removeAttr('style').css('visibility', 'visible');
preview_el.removeAttr('style');
sidebar_content_el.removeAttr('style');
}
}
}
if(full) {
preview_swf = $('#preview-swf'); // swf replaced
var available = {
height: search_el.offset().top - preview_el.offset().top,
width: preview_el.innerWidth() - sidebar_el.outerWidth() - 12 // 12px margin
}, dim = {}, margin = {}, size = {
old: {height: preview_swf.height(), width: preview_swf.width()},
next: {}
}, offset;
if(available.height > available.width) {
dim.larger = 'height';
dim.smaller = 'width';
margin.active = 'marginTop';
margin.inactive = 'marginLeft';
} else {
dim.larger = 'width';
dim.smaller = 'height';
margin.active = 'marginLeft';
margin.inactive = 'marginTop';
}
size.next[dim.smaller] = available[dim.smaller];
size.next[dim.larger] = available[dim.smaller];
size.next[margin.active] = (available[dim.larger] - size.next[dim.larger]) / 2;
size.next[margin.inactive] = 0;
preview_swf.css(size.next);
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);
win.resize(fit).load(fit);
// run fit after search updates select fields
function fitSoon() { setTimeout(fit, 0) }
wardrobe.item_zone_sets.bind('update', fitSoon);
wardrobe.pet_attributes.bind('update', fitSoon);
fit();
}
View.Hash = function (wardrobe) {
var data = {}, proposed_data = {}, previous_query, parse_in_progress = false, TYPES = {
INTEGER: 1,
STRING: 2,
INTEGER_ARRAY: 3
}, KEYS = {
closet: TYPES.INTEGER_ARRAY,
color: TYPES.INTEGER,
name: TYPES.STRING,
objects: TYPES.INTEGER_ARRAY,
outfit: TYPES.INTEGER,
search: TYPES.STRING,
search_offset: TYPES.INTEGER,
species: TYPES.INTEGER,
state: TYPES.INTEGER
}, links_with_return_to = $('a[href*=return_to]');
function checkQuery() {
var query = (document.location.hash || document.location.search).substr(1);
if(query != previous_query) {
parseQuery(query);
previous_query = query;
}
}
function parseQuery(query) {
var new_data = {}, pairs = query.split('&');
parse_in_progress = true;
for(var i = 0; i < pairs.length; i++) {
var pair = pairs[i].split('='),
key = decodeURIComponent(pair[0]),
value = decodeURIComponent(pair[1]);
if(value) {
if(KEYS[key] == TYPES.INTEGER) {
new_data[key] = +value;
} else if(KEYS[key] == TYPES.STRING) {
new_data[key] = decodeURIComponent(value).replace(/\+/g, ' ');
} else if(key.substr(key.length-2) == '[]') {
key = key.substr(0, key.length-2);
if(KEYS[key] == TYPES.INTEGER_ARRAY) {
if(typeof new_data[key] == 'undefined') new_data[key] = [];
new_data[key].push(+value);
}
}
}
}
if(new_data.color !== data.color || new_data.species !== data.species) {
wardrobe.outfits.setPetTypeByColorAndSpecies(new_data.color, new_data.species);
}
if(new_data.closet) {
if(!arraysMatch(new_data.closet, data.closet)) {
wardrobe.outfits.setClosetItemsByIds(new_data.closet.slice(0));
}
} else if(new_data.objects && !arraysMatch(new_data.objects, data.closet)) {
wardrobe.outfits.setClosetItemsByIds(new_data.objects.slice(0));
} else {
wardrobe.outfits.setClosetItemsByIds([]);
}
if(new_data.objects) {
if(!arraysMatch(new_data.objects, data.objects)) {
wardrobe.outfits.setWornItemsByIds(new_data.objects.slice(0));
}
} else {
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.outfits.setPetStateById(new_data.state);
}
if(new_data.outfit != 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});
}
data = new_data;
parse_in_progress = false;
updateLinksWithReturnTo();
}
function changeQuery(changes) {
var value;
if(!parse_in_progress) {
for(var key in changes) {
if(changes.hasOwnProperty(key)) {
value = changes[key];
if(value === undefined) {
delete data[key];
} else {
data[key] = changes[key];
}
}
}
updateQuery();
}
}
function updateQuery() {
var new_query;
new_query = $.param(data).replace(/%5B%5D/g, '[]');
previous_query = new_query;
document.location.hash = '#' + new_query;
updateLinksWithReturnTo();
}
function updateLinksWithReturnTo() {
links_with_return_to.each(function () {
var new_return_to = 'return_to=' + encodeURIComponent(
document.location.pathname +
document.location.search +
document.location.hash
);
this.href = this.href.replace(/return_to=[^&]+/, new_return_to);
});
}
this.initialize = function () {
checkQuery();
setInterval(checkQuery, 100);
}
function singleOutfitResponse(event_name, response) {
wardrobe.outfits.bind(event_name, function () {
if(!wardrobe.outfits.in_transaction) response.apply(this, arguments);
});
}
singleOutfitResponse('updateClosetItems', function (items) {
var item_ids = items.mapProperty('id');
if(!arraysMatch(item_ids, data.closet)) {
changeQuery({closet: item_ids});
}
});
singleOutfitResponse('updateWornItems', function (items) {
var item_ids = items.mapProperty('id'), changes = {};
if(!arraysMatch(item_ids, data.objects)) {
changes.objects = item_ids;
}
if(arraysMatch(item_ids, data.closet) || arraysMatch(item_ids, data.objects)) {
changes.closet = undefined;
} else {
changes.closet = wardrobe.outfits.getClosetItems().mapProperty('id');
}
if(changes.objects || changes.closet) changeQuery(changes);
});
singleOutfitResponse('updatePetType', function (pet_type) {
if(pet_type.color_id != data.color || pet_type.species_id != data.species) {
changeQuery({
color: pet_type.color_id,
species: pet_type.species_id,
state: undefined
});
}
});
singleOutfitResponse('petTypeNotFound', function () {
window.history.back();
});
singleOutfitResponse('updatePetState', function (pet_state) {
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});
}
});
singleOutfitResponse('setOutfit', function (outfit) {
if(outfit.id != data.outfit) {
changeQuery({outfit: outfit.id});
}
});
wardrobe.outfits.bind('loadOutfit', function (outfit) {
changeQuery({
closet: outfit.getClosetItemIds(),
color: outfit.pet_type.color_id,
objects: outfit.getWornItemIds(),
outfit: outfit.id,
species: outfit.pet_type.species_id,
state: outfit.pet_state.id
});
});
wardrobe.outfits.bind('outfitNotFound', function (outfit) {
var new_id = outfit ? outfit.id : undefined;
changeQuery({outfit: new_id});
});
wardrobe.search.bind('updateRequest', function (request) {
if(request.offset != data.search_offset || request.query != data.search) {
changeQuery({
search_offset: request.offset,
search: request.query
});
}
});
}
View.Outfits = function (wardrobe) {
var current_outfit_permalink_el = $('#current-outfit-permalink'),
new_outfit_form_el = $('#save-outfit-form'),
new_outfit_name_el = $('#save-outfit-name'),
outfits_el = $('#preview-outfits'),
outfits_list_el = outfits_el.children('ul'),
outfit_not_found_el = $('#outfit-not-found'),
save_current_outfit_el = $('#save-current-outfit'),
save_current_outfit_name_el = save_current_outfit_el.children('span'),
save_outfit_wrapper_el = $('#save-outfit-wrapper'),
save_success_el = $('#save-success'),
save_error_el = $('#save-error'),
stars = $('#preview-outfits div.outfit-star'),
sidebar_el = $('#preview-sidebar'),
signed_in,
previously_viewing = '';
function liForOutfit(outfit) {
return $('li.outfit-' + outfit.id);
}
function navigateTo(will_be_viewing) {
var currently_viewing = sidebar_el.attr('class');
if(currently_viewing != will_be_viewing) previously_viewing = currently_viewing;
sidebar_el.attr('class', will_be_viewing);
}
/* Show for login */
signed_in = $('meta[name=user-signed-in]').attr('content') == 'true';
if(signed_in) {
$(document.body).addClass('user-signed-in');
} else {
$(document.body).addClass('user-not-signed-in');
}
/* Nav */
function showCloset() {
sharing.onHide();
navigateTo('');
}
function showOutfits() {
sharing.onHide();
wardrobe.outfits.loadOutfits();
navigateTo('viewing-outfits');
}
function showSharing() {
sharing.onShow();
navigateTo('sharing');
}
function showNewOutfitForm() {
new_outfit_name_el.val('');
new_outfit_form_el.removeClass('starred').stopLoading();
save_outfit_wrapper_el.addClass('saving-outfit');
new_outfit_name_el.focus();
}
function hideNewOutfitForm() {
save_outfit_wrapper_el.removeClass('saving-outfit');
}
$('#preview-sidebar-navbar-closet').click(showCloset);
$('#preview-sidebar-navbar-sharing').click(function () {
sharing.startLoading();
wardrobe.outfits.share();
showSharing();
});
$('#preview-sidebar-navbar-outfits').click(showOutfits);
$('#save-outfit, #save-outfit-copy').click(showNewOutfitForm);
$('#save-outfit-cancel').click(hideNewOutfitForm);
$('#save-outfit-not-signed-in').click(function () {
window.location.replace($('#userbar a').attr('href'));
});
/* 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');
wardrobe.outfits.bind('outfitsLoaded', function (outfits) {
var outfit_els = $.tmpl('outfitTemplate', outfits);
outfits_list_el.html('').append(outfit_els).addClass('loaded');
updateActiveOutfit();
for(var i = 0; i < outfits.length; i++) {
listSubscribeToImage(outfits[i]);
}
});
wardrobe.outfits.bind('addOutfit', function (outfit, i) {
var next_child = outfits_list_el.children().not('.hiding').eq(i),
outfit_el = $.tmpl('outfitTemplate', outfit.clone());
if(next_child.length) {
outfit_el.insertBefore(next_child);
} else {
outfit_el.appendTo(outfits_list_el);
}
updateActiveOutfit();
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.outfits.bind('removeOutfit', function (outfit, i) {
var outfit_el = outfits_list_el.children().not('.hiding').eq(i);
outfit_el.addClass('hiding').stop(true).animate({width: 0}, 'normal', function () { outfit_el.remove() });
listUnsubscribeFromImage(outfit);
});
$('#preview-outfits li header, #preview-outfits li .outfit-thumbnail-wrapper').live('click', function () {
wardrobe.outfits.load($(this).tmplItem().data.id);
});
$('a.outfit-rename-button').live('click', function (e) {
e.preventDefault();
var li = $(this).closest('li').addClass('renaming'),
name = li.find('span.outfit-name').text();
li.find('input.outfit-rename-field').val(name).focus();
});
function submitRename() {
var el = $(this), outfit = el.tmplItem().data, new_name = el.val(),
li = el.closest('li').removeClass('renaming');
if(new_name != outfit.name) {
li.startLoading();
wardrobe.outfits.renameOutfit(outfit, new_name);
}
}
$('input.outfit-rename-field').live('blur', submitRename);
$('form.outfit-rename-form').live('submit', function (e) {
e.preventDefault();
var input = $(this).find('input');
submitRename.apply(input);
});
$('input.outfit-url').live('mouseover', function () {
this.focus();
}).live('mouseout', function () {
this.blur();
});
$('a.outfit-delete').live('click', function (e) {
e.stopPropagation();
e.preventDefault();
$(this).closest('li').addClass('confirming-deletion');
});
$('a.outfit-delete-confirmation-yes').live('click', function (e) {
var outfit = $(this).tmplItem().data;
e.preventDefault();
wardrobe.outfits.destroyOutfit(outfit);
if(wardrobe.outfits.getOutfit().id == outfit.id) {
wardrobe.outfits.setId(null);
}
});
$('a.outfit-delete-confirmation-no').live('click', function (e) {
e.preventDefault();
$(this).closest('li').removeClass('confirming-deletion');
});
stars.live('click', function (e) {
e.stopPropagation();
var el = $(this);
el.closest('li').startLoading();
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) {
var url = generateOutfitPermalink(outfit);
outfit_permalink_el.attr('href', url);
if(outfit_url_el) outfit_url_el.val(url);
}
function setCurrentOutfitPermalink(outfit) {
setOutfitPermalink(outfit, current_outfit_permalink_el);
}
function setActiveOutfit(outfit) {
outfits_list_el.find('li.active').removeClass('active');
if(outfit.id) {
setCurrentOutfitPermalink(outfit);
liForOutfit(outfit).addClass('active');
save_current_outfit_name_el.text(outfit.name);
}
save_outfit_wrapper_el.toggleClass('active-outfit', outfit.id ? true : false);
}
function updateActiveOutfit() {
setActiveOutfit(wardrobe.outfits.getOutfit());
}
wardrobe.outfits.bind('setOutfit', setActiveOutfit);
wardrobe.outfits.bind('outfitNotFound', setActiveOutfit);
wardrobe.outfits.bind('outfitRenamed', function (outfit) {
if(outfit.id == wardrobe.outfits.getId()) {
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 */
save_current_outfit_el.click(function () {
wardrobe.outfits.update();
});
new_outfit_form_el.submit(function (e) {
e.preventDefault();
new_outfit_form_el.startLoading();
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 () {
new_outfit_form_el.toggleClass('starred');
});
var SAVE_ERRORS = {
'item_outfit_relationships': "Item not found. How odd. Pull some items out of your closet and try again.",
'pet_state': "Pet state not found. How odd. Try picking a new Gender/Emotion.",
'name': true,
'user': "You must be logged in to save outfits"
};
function saveErrorMessage(text) {
save_error_el.text(text).notify();
}
wardrobe.outfits.bind('saveSuccess', function (outfit) {
save_success_el.notify();
});
wardrobe.outfits.bind('createSuccess', function (outfit) {
showOutfits();
hideNewOutfitForm();
});
function shareComplete(outfit) {
save_outfit_wrapper_el.stopLoading().addClass('shared-outfit');
sharing.setOutfit(outfit);
showSharing();
}
wardrobe.outfits.bind('shareSuccess', shareComplete);
wardrobe.outfits.bind('shareSkipped', shareComplete);
function clearSharedOutfit() {
save_outfit_wrapper_el.removeClass('shared-outfit');
}
wardrobe.outfits.bind('updateClosetItems', clearSharedOutfit);
wardrobe.outfits.bind('updateWornItems', clearSharedOutfit);
wardrobe.outfits.bind('updatePetState', clearSharedOutfit);
function saveFailure(outfit, response) {
var errors = response.errors;
if(typeof errors == 'undefined') {
saveErrorMessage("Whoops! The save failed, but the server didn't say why. Please try again.");
} else {
for(var key in SAVE_ERRORS) {
if(SAVE_ERRORS.hasOwnProperty(key) && typeof errors[key] != 'undefined') {
var message = SAVE_ERRORS[key];
if(message === true) {
message = key.charAt(0).toUpperCase() + key.substr(1) + ' ' +
errors[key];
}
saveErrorMessage(message);
break;
}
}
}
new_outfit_form_el.stopLoading();
liForOutfit(outfit).stopLoading();
}
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.outfits.bind('outfitNotFound', function () {
outfit_not_found_el.notify();
});
}
View.PetStateForm = function (wardrobe) {
var INPUT_NAME = 'pet_state_id', form_query = '#pet-state-form',
form = $(form_query),
ul = form.children('ul'),
button_query = form_query + ' button';
$(button_query).live('click', function (e) {
e.preventDefault();
wardrobe.outfits.setPetStateById(+$(this).data('value'));
});
function updatePetState(pet_state) {
if(pet_state) {
ul.children('li.selected').removeClass('selected');
$(button_query + '[data-value=' + pet_state.id + ']').parent().addClass('selected');
}
}
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) {
form.addClass('hidden');
} else {
form.removeClass('hidden');
for(var i = 0; i < ids.length; i++) {
id = 'pet-state-button-' + i;
li = $('<li/>');
button = $('<button/>', {
id: id,
text: i + 1,
"data-value": ids[i]
});
button.appendTo(li);
li.appendTo(ul);
}
updatePetState(wardrobe.outfits.getPetState());
}
});
wardrobe.outfits.bind('updatePetState', updatePetState);
}
View.PetTypeForm = function (wardrobe) {
var form = $('#pet-type-form'), dropdowns = {}, loaded = false;
form.submit(function (e) {
e.preventDefault();
wardrobe.outfits.setPetTypeByColorAndSpecies(
+dropdowns.color.val(), +dropdowns.species.val()
);
}).children('select').each(function () {
dropdowns[this.name] = $(this);
});
this.initialize = function () {
wardrobe.pet_attributes.load();
}
function updatePetType(pet_type) {
if(loaded && pet_type) {
$.each(dropdowns, function (name) {
dropdowns[name].val(pet_type[name + '_id']);
});
}
}
wardrobe.pet_attributes.bind('update', function (attributes) {
$.each(attributes, function (type) {
var dropdown = dropdowns[type];
$.each(this, function () {
var option = $('<option/>', {
text: this.name,
value: this.id
});
option.appendTo(dropdown);
});
});
loaded = true;
updatePetType(wardrobe.outfits.getPetType());
});
wardrobe.outfits.bind('updatePetType', updatePetType);
wardrobe.outfits.bind('petTypeNotFound', function () {
$('#pet-type-not-found').show('normal').delay(3000).hide('fast');
});
}
View.PreviewAdapterForm = function (wardrobe) {
var preview = wardrobe.views.Preview;
var Konami=function(){var a={addEvent:function(b,c,d,e){if(b.addEventListener)b.addEventListener(c,d,false);else if(b.attachEvent){b["e"+c+d]=d;b[c+d]=function(){b["e"+c+d](window.event,e)};b.attachEvent("on"+c,b[c+d])}},input:"",pattern:"3838404037393739666513",load:function(b){this.addEvent(document,"keydown",function(c,d){if(d)a=d;a.input+=c?c.keyCode:event.keyCode;if(a.input.indexOf(a.pattern)!=-1){a.code(b);a.input=""}},this);this.iphone.load(b)},code:function(b){window.location=b},iphone:{start_x:0,start_y:0,stop_x:0,stop_y:0,tap:false,capture:false,keys:["UP","UP","DOWN","DOWN","LEFT","RIGHT","LEFT","RIGHT","TAP","TAP","TAP"],code:function(b){a.code(b)},load:function(b){a.addEvent(document,"touchmove",function(c){if(c.touches.length==1&&a.iphone.capture==true){c=c.touches[0];a.iphone.stop_x=c.pageX;a.iphone.stop_y=c.pageY;a.iphone.tap=false;a.iphone.capture=false;a.iphone.check_direction()}});a.addEvent(document,"touchend",function(){a.iphone.tap==true&&a.iphone.check_direction(b)},false);a.addEvent(document,"touchstart",function(c){a.iphone.start_x=c.changedTouches[0].pageX;a.iphone.start_y=c.changedTouches[0].pageY;a.iphone.tap=true;a.iphone.capture=true})},check_direction:function(b){x_magnitude=Math.abs(this.start_x-this.stop_x);y_magnitude=Math.abs(this.start_y-this.stop_y);x=this.start_x-this.stop_x<0?"RIGHT":"LEFT";y=this.start_y-this.stop_y<0?"DOWN":"UP";result=x_magnitude>y_magnitude?x:y;result=this.tap==true?"TAP":result;if(result==this.keys[0])this.keys=this.keys.slice(1,this.keys.length);this.keys.length==0&&this.code(b)}}};return a};
konami = new Konami();
konami.code = function () {
preview.toggleAdapter();
}
konami.load();
var modeWrapper = $('#preview-mode').addClass('flash-active');
var modeOptions = $('#preview-mode-toggle li');
function activate(el, modeOn, modeOff) {
modeWrapper.removeClass(modeOff + '-active').addClass(modeOn + '-active');
$(el).addClass('active');
}
var flashToggle = $('#preview-mode-flash').click(function () {
activate(this, 'flash', 'image');
preview.useSWFAdapter();
});
var imageToggle = $('#preview-mode-image').click(function () {
activate(this, 'image', 'flash');
preview.useImageAdapter();
});
if(preview.usingImageAdapter()) {
activate(imageToggle, 'image', 'flash');
}
var DOWNLOAD_SIZES = {
'small': [150, 150],
'medium': [300, 300],
'large': [600, 600]
};
$('#preview-download-image button').click(function () {
var size = DOWNLOAD_SIZES[this.getAttribute('data-download-size')];
preview.adapter.saveImage(size);
});
if(document.createElement('canvas').getContext) {
// If browser supports canvas
modeWrapper.addClass('can-download');
}
}
View.ReportBrokenImage = function (wardrobe) {
var link = $('#report-broken-image');
var baseURL = link.attr('data-base-url');
function updateLink() {
var assets = wardrobe.outfits.getVisibleAssets();
var url = baseURL + "?";
for(var i = 0; i < assets.length; i++) {
if(i > 0) url += "&";
url += "asset_ids[" + assets[i].type + "][]=" + assets[i].id;
}
link.attr('href', url);
}
wardrobe.outfits.bind('updateWornItems', updateLink);
wardrobe.outfits.bind('updateItemAssets', updateLink);
wardrobe.outfits.bind('updatePetState', updateLink);
}
View.Search = function (wardrobe) {
var form_selector = '#preview-search-form', form = $(form_selector),
item_set = new Partial.ItemSet(wardrobe, form_selector + ' ul'),
input_el = form.find('input[name=query]'),
clear_el = $('#preview-search-form-clear'),
error_el = $('#preview-search-form-error'),
help_el = $('#preview-search-form-help'),
loading_el = $('#preview-search-form-loading'),
no_results_el = $('#preview-search-form-no-results'),
no_results_span = no_results_el.children('span'),
your_items_links = $('.preview-search-form-your-items'),
PAGINATION = {
INNER_WINDOW: 4,
OUTER_WINDOW: 1,
GAP_TEXT: '&hellip;',
PREV_TEXT: '&larr; Previous',
NEXT_TEXT: 'Next &rarr;',
PAGE_EL: $('<a/>', {href: '#'}),
CURRENT_EL: $('<span/>', {'class': 'current'}),
EL_ID: '#preview-search-form-pagination',
PER_PAGE: 21
}, object_width = 112, last_request;
PAGINATION.EL = $(PAGINATION.EL_ID);
PAGINATION.GAP_EL = $('<span/>', {'class': 'gap', html: PAGINATION.GAP_TEXT})
PAGINATION.PREV_EL = $('<a/>', {href: '#', rel: 'prev', html: PAGINATION.PREV_TEXT});
PAGINATION.NEXT_EL = $('<a/>', {href: '#', rel: 'next', html: PAGINATION.NEXT_TEXT});
$(PAGINATION.EL_ID + ' a').live('click', function (e) {
e.preventDefault();
loadPage($(this).data('page'));
});
this.initialize = $.proxy(wardrobe.item_zone_sets, 'load');
wardrobe.search.setPerPage(PAGINATION.PER_PAGE);
function updatePerPage() {
var new_per_page = Math.floor(form.width() / object_width),
offset, new_page;
if(!$(document.body).hasClass('fullscreen')) new_per_page *= 4;
if(new_per_page != PAGINATION.PER_PAGE) {
PAGINATION.PER_PAGE = new_per_page;
wardrobe.search.setPerPage(PAGINATION.PER_PAGE);
if(last_request) {
loadOffset(last_request.offset);
}
}
}
$(window).resize(updatePerPage).load(updatePerPage);
updatePerPage();
function loadOffset(offset) {
wardrobe.search.setItemsByQuery(input_el.val(), {offset: offset});
}
function loadPage(page) {
wardrobe.search.setItemsByQuery(input_el.val(), {page: page});
}
function stopLoading() {
loading_el.stop(true, true).hide();
}
form.submit(function (e) {
e.preventDefault();
loadPage(1);
});
clear_el.click(function (e) {
e.preventDefault();
input_el.val('');
form.submit();
});
your_items_links.click(function (e) {
e.preventDefault();
input_el.val('user:' + this.getAttribute('data-search-value'));
form.submit();
});
wardrobe.search.bind('startRequest', function () {
loading_el.delay(1000).show('slow');
});
wardrobe.search.bind('updateItems', function (items) {
var fit = $('#preview').data('fit') || $.noop;
stopLoading();
item_set.setItems(items);
if(wardrobe.search.request.query) {
if(!items.length) {
no_results_el.show();
}
} else {
help_el.show();
}
form.toggleClass('has-results', items.length > 0);
fit();
});
wardrobe.search.bind('updateRequest', function (request) {
last_request = request;
error_el.hide('fast');
help_el.hide();
no_results_el.hide();
input_el.val(request.query || '');
no_results_span.text(request.query);
clear_el.toggle(!!request.query);
});
wardrobe.search.bind('updatePagination', function (current_page, total_pages) {
// ported from http://github.com/mislav/will_paginate/blob/master/lib/will_paginate/view_helpers.rb#L274
var window_from = current_page - PAGINATION.INNER_WINDOW,
window_to = current_page + PAGINATION.INNER_WINDOW,
visible = [], left_gap, right_gap, subtract_left, subtract_right,
i = 1;
if(window_to > total_pages) {
window_from -= window_to - total_pages;
window_to = total_pages;
}
if(window_from < 1) {
window_to += 1 - window_from;
window_from = 1;
if(window_to > total_pages) window_to = total_pages;
}
left_gap = [2 + PAGINATION.OUTER_WINDOW, window_from];
right_gap = [window_to + 1, total_pages - PAGINATION.OUTER_WINDOW];
subtract_left = (left_gap[1] - left_gap[0]) > 1;
subtract_right = (right_gap[1] - right_gap[0]) > 1;
PAGINATION.EL.children().remove();
if(current_page > 1) {
PAGINATION.PREV_EL.clone().data('page', current_page - 1).appendTo(PAGINATION.EL);
}
while(i <= total_pages) {
if(subtract_left && i >= left_gap[0] && i < left_gap[1]) {
PAGINATION.GAP_EL.clone().appendTo(PAGINATION.EL);
i = left_gap[1];
} else if(subtract_right && i >= right_gap[0] && i < right_gap[1]) {
PAGINATION.GAP_EL.clone().appendTo(PAGINATION.EL);
i = right_gap[1];
} else {
if(i == current_page) {
PAGINATION.CURRENT_EL.clone().text(i).appendTo(PAGINATION.EL);
} else {
PAGINATION.PAGE_EL.clone().text(i).data('page', i).appendTo(PAGINATION.EL);
}
i++;
}
}
if(current_page < total_pages) {
PAGINATION.NEXT_EL.clone().data('page', current_page + 1).appendTo(PAGINATION.EL);
}
});
wardrobe.search.bind('error', function (error) {
stopLoading();
error_el.text(error).show('normal');
});
help_el.find('dt').each(function () {
var el = $(this);
if(!el.children().length) {
el.wrapInner($('<a/>', {href: '#'}));
}
}).children('span:not(.search-helper)').each(function () {
var el = $(this);
el.replaceWith($('<a/>', {href: '#', text: el.text()}));
});
help_el.find('dt a').live('click', function (e) {
var el = $(this), siblings = el.parent().children(), query;
e.preventDefault();
if(siblings.length > 1) {
query = siblings.map(function () {
var el = $(this);
return el[el.is('select') ? 'val' : 'text']();
}).get().join('');
} else {
query = el.text();
}
input_el.val(query);
form.submit();
});
$('select.search-helper').live('change', function () {
var el = $(this), filter = el.attr('data-search-filter');
$('select.search-helper[data-search-filter=' + filter + ']').val(el.val());
});
function prepBuildHelper(type, getSet) {
return function (objs) {
var select = $('<select/>',
{'class': 'search-helper', 'data-search-filter': type}),
span = $('span.search-helper[data-search-filter=' + type + ']');
objs = getSet(objs);
for(var i = 0, l = objs.length; i < l; i++) {
$('<option/>', {text: objs[i].name}).appendTo(select);
}
span.replaceWith(function () {
return select.clone().fadeIn('fast');
});
}
}
function getSpecies(x) { return x.species }
wardrobe.item_zone_sets.bind('update', prepBuildHelper('type', function (x) {
return x;
}));
wardrobe.pet_attributes.bind('update', prepBuildHelper('species', getSpecies));
//wardrobe.pet_attributes.bind('update', prepBuildHelper('only', getSpecies));
}
View.Title = function (wardrobe) {
wardrobe.base_pet.bind('updateName', function (name) {
$('#title').text("Planning " + name + "'s outfit");
});
}
var userbar_sessions_link = $('#userbar a:last'),
userbar_message_verb = userbar_sessions_link.text() == 'Log out' ? 'logged out' : 'sent to the login page',
userbar_message_el = $('<span/>', {
id: 'userbar-message',
text: "You will be " + userbar_message_verb + ", then brought back to this exact outfit you've made."
}).prependTo('#userbar');
userbar_sessions_link.hover(function () {
userbar_message_el.stop().fadeTo('normal', .5);
}, function () {
userbar_message_el.stop().fadeOut('fast');
});
$.ajaxSetup({
error: function (xhr) {
$.jGrowl("There was an error loading that last resource. Oops. Please try again!");
}
});
main_wardrobe = new Wardrobe();
main_wardrobe.registerViews(View);
main_wardrobe.initialize();
var TIME_TO_DONATION_REQUEST_IN_MINUTES = 10;
var donationRequestEl = $('#preview-sidebar-donation-request');
donationRequestEl.find('a').click(function(e) {
donationRequestEl.slideUp(250);
var response = this.id == 'preview-sidebar-donation-request-no-thanks' ? 0 : 1;
if(!response) { // href is #
e.preventDefault();
}
var expiryDate = new Date();
expiryDate.setTime(expiryDate.getTime() + 7*24*60*60*1000); // one week from now
document.cookie = "previewSidebarDonationResponse=" + response + "; expires=" + expiryDate.toGMTString();
});
if(document.cookie.indexOf('previewSidebarDonationResponse') == -1) {
setTimeout(function () {
donationRequestEl.slideDown(1000);
}, TIME_TO_DONATION_REQUEST_IN_MINUTES * 60 * 1000);
}