Compare commits
No commits in common. "583f3c712f638739c6ef5e4500d88edb3bb10e34" and "c8e53165c7a1e21acc4fca6464e7f570c204854a" have entirely different histories.
583f3c712f
...
c8e53165c7
10 changed files with 95 additions and 147 deletions
|
@ -7,11 +7,7 @@
|
||||||
|
|
||||||
function hangersInit() {
|
function hangersInit() {
|
||||||
for (var i = 0; i < hangersInitCallbacks.length; i++) {
|
for (var i = 0; i < hangersInitCallbacks.length; i++) {
|
||||||
try {
|
|
||||||
hangersInitCallbacks[i]();
|
hangersInitCallbacks[i]();
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,36 +58,6 @@
|
||||||
hangersEl.toggleClass("comparing");
|
hangersEl.toggleClass("comparing");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Read the item IDs of trade matches from the meta tags.
|
|
||||||
const ownedIds =
|
|
||||||
document
|
|
||||||
.querySelector("meta[name=trade-matches-owns]")
|
|
||||||
?.getAttribute("value")
|
|
||||||
?.split(",") ?? [];
|
|
||||||
const wantedIds =
|
|
||||||
document
|
|
||||||
.querySelector("meta[name=trade-matches-wants]")
|
|
||||||
?.getAttribute("value")
|
|
||||||
?.split(",") ?? [];
|
|
||||||
|
|
||||||
// Apply the `user-owns` and `user-wants` classes to the relevant entries.
|
|
||||||
// This both provides immediate visual feedback, and sets up "Compare with
|
|
||||||
// Your Items" to toggle to just them!
|
|
||||||
//
|
|
||||||
// NOTE: The motivation here is caching: this allows us to share a cache of
|
|
||||||
// the closet list contents across all users, without `user-owns` or
|
|
||||||
// `user-wants` classes for one specific user getting cached and reused.
|
|
||||||
const hangerEls = document.querySelectorAll("#closet-hangers .object");
|
|
||||||
for (const hangerEl of hangerEls) {
|
|
||||||
const itemId = hangerEl.getAttribute("data-item-id");
|
|
||||||
if (ownedIds.includes(itemId)) {
|
|
||||||
hangerEl.classList.add("user-owns");
|
|
||||||
}
|
|
||||||
if (wantedIds.includes(itemId)) {
|
|
||||||
hangerEl.classList.add("user-wants");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
Hanger forms
|
Hanger forms
|
||||||
|
@ -515,6 +481,13 @@
|
||||||
updateBulkActions();
|
updateBulkActions();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// hahaha, nasty hacks to make stickUp use our old jQuery
|
||||||
|
$.fn.on = $.fn.bind;
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
$(".bulk-actions").stickUp();
|
||||||
|
});
|
||||||
|
|
||||||
function maintainCheckboxes(fn) {
|
function maintainCheckboxes(fn) {
|
||||||
var checkedIds = getCheckedIds();
|
var checkedIds = getCheckedIds();
|
||||||
|
|
||||||
|
|
1
app/assets/javascripts/lib/stickUp.min.js
vendored
Normal file
1
app/assets/javascripts/lib/stickUp.min.js
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
jQuery(function($){$(document).ready(function(){var contentButton = [];var contentTop = [];var content = [];var lastScrollTop = 0;var scrollDir = '';var itemClass = '';var itemHover = '';var menuSize = null;var stickyHeight = 0;var stickyMarginB = 0;var currentMarginT = 0;var topMargin = 0;$(window).scroll(function(event){var st = $(this).scrollTop();if (st > lastScrollTop){scrollDir = 'down';} else {scrollDir = 'up';}lastScrollTop = st;});$.fn.stickUp = function( options ) {$(this).addClass('stuckMenu');var objn = 0;if(options != null) {for(var o in options.parts) {if (options.parts.hasOwnProperty(o)){content[objn] = options.parts[objn];objn++;}}if(objn == 0) {console.log('error:needs arguments');}itemClass = options.itemClass;itemHover = options.itemHover;if(options.topMargin != null) {if(options.topMargin == 'auto') {topMargin = parseInt($('.stuckMenu').css('margin-top'));} else {if(isNaN(options.topMargin) && options.topMargin.search("px") > 0){topMargin = parseInt(options.topMargin.replace("px",""));} else if(!isNaN(parseInt(options.topMargin))) {topMargin = parseInt(options.topMargin);} else {console.log("incorrect argument, ignored.");topMargin = 0;} }} else {topMargin = 0;}menuSize = $('.'+itemClass).size();}stickyHeight = parseInt($(this).height());stickyMarginB = parseInt($(this).css('margin-bottom'));currentMarginT = parseInt($(this).next().closest('div').css('margin-top'));vartop = parseInt($(this).offset().top);};$(document).on('scroll', function() {varscroll = parseInt($(document).scrollTop());if(menuSize != null){for(var i=0;i < menuSize;i++){contentTop[i] = $('#'+content[i]+'').offset().top;function bottomView(i) {contentView = $('#'+content[i]+'').height()*.4;testView = contentTop[i] - contentView;if(varscroll > testView){$('.'+itemClass).removeClass(itemHover);$('.'+itemClass+':eq('+i+')').addClass(itemHover);} else if(varscroll < 50){$('.'+itemClass).removeClass(itemHover);$('.'+itemClass+':eq(0)').addClass(itemHover);}}if(scrollDir == 'down' && varscroll > contentTop[i]-50 && varscroll < contentTop[i]+50) {$('.'+itemClass).removeClass(itemHover);$('.'+itemClass+':eq('+i+')').addClass(itemHover);}if(scrollDir == 'up') {bottomView(i);}}}if(vartop < varscroll + topMargin){$('.stuckMenu').addClass('isStuck');$('.stuckMenu').next().closest('div').css({'margin-top': stickyHeight + stickyMarginB + currentMarginT + 'px'}, 10);$('.stuckMenu').css("position","fixed");$('.isStuck').css({top: '0px'}, 10, function(){});};if(varscroll + topMargin < vartop){$('.stuckMenu').removeClass('isStuck');$('.stuckMenu').next().closest('div').css({'margin-top': currentMarginT + 'px'}, 10);$('.stuckMenu').css("position","relative");};});});});
|
|
@ -96,7 +96,6 @@ body.closet_hangers-index
|
||||||
#closet-hangers
|
#closet-hangers
|
||||||
clear: both
|
clear: both
|
||||||
text-align: center
|
text-align: center
|
||||||
border-top: 1px solid $module-border-color
|
|
||||||
|
|
||||||
.object
|
.object
|
||||||
.quantity
|
.quantity
|
||||||
|
@ -153,9 +152,6 @@ body.closet_hangers-index
|
||||||
margin-bottom: 2em
|
margin-bottom: 2em
|
||||||
padding-bottom: 1em
|
padding-bottom: 1em
|
||||||
|
|
||||||
&:first-of-type
|
|
||||||
border-top: 0
|
|
||||||
|
|
||||||
> header
|
> header
|
||||||
border-bottom: 1px solid $soft-border-color
|
border-bottom: 1px solid $soft-border-color
|
||||||
display: block
|
display: block
|
||||||
|
@ -380,6 +376,7 @@ body.closet_hangers-index
|
||||||
|
|
||||||
.bulk-actions
|
.bulk-actions
|
||||||
background: $background-color
|
background: $background-color
|
||||||
|
border-top: 1px solid $module-border-color
|
||||||
box-sizing: border-box
|
box-sizing: border-box
|
||||||
display: block
|
display: block
|
||||||
font-size: 85%
|
font-size: 85%
|
||||||
|
@ -387,9 +384,9 @@ body.closet_hangers-index
|
||||||
text-align: center
|
text-align: center
|
||||||
width: 800px
|
width: 800px
|
||||||
|
|
||||||
position: sticky
|
&.isStuck
|
||||||
top: 0
|
|
||||||
border-bottom: 1px solid $module-border-color
|
border-bottom: 1px solid $module-border-color
|
||||||
|
border-top: 0
|
||||||
z-index: 11 /* beat the visibility form */
|
z-index: 11 /* beat the visibility form */
|
||||||
|
|
||||||
.bulk-actions-intro, .bulk-actions-target-desc-singular
|
.bulk-actions-intro, .bulk-actions-target-desc-singular
|
||||||
|
|
|
@ -45,24 +45,24 @@ class ClosetHangersController < ApplicationController
|
||||||
visible_groups = @user.closet_hangers_groups_visible_to(@perspective_user)
|
visible_groups = @user.closet_hangers_groups_visible_to(@perspective_user)
|
||||||
@unlisted_closet_hangers_by_owned = find_unlisted_closet_hangers_by_owned(visible_groups)
|
@unlisted_closet_hangers_by_owned = find_unlisted_closet_hangers_by_owned(visible_groups)
|
||||||
|
|
||||||
@items = []
|
items = []
|
||||||
|
|
||||||
@closet_lists_by_owned.each do |owned, lists|
|
@closet_lists_by_owned.each do |owned, lists|
|
||||||
lists.each do |list|
|
lists.each do |list|
|
||||||
list.hangers.each do |hanger|
|
list.hangers.each do |hanger|
|
||||||
@items << hanger.item
|
items << hanger.item
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@unlisted_closet_hangers_by_owned.each do |owned, hangers|
|
@unlisted_closet_hangers_by_owned.each do |owned, hangers|
|
||||||
hangers.each do |hanger|
|
hangers.each do |hanger|
|
||||||
@items << hanger.item
|
items << hanger.item
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if @public_perspective && user_signed_in?
|
if @public_perspective && user_signed_in?
|
||||||
current_user.assign_closeted_to_items!(@items)
|
current_user.assign_closeted_to_items!(items)
|
||||||
end
|
end
|
||||||
|
|
||||||
@campaign = Fundraising::Campaign.current
|
@campaign = Fundraising::Campaign.current
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
require 'cgi'
|
require 'cgi'
|
||||||
require 'digest'
|
|
||||||
|
|
||||||
module ClosetHangersHelper
|
module ClosetHangersHelper
|
||||||
def closet_hangers_help_class(user)
|
def closet_hangers_help_class(user)
|
||||||
'hidden' unless user.closet_hangers.empty?
|
'hidden' unless user.closet_hangers.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def closet_hanger_partial_class(hanger)
|
||||||
|
'object'.tap do |class_name|
|
||||||
|
class_name << ' user-owns' if hanger.item.owned?
|
||||||
|
class_name << ' user-wants' if hanger.item.wanted?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def send_neomail_url(neopets_username)
|
def send_neomail_url(neopets_username)
|
||||||
"https://www.neopets.com/neomessages.phtml?type=send&recipient=#{CGI.escape neopets_username}"
|
"https://www.neopets.com/neomessages.phtml?type=send&recipient=#{CGI.escape neopets_username}"
|
||||||
end
|
end
|
||||||
|
@ -118,8 +124,8 @@ module ClosetHangersHelper
|
||||||
|
|
||||||
def render_closet_lists(lists)
|
def render_closet_lists(lists)
|
||||||
if lists
|
if lists
|
||||||
render partial: 'closet_lists/closet_list', collection: lists,
|
render :partial => 'closet_lists/closet_list', :collection => lists,
|
||||||
locals: {show_controls: !public_perspective?}
|
:locals => {:show_controls => !public_perspective?}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -134,20 +140,6 @@ module ClosetHangersHelper
|
||||||
hangers ? hangers.size : 0
|
hangers ? hangers.size : 0
|
||||||
end
|
end
|
||||||
|
|
||||||
def unlisted_hangers_cache_key(owned)
|
|
||||||
# It'd be nice if this was a closet list like any other, instead of being a
|
|
||||||
# weird separate thing! Then we could use the same closet list cache key,
|
|
||||||
# in which adding/removing stuff in the list touches the simple updated_at.
|
|
||||||
# Instead, we encode the hashed list of hanger IDs and last updated_at into
|
|
||||||
# the key! (The digest is to prevent the cache key from getting obscenely
|
|
||||||
# large for long lists!)
|
|
||||||
hangers = @unlisted_closet_hangers_by_owned[owned] || []
|
|
||||||
ids = hangers.map(&:id).join(",")
|
|
||||||
last_updated_at = hangers.map(&:updated_at).max
|
|
||||||
|
|
||||||
["owned=#{owned}", Digest::MD5.hexdigest(ids), last_updated_at.to_i]
|
|
||||||
end
|
|
||||||
|
|
||||||
def closet_lists_group_name(subject, owned)
|
def closet_lists_group_name(subject, owned)
|
||||||
ownership_key = owned ? 'owned_by' : 'wanted_by'
|
ownership_key = owned ? 'owned_by' : 'wanted_by'
|
||||||
if subject == :you
|
if subject == :you
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
class ClosetHanger < ApplicationRecord
|
class ClosetHanger < ApplicationRecord
|
||||||
belongs_to :item
|
belongs_to :item
|
||||||
belongs_to :list, class_name: 'ClosetList', optional: true, touch: true
|
belongs_to :list, class_name: 'ClosetList', optional: true
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
|
|
||||||
delegate :name, to: :item, prefix: true
|
delegate :name, to: :item, prefix: true
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
-# NOTE: Changing this requires bumping the cache at `_closet_list.html.haml`!
|
%div{'class' => closet_hanger_partial_class(closet_hanger), 'data-item-id' => closet_hanger.item_id, 'data-quantity' => closet_hanger.quantity, 'data-id' => closet_hanger.id}
|
||||||
.object{'data-item-id' => closet_hanger.item_id, 'data-quantity' => closet_hanger.quantity, 'data-id' => closet_hanger.id}
|
|
||||||
= render_item_link(closet_hanger.item)
|
= render_item_link(closet_hanger.item)
|
||||||
.quantity{:class => "quantity-#{closet_hanger.quantity}"}
|
.quantity{:class => "quantity-#{closet_hanger.quantity}"}
|
||||||
%span= closet_hanger.quantity
|
%span= closet_hanger.quantity
|
||||||
|
|
|
@ -55,7 +55,6 @@
|
||||||
= link_to t('.import_from.gallery'), new_neopets_page_import_task_path(page_type: 'gallery', expected_index: 1)
|
= link_to t('.import_from.gallery'), new_neopets_page_import_task_path(page_type: 'gallery', expected_index: 1)
|
||||||
= link_to t('.export_to.petpage'), petpage_user_closet_hangers_path(@user)
|
= link_to t('.export_to.petpage'), petpage_user_closet_hangers_path(@user)
|
||||||
|
|
||||||
#closet-hangers{:class => public_perspective? ? nil : 'current-user'}
|
|
||||||
- unless public_perspective?
|
- unless public_perspective?
|
||||||
-# TODO: i18n
|
-# TODO: i18n
|
||||||
.bulk-actions{'data-target-count' => 0}
|
.bulk-actions{'data-target-count' => 0}
|
||||||
|
@ -80,8 +79,10 @@
|
||||||
%button Remove all
|
%button Remove all
|
||||||
%li
|
%li
|
||||||
%button.bulk-actions-deselect-all Deselect all
|
%button.bulk-actions-deselect-all Deselect all
|
||||||
|
|
||||||
|
#closet-hangers{:class => public_perspective? ? nil : 'current-user'}
|
||||||
- [true, false].each do |owned|
|
- [true, false].each do |owned|
|
||||||
%section.closet-hangers-group{'data-owned' => owned.to_s, :id => "closet-hangers-group-#{owned}"}
|
.closet-hangers-group{'data-owned' => owned.to_s, :id => "closet-hangers-group-#{owned}"}
|
||||||
%header
|
%header
|
||||||
%h3= closet_lists_group_name(closet_hangers_subject(@user), owned)
|
%h3= closet_lists_group_name(closet_hangers_subject(@user), owned)
|
||||||
%span.toggle.show= t '.toggle_group.show'
|
%span.toggle.show= t '.toggle_group.show'
|
||||||
|
@ -108,13 +109,13 @@
|
||||||
%h4= t '.unlisted.header'
|
%h4= t '.unlisted.header'
|
||||||
- if !@public_perspective
|
- if !@public_perspective
|
||||||
= render partial: 'closet_lists/trading_neomail_warning', locals: {list: @user.null_closet_list(owned), user: @user}
|
= render partial: 'closet_lists/trading_neomail_warning', locals: {list: @user.null_closet_list(owned), user: @user}
|
||||||
- cache unlisted_hangers_cache_key(owned) do
|
|
||||||
.closet-list-content
|
.closet-list-content
|
||||||
.closet-list-hangers
|
.closet-list-hangers
|
||||||
= render_unlisted_closet_hangers(owned)
|
= render_unlisted_closet_hangers(owned)
|
||||||
%span.empty-list= t '.unlisted.empty'
|
%span.empty-list= t '.unlisted.empty'
|
||||||
|
|
||||||
- if user_signed_in?
|
- if user_signed_in?
|
||||||
|
- localized_cache action_suffix: 'tmpls' do
|
||||||
%script#autocomplete-item-tmpl{type: 'text/x-jquery-tmpl'}
|
%script#autocomplete-item-tmpl{type: 'text/x-jquery-tmpl'}
|
||||||
%a
|
%a
|
||||||
= t '.autocomplete.add_item_html', item_name: '${item_name}'
|
= t '.autocomplete.add_item_html', item_name: '${item_name}'
|
||||||
|
@ -153,15 +154,4 @@
|
||||||
- content_for :javascripts do
|
- content_for :javascripts do
|
||||||
= include_javascript_libraries :jquery, :jquery_tmpl
|
= include_javascript_libraries :jquery, :jquery_tmpl
|
||||||
= javascript_include_tag 'ajax_auth', 'lib/jquery.ui', 'lib/jquery.jgrowl',
|
= javascript_include_tag 'ajax_auth', 'lib/jquery.ui', 'lib/jquery.jgrowl',
|
||||||
'closet_hangers/index'
|
'lib/stickUp.min', 'closet_hangers/index'
|
||||||
|
|
||||||
- if public_perspective? && user_signed_in?
|
|
||||||
- content_for :meta do
|
|
||||||
%meta{
|
|
||||||
name: "trade-matches-owns",
|
|
||||||
value: @items.select(&:owned?).map(&:id).join(",")
|
|
||||||
}
|
|
||||||
%meta{
|
|
||||||
name: "trade-matches-wants",
|
|
||||||
value: @items.select(&:wanted?).map(&:id).join(",")
|
|
||||||
}
|
|
|
@ -18,8 +18,6 @@
|
||||||
- if show_controls
|
- if show_controls
|
||||||
= render partial: 'closet_lists/trading_neomail_warning', locals: {list: closet_list, user: @user}
|
= render partial: 'closet_lists/trading_neomail_warning', locals: {list: closet_list, user: @user}
|
||||||
|
|
||||||
-# Cachebuster comment: Updated downstream content at Feb 20 2024, 6:15pm
|
|
||||||
- cache closet_list do
|
|
||||||
.closet-list-content
|
.closet-list-content
|
||||||
- if closet_list.description?
|
- if closet_list.description?
|
||||||
= closet_list_description_format closet_list
|
= closet_list_description_format closet_list
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
-# NOTE: Changing this requires bumping the cache at `_closet_list.html.haml`!
|
|
||||||
= link_to item_path(item) do
|
= link_to item_path(item) do
|
||||||
= image_tag item.thumbnail_url, alt: "Thumbnail for #{item.name}",
|
= image_tag item.thumbnail_url, :alt => item.description, :title => item.description
|
||||||
title: item.description, loading: "lazy"
|
|
||||||
%span.name= item.name
|
%span.name= item.name
|
||||||
= nc_icon_for(item)
|
= nc_icon_for(item)
|
||||||
|
|
Loading…
Reference in a new issue