closet hangers page gets serious ajax action

This commit is contained in:
Emi Matchu 2011-07-15 22:52:53 -04:00
parent 3ac30bb6b1
commit eeb3fc3af9
7 changed files with 169 additions and 33 deletions

View file

@ -22,16 +22,35 @@ class ClosetHangersController < ApplicationController
unless @closet_hanger.quantity == 0 # save the hanger, new record or not unless @closet_hanger.quantity == 0 # save the hanger, new record or not
if @closet_hanger.save if @closet_hanger.save
respond_to do |format|
format.html {
flash[:success] = "Success! You own #{@closet_hanger.quantity} #{@item.name.pluralize}." flash[:success] = "Success! You own #{@closet_hanger.quantity} #{@item.name.pluralize}."
redirect_back!
}
format.json { render :json => true }
end
else else
respond_to do |format|
format.html {
flash[:alert] = "We couldn't save how many of this item you own: #{@closet_hanger.errors.full_messages.to_sentence}" flash[:alert] = "We couldn't save how many of this item you own: #{@closet_hanger.errors.full_messages.to_sentence}"
redirect_back!
}
format.json { render :json => {:errors => @closet_hanger.errors.full_messages}, :status => :unprocessable_entity }
end
end end
else # delete the hanger since the user doesn't want it else # delete the hanger since the user doesn't want it
@closet_hanger.destroy @closet_hanger.destroy
respond_to do |format|
format.html {
flash[:success] = "Success! You do not own #{@item.name}." flash[:success] = "Success! You do not own #{@item.name}."
end redirect_back!
}
redirect_to params[:return_to] || @item format.json { render :json => true }
end
end
end end
alias_method :create, :update alias_method :create, :update
@ -41,5 +60,9 @@ class ClosetHangersController < ApplicationController
def authorize_user! def authorize_user!
raise AccessDenied unless user_signed_in? && current_user.id == params[:user_id].to_i raise AccessDenied unless user_signed_in? && current_user.id == params[:user_id].to_i
end end
def redirect_back!
redirect_to params[:return_to] || @item
end
end end

View file

@ -157,8 +157,8 @@ ul.buttons
.object .object
+inline-block +inline-block
margin: .5em 0 margin: $object-padding 0
padding: 0 .5em padding: 0 $object-padding
position: relative position: relative
text-align: center text-align: center
vertical-align: top vertical-align: top

View file

@ -24,8 +24,9 @@ body.closet_hangers-index
padding: 2px 4px padding: 2px 4px
position: absolute position: absolute
left: ($object-width - $object-img-size) / 2 + $object-padding left: ($object-width - $object-img-size) / 2 + $object-padding
line-height: 1
text-align: left text-align: left
top: $object-img-size - 24px top: $object-img-size - 20px
form form
display: none display: none
@ -35,11 +36,10 @@ body.closet_hangers-index
font-weight: bold font-weight: bold
&.current-user &.current-user
.object:hover .object:hover .quantity
.quantity
+opacity(1) +opacity(1)
background: transparent background: transparent
top: $object-img-size - 25px top: $object-img-size - 24px
padding: 0 padding: 0
span span
@ -55,3 +55,18 @@ body.closet_hangers-index
input[type=submit] input[type=submit]
font-size: 85% font-size: 85%
&.js
.object:hover .quantity
input[type=number]
width: 2.5em
input[type=submit]
display: none
.object.loading
background: $module-bg-color
outline: 1px solid $module-border-color
.quantity span:after
content: ""

View file

@ -24,7 +24,8 @@ $text-font: "Droid Serif", Georgia, "Times New Roman", Times, serif
$object-img-size: 80px $object-img-size: 80px
$object-width: 100px $object-width: 100px
$object-padding: 6px $object-padding: 8px
$nc-icon-size: 16px $nc-icon-size: 16px
$container-top-padding: 3em $container-top-padding: 3em

View file

@ -4,8 +4,13 @@
= link_to "Import closet from Neopets", new_closet_page_path, :id => 'import-link' = link_to "Import closet from Neopets", new_closet_page_path, :id => 'import-link'
- else - else
- title "#{@user.name}'s Items" - title "#{@user.name}'s Items"
#closet-hangers{:class => user_is?(@user) ? 'current-user' : nil} #closet-hangers{:class => user_is?(@user) ? 'current-user' : nil}
- if !@closet_hangers.empty? - if !@closet_hangers.empty?
- if user_is?(@user)
%p
These are the items you own. Hover over an item to remove it from the
list or to change the quantity.
= render @closet_hangers = render @closet_hangers
- else - else
- if user_is?(@user) - if user_is?(@user)
@ -22,3 +27,7 @@
- else - else
%p #{@user.name} hasn't tracked any items on Dress to Impress. %p #{@user.name} hasn't tracked any items on Dress to Impress.
- content_for :javascripts do
= include_javascript_libraries :jquery
= javascript_include_tag 'jquery.jgrowl.js', 'closet_hangers/index'

View file

@ -0,0 +1,70 @@
(function () {
var hangersEl = $('#closet-hangers.current-user');
hangersEl.addClass('js');
$.fn.hasChanged = function () {
return this.data('previousValue') != this.val();
}
$.fn.revertValue = function () {
this.each(function () {
var el = $(this);
el.val(el.data('previousValue'));
});
}
$.fn.storeValue = function () {
this.each(function () {
var el = $(this);
el.data('previousValue', el.val());
});
}
function submitForm(form) {
if(form.data('loading')) return false;
var input = form.children("input[type=number]");
if(input.hasChanged()) {
var objectWrapper = form.closest(".object").addClass("loading");
var span = objectWrapper.find("span").text(input.val());
form.data('loading', true);
$.ajax({
url: form.attr("action") + ".json",
type: "post",
data: form.serialize(),
dataType: "json",
complete: function (data) {
objectWrapper.removeClass("loading");
form.data('loading', false);
},
success: function () {
input.storeValue();
},
error: function (xhr) {
var data = $.parseJSON(xhr.responseText);
input.revertValue();
span.text(input.val());
if(typeof data.errors != 'undefined') {
$.jGrowl("Error updating quantity: " + data.errors.join(", "));
} else {
$.jGrowl("We had trouble updating the quantity just now. Try again?");
}
}
});
}
}
hangersEl.find('form').submit(function (e) {
e.preventDefault();
submitForm($(this));
});
hangersEl.find('input[type=number]').change(function () {
submitForm($(this).parent());
}).storeValue();
hangersEl.find('div.object').mouseleave(function () {
submitForm($(this).find('form'));
});
})();

View file

@ -271,8 +271,8 @@ ul.buttons li, ul.buttons li form {
vertical-align: middle; vertical-align: middle;
*display: inline; *display: inline;
*vertical-align: auto; *vertical-align: auto;
margin: 0.5em 0; margin: 8px 0;
padding: 0 0.5em; padding: 0 8px;
position: relative; position: relative;
text-align: center; text-align: center;
vertical-align: top; vertical-align: top;
@ -323,11 +323,11 @@ ul.buttons li, ul.buttons li form {
} }
/* line 190, ../../../app/stylesheets/_layout.sass */ /* line 190, ../../../app/stylesheets/_layout.sass */
.object .nc-icon { .object .nc-icon {
right: 16px; right: 18px;
} }
/* line 193, ../../../app/stylesheets/_layout.sass */ /* line 193, ../../../app/stylesheets/_layout.sass */
.object .closeted-icon { .object .closeted-icon {
left: 16px; left: 18px;
} }
/* line 196, ../../../app/stylesheets/_layout.sass */ /* line 196, ../../../app/stylesheets/_layout.sass */
@ -610,15 +610,16 @@ body.closet_hangers-index #closet-hangers .object .quantity {
background: white; background: white;
padding: 2px 4px; padding: 2px 4px;
position: absolute; position: absolute;
left: 16px; left: 18px;
line-height: 1;
text-align: left; text-align: left;
top: 56px; top: 60px;
} }
/* line 30, ../../../app/stylesheets/closet_hangers/_index.sass */ /* line 31, ../../../app/stylesheets/closet_hangers/_index.sass */
body.closet_hangers-index #closet-hangers .object .quantity form { body.closet_hangers-index #closet-hangers .object .quantity form {
display: none; display: none;
} }
/* line 33, ../../../app/stylesheets/closet_hangers/_index.sass */ /* line 34, ../../../app/stylesheets/closet_hangers/_index.sass */
body.closet_hangers-index #closet-hangers .object .quantity span, body.closet_hangers-index #closet-hangers .object .quantity input[type=number] { body.closet_hangers-index #closet-hangers .object .quantity span, body.closet_hangers-index #closet-hangers .object .quantity input[type=number] {
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
@ -630,7 +631,7 @@ body.closet_hangers-index #closet-hangers.current-user .object:hover .quantity {
-o-opacity: 1; -o-opacity: 1;
-khtml-opacity: 1; -khtml-opacity: 1;
background: transparent; background: transparent;
top: 55px; top: 56px;
padding: 0; padding: 0;
} }
/* line 45, ../../../app/stylesheets/closet_hangers/_index.sass */ /* line 45, ../../../app/stylesheets/closet_hangers/_index.sass */
@ -642,7 +643,7 @@ body.closet_hangers-index #closet-hangers.current-user .object:hover .quantity f
display: inline; display: inline;
} }
/* line 51, ../../../app/stylesheets/closet_hangers/_index.sass */ /* line 51, ../../../app/stylesheets/closet_hangers/_index.sass */
body.closet_hangers-index #closet-hangers.current-user .object:hover .quantity form input[type=number] { body.closet_hangers-index #closet-hangers.current-user .object:hover .quantity input[type=number] {
padding: 2px; padding: 2px;
width: 2em; width: 2em;
} }
@ -650,6 +651,23 @@ body.closet_hangers-index #closet-hangers.current-user .object:hover .quantity f
body.closet_hangers-index #closet-hangers.current-user .object:hover .quantity input[type=submit] { body.closet_hangers-index #closet-hangers.current-user .object:hover .quantity input[type=submit] {
font-size: 85%; font-size: 85%;
} }
/* line 60, ../../../app/stylesheets/closet_hangers/_index.sass */
body.closet_hangers-index #closet-hangers.current-user.js .object:hover .quantity input[type=number] {
width: 2.5em;
}
/* line 63, ../../../app/stylesheets/closet_hangers/_index.sass */
body.closet_hangers-index #closet-hangers.current-user.js .object:hover .quantity input[type=submit] {
display: none;
}
/* line 66, ../../../app/stylesheets/closet_hangers/_index.sass */
body.closet_hangers-index #closet-hangers.current-user.js .object.loading {
background: #eeffee;
outline: 1px solid #006600;
}
/* line 70, ../../../app/stylesheets/closet_hangers/_index.sass */
body.closet_hangers-index #closet-hangers.current-user.js .object.loading .quantity span:after {
content: "…";
}
/* line 3, ../../../app/stylesheets/closet_pages/_new.sass */ /* line 3, ../../../app/stylesheets/closet_pages/_new.sass */
body.closet_pages-new #closet-page-form, body.closet_pages-create #closet-page-form { body.closet_pages-new #closet-page-form, body.closet_pages-create #closet-page-form {