GC Quickstock Helper (Form over Function)

Adds a button to items that have not been tagged on Quick Stock that allows you to save your Deposit, Stock, Discard preference. To remove a preference, use the "Remove Item" button in the Tampermonkey menu (in your browser extensions). The button will load again for that item on next refresh. Recommend turning off auto-update to protect your GM Storage. Copy your GM Storage text to notepad before updating, then paste back in after update.

  1. // ==UserScript==
  2. // @name GC Quickstock Helper (Form over Function)
  3. // @namespace https://greasyfork.org/users/1295622
  4. // @version 1.5
  5. // @description Adds a button to items that have not been tagged on Quick Stock that allows you to save your Deposit, Stock, Discard preference. To remove a preference, use the "Remove Item" button in the Tampermonkey menu (in your browser extensions). The button will load again for that item on next refresh. Recommend turning off auto-update to protect your GM Storage. Copy your GM Storage text to notepad before updating, then paste back in after update.
  6. // @author spiderpool1855 (based on Dij's auto discard script)
  7. // @match https://www.grundos.cafe/quickstock/
  8. // @match https://grundos.cafe/quickstock/
  9. // @grant GM.getValue
  10. // @grant GM.setValue
  11. // @grant GM.deleteValue
  12. // @grant GM.registerMenuCommand
  13. // @grant GM.addStyle
  14. // @grant GM.xmlHttpRequest
  15. // @license MIT
  16. // ==/UserScript==
  17.  
  18. (function() {
  19. 'use strict';
  20.  
  21. async function setVariableValue(variableName, promptMessage, action) {
  22. let currentValue = JSON.parse(await GM.getValue(variableName, '[]'));
  23. let userInput = prompt(promptMessage);
  24.  
  25. if (userInput !== null) {
  26. switch (action) {
  27. case 'add':
  28. if (!currentValue.includes(userInput)) {
  29. currentValue.push(userInput);
  30. }
  31. break;
  32. case 'remove':
  33. currentValue = currentValue.filter(item => item !== userInput);
  34. break;
  35. }
  36. GM.setValue(variableName, JSON.stringify(currentValue));
  37. }
  38. }
  39.  
  40. async function removeFromAll(promptMessage) {
  41. let userInput = prompt(promptMessage);
  42.  
  43. if (userInput !== null) {
  44. let discard = JSON.parse(await GM.getValue('defaultDiscard', '[]'));
  45. let stock = JSON.parse(await GM.getValue('defaultStock', '[]'));
  46. let deposit = JSON.parse(await GM.getValue('defaultDeposit', '[]'));
  47.  
  48. discard = discard.filter(item => item !== userInput);
  49. stock = stock.filter(item => item !== userInput);
  50. deposit = deposit.filter(item => item !== userInput);
  51.  
  52. GM.setValue('defaultDiscard', JSON.stringify(discard));
  53. GM.setValue('defaultStock', JSON.stringify(stock));
  54. GM.setValue('defaultDeposit', JSON.stringify(deposit));
  55. }
  56. }
  57.  
  58. GM.registerMenuCommand("Remove item", function() {
  59. removeFromAll('Remove item: ');
  60. });
  61. })();
  62.  
  63.  
  64. (async function() {
  65. 'use strict';
  66.  
  67. // Load arrays from GM storage or start new
  68. const defaultDiscard = JSON.parse(await GM.getValue('defaultDiscard', '[]'));
  69. const defaultStock = JSON.parse(await GM.getValue('defaultStock', '[]'));
  70. const defaultDeposit = JSON.parse(await GM.getValue('defaultDeposit', '[]'));
  71.  
  72. // save arrays to GM storage
  73. async function saveArrays() {
  74. await GM.setValue('defaultDiscard', JSON.stringify(defaultDiscard));
  75. await GM.setValue('defaultStock', JSON.stringify(defaultStock));
  76. await GM.setValue('defaultDeposit', JSON.stringify(defaultDeposit));
  77. }
  78.  
  79. // create a button with dropdown
  80. function addTaggingButton(itemElement, itemName) {
  81. const button = document.createElement('button');
  82. button.type = "button";
  83. button.style.width = '10px';
  84. button.style.height = '5px';
  85. button.style.marginLeft = '10px';
  86. button.style.cursor = 'pointer';
  87. //button.style.border = 'none'; // Optional: remove border
  88.  
  89. // Create dropdown menu
  90. const select = document.createElement('select');
  91. const options = ['Add to List', 'Deposit', 'Stock', 'Discard'];
  92. options.forEach(option => {
  93. const opt = document.createElement('option');
  94. opt.value = option;
  95. opt.textContent = option;
  96. select.appendChild(opt);
  97. });
  98. select.style.display = 'none';
  99. select.style.position = 'absolute';
  100. select.style.zIndex = '1000'; // Ensure dropdown appears on top
  101.  
  102. // Show dropdown on button click
  103. button.addEventListener('click', (event) => {
  104. event.stopPropagation();
  105. select.style.display = (select.style.display === 'none') ? 'inline' : 'none';
  106. // Position the dropdown directly below the button
  107. select.style.top = `${button.offsetTop + button.offsetHeight}px`;
  108. select.style.left = `${button.offsetLeft}px`;
  109. });
  110.  
  111. // Update arrays on selection
  112. select.addEventListener('change', async () => {
  113. const value = select.value;
  114. switch (value) {
  115. case 'Deposit':
  116. if (!defaultDeposit.includes(itemName)) {
  117. defaultDeposit.push(itemName);
  118. }
  119. if (defaultStock.includes(itemName)) {
  120. defaultStock.splice(defaultStock.indexOf(itemName), 1);
  121. }
  122. if (defaultDiscard.includes(itemName)) {
  123. defaultDiscard.splice(defaultDiscard.indexOf(itemName), 1);
  124. }
  125. break;
  126. case 'Stock':
  127. if (!defaultStock.includes(itemName)) {
  128. defaultStock.push(itemName);
  129. }
  130. if (defaultDeposit.includes(itemName)) {
  131. defaultDeposit.splice(defaultDeposit.indexOf(itemName), 1);
  132. }
  133. if (defaultDiscard.includes(itemName)) {
  134. defaultDiscard.splice(defaultDiscard.indexOf(itemName), 1);
  135. }
  136. break;
  137. case 'Discard':
  138. if (!defaultDiscard.includes(itemName)) {
  139. defaultDiscard.push(itemName);
  140. }
  141. if (defaultDeposit.includes(itemName)) {
  142. defaultDeposit.splice(defaultDeposit.indexOf(itemName), 1);
  143. }
  144. if (defaultStock.includes(itemName)) {
  145. defaultStock.splice(defaultStock.indexOf(itemName), 1);
  146. }
  147. break;
  148. }
  149. // Save arrays after modification
  150. await saveArrays();
  151. // Hide dropdown and remove button after selection
  152. select.style.display = 'none';
  153. button.remove();
  154. updateItems();
  155. });
  156.  
  157. itemElement.appendChild(button);
  158. itemElement.appendChild(select);
  159. }
  160.  
  161. // fill out quickstock form with chosen selections
  162. function updateItems() {
  163. const quickstock = document.querySelector("main .market_grid");
  164. if (!quickstock) return;
  165.  
  166. const gridLength = quickstock.querySelectorAll(".header").length;
  167. const quickstockNames = quickstock.querySelectorAll(".data.justify-right");
  168. const quickstockDeposit = quickstock.querySelectorAll(`.data:nth-child(${gridLength}n+3)`);
  169. const quickstockStock = quickstock.querySelectorAll(`.data:nth-child(${gridLength}n+2)`);
  170. const quickstockDiscard = quickstock.querySelectorAll(`.data:nth-child(${gridLength}n+5)`);
  171.  
  172. quickstockNames.forEach((itemName, index) => {
  173. const name = itemName.innerText;
  174. if (defaultDiscard.includes(name)) {
  175. quickstockDiscard[index].children[0].checked = true;
  176. } else if (defaultStock.includes(name)) {
  177. quickstockStock[index].children[0].checked = true;
  178. } else if (defaultDeposit.includes(name)) {
  179. quickstockDeposit[index].children[0].checked = true;
  180. }
  181.  
  182. // Add tagging button only if the item is not in any of the arrays
  183. if (!defaultDiscard.includes(name) && !defaultStock.includes(name) && !defaultDeposit.includes(name)) {
  184. if (!quickstockNames[index].querySelector('button')) {
  185. addTaggingButton(quickstockNames[index], name);
  186. }
  187. }
  188. });
  189. }
  190.  
  191. // Allows page to see the array change after initial dropdown selection so it will fill quickstock without a refresh
  192. const observer = new MutationObserver(() => {
  193. updateItems();
  194. // Disconnect the observer after the initial update
  195. observer.disconnect();
  196. });
  197.  
  198. // Initial update and start observing
  199. updateItems();
  200. observer.observe(document.body, { childList: true, subtree: true });
  201.  
  202. })();