diff --git a/app/assets/javascripts/modeling.js.jsx b/app/assets/javascripts/modeling.js.jsx
index 267f1e47..c8b0770d 100644
--- a/app/assets/javascripts/modeling.js.jsx
+++ b/app/assets/javascripts/modeling.js.jsx
@@ -54,11 +54,40 @@
}
};
+ var ImpressUser = (function() {
+ var userSignedIn = ($('meta[name=user-signed-in]').attr('content') === 'true');
+ if (userSignedIn) {
+ return {
+ // TODO
+ };
+ } else {
+ return {
+ _key: "guestNeopetsUsernames",
+ _setNeopetsUsernames: function(usernames) {
+ localStorage.setItem(this._key, JSON.stringify(usernames));
+ },
+ addNeopetsUsername: function(username) {
+ this._setNeopetsUsernames(this.getNeopetsUsernames().concat([username]));
+ },
+ removeNeopetsUsername: function(username) {
+ this._setNeopetsUsernames(this.getNeopetsUsernames().filter(function(u) {
+ return u !== username;
+ }));
+ },
+ getNeopetsUsernames: function() {
+ return JSON.parse(localStorage.getItem(this._key)) || [];
+ }
+ };
+ }
+ })();
+
var Modeling = {
_customizationsByPetId: {},
_customizations: [],
_itemsById: {},
_items: [],
+ _usersComponent: {setState: function() {}},
+ _neopetsUsernamesPresenceMap: {},
_addCustomization: function(customization) {
// Set all equipped, interesting items' statuses as success and cross
// them off the list.
@@ -78,7 +107,7 @@
});
this._customizationsByPetId[customization.custom_pet.name] = customization;
this._customizations = this._buildCustomizations();
- this._update();
+ this._updateCustomizations();
},
_addNewCustomization: function(customization) {
customization.loadingForItemId = null;
@@ -127,37 +156,42 @@
console.error("couldn't load user %s's customizations", neopiaUserId);
});
},
- _loadManyUsersCustomizations: function(neopiaUserIds) {
- return neopiaUserIds.map(this._loadUserCustomizations.bind(this));
- },
_startLoading: function(neopiaPetId, itemId) {
var customization = this._customizationsByPetId[neopiaPetId];
customization.loadingForItemId = itemId;
customization.statusByItemId[itemId] = "loading";
- this._update();
+ this._updateCustomizations();
},
_stopLoading: function(neopiaPetId, itemId, status) {
var customization = this._customizationsByPetId[neopiaPetId];
customization.loadingForItemId = null;
customization.statusByItemId[itemId] = status;
- this._update();
+ this._updateCustomizations();
},
- _update: function() {
- var customizations = this._customizations;
+ _updateCustomizations: function() {
+ var neopetsUsernamesPresenceMap = this._neopetsUsernamesPresenceMap;
+ var liveCustomizations = this._customizations.filter(function(c) {
+ return neopetsUsernamesPresenceMap[c.custom_pet.owner];
+ });
this._items.forEach(function(item) {
- var filteredCustomizations = customizations.filter(function(c) {
+ var filteredCustomizations = liveCustomizations.filter(function(c) {
return item.missingBodyIdsPresenceMap[c.custom_pet.body_id];
});
item.component.setState({customizations: filteredCustomizations});
});
},
+ _updateUsernames: function() {
+ var usernames = Object.keys(this._neopetsUsernamesPresenceMap);
+ this._usersComponent.setState({usernames: usernames});
+ },
init: function($) {
Neopia.init();
this._createItems($);
- // TODO: use user prefs, silly!
- var search = document.location.search;
- var users = search.indexOf('=') >= 0 ? search.split('=')[1].split(',') : '';
- this._loadManyUsersCustomizations(users);
+ var usersEl = $('#modeling-neopets-users');
+ this._usersComponent = React.renderComponent(,
+ usersEl.get(0));
+ var usernames = ImpressUser.getNeopetsUsernames();
+ usernames.forEach(this.addUsername.bind(this));
},
model: function(neopiaPetId, itemId) {
var oldCustomization = this._customizationsByPetId[neopiaPetId];
@@ -181,6 +215,22 @@
.fail(function() {
Modeling._stopLoading(neopiaPetId, itemId, "error");
});
+ },
+ addUsername: function(username) {
+ if (typeof this._neopetsUsernamesPresenceMap[username] === 'undefined') {
+ this._neopetsUsernamesPresenceMap[username] = true;
+ ImpressUser.addNeopetsUsername(username);
+ this._loadUserCustomizations(username);
+ this._updateUsernames();
+ }
+ },
+ removeUsername: function(username) {
+ if (this._neopetsUsernamesPresenceMap[username]) {
+ delete this._neopetsUsernamesPresenceMap[username];
+ ImpressUser.removeNeopetsUsername(username);
+ this._updateCustomizations();
+ this._updateUsernames();
+ }
}
};
@@ -195,7 +245,7 @@
item={item}
key={customization.custom_pet.name} />;
}
- var sortedCustomizations = this.state.customizations.sort(function(a, b) {
+ var sortedCustomizations = this.state.customizations.slice(0).sort(function(a, b) {
var aName = a.custom_pet.name.toLowerCase();
var bName = b.custom_pet.name.toLowerCase();
if (aName < bName) return -1;
@@ -243,5 +293,43 @@
}
});
+ var NeopetsUsernamesForm = React.createClass({
+ getInitialState: function() {
+ return {usernames: [], newUsername: ""};
+ },
+ render: function() {
+ function buildUsernameItem(username) {
+ return ;
+ }
+ return
+
{this.state.usernames.slice(0).sort().map(buildUsernameItem)}
+
;
+ },
+ handleChange: function(e) {
+ this.setState({newUsername: e.target.value});
+ },
+ handleSubmit: function(e) {
+ e.preventDefault();
+ this.state.newUsername = $.trim(this.state.newUsername);
+ if (this.state.newUsername.length) {
+ Modeling.addUsername(this.state.newUsername);
+ this.setState({newUsername: ""});
+ }
+ }
+ });
+
+ var NeopetsUsernameItem = React.createClass({
+ render: function() {
+ return {this.props.username}
+ },
+ handleClick: function(e) {
+ Modeling.removeUsername(this.props.username);
+ }
+ });
+
Modeling.init($);
})(jQuery);
diff --git a/app/assets/stylesheets/outfits/_new.sass b/app/assets/stylesheets/outfits/_new.sass
index 5574a83a..9a4b7879 100644
--- a/app/assets/stylesheets/outfits/_new.sass
+++ b/app/assets/stylesheets/outfits/_new.sass
@@ -144,24 +144,29 @@ body.outfits-new
font-style: italic
margin-bottom: .5em
- #newest-modeled-items
- text-align: center
+ #modeling-neopets-users
+ float: right
+ font-size: 85%
+ margin-top: -5px
+ max-width: 55%
+ text-align: right
- .object
- margin: 2px
- padding: 0
- width: 80px
+ ul, li, form
+ display: inline-block
- .name
- display: none
+ li
+ +border-radius(6px)
+ border: 1px solid $soft-border-color
+ line-height: 1
+ margin: 0 4px
+ padding: 2px 4px 2px 8px
- img
- margin: 0
+ button
+ +reset-awesome-button
+ margin-left: 6px
- .nc-icon
- right: 0
-
#newest-unmodeled-items
+ clear: both
list-style: none
> li
@@ -264,7 +269,24 @@ body.outfits-new
.message
font-style: italic
font-size: 85%
-
+
+ #newest-modeled-items
+ text-align: center
+
+ .object
+ margin: 2px
+ padding: 0
+ width: 80px
+
+ .name
+ display: none
+
+ img
+ margin: 0
+
+ .nc-icon
+ right: 0
+
#latest-contribution
+subtle-banner
diff --git a/app/controllers/outfits_controller.rb b/app/controllers/outfits_controller.rb
index 359d5bca..a397e24d 100644
--- a/app/controllers/outfits_controller.rb
+++ b/app/controllers/outfits_controller.rb
@@ -75,6 +75,8 @@ class OutfitsController < ApplicationController
@latest_contribution = Contribution.recent.first
Contribution.preload_contributeds_and_parents([@latest_contribution])
end
+
+ @neopets_usernames = user_signed_in? ? current_user.neopets_usernames : []
end
def show
diff --git a/app/models/user.rb b/app/models/user.rb
index b6bd3707..4775a828 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -89,6 +89,10 @@ class User < ActiveRecord::Base
owned ? ClosetList::NullOwned.new(self) : ClosetList::NullWanted.new(self)
end
+ def neopets_usernames
+ [neopets_username]
+ end
+
def self.find_or_create_from_remote_auth_data(user_data)
user = find_or_initialize_by_remote_id_and_auth_server_id(
user_data['id'],
diff --git a/app/views/outfits/new.html.haml b/app/views/outfits/new.html.haml
index 7ed53a58..e7feb3a6 100644
--- a/app/views/outfits/new.html.haml
+++ b/app/views/outfits/new.html.haml
@@ -76,6 +76,7 @@
-# TODO: i18n all the things
-# TODO: cache this entire block? or just request newest items every time?
- if @newest_unmodeled_items.present?
+ #modeling-neopets-users{'data-usernames' => @neopets_usernames.to_json}
%h3= t '.newest_items.unmodeled.header'
%ul#newest-unmodeled-items
- @newest_unmodeled_items.each do |item|