// ==UserScript==
// @name Bazaar Item Search powered by IronNerd
// @namespace [email protected]
// @version 0.4.5
// @description View items you are searching for in bazaars!
// @author Nurv [669537]
// @match https://www.torn.com/page.php?sid=ItemMarket*
// @grant GM_xmlhttpRequest
// @grant GM_setValue
// @grant GM_getValue
// @run-at document-end
// @license Copyright IronNerd.me
// @connect ironnerd.me
// ==/UserScript==
(function () {
'use strict';
console.log('IronNerd Bazaar Enhancements script started.');
// ------------------ Configuration ------------------
const BACKEND_URL = 'https://www.ironnerd.me';
const ongoingRequests = new Set();
let currentPage = 1;
const itemsPerPage = 15;
let allBazaarItems = [];
// ------------------ Initialization ------------------
init();
function init() {
injectAdditionalStyles();
ensureBazaarEnhancerContainer();
addBazaarButtons();
observeDOMChanges();
detectSearch();
observeDarkMode();
initializeTopCheapestItems();
adjustBazaarEnhancerContainerTheme();
}
// ------------------ Utility Functions ------------------
function debounce(func, wait) {
let timeout;
return function (...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
function getItemInfoFromURL() {
const url = new URL(window.location.href);
let itemID = null;
let itemName = '';
let hash = url.hash.startsWith('#/') ? url.hash.substring(2) : url.hash.substring(1);
const hashParts = hash.split('/');
const paramsString = hashParts[hashParts.length - 1];
const hashParams = new URLSearchParams(paramsString);
itemID = hashParams.get('itemID');
itemName = hashParams.get('itemName') ? decodeURIComponent(hashParams.get('itemName')) : '';
if (!itemID) {
const searchParams = url.searchParams;
itemID = searchParams.get('itemID');
itemName = searchParams.get('itemName') ? decodeURIComponent(searchParams.get('itemName')) : '';
}
if (itemID) {
return { itemID: parseInt(itemID), itemName };
}
return { itemID: null, itemName: '' };
}
function ensureBazaarEnhancerContainer() {
let container = document.getElementById('bazaar-enhancer-container');
if (!container) {
container = document.createElement('div');
container.id = 'bazaar-enhancer-container';
const delimiter = document.querySelector('.delimiter___zFh2E');
if (delimiter && delimiter.parentNode) {
delimiter.parentNode.insertBefore(container, delimiter.nextSibling);
} else {
document.body.appendChild(container);
}
console.log('IronNerd Bazaar Enhancements: `bazaar-enhancer-container` created and appended to the DOM.');
} else {
console.log('IronNerd Bazaar Enhancements: `bazaar-enhancer-container` already exists.');
}
}
function addBazaarButtons() {
const addListingsLink = document.querySelector('a[href="#/addListing"]');
if (addListingsLink) {
const linksContainer = addListingsLink.parentElement;
if (linksContainer && !document.getElementById('bazaarButton')) {
const bazaarLink = addListingsLink.cloneNode(true);
bazaarLink.id = 'bazaarButton';
bazaarLink.setAttribute('aria-labelledby', 'Bazaar');
bazaarLink.href = '#';
const linkTitle = bazaarLink.querySelector('.linkTitle____NPyM');
if (linkTitle) {
linkTitle.innerText = 'Bazaar';
}
const svgIcon = bazaarLink.querySelector('svg');
if (svgIcon) {
svgIcon.innerHTML = '<svg fill="#000000" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 902.86 902.86" xml:space="preserve"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <g> <g> <path d="M671.504,577.829l110.485-432.609H902.86v-68H729.174L703.128,179.2L0,178.697l74.753,399.129h596.751V577.829z M685.766,247.188l-67.077,262.64H131.199L81.928,246.756L685.766,247.188z"></path> <path d="M578.418,825.641c59.961,0,108.743-48.783,108.743-108.744s-48.782-108.742-108.743-108.742H168.717 c-59.961,0-108.744,48.781-108.744,108.742s48.782,108.744,108.744,108.744c59.962,0,108.743-48.783,108.743-108.744 c0-14.4-2.821-28.152-7.927-40.742h208.069c-5.107,12.59-7.928,26.342-7.928,40.742 C469.675,776.858,518.457,825.641,578.418,825.641z M209.46,716.897c0,22.467-18.277,40.744-40.743,40.744 c-22.466,0-40.744-18.277-40.744-40.744c0-22.465,18.277-40.742,40.744-40.742C191.183,676.155,209.46,694.432,209.46,716.897z M619.162,716.897c0,22.467-18.277,40.744-40.743,40.744s-40.743-18.277-40.743-40.744c0-22.465,18.277-40.742,40.743-40.742 S619.162,694.432,619.162,716.897z"></path> </g> </g> </g></svg>';
}
bazaarLink.addEventListener('click', (e) => {
e.preventDefault();
openShowBazaarModal();
});
linksContainer.appendChild(bazaarLink);
console.log('Bazaar button added to layout.');
}
}
}
function createBazaarButton(id, text) {
const button = document.createElement('button');
button.id = id;
button.innerText = text;
button.style.cursor = 'pointer';
button.style.padding = '6px 10px';
button.style.margin = '5px';
button.style.backgroundColor = '#4caf50';
button.style.color = '#fff';
button.style.border = 'none';
button.style.borderRadius = '4px';
button.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.2)';
button.style.fontSize = '12px';
button.type = 'button';
button.addEventListener('click', () => {
console.log(`${text} button clicked!`);
openShowBazaarModal();
});
return button;
}
function observeDOMChanges() {
const targetNode = document.body;
const config = { childList: true, subtree: true };
const debouncedAddButtons = debounce(() => {
addBazaarButtons();
}, 500);
const callback = function (mutationsList, observer) {
for (let mutation of mutationsList) {
if (mutation.type === 'childList') {
debouncedAddButtons();
}
}
};
const observer = new MutationObserver(callback);
observer.observe(targetNode, config);
}
function openShowBazaarModal() {
createShowBazaarModal();
const modal = document.getElementById('showBazaarModal');
if (modal) {
modal.style.display = 'flex';
const { itemID, itemName } = getItemInfoFromURL();
const itemNameDisplay = modal.querySelector('#itemNameDisplay');
const resultsContainer = modal.querySelector('#showBazaarResults');
currentPage = 1;
allBazaarItems = [];
if (itemName && itemNameDisplay) {
itemNameDisplay.innerText = `Showing Bazaar Listings for: ${itemName}`;
} else {
itemNameDisplay.innerText = 'No item selected.';
}
if (itemID) {
fetchBazaarItems(itemID);
} else {
resultsContainer.innerHTML = '<p>No item selected for display.</p>';
}
trapFocus(modal);
} else {
console.error('IronNerd Bazaar Enhancements: showBazaarModal element not found.');
}
}
function createShowBazaarModal() {
if (document.getElementById('showBazaarModal')) {
return;
}
const overlay = document.createElement('div');
overlay.id = 'showBazaarModal';
overlay.setAttribute('role', 'dialog');
overlay.setAttribute('aria-labelledby', 'modal-title');
overlay.setAttribute('aria-modal', 'true');
overlay.style.position = 'fixed';
overlay.style.top = '0';
overlay.style.left = '0';
overlay.style.width = '100%';
overlay.style.height = '100%';
overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
overlay.style.display = 'none';
overlay.style.zIndex = '10000';
overlay.style.overflowY = 'auto';
overlay.style.alignItems = 'center';
overlay.style.justifyContent = 'center';
const modalContent = document.createElement('div');
modalContent.id = 'modal-content';
modalContent.style.backgroundColor = '#9e9b9b';
modalContent.style.padding = '20px';
modalContent.style.borderRadius = '8px';
modalContent.style.width = '90%';
modalContent.style.maxWidth = '800px';
modalContent.style.position = 'relative';
modalContent.style.boxShadow = '0 5px 15px rgba(0,0,0,0.3)';
modalContent.style.maxHeight = '90%';
modalContent.style.overflowY = 'auto';
const closeBtn = document.createElement('span');
closeBtn.innerHTML = '×';
closeBtn.style.position = 'absolute';
closeBtn.style.top = '10px';
closeBtn.style.right = '20px';
closeBtn.style.fontSize = '30px';
closeBtn.style.fontWeight = 'bold';
closeBtn.style.cursor = 'pointer';
closeBtn.style.color = '#aaa';
closeBtn.addEventListener('mouseover', () => {
closeBtn.style.color = '#000';
});
closeBtn.addEventListener('mouseout', () => {
closeBtn.style.color = '#aaa';
});
closeBtn.addEventListener('click', closeShowBazaarModal);
const title = document.createElement('h2');
title.id = 'modal-title';
title.style.textAlign = 'center';
title.style.marginBottom = '20px';
const itemNameDisplay = document.createElement('h3');
itemNameDisplay.id = 'itemNameDisplay';
itemNameDisplay.style.textAlign = 'center';
itemNameDisplay.style.marginBottom = '10px';
itemNameDisplay.style.color = '#333';
modalContent.appendChild(itemNameDisplay);
const resultsContainer = document.createElement('div');
resultsContainer.id = 'showBazaarResults';
resultsContainer.style.marginTop = '20px';
const statusDiv = document.createElement('div');
statusDiv.id = 'showBazaarStatusMessage';
statusDiv.style.marginTop = '10px';
statusDiv.style.fontWeight = 'bold';
modalContent.appendChild(closeBtn);
modalContent.appendChild(title);
modalContent.appendChild(resultsContainer);
modalContent.appendChild(statusDiv);
overlay.appendChild(modalContent);
document.body.appendChild(overlay);
overlay.addEventListener('click', function (event) {
if (event.target === overlay) {
closeShowBazaarModal();
}
});
document.addEventListener('keydown', function (event) {
if (event.key === 'Escape') {
closeShowBazaarModal();
}
});
}
function closeShowBazaarModal() {
const modal = document.getElementById('showBazaarModal');
if (modal) {
modal.style.display = 'none';
}
}
function fetchBazaarItems(itemID) {
const modal = document.getElementById('showBazaarModal');
const resultsContainer = modal.querySelector('#showBazaarResults');
const statusDiv = modal.querySelector('#showBazaarStatusMessage');
if (ongoingRequests.has(`bazaar_items_${itemID}`)) {
return;
}
ongoingRequests.add(`bazaar_items_${itemID}`);
resultsContainer.innerHTML = `
<p>Loading...</p>
<div class="loading-spinner"></div>
`;
statusDiv.innerHTML = '';
GM_xmlhttpRequest({
method: 'GET',
url: `${BACKEND_URL}/get_bazaar_items/${itemID}`,
headers: {
'Accept': 'application/json',
},
onload: function (response) {
ongoingRequests.delete(`bazaar_items_${itemID}`);
if (response.status === 200) {
try {
const data = JSON.parse(response.responseText);
if (data.bazaar_items) {
allBazaarItems = data.bazaar_items;
displayBazaarItems(allBazaarItems);
} else {
resultsContainer.innerHTML = '<p>No items found.</p>';
}
} catch (e) {
resultsContainer.innerHTML = '<p>Error parsing server response.</p>';
}
} else {
resultsContainer.innerHTML = `<p>Error: ${response.status} - ${response.statusText}</p>`;
}
},
onerror: function (error) {
ongoingRequests.delete(`bazaar_items_${itemID}`);
resultsContainer.innerHTML = '<p>Network error occurred. Please try again later.</p>';
}
});
}
function displayBazaarItems(items) {
const modal = document.getElementById('showBazaarModal');
const resultsContainer = modal.querySelector('#showBazaarResults');
resultsContainer.innerHTML = '';
if (items.length === 0) {
resultsContainer.innerHTML = '<p>No items found in registered bazaars.</p>';
return;
}
const totalPages = Math.ceil(items.length / itemsPerPage);
if (currentPage > totalPages) currentPage = totalPages;
const startIndex = (currentPage - 1) * itemsPerPage;
const endIndex = Math.min(startIndex + itemsPerPage, items.length);
const paginatedItems = items.slice(startIndex, endIndex);
const tableContainer = document.createElement('div');
tableContainer.style.overflowX = 'table-responsive';
tableContainer.style.width = '100%';
const table = document.createElement('table');
table.className = 'bazaar-table';
table.style.width = '100%';
table.style.borderCollapse = 'collapse';
const thead = document.createElement('thead');
const headerRow = document.createElement('tr');
const headers = ['Image', 'Owner', 'Price ($)', 'Quantity', 'Visit Bazaar'];
headers.forEach(header => {
const th = document.createElement('th');
th.innerText = header;
th.style.border = '1px solid #ccc';
th.style.padding = '8px';
th.style.backgroundColor = '#f2f2f2';
th.style.textAlign = 'center';
th.style.fontSize = '14px';
headerRow.appendChild(th);
});
thead.appendChild(headerRow);
table.appendChild(thead);
const tbody = document.createElement('tbody');
paginatedItems.forEach(item => {
const tr = document.createElement('tr');
const imgCell = document.createElement('td');
imgCell.style.border = '1px solid #ccc';
imgCell.style.padding = '4px';
imgCell.style.textAlign = 'center';
const img = document.createElement('img');
img.src = `/images/items/${item.item_id}/small.png`;
img.alt = item.name;
img.style.height = '30px';
imgCell.appendChild(img);
tr.appendChild(imgCell);
const ownerCell = document.createElement('td');
ownerCell.setAttribute('data-label', 'Owner');
ownerCell.style.border = '1px solid #ccc';
ownerCell.style.padding = '6px';
ownerCell.style.textAlign = 'center';
ownerCell.style.fontSize = '14px';
const ownerLink = document.createElement('a');
ownerLink.href = `https://www.torn.com/profiles.php?XID=${item.user_id}`;
ownerLink.textContent = item.user_id;
ownerLink.target = '_blank';
ownerLink.style.color = 'inherit';
ownerLink.style.textDecoration = 'none';
ownerLink.addEventListener('mouseover', () => {
ownerLink.style.textDecoration = 'underline';
});
ownerLink.addEventListener('mouseout', () => {
ownerLink.style.textDecoration = 'none';
});
ownerCell.appendChild(ownerLink);
tr.appendChild(ownerCell);
const priceTd = document.createElement('td');
priceTd.innerText = `$${item.price.toLocaleString()}`;
priceTd.setAttribute('data-label', 'Price ($)');
priceTd.style.border = '1px solid #ccc';
priceTd.style.padding = '6px';
priceTd.style.textAlign = 'center';
priceTd.style.fontSize = '14px';
tr.appendChild(priceTd);
const quantityTd = document.createElement('td');
quantityTd.innerText = item.quantity;
quantityTd.setAttribute('data-label', 'Quantity');
quantityTd.style.border = '1px solid #ccc';
quantityTd.style.padding = '6px';
quantityTd.style.textAlign = 'center';
quantityTd.style.fontSize = '14px';
tr.appendChild(quantityTd);
const bazaarTd = document.createElement('td');
bazaarTd.style.border = '1px solid #ccc';
bazaarTd.style.padding = '6px';
bazaarTd.style.textAlign = 'center';
bazaarTd.style.fontSize = '14px';
const bazaarLink = document.createElement('a');
bazaarLink.href = `https://www.torn.com/bazaar.php?userID=${item.user_id}`;
bazaarLink.textContent = 'Visit';
bazaarLink.target = '_blank';
bazaarLink.style.color = '#007bff';
bazaarLink.style.textDecoration = 'none';
bazaarLink.addEventListener('mouseover', () => {
bazaarLink.style.textDecoration = 'underline';
});
bazaarLink.addEventListener('mouseout', () => {
bazaarLink.style.textDecoration = 'none';
});
bazaarTd.appendChild(bazaarLink);
bazaarTd.setAttribute('data-label', 'Visit Bazaar');
tr.appendChild(bazaarTd);
tbody.appendChild(tr);
});
table.appendChild(tbody);
tableContainer.appendChild(table);
resultsContainer.appendChild(tableContainer);
addPaginationControls(resultsContainer, allBazaarItems.length, totalPages);
adjustBazaarTableTheme();
}
function addPaginationControls(container, totalItems, totalPages) {
const existingPagination = container.querySelector('.pagination-controls');
if (existingPagination) {
existingPagination.remove();
}
if (totalPages <= 1) return;
const paginationContainer = document.createElement('div');
paginationContainer.className = 'pagination-controls';
paginationContainer.style.display = 'flex';
paginationContainer.style.justifyContent = 'center';
paginationContainer.style.alignItems = 'center';
paginationContainer.style.marginTop = '15px';
paginationContainer.style.flexWrap = 'wrap';
const prevButton = document.createElement('button');
prevButton.innerText = 'Previous';
prevButton.disabled = currentPage === 1;
prevButton.className = 'pagination-button';
prevButton.addEventListener('click', () => {
if (currentPage > 1) {
currentPage--;
displayBazaarItems(allBazaarItems);
}
});
paginationContainer.appendChild(prevButton);
const pageIndicator = document.createElement('span');
pageIndicator.innerText = `Page ${currentPage} of ${totalPages}`;
pageIndicator.style.margin = '0 10px';
pageIndicator.style.fontSize = '14px';
paginationContainer.appendChild(pageIndicator);
const nextButton = document.createElement('button');
nextButton.innerText = 'Next';
nextButton.disabled = currentPage === totalPages;
nextButton.className = 'pagination-button';
nextButton.addEventListener('click', () => {
if (currentPage < totalPages) {
currentPage++;
displayBazaarItems(allBazaarItems);
}
});
paginationContainer.appendChild(nextButton);
container.appendChild(paginationContainer);
}
function fetchTopCheapestItems(itemID) {
const { itemName } = getItemInfoFromURL();
const container = document.getElementById('bazaar-enhancer-container');
if (!container) {
console.error('IronNerd Bazaar Enhancements: Container for top 3 items not found.');
return;
}
if (ongoingRequests.has(`top_cheapest_${itemID}`)) {
return;
}
ongoingRequests.add(`top_cheapest_${itemID}`);
container.innerHTML = `
<p>Loading top 3 cheapest items...</p>
<div class="loading-spinner"></div>
`;
GM_xmlhttpRequest({
method: 'GET',
url: `${BACKEND_URL}/get_top_cheapest_items/${itemID}`,
headers: {
'Accept': 'application/json',
},
onload: function (response) {
ongoingRequests.delete(`top_cheapest_${itemID}`);
if (response.status === 200) {
try {
const data = JSON.parse(response.responseText);
if (data.top_cheapest_items && Array.isArray(data.top_cheapest_items)) {
displayTopCheapestItems(data.top_cheapest_items, itemName);
} else {
displayShowBazaarStatusMessage('error', 'Invalid data format received.');
}
} catch (e) {
container.innerHTML = '<p>Error parsing server response.</p>';
console.error('IronNerd Bazaar Enhancements: Parsing Error:', e);
}
} else {
container.innerHTML = `<p>Error: ${response.status} - ${response.statusText}</p>`;
console.error('IronNerd Bazaar Enhancements: Fetch Top 3 Cheapest Items Error:', response.responseText);
}
},
onerror: function (error) {
ongoingRequests.delete(`top_cheapest_${itemID}`);
container.innerHTML = '<p>Network error occurred. Please try again later.</p>';
console.error('IronNerd Bazaar Enhancements: Network Error:', error);
}
});
}
function displayTopCheapestItems(items, itemName = 'Item') {
const container = document.getElementById('bazaar-enhancer-container');
container.innerHTML = '';
if (!items || items.length === 0) {
container.innerHTML = '<p>No items found.</p>';
return;
}
const title = document.createElement('h3');
title.innerText = `Top 3 Cheapest ${itemName} Bazaar Items`;
title.style.textAlign = 'center';
title.style.marginTop = '2px';
title.style.marginBottom = '10px';
container.appendChild(title);
const tableContainer = document.createElement('div');
tableContainer.style.overflowX = 'table-responsive';
tableContainer.style.width = '100%';
const table = document.createElement('table');
table.className = 'top-cheapest-table';
table.style.width = '100%';
table.style.borderCollapse = 'collapse';
const thead = document.createElement('thead');
const headerRow = document.createElement('tr');
const headers = ['Rank', 'Price ($)', 'Quantity', 'Seller', 'Visit Bazaar'];
headers.forEach(headerText => {
const th = document.createElement('th');
th.innerText = headerText;
th.style.border = '1px solid #ccc';
th.style.padding = '8px';
th.style.backgroundColor = '#e0e0e0';
th.style.textAlign = 'center';
th.style.fontSize = '14px';
headerRow.appendChild(th);
});
thead.appendChild(headerRow);
table.appendChild(thead);
const tbody = document.createElement('tbody');
items.forEach((item, index) => {
const tr = document.createElement('tr');
const rankTd = document.createElement('td');
rankTd.innerText = index + 1;
rankTd.style.border = '1px solid #ccc';
rankTd.style.padding = '6px';
rankTd.style.textAlign = 'center';
rankTd.style.fontSize = '14px';
tr.appendChild(rankTd);
const priceTd = document.createElement('td');
priceTd.innerText = `$${item.price.toLocaleString()}`;
priceTd.setAttribute('data-label', 'Price ($)');
priceTd.style.border = '1px solid #ccc';
priceTd.style.padding = '6px';
priceTd.style.textAlign = 'center';
priceTd.style.fontSize = '14px';
tr.appendChild(priceTd);
const quantityTd = document.createElement('td');
quantityTd.innerText = item.quantity;
quantityTd.setAttribute('data-label', 'Quantity');
quantityTd.style.border = '1px solid #ccc';
quantityTd.style.padding = '6px';
quantityTd.style.textAlign = 'center';
quantityTd.style.fontSize = '14px';
tr.appendChild(quantityTd);
const sellerTd = document.createElement('td');
sellerTd.setAttribute('data-label', 'Seller');
sellerTd.style.border = '1px solid #ccc';
sellerTd.style.padding = '6px';
sellerTd.style.textAlign = 'center';
sellerTd.style.fontSize = '14px';
const sellerLink = document.createElement('a');
sellerLink.href = `https://www.torn.com/profiles.php?XID=${item.user_id}`;
sellerLink.textContent = item.user_id;
sellerLink.target = '_blank';
sellerLink.style.color = 'inherit';
sellerLink.style.textDecoration = 'none';
sellerLink.addEventListener('mouseover', () => {
sellerLink.style.textDecoration = 'underline';
});
sellerLink.addEventListener('mouseout', () => {
sellerLink.style.textDecoration = 'none';
});
sellerTd.appendChild(sellerLink);
tr.appendChild(sellerTd);
const bazaarTd = document.createElement('td');
bazaarTd.style.border = '1px solid #ccc';
bazaarTd.style.padding = '6px';
bazaarTd.style.textAlign = 'center';
bazaarTd.style.fontSize = '14px';
const bazaarLink = document.createElement('a');
bazaarLink.href = `https://www.torn.com/bazaar.php?userID=${item.user_id}`;
bazaarLink.textContent = 'Visit';
bazaarLink.target = '_blank';
bazaarLink.style.color = '#007bff';
bazaarLink.style.textDecoration = 'none';
bazaarLink.addEventListener('mouseover', () => {
bazaarLink.style.textDecoration = 'underline';
});
bazaarLink.addEventListener('mouseout', () => {
bazaarLink.style.textDecoration = 'none';
});
bazaarTd.appendChild(bazaarLink);
bazaarTd.setAttribute('data-label', 'Visit Bazaar');
tr.appendChild(bazaarTd);
tbody.appendChild(tr);
});
table.appendChild(tbody);
tableContainer.appendChild(table);
container.appendChild(tableContainer);
adjustTopCheapestTableTheme();
}
function detectSearch() {
window.addEventListener('hashchange', onHashChange, false);
window.addEventListener('popstate', onHashChange, false);
onHashChange();
}
function onHashChange() {
const { itemID, itemName } = getItemInfoFromURL();
if (itemID) {
fetchTopCheapestItems(itemID);
}
}
function initializeTopCheapestItems() {
const { itemID, itemName } = getItemInfoFromURL();
if (itemID) {
fetchTopCheapestItems(itemID);
} else {
console.warn('IronNerd Bazaar Enhancements: Item ID not found in URL. Top 3 Cheapest Items will not be displayed.');
}
}
function displayShowBazaarStatusMessage(status, message) {
const statusDiv = document.getElementById('showBazaarStatusMessage');
if (!statusDiv) return;
statusDiv.innerHTML = '';
const icon = document.createElement('span');
icon.style.marginRight = '8px';
if (status === 'success') {
icon.textContent = '✅';
statusDiv.style.color = '#155724';
statusDiv.style.backgroundColor = '#d4edda';
} else if (status === 'error') {
icon.textContent = '❌';
statusDiv.style.color = '#721c24';
statusDiv.style.backgroundColor = '#f8d7da';
} else if (status === 'info') {
icon.textContent = 'ℹ️';
statusDiv.style.color = '#004085';
statusDiv.style.backgroundColor = '#cce5ff';
}
const messageSpan = document.createElement('span');
messageSpan.textContent = message;
statusDiv.appendChild(icon);
statusDiv.appendChild(messageSpan);
statusDiv.style.padding = '5px';
statusDiv.style.borderRadius = '3px';
statusDiv.style.display = 'flex';
statusDiv.style.alignItems = 'center';
statusDiv.style.transition = 'background-color 0.3s, color 0.3s';
setTimeout(() => {
statusDiv.textContent = '';
statusDiv.style.display = 'none';
}, 5000);
}
function trapFocus(modal) {
const focusableElements = modal.querySelectorAll('a[href], button, textarea, input, select');
if (focusableElements.length === 0) return;
const firstFocusable = focusableElements[0];
const lastFocusable = focusableElements[focusableElements.length - 1];
modal.addEventListener('keydown', function (e) {
const isTabPressed = (e.key === 'Tab' || e.keyCode === 9);
if (!isTabPressed) return;
if (e.shiftKey) {
if (document.activeElement === firstFocusable) {
lastFocusable.focus();
e.preventDefault();
}
} else {
if (document.activeElement === lastFocusable) {
firstFocusable.focus();
e.preventDefault();
}
}
});
}
function injectAdditionalStyles() {
const style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = `
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#showBazaarModal {
background-color: rgba(0, 0, 0, 0.7);
display: flex;
align-items: center;
justify-content: center;
z-index: 10000;
padding: 20px;
}
#showBazaarModal #modal-content {
background-color: #fff;
color: #000;
padding: 20px;
border-radius: 12px;
max-width: 800px;
width: 100%;
box-sizing: border-box;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
overflow-y: auto;
max-height: 80vh;
margin: 0 10px;
}
#showBazaarModal h2 {
text-align: center;
font-size: 1.5em;
margin-bottom: 15px;
color: #333;
}
#itemNameDisplay {
text-align: center;
margin-bottom: 15px;
color: #333;
font-size: 1.3em;
font-weight: bold;
}
#bazaar-enhancer-container {
background-color: #ffffff;
color: #000000;
border: 1px solid #ddd;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
border-radius: 8px;
padding: 10px;
margin: 10px 0;
transition: background-color 0.3s, color 0.3s;
}
.dark-mode #bazaar-enhancer-container {
background-color: rgba(0, 0, 0, 0.6);
color: #f0f0f0;
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);
}
#showBazaarModal table.bazaar-table,
#bazaar-enhancer-container table.top-cheapest-table {
color: black;
width: 100%;
border-collapse: collapse;
margin-top: 10px;
table-layout: auto;
}
#showBazaarModal table.bazaar-table th,
#showBazaarModal table.bazaar-table td,
#bazaar-enhancer-container table.top-cheapest-table th,
#bazaar-enhancer-container table.top-cheapest-table td {
text-align: center;
padding: 8px;
border: 1px solid #ccc;
}
#showBazaarModal table.bazaar-table th,
#bazaar-enhancer-container table.top-cheapest-table th {
background-color: #f2f2f2;
}
.dark-mode #showBazaarModal table.bazaar-table th,
.dark-mode #showBazaarModal table.bazaar-table td,
.dark-mode #bazaar-enhancer-container table.top-cheapest-table th,
.dark-mode #bazaar-enhancer-container table.top-cheapest-table td {
background-color: #2a2a2a;
color: #f0f0f0;
}
.dark-mode #showBazaarModal table.bazaar-table th,
.dark-mode #bazaar-enhancer-container table.top-cheapest-table th {
background-color: #333;
}
#mobileBazaarButton,
#desktopBazaarButton {
padding: 6px 10px;
font-size: 12px;
border-radius: 4px;
margin: 5px;
background-color: #4caf50;
color: white;
border: none;
cursor: pointer;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
transition: background-color 0.3s, opacity 0.3s;
}
#mobileBazaarButton:hover,
#desktopBazaarButton:hover {
background-color: #45a049;
opacity: 0.9;
}
#showBazaarModal .pagination-button,
#bazaar-enhancer-container .pagination-button {
padding: 6px 10px;
font-size: 12px;
margin: 5px;
border: 1px solid #ccc;
background-color: #4caf50;
color: white;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s, opacity 0.3s;
}
#showBazaarModal .pagination-button:disabled,
#bazaar-enhancer-container .pagination-button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
#showBazaarModal .pagination-button:hover:not(:disabled),
#bazaar-enhancer-container .pagination-button:hover:not(:disabled) {
background-color: #45a049;
}
@media screen and (max-width: 768px) {
#showBazaarModal #modal-content {
padding: 15px;
}
#bazaarButton {
padding: 5px 8px;
font-size: 12px;
}
#showBazaarModal table.bazaar-table th,
#bazaar-enhancer-container table.top-cheapest-table th,
#showBazaarModal table.bazaar-table td,
#bazaar-enhancer-container table.top-cheapest-table td {
padding: 6px;
}
}
#showBazaarModal .loading-spinner,
#bazaar-enhancer-container .loading-spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
width: 24px;
height: 24px;
animation: spin 2s linear infinite;
display: inline-block;
margin-left: 10px;
}
`;
document.head.appendChild(style);
}
function adjustBazaarTableTheme() {
const isDarkMode = document.body.classList.contains('dark-mode');
const bazaarTable = document.querySelector('.bazaar-table');
if (isDarkMode && bazaarTable) {
bazaarTable.style.backgroundColor = '#1c1c1c';
bazaarTable.style.color = '#f0f0f0';
bazaarTable.querySelectorAll('th').forEach(th => {
th.style.backgroundColor = '#444';
th.style.color = '#ffffff';
});
bazaarTable.querySelectorAll('tr:nth-child(even)').forEach(tr => {
tr.style.backgroundColor = '#2a2a2a';
});
bazaarTable.querySelectorAll('tr:nth-child(odd)').forEach(tr => {
tr.style.backgroundColor = '#1e1e1e';
});
bazaarTable.querySelectorAll('td a').forEach(a => {
a.style.color = '#4ea8de';
});
} else if (bazaarTable) {
bazaarTable.style.backgroundColor = '#fff';
bazaarTable.style.color = '#000';
bazaarTable.querySelectorAll('th').forEach(th => {
th.style.backgroundColor = '#f2f2f2';
th.style.color = '#000';
});
bazaarTable.querySelectorAll('tr:nth-child(even)').forEach(tr => {
tr.style.backgroundColor = '#f9f9f9';
});
bazaarTable.querySelectorAll('tr:nth-child(odd)').forEach(tr => {
tr.style.backgroundColor = '#fff';
});
bazaarTable.querySelectorAll('td a').forEach(a => {
a.style.color = '#007bff';
});
}
}
function adjustTopCheapestTableTheme() {
const isDarkMode = document.body.classList.contains('dark-mode');
const topCheapestTable = document.querySelector('.top-cheapest-table');
if (isDarkMode && topCheapestTable) {
topCheapestTable.style.backgroundColor = '#1c1c1c';
topCheapestTable.style.color = '#f0f0f0';
topCheapestTable.querySelectorAll('th').forEach(th => {
th.style.backgroundColor = '#444';
th.style.color = '#ffffff';
});
topCheapestTable.querySelectorAll('tr:nth-child(even)').forEach(tr => {
tr.style.backgroundColor = '#2a2a2a';
});
topCheapestTable.querySelectorAll('tr:nth-child(odd)').forEach(tr => {
tr.style.backgroundColor = '#1e1e1e';
});
topCheapestTable.querySelectorAll('td a').forEach(a => {
a.style.color = '#4ea8de';
});
} else if (topCheapestTable) {
topCheapestTable.style.backgroundColor = '#fff';
topCheapestTable.style.color = '#000';
topCheapestTable.querySelectorAll('th').forEach(th => {
th.style.backgroundColor = '#f2f2f2';
th.style.color = '#000';
});
topCheapestTable.querySelectorAll('tr:nth-child(even)').forEach(tr => {
tr.style.backgroundColor = '#f9f9f9';
});
topCheapestTable.querySelectorAll('tr:nth-child(odd)').forEach(tr => {
tr.style.backgroundColor = '#fff';
});
topCheapestTable.querySelectorAll('td a').forEach(a => {
a.style.color = '#007bff';
});
}
}
function adjustBazaarEnhancerContainerTheme() {
const container = document.getElementById('bazaar-enhancer-container');
const isDarkMode = document.body.classList.contains('dark-mode');
if (container) {
if (isDarkMode) {
container.style.backgroundColor = 'rgba(0, 0, 0, 0.6)';
container.style.color = '#f0f0f0';
container.style.border = '1px solid rgba(255, 255, 255, 0.1)';
container.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.4)';
} else {
container.style.backgroundColor = '#ffffff';
container.style.color = '#000000';
container.style.border = '1px solid #ddd';
container.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.1)';
}
}
}
function observeDarkMode() {
const observer = new MutationObserver(() => {
adjustBazaarTableTheme();
adjustTopCheapestTableTheme();
adjustBazaarEnhancerContainerTheme();
});
observer.observe(document.body, { attributes: true, attributeFilter: ['class'] });
}
})();