From d6f1c08cc86865732cff89299639403b8f22d8b0 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 2 Aug 2020 21:44:28 -0400 Subject: [PATCH 01/61] retain open/closed status of the modal window across page loads --- src/favorite-setups.js | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 55d79ac..4e0e5ea 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -268,6 +268,7 @@ closeButton.textContent = "x"; closeButton.onclick = function () { document.body.removeChild(mainDiv); + localStorage.setItem('showSetups', "N"); }; topDiv.appendChild(closeButton); @@ -779,8 +780,14 @@ button.innerText = "Favorite Setups"; button.addEventListener("click", function () { const existing = document.querySelector("#tsitu-fave-setups"); - if (existing) existing.remove(); - else render(); + if (existing) { + localStorage.setItem('showSetups', "N"); + existing.remove(); + } + else { + localStorage.setItem('showSetups', "Y"); + render() + }; }); button.addEventListener("contextmenu", function () { if (confirm("Toggle 'Favorite Setups' placement?")) { @@ -802,8 +809,14 @@ link.innerText = "[Favorite Setups]"; link.addEventListener("click", function () { const existing = document.querySelector("#tsitu-fave-setups"); - if (existing) existing.remove(); - else render(); + { + localStorage.setItem('showSetups', "N"); // retain previous open/close behaviour + existing.remove(); + } + else { + render(); + localStorage.setItem('showSetups', "Y"); // retain previous open/close behaviour + }; return false; // Prevent default link clicked behavior }); link.addEventListener("contextmenu", function () { @@ -818,6 +831,9 @@ } } } + // retain previous open/close behaviour + var openedSettings = localStorage.getItem('showSetups'); + if(openedSettings == "Y") render(); injectUI(); /** From a038bfd4d0fe5fa34fc746b8851711b8691c64ff Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 2 Aug 2020 21:51:44 -0400 Subject: [PATCH 02/61] added location to data object and import/save/reset functions --- src/favorite-setups.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 4e0e5ea..863e7fb 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -50,7 +50,8 @@ cheese: 3, trinket: 4, charm: 4, - skin: 5 + skin: 5, + location: 6 }; const originalOpen = XMLHttpRequest.prototype.open; @@ -71,7 +72,8 @@ base: {}, weapon: {}, trinket: {}, - skin: {} + skin: {}, + location: {} }; data.forEach(el => { @@ -142,6 +144,7 @@ const rawData = localStorage.getItem("tsitu-owned-components"); if (rawData) { const data = JSON.parse(rawData); + data.location = []; const dataKeys = Object.keys(data).sort((a, b) => { return displayOrder[a] - displayOrder[b]; }); @@ -353,6 +356,7 @@ .value; // const skin = document.querySelector("#favorite-setup-input-skin").value; const name = document.querySelector("#favorite-setup-name").value; + const location = document.querySelector("#favorite-setup-input-location").value; if (name.length >= 1 && name.length <= 20) { const obj = {}; @@ -361,7 +365,8 @@ base: "N/A", weapon: "N/A", trinket: "N/A", - skin: "N/A" + skin: "N/A", + location: "N/A" }; if (data.bait[bait] !== undefined) obj[name].bait = bait; @@ -369,6 +374,7 @@ if (data.weapon[weapon] !== undefined) obj[name].weapon = weapon; if (data.trinket[charm] !== undefined) obj[name].trinket = charm; // if (data.skin[skin] !== undefined) obj[name].skin = skin; + if (data.location[location] !== undefined) obj[name].location = location; obj[name].sort = -1; const storedRaw = localStorage.getItem("favorite-setups-saved"); @@ -409,6 +415,8 @@ user.weapon_name || ""; document.querySelector("#favorite-setup-input-charm").value = user.trinket_name || ""; + document.querySelector("#favorite-setup-input-location").value = + user.environment_name || ""; // if (user.skin_name) { // document.querySelector("#favorite-setup-input-skin").value = // user.skin_name; // not really a thing, gotta use a qS probably or parse from LS ID-name map @@ -425,6 +433,7 @@ document.querySelector("#favorite-setup-input-charm").value = ""; // document.querySelector("#favorite-setup-input-skin").value = ""; document.querySelector("#favorite-setup-name").value = ""; + document.querySelector("#favorite-setup-input-location").value = ""; }; const buttonSpan = document.createElement("span"); From 6389e80e1e510e319398c8853128d60d71b37a96 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 2 Aug 2020 21:56:15 -0400 Subject: [PATCH 03/61] added location loading to edit button --- src/favorite-setups.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 863e7fb..63e42ef 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -638,6 +638,8 @@ el.weapon === "N/A" ? "" : el.weapon; document.querySelector("#favorite-setup-input-charm").value = el.trinket === "N/A" ? "" : el.trinket; + document.querySelector("#favorite-setup-input-location").value = + el.location === "N/A" ? "" : el.location; // document.querySelector("#favorite-setup-input-skin").value = // el.skin === "N/A" ? "" : el.skin; document.querySelector("#favorite-setup-name").value = name || ""; From 3d3d95b0364e1216df52478a6c6ef9542bb05ce4 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 2 Aug 2020 21:56:44 -0400 Subject: [PATCH 04/61] added travel button to setups using saved location --- src/favorite-setups.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 63e42ef..e41cd45 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -566,6 +566,7 @@ for (let type of elKeys) { if (type === "sort") continue; if (type === "skin") continue; + if (type === "location") continue; const img = document.createElement("img"); img.style.height = "40px"; @@ -663,6 +664,18 @@ } }; + const travelButton = document.createElement("button"); //ast location mod + travelButton.setAttribute("class","travelButton"); + travelButton.title = "Left click to travel, Right click to update setup location to current location" + if (el.location) { + travelButton.textContent = el.location; + } else { + travelButton.textContent = 'N/A' + }; + travelButton.onclick = function () { + app.pages.TravelPage.travel (locMap[el.location].type); + }; + const buttonCol = document.createElement("td"); buttonCol.style.textAlign = "center"; buttonCol.style.verticalAlign = "middle"; @@ -672,6 +685,7 @@ buttonCol.appendChild(deleteButton); buttonCol.appendChild(document.createElement("br")); buttonCol.appendChild(armButton); + buttonCol.appendChild(travelButton); const setupRow = document.createElement("tr"); setupRow.className = "tsitu-fave-setup-row"; From b4ff35dcd97012d1f95e1966e96807032198fc47 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 2 Aug 2020 22:06:09 -0400 Subject: [PATCH 05/61] bug fix: missed if statement --- src/favorite-setups.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 4e0e5ea..06c7ef2 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -809,7 +809,7 @@ link.innerText = "[Favorite Setups]"; link.addEventListener("click", function () { const existing = document.querySelector("#tsitu-fave-setups"); - { + if (existing) { localStorage.setItem('showSetups', "N"); // retain previous open/close behaviour existing.remove(); } From 398a0be0896c9200249ea67d07a3c01674ebe13b Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 2 Aug 2020 22:08:59 -0400 Subject: [PATCH 06/61] bug fix --- src/favorite-setups.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 06c7ef2..88908c9 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -557,6 +557,7 @@ for (let type of elKeys) { if (type === "sort") continue; if (type === "skin") continue; + if (type === "location") continue; const img = document.createElement("img"); img.style.height = "40px"; From ec3ea16c2e065473d531818a18c39f238fe8ad2a Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 2 Aug 2020 22:22:24 -0400 Subject: [PATCH 07/61] adding location datalist for dropdown --- src/favorite-setups.js | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index e41cd45..e715d7f 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -54,6 +54,33 @@ location: 6 }; + // Pull and save location list + const xhr = new XMLHttpRequest(); + xhr.open( + "POST", + `https://www.mousehuntgame.com/managers/ajax/pages/page.php?page_class=HunterProfile&page_arguments%5Btab%5D=mice&page_arguments%5Bsub_tab%5D=location&uh=${user.unique_hash}` + ); + xhr.onload = function () { + const response = JSON.parse(xhr.responseText); + const locations = + response.page.tabs.mice.subtabs[1].mouse_list.categories; + if (locations) { + const masterObj = {}; + + locations.forEach(el => { + const obj = {}; + obj["type"] = el.type; + masterObj[el.name] = obj; + }); + + localStorage.setItem( + "ast-location-mapping", + JSON.stringify(masterObj) + ); + }; + }; + xhr.send(); + const originalOpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function () { this.addEventListener("load", function () { @@ -142,9 +169,22 @@ if (existing) existing.remove(); const rawData = localStorage.getItem("tsitu-owned-components"); + const locMap = JSON.parse(localStorage.getItem("ast-location-mapping")); // ast location mod + // aliases for locations with multiple environment_names for the same environment_type + locMap["Cursed City"] = {"type": "lost_city"}; + locMap["Sand Crypts"] = {"type": "sand_dunes"}; + locMap["Twisted Garden"] = {"type": "desert_oasis"}; + if (rawData) { const data = JSON.parse(rawData); +<<<<<<< Updated upstream data.location = []; +======= +<<<<<<< Updated upstream +======= + data.location = locMap; +>>>>>>> Stashed changes +>>>>>>> Stashed changes const dataKeys = Object.keys(data).sort((a, b) => { return displayOrder[a] - displayOrder[b]; }); From 0293f96a236ec178e677198a35ea755ce0de60c1 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 2 Aug 2020 22:23:11 -0400 Subject: [PATCH 08/61] stashed changes --- src/favorite-setups.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index e715d7f..b2faaf2 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -177,14 +177,7 @@ if (rawData) { const data = JSON.parse(rawData); -<<<<<<< Updated upstream - data.location = []; -======= -<<<<<<< Updated upstream -======= data.location = locMap; ->>>>>>> Stashed changes ->>>>>>> Stashed changes const dataKeys = Object.keys(data).sort((a, b) => { return displayOrder[a] - displayOrder[b]; }); From 693d86c6d4341e4595b27cb1e493c29a42665904 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 2 Aug 2020 22:57:15 -0400 Subject: [PATCH 09/61] sort edited setups with a name change adjacent to originating setup --- src/favorite-setups.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 88908c9..dde6836 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -140,6 +140,8 @@ if (existing) existing.remove(); const rawData = localStorage.getItem("tsitu-owned-components"); + var editSort = -1; // ast location mod. change to -2 if you want new setups to appear above location sorted setups until they are manually sorted. + if (rawData) { const data = JSON.parse(rawData); const dataKeys = Object.keys(data).sort((a, b) => { @@ -369,7 +371,9 @@ if (data.weapon[weapon] !== undefined) obj[name].weapon = weapon; if (data.trinket[charm] !== undefined) obj[name].trinket = charm; // if (data.skin[skin] !== undefined) obj[name].skin = skin; - obj[name].sort = -1; + obj[name].sort = editSort; // ast location mod + console.log("saved setup '"+name+"': "+JSON.stringify(obj[name])); // ast location mod + const storedRaw = localStorage.getItem("favorite-setups-saved"); if (storedRaw) { @@ -633,6 +637,7 @@ // document.querySelector("#favorite-setup-input-skin").value = // el.skin === "N/A" ? "" : el.skin; document.querySelector("#favorite-setup-name").value = name || ""; + editSort = el.sort; // for sorting name-edited setups after the originating setup this button was clicked on }; const deleteButton = document.createElement("button"); From 214e57c07365482889c9af26d0ff8b804169ac04 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 2 Aug 2020 22:57:24 -0400 Subject: [PATCH 10/61] 30 char limit on name --- src/favorite-setups.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index dde6836..25a367e 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -356,7 +356,7 @@ // const skin = document.querySelector("#favorite-setup-input-skin").value; const name = document.querySelector("#favorite-setup-name").value; - if (name.length >= 1 && name.length <= 20) { + if (name.length >= 1 && name.length <= 30) { const obj = {}; obj[name] = { bait: "N/A", From eb8264d6316c699f8ff699b5a257889dcfa8400f Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 2 Aug 2020 22:57:59 -0400 Subject: [PATCH 11/61] console log when editing setup --- src/favorite-setups.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 25a367e..0738763 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -638,6 +638,7 @@ // el.skin === "N/A" ? "" : el.skin; document.querySelector("#favorite-setup-name").value = name || ""; editSort = el.sort; // for sorting name-edited setups after the originating setup this button was clicked on + console.log("editing setup: "+name+" from sort position "+editSort); }; const deleteButton = document.createElement("button"); From b3c5e62749330320d71ec28d54179bd29fd111db Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 2 Aug 2020 23:01:02 -0400 Subject: [PATCH 12/61] bug fix: 30 char limit on name --- src/favorite-setups.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 0738763..819320b 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -329,7 +329,7 @@ nameInput.id = "favorite-setup-name"; nameInput.required = true; nameInput.minLength = 1; - nameInput.maxLength = 20; + nameInput.maxLength = 30; const nameInputCol = document.createElement("td"); nameInputCol.appendChild(nameInput); From fa30a26080413a4087b780e60954219b364fe9c9 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 2 Aug 2020 23:01:53 -0400 Subject: [PATCH 13/61] load/edit buttons focus the name input, and "enter" key saves the setup --- src/favorite-setups.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 819320b..eb0bf93 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -330,6 +330,16 @@ nameInput.required = true; nameInput.minLength = 1; nameInput.maxLength = 30; + nameInput.addEventListener("keyup", function(event) { + // Number 13 is the "Enter" key on the keyboard + if (event.keyCode === 13) { + // Cancel the default action, if needed + event.preventDefault(); + // Trigger the button element with a click + document.getElementById("saveButton").click(); + } + }); + const nameInputCol = document.createElement("td"); nameInputCol.appendChild(nameInput); @@ -417,6 +427,8 @@ // document.querySelector("#favorite-setup-input-skin").value = // user.skin_name; // not really a thing, gotta use a qS probably or parse from LS ID-name map // } + document.getElementById("favorite-setup-name").focus(); + console.log("loaded items: ",user.bait_name, user.base_name, user.weapon_name, user.trinket_name, user.environment_name); }; const resetButton = document.createElement("button"); @@ -639,6 +651,7 @@ document.querySelector("#favorite-setup-name").value = name || ""; editSort = el.sort; // for sorting name-edited setups after the originating setup this button was clicked on console.log("editing setup: "+name+" from sort position "+editSort); + document.getElementById("favorite-setup-name").focus(); // ast location mod }; const deleteButton = document.createElement("button"); From cf71a5e3490efa6422b5c10a7d5fe7a0df4299dd Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 2 Aug 2020 23:12:42 -0400 Subject: [PATCH 14/61] save and load scroll position when re-rendering after saving a setup --- src/favorite-setups.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index eb0bf93..de0f26d 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -403,7 +403,10 @@ } else { localStorage.setItem("favorite-setups-saved", JSON.stringify(obj)); } + var saveScroll = document.getElementById("scroller").scrollTop; // ast location mod render(); + document.getElementById("scroller").scrollTop = saveScroll; + console.log("scroll position before/after: "+saveScroll+" / "+document.getElementById("scroller").scrollTop); } else { alert( "Please enter a name for your setup that is between 1-20 characters" From a121553a6a49f5b19c9117dd7d2a03a446bb494d Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 2 Aug 2020 23:14:20 -0400 Subject: [PATCH 15/61] delete button no long rerenders, deleting setup right from the DOM --- src/favorite-setups.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index de0f26d..a1a0a4d 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -670,7 +670,10 @@ "favorite-setups-saved", JSON.stringify(storedData) ); - render(); + // to delete from DOM without a re-render + var i = this.parentNode.rowIndex; + console.log("deleted '"+name+"' from rowIndex: "+i); + document.getElementById("setupTbody").deleteRow(i); } } }; From 7c6fd2ac0b57372901b302157214b51939e31f74 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 2 Aug 2020 23:16:26 -0400 Subject: [PATCH 16/61] auto save on sort --- src/favorite-setups.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index a1a0a4d..c4527f9 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -743,7 +743,28 @@ placeholder: "ui-state-highlight-tsitu", scroll: true, scrollSensitivity: 20, - scrollSpeed: 20 + scrollSpeed: 20, + update: function() { + const storedRaw = localStorage.getItem("favorite-setups-saved"); + if (storedRaw) { + const storedData = JSON.parse(storedRaw); + const nameSpans = document.querySelectorAll( + ".tsitu-fave-setup-namespan" + ); + if (nameSpans.length === Object.keys(storedData).length) { + for (let i = 0; i < nameSpans.length; i++) { + const name = nameSpans[i].textContent; + if (storedData[name] !== undefined) { + storedData[name].sort = i; + } + } + localStorage.setItem( + "favorite-setups-saved", + JSON.stringify(storedData) + ); + } + } + } }); setupTable.appendChild(setupTbody); setupTableDiv.appendChild(setupTable); From f881936f32f42ee692c3815c8f5706fa1b4e25ce Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 2 Aug 2020 23:19:40 -0400 Subject: [PATCH 17/61] replaced save/reset sort buttons with a toggle sort lock --- src/favorite-setups.js | 58 +++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 37 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index c4527f9..ae1b98d 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -695,43 +695,27 @@ setupTbody.appendChild(setupRow); } - // Save and reset sort buttons - const saveSort = document.createElement("button"); - saveSort.innerText = "Save Sort Order"; - saveSort.onclick = function () { - if (confirm("Are you sure you'd like to save this sort order?")) { - const storedRaw = localStorage.getItem("favorite-setups-saved"); - if (storedRaw) { - const storedData = JSON.parse(storedRaw); - const nameSpans = document.querySelectorAll( - ".tsitu-fave-setup-namespan" - ); - if (nameSpans.length === Object.keys(storedData).length) { - for (let i = 0; i < nameSpans.length; i++) { - const name = nameSpans[i].textContent; - if (storedData[name] !== undefined) { - storedData[name].sort = i; - } - } - localStorage.setItem( - "favorite-setups-saved", - JSON.stringify(storedData) + // Toggle sort lock/unlock + const toggleSort = document.createElement("button"); // ast location mod + toggleSort.id = "toggleSort"; + toggleSort.innerText = "Click to unlock drag and drop sort";// "Reset Sort Order"; + toggleSort.onclick = function () { + var disabled = $(setupTbody).sortable("option", "disabled"); + if (disabled) { + $(setupTbody).sortable("enable"); + toggleSort.innerText = "Drag to sort"; + GM_addStyle( //disable setup name selection when dragging + " .tsitu-fave-setup-namespan { grid-area: a; font-size: inherit; text-align: left; text-overflow: ellipsis; user-select: none;}" + ); + } else { + $(setupTbody).sortable("disable"); + toggleSort.innerText = "Click to unlock sort"; + GM_addStyle( + " .tsitu-fave-setup-namespan { grid-area: a; font-size: inherit; text-align: left; text-overflow: ellipsis; user-select: text;}" ); - render(); - } } - } }; - const resetSort = document.createElement("button"); - resetSort.innerText = "Reset Sort Order"; - resetSort.onclick = function () { - if ( - confirm("Are you sure you'd like to reset to last saved sort order?") - ) { - render(); - } - }; const sortSpan = document.createElement("span"); sortSpan.innerText = "Drag & drop to rearrange setup rows (PC only)"; @@ -742,8 +726,10 @@ $(setupTbody).sortable({ placeholder: "ui-state-highlight-tsitu", scroll: true, - scrollSensitivity: 20, + scrollSensitivity: 80, scrollSpeed: 20, + cursor: "move", + disabled: true, update: function() { const storedRaw = localStorage.getItem("favorite-setups-saved"); if (storedRaw) { @@ -783,9 +769,7 @@ mainDiv.appendChild(document.createElement("br")); mainDiv.appendChild(setupTableDiv); mainDiv.appendChild(document.createElement("br")); - mainDiv.appendChild(saveSort); - mainDiv.appendChild(document.createTextNode("\u00A0\u00A0")); - mainDiv.appendChild(resetSort); + mainDiv.appendChild(toggleSort); mainDiv.appendChild(document.createElement("br")); mainDiv.appendChild(sortSpan); document.body.appendChild(mainDiv); From dfe369bd57dc1ff7649ada7ad8fe2b5d23eaaf39 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 2 Aug 2020 23:21:39 -0400 Subject: [PATCH 18/61] enabling drag for the entire top div --- src/favorite-setups.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index ae1b98d..19f8ff5 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -773,7 +773,7 @@ mainDiv.appendChild(document.createElement("br")); mainDiv.appendChild(sortSpan); document.body.appendChild(mainDiv); - dragElement(mainDiv, titleSpan); + dragElement(mainDiv, topDiv); // Reposition popup based on previous dragged location const posTop = localStorage.getItem("favorite-setup-pos-top"); From 6531f54cc20dcd7c46d11d5143a1a4e1bd2ee877 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Mon, 3 Aug 2020 00:05:16 -0400 Subject: [PATCH 19/61] removed elements and updated id/class to prepare for switch to CSS grid --- src/favorite-setups.js | 49 ++++++++++++------------------------------ 1 file changed, 14 insertions(+), 35 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index eec028d..0abf04a 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -613,15 +613,15 @@ }); const imgSpan = document.createElement("span"); - imgSpan.style.paddingRight = "10px"; + imgSpan.className = "button"; + imgSpan.id = "imgSpan"; + for (let type of elKeys) { if (type === "sort") continue; if (type === "skin") continue; if (type === "location") continue; const img = document.createElement("img"); - img.style.height = "40px"; - img.style.width = "40px"; let item = el[type]; if (data.weapon["Golem Guardian Trap"] !== undefined) { if (type === "weapon") { @@ -661,25 +661,11 @@ const nameSpan = document.createElement("span"); nameSpan.className = "tsitu-fave-setup-namespan"; - nameSpan.style.fontSize = "14px"; nameSpan.textContent = name; - const nameImgCol = document.createElement("td"); - nameImgCol.style.padding = "5px 0px 5px 8px"; - nameImgCol.appendChild(nameSpan); - nameImgCol.appendChild(document.createElement("br")); - nameImgCol.appendChild(imgSpan); - - const armButton = document.createElement("button"); - armButton.style.fontSize = "16px"; - armButton.style.fontWeight = "bold"; - armButton.textContent = "Arm!"; - armButton.onclick = function () { - batchLoad(el.bait, el.base, el.weapon, el.trinket, el.skin); - }; - const editButton = document.createElement("button"); - editButton.style.fontSize = "10px"; + editButton.id = "editButton"; + editButton.className = "button"; editButton.textContent = "✏️"; editButton.onclick = function () { document.querySelector("#favorite-setup-input-cheese").value = @@ -701,8 +687,9 @@ }; const deleteButton = document.createElement("button"); - deleteButton.style.fontSize = "12px"; - deleteButton.textContent = "x"; + deleteButton.id = "deleteButton"; + deleteButton.className = "button"; + deleteButton.textContent = "🗑️"; deleteButton.onclick = function () { if (confirm(`Delete setup '${name}'?`)) { const storedRaw = localStorage.getItem("favorite-setups-saved"); @@ -722,7 +709,7 @@ }; const travelButton = document.createElement("button"); //ast location mod - travelButton.setAttribute("class","travelButton"); + travelButton.className = "travelButton"; travelButton.title = "Left click to travel, Right click to update setup location to current location" if (el.location) { travelButton.textContent = el.location; @@ -733,21 +720,13 @@ app.pages.TravelPage.travel (locMap[el.location].type); }; - const buttonCol = document.createElement("td"); - buttonCol.style.textAlign = "center"; - buttonCol.style.verticalAlign = "middle"; - buttonCol.style.paddingRight = "10px"; - buttonCol.appendChild(editButton); - buttonCol.appendChild(document.createTextNode("\u00A0")); - buttonCol.appendChild(deleteButton); - buttonCol.appendChild(document.createElement("br")); - buttonCol.appendChild(armButton); - buttonCol.appendChild(travelButton); - const setupRow = document.createElement("tr"); setupRow.className = "tsitu-fave-setup-row"; - setupRow.appendChild(nameImgCol); - setupRow.appendChild(buttonCol); + setupRow.appendChild(nameSpan); + setupRow.appendChild(travelButton); + setupRow.appendChild(imgSpan); + setupRow.appendChild(editButton); + setupRow.appendChild(deleteButton); setupTbody.appendChild(setupRow); } From 4318d0a3bcf03e77b2a5477c5b116f57232d41e9 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 2 Aug 2020 23:44:51 -0400 Subject: [PATCH 20/61] moved arm button functionality to setup img span and removed html table elements --- src/favorite-setups.js | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 0abf04a..0844dec 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -657,12 +657,22 @@ "https://www.mousehuntgame.com/images/items/stats/ee8f12ab8e042415063ef4140cefab7b.gif?cv=243"; if (data[type][item]) img.src = data[type][item][1]; imgSpan.appendChild(img); - } + }; + imgSpan.onclick = function () { //ast location mod + batchLoad(el.bait, el.base, el.weapon, el.trinket, el.skin); + console.log("armed '"+name+"': ", el.bait, el.base, el.weapon, el.trinket, el.skin, el.location); + }; const nameSpan = document.createElement("span"); nameSpan.className = "tsitu-fave-setup-namespan"; nameSpan.textContent = name; + const nameImgCol = document.createElement("td"); + nameImgCol.style.padding = "5px 0px 5px 8px"; + nameImgCol.appendChild(nameSpan); + nameImgCol.appendChild(document.createElement("br")); + nameImgCol.appendChild(imgSpan); + const editButton = document.createElement("button"); editButton.id = "editButton"; editButton.className = "button"; @@ -720,6 +730,16 @@ app.pages.TravelPage.travel (locMap[el.location].type); }; + const buttonCol = document.createElement("td"); + buttonCol.style.textAlign = "center"; + buttonCol.style.verticalAlign = "middle"; + buttonCol.style.paddingRight = "10px"; + buttonCol.appendChild(editButton); + buttonCol.appendChild(document.createTextNode("\u00A0")); + buttonCol.appendChild(deleteButton); + buttonCol.appendChild(document.createElement("br")); + buttonCol.appendChild(travelButton); + const setupRow = document.createElement("tr"); setupRow.className = "tsitu-fave-setup-row"; setupRow.appendChild(nameSpan); From eb4709dc3513b89f8b5d3d7804b7bb67143374c1 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Mon, 3 Aug 2020 00:14:37 -0400 Subject: [PATCH 21/61] removing excess elements to clean up UI --- src/favorite-setups.js | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 0844dec..afae865 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -496,15 +496,6 @@ buttonSpan.appendChild(document.createTextNode("\u00A0\u00A0")); buttonSpan.appendChild(resetButton); - // Items last updated span - const timeUpdated = document.createElement("span"); - let tsLatestStr = "N/A"; - const tsLatestRaw = localStorage.getItem("favorite-setup-timestamp"); - if (tsLatestRaw) { - tsLatestStr = new Date(parseInt(tsLatestRaw)).toLocaleString(); - } - timeUpdated.textContent = `[Owned items last updated: ${tsLatestStr}]`; - // Setup table styling const setupTableDiv = document.createElement("div"); setupTableDiv.style.overflowY = "scroll"; @@ -812,21 +803,11 @@ // Append everything to main popup UI mainDiv.appendChild(topDiv); - mainDiv.appendChild(document.createElement("br")); - mainDiv.appendChild(dataListDiv); - mainDiv.appendChild(timeUpdated); - mainDiv.appendChild(document.createElement("br")); - mainDiv.appendChild(document.createElement("br")); mainDiv.appendChild(buttonSpan); - mainDiv.appendChild(document.createElement("br")); - mainDiv.appendChild(document.createElement("br")); + mainDiv.appendChild(dataListDiv); mainDiv.appendChild(setupSelectorDiv); - mainDiv.appendChild(document.createElement("br")); mainDiv.appendChild(setupTableDiv); - mainDiv.appendChild(document.createElement("br")); mainDiv.appendChild(toggleSort); - mainDiv.appendChild(document.createElement("br")); - mainDiv.appendChild(sortSpan); document.body.appendChild(mainDiv); dragElement(mainDiv, topDiv); From ca57288d1d9d26237e8bdda7b272c6905e82a2b4 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Mon, 3 Aug 2020 00:15:17 -0400 Subject: [PATCH 22/61] removing html table elements to prepare for CSS grid --- src/favorite-setups.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index afae865..e4e0753 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -658,12 +658,6 @@ nameSpan.className = "tsitu-fave-setup-namespan"; nameSpan.textContent = name; - const nameImgCol = document.createElement("td"); - nameImgCol.style.padding = "5px 0px 5px 8px"; - nameImgCol.appendChild(nameSpan); - nameImgCol.appendChild(document.createElement("br")); - nameImgCol.appendChild(imgSpan); - const editButton = document.createElement("button"); editButton.id = "editButton"; editButton.className = "button"; @@ -721,16 +715,6 @@ app.pages.TravelPage.travel (locMap[el.location].type); }; - const buttonCol = document.createElement("td"); - buttonCol.style.textAlign = "center"; - buttonCol.style.verticalAlign = "middle"; - buttonCol.style.paddingRight = "10px"; - buttonCol.appendChild(editButton); - buttonCol.appendChild(document.createTextNode("\u00A0")); - buttonCol.appendChild(deleteButton); - buttonCol.appendChild(document.createElement("br")); - buttonCol.appendChild(travelButton); - const setupRow = document.createElement("tr"); setupRow.className = "tsitu-fave-setup-row"; setupRow.appendChild(nameSpan); From 682ae8620c424dac1970202ff99cd1cddd159204 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Mon, 3 Aug 2020 00:24:25 -0400 Subject: [PATCH 23/61] deleting space --- src/favorite-setups.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index e4e0753..9ff0870 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -170,7 +170,6 @@ const rawData = localStorage.getItem("tsitu-owned-components"); var editSort = -1; // ast location mod. change to -2 if you want new setups to appear above location sorted setups until they are manually sorted. - const locMap = JSON.parse(localStorage.getItem("ast-location-mapping")); // ast location mod // aliases for locations with multiple environment_names for the same environment_type locMap["Cursed City"] = {"type": "lost_city"}; From c4c13dc44762297b4228ac670b4a496bedd680d5 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Mon, 3 Aug 2020 00:29:37 -0400 Subject: [PATCH 24/61] added CSS style sheets, implementing table grid --- src/favorite-setups.js | 232 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 231 insertions(+), 1 deletion(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 9ff0870..ab16317 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -8,7 +8,237 @@ // @match http://www.mousehuntgame.com/* // @match https://www.mousehuntgame.com/* // ==/UserScript== - +GM_addStyle ( ` +#tsitu-fave-setups { + background-color: #F5F5F5; + position: fixed; + z-index: 42; + left: 5px; + top: 5px; + border: solid 3px #696969; + padding: 10px; + text-align: center; + border-radius: 10px; + height: 95vh; + overflow: hidden; + display: flex; + flex-direction: column; + font-size: inherit; + resize: both; + min-width: min-content; + min-height: 25vh; +} +} +#tsitu-fave-setups button { + cursor: pointer; +} +#tsitu-fave-setups .title { + font-weight: bold; + font-size: 160%; + text-decoration: underline; +} +#tsitu-fave-setups #close-button { + float: right; + font-size: 15px; + color: rgba(690,0,0,0.69); + padding: 1px 5px; + margin: -11px; + //background-color: rgba(420,0,0,0.420); + //border-radius: 0px 5px; + //border: none; +} + +.btn-group { + display: inline-flex; + justify-content: center; + padding: 8px 0px; +} +.btn-group .button { + margin: -1px; + flex-grow: 1; + font-size: 100%; +} +#saveButton { + font-weight: bold; + font-size: 120%; +} + +.favInput { + //display: flex; + //flex-grow: 1; + width: calc(100% - 5px*2 - 2px); + padding: 1px 5px; + //justify-content: center; + margin: -1px -1px; + font-size: 110%; +} + +#collapsible { + display: none; +} + +#dataListDiv { + max-height: 0px; + overflow-y: hidden; + opacity: 1; + transition: max-height 250ms ease-in-out, opacity 500ms; +} + +#collapsible:checked + #dataListDiv { + max-height: 100%; + overflow-y: visible; + opacity: 1; +} + +#dataListTable { + width: 100%; +} + +.setupSelectorDiv { + padding-bottom: 5px; +} + +#scroller { + /* fill parent */ + display: block; + width: 100%; + height: 100%; + /* set to some transparent color */ + border-color: rgba(0, 0, 0, 0.0); + transition: border-color 300ms ease-in-out; + overflow: auto; + padding-right: 2px; + margin-bottom: 5px; +} + +#scroller:hover { + /* the color we want the scrollbar on hover */ + border-color: rgba(0, 0, 0, 0.3); +} + +#scroller::-webkit-scrollbar, +#scroller::-webkit-scrollbar-thumb, +#scroller::-webkit-scrollbar-corner { + /* add border to act as background-color */ + border-right-style: outset; + border-right-width: 3px; + /* inherit border-color to inherit transitions */ + border-color: inherit; +} +#scroller::-webkit-scrollbar { + width: 3px; + height: 3px; + border-color: rgba(0,0,0,0); +} +#scroller::-webkit-scrollbar-thumb { + border-color: inherit; + border-radius: 50px; +} + +#scroller::-webkit-scrollbar-thumb:active { + border-color: rgba(0, 0, 0, 0.5); +} + +// #setupTableDiv { +// overflow-y: scroll; +// max-height: 100%; +// } +// #setupTableDiv::-webkit-scrollbar +// { +// width: 5px; +// background-color: #F5F5F5; +// } +// #setupTableDiv::-webkit-scrollbar-thumb +// { +// background-color: #696969; +// border-radius: 420px; +// } +#setupTbody tr:nth-child(odd){ + background-color: rgba(0, 0, 0, 0.25); +} +#setupTbody tr:nth-child(even){ + background-color: rgba(0, 0, 0, 0.069); +} +.tsitu-fave-setup-row { + display: grid; + align-items: stretch; + grid-template-columns: 1fr auto 2em; + grid-template-rows: 50% 50%; + grid-template-areas: + "a c d" + "b c e"; + padding: 3px; + border-radius: 3px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.tsitu-fave-setup-namespan { + grid-area: a; + font-size: inherit; + text-align: left; + text-overflow: ellipsis; + padding-top: 3px; + padding-left: 3px; + margin-right: -3px; +} +.travelButton { + grid-area: b; + overflow: hidden; + padding: 0px 2px; + font-size: inherit; + display: flex; + align-items: center; + justify-content: center; + width: auto; +} +#imgSpan { + grid-area: c; + //align-items: center; + max-height: 100%; + max-width: max-content; + min-width: max-content; + padding: 0px 0px 0px 0px; + margin-left: 3px; + margin-right: -1px; + //justify-items: center; + overflow: hidden; +} +#imgSpan img { + max-height: 100%; + max-width: 100%; + height: 3.2vh; /* change this to change the overall size which should scale with this */ +// width: auto; +// object-fit: scale-down; + margin-bottom: -3px; +} +#editButton { + grid-area: d; + text-align: center; + font-size: inherit; + padding: 0; + margin-bottom: -1px; +} +#deleteButton { + grid-area: e; + text-align: center; + font-size: inherit; + padding: 0; + margin-top: -1px; +} +#resizeButton { + display: flex; + flex-direction: right; + float: right; + font-size: 15px; + color: rgba(690,0,0,0.69); + padding: 1px 5px; + margin: -11px; + background-color: rgba(420,0,0,0.420); + border-radius: 5px 0px; + border: none; +} +`); (function () { // Observe Camp page for mutations (to re-inject button) const observerTarget = document.querySelector(".mousehuntPage-content"); From 00f70fb25c00571d874dfd06c0b545dbba5015c1 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Mon, 3 Aug 2020 00:32:20 -0400 Subject: [PATCH 25/61] added scroller wrapper to setup table --- src/favorite-setups.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index ab16317..6555f38 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -821,6 +821,12 @@ GM_addStyle ( ` // TODO: [med] Mobile UX for drag & drop as well as scrollable div (jquery-ui-touch-punch did not work for simulating touch events) // TODO: [low] Skin implementation/checks (in-progress, but either save for later or scrap entirely since use case is minimal) + const scroller = document.createElement("div"); + scroller.id = "scroller"; + + const setupTableDiv = document.createElement("div"); + setupTableDiv.id = "setupTableDiv"; + // Generate and append each saved setup as a new savedSetupSortKeys.forEach(name => { generateRow(name); @@ -1019,7 +1025,8 @@ GM_addStyle ( ` mainDiv.appendChild(buttonSpan); mainDiv.appendChild(dataListDiv); mainDiv.appendChild(setupSelectorDiv); - mainDiv.appendChild(setupTableDiv); + scroller.appendChild(setupTableDiv); + mainDiv.appendChild(scroller); mainDiv.appendChild(toggleSort); document.body.appendChild(mainDiv); dragElement(mainDiv, topDiv); From dcdc27d23fc57f6439cf6f541f4d004b79edecab Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Mon, 3 Aug 2020 00:33:21 -0400 Subject: [PATCH 26/61] bug fix: removed old setupTableDiv --- src/favorite-setups.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 6555f38..6de5fff 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -726,9 +726,6 @@ GM_addStyle ( ` buttonSpan.appendChild(resetButton); // Setup table styling - const setupTableDiv = document.createElement("div"); - setupTableDiv.style.overflowY = "scroll"; - setupTableDiv.style.height = "50vh"; const setupTable = document.createElement("table"); const setupTbody = document.createElement("tbody"); From 82b9e6487e722ca4489b1195ed5e79e8ee7bf102 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Mon, 3 Aug 2020 00:44:41 -0400 Subject: [PATCH 27/61] removing in-line styles, assigning ids and classes to format in the CSS --- src/favorite-setups.js | 66 ++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 6de5fff..6449c00 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -507,32 +507,19 @@ GM_addStyle ( ` // Main popup styling const mainDiv = document.createElement("div"); mainDiv.id = "tsitu-fave-setups"; - mainDiv.style.backgroundColor = "#F5F5F5"; - mainDiv.style.position = "fixed"; - mainDiv.style.zIndex = "42"; - mainDiv.style.left = "5px"; - mainDiv.style.top = "5px"; - mainDiv.style.border = "solid 3px #696969"; - mainDiv.style.borderRadius = "20px"; - mainDiv.style.padding = "10px"; - mainDiv.style.textAlign = "center"; // Top div styling (close button, title, drag instructions) const topDiv = document.createElement("div"); + topDiv.id = "header" + topDiv.title = "Drag header to reposition this popup"; const titleSpan = document.createElement("span"); - titleSpan.style.fontWeight = "bold"; - titleSpan.style.fontSize = "18px"; - titleSpan.style.textDecoration = "underline"; - titleSpan.style.paddingLeft = "20px"; + titleSpan.className = "title"; titleSpan.innerText = "Favorite Setups"; - const dragSpan = document.createElement("span"); - dragSpan.innerText = "(Drag title to reposition this popup)"; const closeButton = document.createElement("button"); - closeButton.style.float = "right"; - closeButton.style.fontSize = "8px"; - closeButton.textContent = "x"; + closeButton.id = "close-button"; + closeButton.textContent = "×"; closeButton.onclick = function () { document.body.removeChild(mainDiv); localStorage.setItem('showSetups', "N"); @@ -540,12 +527,11 @@ GM_addStyle ( ` topDiv.appendChild(closeButton); topDiv.appendChild(titleSpan); - topDiv.appendChild(document.createElement("br")); - topDiv.appendChild(dragSpan); // Build dropdowns const dataListTable = document.createElement("table"); - dataListTable.style.margin = "0 auto"; + dataListTable.id = "dataListTable"; + for (let rawCategory of dataKeys) { let category = rawCategory; if (category === "sort") continue; @@ -564,9 +550,10 @@ GM_addStyle ( ` const dataListLabel = document.createElement("label"); dataListLabel.htmlFor = `favorite-setup-input-${category}`; dataListLabel.textContent = `Select ${category}: `; - const dataListInput = document.createElement("input"); dataListInput.id = `favorite-setup-input-${category}`; + dataListInput.className = "favInput"; + dataListInput.setAttribute("placeholder", `Select ${category}: `); dataListInput.setAttribute( "list", `favorite-setup-datalist-${category}` @@ -578,8 +565,14 @@ GM_addStyle ( ` const inputCol = document.createElement("td"); labelCol.appendChild(dataList); labelCol.appendChild(dataListLabel); + inputCol.className = "inputCol"; + inputCol.appendChild(dataList); inputCol.appendChild(dataListInput); dataListRow.appendChild(labelCol); + + const dataListRow = document.createElement("tr"); + dataListRow.className = "dataListRow"; + dataListRow.appendChild(inputCol); dataListTable.appendChild(dataListRow); } @@ -588,10 +581,11 @@ GM_addStyle ( ` nameSpan.textContent = "Setup name: "; const nameSpanCol = document.createElement("td"); nameSpanCol.appendChild(nameSpan); - const nameInput = document.createElement("input"); nameInput.type = "text"; nameInput.id = "favorite-setup-name"; + nameInput.className = "favInput"; + nameInput.setAttribute("placeholder", "Setup name: "); nameInput.required = true; nameInput.minLength = 1; nameInput.maxLength = 30; @@ -612,13 +606,15 @@ GM_addStyle ( ` nameRow.appendChild(nameSpanCol); nameRow.appendChild(nameInputCol); dataListTable.appendChild(nameRow); + const dataListDiv = document.createElement("div"); + dataListDiv.id = "dataListDiv"; dataListDiv.appendChild(dataListTable); // Import setup / Save setup / Reset input buttons const saveButton = document.createElement("button"); - saveButton.style.fontSize = "15px"; - saveButton.style.fontWeight = "bold"; + saveButton.id = "saveButton"; + saveButton.className = "button"; saveButton.textContent = "Save Setup"; saveButton.onclick = function () { const bait = document.querySelector("#favorite-setup-input-cheese") @@ -682,7 +678,8 @@ GM_addStyle ( ` }; const loadButton = document.createElement("button"); - loadButton.style.fontSize = "11px"; + loadButton.id = "loadButton"; + loadButton.className = "button"; loadButton.textContent = "Import setup"; loadButton.onclick = function () { document.querySelector("#favorite-setup-input-cheese").value = @@ -704,7 +701,7 @@ GM_addStyle ( ` }; const resetButton = document.createElement("button"); - resetButton.style.fontSize = "11px"; + resetButton.className = "button"; resetButton.textContent = "Reset inputs"; resetButton.onclick = function () { document.querySelector("#favorite-setup-input-cheese").value = ""; @@ -717,18 +714,11 @@ GM_addStyle ( ` }; const buttonSpan = document.createElement("span"); - buttonSpan.style.paddingTop = "8px"; - buttonSpan.style.textAlign = "center"; + buttonSpan.className = "btn-group"; buttonSpan.appendChild(loadButton); - buttonSpan.appendChild(document.createTextNode("\u00A0\u00A0")); buttonSpan.appendChild(saveButton); - buttonSpan.appendChild(document.createTextNode("\u00A0\u00A0")); buttonSpan.appendChild(resetButton); - // Setup table styling - const setupTable = document.createElement("table"); - const setupTbody = document.createElement("tbody"); - // Sort existing saved setups const savedRaw = localStorage.getItem("favorite-setups-saved"); const savedSetups = JSON.parse(savedRaw) || {}; @@ -751,6 +741,8 @@ GM_addStyle ( ` const setupSelectorInput = document.createElement("input"); setupSelectorInput.id = "favorite-setup-selector-input"; + setupSelectorInput.className = "favInput"; + setupSelectorInput.setAttribute("placeholder", "Jump to setup:"); setupSelectorInput.setAttribute("list", "favorite-setup-selector"); setupSelectorInput.oninput = function () { const name = setupSelectorInput.value; @@ -820,6 +812,10 @@ GM_addStyle ( ` const scroller = document.createElement("div"); scroller.id = "scroller"; + // Setup table styling + const setupTable = document.createElement("table"); + const setupTbody = document.createElement("tbody"); + setupTbody.id = "setupTbody"; const setupTableDiv = document.createElement("div"); setupTableDiv.id = "setupTableDiv"; From 6315755bc2b6b9551a1a69541fcb3dacd9133a81 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Mon, 3 Aug 2020 00:45:03 -0400 Subject: [PATCH 28/61] replacing labels with input placeholders --- src/favorite-setups.js | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 6449c00..51f04ab 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -547,9 +547,6 @@ GM_addStyle ( ` dataList.appendChild(option); } - const dataListLabel = document.createElement("label"); - dataListLabel.htmlFor = `favorite-setup-input-${category}`; - dataListLabel.textContent = `Select ${category}: `; const dataListInput = document.createElement("input"); dataListInput.id = `favorite-setup-input-${category}`; dataListInput.className = "favInput"; @@ -559,16 +556,10 @@ GM_addStyle ( ` `favorite-setup-datalist-${category}` ); - const dataListRow = document.createElement("tr"); - const labelCol = document.createElement("td"); - labelCol.style.paddingRight = "8px"; const inputCol = document.createElement("td"); - labelCol.appendChild(dataList); - labelCol.appendChild(dataListLabel); inputCol.className = "inputCol"; inputCol.appendChild(dataList); inputCol.appendChild(dataListInput); - dataListRow.appendChild(labelCol); const dataListRow = document.createElement("tr"); dataListRow.className = "dataListRow"; @@ -577,10 +568,6 @@ GM_addStyle ( ` dataListTable.appendChild(dataListRow); } - const nameSpan = document.createElement("span"); - nameSpan.textContent = "Setup name: "; - const nameSpanCol = document.createElement("td"); - nameSpanCol.appendChild(nameSpan); const nameInput = document.createElement("input"); nameInput.type = "text"; nameInput.id = "favorite-setup-name"; @@ -603,7 +590,6 @@ GM_addStyle ( ` nameInputCol.appendChild(nameInput); const nameRow = document.createElement("tr"); - nameRow.appendChild(nameSpanCol); nameRow.appendChild(nameInputCol); dataListTable.appendChild(nameRow); @@ -735,10 +721,6 @@ GM_addStyle ( ` setupSelector.appendChild(option); } - const setupSelectorLabel = document.createElement("label"); - setupSelectorLabel.htmlFor = "favorite-setup-selector-input"; - setupSelectorLabel.textContent = `Jump to setup: `; - const setupSelectorInput = document.createElement("input"); setupSelectorInput.id = "favorite-setup-selector-input"; setupSelectorInput.className = "favInput"; @@ -800,7 +782,6 @@ GM_addStyle ( ` const setupSelectorDiv = document.createElement("div"); setupSelectorDiv.appendChild(setupSelector); - setupSelectorDiv.appendChild(setupSelectorLabel); setupSelectorDiv.appendChild(setupSelectorInput); // TODO: Improve async logic, probably await completion of a component switch otherwise might overlap and/or silently fail From c93de6d2bdbe015031d44212a1b00b53e8fc9664 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Mon, 3 Aug 2020 00:53:02 -0400 Subject: [PATCH 29/61] bug fix: missed id assignment --- src/favorite-setups.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 51f04ab..8f5558a 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -781,6 +781,7 @@ GM_addStyle ( ` }; const setupSelectorDiv = document.createElement("div"); + setupSelectorDiv.className = "setupSelectorDiv"; setupSelectorDiv.appendChild(setupSelector); setupSelectorDiv.appendChild(setupSelectorInput); From 898fdca456e0f1ae04819910b2a1ba3040c824fa Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Mon, 3 Aug 2020 00:53:02 -0400 Subject: [PATCH 30/61] bug fix: missed id assignment From fe3f6b5ada12345ca0176032a7a2ebb9550e7fde Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Mon, 3 Aug 2020 00:53:02 -0400 Subject: [PATCH 31/61] collapsible data list section --- src/favorite-setups.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 51f04ab..5fe4a54 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -593,6 +593,11 @@ GM_addStyle ( ` nameRow.appendChild(nameInputCol); dataListTable.appendChild(nameRow); + // Hidden checkbox to toggle dataListDiv visibility + const collapsibleCheckbox = document.createElement("input"); + collapsibleCheckbox.id = "collapsible"; + collapsibleCheckbox.type = "checkbox"; + const dataListDiv = document.createElement("div"); dataListDiv.id = "dataListDiv"; dataListDiv.appendChild(dataListTable); @@ -658,7 +663,7 @@ GM_addStyle ( ` console.log("scroll position before/after: "+saveScroll+" / "+document.getElementById("scroller").scrollTop); } else { alert( - "Please enter a name for your setup that is between 1-20 characters" + "Please enter a name for your setup that is between 1-30 characters" ); } }; @@ -668,6 +673,7 @@ GM_addStyle ( ` loadButton.className = "button"; loadButton.textContent = "Import setup"; loadButton.onclick = function () { + document.querySelector("#collapsible").checked = true; // to toggle collapsible document.querySelector("#favorite-setup-input-cheese").value = user.bait_name || ""; document.querySelector("#favorite-setup-input-base").value = @@ -690,6 +696,7 @@ GM_addStyle ( ` resetButton.className = "button"; resetButton.textContent = "Reset inputs"; resetButton.onclick = function () { + document.querySelector("#collapsible").checked = false; // to toggle collapsible document.querySelector("#favorite-setup-input-cheese").value = ""; document.querySelector("#favorite-setup-input-base").value = ""; document.querySelector("#favorite-setup-input-weapon").value = ""; @@ -872,6 +879,7 @@ GM_addStyle ( ` editButton.className = "button"; editButton.textContent = "✏️"; editButton.onclick = function () { + document.querySelector("#collapsible").checked = true; document.querySelector("#favorite-setup-input-cheese").value = el.bait === "N/A" ? "" : el.bait; document.querySelector("#favorite-setup-input-base").value = From 10b5716e04561fdde22f56a55743af7799eea99b Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Mon, 3 Aug 2020 00:53:02 -0400 Subject: [PATCH 32/61] adding disarm button --- src/favorite-setups.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 5fe4a54..0e9d879 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -706,11 +706,19 @@ GM_addStyle ( ` document.querySelector("#favorite-setup-input-location").value = ""; }; + const disarmButton = document.createElement("button"); + disarmButton.className = "button"; + disarmButton.textContent = "Disarm"; + disarmButton.onclick = function () { + hg.utils.TrapControl.disarmBait().go(); + }; + const buttonSpan = document.createElement("span"); buttonSpan.className = "btn-group"; buttonSpan.appendChild(loadButton); buttonSpan.appendChild(saveButton); buttonSpan.appendChild(resetButton); + buttonSpan.appendChild(disarmButton); // Sort existing saved setups const savedRaw = localStorage.getItem("favorite-setups-saved"); From 898f6986f8fbced24362497526852e0e1b1b2049 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Mon, 3 Aug 2020 00:53:02 -0400 Subject: [PATCH 33/61] right click function: add location to existing setups to ease migration --- src/favorite-setups.js | 58 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 0e9d879..840e40c 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -939,6 +939,61 @@ GM_addStyle ( ` travelButton.onclick = function () { app.pages.TravelPage.travel (locMap[el.location].type); }; + //refresh setup with location to ease migration of old setups + travelButton.oncontextmenu = function() { + const bait = el.bait; + const base = el.base; + const weapon = el.weapon; + const charm = el.trinket; + const location = user.environment_name // ast location mod + + if (name.length >= 1 && name.length <= 30) { + const obj = {}; + obj[name] = { + bait: "N/A", + base: "N/A", + weapon: "N/A", + trinket: "N/A", + skin: "N/A" + ,location: "N/A" // ast location mod + }; + + if (data.bait[bait] !== undefined) obj[name].bait = bait; + if (data.base[base] !== undefined) obj[name].base = base; + if (data.weapon[weapon] !== undefined) obj[name].weapon = weapon; + if (data.trinket[charm] !== undefined) obj[name].trinket = charm; + // if (data.skin[skin] !== undefined) obj[name].skin = skin; + obj[name].location = location; // ast location mod + obj[name].sort = editSort; // ast location mod + console.log("saved setup '"+name+"': "+JSON.stringify(obj[name])); // ast location mod + + const storedRaw = localStorage.getItem("favorite-setups-saved"); + if (storedRaw) { + const storedData = JSON.parse(storedRaw); + if (storedData[name] !== undefined) { + if (confirm(`Do you want to overwrite saved setup '${name}'?`)) { + obj[name].sort = storedData[name].sort; + } else { + return; + } + } + storedData[name] = obj[name]; + localStorage.setItem( + "favorite-setups-saved", + JSON.stringify(storedData) + ); + } else { + localStorage.setItem("favorite-setups-saved", JSON.stringify(obj)); + } + var saveScroll = document.getElementById("scroller").scrollTop; // ast location mod + render(); + document.getElementById("scroller").scrollTop = saveScroll; + } else { + alert( + "Please enter a name for your setup that is between 1-20 characters" + ); + }; + }; const setupRow = document.createElement("tr"); setupRow.className = "tsitu-fave-setup-row"; @@ -971,9 +1026,6 @@ GM_addStyle ( ` } }; - const sortSpan = document.createElement("span"); - sortSpan.innerText = "Drag & drop to rearrange setup rows (PC only)"; - // Make the table drag & drop-able via jQuery sortable() GM_addStyle( ".ui-state-highlight-tsitu { height: 68px; background-color: #FAFFAF; }" From 48517a1d904dac0bd53e777c53b9f92bd0d3de05 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Mon, 3 Aug 2020 00:53:02 -0400 Subject: [PATCH 34/61] missed addition to make collapsible code work --- src/favorite-setups.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 840e40c..aac0512 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -1065,6 +1065,7 @@ GM_addStyle ( ` // Append everything to main popup UI mainDiv.appendChild(topDiv); mainDiv.appendChild(buttonSpan); + mainDiv.appendChild(collapsibleCheckbox); mainDiv.appendChild(dataListDiv); mainDiv.appendChild(setupSelectorDiv); scroller.appendChild(setupTableDiv); From ec6311fd4c1931e5ed427303bc9bc935a1041313 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Mon, 3 Aug 2020 00:53:02 -0400 Subject: [PATCH 35/61] imgSpan to button for increased clarity --- src/favorite-setups.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 45ef47a..85dcd6d 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -828,7 +828,7 @@ GM_addStyle ( ` return displayOrder[a] - displayOrder[b]; }); - const imgSpan = document.createElement("span"); + const imgSpan = document.createElement("button"); imgSpan.className = "button"; imgSpan.id = "imgSpan"; From ad59e96b1d7ea86a46ab9fbb3ea787f9e2c04b16 Mon Sep 17 00:00:00 2001 From: Joshua Cheng <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Mon, 3 Aug 2020 00:53:02 -0400 Subject: [PATCH 36/61] automatically sort setups with current location to the top --- src/favorite-setups.js | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index b2faaf2..18b2d75 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -583,8 +583,26 @@ // TODO: [med] Mobile UX for drag & drop as well as scrollable div (jquery-ui-touch-punch did not work for simulating touch events) // TODO: [low] Skin implementation/checks (in-progress, but either save for later or scrap entirely since use case is minimal) - // Generate and append each saved setup as a new + // Sort setups from the current location to the top of the list + function locSort (name) { + //console.log("saved loc: "+savedSetups[name].location, "\n loc bool: "+!!savedSetups[name].location, "\n current loc: "+user.environment_name, "\n current loc bool: "+!!user.environment_name, "\n current loc is saved loc: "+(user.environment_name===savedSetups[name].location), "\n test: "+(!!savedSetups[name].location && user.environment_name == savedSetups[name].location)); + if (user.environment_name === savedSetups[name].location) { + //console.log("saved loc: "+savedSetups[name].location, "\n loc bool: "+!!savedSetups[name].location, "\n current loc: "+user.environment_name, "\n current loc bool: "+!!user.environment_name, "\n current loc is saved loc: "+(user.environment_name===savedSetups[name].location), "\n test: "+(!!savedSetups[name].location && user.environment_name == savedSetups[name].location)); + savedSetups[name].sort = -1; + //console.log("location sorted setup: "+savedSetups[name]) + }; + }; + savedSetupSortKeys.forEach(name => { + locSort(name); + }); + + const sortedSetupKeys = Object.keys(savedSetups).sort((a, b) => { + return savedSetups[a].sort - savedSetups[b].sort; + }); + + // Generate and append each saved setup as a new + sortedSetupKeys.forEach(name => { generateRow(name); }); From 629ba0f8c2cf340b2a91e14d6914cad6deb7f1d2 Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Mon, 11 Apr 2022 03:23:15 -0400 Subject: [PATCH 37/61] Updated header info for Greasy Fork --- src/favorite-setups.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index d37a158..2a60a74 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -1,8 +1,8 @@ // ==UserScript== -// @name MouseHunt - Favorite Setups -// @author Tran Situ (tsitu) -// @namespace https://greasyfork.org/en/users/232363-tsitu -// @version 1.5.1 +// @name MouseHunt - Favorite Setups+ +// @author Tran Situ (tsitu), asterios +// @namespace https://greasyfork.org/en/users/900615-personalpalimpsest +// @version 2.0.0 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* From c8df4019b559298f33ec8c54e86900dc94dbb7d3 Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Mon, 11 Apr 2022 12:26:36 -0400 Subject: [PATCH 38/61] removed author of original script, due to advice that they may not want to be contacted to support this fork --- src/favorite-setups.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 2a60a74..e542f75 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -1,8 +1,8 @@ // ==UserScript== // @name MouseHunt - Favorite Setups+ -// @author Tran Situ (tsitu), asterios +// @author PersonalPalimpsest (asterios) // @namespace https://greasyfork.org/en/users/900615-personalpalimpsest -// @version 2.0.0 +// @version 2.0.1 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* From 24be512d26127b0f6e5c45eed22cc52a6c1bd5a7 Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 13 Nov 2022 18:08:14 -0500 Subject: [PATCH 39/61] minor fix to scrollbars --- src/favorite-setups.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index e542f75..4ffbbd9 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -2,7 +2,7 @@ // @name MouseHunt - Favorite Setups+ // @author PersonalPalimpsest (asterios) // @namespace https://greasyfork.org/en/users/900615-personalpalimpsest -// @version 2.0.1 +// @version 2.0.2 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* @@ -106,7 +106,7 @@ GM_addStyle ( ` /* set to some transparent color */ border-color: rgba(0, 0, 0, 0.0); transition: border-color 300ms ease-in-out; - overflow: auto; + overflow: scroll; padding-right: 2px; margin-bottom: 5px; } From 476e656aaa98903b7fe2022ec6665c38cb56ca5e Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 13 Nov 2022 18:10:04 -0500 Subject: [PATCH 40/61] Create favorite-setups-README.md --- favorite-setups-README.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 favorite-setups-README.md diff --git a/favorite-setups-README.md b/favorite-setups-README.md new file mode 100644 index 0000000..f18005e --- /dev/null +++ b/favorite-setups-README.md @@ -0,0 +1,35 @@ +# MouseHunt - Favorite Setups+ + +Based on the [script from tsitu](https://greasyfork.org/en/scripts/388403-mousehunt-favorite-setups), developed with his advice. + +Allows the import/edit/saving of setups along with their associated locations, for quick location + setup changes. Designed with a dense UI to maximize setups visible at once, and with drag/drop support for reorganizing. + +Adds a bunch of features and densifies the UI for my personal preference. Differences from tsitu's script: + +**Known issues:** +- jump to setup search doesn't seem to work +- resizing isn't "sticky" across refreshes +- CSoS doesn't work, has to be saved as SoS +- location based auto-sorting gets funky when new setups are added and manual sorts haven't been done yet +- if you want to help fix these problems or anything else, here's [the script on my github](https://github.com/PersonalPalimpsest/MH-Userscripts/blob/master/src/favorite-setups.js) + +**Location-based features:** +- added location when saving and loading setups, along with a travel button for that location for each setup +- right click function added to travel buttons to add the current location to a setup. helpful for migrating old setups so you don't have to recreate from scratch +- auto sorts setups with location = current location to the top. Does not update when you travel without reloading the page or the pop-up + +**UX:** +- 'Arm' button combined with the setup icons +- retain open/closed status of the pop-up across page loads +- increased setup char limit to 30 +- saving an edited setup with a different name now saves it in the sort order right after the initial setup +- load and edit buttons now bring the cursor focus to the name field, allowing for typing it in right away +- "enter" key while focus is in the name field clicks the save button +- scroll position is now retained when saving a setup +- deleting a setup happens instantly +- sorting setups saves automatically +- a toggle lock was implemented to combat unintended sorting, and the save/reset sort buttons were removed +- the modal window can now be dragged by selecting anywhere in the top div instead of just the title text +- collapsible data list section for more setups visible at once +- adding disarm button +- general CSS style changes to remove elements, shrink borders and padding, densify the display of setups, and other backend cleanup/rejigging From 8abec96b466556c9784e71a1e8c4e80ee0dafd69 Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Fri, 31 Mar 2023 13:05:29 -0400 Subject: [PATCH 41/61] Re-renders (and sorts) on travel --- src/favorite-setups.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 4ffbbd9..8a670fb 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -2,7 +2,7 @@ // @name MouseHunt - Favorite Setups+ // @author PersonalPalimpsest (asterios) // @namespace https://greasyfork.org/en/users/900615-personalpalimpsest -// @version 2.0.2 +// @version 2.1.0 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* @@ -207,7 +207,7 @@ GM_addStyle ( ` #imgSpan img { max-height: 100%; max-width: 100%; - height: 3.2vh; /* change this to change the overall size which should scale with this */ + height: 3.2vh; /* change this to change the overall size which should scale with this */ // width: auto; // object-fit: scale-down; margin-bottom: -3px; @@ -311,6 +311,19 @@ GM_addStyle ( ` }; xhr.send(); + // Re-render on location change + const travelObserver = XMLHttpRequest.prototype.open; + XMLHttpRequest.prototype.open = function () { + this.addEventListener('load', function () { + if (this.responseURL == `https://www.mousehuntgame.com/managers/ajax/users/changeenvironment.php`) { + console.log('Travel detected'); + render(); + render(); + } + }) + travelObserver.apply(this, arguments); + } + const originalOpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function () { this.addEventListener("load", function () { @@ -487,6 +500,7 @@ GM_addStyle ( ` await hg.utils.TrapControl.disarmItem(classification).go(); } else { await hg.utils.TrapControl.armItem(id, classification).go(); + // console.log(id, classification); // const testEl = document.createElement("a"); // testEl.setAttribute("data-item-id", id); // console.log(testEl); From 664386ea37bc745b818d9b76133474e4409b3ba6 Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Fri, 31 Mar 2023 14:10:40 -0400 Subject: [PATCH 42/61] Saves resizing of the popup --- src/favorite-setups.js | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 8a670fb..97570a7 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -2,7 +2,7 @@ // @name MouseHunt - Favorite Setups+ // @author PersonalPalimpsest (asterios) // @namespace https://greasyfork.org/en/users/900615-personalpalimpsest -// @version 2.1.0 +// @version 2.2.0 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* @@ -12,21 +12,20 @@ GM_addStyle ( ` #tsitu-fave-setups { background-color: #F5F5F5; position: fixed; - z-index: 42; + z-index: 69420; left: 5px; top: 5px; border: solid 3px #696969; padding: 10px; text-align: center; border-radius: 10px; - height: 95vh; + max-height: 95vh; overflow: hidden; display: flex; flex-direction: column; font-size: inherit; resize: both; min-width: min-content; - min-height: 25vh; } } #tsitu-fave-setups button { @@ -106,7 +105,7 @@ GM_addStyle ( ` /* set to some transparent color */ border-color: rgba(0, 0, 0, 0.0); transition: border-color 300ms ease-in-out; - overflow: scroll; + overflow-y: scroll; padding-right: 2px; margin-bottom: 5px; } @@ -756,9 +755,9 @@ GM_addStyle ( ` setupSelectorInput.setAttribute("placeholder", "Jump to setup:"); setupSelectorInput.setAttribute("list", "favorite-setup-selector"); setupSelectorInput.oninput = function () { + console.log('testing selector input'); const name = setupSelectorInput.value; - if (savedSetups[name] !== undefined) { - const rows = document.querySelectorAll("tr.tsitu-fave-setup-row"); + if (savedSetups[name] !== undefined) { const rows = document.querySelectorAll("tr.tsitu-fave-setup-row"); rows.forEach(el => { el.style.backgroundColor = ""; }); @@ -1105,6 +1104,20 @@ GM_addStyle ( ` mainDiv.appendChild(scroller); mainDiv.appendChild(toggleSort); document.body.appendChild(mainDiv); + + const resizeObserver = new ResizeObserver(entries => { + for (let entry of entries) { + // console.log(`${entry.target.style.height} h + ${entry.target.style.width} w`); + localStorage.setItem("favorite-setup-saved-height",entry.target.style.height); + localStorage.setItem("favorite-setup-saved-width",entry.target.style.width); + } + }); + + resizeObserver.observe(mainDiv); + + mainDiv.style.height = localStorage.getItem("favorite-setup-saved-height"); + mainDiv.style.width = localStorage.getItem("favorite-setup-saved-width"); + dragElement(mainDiv, topDiv); // Reposition popup based on previous dragged location From 3662b5036839e4175f9172726617842987fe6afc Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sat, 1 Apr 2023 14:43:26 -0400 Subject: [PATCH 43/61] Fixed "Jump to setup" and maintains sort at current location --- src/favorite-setups.js | 104 ++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 97570a7..83facac 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -2,7 +2,7 @@ // @name MouseHunt - Favorite Setups+ // @author PersonalPalimpsest (asterios) // @namespace https://greasyfork.org/en/users/900615-personalpalimpsest -// @version 2.2.0 +// @version 2.2.2 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* @@ -754,59 +754,60 @@ GM_addStyle ( ` setupSelectorInput.className = "favInput"; setupSelectorInput.setAttribute("placeholder", "Jump to setup:"); setupSelectorInput.setAttribute("list", "favorite-setup-selector"); - setupSelectorInput.oninput = function () { - console.log('testing selector input'); - const name = setupSelectorInput.value; - if (savedSetups[name] !== undefined) { const rows = document.querySelectorAll("tr.tsitu-fave-setup-row"); - rows.forEach(el => { - el.style.backgroundColor = ""; - }); - - /** + setupSelectorInput.oninput = function () { + const name = setupSelectorInput.value; + if (savedSetups[name] !== undefined) { + // remove background color for all setups (other than the banding) + const rows = document.querySelectorAll("tr.tsitu-fave-setup-row"); + rows.forEach(el => { + el.style.backgroundColor = ""; + }); + + /** * Return row element that matches dropdown setup name * @param {string} name Dropdown setup name * @return {HTMLElement|false} that should be highlighted and scrolled to */ - function findElement(name) { - for (let el of rows) { - const spans = el.querySelectorAll("span"); - if (spans.length === 2) { - if (name === spans[0].textContent) { - return el; - } - } - } - - return false; - } - - // Calculate index for nth-child - const targetEl = findElement(name); - let nthChildValue = 0; - for (let i = 0; i < rows.length; i++) { - const el = rows[i]; - if (el === targetEl) { - nthChildValue = i + 1; - break; - } - } - - // tr:nth-child value (min = 1) - const scrollRow = document.querySelector( - `tr.tsitu-fave-setup-row:nth-child(${nthChildValue})` - ); - if (scrollRow) { - scrollRow.style.backgroundColor = "#D6EBA1"; - scrollRow.scrollIntoView({ - behavior: "auto", - block: "nearest", - inline: "nearest" - }); - } - - setupSelectorInput.value = ""; - } - }; + function findElement(name) { + for (let el of rows) { + const spans = el.querySelectorAll("span"); + if (spans.length === 1) { + if (name === spans[0].textContent) { + return el; + } + } + } + + return false; + } + + // Calculate index for nth-child + const targetEl = findElement(name); + let nthChildValue = 0; + for (let i = 0; i < rows.length; i++) { + const el = rows[i]; + if (el === targetEl) { + nthChildValue = i + 1; + break; + } + } + + // tr:nth-child value (min = 1) + const scrollRow = document.querySelector( + `tr.tsitu-fave-setup-row:nth-child(${nthChildValue})` + ); + if (scrollRow) { + scrollRow.style.backgroundColor = "#D6EBA1"; + scrollRow.scrollIntoView({ + behavior: "auto", + block: "nearest", + inline: "nearest" + }); + } + + setupSelectorInput.value = ""; + } + }; const setupSelectorDiv = document.createElement("div"); setupSelectorDiv.className = "setupSelectorDiv"; @@ -814,7 +815,6 @@ GM_addStyle ( ` setupSelectorDiv.appendChild(setupSelectorInput); // TODO: Improve async logic, probably await completion of a component switch otherwise might overlap and/or silently fail - // TODO: [high] Location tags on setup creation (checkboxes a la best setups) // TODO: [med] Import/export setup "profiles" (separate dropdown of profiles) (export specific profile obj to dropbox/pastebin?) // ^ Profile management could be an elegant bulk grouping solution if done properly // TODO: [med] Mobile UX for drag & drop as well as scrollable div (jquery-ui-touch-punch did not work for simulating touch events) @@ -835,7 +835,7 @@ GM_addStyle ( ` //console.log("saved loc: "+savedSetups[name].location, "\n loc bool: "+!!savedSetups[name].location, "\n current loc: "+user.environment_name, "\n current loc bool: "+!!user.environment_name, "\n current loc is saved loc: "+(user.environment_name===savedSetups[name].location), "\n test: "+(!!savedSetups[name].location && user.environment_name == savedSetups[name].location)); if (user.environment_name === savedSetups[name].location) { //console.log("saved loc: "+savedSetups[name].location, "\n loc bool: "+!!savedSetups[name].location, "\n current loc: "+user.environment_name, "\n current loc bool: "+!!user.environment_name, "\n current loc is saved loc: "+(user.environment_name===savedSetups[name].location), "\n test: "+(!!savedSetups[name].location && user.environment_name == savedSetups[name].location)); - savedSetups[name].sort = -1; + savedSetups[name].sort -= 420; //console.log("location sorted setup: "+savedSetups[name]) }; }; From 48811d62f0539f60ab2cfef653f2589244fedba1 Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sat, 1 Apr 2023 19:40:05 -0400 Subject: [PATCH 44/61] Show only first setup for non-current areas Cleaned up some formatting and changed render function to a toggle --- src/favorite-setups.js | 1994 ++++++++++++++++++++-------------------- 1 file changed, 1019 insertions(+), 975 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 83facac..d8a2076 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -2,7 +2,7 @@ // @name MouseHunt - Favorite Setups+ // @author PersonalPalimpsest (asterios) // @namespace https://greasyfork.org/en/users/900615-personalpalimpsest -// @version 2.2.2 +// @version 2.3.2 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* @@ -27,15 +27,17 @@ GM_addStyle ( ` resize: both; min-width: min-content; } -} + #tsitu-fave-setups button { cursor: pointer; } + #tsitu-fave-setups .title { font-weight: bold; font-size: 160%; text-decoration: underline; } + #tsitu-fave-setups #close-button { float: right; font-size: 15px; @@ -179,7 +181,7 @@ GM_addStyle ( ` text-overflow: ellipsis; padding-top: 3px; padding-left: 3px; - margin-right: -3px; + margin-right: -1px; } .travelButton { grid-area: b; @@ -190,6 +192,8 @@ GM_addStyle ( ` align-items: center; justify-content: center; width: auto; + text-overflow: ellipsis; + min-width: max-content; } #imgSpan { grid-area: c; @@ -239,76 +243,76 @@ GM_addStyle ( ` } `); (function () { - // Observe Camp page for mutations (to re-inject button) - const observerTarget = document.querySelector(".mousehuntPage-content"); - if (observerTarget) { - MutationObserver = - window.MutationObserver || - window.WebKitMutationObserver || - window.MozMutationObserver; - - const observer = new MutationObserver(function () { - const campExists = document.querySelector( - ".mousehuntPage-content.PageCamp" - ); - if (campExists) { - // Disconnect and reconnect later to prevent infinite mutation loop - observer.disconnect(); - - // Re-render buttons (mainly for alternate TEM area placement) - injectUI(); - - observer.observe(observerTarget, { - childList: true, - subtree: true - }); - } - }); - - observer.observe(observerTarget, { - childList: true, - subtree: true - }); - } - - // Sorted from low to high (matches top HUD except weapon/base swapped for clarity) - const displayOrder = { - weapon: 1, - base: 2, - bait: 3, - cheese: 3, - trinket: 4, - charm: 4, - skin: 5, - location: 6 - }; - - // Pull and save location list - const xhr = new XMLHttpRequest(); - xhr.open( - "POST", - `https://www.mousehuntgame.com/managers/ajax/pages/page.php?page_class=HunterProfile&page_arguments%5Btab%5D=mice&page_arguments%5Bsub_tab%5D=location&uh=${user.unique_hash}` - ); - xhr.onload = function () { - const response = JSON.parse(xhr.responseText); - const locations = - response.page.tabs.mice.subtabs[1].mouse_list.categories; - if (locations) { - const masterObj = {}; - - locations.forEach(el => { - const obj = {}; - obj["type"] = el.type; - masterObj[el.name] = obj; - }); - - localStorage.setItem( - "ast-location-mapping", - JSON.stringify(masterObj) - ); - }; - }; - xhr.send(); + // Observe Camp page for mutations (to re-inject button) + const observerTarget = document.querySelector(".mousehuntPage-content"); + if (observerTarget) { + MutationObserver = + window.MutationObserver || + window.WebKitMutationObserver || + window.MozMutationObserver; + + const observer = new MutationObserver(function () { + const campExists = document.querySelector( + ".mousehuntPage-content[data-page = PageCamp]" + ); + if (campExists) { + // Disconnect and reconnect later to prevent infinite mutation loop + observer.disconnect(); + + // Re-render buttons (mainly for alternate TEM area placement) + injectUI(); + + observer.observe(observerTarget, { + childList: true, + subtree: true + }); + } + }); + + observer.observe(observerTarget, { + childList: true, + subtree: true + }); + } + + // Sorted from low to high (matches top HUD except weapon/base swapped for clarity) + const displayOrder = { + weapon: 1, + base: 2, + bait: 3, + cheese: 3, + trinket: 4, + charm: 4, + skin: 5, + location: 6 + }; + + // Pull and save location list + const xhr = new XMLHttpRequest(); + xhr.open( + "POST", + `https://www.mousehuntgame.com/managers/ajax/pages/page.php?page_class=HunterProfile&page_arguments%5Btab%5D=mice&page_arguments%5Bsub_tab%5D=location&uh=${user.unique_hash}` + ); + xhr.onload = function () { + const response = JSON.parse(xhr.responseText); + const locations = + response.page.tabs.mice.subtabs[1].mouse_list.categories; + if (locations) { + const masterObj = {}; + + locations.forEach(el => { + const obj = {}; + obj["type"] = el.type; + masterObj[el.name] = obj; + }); + + localStorage.setItem( + "ast-location-mapping", + JSON.stringify(masterObj) + ); + }; + }; + xhr.send(); // Re-render on location change const travelObserver = XMLHttpRequest.prototype.open; @@ -316,942 +320,982 @@ GM_addStyle ( ` this.addEventListener('load', function () { if (this.responseURL == `https://www.mousehuntgame.com/managers/ajax/users/changeenvironment.php`) { console.log('Travel detected'); - render(); - render(); + toggleRender(); + toggleRender(); } }) travelObserver.apply(this, arguments); } - const originalOpen = XMLHttpRequest.prototype.open; - XMLHttpRequest.prototype.open = function () { - this.addEventListener("load", function () { - if ( - this.responseURL === - "https://www.mousehuntgame.com/managers/ajax/users/gettrapcomponents.php" - ) { - let data; - try { - data = JSON.parse(this.responseText).components; - if (data && data.length > 0) { - const ownedItems = JSON.parse( - localStorage.getItem("tsitu-owned-components") - ) || { - bait: {}, - base: {}, - weapon: {}, - trinket: {}, - skin: {}, - location: {} - }; - - data.forEach(el => { - let key = el.name; - const arr = [el.item_id, el.thumbnail]; - if (el.classification === "skin") { - arr.push(el.component_name); - } - - if (el.classification === "weapon") { - if (el.name.indexOf("Golem Guardian") >= 0) { - // Golem Guardian edge case - arr[0] = 2732; - key = "Golem Guardian Trap"; - } else if (el.name.indexOf("Isle Idol") >= 0) { - // Isle Idol edge case - arr[0] = 1127; - key = "Isle Idol Trap"; - } - } - - ownedItems[el.classification][key] = arr; - - // switch statement for all 5 classifications - // ^ custom array, last element = image_trap hash if available - // ^ ideally thumbnail is also just the hash portion, img src can be trivially built dynamically - // ^ i believe this is for synergy with equipment-preview, so it's not necessary for now - }); - - // Edge case cleanup - Object.keys(ownedItems.weapon).forEach(el => { - if ( - (el.indexOf("Golem Guardian") >= 0 && - el !== "Golem Guardian Trap") || - (el.indexOf("Isle Idol") >= 0 && el !== "Isle Idol Trap") - ) { - delete ownedItems.weapon[el]; - } - }); - - localStorage.setItem( - "tsitu-owned-components", - JSON.stringify(ownedItems) - ); - localStorage.setItem("favorite-setup-timestamp", Date.now()); - const existing = document.querySelector("#tsitu-fave-setups"); - if (existing) render(); - } else { - console.log( - "Invalid components array data from gettrapcomponents.php" - ); - } - } catch (error) { - console.log( - "Failed to process server response for gettrapcomponents.php" - ); - console.error(error.stack); - } - } - }); - originalOpen.apply(this, arguments); - }; - - function render() { - const existing = document.querySelector("#tsitu-fave-setups"); - if (existing) existing.remove(); - - const rawData = localStorage.getItem("tsitu-owned-components"); - var editSort = -1; // ast location mod. change to -2 if you want new setups to appear above location sorted setups until they are manually sorted. - const locMap = JSON.parse(localStorage.getItem("ast-location-mapping")); // ast location mod - // aliases for locations with multiple environment_names for the same environment_type - locMap["Cursed City"] = {"type": "lost_city"}; - locMap["Sand Crypts"] = {"type": "sand_dunes"}; - locMap["Twisted Garden"] = {"type": "desert_oasis"}; - - if (rawData) { - const data = JSON.parse(rawData); - data.location = locMap; - const dataKeys = Object.keys(data).sort((a, b) => { - return displayOrder[a] - displayOrder[b]; - }); - - async function batchLoad( - baitName, - baseName, - weaponName, - trinketName, - skinName - ) { - if (weaponName.indexOf("Golem Guardian") >= 0) { - weaponName = "Golem Guardian Trap"; - } - if (weaponName.indexOf("Isle Idol") >= 0) { - weaponName = "Isle Idol Trap"; - } - - // Diff current setup with proposed batch to minimize server load - const diff = {}; - if (data.bait[baitName] && user.bait_name !== baitName) { - diff.bait = data.bait[baitName][0]; - } - if (data.base[baseName] && user.base_name !== baseName) { - diff.base = data.base[baseName][0]; - } - if (data.weapon[weaponName] && user.weapon_name !== weaponName) { - diff.weapon = data.weapon[weaponName][0]; - } - if (data.trinket[trinketName] && user.trinket_name !== trinketName) { - diff.trinket = data.trinket[trinketName][0]; - } - // if ( - // data.skin[skinName] && - // data.skin[skinName][2] === weaponName && - // user.skin_item_id !== data.skin[skinName][0] - // // note: this will probably proc every single time... diff AFTER weapon swap? - // ) { - // diff.skin = data.skin[skinName][0]; - // } - - if (baitName === "N/A") diff.bait = "disarm"; - if (trinketName === "N/A") diff.trinket = "disarm"; - // if (skinName === "N/A") diff.skin = "disarm"; - - const diffKeys = Object.keys(diff).sort((a, b) => { - return displayOrder[a] - displayOrder[b]; - }); - - if (diffKeys.length === 0) { - return; // Cancel if setup isn't changing - } else if (diffKeys.length >= 2) { - localStorage.setItem("tsitu-batch-loading", true); // Minimize Mapping Helper TEM requests by setting an in-progress bool - } - - function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); - } - - let counter = 0; - for (let classification of diffKeys) { - /** + const originalOpen = XMLHttpRequest.prototype.open; + XMLHttpRequest.prototype.open = function () { + this.addEventListener("load", function () { + if ( + this.responseURL === + "https://www.mousehuntgame.com/managers/ajax/users/gettrapcomponents.php" + ) { + let data; + try { + data = JSON.parse(this.responseText).components; + if (data && data.length > 0) { + const ownedItems = JSON.parse( + localStorage.getItem("tsitu-owned-components") + ) || { + bait: {}, + base: {}, + weapon: {}, + trinket: {}, + skin: {}, + location: {} + }; + + data.forEach(el => { + let key = el.name; + const arr = [el.item_id, el.thumbnail]; + if (el.classification === "skin") { + arr.push(el.component_name); + } + + if (el.classification === "weapon") { + if (el.name.indexOf("Golem Guardian") >= 0) { + // Golem Guardian edge case + arr[0] = 2732; + key = "Golem Guardian Trap"; + } else if (el.name.indexOf("Isle Idol") >= 0) { + // Isle Idol edge case + arr[0] = 1127; + key = "Isle Idol Trap"; + } + } + + ownedItems[el.classification][key] = arr; + + // switch statement for all 5 classifications + // ^ custom array, last element = image_trap hash if available + // ^ ideally thumbnail is also just the hash portion, img src can be trivially built dynamically + // ^ i believe this is for synergy with equipment-preview, so it's not necessary for now + }); + + // Edge case cleanup + Object.keys(ownedItems.weapon).forEach(el => { + if ( + (el.indexOf("Golem Guardian") >= 0 && + el !== "Golem Guardian Trap") || + (el.indexOf("Isle Idol") >= 0 && el !== "Isle Idol Trap") + ) { + delete ownedItems.weapon[el]; + } + }); + + localStorage.setItem( + "tsitu-owned-components", + JSON.stringify(ownedItems) + ); + localStorage.setItem("favorite-setup-timestamp", Date.now()); + // const existing = document.querySelector("#tsitu-fave-setups"); + // if (existing) + toggleRender(); + toggleRender(); + } else { + console.log( + "Invalid components array data from gettrapcomponents.php" + ); + } + } catch (error) { + console.log( + "Failed to process server response for gettrapcomponents.php" + ); + console.error(error.stack); + } + } + }); + originalOpen.apply(this, arguments); + }; + + function toggleRender() { + const existing = document.querySelector("#tsitu-fave-setups"); + if (existing) { + // console.log(existing); + localStorage.setItem('showSetups', "N"); + localStorage.setItem("favorite-setup-saved-height",existing.style.height); + localStorage.setItem("favorite-setup-saved-width",existing.style.width); + // console.log(existing.style.height); + existing.remove(); + } + else { + localStorage.setItem('showSetups', "Y"); + const rawData = localStorage.getItem("tsitu-owned-components"); + var editSort = -1; // ast location mod. change to -2 if you want new setups to appear above location sorted setups until they are manually sorted. + const locMap = JSON.parse(localStorage.getItem("ast-location-mapping")); // ast location mod + // aliases for locations with multiple environment_names for the same environment_type + locMap["Cursed City"] = {"type": "lost_city"}; + locMap["Sand Crypts"] = {"type": "sand_dunes"}; + locMap["Twisted Garden"] = {"type": "desert_oasis"}; + + if (rawData) { + const data = JSON.parse(rawData); + data.location = locMap; + const dataKeys = Object.keys(data).sort((a, b) => { + return displayOrder[a] - displayOrder[b]; + }); + + async function batchLoad( + baitName, + baseName, + weaponName, + trinketName, + skinName + ) { + if (weaponName.indexOf("Golem Guardian") >= 0) { + weaponName = "Golem Guardian Trap"; + } + if (weaponName.indexOf("Isle Idol") >= 0) { + weaponName = "Isle Idol Trap"; + } + + // Diff current setup with proposed batch to minimize server load + const diff = {}; + if (data.bait[baitName] && user.bait_name !== baitName) { + diff.bait = data.bait[baitName][0]; + } + if (data.base[baseName] && user.base_name !== baseName) { + diff.base = data.base[baseName][0]; + } + if (data.weapon[weaponName] && user.weapon_name !== weaponName) { + diff.weapon = data.weapon[weaponName][0]; + } + if (data.trinket[trinketName] && user.trinket_name !== trinketName) { + diff.trinket = data.trinket[trinketName][0]; + } + // if ( + // data.skin[skinName] && + // data.skin[skinName][2] === weaponName && + // user.skin_item_id !== data.skin[skinName][0] + // // note: this will probably proc every single time... diff AFTER weapon swap? + // ) { + // diff.skin = data.skin[skinName][0]; + // } + + if (baitName === "N/A") diff.bait = "disarm"; + if (trinketName === "N/A") diff.trinket = "disarm"; + // if (skinName === "N/A") diff.skin = "disarm"; + + const diffKeys = Object.keys(diff).sort((a, b) => { + return displayOrder[a] - displayOrder[b]; + }); + + if (diffKeys.length === 0) { + return; // Cancel if setup isn't changing + } else if (diffKeys.length >= 2) { + localStorage.setItem("tsitu-batch-loading", true); // Minimize Mapping Helper TEM requests by setting an in-progress bool + } + + function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } + + let counter = 0; + for (let classification of diffKeys) { + /** * TODO: Investigate bug that de-skins a weapon if you've used mobile app FS to arm a skinless weapon setup * Attempted to emulate browser item selector click by calling `app.pages.CampPage.armItem(element)` * Passed in a "fake" element with data-item-id so that `tmpItem` is derived * Inside `armItem`: 'syncInventory' and/or 'loadItems' fills in 'trapItems' so that 'getItemById' works * Final TrapControl requests seem to be identical with script... so the stuff before might be relevant */ - counter += 1; - if (counter === diffKeys.length) { - localStorage.setItem("tsitu-batch-loading", false); // Reset bool in time for last request - } - - const id = diff[classification]; - if (id === "disarm") { - await hg.utils.TrapControl.disarmItem(classification).go(); - } else { - await hg.utils.TrapControl.armItem(id, classification).go(); - // console.log(id, classification); - // const testEl = document.createElement("a"); - // testEl.setAttribute("data-item-id", id); - // console.log(testEl); - // await app.pages.CampPage.armItem(testEl); - } - await sleep(420); - } - - // Another reset just in case something goes wrong inside the for...of - localStorage.setItem("tsitu-batch-loading", false); - - // Deprecated the old method because unable to prevent userinventory.php calls from syncArmedItems (caused by mobile/regular desync) - // Witnessed up to an 18 request simul-slam (at least +1 increments starting from 3 / n-1 duplicates with 1 response's items[] different) - // If switching back to a previous setup then things do seem to be cached - // CBS may investigate at some point, but going to use the new method above for v1.0 and beyond - } - - // Main popup styling - const mainDiv = document.createElement("div"); - mainDiv.id = "tsitu-fave-setups"; - - // Top div styling (close button, title, drag instructions) - const topDiv = document.createElement("div"); - topDiv.id = "header" - topDiv.title = "Drag header to reposition this popup"; - - const titleSpan = document.createElement("span"); - titleSpan.className = "title"; - titleSpan.innerText = "Favorite Setups"; - - const closeButton = document.createElement("button"); - closeButton.id = "close-button"; - closeButton.textContent = "×"; - closeButton.onclick = function () { - document.body.removeChild(mainDiv); - localStorage.setItem('showSetups', "N"); - }; - - topDiv.appendChild(closeButton); - topDiv.appendChild(titleSpan); - - // Build dropdowns - const dataListTable = document.createElement("table"); - dataListTable.id = "dataListTable"; - - for (let rawCategory of dataKeys) { - let category = rawCategory; - if (category === "sort") continue; - if (category === "skin") continue; // note: only show appropriate skins if implementing - if (category === "bait") category = "cheese"; - if (category === "trinket") category = "charm"; - - const dataList = document.createElement("datalist"); - dataList.id = `favorite-setup-datalist-${category}`; - for (let item of Object.keys(data[rawCategory]).sort()) { - const option = document.createElement("option"); - option.value = item; - dataList.appendChild(option); - } - - const dataListInput = document.createElement("input"); - dataListInput.id = `favorite-setup-input-${category}`; - dataListInput.className = "favInput"; - dataListInput.setAttribute("placeholder", `Select ${category}: `); - dataListInput.setAttribute( - "list", - `favorite-setup-datalist-${category}` - ); - - const inputCol = document.createElement("td"); - inputCol.className = "inputCol"; - inputCol.appendChild(dataList); - inputCol.appendChild(dataListInput); - - const dataListRow = document.createElement("tr"); - dataListRow.className = "dataListRow"; - - dataListRow.appendChild(inputCol); - dataListTable.appendChild(dataListRow); - } - - const nameInput = document.createElement("input"); - nameInput.type = "text"; - nameInput.id = "favorite-setup-name"; - nameInput.className = "favInput"; - nameInput.setAttribute("placeholder", "Setup name: "); - nameInput.required = true; - nameInput.minLength = 1; - nameInput.maxLength = 30; - nameInput.addEventListener("keyup", function(event) { - // Number 13 is the "Enter" key on the keyboard - if (event.keyCode === 13) { - // Cancel the default action, if needed - event.preventDefault(); - // Trigger the button element with a click - document.getElementById("saveButton").click(); - } - }); - - const nameInputCol = document.createElement("td"); - nameInputCol.appendChild(nameInput); - - const nameRow = document.createElement("tr"); - nameRow.appendChild(nameInputCol); - dataListTable.appendChild(nameRow); - - // Hidden checkbox to toggle dataListDiv visibility - const collapsibleCheckbox = document.createElement("input"); - collapsibleCheckbox.id = "collapsible"; - collapsibleCheckbox.type = "checkbox"; - - const dataListDiv = document.createElement("div"); - dataListDiv.id = "dataListDiv"; - dataListDiv.appendChild(dataListTable); - - // Import setup / Save setup / Reset input buttons - const saveButton = document.createElement("button"); - saveButton.id = "saveButton"; - saveButton.className = "button"; - saveButton.textContent = "Save Setup"; - saveButton.onclick = function () { - const bait = document.querySelector("#favorite-setup-input-cheese") - .value; - const base = document.querySelector("#favorite-setup-input-base").value; - const weapon = document.querySelector("#favorite-setup-input-weapon") - .value; - const charm = document.querySelector("#favorite-setup-input-charm") - .value; - // const skin = document.querySelector("#favorite-setup-input-skin").value; - const name = document.querySelector("#favorite-setup-name").value; - const location = document.querySelector("#favorite-setup-input-location").value; - - if (name.length >= 1 && name.length <= 30) { - const obj = {}; - obj[name] = { - bait: "N/A", - base: "N/A", - weapon: "N/A", - trinket: "N/A", - skin: "N/A", - location: "N/A" - }; - - if (data.bait[bait] !== undefined) obj[name].bait = bait; - if (data.base[base] !== undefined) obj[name].base = base; - if (data.weapon[weapon] !== undefined) obj[name].weapon = weapon; - if (data.trinket[charm] !== undefined) obj[name].trinket = charm; - // if (data.skin[skin] !== undefined) obj[name].skin = skin; - if (data.location[location] !== undefined) obj[name].location = location; - obj[name].sort = editSort; - console.log("saved setup '"+name+"': "+JSON.stringify(obj[name])); - - const storedRaw = localStorage.getItem("favorite-setups-saved"); - if (storedRaw) { - const storedData = JSON.parse(storedRaw); - if (storedData[name] !== undefined) { - if (confirm(`Do you want to overwrite saved setup '${name}'?`)) { - obj[name].sort = storedData[name].sort; - } else { - return; - } - } - storedData[name] = obj[name]; - localStorage.setItem( - "favorite-setups-saved", - JSON.stringify(storedData) - ); - } else { - localStorage.setItem("favorite-setups-saved", JSON.stringify(obj)); - } - var saveScroll = document.getElementById("scroller").scrollTop; // ast location mod - render(); - document.getElementById("scroller").scrollTop = saveScroll; - console.log("scroll position before/after: "+saveScroll+" / "+document.getElementById("scroller").scrollTop); - } else { - alert( - "Please enter a name for your setup that is between 1-30 characters" - ); - } - }; - - const loadButton = document.createElement("button"); - loadButton.id = "loadButton"; - loadButton.className = "button"; - loadButton.textContent = "Import setup"; - loadButton.onclick = function () { - document.querySelector("#collapsible").checked = true; // to toggle collapsible - document.querySelector("#favorite-setup-input-cheese").value = - user.bait_name || ""; - document.querySelector("#favorite-setup-input-base").value = - user.base_name || ""; - document.querySelector("#favorite-setup-input-weapon").value = - user.weapon_name || ""; - document.querySelector("#favorite-setup-input-charm").value = - user.trinket_name || ""; - document.querySelector("#favorite-setup-input-location").value = - user.environment_name || ""; - // if (user.skin_name) { - // document.querySelector("#favorite-setup-input-skin").value = - // user.skin_name; // not really a thing, gotta use a qS probably or parse from LS ID-name map - // } - document.getElementById("favorite-setup-name").focus(); - console.log("loaded items: ",user.bait_name, user.base_name, user.weapon_name, user.trinket_name, user.environment_name); - }; - - const resetButton = document.createElement("button"); - resetButton.className = "button"; - resetButton.textContent = "Reset inputs"; - resetButton.onclick = function () { - document.querySelector("#collapsible").checked = false; // to toggle collapsible - document.querySelector("#favorite-setup-input-cheese").value = ""; - document.querySelector("#favorite-setup-input-base").value = ""; - document.querySelector("#favorite-setup-input-weapon").value = ""; - document.querySelector("#favorite-setup-input-charm").value = ""; - // document.querySelector("#favorite-setup-input-skin").value = ""; - document.querySelector("#favorite-setup-name").value = ""; - document.querySelector("#favorite-setup-input-location").value = ""; - }; - - const disarmButton = document.createElement("button"); - disarmButton.className = "button"; - disarmButton.textContent = "Disarm"; - disarmButton.onclick = function () { - hg.utils.TrapControl.disarmBait().go(); - }; - - const buttonSpan = document.createElement("span"); - buttonSpan.className = "btn-group"; - buttonSpan.appendChild(loadButton); - buttonSpan.appendChild(saveButton); - buttonSpan.appendChild(resetButton); - buttonSpan.appendChild(disarmButton); - - // Sort existing saved setups - const savedRaw = localStorage.getItem("favorite-setups-saved"); - const savedSetups = JSON.parse(savedRaw) || {}; - const savedSetupSortKeys = Object.keys(savedSetups).sort((a, b) => { - return savedSetups[a].sort - savedSetups[b].sort; - }); - - // Create setup dropdown selector - const setupSelector = document.createElement("datalist"); - setupSelector.id = "favorite-setup-selector"; - for (let item of savedSetupSortKeys) { - const option = document.createElement("option"); - option.value = item; - setupSelector.appendChild(option); - } - - const setupSelectorInput = document.createElement("input"); - setupSelectorInput.id = "favorite-setup-selector-input"; - setupSelectorInput.className = "favInput"; - setupSelectorInput.setAttribute("placeholder", "Jump to setup:"); - setupSelectorInput.setAttribute("list", "favorite-setup-selector"); - setupSelectorInput.oninput = function () { - const name = setupSelectorInput.value; - if (savedSetups[name] !== undefined) { - // remove background color for all setups (other than the banding) - const rows = document.querySelectorAll("tr.tsitu-fave-setup-row"); - rows.forEach(el => { - el.style.backgroundColor = ""; + counter += 1; + if (counter === diffKeys.length) { + localStorage.setItem("tsitu-batch-loading", false); // Reset bool in time for last request + } + + const id = diff[classification]; + if (id === "disarm") { + await hg.utils.TrapControl.disarmItem(classification).go(); + } else { + await hg.utils.TrapControl.armItem(id, classification).go(); + // console.log(id, classification); + // const testEl = document.createElement("a"); + // testEl.setAttribute("data-item-id", id); + // console.log(testEl); + // await app.pages.CampPage.armItem(testEl); + } + await sleep(420); + } + + // Another reset just in case something goes wrong inside the for...of + localStorage.setItem("tsitu-batch-loading", false); + + // Deprecated the old method because unable to prevent userinventory.php calls from syncArmedItems (caused by mobile/regular desync) + // Witnessed up to an 18 request simul-slam (at least +1 increments starting from 3 / n-1 duplicates with 1 response's items[] different) + // If switching back to a previous setup then things do seem to be cached + // CBS may investigate at some point, but going to use the new method above for v1.0 and beyond + } + + // Main popup styling + const mainDiv = document.createElement("div"); + mainDiv.id = "tsitu-fave-setups"; + + // Top div styling (close button, title, drag instructions) + const topDiv = document.createElement("div"); + topDiv.id = "header" + topDiv.title = "Drag header to reposition this popup"; + + const titleSpan = document.createElement("span"); + titleSpan.className = "title"; + titleSpan.innerText = "Favorite Setups"; + + const closeButton = document.createElement("button"); + closeButton.id = "close-button"; + closeButton.textContent = "×"; + closeButton.onclick = function () { + document.body.removeChild(mainDiv); + localStorage.setItem('showSetups', "N"); + }; + + topDiv.appendChild(closeButton); + topDiv.appendChild(titleSpan); + + // Build dropdowns + const dataListTable = document.createElement("table"); + dataListTable.id = "dataListTable"; + + for (let rawCategory of dataKeys) { + let category = rawCategory; + if (category === "sort") continue; + if (category === "skin") continue; // note: only show appropriate skins if implementing + if (category === "bait") category = "cheese"; + if (category === "trinket") category = "charm"; + + const dataList = document.createElement("datalist"); + dataList.id = `favorite-setup-datalist-${category}`; + for (let item of Object.keys(data[rawCategory]).sort()) { + const option = document.createElement("option"); + option.value = item; + dataList.appendChild(option); + } + + const dataListInput = document.createElement("input"); + dataListInput.id = `favorite-setup-input-${category}`; + dataListInput.className = "favInput"; + dataListInput.setAttribute("placeholder", `Select ${category}: `); + dataListInput.setAttribute( + "list", + `favorite-setup-datalist-${category}` + ); + + const inputCol = document.createElement("td"); + inputCol.className = "inputCol"; + inputCol.appendChild(dataList); + inputCol.appendChild(dataListInput); + + const dataListRow = document.createElement("tr"); + dataListRow.className = "dataListRow"; + + dataListRow.appendChild(inputCol); + dataListTable.appendChild(dataListRow); + } + + const nameInput = document.createElement("input"); + nameInput.type = "text"; + nameInput.id = "favorite-setup-name"; + nameInput.className = "favInput"; + nameInput.setAttribute("placeholder", "Setup name: "); + nameInput.required = true; + nameInput.minLength = 1; + nameInput.maxLength = 30; + nameInput.addEventListener("keyup", function(event) { + // Number 13 is the "Enter" key on the keyboard + if (event.keyCode === 13) { + // Cancel the default action, if needed + event.preventDefault(); + // Trigger the button element with a click + document.getElementById("saveButton").click(); + } + }); + + const nameInputCol = document.createElement("td"); + nameInputCol.appendChild(nameInput); + + const nameRow = document.createElement("tr"); + nameRow.appendChild(nameInputCol); + dataListTable.appendChild(nameRow); + + // Hidden checkbox to toggle dataListDiv visibility + const collapsibleCheckbox = document.createElement("input"); + collapsibleCheckbox.id = "collapsible"; + collapsibleCheckbox.type = "checkbox"; + + const dataListDiv = document.createElement("div"); + dataListDiv.id = "dataListDiv"; + dataListDiv.appendChild(dataListTable); + + // Import setup / Save setup / Reset input buttons + const saveButton = document.createElement("button"); + saveButton.id = "saveButton"; + saveButton.className = "button"; + saveButton.textContent = "Save Setup"; + saveButton.onclick = function () { + const bait = document.querySelector("#favorite-setup-input-cheese") + .value; + const base = document.querySelector("#favorite-setup-input-base").value; + const weapon = document.querySelector("#favorite-setup-input-weapon") + .value; + const charm = document.querySelector("#favorite-setup-input-charm") + .value; + // const skin = document.querySelector("#favorite-setup-input-skin").value; + const name = document.querySelector("#favorite-setup-name").value; + const location = document.querySelector("#favorite-setup-input-location").value; + + if (name.length >= 1 && name.length <= 30) { + const obj = {}; + obj[name] = { + bait: "N/A", + base: "N/A", + weapon: "N/A", + trinket: "N/A", + skin: "N/A", + location: "N/A" + }; + + if (data.bait[bait] !== undefined) obj[name].bait = bait; + if (data.base[base] !== undefined) obj[name].base = base; + if (data.weapon[weapon] !== undefined) obj[name].weapon = weapon; + if (data.trinket[charm] !== undefined) obj[name].trinket = charm; + // if (data.skin[skin] !== undefined) obj[name].skin = skin; + if (data.location[location] !== undefined) obj[name].location = location; + obj[name].sort = editSort; + console.log("saved setup '"+name+"': "+JSON.stringify(obj[name])); + + const storedRaw = localStorage.getItem("favorite-setups-saved"); + if (storedRaw) { + const storedData = JSON.parse(storedRaw); + if (storedData[name] !== undefined) { + if (confirm(`Do you want to overwrite saved setup '${name}'?`)) { + obj[name].sort = storedData[name].sort; + } else { + return; + } + } + storedData[name] = obj[name]; + localStorage.setItem( + "favorite-setups-saved", + JSON.stringify(storedData) + ); + } else { + localStorage.setItem("favorite-setups-saved", JSON.stringify(obj)); + } + var saveScroll = document.getElementById("scroller").scrollTop; // ast location mod + toggleRender(); + toggleRender(); + document.getElementById("scroller").scrollTop = saveScroll; + console.log("scroll position before/after: "+saveScroll+" / "+document.getElementById("scroller").scrollTop); + } else { + alert( + "Please enter a name for your setup that is between 1-30 characters" + ); + } + }; + + const loadButton = document.createElement("button"); + loadButton.id = "loadButton"; + loadButton.className = "button"; + loadButton.textContent = "Import setup"; + loadButton.onclick = function () { + document.querySelector("#collapsible").checked = true; // to toggle collapsible + document.querySelector("#favorite-setup-input-cheese").value = + user.bait_name || ""; + document.querySelector("#favorite-setup-input-base").value = + user.base_name || ""; + document.querySelector("#favorite-setup-input-weapon").value = + user.weapon_name || ""; + document.querySelector("#favorite-setup-input-charm").value = + user.trinket_name || ""; + document.querySelector("#favorite-setup-input-location").value = + user.environment_name || ""; + // if (user.skin_name) { + // document.querySelector("#favorite-setup-input-skin").value = + // user.skin_name; // not really a thing, gotta use a qS probably or parse from LS ID-name map + // } + document.getElementById("favorite-setup-name").focus(); + console.log("loaded items: ",user.bait_name, user.base_name, user.weapon_name, user.trinket_name, user.environment_name); + }; + + const resetButton = document.createElement("button"); + resetButton.className = "button"; + resetButton.textContent = "Reset inputs"; + resetButton.onclick = function () { + document.querySelector("#collapsible").checked = false; // to toggle collapsible + document.querySelector("#favorite-setup-input-cheese").value = ""; + document.querySelector("#favorite-setup-input-base").value = ""; + document.querySelector("#favorite-setup-input-weapon").value = ""; + document.querySelector("#favorite-setup-input-charm").value = ""; + // document.querySelector("#favorite-setup-input-skin").value = ""; + document.querySelector("#favorite-setup-name").value = ""; + document.querySelector("#favorite-setup-input-location").value = ""; + }; + + const disarmButton = document.createElement("button"); + disarmButton.className = "button"; + disarmButton.textContent = "Disarm"; + disarmButton.onclick = function () { + hg.utils.TrapControl.disarmBait().go(); + }; + + const buttonSpan = document.createElement("span"); + buttonSpan.className = "btn-group"; + buttonSpan.appendChild(loadButton); + buttonSpan.appendChild(saveButton); + buttonSpan.appendChild(resetButton); + buttonSpan.appendChild(disarmButton); + + // Sort existing saved setups + const savedRaw = localStorage.getItem("favorite-setups-saved"); + const savedSetups = JSON.parse(savedRaw) || {}; + const savedSetupSortKeys = Object.keys(savedSetups).sort((a, b) => { + return savedSetups[a].sort - savedSetups[b].sort; }); - /** + // Create setup dropdown selector + const setupSelector = document.createElement("datalist"); + setupSelector.id = "favorite-setup-selector"; + for (let item of savedSetupSortKeys) { + const option = document.createElement("option"); + option.value = item; + setupSelector.appendChild(option); + } + + const setupSelectorInput = document.createElement("input"); + setupSelectorInput.id = "favorite-setup-selector-input"; + setupSelectorInput.className = "favInput"; + setupSelectorInput.setAttribute("placeholder", "Jump to setup:"); + setupSelectorInput.setAttribute("list", "favorite-setup-selector"); + setupSelectorInput.oninput = function () { + const name = setupSelectorInput.value; + if (savedSetups[name] !== undefined) { + // remove background color for all setups (other than the banding) + const rows = document.querySelectorAll("tr.tsitu-fave-setup-row"); + rows.forEach(el => { + el.style.backgroundColor = ""; + }); + + /** * Return row element that matches dropdown setup name * @param {string} name Dropdown setup name * @return {HTMLElement|false} that should be highlighted and scrolled to */ - function findElement(name) { - for (let el of rows) { - const spans = el.querySelectorAll("span"); - if (spans.length === 1) { - if (name === spans[0].textContent) { - return el; + function findElement(name) { + for (let el of rows) { + const spans = el.querySelectorAll("span"); + if (spans.length === 1) { + if (name === spans[0].textContent) { + el.style.display = "grid"; + return el; + } + } } + + return false; + } + + // Calculate index for nth-child + const targetEl = findElement(name); + let nthChildValue = 0; + for (let i = 0; i < rows.length; i++) { + const el = rows[i]; + if (el === targetEl) { + nthChildValue = i + 1; + break; + } + } + + // tr:nth-child value (min = 1) + const scrollRow = document.querySelector( + `tr.tsitu-fave-setup-row:nth-child(${nthChildValue})` + ); + if (scrollRow) { + scrollRow.style.backgroundColor = "#D6EBA1"; + scrollRow.scrollIntoView({ + behavior: "auto", + block: "nearest", + inline: "nearest" + }); } + + setupSelectorInput.value = ""; } + }; + + const setupSelectorDiv = document.createElement("div"); + setupSelectorDiv.className = "setupSelectorDiv"; + setupSelectorDiv.appendChild(setupSelector); + setupSelectorDiv.appendChild(setupSelectorInput); + + // TODO: Improve async logic, probably await completion of a component switch otherwise might overlap and/or silently fail + // TODO: [med] Import/export setup "profiles" (separate dropdown of profiles) (export specific profile obj to dropbox/pastebin?) + // ^ Profile management could be an elegant bulk grouping solution if done properly + // TODO: [med] Mobile UX for drag & drop as well as scrollable div (jquery-ui-touch-punch did not work for simulating touch events) + // TODO: [low] Skin implementation/checks (in-progress, but either save for later or scrap entirely since use case is minimal) + + const scroller = document.createElement("div"); + scroller.id = "scroller"; + // Setup table styling + const setupTable = document.createElement("table"); + const setupTbody = document.createElement("tbody"); + setupTbody.id = "setupTbody"; + + const setupTableDiv = document.createElement("div"); + setupTableDiv.id = "setupTableDiv"; + + // Sort setups from the current location to the top of the list + function locSort (name) { + //console.log("saved loc: "+savedSetups[name].location, "\n loc bool: "+!!savedSetups[name].location, "\n current loc: "+user.environment_name, "\n current loc bool: "+!!user.environment_name, "\n current loc is saved loc: "+(user.environment_name===savedSetups[name].location), "\n test: "+(!!savedSetups[name].location && user.environment_name == savedSetups[name].location)); + if (user.environment_name === savedSetups[name].location) { + //console.log("saved loc: "+savedSetups[name].location, "\n loc bool: "+!!savedSetups[name].location, "\n current loc: "+user.environment_name, "\n current loc bool: "+!!user.environment_name, "\n current loc is saved loc: "+(user.environment_name===savedSetups[name].location), "\n test: "+(!!savedSetups[name].location && user.environment_name == savedSetups[name].location)); + savedSetups[name].sort -= 420; + //console.log("location sorted setup: "+savedSetups[name]) + }; + }; + + savedSetupSortKeys.forEach(name => { + locSort(name); + }); + + const sortedSetupKeys = Object.keys(savedSetups).sort((a, b) => { + return savedSetups[a].sort - savedSetups[b].sort; + }); + + // Generate and append each saved setup as a new + sortedSetupKeys.forEach(name => { + generateRow(name); + }); - return false; + function generateRow(name) { + const el = savedSetups[name]; + const elKeys = Object.keys(savedSetups[name]).sort((a, b) => { + return displayOrder[a] - displayOrder[b]; + }); + + const imgSpan = document.createElement("button"); + imgSpan.className = "button"; + imgSpan.id = "imgSpan"; + + for (let type of elKeys) { + if (type === "sort") continue; + if (type === "skin") continue; + if (type === "location") continue; + + const img = document.createElement("img"); + let item = el[type]; + if (data.weapon["Golem Guardian Trap"] !== undefined) { + if (type === "weapon") { + if (item.indexOf("Golem Guardian") >= 0) { + item = "Golem Guardian Trap"; + } else if (item.indexOf("Isle Idol") >= 0) { + item = "Isle Idol Trap"; + } + } + } + img.title = item; + if (item === "N/A") { + if (type === "bait") img.title = "Disarm Bait"; + if (type === "trinket") img.title = "Disarm Charm"; + // if (type === "skin") img.title = "Disarm Skin"; + } + img.onclick = function () { + // Mobile tooltip behavior = LOW priority because long pressing works on FF + // const appendTitle = img.querySelector(".append-title"); + // if (!appendTitle) { + // const appendSpan = document.createElement("span"); + // appendSpan.className = "append-title"; + // appendSpan.style.position = "absolute"; + // appendSpan.style.padding = "4px"; + // // appendSpan.textContent = item; + // appendSpan.textContent = img.title; + // img.append(appendSpan); + // } else { + // appendTitle.remove(); + // } + }; + img.src = + "https://www.mousehuntgame.com/images/items/stats/ee8f12ab8e042415063ef4140cefab7b.gif?cv=243"; + if (data[type][item]) img.src = data[type][item][1]; + imgSpan.appendChild(img); + }; + imgSpan.onclick = function () { //ast location mod + batchLoad(el.bait, el.base, el.weapon, el.trinket, el.skin); + console.log("armed '"+name+"': ", el.bait, el.base, el.weapon, el.trinket, el.skin, el.location); + }; + + const nameSpan = document.createElement("span"); + nameSpan.className = "tsitu-fave-setup-namespan"; + nameSpan.textContent = name; + + const editButton = document.createElement("button"); + editButton.id = "editButton"; + editButton.className = "button"; + editButton.textContent = "✏️"; + editButton.onclick = function () { + document.querySelector("#collapsible").checked = true; + document.querySelector("#favorite-setup-input-cheese").value = + el.bait === "N/A" ? "" : el.bait; + document.querySelector("#favorite-setup-input-base").value = + el.base === "N/A" ? "" : el.base; + document.querySelector("#favorite-setup-input-weapon").value = + el.weapon === "N/A" ? "" : el.weapon; + document.querySelector("#favorite-setup-input-charm").value = + el.trinket === "N/A" ? "" : el.trinket; + document.querySelector("#favorite-setup-input-location").value = + el.location === "N/A" ? "" : el.location; + // document.querySelector("#favorite-setup-input-skin").value = + // el.skin === "N/A" ? "" : el.skin; + document.querySelector("#favorite-setup-name").value = name || ""; + editSort = el.sort; // for sorting name-edited setups after the originating setup this button was clicked on + console.log("editing setup: "+name+" from sort position "+editSort); + document.getElementById("favorite-setup-name").focus(); // ast location mod + }; + + const deleteButton = document.createElement("button"); + deleteButton.id = "deleteButton"; + deleteButton.className = "button"; + deleteButton.textContent = "🗑️"; + deleteButton.onclick = function () { + if (confirm(`Delete setup '${name}'?`)) { + const storedRaw = localStorage.getItem("favorite-setups-saved"); + if (storedRaw) { + const storedData = JSON.parse(storedRaw); + if (storedData[name]) delete storedData[name]; + localStorage.setItem( + "favorite-setups-saved", + JSON.stringify(storedData) + ); + // to delete from DOM without a re-render + var i = this.parentNode.rowIndex; + console.log("deleted '"+name+"' from rowIndex: "+i); + document.getElementById("setupTbody").deleteRow(i); + } + } + }; + + const travelButton = document.createElement("button"); //ast location mod + travelButton.className = "travelButton"; + travelButton.title = "Left click to travel, Right click to update setup location to current location" + if (el.location) { + travelButton.textContent = el.location; + } else { + travelButton.textContent = 'N/A' + }; + travelButton.onclick = function () { + app.pages.TravelPage.travel (locMap[el.location].type); + }; + //refresh setup with location to ease migration of old setups + travelButton.oncontextmenu = function() { + const bait = el.bait; + const base = el.base; + const weapon = el.weapon; + const charm = el.trinket; + const location = user.environment_name // ast location mod + + if (name.length >= 1 && name.length <= 30) { + const obj = {}; + obj[name] = { + bait: "N/A", + base: "N/A", + weapon: "N/A", + trinket: "N/A", + skin: "N/A" + ,location: "N/A" // ast location mod + }; + + if (data.bait[bait] !== undefined) obj[name].bait = bait; + if (data.base[base] !== undefined) obj[name].base = base; + if (data.weapon[weapon] !== undefined) obj[name].weapon = weapon; + if (data.trinket[charm] !== undefined) obj[name].trinket = charm; + // if (data.skin[skin] !== undefined) obj[name].skin = skin; + obj[name].location = location; // ast location mod + obj[name].sort = editSort; // ast location mod + console.log("saved setup '"+name+"': "+JSON.stringify(obj[name])); // ast location mod + + const storedRaw = localStorage.getItem("favorite-setups-saved"); + if (storedRaw) { + const storedData = JSON.parse(storedRaw); + if (storedData[name] !== undefined) { + if (confirm(`Do you want to overwrite saved setup '${name}'?`)) { + obj[name].sort = storedData[name].sort; + } else { + return; + } + } + storedData[name] = obj[name]; + localStorage.setItem( + "favorite-setups-saved", + JSON.stringify(storedData) + ); + } else { + localStorage.setItem("favorite-setups-saved", JSON.stringify(obj)); + } + var saveScroll = document.getElementById("scroller").scrollTop; // ast location mod + toggleRender(); + toggleRender(); + document.getElementById("scroller").scrollTop = saveScroll; + } else { + alert( + "Please enter a name for your setup that is between 1-20 characters" + ); + }; + }; + + const setupRow = document.createElement("tr"); + setupRow.className = "tsitu-fave-setup-row"; + setupRow.appendChild(nameSpan); + setupRow.appendChild(travelButton); + setupRow.appendChild(imgSpan); + setupRow.appendChild(editButton); + setupRow.appendChild(deleteButton); + setupTbody.appendChild(setupRow); + + // if (user.environment_name !== el.location) { + // const allLocations = document.querySelectorAll('tr.tsitu-fave-setup-row .travelButton'); + // let locSetupCount = 0; + // // for (const loc of allLocations) { + // // if (loc.textContent === el.location) { + // // locSetupCount++; + // // console.log(locSetupCount) + // // } + // // console.log(locSetupCount) + // // } + // console.log(el.location); + // console.log(allLocations); + // if (locSetupCount > 1) { + // setupRow.style.display = "none"; + // } + // } } - // Calculate index for nth-child - const targetEl = findElement(name); - let nthChildValue = 0; - for (let i = 0; i < rows.length; i++) { - const el = rows[i]; - if (el === targetEl) { - nthChildValue = i + 1; - break; + // Toggle sort lock/unlock + const toggleSort = document.createElement("button"); // ast location mod + toggleSort.id = "toggleSort"; + toggleSort.innerText = "Click to unlock drag and drop sort";// "Reset Sort Order"; + toggleSort.onclick = function () { + var disabled = $(setupTbody).sortable("option", "disabled"); + if (disabled) { + $(setupTbody).sortable("enable"); + toggleSort.innerText = "Drag to sort"; + GM_addStyle( //disable setup name selection when dragging + " .tsitu-fave-setup-namespan { grid-area: a; font-size: inherit; text-align: left; text-overflow: ellipsis; user-select: none;}" + ); + } else { + $(setupTbody).sortable("disable"); + toggleSort.innerText = "Click to unlock sort"; + GM_addStyle( + " .tsitu-fave-setup-namespan { grid-area: a; font-size: inherit; text-align: left; text-overflow: ellipsis; user-select: text;}" + ); } - } + }; - // tr:nth-child value (min = 1) - const scrollRow = document.querySelector( - `tr.tsitu-fave-setup-row:nth-child(${nthChildValue})` + // Make the table drag & drop-able via jQuery sortable() + GM_addStyle( + ".ui-state-highlight-tsitu { height: 68px; background-color: #FAFFAF; }" ); - if (scrollRow) { - scrollRow.style.backgroundColor = "#D6EBA1"; - scrollRow.scrollIntoView({ - behavior: "auto", - block: "nearest", - inline: "nearest" - }); + $(setupTbody).sortable({ + placeholder: "ui-state-highlight-tsitu", + scroll: true, + scrollSensitivity: 80, + scrollSpeed: 20, + cursor: "move", + disabled: true, + update: function() { + const storedRaw = localStorage.getItem("favorite-setups-saved"); + if (storedRaw) { + const storedData = JSON.parse(storedRaw); + const nameSpans = document.querySelectorAll( + ".tsitu-fave-setup-namespan" + ); + if (nameSpans.length === Object.keys(storedData).length) { + for (let i = 0; i < nameSpans.length; i++) { + const name = nameSpans[i].textContent; + if (storedData[name] !== undefined) { + storedData[name].sort = i; + } + } + localStorage.setItem( + "favorite-setups-saved", + JSON.stringify(storedData) + ); + } + } + } + }); + setupTable.appendChild(setupTbody); + setupTableDiv.appendChild(setupTable); + + // Append everything to main popup UI + mainDiv.appendChild(topDiv); + mainDiv.appendChild(buttonSpan); + mainDiv.appendChild(collapsibleCheckbox); + mainDiv.appendChild(dataListDiv); + mainDiv.appendChild(setupSelectorDiv); + scroller.appendChild(setupTableDiv); + mainDiv.appendChild(scroller); + mainDiv.appendChild(toggleSort); + document.body.appendChild(mainDiv); + + const resizeObserver = new ResizeObserver(entries => { + for (let entry of entries) { + // console.log(`${entry.target.style.height} h + ${entry.target.style.width} w`); + localStorage.setItem("favorite-setup-saved-height",entry.target.style.height); + localStorage.setItem("favorite-setup-saved-width",entry.target.style.width); + } + }); + + resizeObserver.observe(mainDiv); + + mainDiv.style.height = localStorage.getItem("favorite-setup-saved-height"); + mainDiv.style.width = localStorage.getItem("favorite-setup-saved-width"); + + dragElement(mainDiv, topDiv); + + // Reposition popup based on previous dragged location + const posTop = localStorage.getItem("favorite-setup-pos-top"); + const posLeft = localStorage.getItem("favorite-setup-pos-left"); + if (posTop && posLeft) { + const intTop = parseInt(posTop); + if (intTop > 0 && intTop < window.innerHeight - 150) { + mainDiv.style.top = posTop; + } + const intLeft = parseInt(posLeft); + if (intLeft > 0 && intLeft < window.innerWidth - 150) { + mainDiv.style.left = posLeft; + } } + } else { + alert( + "No owned item data available. Please refresh, click any of the 5 setup-changing boxes, and try again" + ); + } + hideExtraLocationRows () + } + } + function hideExtraLocationRows () { + const savedSetupRows = document.querySelectorAll('tr.tsitu-fave-setup-row'); - setupSelectorInput.value = ""; + for (const setup of savedSetupRows) { + + const setupLoc = setup.querySelector('.travelButton').textContent; + let setupLocCount = 0; + + for (const setup of savedSetupRows) { + if (setupLoc === setup.querySelector('.travelButton').textContent) { + setupLocCount++; + // hide extra rows of non-current locations that already have a visible setup + if (user.environment_name !== setupLoc && setupLocCount > 1) { + setup.style.display = "none"; + } + } } - }; + // console.log(`Total # of setups for ${setupLoc}: ${setupLocCount}`); + } + } - const setupSelectorDiv = document.createElement("div"); - setupSelectorDiv.className = "setupSelectorDiv"; - setupSelectorDiv.appendChild(setupSelector); - setupSelectorDiv.appendChild(setupSelectorInput); - - // TODO: Improve async logic, probably await completion of a component switch otherwise might overlap and/or silently fail - // TODO: [med] Import/export setup "profiles" (separate dropdown of profiles) (export specific profile obj to dropbox/pastebin?) - // ^ Profile management could be an elegant bulk grouping solution if done properly - // TODO: [med] Mobile UX for drag & drop as well as scrollable div (jquery-ui-touch-punch did not work for simulating touch events) - // TODO: [low] Skin implementation/checks (in-progress, but either save for later or scrap entirely since use case is minimal) - - const scroller = document.createElement("div"); - scroller.id = "scroller"; - // Setup table styling - const setupTable = document.createElement("table"); - const setupTbody = document.createElement("tbody"); - setupTbody.id = "setupTbody"; - - const setupTableDiv = document.createElement("div"); - setupTableDiv.id = "setupTableDiv"; - - // Sort setups from the current location to the top of the list - function locSort (name) { - //console.log("saved loc: "+savedSetups[name].location, "\n loc bool: "+!!savedSetups[name].location, "\n current loc: "+user.environment_name, "\n current loc bool: "+!!user.environment_name, "\n current loc is saved loc: "+(user.environment_name===savedSetups[name].location), "\n test: "+(!!savedSetups[name].location && user.environment_name == savedSetups[name].location)); - if (user.environment_name === savedSetups[name].location) { - //console.log("saved loc: "+savedSetups[name].location, "\n loc bool: "+!!savedSetups[name].location, "\n current loc: "+user.environment_name, "\n current loc bool: "+!!user.environment_name, "\n current loc is saved loc: "+(user.environment_name===savedSetups[name].location), "\n test: "+(!!savedSetups[name].location && user.environment_name == savedSetups[name].location)); - savedSetups[name].sort -= 420; - //console.log("location sorted setup: "+savedSetups[name]) - }; - }; - - savedSetupSortKeys.forEach(name => { - locSort(name); - }); - - const sortedSetupKeys = Object.keys(savedSetups).sort((a, b) => { - return savedSetups[a].sort - savedSetups[b].sort; - }); - - // Generate and append each saved setup as a new - sortedSetupKeys.forEach(name => { - generateRow(name); - }); - - function generateRow(name) { - const el = savedSetups[name]; - const elKeys = Object.keys(savedSetups[name]).sort((a, b) => { - return displayOrder[a] - displayOrder[b]; - }); - - const imgSpan = document.createElement("button"); - imgSpan.className = "button"; - imgSpan.id = "imgSpan"; - - for (let type of elKeys) { - if (type === "sort") continue; - if (type === "skin") continue; - if (type === "location") continue; - - const img = document.createElement("img"); - let item = el[type]; - if (data.weapon["Golem Guardian Trap"] !== undefined) { - if (type === "weapon") { - if (item.indexOf("Golem Guardian") >= 0) { - item = "Golem Guardian Trap"; - } else if (item.indexOf("Isle Idol") >= 0) { - item = "Isle Idol Trap"; - } - } - } - img.title = item; - if (item === "N/A") { - if (type === "bait") img.title = "Disarm Bait"; - if (type === "trinket") img.title = "Disarm Charm"; - // if (type === "skin") img.title = "Disarm Skin"; - } - img.onclick = function () { - // Mobile tooltip behavior = LOW priority because long pressing works on FF - // const appendTitle = img.querySelector(".append-title"); - // if (!appendTitle) { - // const appendSpan = document.createElement("span"); - // appendSpan.className = "append-title"; - // appendSpan.style.position = "absolute"; - // appendSpan.style.padding = "4px"; - // // appendSpan.textContent = item; - // appendSpan.textContent = img.title; - // img.append(appendSpan); - // } else { - // appendTitle.remove(); - // } - }; - img.src = - "https://www.mousehuntgame.com/images/items/stats/ee8f12ab8e042415063ef4140cefab7b.gif?cv=243"; - if (data[type][item]) img.src = data[type][item][1]; - imgSpan.appendChild(img); - }; - imgSpan.onclick = function () { //ast location mod - batchLoad(el.bait, el.base, el.weapon, el.trinket, el.skin); - console.log("armed '"+name+"': ", el.bait, el.base, el.weapon, el.trinket, el.skin, el.location); - }; - - const nameSpan = document.createElement("span"); - nameSpan.className = "tsitu-fave-setup-namespan"; - nameSpan.textContent = name; - - const editButton = document.createElement("button"); - editButton.id = "editButton"; - editButton.className = "button"; - editButton.textContent = "✏️"; - editButton.onclick = function () { - document.querySelector("#collapsible").checked = true; - document.querySelector("#favorite-setup-input-cheese").value = - el.bait === "N/A" ? "" : el.bait; - document.querySelector("#favorite-setup-input-base").value = - el.base === "N/A" ? "" : el.base; - document.querySelector("#favorite-setup-input-weapon").value = - el.weapon === "N/A" ? "" : el.weapon; - document.querySelector("#favorite-setup-input-charm").value = - el.trinket === "N/A" ? "" : el.trinket; - document.querySelector("#favorite-setup-input-location").value = - el.location === "N/A" ? "" : el.location; - // document.querySelector("#favorite-setup-input-skin").value = - // el.skin === "N/A" ? "" : el.skin; - document.querySelector("#favorite-setup-name").value = name || ""; - editSort = el.sort; // for sorting name-edited setups after the originating setup this button was clicked on - console.log("editing setup: "+name+" from sort position "+editSort); - document.getElementById("favorite-setup-name").focus(); // ast location mod - }; - - const deleteButton = document.createElement("button"); - deleteButton.id = "deleteButton"; - deleteButton.className = "button"; - deleteButton.textContent = "🗑️"; - deleteButton.onclick = function () { - if (confirm(`Delete setup '${name}'?`)) { - const storedRaw = localStorage.getItem("favorite-setups-saved"); - if (storedRaw) { - const storedData = JSON.parse(storedRaw); - if (storedData[name]) delete storedData[name]; - localStorage.setItem( - "favorite-setups-saved", - JSON.stringify(storedData) - ); - // to delete from DOM without a re-render - var i = this.parentNode.rowIndex; - console.log("deleted '"+name+"' from rowIndex: "+i); - document.getElementById("setupTbody").deleteRow(i); - } - } - }; - - const travelButton = document.createElement("button"); //ast location mod - travelButton.className = "travelButton"; - travelButton.title = "Left click to travel, Right click to update setup location to current location" - if (el.location) { - travelButton.textContent = el.location; - } else { - travelButton.textContent = 'N/A' - }; - travelButton.onclick = function () { - app.pages.TravelPage.travel (locMap[el.location].type); - }; - //refresh setup with location to ease migration of old setups - travelButton.oncontextmenu = function() { - const bait = el.bait; - const base = el.base; - const weapon = el.weapon; - const charm = el.trinket; - const location = user.environment_name // ast location mod - - if (name.length >= 1 && name.length <= 30) { - const obj = {}; - obj[name] = { - bait: "N/A", - base: "N/A", - weapon: "N/A", - trinket: "N/A", - skin: "N/A" - ,location: "N/A" // ast location mod - }; - - if (data.bait[bait] !== undefined) obj[name].bait = bait; - if (data.base[base] !== undefined) obj[name].base = base; - if (data.weapon[weapon] !== undefined) obj[name].weapon = weapon; - if (data.trinket[charm] !== undefined) obj[name].trinket = charm; - // if (data.skin[skin] !== undefined) obj[name].skin = skin; - obj[name].location = location; // ast location mod - obj[name].sort = editSort; // ast location mod - console.log("saved setup '"+name+"': "+JSON.stringify(obj[name])); // ast location mod - - const storedRaw = localStorage.getItem("favorite-setups-saved"); - if (storedRaw) { - const storedData = JSON.parse(storedRaw); - if (storedData[name] !== undefined) { - if (confirm(`Do you want to overwrite saved setup '${name}'?`)) { - obj[name].sort = storedData[name].sort; - } else { - return; - } - } - storedData[name] = obj[name]; - localStorage.setItem( - "favorite-setups-saved", - JSON.stringify(storedData) - ); - } else { - localStorage.setItem("favorite-setups-saved", JSON.stringify(obj)); - } - var saveScroll = document.getElementById("scroller").scrollTop; // ast location mod - render(); - document.getElementById("scroller").scrollTop = saveScroll; - } else { - alert( - "Please enter a name for your setup that is between 1-20 characters" - ); - }; - }; - - const setupRow = document.createElement("tr"); - setupRow.className = "tsitu-fave-setup-row"; - setupRow.appendChild(nameSpan); - setupRow.appendChild(travelButton); - setupRow.appendChild(imgSpan); - setupRow.appendChild(editButton); - setupRow.appendChild(deleteButton); - setupTbody.appendChild(setupRow); - } - - // Toggle sort lock/unlock - const toggleSort = document.createElement("button"); // ast location mod - toggleSort.id = "toggleSort"; - toggleSort.innerText = "Click to unlock drag and drop sort";// "Reset Sort Order"; - toggleSort.onclick = function () { - var disabled = $(setupTbody).sortable("option", "disabled"); - if (disabled) { - $(setupTbody).sortable("enable"); - toggleSort.innerText = "Drag to sort"; - GM_addStyle( //disable setup name selection when dragging - " .tsitu-fave-setup-namespan { grid-area: a; font-size: inherit; text-align: left; text-overflow: ellipsis; user-select: none;}" - ); - } else { - $(setupTbody).sortable("disable"); - toggleSort.innerText = "Click to unlock sort"; - GM_addStyle( - " .tsitu-fave-setup-namespan { grid-area: a; font-size: inherit; text-align: left; text-overflow: ellipsis; user-select: text;}" - ); - } - }; - - // Make the table drag & drop-able via jQuery sortable() - GM_addStyle( - ".ui-state-highlight-tsitu { height: 68px; background-color: #FAFFAF; }" - ); - $(setupTbody).sortable({ - placeholder: "ui-state-highlight-tsitu", - scroll: true, - scrollSensitivity: 80, - scrollSpeed: 20, - cursor: "move", - disabled: true, - update: function() { - const storedRaw = localStorage.getItem("favorite-setups-saved"); - if (storedRaw) { - const storedData = JSON.parse(storedRaw); - const nameSpans = document.querySelectorAll( - ".tsitu-fave-setup-namespan" - ); - if (nameSpans.length === Object.keys(storedData).length) { - for (let i = 0; i < nameSpans.length; i++) { - const name = nameSpans[i].textContent; - if (storedData[name] !== undefined) { - storedData[name].sort = i; - } - } - localStorage.setItem( - "favorite-setups-saved", - JSON.stringify(storedData) - ); - } - } - } - }); - setupTable.appendChild(setupTbody); - setupTableDiv.appendChild(setupTable); - - // Append everything to main popup UI - mainDiv.appendChild(topDiv); - mainDiv.appendChild(buttonSpan); - mainDiv.appendChild(collapsibleCheckbox); - mainDiv.appendChild(dataListDiv); - mainDiv.appendChild(setupSelectorDiv); - scroller.appendChild(setupTableDiv); - mainDiv.appendChild(scroller); - mainDiv.appendChild(toggleSort); - document.body.appendChild(mainDiv); - - const resizeObserver = new ResizeObserver(entries => { - for (let entry of entries) { - // console.log(`${entry.target.style.height} h + ${entry.target.style.width} w`); - localStorage.setItem("favorite-setup-saved-height",entry.target.style.height); - localStorage.setItem("favorite-setup-saved-width",entry.target.style.width); + // Inject initial button/link into UI + function injectUI() { + document.querySelectorAll("#fave-setup-button").forEach(el => el.remove()); + + const lsPlacement = localStorage.getItem("favorite-setup-placement"); + if (lsPlacement === "tem") { + const target = document.querySelector( + ".campPage-trap-armedItemContainer" + ); + if (target) { + const div = document.createElement("div"); + div.id = "fave-setup-button"; + const button = document.createElement("button"); + button.innerText = "Favorite Setups"; + button.addEventListener("click", function () { + toggleRender() + }); + button.addEventListener("contextmenu", function () { + if (confirm("Toggle 'Favorite Setups' placement?")) { + localStorage.setItem("favorite-setup-placement", "top"); + injectUI(); + } else { + localStorage.setItem("favorite-setup-placement", "tem"); + } + }); + div.appendChild(document.createElement("br")); + div.appendChild(button); + target.appendChild(div); } - }); + } else { + const target = document.querySelector(".mousehuntHud-gameInfo"); + if (target) { + const link = document.createElement("a"); + link.id = "fave-setup-button"; + link.innerText = "[Favorite Setups]"; + link.addEventListener("click", function () { + toggleRender(); + return false; // Prevent default link clicked behavior + }); + link.addEventListener("contextmenu", function () { + if (confirm("Toggle '[Favorite Setups]' placement?")) { + localStorage.setItem("favorite-setup-placement", "tem"); + injectUI(); + } else { + localStorage.setItem("favorite-setup-placement", "top"); + } + }); + target.prepend(link); + } + } + } + // retain previous open/close behaviour + var openedSettings = localStorage.getItem('showSetups'); + console.log(openedSettings); + if(openedSettings == "Y") { + console.log('test2'); + toggleRender(); + } + injectUI(); - resizeObserver.observe(mainDiv); - - mainDiv.style.height = localStorage.getItem("favorite-setup-saved-height"); - mainDiv.style.width = localStorage.getItem("favorite-setup-saved-width"); - - dragElement(mainDiv, topDiv); - - // Reposition popup based on previous dragged location - const posTop = localStorage.getItem("favorite-setup-pos-top"); - const posLeft = localStorage.getItem("favorite-setup-pos-left"); - if (posTop && posLeft) { - const intTop = parseInt(posTop); - if (intTop > 0 && intTop < window.innerHeight - 150) { - mainDiv.style.top = posTop; - } - const intLeft = parseInt(posLeft); - if (intLeft > 0 && intLeft < window.innerWidth - 150) { - mainDiv.style.left = posLeft; - } - } - } else { - alert( - "No owned item data available. Please refresh, click any of the 5 setup-changing boxes, and try again" - ); - } - } - - // Inject initial button/link into UI - function injectUI() { - document.querySelectorAll("#fave-setup-button").forEach(el => el.remove()); - - const lsPlacement = localStorage.getItem("favorite-setup-placement"); - if (lsPlacement === "tem") { - const target = document.querySelector( - ".campPage-trap-armedItemContainer" - ); - if (target) { - const div = document.createElement("div"); - div.id = "fave-setup-button"; - const button = document.createElement("button"); - button.innerText = "Favorite Setups"; - button.addEventListener("click", function () { - const existing = document.querySelector("#tsitu-fave-setups"); - if (existing) { - localStorage.setItem('showSetups', "N"); - existing.remove(); - } - else { - localStorage.setItem('showSetups', "Y"); - render() - }; - }); - button.addEventListener("contextmenu", function () { - if (confirm("Toggle 'Favorite Setups' placement?")) { - localStorage.setItem("favorite-setup-placement", "top"); - injectUI(); - } else { - localStorage.setItem("favorite-setup-placement", "tem"); - } - }); - div.appendChild(document.createElement("br")); - div.appendChild(button); - target.appendChild(div); - } - } else { - const target = document.querySelector(".mousehuntHud-gameInfo"); - if (target) { - const link = document.createElement("a"); - link.id = "fave-setup-button"; - link.innerText = "[Favorite Setups]"; - link.addEventListener("click", function () { - const existing = document.querySelector("#tsitu-fave-setups"); - if (existing) { - localStorage.setItem('showSetups', "N"); // retain previous open/close behaviour - existing.remove(); - } - else { - render(); - localStorage.setItem('showSetups', "Y"); // retain previous open/close behaviour - }; - return false; // Prevent default link clicked behavior - }); - link.addEventListener("contextmenu", function () { - if (confirm("Toggle '[Favorite Setups]' placement?")) { - localStorage.setItem("favorite-setup-placement", "tem"); - injectUI(); - } else { - localStorage.setItem("favorite-setup-placement", "top"); - } - }); - target.prepend(link); - } - } - } - // retain previous open/close behaviour - var openedSettings = localStorage.getItem('showSetups'); - if(openedSettings == "Y") render(); - injectUI(); - - /** + /** * Element dragging functionality * @param {HTMLElement} el Element that actually moves * @param {HTMLElement} target Element to drag in order to move 'el' */ - function dragElement(el, target) { - var pos1 = 0, - pos2 = 0, - pos3 = 0, - pos4 = 0; - - if (document.getElementById(target.id + "header")) { - document.getElementById(target.id + "header").onmousedown = dragMouseDown; - } else { - target.onmousedown = dragMouseDown; - } - - function dragMouseDown(e) { - e = e || window.event; - pos3 = e.clientX; - pos4 = e.clientY; - document.onmouseup = closeDragElement; - document.onmousemove = elementDrag; - } - - function elementDrag(e) { - e = e || window.event; - pos1 = pos3 - e.clientX; - pos2 = pos4 - e.clientY; - pos3 = e.clientX; - pos4 = e.clientY; - el.style.top = el.offsetTop - pos2 + "px"; - el.style.left = el.offsetLeft - pos1 + "px"; - } - - function closeDragElement() { - document.onmouseup = null; - document.onmousemove = null; - localStorage.setItem("favorite-setup-pos-top", el.style.top); - localStorage.setItem("favorite-setup-pos-left", el.style.left); - } - } + function dragElement(el, target) { + var pos1 = 0, + pos2 = 0, + pos3 = 0, + pos4 = 0; + + if (document.getElementById(target.id + "header")) { + document.getElementById(target.id + "header").onmousedown = dragMouseDown; + } else { + target.onmousedown = dragMouseDown; + } + + function dragMouseDown(e) { + e = e || window.event; + pos3 = e.clientX; + pos4 = e.clientY; + document.onmouseup = closeDragElement; + document.onmousemove = elementDrag; + } + + function elementDrag(e) { + e = e || window.event; + pos1 = pos3 - e.clientX; + pos2 = pos4 - e.clientY; + pos3 = e.clientX; + pos4 = e.clientY; + el.style.top = el.offsetTop - pos2 + "px"; + el.style.left = el.offsetLeft - pos1 + "px"; + } + + function closeDragElement() { + document.onmouseup = null; + document.onmousemove = null; + localStorage.setItem("favorite-setup-pos-top", el.style.top); + localStorage.setItem("favorite-setup-pos-left", el.style.left); + } + } })(); From daf9fdc35d570530f4d65841cb96c450dd8667d9 Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sat, 1 Apr 2023 19:53:13 -0400 Subject: [PATCH 45/61] cleaning up consolelogs --- src/favorite-setups.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index d8a2076..f460cb3 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -2,7 +2,7 @@ // @name MouseHunt - Favorite Setups+ // @author PersonalPalimpsest (asterios) // @namespace https://greasyfork.org/en/users/900615-personalpalimpsest -// @version 2.3.2 +// @version 2.3.3 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* @@ -12,7 +12,7 @@ GM_addStyle ( ` #tsitu-fave-setups { background-color: #F5F5F5; position: fixed; - z-index: 69420; + z-index: 69; left: 5px; top: 5px; border: solid 3px #696969; @@ -1249,9 +1249,7 @@ GM_addStyle ( ` } // retain previous open/close behaviour var openedSettings = localStorage.getItem('showSetups'); - console.log(openedSettings); if(openedSettings == "Y") { - console.log('test2'); toggleRender(); } injectUI(); From 87900da2b6e36986fe59ced861bbdab57c425148 Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sat, 1 Apr 2023 19:57:24 -0400 Subject: [PATCH 46/61] Updating to reflect 2.3.3 --- favorite-setups-README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/favorite-setups-README.md b/favorite-setups-README.md index f18005e..b64180c 100644 --- a/favorite-setups-README.md +++ b/favorite-setups-README.md @@ -7,16 +7,17 @@ Allows the import/edit/saving of setups along with their associated locations, f Adds a bunch of features and densifies the UI for my personal preference. Differences from tsitu's script: **Known issues:** -- jump to setup search doesn't seem to work -- resizing isn't "sticky" across refreshes -- CSoS doesn't work, has to be saved as SoS -- location based auto-sorting gets funky when new setups are added and manual sorts haven't been done yet +- jump to setup search doesn't seem to work - FIXED +- resizing isn't "sticky" across refreshes - FIXED +- CSoS doesn't work, has to be saved as SoS - FIXED +- location based auto-sorting gets funky when new setups are added and manual sorts haven't been done yet - partly FIXED - if you want to help fix these problems or anything else, here's [the script on my github](https://github.com/PersonalPalimpsest/MH-Userscripts/blob/master/src/favorite-setups.js) **Location-based features:** - added location when saving and loading setups, along with a travel button for that location for each setup - right click function added to travel buttons to add the current location to a setup. helpful for migrating old setups so you don't have to recreate from scratch -- auto sorts setups with location = current location to the top. Does not update when you travel without reloading the page or the pop-up +- auto sorts setups with location = current location to the top. Now updates when you travel +- only shows the first setup of all locations other than the current one to reduce clutter **UX:** - 'Arm' button combined with the setup icons @@ -33,3 +34,4 @@ Adds a bunch of features and densifies the UI for my personal preference. Differ - collapsible data list section for more setups visible at once - adding disarm button - general CSS style changes to remove elements, shrink borders and padding, densify the display of setups, and other backend cleanup/rejigging +- resizable pop-up that remembers its size across page loads From 7769ad01787cb83e46fde7d083ca6eafc945257d Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sat, 1 Apr 2023 21:02:49 -0400 Subject: [PATCH 47/61] Update favorite-setups-README.md --- favorite-setups-README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/favorite-setups-README.md b/favorite-setups-README.md index b64180c..f95edc1 100644 --- a/favorite-setups-README.md +++ b/favorite-setups-README.md @@ -7,17 +7,17 @@ Allows the import/edit/saving of setups along with their associated locations, f Adds a bunch of features and densifies the UI for my personal preference. Differences from tsitu's script: **Known issues:** -- jump to setup search doesn't seem to work - FIXED -- resizing isn't "sticky" across refreshes - FIXED -- CSoS doesn't work, has to be saved as SoS - FIXED -- location based auto-sorting gets funky when new setups are added and manual sorts haven't been done yet - partly FIXED +~~- jump to setup search doesn't seem to work~~ FIXED +~~- resizing isn't "sticky" across refreshes~~ FIXED +~~- CSoS doesn't work, has to be saved as SoS~~ FIXED +- location based auto-sorting gets funky when new setups are added and manual sorts haven't been done yet - if you want to help fix these problems or anything else, here's [the script on my github](https://github.com/PersonalPalimpsest/MH-Userscripts/blob/master/src/favorite-setups.js) **Location-based features:** - added location when saving and loading setups, along with a travel button for that location for each setup -- right click function added to travel buttons to add the current location to a setup. helpful for migrating old setups so you don't have to recreate from scratch - auto sorts setups with location = current location to the top. Now updates when you travel - only shows the first setup of all locations other than the current one to reduce clutter +- right click function added to travel buttons to add the current location to a setup. helpful for migrating old setups so you don't have to recreate from scratch **UX:** - 'Arm' button combined with the setup icons From ff380d2b8be2b10b82cb1a8e593ab29a2731c571 Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sat, 1 Apr 2023 21:03:14 -0400 Subject: [PATCH 48/61] Update favorite-setups-README.md --- favorite-setups-README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/favorite-setups-README.md b/favorite-setups-README.md index f95edc1..80fd23d 100644 --- a/favorite-setups-README.md +++ b/favorite-setups-README.md @@ -7,9 +7,9 @@ Allows the import/edit/saving of setups along with their associated locations, f Adds a bunch of features and densifies the UI for my personal preference. Differences from tsitu's script: **Known issues:** -~~- jump to setup search doesn't seem to work~~ FIXED -~~- resizing isn't "sticky" across refreshes~~ FIXED -~~- CSoS doesn't work, has to be saved as SoS~~ FIXED +- ~~jump to setup search doesn't seem to work~~ FIXED +- ~~resizing isn't "sticky" across refreshes~~ FIXED +- ~~CSoS doesn't work, has to be saved as SoS~~ FIXED - location based auto-sorting gets funky when new setups are added and manual sorts haven't been done yet - if you want to help fix these problems or anything else, here's [the script on my github](https://github.com/PersonalPalimpsest/MH-Userscripts/blob/master/src/favorite-setups.js) From a965e2bb03f071adb1bff3f30fff4d0864797dbc Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Mon, 3 Apr 2023 15:47:34 -0400 Subject: [PATCH 49/61] Updated to work on travel using the Map interface --- src/favorite-setups.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index f460cb3..d01bbb1 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -2,7 +2,7 @@ // @name MouseHunt - Favorite Setups+ // @author PersonalPalimpsest (asterios) // @namespace https://greasyfork.org/en/users/900615-personalpalimpsest -// @version 2.3.3 +// @version 2.3.4 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* @@ -210,7 +210,7 @@ GM_addStyle ( ` #imgSpan img { max-height: 100%; max-width: 100%; - height: 3.2vh; /* change this to change the overall size which should scale with this */ + height: 3vh; /* change this to change the overall size which should scale with this */ // width: auto; // object-fit: scale-down; margin-bottom: -3px; @@ -318,7 +318,8 @@ GM_addStyle ( ` const travelObserver = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function () { this.addEventListener('load', function () { - if (this.responseURL == `https://www.mousehuntgame.com/managers/ajax/users/changeenvironment.php`) { + if (this.responseURL == `https://www.mousehuntgame.com/managers/ajax/users/changeenvironment.php` || + this.responseURL == `https://www.mousehuntgame.com/managers/ajax/users/treasuremap.php`) { console.log('Travel detected'); toggleRender(); toggleRender(); From 2296cb7a6a1b42ad12d9fec748b23a96e87d1d93 Mon Sep 17 00:00:00 2001 From: Hank McCord Date: Mon, 17 Apr 2023 11:42:31 -0400 Subject: [PATCH 50/61] Change all trap components with one API call --- src/favorite-setups.js | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index d01bbb1..4fce810 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -2,7 +2,7 @@ // @name MouseHunt - Favorite Setups+ // @author PersonalPalimpsest (asterios) // @namespace https://greasyfork.org/en/users/900615-personalpalimpsest -// @version 2.3.4 +// @version 2.4.0 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* @@ -487,44 +487,34 @@ GM_addStyle ( ` if (diffKeys.length === 0) { return; // Cancel if setup isn't changing - } else if (diffKeys.length >= 2) { - localStorage.setItem("tsitu-batch-loading", true); // Minimize Mapping Helper TEM requests by setting an in-progress bool } - function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); - } + // Since we only call `go` once, we dont need to set the batching local storage variable anymore + // localStorage.setItem("tsitu-batch-loading", true); // Minimize Mapping Helper TEM requests by setting an in-progress bool - let counter = 0; for (let classification of diffKeys) { /** - * TODO: Investigate bug that de-skins a weapon if you've used mobile app FS to arm a skinless weapon setup - * Attempted to emulate browser item selector click by calling `app.pages.CampPage.armItem(element)` - * Passed in a "fake" element with data-item-id so that `tmpItem` is derived - * Inside `armItem`: 'syncInventory' and/or 'loadItems' fills in 'trapItems' so that 'getItemById' works - * Final TrapControl requests seem to be identical with script... so the stuff before might be relevant - */ - counter += 1; - if (counter === diffKeys.length) { - localStorage.setItem("tsitu-batch-loading", false); // Reset bool in time for last request - } + * TODO: Investigate bug that de-skins a weapon if you've used mobile app FS to arm a skinless weapon setup + * Attempted to emulate browser item selector click by calling `app.pages.CampPage.armItem(element)` + * Passed in a "fake" element with data-item-id so that `tmpItem` is derived + * Inside `armItem`: 'syncInventory' and/or 'loadItems' fills in 'trapItems' so that 'getItemById' works + * Final TrapControl requests seem to be identical with script... so the stuff before might be relevant + */ const id = diff[classification]; if (id === "disarm") { - await hg.utils.TrapControl.disarmItem(classification).go(); + hg.utils.TrapControl.disarmItem(classification); } else { - await hg.utils.TrapControl.armItem(id, classification).go(); + hg.utils.TrapControl.armItem(id, classification); // console.log(id, classification); // const testEl = document.createElement("a"); // testEl.setAttribute("data-item-id", id); // console.log(testEl); // await app.pages.CampPage.armItem(testEl); } - await sleep(420); } - - // Another reset just in case something goes wrong inside the for...of - localStorage.setItem("tsitu-batch-loading", false); + // Change all the differences in one API call + hg.utils.TrapControl.go(); // Deprecated the old method because unable to prevent userinventory.php calls from syncArmedItems (caused by mobile/regular desync) // Witnessed up to an 18 request simul-slam (at least +1 increments starting from 3 / n-1 duplicates with 1 response's items[] different) From 833d7d400a3e8a6e01dd899de0b8afe2284bceaa Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sun, 15 Oct 2023 12:18:07 -0400 Subject: [PATCH 51/61] Cleaning up console spam --- src/favorite-setups.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 4fce810..f4601ef 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -2,7 +2,7 @@ // @name MouseHunt - Favorite Setups+ // @author PersonalPalimpsest (asterios) // @namespace https://greasyfork.org/en/users/900615-personalpalimpsest -// @version 2.4.0 +// @version 2.4.1 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* @@ -318,11 +318,15 @@ GM_addStyle ( ` const travelObserver = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function () { this.addEventListener('load', function () { - if (this.responseURL == `https://www.mousehuntgame.com/managers/ajax/users/changeenvironment.php` || - this.responseURL == `https://www.mousehuntgame.com/managers/ajax/users/treasuremap.php`) { - console.log('Travel detected'); - toggleRender(); - toggleRender(); + try { + if (this.responseURL == `https://www.mousehuntgame.com/managers/ajax/users/changeenvironment.php` || + this.responseURL == `https://www.mousehuntgame.com/managers/ajax/users/treasuremap.php` && JSON.parse(this.responseText).journal_markup[0].render_data.css_class == 'entry short travel' + ) { + console.log('Travel detected'); + toggleRender(); + toggleRender(); + } + } catch(error) { } }) travelObserver.apply(this, arguments); From e31e38e205accd7cba7c9c23bd198b7d76e9b7cd Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Wed, 24 Apr 2024 20:37:36 -0400 Subject: [PATCH 52/61] Moved top button position to menu bar --- src/favorite-setups.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index f4601ef..e38986d 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -2,7 +2,7 @@ // @name MouseHunt - Favorite Setups+ // @author PersonalPalimpsest (asterios) // @namespace https://greasyfork.org/en/users/900615-personalpalimpsest -// @version 2.4.1 +// @version 2.5.1 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* @@ -1221,16 +1221,17 @@ GM_addStyle ( ` target.appendChild(div); } } else { - const target = document.querySelector(".mousehuntHud-gameInfo"); + const target = document.querySelector(".mousehuntHeaderView-dropdownContainer"); if (target) { - const link = document.createElement("a"); - link.id = "fave-setup-button"; - link.innerText = "[Favorite Setups]"; - link.addEventListener("click", function () { + const setupTab = document.createElement("a"); + setupTab.id = "fave-setup-menu"; + setupTab.innerHTML = "Setups"; + setupTab.className = 'menuItem'; + setupTab.addEventListener("click", function () { toggleRender(); return false; // Prevent default link clicked behavior }); - link.addEventListener("contextmenu", function () { + setupTab.addEventListener("contextmenu", function () { if (confirm("Toggle '[Favorite Setups]' placement?")) { localStorage.setItem("favorite-setup-placement", "tem"); injectUI(); @@ -1238,7 +1239,7 @@ GM_addStyle ( ` localStorage.setItem("favorite-setup-placement", "top"); } }); - target.prepend(link); + target.prepend(setupTab); } } } From 4baef796ab9a04d21928cbc4fbdd15a4158a75af Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Wed, 24 Apr 2024 20:51:03 -0400 Subject: [PATCH 53/61] fixing element duplication bug --- src/favorite-setups.js | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index e38986d..87598b4 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -2,7 +2,7 @@ // @name MouseHunt - Favorite Setups+ // @author PersonalPalimpsest (asterios) // @namespace https://greasyfork.org/en/users/900615-personalpalimpsest -// @version 2.5.1 +// @version 2.5.2 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* @@ -1223,23 +1223,27 @@ GM_addStyle ( ` } else { const target = document.querySelector(".mousehuntHeaderView-dropdownContainer"); if (target) { - const setupTab = document.createElement("a"); - setupTab.id = "fave-setup-menu"; - setupTab.innerHTML = "Setups"; - setupTab.className = 'menuItem'; - setupTab.addEventListener("click", function () { - toggleRender(); - return false; // Prevent default link clicked behavior - }); - setupTab.addEventListener("contextmenu", function () { - if (confirm("Toggle '[Favorite Setups]' placement?")) { - localStorage.setItem("favorite-setup-placement", "tem"); - injectUI(); - } else { - localStorage.setItem("favorite-setup-placement", "top"); - } - }); - target.prepend(setupTab); + // Check if the setup tab already exists + let setupTabExists = document.querySelector('#fave-setup-menu'); + if (!setupTabExists) { + const setupTab = document.createElement("a"); + setupTab.id = "fave-setup-menu"; + setupTab.innerHTML = "Setups"; + setupTab.className = 'menuItem'; + setupTab.addEventListener("click", function () { + toggleRender(); + return false; // Prevent default link clicked behavior + }); + setupTab.addEventListener("contextmenu", function () { + if (confirm("Toggle '[Favorite Setups]' placement?")) { + localStorage.setItem("favorite-setup-placement", "tem"); + injectUI(); + } else { + localStorage.setItem("favorite-setup-placement", "top"); + } + }); + target.prepend(setupTab); + } } } } From abb40e2767b597e533de5b80a53f3728e5a76d35 Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sat, 8 Jun 2024 01:39:20 -0400 Subject: [PATCH 54/61] Add M1K aura button Adds button to top menu bar to launch a user prompt for the number of processors/hours of aura they wish to proc. --- src/favorite-setups.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 87598b4..e30e633 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -2,7 +2,7 @@ // @name MouseHunt - Favorite Setups+ // @author PersonalPalimpsest (asterios) // @namespace https://greasyfork.org/en/users/900615-personalpalimpsest -// @version 2.5.2 +// @version 2.6.0 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* @@ -1243,6 +1243,17 @@ GM_addStyle ( ` } }); target.prepend(setupTab); + + const m1kTab = document.createElement('a'); + m1kTab.id = 'm1k-aura-button'; + m1kTab.innerHTML = 'M1K'; + m1kTab.className = 'menuItem'; + m1kTab.addEventListener("click", function () { + let auraHrs = parseFloat(prompt('How many hours of aura?')); + hg.utils.UserInventory.useConvertible('fulminas_gift_convertible',auraHrs); + return false; // Prevent default link clicked behavior + }); + target.prepend(m1kTab); } } } From 408cbf88470acb8cbc2d0a9840fc01f73b7c3883 Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sat, 8 Jun 2024 01:40:25 -0400 Subject: [PATCH 55/61] corrected placeholder fulmina gift variable to kilohertz proc --- src/favorite-setups.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index e30e633..fd92396 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -2,7 +2,7 @@ // @name MouseHunt - Favorite Setups+ // @author PersonalPalimpsest (asterios) // @namespace https://greasyfork.org/en/users/900615-personalpalimpsest -// @version 2.6.0 +// @version 2.6.1 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* @@ -1250,7 +1250,7 @@ GM_addStyle ( ` m1kTab.className = 'menuItem'; m1kTab.addEventListener("click", function () { let auraHrs = parseFloat(prompt('How many hours of aura?')); - hg.utils.UserInventory.useConvertible('fulminas_gift_convertible',auraHrs); + hg.utils.UserInventory.useConvertible('kilohertz_processor_convertible',auraHrs); return false; // Prevent default link clicked behavior }); target.prepend(m1kTab); From 643daa12a0bb5dd1da5c6debde73e795c713a717 Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Sat, 8 Jun 2024 01:49:55 -0400 Subject: [PATCH 56/61] error handling when prompt value null or < 1 --- src/favorite-setups.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index fd92396..1a3d8be 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -2,11 +2,13 @@ // @name MouseHunt - Favorite Setups+ // @author PersonalPalimpsest (asterios) // @namespace https://greasyfork.org/en/users/900615-personalpalimpsest -// @version 2.6.1 +// @version 2.6.2 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* // @match https://www.mousehuntgame.com/* +// @downloadURL https://update.greasyfork.org/scripts/443164/MouseHunt%20-%20Favorite%20Setups%2B.user.js +// @updateURL https://update.greasyfork.org/scripts/443164/MouseHunt%20-%20Favorite%20Setups%2B.meta.js // ==/UserScript== GM_addStyle ( ` #tsitu-fave-setups { @@ -1250,7 +1252,9 @@ GM_addStyle ( ` m1kTab.className = 'menuItem'; m1kTab.addEventListener("click", function () { let auraHrs = parseFloat(prompt('How many hours of aura?')); - hg.utils.UserInventory.useConvertible('kilohertz_processor_convertible',auraHrs); + if (auraHrs >= 1){ + hg.utils.UserInventory.useConvertible('kilohertz_processor_convertible',auraHrs); + }; return false; // Prevent default link clicked behavior }); target.prepend(m1kTab); From c23b5191992feb0e6fcc6d837605cf966e046ce0 Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Tue, 29 Oct 2024 22:46:37 -0400 Subject: [PATCH 57/61] limit API calls for location list refreshing --- src/favorite-setups.js | 63 +++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 1a3d8be..b2a9a39 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -2,7 +2,7 @@ // @name MouseHunt - Favorite Setups+ // @author PersonalPalimpsest (asterios) // @namespace https://greasyfork.org/en/users/900615-personalpalimpsest -// @version 2.6.2 +// @version 2.7.0 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* @@ -289,32 +289,43 @@ GM_addStyle ( ` location: 6 }; - // Pull and save location list - const xhr = new XMLHttpRequest(); - xhr.open( - "POST", - `https://www.mousehuntgame.com/managers/ajax/pages/page.php?page_class=HunterProfile&page_arguments%5Btab%5D=mice&page_arguments%5Bsub_tab%5D=location&uh=${user.unique_hash}` - ); - xhr.onload = function () { - const response = JSON.parse(xhr.responseText); - const locations = - response.page.tabs.mice.subtabs[1].mouse_list.categories; - if (locations) { - const masterObj = {}; - - locations.forEach(el => { - const obj = {}; - obj["type"] = el.type; - masterObj[el.name] = obj; - }); - - localStorage.setItem( - "ast-location-mapping", - JSON.stringify(masterObj) - ); + const currentVersion = '2.7.0'; // Update this version number when you update the script + const storedVersion = localStorage.getItem('ast-location-script-version'); + + if (!storedVersion || storedVersion !== currentVersion) { + // Pull and save location list + const xhr = new XMLHttpRequest(); + xhr.open( + "POST", + `https://www.mousehuntgame.com/managers/ajax/pages/page.php?page_class=HunterProfile&page_arguments%5Btab%5D=mice&page_arguments%5Bsub_tab%5D=location&uh=${user.unique_hash}` + ); + xhr.onload = function () { + const response = JSON.parse(xhr.responseText); + const locations = + response.page.tabs.mice.subtabs[1].mouse_list.categories; + if (locations) { + const masterObj = {}; + + locations.forEach(el => { + const obj = {}; + obj["type"] = el.type; + masterObj[el.name] = obj; + }); + + localStorage.setItem( + "ast-location-mapping", + JSON.stringify(masterObj) + ); + }; }; - }; - xhr.send(); + xhr.send(); + + + // Update the stored version + localStorage.setItem("ast-location-script-version", currentVersion); + } else { + console.log("Script is up-to-date, skipping location update."); + } // Re-render on location change const travelObserver = XMLHttpRequest.prototype.open; From 3b74d09cfec14cdfd78808c90e598221dad0c93b Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Tue, 3 Dec 2024 23:57:27 -0500 Subject: [PATCH 58/61] treasuremap_v2 endpoint and filter auto-scroll --- src/favorite-setups.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index b2a9a39..82d5876 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -2,7 +2,7 @@ // @name MouseHunt - Favorite Setups+ // @author PersonalPalimpsest (asterios) // @namespace https://greasyfork.org/en/users/900615-personalpalimpsest -// @version 2.7.0 +// @version 2.7.3 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* @@ -38,6 +38,7 @@ GM_addStyle ( ` font-weight: bold; font-size: 160%; text-decoration: underline; + color: black; } #tsitu-fave-setups #close-button { @@ -184,6 +185,7 @@ GM_addStyle ( ` padding-top: 3px; padding-left: 3px; margin-right: -1px; + color: black; } .travelButton { grid-area: b; @@ -333,7 +335,7 @@ GM_addStyle ( ` this.addEventListener('load', function () { try { if (this.responseURL == `https://www.mousehuntgame.com/managers/ajax/users/changeenvironment.php` || - this.responseURL == `https://www.mousehuntgame.com/managers/ajax/users/treasuremap.php` && JSON.parse(this.responseText).journal_markup[0].render_data.css_class == 'entry short travel' + this.responseURL == `https://www.mousehuntgame.com/managers/ajax/users/treasuremap_v2.php` && JSON.parse(this.responseText).journal_markup[0].render_data.css_class == 'entry short travel' ) { console.log('Travel detected'); toggleRender(); @@ -824,8 +826,8 @@ GM_addStyle ( ` scrollRow.style.backgroundColor = "#D6EBA1"; scrollRow.scrollIntoView({ behavior: "auto", - block: "nearest", - inline: "nearest" + block: "start", + inline: "start" }); } From 80fd5e07234c8ea0bd1d29e98383e9fbf700df78 Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Tue, 26 Aug 2025 13:50:25 -0400 Subject: [PATCH 59/61] added CJS button to FI HUD in fave setups+ --- src/favorite-setups.js | 139 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 138 insertions(+), 1 deletion(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 82d5876..914ceaf 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -2,7 +2,7 @@ // @name MouseHunt - Favorite Setups+ // @author PersonalPalimpsest (asterios) // @namespace https://greasyfork.org/en/users/900615-personalpalimpsest -// @version 2.7.3 +// @version 2.8.0 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* @@ -1271,6 +1271,143 @@ GM_addStyle ( ` return false; // Prevent default link clicked behavior }); target.prepend(m1kTab); + + /* -----------Floating Islands (FI) CJS Button------------ */ + // A flag to track if the mouse is hovering over the button + let isHovering = false; + + // Rephrased text to minimize redundancy + const auraActionTexts = { + activate: { + prompt: 'How many days of aura?', + log: 'Activating aura for', + }, + extend: { + prompt: 'How many days to extend the aura?', + log: 'Extending aura for', + } + }; + + // The function to handle activating or extending the aura + const handleAuraAction = (action) => { + const texts = auraActionTexts[action]; + + const days = parseFloat(prompt(texts.prompt)); + if (days >= 1) { + console.log(`${texts.log} ${days} days.`); + hg.utils.UserInventory.useConvertible('jet_stream_crate_convertible', days); + } else { + console.log("Invalid number of days. Aura not activated/extended."); + } + }; + + // The function to update the button's appearance based on the aura's state + const updateAuraButtonState = () => { + const activeAuraIcon = document.querySelector(".QuestJetStreamAura.active"); + const auraButton = document.getElementById('aura-button'); + + if (auraButton) { + if (!isHovering) { + if (activeAuraIcon) { + auraButton.textContent = 'JS ON'; + } else { + auraButton.textContent = 'JS OFF'; + } + } + + if (activeAuraIcon) { + // Aura is ON (Blue) + auraButton.style.backgroundColor = 'rgb(29, 197, 247)'; + + auraButton.onclick = () => handleAuraAction('extend'); + } else { + // Aura is OFF (Grey) + auraButton.style.backgroundColor = '#666666'; + + auraButton.onclick = () => handleAuraAction('activate'); + } + } + }; + + // The function to create and insert the aura button + const createAuraButton = () => { + if (document.getElementById('aura-button')) { + return; + } + + const fuelButton = document.querySelector(".floatingIslandsHUD-fuel-button"); + if (fuelButton) { + const newButton = document.createElement('div'); + newButton.id = 'aura-button'; + + // --- Shared static styles --- + newButton.style.color = 'rgb(255, 255, 255)'; + newButton.style.opacity = '0.9'; + newButton.style.position = 'absolute'; + newButton.style.bottom = '-2px'; + newButton.style.left = '50%'; + newButton.style.transform = 'translateX(-50%)'; + newButton.style.border = '1px solid transparent'; + newButton.style.zIndex = '2'; + newButton.style.padding = '0px 2px'; + newButton.style.borderRadius = '3px'; + newButton.style.width = '38px'; + newButton.style.textAlign = 'center'; + newButton.style.cursor = 'pointer'; + newButton.style.boxShadow = '0 0 0 1px rgba(0, 0, 0, 0.3)'; + // --- End of shared styles --- + + // Set the hover events with the isHovering flag + newButton.onmouseover = function() { + isHovering = true; + this.style.filter = 'brightness(1.2)'; + if (this.textContent === 'JS ON') { + this.textContent = 'Extend'; + } else if (this.textContent === 'JS OFF') { + this.textContent = 'Activate'; + } + }; + newButton.onmouseleave = function() { + isHovering = false; + this.style.filter = 'none'; + if (document.querySelector(".QuestJetStreamAura.active")) { + this.textContent = 'JS ON'; + } else { + this.textContent = 'JS OFF'; + } + }; + + fuelButton.after(newButton); + } + }; + + // The function that performs the DOM injections and updates + const performDomUpdates = () => { + observer.disconnect(); + + // --- TESTING CODE: Force the aura state to OFF --- + // const activeAurasForTesting = document.querySelectorAll(".QuestJetStreamAura.active"); + // activeAurasForTesting.forEach(aura => { + // aura.classList.remove('active'); + // }); + // --------------------------------------------- + + createAuraButton(); + updateAuraButtonState(); + const config = { childList: true, subtree: true }; + observer.observe(document.body, config); + }; + + // Set up a MutationObserver to watch the body for changes + const observer = new MutationObserver(performDomUpdates); + + // The initial config to start watching the body + const initialConfig = { childList: true, subtree: true }; + observer.observe(document.body, initialConfig); + + // Initial call to run the injections on page load + performDomUpdates(); + /* -----------Floating Islands (FI) CJS Button------------ */ } } } From 5435dfee33516b8749df2402ad25fabd63bd05c1 Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Thu, 11 Sep 2025 18:31:52 -0400 Subject: [PATCH 60/61] update version # so it pulls location again --- src/favorite-setups.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index 914ceaf..ea4af17 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -2,7 +2,7 @@ // @name MouseHunt - Favorite Setups+ // @author PersonalPalimpsest (asterios) // @namespace https://greasyfork.org/en/users/900615-personalpalimpsest -// @version 2.8.0 +// @version 2.8.1 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* @@ -291,7 +291,7 @@ GM_addStyle ( ` location: 6 }; - const currentVersion = '2.7.0'; // Update this version number when you update the script + const currentVersion = '2.8.1'; // Update this version number when you update the script const storedVersion = localStorage.getItem('ast-location-script-version'); if (!storedVersion || storedVersion !== currentVersion) { From e66a619b0dc0d5beb59b8c75bdb7a4bfe67aca95 Mon Sep 17 00:00:00 2001 From: asterios <22689840+PersonalPalimpsest@users.noreply.github.com> Date: Thu, 20 Nov 2025 19:37:38 -0500 Subject: [PATCH 61/61] add GOTD button to swap base and charm --- src/favorite-setups.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/favorite-setups.js b/src/favorite-setups.js index ea4af17..ad7ddbe 100644 --- a/src/favorite-setups.js +++ b/src/favorite-setups.js @@ -2,7 +2,7 @@ // @name MouseHunt - Favorite Setups+ // @author PersonalPalimpsest (asterios) // @namespace https://greasyfork.org/en/users/900615-personalpalimpsest -// @version 2.8.1 +// @version 2.9.0 // @description Unlimited custom favorite trap setups! // @grant GM_addStyle // @match http://www.mousehuntgame.com/* @@ -291,7 +291,7 @@ GM_addStyle ( ` location: 6 }; - const currentVersion = '2.8.1'; // Update this version number when you update the script + const currentVersion = '2.9.0'; // Update this version number when you update the script const storedVersion = localStorage.getItem('ast-location-script-version'); if (!storedVersion || storedVersion !== currentVersion) { @@ -744,6 +744,15 @@ GM_addStyle ( ` document.querySelector("#favorite-setup-input-location").value = ""; }; + const gotdButton = document.createElement("button"); + gotdButton.className = "button"; + gotdButton.textContent = "GOTD"; + gotdButton.onclick = function () { + hg.utils.TrapControl.armItem(1478,'trinket'); //unstable + hg.utils.TrapControl.armItem(3150,'base'); //LE GOTD base + hg.utils.TrapControl.go() + }; + const disarmButton = document.createElement("button"); disarmButton.className = "button"; disarmButton.textContent = "Disarm"; @@ -756,6 +765,7 @@ GM_addStyle ( ` buttonSpan.appendChild(loadButton); buttonSpan.appendChild(saveButton); buttonSpan.appendChild(resetButton); + buttonSpan.appendChild(gotdButton); buttonSpan.appendChild(disarmButton); // Sort existing saved setups