Widget:Calculator/HighLite/Nameplates

<style> /* General widget container styling */

  1. widget-main-container {
 max-width: 600px;
 margin: 20px auto;
 padding: 15px;
 background-color: var(--bg-main, #1e1f22);
 color: var(--text-main, #b6b4b2);
 border: 1px solid var(--border-color-base, #2d2d2d);
 border-radius: 5px;
 font-family: sans-serif;

}

  1. widget-main-container h2, #widget-main-container h3 {
 color: var(--text-heading, #d1ccc6);
 margin-top: 10px;
 margin-bottom: 10px;

}

  1. loading-indicator, #error-message {
 padding: 10px;
 text-align: center;

}

/* Styles for search input */

  1. item-search {
 width: calc(100% - 20px);
 padding: 8px 10px;
 margin-bottom: 15px;
 background-color: var(--bg-secondary, #28292d);
 color: var(--text-main, #b6b4b2);
 border: 1px solid var(--border-color-base, #3d3d3d);
 border-radius: 4px;

}

/* Styles for output textarea */

  1. output-list {
 width: 100%;
 background-color: var(--bg-secondary, #28292d);
 color: var(--text-main, #b6b4b2);
 border: 1px solid var(--border-color-base, #2d2d2d);
 border-radius: 4px;
 padding: 10px;
 font-family: monospace;
 resize: vertical;

}

/* Styles for copy button */

  1. copy-button {
 background-color: #007bff;
 color: white;
 border: none;
 border-radius: 4px;
 padding: 10px 15px;
 cursor: pointer;
 font-size: 16px;
 margin-top: 10px;

}

  1. copy-button:hover {
 background-color: #0056b3;

}

  1. copy-feedback {
 margin-left: 10px;
 color: green;

}


/* Styles for the main table headers and cells */

  1. item-display-table {
 border-collapse: collapse;
 margin-top: 20px;
 background-color: var(--bg-secondary, #28292d);
 border: 1px solid var(--border-color-base, #2d2d2d);
 border-radius: 5px;

}

  1. item-display-table th, #item-display-table td {
 border: 1px solid var(--border-color-light, #3a3b3e);
 padding: 8px;
 text-align: left;

}

  1. item-display-table th {
 background-color: var(--bg-dark, #1a1b1e);
 color: var(--text-heading, #d1ccc6);

}

/* Styles for the buttons within table cells */ .nameplate-buttons-cell {

 white-space: nowrap;

}

.item-status-buttons {

 display: flex;
 gap: 5px;

}

/* Base style for ALL buttons - ULTIMATE SPECIFICITY */ /* Using multiple IDs and classes to ensure these styles win */

  1. item-display-table td.nameplate-buttons-cell div.item-status-buttons button {
 flex-grow: 1 !important; /* Ensure consistent width distribution */
 border-radius: 4px !important;
 text-align: center !important;
 font-weight: bold !important;
 white-space: nowrap !important;
 cursor: pointer !important;
 transition: background-color 0.2s, color 0.2s, border-color 0.2s !important;
 /* Default INACTIVE styling (gray) */
 background-color: #2a2c2f !important;
 border: 1px solid #444 !important;
 color: #b6b4b2 !important;
 /* Consistent Sizing */
 padding: 4px 8px !important;
 font-size: 0.85em !important;
 min-width: 60px !important;
 height: auto !important; /* Let content dictate height, prevent fixed height */
 line-height: normal !important; /* Standard line height */

}

/* Hover state for inactive buttons */

  1. item-display-table td.nameplate-buttons-cell div.item-status-buttons button:not(.active):hover {
 background-color: #3a3a3a !important;
 border-color: #0fc065 !important;
 color: #0fc065 !important;

}

/* ACTIVE button style (green) */

  1. item-display-table td.nameplate-buttons-cell div.item-status-buttons button.active {
 background-color: #0fc065 !important;
 border-color: #0fc065 !important;
 color: #000 !important; /* Black text for contrast */
 /* Ensure consistent sizing for active state too */
 padding: 4px 8px !important;
 font-size: 0.85em !important;
 min-width: 60px !important;
 height: auto !important;
 line-height: normal !important;

} </style>

<script> (function() {

'use strict';
// Global variables for elements
let itemSearchInput;
let itemDisplayTable; // This refers to the table on the main page where Cargo outputs
let outputListTextarea;
let copyButton;
let copyFeedback;
let allItems = []; // To store all fetched items and their current states
// Store a reference to the tbody element where event listeners will be attached
let tableTbodyElement = null;
const DEFAULT_ITEM_LIST = "Acorn:0,Alchemy Scroll:0,Amethyst Gem:0,Amethyst Necklace:-1,Archer's Boots:1,Archer's Cape:1,Archer's Gloves:1,Armoury Key:0,Arrow Shafts:0,Aruba Root:-1,Baked Potato:-1,Bandit Mask:1,Barbarian Helm:0,Basic Rod:-1,Bass:-1,Beer:-1,Black Bear Paw:-1,Black Cape:-1,Black Leather Boots:0,Black Leather Gloves:-1,Blood Gloves:1,Blood Hat:1,Blood Hood:1,Blood Robe Bottoms:1,Blood Robe Top:1,Blood Scroll:0,Blue Cape:-1,Blue Headband:0,Blue Santa Hat:1,Blue Wizard's Boots:1,Blue Wizard's Bottoms:0,Blue Wizard's Gloves:1,Blue Wizard's Hat:0,Blue Wizard's Top:0,Bluegill:-1,Bone Meal:-1,Bones:-1,Bottle Of Rum:-1,Bronze Arrowheads:0,Bronze Arrows:0,Bronze Bar:0,Bronze Battleaxe:-1,Bronze Chainmail Body:-1,Bronze Chestplate:-1,Bronze Full Helm:-1,Bronze Gloves:-1,Bronze Great Sword:-1,Bronze Hatchet:-1,Bronze Helm:-1,Bronze Longsword:-1,Bronze Pickaxe:-1,Bronze Platelegs:-1,Bronze Scimitar:-1,Bronze Shield:-1,Brown Bear Paw:-1,Burnt Food:-1,Calcium Brew:-1,Carbonado Gem:1,Carbonado Necklace:0,Carp:-1,Carrot:-1,Cave Bear Paw:-1,Celadium Bar:1,Celadium Ore:1,Celadon Arrowheads:0,Celadon Arrows:0,Celadon Battleaxe:1,Celadon Chainmail Body:1,Celadon Chainmail Body (Gold Plating):1,Celadon Chainmail Body (Silver Plating):1,Celadon Chestplate:1,Celadon Chestplate (Gold Plating):1,Celadon Chestplate (Silver Plating):1,Celadon Full Helm:1,Celadon Full Helm (Gold Plating And Gold Plume):1,Celadon Full Helm (Gold Plating):1,Celadon Full Helm (Gold Plume):1,Celadon Full Helm (Purple Plume):1,Celadon Full Helm (Silver Plating And Gold Plume):1,Celadon Full Helm (Silver Plating):1,Celadon Gloves:1,Celadon Gloves (Gold Plating):1,Celadon Gloves (Silver Plating):1,Celadon Great Sword:1,Celadon Hatchet:1,Celadon Helm:1,Celadon Helm (Gold Plating):1,Celadon Helm (Silver Plating):1,Celadon Longsword:1,Celadon Orb (Dim Glow):1,Celadon Orb (Extremely Bright):1,Celadon Orb (Barely Glowing):1,Celadon Orb (Fairly Bright):1,Celadon Orb (Dull):1,Celadon Orb (Faint Glow):1,Celadon Pickaxe:1,Celadon Platelegs:1,Celadon Platelegs (Gold Plating):1,Celadon Platelegs (Silver Plating):1,Celadon Scimitar:1,Celadon Shield:1,Celadon Shield (Gold Plating And Gold Trim):1,Celadon Shield (Gold Plating):1,Celadon Shield (Gold Trim):1,Celadon Shield (Silver Plating And Gold Trim):1,Celadon Shield (Silver Plating):1,Champion's Cape:1,Charred Bone Meal:-1,Charred Bones:-1,Chef's Hat:-1,Cherry Blossom:0,Cherry Bow:0,Cherry Logs:0,Chicken (Cooked):-1,Chisel:-1,Christmas Present (Green):1,Christmas Present (Red):1,Christmas Present (Blue):1,Christmas Present (White):1,Citrine Gem:0,Citrine Necklace:-1,Clownfish:-1,Coal:0,Coconut:0,Coins:0,Conch:-1,Copper Ore:0,Corn:-1,Coronium Arrowheads:0,Coronium Arrows:0,Coronium Bar:0,Coronium Battleaxe:0,Coronium Chainmail Body:0,Coronium Chainmail Body (Gold Plating):1,Coronium Chainmail Body (Silver Plating):1,Coronium Chestplate:0,Coronium Chestplate (Gold Plating):1,Coronium Chestplate (Silver Plating):1,Coronium Full Helm:0,Coronium Full Helm (Gold Plating And Gold Plume):1,Coronium Full Helm (Gold Plating):1,Coronium Full Helm (Gold Plume):1,Coronium Full Helm (Purple Plume):1,Coronium Full Helm (Silver Plating And Gold Plume):1,Coronium Full Helm (Silver Plating):1,Coronium Gloves:0,Coronium Gloves (Gold Plating):1,Coronium Gloves (Silver Plating):1,Coronium Great Sword:0,Coronium Hatchet:0,Coronium Helm:0,Coronium Helm (Gold Plating):1,Coronium Helm (Silver Plating):1,Coronium Longsword:0,Coronium Ore:0,Coronium Pickaxe:0,Coronium Platelegs:0,Coronium Platelegs (Gold Plating):1,Coronium Platelegs (Silver Plating):1,Coronium Scimitar:0,Coronium Shield:0,Coronium Shield (Gold Plating And Gold Trim):1,Coronium Shield (Gold Plating):1,Coronium Shield (Gold Trim):1,Coronium Shield (Silver Plating And Gold Trim):1,Coronium Shield (Silver Plating):1,Crab:0,Cyclops Eye:0,Damogui's Staff:1,Dark Hood:-1,Deadwood Bow:0,Deadwood Logs:0,Deadwood Scroll:0,Dew Beer:-1,Diamond Gem:1,Diamond Necklace:0,Driftwood:-1,Druid's Hood:-1,Elf Ears:0,Ember Staff:1,Emerald Gem:0,Emerald Necklace:-1,Empty Bottle:-1,Empty Glass:-1,Empty Turtle Shell:-1,Energy Scroll:0,Feathers:0,Fiji Root:-1,Fire Dragonleather:0,Fire Dragonleather Bracers:0,Fire Dragonleather Chaps:0,Fire Scroll:0,Flax:-1,Flour:-1,Forest Staff:1,Frog:-1,Fury Scroll:0,Game Meat:-1,Giant Bones:-1,Giant Gnome's Hat:0,Giant Gnome's Top:0,Giant's Milk:-1,Glass Of Water:-1,Gnome Jail Key:0,Gnome's Hat:-1,Goblin Banker's Key:0,Goblin Whistle:1,Gold Amethyst Necklace:1,Gold Bar:0,Gold Carbonado Necklace:1,Gold Citrine Necklace:0,Gold Diamond Necklace:1,Gold Emerald Necklace:1,Gold Nugget:0,Gold Ruby Necklace:1,Gold Sapphire Necklace:0,Gold Topaz Necklace:1,Gold Warrior Helm:1,Golden Acorn:1,Golden Blossom:1,Golden Coconut:1,Golden Leaf:1,Golden Pinecone:1,Grapes:0,Great Rod:-1,Green Cape:-1,Green Headband:0,Green Santa Hat:1,Grenada Root:-1,Grilled Corn:-1,Half Glass Of Beer:-1,Half Glass Of Calcium Brew:-1,Half Glass Of Dew Beer:-1,Half Glass Of Giant's Milk:-1,Halo:1,Hammer:-1,Headless Arrows:0,Helmet Of Magic:1,Helmet Of Melee:1,Helmet Of Ranging:1,Hydro Staff:1,Iron Arrowheads:0,Iron Arrows:0,Iron Bar:0,Iron Battleaxe:-1,Iron Chainmail Body:-1,Iron Chestplate:-1,Iron Full Helm:-1,Iron Gloves:-1,Iron Great Sword:-1,Iron Hatchet:-1,Iron Helm:-1,Iron Longsword:-1,Iron Ore:0,Iron Pickaxe:-1,Iron Platelegs:-1,Iron Scimitar:-1,Iron Shield:-1,Kitchen Key:0,Knife:-1,Knight's Cape:1,Koi:-1,Leaf:0,Leather:-1,Leather Body Armour:-1,Leather Boots:-1,Leather Bracers:-1,Leather Chaps:-1,Leather Gloves:-1,Legendary Battleaxe:1,Legendary Gloves:1,Legendary Longsword:1,Legendary Scimitar:1,Legendary Shield:1,Leprechaun Flute:1,Leprechaun Hat:1,Leprechaun Sketch:1,Logs:0,Lucky Logs:0,Lucky Scroll:0,Magic Scroll:0,Magician's Cape:1,Mansion Key:0,Mariana Root:0,Marlin:0,Master Rod:1,Maui Root:-1,Message In A Bottle:1,Money Bag:0,Monk's Necklace:-1,Monk's Necklace Mould:-1,Mt. Tan Dew:-1,Nature Scroll:0,Nauru Root:-1,Necklace Mould:-1,Oak Bow:-1,Oak Logs:0,Oak Scroll:0,Octopus:0,Old Hood:-1,Onion:-1,Orange Cape:-1,Palladium Arrowheads:0,Palladium Arrows:0,Palladium Bar:0,Palladium Battleaxe:0,Palladium Chainmail Body:0,Palladium Chestplate:0,Palladium Full Helm:0,Palladium Gloves:0,Palladium Great Sword:0,Palladium Hatchet:0,Palladium Helm:0,Palladium Longsword:0,Palladium Ore:0,Palladium Pickaxe:0,Palladium Platelegs:-1,Palladium Scimitar:0,Palladium Shield:0,Palm Bow:0,Palm Logs:0,Palm Scroll:0,Pestle And Mortar:-1,Pig Iron Bar:-1,Pine Bow:-1,Pine Logs:0,Pine Scroll:0,Pinecone:0,Piranha:-1,Pirate's Bandana:-1,Pirate's Key:1,Plains Dragonleather:0,Plains Dragonleather Bracers:0,Plains Dragonleather Chaps:0,Potato:-1,Potion Of Accuracy (1):-1,Potion Of Accuracy (2):0,Potion Of Defense (1):-1,Potion Of Defense (2):0,Potion Of Fishing (1):-1,Potion Of Fishing (2):0,Potion Of Forestry (1):0,Potion Of Forestry (2):0,Potion Of Magic (1):-1,Potion Of Magic (2):0,Potion Of Mining (1):-1,Potion Of Mining (2):0,Potion Of Mischief (1):-1,Potion Of Mischief (2):0,Potion Of Restoration (1):-1,Potion Of Restoration (2):0,Potion Of Smithing (1):-1,Potion Of Smithing (2):0,Potion Of Strength (1):-1,Potion Of Strength (2):0,Pumpkin:-1,Purple Cape:-1,Rage Scroll:0,Rat Tail:-1,Raw Bass:-1,Raw Beef:-1,Raw Bluegill:-1,Raw Carp:-1,Raw Chicken:-1,Raw Clownfish:0,Raw Crab:0,Raw Frog:-1,Raw Game Meat:-1,Raw Koi:-1,Raw Marlin:0,Raw Octopus:0,Raw Piranha:-1,Raw Rodent Meat:-1,Raw Salmon:-1,Raw Stingray:-1,Raw Tuna:0,Raw Turtle:-1,Raw Walleye:-1,Raw Whaleshark:0,Red Cape:-1,Red Headband:0,Red Mushroom:-1,Red Santa Hat:1,Robe Bottoms:-1,Robe Top:-1,Rodent Meat:-1,Rose:0,Rough Amethyst:0,Rough Carbonado:1,Rough Citrine:0,Rough Diamond:1,Rough Emerald:0,Rough Ruby:0,Rough Sapphire:0,Rough Topaz:0,Royal Cape:1,Ruby Gem:0,Ruby Necklace:0,Sage's Bottoms:-1,Sage's Top:-1,Sakura Scroll:0,Salmon:-1,Samoan Root:-1,Sand Dollar:-1,Sapphire Gem:0,Sapphire Necklace:-1,Sardinian Root:-1,Scallop Shell:-1,Scroll:0,Seashell Shores Bank Key:0,Seaweed:-1,Sewer Key:0,Shovel:-1,Silver Bar:0,Silver Nugget:0,Silver Warrior Helm:1,Squirrel Pelt:-1,Staff:-1,Starfish:-1,Steak:-1,Steel Arrowheads:0,Steel Arrows:0,Steel Bar:0,Steel Battleaxe:0,Steel Chainmail Body:0,Steel Chestplate:-1,Steel Full Helm:-1,Steel Gloves:-1,Steel Great Sword:0,Steel Hatchet:-1,Steel Helm:-1,Steel Longsword:-1,Steel Pickaxe:-1,Steel Platelegs:0,Steel Scimitar:-1,Steel Shield:0,Stingray:0,Strawberry:-1,String:0,Tattered Skirt:-1,Tin Ore:0,Tomato:-1,Tonga Root:-1,Topaz Gem:0,Topaz Necklace:-1,Treasure Map:1,Trumpet:1,Tuna:0,Turtle:0,Ultra Rod:0,Undercroft Key:0,Unheated Dew Mash:-1,Unheated Mash:-1,Unstrung Bow:-1,Unstrung Cherry Bow:0,Unstrung Deadwood Bow:0,Unstrung Oak Bow:-1,Unstrung Palm Bow:0,Unstrung Pine Bow:-1,Unstrung Wizard's Bow:0,Uranium Ore:1,Vanua Root:0,Vial:-1,Vial Of Water:-1,Walleye:-1,Warp Scroll:0,Water Dragonleather:0,Water Dragonleather Bracers:0,Water Dragonleather Chaps:0,Water Scroll:0,Watermelon:-1,Whaleshark:0,Wheat:-1,Witch's Bottoms:-1,Witch's Hat:-1,Witch's Top:-1,Wizard Logs:0,Wizard Scroll:0,Wizard's Boots:0,Wizard's Bottoms:0,Wizard's Bow:0,Wizard's Gloves:0,Wizard's Hat:0,Wizard's Top:0,Wooden Bow:-1,Yellow Cape:-1";
/**
 * Strips disambiguation from item names like "(Tier X)" or "(Room Name)".
 * @param {string} name The original item name.
 * @returns {string} The consolidated item name.
 */
function getConsolidatedItemName(name) {
  if (name.startsWith("Treasure Map (Tier")) {
    return "Treasure Map";
  }
  if (name.startsWith("Undercroft Key (")) {
    return "Undercroft Key";
  }
  return name;
}
/**
 * Injects the calculator's control HTML into the designated wrapper.
 */
function injectCalculatorControls() {
 const wrapper = document.getElementById('nameplate-calculator-wrapper');
 if (!wrapper) {
  console.error('Error: #nameplate-calculator-wrapper not found on the page. Widget cannot initialize.');
  return;
 }
 // Inject the control HTML including search, output, and copy button
 wrapper.innerHTML = `
Initializing calculator...
 `;
 // Assign elements to global variables AFTER they are injected
 itemSearchInput = document.getElementById('item-search');
 outputListTextarea = document.getElementById('output-list');
 copyButton = document.getElementById('copy-button');
 copyFeedback = document.getElementById('copy-feedback');
 itemDisplayTable = document.getElementById('item-display-table'); // Get reference to the table on the main page
}
/**
 * Initializes the interactive buttons and state for each item in the table.
 */
function initializeItemRows() {
 const loadingIndicator = document.getElementById('loading-indicator');
 const errorMessage = document.getElementById('error-message');
 const calculatorControls = document.getElementById('calculator-controls');
 if (!itemDisplayTable || !itemDisplayTable.tBodies[0] || itemDisplayTable.tBodies[0].rows.length === 0) {
  errorMessage.textContent = 'Error: Item data table not found or empty. Please ensure your Cargo query is correct and populating the table correctly.';
  errorMessage.style.display = 'block';
  if (loadingIndicator) loadingIndicator.style.display = 'none';
  console.error('Item display table (ID: item-display-table) not found or has no tbody/rows after waiting.');
  return;
 }
 // Store the tbody element once it's confirmed to exist
 tableTbodyElement = itemDisplayTable.tBodies[0];
 const rows = Array.from(tableTbodyElement.rows); // Convert to array for easier manipulation
 // Temporary map to hold consolidated items and their determined state
 // Key: consolidated item name, Value: { name, state, rowElement (primary one), buttonsCell (primary one) }
 const consolidatedItemsMap = new Map();
 rows.forEach(row => {
  const itemNameLinkCell = row.cells[1];
  const itemNameLink = itemNameLinkCell ? itemNameLinkCell.querySelector('a') : null;
  const originalItemName = itemNameLink ? itemNameLink.textContent.trim() : ;
  if (!originalItemName) {
    console.warn('Skipping row due to missing original item name:', row);
    row.style.display = 'none'; // Hide rows without a name
    return;
  }
  const consolidatedName = getConsolidatedItemName(originalItemName);
  const buttonsCell = row.querySelector('.nameplate-buttons-cell');
  if (!buttonsCell) {
    console.warn('Skipping row due to missing buttons cell:', row);
    row.style.display = 'none'; // Hide rows without a buttons cell
    return;
  }
  // Check if we've already processed this consolidated item
  if (!consolidatedItemsMap.has(consolidatedName)) {
    // This is the first time we see this consolidated item name
    consolidatedItemsMap.set(consolidatedName, {
      name: consolidatedName,
      state: -1, // Default to hide initially, will be overridden by DEFAULT_ITEM_LIST
      rowElement: row, // This row will be the primary one for this consolidated item
      buttonsCell: buttonsCell // This cell will host the buttons
    });
    // Update the displayed item name in the table
    if (itemNameLink) {
      itemNameLink.textContent = consolidatedName;
    } else {
      // Fallback if no link, though usually there should be one
      itemNameLinkCell.textContent = consolidatedName;
    }
    // Create and append buttons to this consolidated item's primary buttonsCell
    const buttonsContainer = document.createElement('div');
    buttonsContainer.className = 'item-status-buttons';
    buttonsContainer.dataset.itemName = consolidatedName; // For event delegation
    const states = [
      { value: -1, text: 'Hide' },
      { value: 0, text: 'Default' },
      { value: 1, text: 'Priority' }
    ];
    states.forEach(state => {
      const button = document.createElement('button');
      button.textContent = state.text;
      button.dataset.value = state.value;
      buttonsContainer.appendChild(button);
    });
    buttonsCell.appendChild(buttonsContainer);
  } else {
    // This is a duplicate of a consolidated item, so hide its row
    row.style.display = 'none';
    // And remove any buttons that might have been automatically rendered by Cargo for it
    if (buttonsCell) {
      buttonsCell.innerHTML = ; // Clear contents of the button cell
    }
  }
 });
 // Convert the map values to an array for allItems
 allItems = Array.from(consolidatedItemsMap.values());
 // Apply the default list or any saved state to the consolidated items
 parseAndApplyList(DEFAULT_ITEM_LIST); // This will update the 'state' in allItems
 generateOutputList(); // Initial generation of the output list
 if (loadingIndicator) loadingIndicator.style.display = 'none';
 if (calculatorControls) calculatorControls.style.display = 'block';
 // --- Attach ONE event listener to the tbody for ALL button clicks ---
 tableTbodyElement.addEventListener('click', (event) => {
  const clickedButton = event.target.closest('button');
  const buttonsContainer = clickedButton ? clickedButton.closest('.item-status-buttons') : null;
  if (clickedButton && buttonsContainer) {
   const itemName = buttonsContainer.dataset.itemName;
   const newState = parseInt(clickedButton.dataset.value, 10);
   const itemObj = allItems.find(i => i.name === itemName);
   if (itemObj) {
    itemObj.state = newState;
   }
   // Update active classes for buttons within this specific item's container
   Array.from(buttonsContainer.children).forEach(btn => {
    if (parseInt(btn.dataset.value, 10) === newState) {
     btn.classList.add('active');
    } else {
     btn.classList.remove('active');
    }
   });
   generateOutputList(); // Auto-update the list
  }
 });
}
/**
 * Generates the comma-separated output list.
 */
function generateOutputList() {
 const output = allItems
  .map(item => `${item.name}:${item.state}`)
  .join(',');
 outputListTextarea.value = output;
}
/**
 * Filters the item list based on search input by hiding/showing table rows.
 */
function filterItemList() {
 const searchTerm = itemSearchInput.value.toLowerCase();
 allItems.forEach(item => {
  // We only care about the single primary row for each consolidated item for display
  const row = item.rowElement;
  if (row) {
    if (item.name.toLowerCase().includes(searchTerm)) {
      row.style.display = ; // Show the primary row
    } else {
      row.style.display = 'none'; // Hide the primary row
    }
  }
 });
}


/**
 * Copies the generated list to the clipboard.
 */
function copyToClipboard() {
 outputListTextarea.select();
 outputListTextarea.setSelectionRange(0, 99999);
 try {
  document.execCommand('copy');
  copyFeedback.textContent = 'Copied!';
  setTimeout(() => { copyFeedback.textContent = , 2000; });
 } catch (err) {
  console.error('Failed to copy text: ', err);
  copyFeedback.textContent = 'Failed to copy.';
  setTimeout(() => { copyFeedback.textContent = , 2000; });
 }
}
/**
 * Parses a list string and applies the settings to the item buttons.
 * @param {string} listString The comma-separated list of "ItemName:Value"
 */
function parseAndApplyList(listString) {
 const newSettings = new Map(); // Use a Map to store parsed settings and consolidate
 listString.split(',').forEach(entry => {
  const parts = entry.trim().split(':');
  if (parts.length === 2) {
   const originalItemName = parts[0].trim();
   const value = parseInt(parts[1].trim(), 10);
   if (!isNaN(value) && [ -1, 0, 1 ].includes(value)) {
    const consolidatedName = getConsolidatedItemName(originalItemName);
    const existingValue = newSettings.has(consolidatedName) ? newSettings.get(consolidatedName) : -2; // Use -2 as a placeholder for "not set"
    // Apply consolidation priority: Priority (1) > Default (0) > Hide (-1)
    if (value > existingValue) { // Higher value (more priority) wins
      newSettings.set(consolidatedName, value);
    }
   }
  }
 });
 allItems.forEach(item => {
  const currentItemName = item.name; // This is already the consolidated name
  let newState = -1; // Default to Hide if not in the pasted list
  if (newSettings.has(currentItemName)) {
   newState = newSettings.get(currentItemName);
  }
  // Update the internal state
  item.state = newState;
  // Update the active class on the buttons for this item (only the primary one)
  if (item.buttonsCell) { // Ensure buttonsCell reference exists (this will be the primary one)
   const buttonsContainer = item.buttonsCell.querySelector('.item-status-buttons');
   if (buttonsContainer) {
    Array.from(buttonsContainer.children).forEach(btn => {
     if (parseInt(btn.dataset.value, 10) === newState) {
      btn.classList.add('active');
     } else {
      btn.classList.remove('active');
     }
    });
   }
  }
 });
 // Re-generate the output list based on the new states
 generateOutputList();
}
/**
 * Main entry point for the widget.
 */
function initWidget() {
 injectCalculatorControls(); // Inject the HTML for controls first
 // Now that controls are injected, attach event listeners to them
 if (itemSearchInput) {
  itemSearchInput.addEventListener('input', filterItemList);
 }
 if (copyButton) {
  copyButton.addEventListener('click', copyToClipboard);
 }
 // Add input listener to the output list textarea for reverse engineering
 if (outputListTextarea) {
  outputListTextarea.addEventListener('input', (event) => {
   parseAndApplyList(event.target.value);
  });
 }
 // Use a MutationObserver to wait for the Cargo table's tbody to be generated
 const observer = new MutationObserver((mutations, obs) => {
  const table = document.getElementById('item-display-table'); // This is the ID of the table on the main page
  if (table && table.tBodies[0] && table.tBodies[0].rows.length > 0) {
   obs.disconnect(); // Stop observing once Cargo has populated the table
   initializeItemRows(); // Proceed with setting up buttons and interactivity
  }
 });
 // Start observing the body for the main Cargo table to appear and be populated
 observer.observe(document.body, { childList: true, subtree: true });
 // Fallback for immediate execution if DOM is already loaded and table is present
 if (document.readyState === 'complete') {
  const table = document.getElementById('item-display-table');
  if (table && table.tBodies[0] && table.tBodies[0].rows.length > 0) {
   observer.disconnect();
   initializeItemRows();
  }
 }
}
// Run initialization when the DOM is ready
if (document.readyState === 'loading') {
 document.addEventListener('DOMContentLoaded', initWidget);
} else {
 initWidget();
}

})(); </script>