Filter Items by Price on Dead Frontier

Filter items on the Dead Frontier market page by user-defined price range and category

  1. // ==UserScript==
  2. // @name Filter Items by Price on Dead Frontier
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.9.1
  5. // @description Filter items on the Dead Frontier market page by user-defined price range and category
  6. // @author Diabetus
  7. // @match https://fairview.deadfrontier.com/onlinezombiemmo/index.php?page=35
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13.  
  14. // Function to validate price input
  15. function validatePriceInput(price) {
  16. const priceRegex = /^\$\d{1,3}(,\d{3})*$/; // Matches $ and commas in the correct format
  17. return priceRegex.test(price);
  18. }
  19.  
  20. // Function to parse price string into a number
  21. function parsePrice(priceString) {
  22. return parseInt(priceString.replace(/[^0-9]/g, ''), 10);
  23. }
  24.  
  25. // Function to filter items by price range
  26. function filterByPriceRange(minPrice, maxPrice) {
  27. const items = document.querySelectorAll('.fakeItem');
  28.  
  29. items.forEach(item => {
  30. const salePriceElement = item.querySelector('.salePrice');
  31.  
  32. if (salePriceElement) {
  33. const priceText = salePriceElement.textContent.trim();
  34.  
  35. if (validatePriceInput(priceText)) {
  36. const price = parsePrice(priceText);
  37.  
  38. if (price < minPrice || price > maxPrice) {
  39. item.style.display = 'none';
  40. } else {
  41. item.style.display = '';
  42. }
  43. }
  44. }
  45. });
  46. }
  47.  
  48. // Function to filter items by food type
  49. function filterByFoodType(type) {
  50. const items = document.querySelectorAll('.fakeItem');
  51.  
  52. items.forEach(item => {
  53. const itemType = item.getAttribute('data-type');
  54.  
  55. if (itemType) {
  56. if (type === 'cooked' && !itemType.includes('_cooked')) {
  57. item.style.display = 'none';
  58. } else if (type === 'uncooked' && itemType.includes('_cooked')) {
  59. item.style.display = 'none';
  60. } else {
  61. item.style.display = '';
  62. }
  63. }
  64. });
  65. }
  66.  
  67. // Function to reset visibility for all food items
  68. function resetAllFoodItems() {
  69. const items = document.querySelectorAll('.fakeItem');
  70.  
  71. items.forEach(item => {
  72. const itemType = item.getAttribute('data-type');
  73.  
  74. if (itemType && itemType.includes('food')) {
  75. item.style.display = '';
  76. }
  77. });
  78. }
  79.  
  80. // Function to filter items by affordability
  81. function filterByAffordability() {
  82. const cashElement = document.querySelector('.heldCash');
  83. const heldCash = parsePrice(cashElement.getAttribute('data-cash'));
  84.  
  85. const items = document.querySelectorAll('.fakeItem');
  86. items.forEach(item => {
  87. const salePriceElement = item.querySelector('.salePrice');
  88.  
  89. if (salePriceElement) {
  90. const priceText = salePriceElement.textContent.trim();
  91. const price = validatePriceInput(priceText) ? parsePrice(priceText) : Infinity;
  92.  
  93. if (price > heldCash) {
  94. item.style.display = 'none';
  95. } else {
  96. item.style.display = '';
  97. }
  98. }
  99. });
  100. }
  101.  
  102. // Function to toggle food options visibility based on category
  103. function toggleFoodOptionsVisibility() {
  104. const foodOptions = document.querySelectorAll('[name="foodType"], label[for="cookedFood"], label[for="uncookedFood"], label[for="bothFood"]');
  105. const currentCategory = document.querySelector('#categoryChoice')?.getAttribute('data-catname');
  106.  
  107. if (currentCategory === 'food') {
  108. foodOptions.forEach(option => {
  109. option.style.display = '';
  110. });
  111. } else {
  112. foodOptions.forEach(option => {
  113. option.style.display = 'none';
  114. });
  115. }
  116. }
  117.  
  118. // Function to create and display the UI
  119. function createFilterUI() {
  120. const uiContainer = document.createElement('div');
  121. uiContainer.style.position = 'fixed';
  122. uiContainer.style.top = '10px';
  123. uiContainer.style.right = '10px';
  124. uiContainer.style.backgroundColor = 'grey';
  125. uiContainer.style.border = '1px solid #ccc';
  126. uiContainer.style.padding = '10px';
  127. uiContainer.style.zIndex = '9999';
  128.  
  129. uiContainer.innerHTML = `
  130. <label for="minPrice" style="color: red;">Min Price:</label>
  131. <input id="minPrice" type="text" placeholder="$0">
  132. <br>
  133. <label for="maxPrice" style="color: red;">Max Price:</label>
  134. <input id="maxPrice" type="text" placeholder="$1,000,000">
  135. <br>
  136. <input type="checkbox" id="hideUnaffordable" name="hideUnaffordable"> <label for="hideUnaffordable" style="color: red;">Hide Items You Can't Afford</label>
  137. <button id="applyFilter">Apply Filter</button>
  138. <p id="errorMessage" style="color: red; display: none;">Invalid price format. Use "$1,000" format.</p>
  139. <br>
  140. <label name="foodType" style="color: red;">Food Type:</label><br>
  141. <input type="radio" id="cookedFood" name="foodType" value="cooked"> <label for="cookedFood">Cooked Food</label><br>
  142. <input type="radio" id="uncookedFood" name="foodType" value="uncooked"> <label for="uncookedFood">Uncooked Food</label><br>
  143. <input type="radio" id="bothFood" name="foodType" value="both" checked> <label for="bothFood">Both</label><br>
  144. `;
  145.  
  146. document.body.appendChild(uiContainer);
  147.  
  148. const minPriceInput = document.getElementById('minPrice');
  149. const maxPriceInput = document.getElementById('maxPrice');
  150. const applyFilterButton = document.getElementById('applyFilter');
  151. const errorMessage = document.getElementById('errorMessage');
  152. const cookedFoodRadio = document.getElementById('cookedFood');
  153. const uncookedFoodRadio = document.getElementById('uncookedFood');
  154. const bothFoodRadio = document.getElementById('bothFood');
  155. const hideUnaffordableCheckbox = document.getElementById('hideUnaffordable');
  156.  
  157. // Automatically filter food type when radio buttons are clicked
  158. cookedFoodRadio.addEventListener('change', () => {
  159. if (cookedFoodRadio.checked) filterByFoodType('cooked');
  160. });
  161.  
  162. uncookedFoodRadio.addEventListener('change', () => {
  163. if (uncookedFoodRadio.checked) filterByFoodType('uncooked');
  164. });
  165.  
  166. bothFoodRadio.addEventListener('change', () => {
  167. if (bothFoodRadio.checked) resetAllFoodItems();
  168. });
  169.  
  170.  
  171. applyFilterButton.addEventListener('click', () => {
  172. const minPriceText = minPriceInput.value.trim();
  173. const maxPriceText = maxPriceInput.value.trim();
  174.  
  175. if ((minPriceText && validatePriceInput(minPriceText)) || (maxPriceText && validatePriceInput(maxPriceText)) || hideUnaffordableCheckbox.checked) {
  176. errorMessage.style.display = 'none';
  177.  
  178. const minPrice = minPriceText && validatePriceInput(minPriceText) ? parsePrice(minPriceText) : 0;
  179. const maxPrice = maxPriceText && validatePriceInput(maxPriceText) ? parsePrice(maxPriceText) : Infinity;
  180.  
  181. filterByPriceRange(minPrice, maxPrice);
  182.  
  183. } else {
  184. errorMessage.style.display = 'block';
  185. }
  186. });
  187.  
  188. hideUnaffordableCheckbox.addEventListener('change', () => {
  189. if (hideUnaffordableCheckbox.checked) {
  190. filterByAffordability();
  191. } else {
  192. filterByPriceRange(0, Infinity); // Reset to show all items within the current range
  193. }
  194. });
  195.  
  196. // Toggle food options visibility based on category
  197. toggleFoodOptionsVisibility();
  198.  
  199. // Observe category changes
  200. const observer = new MutationObserver(toggleFoodOptionsVisibility);
  201. observer.observe(document.querySelector('#categoryChoice'), { attributes: true });
  202. }
  203.  
  204. // Initialize the script
  205. window.addEventListener('load', () => {
  206. createFilterUI();
  207. });
  208. })();