您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds scroll buttons to Dead Frontier Marketplace which lets you quickly jump up or down to the next item with different name. Scrolling happens from the top item perspective - it logs the first visible item inside the marketplace list and scrolls until the top item becomes something else, based on different item name or different data-type.
// ==UserScript== // @name Scroll Buttons // @namespace tampermonkey.net/ // @version 1.0 // @description Adds scroll buttons to Dead Frontier Marketplace which lets you quickly jump up or down to the next item with different name. Scrolling happens from the top item perspective - it logs the first visible item inside the marketplace list and scrolls until the top item becomes something else, based on different item name or different data-type. // @author Lucky11 // @match https://fairview.deadfrontier.com/onlinezombiemmo/index.php?page=35 // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; const ignoreBulletCount = false;//if it's set to true and Ignore_Colour_Stats set to false then while scrolling it will ignore bullet count next to the bullets name const ignore_GC_MC_tags = false;//if it's set to true and Ignore_Colour_Stats set to false then while scrolling it will ignore (GC) (MC) tags next to the gun names const Ignore_Colour_Stats = true;//if set to true it ignores whatever ignoreBulletCount or ignore_GC_MC_tags is set to. Then it skips acts as if both of them are set to true plus ignoring different colours. It only doesn't ignore and stops if item is renamed with different name. const smoothScroll = true;//set to false to disable scroll animation // Toggle controls //KEYBOARD CONTROL const animation_when_keyboard_scroll = true; // Set to false to disable button color changing animation const disableArrowKeys = false; // Set to true to disable scrolling with UP and DOWN arrow keys const disableWSKeys = true; // Set to true to disable scrolling with W and S keys function Main() { // Check if the button already exists to avoid duplicates if (document.getElementById('jumpDownButton')) return; // Create buttons const logButton = document.createElement('button'); logButton.id = 'logButton'; // Set an ID for the button logButton.innerText = 'Log First Visible Item'; logButton.style.margin = '10px'; logButton.style.padding = '5px 10px'; logButton.style.cursor = 'pointer'; const jumpDownButton = document.createElement('button'); jumpDownButton.id = 'jumpDownButton'; // Set an ID for the button jumpDownButton.style.top = '272px'; // Move the button lower by 150px jumpDownButton.style.left = '667px'; jumpDownButton.style.padding = '0'; // Remove padding for a cleaner look jumpDownButton.style.cursor = 'pointer'; jumpDownButton.style.position = 'absolute'; jumpDownButton.style.height = '138px'; // Adjust height as needed jumpDownButton.style.width = '18px'; // Adjust width as needed //jumpDownButton.style.border = 'none'; jumpDownButton.style.border = '1px solid #990000'; // Border with color jumpDownButton.style.backgroundColor = 'rgba(153, 0, 0, 0.3)';//For semi-transparent fill: //jumpDownButton.style.backgroundColor = 'transparent'; // No fill color //jumpDownButton.style.backgroundColor = '#007BFF'; // Button color //jumpDownButton.style.borderRadius = '5px'; // Rounded corners // Create the arrow Down element const arrowdown = document.createElement('div'); arrowdown.style.position = 'absolute'; arrowdown.style.top = '50%'; // Center the arrow vertically arrowdown.style.left = '50%'; // Center the arrow horizontally arrowdown.style.transform = 'translate(-50%, -50%)'; // Center the arrow arrowdown.style.width = '0'; arrowdown.style.height = '0'; arrowdown.style.borderLeft = '5px solid transparent'; arrowdown.style.borderRight = '5px solid transparent'; arrowdown.style.borderTop = '10px solid white'; // Arrow color // Append the arrow Down to the button jumpDownButton.appendChild(arrowdown); const jumpUpButton = document.createElement('button'); jumpUpButton.id = 'jumpUpButton'; // Set an ID for the button jumpUpButton.style.margin = '130px'; jumpUpButton.style.left = '537px'; jumpUpButton.style.padding = '0'; // Remove padding for a cleaner look jumpUpButton.style.cursor = 'pointer'; jumpUpButton.style.position = 'absolute'; jumpUpButton.style.height = '138px'; // Adjust height as needed jumpUpButton.style.width = '18px'; // Adjust width as needed //jumpUpButton.style.border = 'none'; jumpUpButton.style.border = '1px solid #990000'; // Border with color jumpUpButton.style.backgroundColor = 'rgba(153, 0, 0, 0.3)';//For semi-transparent fill: //jumpUpButton.style.borderRadius = '5px'; // Rounded corners // Create the arrow Up element const arrow = document.createElement('div'); arrow.style.position = 'absolute'; arrow.style.top = '50%'; // Center the arrow vertically arrow.style.left = '50%'; // Center the arrow horizontally arrow.style.transform = 'translate(-50%, -50%)'; // Center the arrow arrow.style.width = '0'; arrow.style.height = '0'; arrow.style.borderLeft = '5px solid transparent'; arrow.style.borderRight = '5px solid transparent'; arrow.style.borderBottom = '10px solid white'; // Arrow color // Append the arrow Up to the button jumpUpButton.appendChild(arrow); // Append buttons to the invController div const invController = document.getElementById('invController'); //invController.appendChild(logButton); //enable only for developing - logs in console the top visible item info ect. invController.appendChild(jumpDownButton); invController.appendChild(jumpUpButton); //KEYBOARD CONTROL // Track key press states to prevent multiple triggers on hold const keyStates = { ArrowUp: false, ArrowDown: false, W: false, S: false }; let isAnimatingButton = false; // Function to animate button style function animateButton(button) { if (!animation_when_keyboard_scroll || isAnimatingButton) return; isAnimatingButton = true; // Lock //button.disabled = true; // Disable button // Save original styles const originalBorderColor = button.style.borderColor || ''; const originalBackgroundColor = button.style.backgroundColor || ''; // Change styles to indicate activation button.style.borderColor = '#FFCC00'; // Bright border button.style.backgroundColor = 'rgba(204, 100, 0, 0.5)'; // Less transparent // Revert after 200ms setTimeout(() => { button.style.borderColor = originalBorderColor; button.style.backgroundColor = originalBackgroundColor; //button.disabled = false; // Re-enable button isAnimatingButton = false; // Unlock }, 100); } // Function to handle keydown events function handleKeyDown(e) { // Prevent default if needed if (disableArrowKeys && (e.key === 'ArrowUp' || e.key === 'ArrowDown')) { e.preventDefault(); } // Handle arrow keys with one activation per press if (e.key === 'ArrowUp') { if (!keyStates.ArrowUp) { keyStates.ArrowUp = true; //console.log('Arrow Up pressed'); jumpUp(); } e.preventDefault(); } else if (e.key === 'ArrowDown') { if (!keyStates.ArrowDown) { keyStates.ArrowDown = true; //console.log('Arrow Down pressed'); jumpDown(); } e.preventDefault(); } else if (!disableWSKeys) { // W/S keys as Up/Down if (e.key === 'w' || e.key === 'W') { if (!keyStates.W) { keyStates.W = true; //console.log('W pressed (treated as Arrow Up)'); jumpUp(); } } else if (e.key === 's' || e.key === 'S') { if (!keyStates.S) { keyStates.S = true; //console.log('S pressed (treated as Arrow Down)'); jumpDown(); } } } } function handleKeyUp(e) { // Reset key states if (e.key === 'ArrowUp') { keyStates.ArrowUp = false; //console.log('Arrow Up released'); } else if (e.key === 'ArrowDown') { keyStates.ArrowDown = false; //console.log('Arrow Down released'); } else if (!disableWSKeys) { if (e.key === 'w' || e.key === 'W') { keyStates.W = false; console.log('W released'); } else if (e.key === 's' || e.key === 'S') { keyStates.S = false; console.log('S released'); } } } // Attach event listeners window.addEventListener('keydown', handleKeyDown); window.addEventListener('keyup', handleKeyUp); //KEYBOARD CONTROL function cleanItemNameAmmo(itemName) { const lastParenIndex = itemName.lastIndexOf(' ('); const closingParenIndex = itemName.indexOf(')', lastParenIndex); if (lastParenIndex !== -1 && closingParenIndex !== -1) { const countInParentheses = itemName.substring(lastParenIndex + 2, closingParenIndex).trim(); if (/^\d+$/.test(countInParentheses)) { return itemName.substring(0, lastParenIndex).trim(); } } return itemName; } function cleanItemNameTags(itemName) { const tagsToRemove = ['(MC)', '(GC)', '(HC)', '(NGC)','(AC)']; for (const tag of tagsToRemove) { const tagIndex = itemName.lastIndexOf(tag); if (tagIndex !== -1) { return itemName.substring(0, tagIndex).trim(); } } return itemName; } function getStandardizedItemName(item) { let itemName = item.innerText.split('\n')[0].trim(); if (Ignore_Colour_Stats) { const dataType = item.getAttribute('data-type'); if (dataType) { if (dataType.includes('_name')) { // itemName remains unchanged } else { const dataTypeParts = dataType.split('_'); if (dataTypeParts[dataTypeParts.length - 1] === 'cooked') { itemName = dataTypeParts.join('_'); } else { itemName = dataTypeParts[0]; if (itemName === 'credits' && item.innerText) { itemName = item.innerText.split('\n')[0].trim(); } } } } else { //console.log('data-type attribute is null or undefined for item:', item); itemName = item.innerText.split('\n')[0].trim(); } } if (ignoreBulletCount && !Ignore_Colour_Stats) { itemName = cleanItemNameAmmo(itemName); } if (ignore_GC_MC_tags && !Ignore_Colour_Stats) { itemName = cleanItemNameTags(itemName); } //if services then return level not name and data-type is null const levelElement = item.querySelector('.level'); // Select the level element const dataLevel = levelElement ? levelElement.textContent : null; // Get the text content if (dataLevel) { itemName = dataLevel; } return itemName; } // Function to log the first visible item in the itemDisplay div logButton.addEventListener('click', () => { const itemDisplay = document.getElementById('itemDisplay'); const items = itemDisplay.children; let firstVisibleItem = null; let lastVisibleItem = null; for (let i = 0; i < items.length; i++) { const item = items[i]; const rect = item.getBoundingClientRect(); const displayRect = itemDisplay.getBoundingClientRect(); if (rect.top >= displayRect.top && rect.bottom <= displayRect.bottom) { firstVisibleItem = item; break; } } // If the first visible item is found, look for the last visible item if (firstVisibleItem) { const firstVisibleIndex = Array.from(items).indexOf(firstVisibleItem); const lastVisibleIndex = Math.min(firstVisibleIndex + 13, items.length - 1); // Limit to 13 items below // Find the last visible item within the specified range for (let i = firstVisibleIndex + 1; i <= lastVisibleIndex; i++) { const item = items[i]; const rect = item.getBoundingClientRect(); const displayRect = itemDisplay.getBoundingClientRect(); if (rect.top >= displayRect.top && rect.bottom <= displayRect.bottom) { lastVisibleItem = item; // Update last visible item } } console.log('First Visible Item:', firstVisibleItem.innerText); const dataType = firstVisibleItem.getAttribute('data-type'); console.log('Data Type:', dataType); console.log('Last Visible Item:', lastVisibleItem.innerText); const dataTypeLast = lastVisibleItem.getAttribute('data-type'); console.log('Data Type of Last Visible Item:', dataTypeLast); // Get all child elements inside itemDisplay const items123 = itemDisplay.children; // Check if there are any child elements if (items123.length > 0) { // Get the last child element const lastItem123 = items123[items123.length - 1]; // Log the inner text of the last item console.log('Inner Text:', lastItem123.innerText); // Log the data-type attribute of the last item console.log('Data-type:', lastItem123.getAttribute('data-type')); } else { console.log('No items found inside itemDisplay.'); } if (ignoreBulletCount) { let itemName = getStandardizedItemName(firstVisibleItem); console.log(itemName); } } else { console.log('No items currently visible.'); } }); function smoothScrollTo(element, targetTop) { return new Promise((resolve) => { const startTop = element.scrollTop; const distance = targetTop - startTop; const duration = 200; // duration in ms const startTime = performance.now(); function scroll() { const now = performance.now(); const elapsed = now - startTime; const progress = Math.min(elapsed / duration, 1); element.scrollTop = startTop + distance * progress; if (progress < 1) { requestAnimationFrame(scroll); } else { resolve(); } } requestAnimationFrame(scroll); }); } let isScrolling = false; async function jumpDown() { if (isScrolling) return; isScrolling = true; jumpDownButton.disabled = true; // Disable button // Animate button if enabled animateButton(jumpDownButton); const itemDisplay = document.getElementById('itemDisplay'); //const items = itemDisplay.children; let items; try { items = itemDisplay.children; } catch (error) { console.error('An error occurred while accessing itemDisplay.children:', error); isScrolling = false; // Reset scrolling state if no items are found jumpDownButton.disabled = false; // Re-enable button return; // Exit the function if an error occurs } let firstVisibleItem = null; let firstVisibleItemName = ''; // Find the first visible item for (let i = 0; i < items.length; i++) { const item = items[i]; const rect = item.getBoundingClientRect(); const displayRect = itemDisplay.getBoundingClientRect(); if (rect.top >= displayRect.top && rect.bottom <= displayRect.bottom) { firstVisibleItem = item; firstVisibleItemName = getStandardizedItemName(firstVisibleItem); break; } } if (firstVisibleItem) { let foundFirstVisible = false; for (let i = 0; i < items.length; i++) { const item = items[i]; const itemName = getStandardizedItemName(item); if (foundFirstVisible) { if (itemName !== firstVisibleItemName) { const itemTop = item.offsetTop; // Check if we are at the bottom of the itemDisplay const isAtBottom = itemDisplay.scrollTop + itemDisplay.clientHeight >= itemDisplay.scrollHeight - 1; if (isAtBottom) { console.log("Reached the bottom, stopping scroll."); isScrolling = false; // Reset scrolling state jumpDownButton.disabled = false; // Re-enable button return; // Exit if at the bottom } if (smoothScroll) { // Use smoothScrollTo for smooth scrolling await smoothScrollTo(itemDisplay, itemTop); // Await the smooth scroll isScrolling = false; // Reset scrolling state after completion jumpDownButton.disabled = false; // Re-enable button } else { itemDisplay.scrollTop = itemTop; // Set scroll position directly isScrolling = false; // Reset scrolling state jumpDownButton.disabled = false; // Re-enable button } break; } } if (item === firstVisibleItem) { foundFirstVisible = true; } } } else { console.log('No items currently visible to jump down from.'); isScrolling = false; // Reset scrolling state if no items are found jumpDownButton.disabled = false; // Re-enable button } isScrolling = false; // Reset scrolling state if no items are found jumpDownButton.disabled = false; // Re-enable button } // Function to jump up to the next item above with a different name async function jumpUp() { if (isScrolling) return; isScrolling = true; jumpUpButton.disabled = true; // Disable button // Animate button if enabled animateButton(jumpUpButton); const itemDisplay = document.getElementById('itemDisplay'); //const items = itemDisplay.children; let items; try { items = itemDisplay.children; } catch (error) { console.error('An error occurred while accessing itemDisplay.children:', error); isScrolling = false; jumpUpButton.disabled = false; // Disable button return; // Exit the function if an error occurs } let firstVisibleItem = null; let firstVisibleItemName = ''; for (let i = 0; i < items.length; i++) { const item = items[i]; const rect = item.getBoundingClientRect(); const displayRect = itemDisplay.getBoundingClientRect(); if (rect.top >= displayRect.top && rect.bottom <= displayRect.bottom) { firstVisibleItem = item; firstVisibleItemName = getStandardizedItemName(firstVisibleItem); break; } } if (firstVisibleItem) { for (let i = Array.from(items).indexOf(firstVisibleItem) - 1; i >= 0; i--) { const item = items[i]; const itemName = getStandardizedItemName(item); if (itemName !== firstVisibleItemName) { let foundIndex = -1; for (let j = 0; j < items.length; j++) { if (getStandardizedItemName(items[j]) === itemName) { foundIndex = j; break; } } if (foundIndex !== -1) { const targetTop = items[foundIndex].offsetTop; if (smoothScroll) { await smoothScrollTo(itemDisplay, targetTop); }else{ const itemTop = items[foundIndex].offsetTop; // Get the top position of the item itemDisplay.scrollTop = itemTop; // Set the scroll position directly } isScrolling = false; jumpUpButton.disabled = false; // Disable button return; } //return; } if (Array.from(items).indexOf(item) === 0) { if (smoothScroll) { await smoothScrollTo(itemDisplay, items[0]); }else{ const itemTop = items[0].offsetTop; // Get the top position of the item itemDisplay.scrollTop = itemTop; // Set the scroll position directly } isScrolling = false; jumpUpButton.disabled = false; // Disable button return; } } } else { console.log('No items currently visible to jump up from.'); } isScrolling = false; jumpUpButton.disabled = false; // Disable button } // button event listeners jumpDownButton.addEventListener('click', jumpDown); jumpUpButton.addEventListener('click', jumpUp); } //AddButtons(); /* * Part of the Code below of this script is derived from the "Dead Frontier - Fast Services" script by Shrike00 * Original source: https://update.greasyfork.org/scripts/472536/Dead%20Frontier%20-%20Fast%20Services.user.js * Copyright (c) Shrike00 * Licensed under the MIT License. */ // Initial button creation and observer setup function waitForItemDisplay(callback, timeout) { const start = performance.now(); const check = setInterval(function() { if (document.getElementById("itemDisplay") !== null) { clearInterval(check); callback(); } else if (performance.now() - start > timeout) { clearInterval(check); } }, 100); } function Start() { waitForItemDisplay(function() { // Initial addition of button. Main(); // Mutation observer to check for changes to the marketplace child nodes, re-adding the event listener // whenever the selectMarket element is re-added (which happens when the market tab is changed). const callback = function(mutationList, observer) { for (const record of mutationList) { const element = record.addedNodes[0]; if (element !== undefined && element.id === "selectMarket") { //createSortButton(); checkAndCreateSortButton(); } } } const observer = new MutationObserver(callback); const marketplace = document.getElementById("marketplace"); observer.observe(marketplace, {childList: true}); }, 5000); } function removeButtons() { const logButton = document.getElementById('logButton'); const jumpDownButton = document.getElementById('jumpDownButton'); const jumpUpButton = document.getElementById('jumpUpButton'); if (logButton) { logButton.remove(); // Remove the log button } if (jumpDownButton) { jumpDownButton.remove(); // Remove the jump down button } if (jumpUpButton) { jumpUpButton.remove(); // Remove the jump up button } } function checkAndCreateSortButton() { const pageLogo = document.getElementById("pageLogo"); const marketType = pageLogo ? pageLogo.getAttribute("data-market-type") : null; const innerText = pageLogo ? pageLogo.innerText.trim() : ""; //console.log(innerText); //console.log(marketType); if (marketType === "buy" || innerText === "ITEM-FOR-ITEM") { //console.log("added buttons"); Main(); } else {//if not buy or item for item section of marketplace then remove buttons. //console.log("Removing buttons"); removeButtons(); // Call the function to remove buttons } } Start(); })();