Emi Matchu
1a1615e0ad
I changed the type of this tag without realizing the JS references it by both class and `div`! I think at the time this was a perf suggestion for jQuery, because the best way to query by class name was to query by tag first then filter? It's possible our jQuery still does this, but I don't imagine it's very relevant today, so I'll just remove that for better guarding against similar bugs in the future instead.
852 lines
23 KiB
JavaScript
852 lines
23 KiB
JavaScript
(function () {
|
|
var hangersInitCallbacks = [];
|
|
|
|
function onHangersInit(callback) {
|
|
hangersInitCallbacks[hangersInitCallbacks.length] = callback;
|
|
}
|
|
|
|
function hangersInit() {
|
|
for (var i = 0; i < hangersInitCallbacks.length; i++) {
|
|
try {
|
|
hangersInitCallbacks[i]();
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
Hanger groups
|
|
|
|
*/
|
|
|
|
var hangerGroups = [];
|
|
|
|
$(".closet-hangers-group").each(function () {
|
|
var el = $(this);
|
|
var lists = [];
|
|
|
|
el.find("div.closet-list").each(function () {
|
|
var el = $(this);
|
|
var id = el.attr("data-id");
|
|
if (id) {
|
|
lists[lists.length] = {
|
|
id: parseInt(id, 10),
|
|
label: el.find("h4").text(),
|
|
};
|
|
}
|
|
});
|
|
|
|
hangerGroups[hangerGroups.length] = {
|
|
label: el.find("h3").text(),
|
|
lists: lists,
|
|
owned: el.attr("data-owned") == "true",
|
|
};
|
|
});
|
|
|
|
$(".closet-hangers-group span.toggle").live("click", function () {
|
|
$(this).closest(".closet-hangers-group").toggleClass("hidden");
|
|
});
|
|
|
|
var hangersElQuery = "#closet-hangers";
|
|
var hangersEl = $(hangersElQuery);
|
|
|
|
/*
|
|
|
|
Compare with Your Items
|
|
|
|
*/
|
|
|
|
$("#toggle-compare").click(function () {
|
|
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
|
|
|
|
*/
|
|
|
|
var body = $(document.body).addClass("js");
|
|
if (!body.hasClass("current-user")) return false;
|
|
|
|
// When we get hangers HTML, add the controls. We do this in JS rather than
|
|
// in the HTML for caching, since otherwise the requests can take forever.
|
|
// If there were another way to add hangers, then we'd have to worry about
|
|
// that, but, right now, the only way to create a new hanger from this page
|
|
// is through the autocompleter, which reinitializes anyway. Geez, this thing
|
|
// is begging for a rewrite, but today we're here for performance.
|
|
$("#closet-hanger-update-tmpl").template("updateFormTmpl");
|
|
$("#closet-hanger-destroy-tmpl").template("destroyFormTmpl");
|
|
onHangersInit(function () {
|
|
// Super-lame hack to get the user ID from where it already is :/
|
|
var currentUserId = itemsSearchForm.data("current-user-id");
|
|
$("#closet-hangers .closet-hangers-group").each(function () {
|
|
var groupEl = $(this);
|
|
var owned = groupEl.data("owned");
|
|
|
|
groupEl.find("div.closet-list").each(function () {
|
|
var listEl = $(this);
|
|
var listId = listEl.data("id");
|
|
|
|
listEl.find("div.object").each(function () {
|
|
var hangerEl = $(this);
|
|
var hangerId = hangerEl.data("id");
|
|
var quantityEl = hangerEl.find("div.quantity");
|
|
var quantity = hangerEl.data("quantity");
|
|
|
|
// Ooh, this part is weird. We only want the name to be linked, so
|
|
// lift everything else out.
|
|
var checkboxId = "hanger-selected-" + hangerId;
|
|
var label = $("<label />", { for: checkboxId });
|
|
var link = hangerEl.children("a");
|
|
link.children(":not(.name)").detach().appendTo(label);
|
|
link.detach().appendTo(label);
|
|
var checkbox = $("<input />", {
|
|
type: "checkbox",
|
|
id: checkboxId,
|
|
}).appendTo(hangerEl);
|
|
label.appendTo(hangerEl);
|
|
|
|
// I don't usually like to _blank things, but it's too easy to click
|
|
// the text when you didn't mean to and lose your selection work.
|
|
link.attr("target", "_blank");
|
|
|
|
$.tmpl("updateFormTmpl", {
|
|
user_id: currentUserId,
|
|
closet_hanger_id: hangerId,
|
|
quantity: quantity,
|
|
list_id: listId,
|
|
owned: owned,
|
|
}).appendTo(quantityEl);
|
|
|
|
$.tmpl("destroyFormTmpl", {
|
|
user_id: currentUserId,
|
|
closet_hanger_id: hangerId,
|
|
}).appendTo(hangerEl);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
$.fn.liveDraggable = function (opts) {
|
|
this.live("mouseover", function () {
|
|
if (!$(this).data("init")) {
|
|
$(this).data("init", true).draggable(opts);
|
|
}
|
|
});
|
|
};
|
|
|
|
$.fn.disableForms = function () {
|
|
return this.data("formsDisabled", true)
|
|
.find("input")
|
|
.attr("disabled", "disabled")
|
|
.end();
|
|
};
|
|
|
|
$.fn.enableForms = function () {
|
|
return this.data("formsDisabled", false)
|
|
.find("input")
|
|
.removeAttr("disabled")
|
|
.end();
|
|
};
|
|
|
|
$.fn.hasChanged = function () {
|
|
return this.attr("data-previous-value") != this.val();
|
|
};
|
|
|
|
$.fn.revertValue = function () {
|
|
return this.each(function () {
|
|
var el = $(this);
|
|
el.val(el.attr("data-previous-value"));
|
|
});
|
|
};
|
|
|
|
$.fn.storeValue = function () {
|
|
return this.each(function () {
|
|
var el = $(this);
|
|
el.attr("data-previous-value", el.val());
|
|
});
|
|
};
|
|
|
|
$.fn.insertIntoSortedList = function (list, compare) {
|
|
var newChild = this,
|
|
inserted = false;
|
|
list.children().each(function () {
|
|
if (compare(newChild, $(this)) < 1) {
|
|
newChild.insertBefore(this);
|
|
inserted = true;
|
|
return false;
|
|
}
|
|
});
|
|
if (!inserted) newChild.appendTo(list);
|
|
return this;
|
|
};
|
|
|
|
function handleSaveError(xhr, action) {
|
|
try {
|
|
var data = $.parseJSON(xhr.responseText);
|
|
} catch (e) {
|
|
var data = {};
|
|
}
|
|
|
|
if (typeof data.errors != "undefined") {
|
|
$.jGrowl("Error " + action + ": " + data.errors.join(", "));
|
|
} else {
|
|
$.jGrowl("We had trouble " + action + " just now. Try again?");
|
|
}
|
|
}
|
|
|
|
function objectRemoved(objectWrapper) {
|
|
objectWrapper.hide(250, function () {
|
|
objectWrapper.remove();
|
|
updateBulkActions();
|
|
});
|
|
}
|
|
|
|
function compareItemsByName(a, b) {
|
|
return a.find("span.name").text().localeCompare(b.find("span.name").text());
|
|
}
|
|
|
|
function findList(owned, id, item) {
|
|
if (id) {
|
|
return $("#closet-list-" + id);
|
|
} else {
|
|
return $(
|
|
".closet-hangers-group[data-owned=" +
|
|
owned +
|
|
"] div.closet-list.unlisted",
|
|
);
|
|
}
|
|
}
|
|
|
|
function updateListHangersCount(el) {
|
|
el.attr("data-hangers-count", el.find("div.object").length);
|
|
}
|
|
|
|
function moveItemToList(item, owned, listId) {
|
|
var newList = findList(owned, listId, item);
|
|
var oldList = item.closest("div.closet-list");
|
|
var hangersWrapper = newList.find("div.closet-list-hangers");
|
|
item.insertIntoSortedList(hangersWrapper, compareItemsByName);
|
|
updateListHangersCount(oldList);
|
|
updateListHangersCount(newList);
|
|
}
|
|
|
|
function submitUpdateForm(form) {
|
|
if (form.data("loading")) return false;
|
|
var quantityEl = form.children("input[name=closet_hanger[quantity]]");
|
|
var ownedEl = form.children("input[name=closet_hanger[owned]]");
|
|
var listEl = form.children("input[name=closet_hanger[list_id]]");
|
|
var listChanged = ownedEl.hasChanged() || listEl.hasChanged();
|
|
if (listChanged || quantityEl.hasChanged()) {
|
|
var objectWrapper = form.closest(".object").addClass("loading");
|
|
var newQuantity = quantityEl.val();
|
|
var quantitySpan = objectWrapper.find(".quantity span").text(newQuantity);
|
|
objectWrapper.attr("data-quantity", newQuantity);
|
|
var data = form.serialize(); // get data before disabling inputs
|
|
objectWrapper.disableForms();
|
|
form.data("loading", true);
|
|
if (listChanged)
|
|
moveItemToList(objectWrapper, ownedEl.val(), listEl.val());
|
|
$.ajax({
|
|
url: form.attr("action") + ".json",
|
|
type: "post",
|
|
data: data,
|
|
dataType: "json",
|
|
complete: function (data) {
|
|
if (quantityEl.val() == 0) {
|
|
objectRemoved(objectWrapper);
|
|
} else {
|
|
objectWrapper.removeClass("loading").enableForms();
|
|
}
|
|
form.data("loading", false);
|
|
},
|
|
success: function () {
|
|
// Now that the move was successful, let's merge it with any
|
|
// conflicting hangers
|
|
var id = objectWrapper.attr("data-item-id");
|
|
var conflictingHanger = findList(
|
|
ownedEl.val(),
|
|
listEl.val(),
|
|
objectWrapper,
|
|
)
|
|
.find("div[data-item-id=" + id + "]")
|
|
.not(objectWrapper);
|
|
if (conflictingHanger.length) {
|
|
var conflictingQuantity = parseInt(
|
|
conflictingHanger.attr("data-quantity"),
|
|
10,
|
|
);
|
|
|
|
var currentQuantity = parseInt(newQuantity, 10);
|
|
|
|
var mergedQuantity = conflictingQuantity + currentQuantity;
|
|
|
|
quantitySpan.text(mergedQuantity);
|
|
quantityEl.val(mergedQuantity);
|
|
objectWrapper.attr("data-quantity", mergedQuantity);
|
|
|
|
conflictingHanger.remove();
|
|
}
|
|
|
|
quantityEl.storeValue();
|
|
ownedEl.storeValue();
|
|
listEl.storeValue();
|
|
|
|
updateBulkActions();
|
|
},
|
|
error: function (xhr) {
|
|
quantityEl.revertValue();
|
|
ownedEl.revertValue();
|
|
listEl.revertValue();
|
|
if (listChanged)
|
|
moveItemToList(objectWrapper, ownedEl.val(), listEl.val());
|
|
quantitySpan.text(quantityEl.val());
|
|
|
|
handleSaveError(xhr, "updating the quantity");
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
$(hangersElQuery + " form.closet-hanger-update").live("submit", function (e) {
|
|
e.preventDefault();
|
|
submitUpdateForm($(this));
|
|
});
|
|
|
|
function editableInputs() {
|
|
return $(hangersElQuery).find(
|
|
"input[name=closet_hanger[quantity]], " +
|
|
"input[name=closet_hanger[owned]], " +
|
|
"input[name=closet_hanger[list_id]]",
|
|
);
|
|
}
|
|
|
|
$(hangersElQuery + "input[name=closet_hanger[quantity]]")
|
|
.live("change", function () {
|
|
submitUpdateForm($(this).parent());
|
|
})
|
|
.storeValue();
|
|
|
|
onHangersInit(function () {
|
|
editableInputs().storeValue();
|
|
});
|
|
|
|
$(hangersElQuery + " div.object")
|
|
.live("mouseleave", function () {
|
|
submitUpdateForm($(this).find("form.closet-hanger-update"));
|
|
})
|
|
.liveDraggable({
|
|
appendTo: "#closet-hangers",
|
|
distance: 20,
|
|
helper: "clone",
|
|
revert: "invalid",
|
|
});
|
|
|
|
$(hangersElQuery + " form.closet-hanger-destroy").live(
|
|
"submit",
|
|
function (e) {
|
|
e.preventDefault();
|
|
var form = $(this);
|
|
var button = form.children("input[type=submit]").val("Removing…");
|
|
var objectWrapper = form.closest(".object").addClass("loading");
|
|
var data = form.serialize(); // get data before disabling inputs
|
|
objectWrapper.addClass("loading").disableForms();
|
|
$.ajax({
|
|
url: form.attr("action") + ".json",
|
|
type: "post",
|
|
data: data,
|
|
dataType: "json",
|
|
complete: function () {
|
|
button.val("Remove");
|
|
},
|
|
success: function () {
|
|
objectRemoved(objectWrapper);
|
|
},
|
|
error: function () {
|
|
objectWrapper.removeClass("loading").enableForms();
|
|
$.jGrowl("Error removing item. Try again?");
|
|
},
|
|
});
|
|
},
|
|
);
|
|
|
|
$(hangersElQuery + " .select-all").live("click", function (e) {
|
|
var checkboxes = $(this)
|
|
.closest(".closet-list")
|
|
.find(".object input[type=checkbox]");
|
|
|
|
var allChecked = true;
|
|
checkboxes.each(function () {
|
|
if (!this.checked) {
|
|
allChecked = false;
|
|
return false;
|
|
}
|
|
});
|
|
|
|
checkboxes.attr("checked", !allChecked);
|
|
|
|
updateBulkActions(); // setting the checked prop doesn't fire change events
|
|
});
|
|
|
|
function getCheckboxes() {
|
|
return $(hangersElQuery + " input[type=checkbox]");
|
|
}
|
|
|
|
function getCheckedIds() {
|
|
var checkedIds = [];
|
|
getCheckboxes()
|
|
.filter(":checked")
|
|
.each(function () {
|
|
if (this.checked) checkedIds.push(this.id);
|
|
});
|
|
return checkedIds;
|
|
}
|
|
|
|
getCheckboxes().live("change", updateBulkActions);
|
|
|
|
function updateBulkActions() {
|
|
var checkedCount = getCheckboxes().filter(":checked").length;
|
|
$(".bulk-actions").attr("data-target-count", checkedCount);
|
|
$(".bulk-actions-target-count").text(checkedCount);
|
|
}
|
|
|
|
$(".bulk-actions-move-all").bind("submit", function (e) {
|
|
// TODO: DRY
|
|
e.preventDefault();
|
|
var form = $(this);
|
|
var data = form.serializeArray();
|
|
data.push({
|
|
name: "return_to",
|
|
value: window.location.pathname + window.location.search,
|
|
});
|
|
|
|
var checkedBoxes = getCheckboxes().filter(":checked");
|
|
checkedBoxes.each(function () {
|
|
data.push({
|
|
name: "ids[]",
|
|
value: $(this).closest(".object").attr("data-id"),
|
|
});
|
|
});
|
|
|
|
$.ajax({
|
|
url: form.attr("action"),
|
|
type: form.attr("method"),
|
|
data: data,
|
|
success: function (html) {
|
|
var doc = $(html);
|
|
hangersEl.html(doc.find("#closet-hangers").html());
|
|
hangersInit();
|
|
updateBulkActions(); // don't want to maintain checked; deselect em all
|
|
doc
|
|
.find(".flash")
|
|
.hide()
|
|
.insertBefore(hangersEl)
|
|
.show(500)
|
|
.delay(5000)
|
|
.hide(250);
|
|
itemsSearchField.val("");
|
|
},
|
|
error: function (xhr) {
|
|
handleSaveError(xhr, "moving these items");
|
|
},
|
|
});
|
|
});
|
|
|
|
$(".bulk-actions-remove-all").bind("submit", function (e) {
|
|
e.preventDefault();
|
|
var form = $(this);
|
|
var hangerIds = [];
|
|
var checkedBoxes = getCheckboxes().filter(":checked");
|
|
var hangerEls = $();
|
|
checkedBoxes.each(function () {
|
|
hangerEls = hangerEls.add($(this).closest(".object"));
|
|
});
|
|
hangerEls.each(function () {
|
|
hangerIds.push($(this).attr("data-id"));
|
|
});
|
|
$.ajax({
|
|
url: form.attr("action") + ".json?" + $.param({ ids: hangerIds }),
|
|
type: "delete",
|
|
dataType: "json",
|
|
success: function () {
|
|
objectRemoved(hangerEls);
|
|
},
|
|
error: function () {
|
|
$.jGrowl("Error removing items. Try again?");
|
|
},
|
|
});
|
|
});
|
|
|
|
$(".bulk-actions-deselect-all").bind("click", function (e) {
|
|
getCheckboxes().filter(":checked").attr("checked", false);
|
|
updateBulkActions();
|
|
});
|
|
|
|
function maintainCheckboxes(fn) {
|
|
var checkedIds = getCheckedIds();
|
|
|
|
fn();
|
|
|
|
checkedIds.forEach(function (id) {
|
|
document.getElementById(id).checked = true;
|
|
});
|
|
updateBulkActions();
|
|
}
|
|
|
|
/*
|
|
|
|
Search, autocomplete
|
|
|
|
*/
|
|
|
|
var itemsSearchForm = $("#closet-hangers-items-search[data-current-user-id]");
|
|
var itemsSearchField = itemsSearchForm.children("input[name=q]");
|
|
|
|
itemsSearchField.autocomplete({
|
|
select: function (e, ui) {
|
|
if (ui.item.is_item) {
|
|
// Let the autocompleter finish up this search before starting a new one
|
|
setTimeout(function () {
|
|
itemsSearchField.autocomplete("search", ui.item);
|
|
}, 0);
|
|
} else {
|
|
var item = ui.item.item;
|
|
var group = ui.item.group;
|
|
|
|
itemsSearchField.addClass("loading");
|
|
|
|
var closetHanger = {
|
|
owned: group.owned,
|
|
list_id: ui.item.list ? ui.item.list.id : "",
|
|
};
|
|
|
|
if (!item.hasHanger) closetHanger.quantity = 1;
|
|
|
|
$.ajax({
|
|
url:
|
|
"/user/" +
|
|
itemsSearchForm.data("current-user-id") +
|
|
"/items/" +
|
|
item.id +
|
|
"/closet_hangers",
|
|
type: "post",
|
|
data: {
|
|
closet_hanger: closetHanger,
|
|
return_to: window.location.pathname + window.location.search,
|
|
},
|
|
complete: function () {
|
|
itemsSearchField.removeClass("loading");
|
|
},
|
|
success: function (html) {
|
|
var doc = $(html);
|
|
maintainCheckboxes(function () {
|
|
hangersEl.html(doc.find("#closet-hangers").html());
|
|
hangersInit();
|
|
});
|
|
doc
|
|
.find(".flash")
|
|
.hide()
|
|
.insertBefore(hangersEl)
|
|
.show(500)
|
|
.delay(5000)
|
|
.hide(250);
|
|
itemsSearchField.val("");
|
|
},
|
|
error: function (xhr) {
|
|
handleSaveError(xhr, "adding the item");
|
|
},
|
|
});
|
|
}
|
|
},
|
|
source: function (input, callback) {
|
|
if (typeof input.term == "string") {
|
|
// user-typed query
|
|
$.getJSON("/items.json?q=" + input.term, function (data) {
|
|
var output = [];
|
|
var items = data.items;
|
|
for (var i in items) {
|
|
items[i].label = items[i].name;
|
|
items[i].is_item = true;
|
|
output[output.length] = items[i];
|
|
}
|
|
callback(output);
|
|
});
|
|
} else {
|
|
// item was chosen, now choose a group to insert
|
|
var groupInserts = [],
|
|
group;
|
|
var item = input.term,
|
|
itemEl,
|
|
occupiedGroups,
|
|
hasHanger;
|
|
for (var i in hangerGroups) {
|
|
group = hangerGroups[i];
|
|
itemEl = $(
|
|
".closet-hangers-group[data-owned=" +
|
|
group.owned +
|
|
"] div.object[data-item-id=" +
|
|
item.id +
|
|
"]",
|
|
);
|
|
occupiedGroups = itemEl.closest(".closet-list");
|
|
hasHanger = occupiedGroups.filter(".unlisted").length > 0;
|
|
|
|
groupInserts[groupInserts.length] = {
|
|
group: group,
|
|
item: item,
|
|
label: item.label,
|
|
hasHanger: hasHanger,
|
|
};
|
|
|
|
for (var i = 0; i < group.lists.length; i++) {
|
|
hasHanger =
|
|
occupiedGroups.filter("[data-id=" + group.lists[i].id + "]")
|
|
.length > 0;
|
|
groupInserts[groupInserts.length] = {
|
|
group: group,
|
|
item: item,
|
|
label: item.label,
|
|
list: group.lists[i],
|
|
hasHanger: hasHanger,
|
|
};
|
|
}
|
|
}
|
|
callback(groupInserts);
|
|
}
|
|
},
|
|
});
|
|
|
|
var autocompleter = itemsSearchField.data("autocomplete");
|
|
|
|
autocompleter._renderItem = function (ul, item) {
|
|
var li = $("<li></li>").data("item.autocomplete", item);
|
|
if (item.is_item) {
|
|
// these are items from the server
|
|
$("#autocomplete-item-tmpl").tmpl({ item_name: item.label }).appendTo(li);
|
|
} else if (item.list) {
|
|
// these are list inserts
|
|
var listName = item.list.label;
|
|
if (item.hasHanger) {
|
|
$("#autocomplete-already-in-collection-tmpl")
|
|
.tmpl({ collection_name: listName })
|
|
.appendTo(li);
|
|
} else {
|
|
$("#autocomplete-add-to-list-tmpl")
|
|
.tmpl({ list_name: listName })
|
|
.appendTo(li);
|
|
}
|
|
li.addClass("closet-list-autocomplete-item");
|
|
} else {
|
|
// these are group inserts
|
|
var groupName = item.group.label;
|
|
if (!item.hasHanger) {
|
|
$("#autocomplete-add-to-group-tmpl")
|
|
.tmpl({ group_name: groupName.replace(/\s+$/, "") })
|
|
.appendTo(li);
|
|
} else {
|
|
$("#autocomplete-already-in-collection-tmpl")
|
|
.tmpl({ collection_name: groupName })
|
|
.appendTo(li);
|
|
}
|
|
li.addClass("closet-hangers-group-autocomplete-item");
|
|
}
|
|
return li.appendTo(ul);
|
|
};
|
|
|
|
/*
|
|
|
|
Contact Neopets username form
|
|
|
|
*/
|
|
|
|
var contactEl = $("#closet-hangers-contact");
|
|
var contactForm = contactEl.children("form");
|
|
var contactField = contactForm.children("select");
|
|
|
|
var contactAddOption = $("<option/>", {
|
|
text: contactField.attr("data-new-text"),
|
|
value: -1,
|
|
});
|
|
contactAddOption.appendTo(contactField);
|
|
var currentUserId = $("meta[name=current-user-id]").attr("content");
|
|
|
|
function submitContactForm() {
|
|
var data = contactForm.serialize();
|
|
contactForm.disableForms();
|
|
$.ajax({
|
|
url: contactForm.attr("action") + ".json",
|
|
type: "post",
|
|
data: data,
|
|
dataType: "json",
|
|
complete: function () {
|
|
contactForm.enableForms();
|
|
},
|
|
error: function (xhr) {
|
|
handleSaveError(xhr, "saving Neopets username");
|
|
},
|
|
});
|
|
}
|
|
|
|
contactField.change(function (e) {
|
|
if (contactField.val() < 0) {
|
|
var newUsername = $.trim(
|
|
prompt(contactField.attr("data-new-prompt"), ""),
|
|
);
|
|
if (newUsername) {
|
|
$.ajax({
|
|
url: "/user/" + currentUserId + "/neopets-connections",
|
|
type: "POST",
|
|
data: { neopets_connection: { neopets_username: newUsername } },
|
|
dataType: "json",
|
|
success: function (connection) {
|
|
var newOption = $("<option/>", {
|
|
text: newUsername,
|
|
value: connection.id,
|
|
});
|
|
newOption.insertBefore(contactAddOption);
|
|
contactField.val(connection.id);
|
|
submitContactForm();
|
|
},
|
|
});
|
|
}
|
|
} else {
|
|
submitContactForm();
|
|
}
|
|
});
|
|
|
|
/*
|
|
|
|
Hanger list controls
|
|
|
|
*/
|
|
|
|
$("input[type=submit][data-confirm]").live("click", function (e) {
|
|
if (!confirm(this.getAttribute("data-confirm"))) e.preventDefault();
|
|
});
|
|
|
|
/*
|
|
|
|
Closet list droppable
|
|
|
|
*/
|
|
|
|
onHangersInit(function () {
|
|
$("div.closet-list").droppable({
|
|
accept: "div.object",
|
|
activate: function () {
|
|
$(this)
|
|
.find(".closet-list-content")
|
|
.animate({ opacity: 0, height: 100 }, 250);
|
|
},
|
|
activeClass: "droppable-active",
|
|
deactivate: function () {
|
|
$(this)
|
|
.find(".closet-list-content")
|
|
.css("height", "auto")
|
|
.animate({ opacity: 1 }, 250);
|
|
},
|
|
drop: function (e, ui) {
|
|
var form = ui.draggable.find("form.closet-hanger-update");
|
|
form
|
|
.find("input[name=closet_hanger[list_id]]")
|
|
.val(this.getAttribute("data-id"));
|
|
form
|
|
.find("input[name=closet_hanger[owned]]")
|
|
.val($(this).closest(".closet-hangers-group").attr("data-owned"));
|
|
submitUpdateForm(form);
|
|
},
|
|
});
|
|
});
|
|
|
|
/*
|
|
|
|
Visibility Descriptions
|
|
|
|
*/
|
|
|
|
function updateVisibilityDescription() {
|
|
var descriptions = $(this)
|
|
.closest(".visibility-form")
|
|
.find("ul.visibility-descriptions");
|
|
|
|
descriptions.children("li.current").removeClass("current");
|
|
descriptions
|
|
.children("li[data-id=" + $(this).val() + "]")
|
|
.addClass("current");
|
|
}
|
|
|
|
function visibilitySelects() {
|
|
return $("form.visibility-form select");
|
|
}
|
|
|
|
visibilitySelects().live("change", updateVisibilityDescription);
|
|
|
|
onHangersInit(function () {
|
|
visibilitySelects().each(updateVisibilityDescription);
|
|
});
|
|
|
|
/*
|
|
|
|
Help
|
|
|
|
*/
|
|
|
|
$("#toggle-help").click(function () {
|
|
$("#closet-hangers-help").toggleClass("hidden");
|
|
});
|
|
|
|
/*
|
|
|
|
Share URL
|
|
|
|
*/
|
|
|
|
$("#closet-hangers-share-box")
|
|
.mouseover(function () {
|
|
$(this).focus();
|
|
})
|
|
.mouseout(function () {
|
|
$(this).blur();
|
|
});
|
|
|
|
/*
|
|
|
|
Initialize
|
|
|
|
*/
|
|
|
|
hangersInit();
|
|
})();
|