您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Fan-made sorting tool for Kill Team rules page. Adds alphabetical and date sorting functionality with configurable date formats. This is an unofficial tool not affiliated with, endorsed, or sponsored by Games Workshop. Warhammer Kill Team is a trademark of Games Workshop Limited.
// ==UserScript== // @name Warhammer Kill Team Rules Sorter // @namespace https://greasyfork.org/en/users/Kardiff // @version 1.1.1 // @description Fan-made sorting tool for Kill Team rules page. Adds alphabetical and date sorting functionality with configurable date formats. This is an unofficial tool not affiliated with, endorsed, or sponsored by Games Workshop. Warhammer Kill Team is a trademark of Games Workshop Limited. // @author Kardiff // @match https://www.warhammer-community.com/*/downloads/kill-team/ // @license MIT // @run-at document-idle // @supportURL https://github.com/Kardiff-Kill-Team/page_sorter/issues // @homepageURL https://github.com/Kardiff-Kill-Team/page_sorter // ==/UserScript== (function() { 'use strict'; const styles = ` .sort-controls { position: sticky; top: 0; background: white; padding: 10px; z-index: 1000; box-shadow: 0 2px 5px rgba(0,0,0,0.1); margin-bottom: 20px; display: flex; justify-content: center; gap: 10px; } .sort-button { padding: 8px 15px; border: none; border-radius: 4px; background: #234; color: white; cursor: pointer; font-weight: bold; min-width: 150px; } .sort-button:hover { background: #345; } `; // Date format configurations const dateFormats = { US: { label: 'US (MM/DD/YYYY)', format: (day, month, year) => `${month}/${day}/${year}`, parse: (text) => { const [month, day, year] = text.split('/'); return new Date(`${year}-${month}-${day}`); } }, EU: { label: 'EU (DD/MM/YYYY)', format: (day, month, year) => `${day}/${month}/${year}`, parse: (text) => { const [day, month, year] = text.split('/'); return new Date(`${year}-${month}-${day}`); } }, ISO: { label: 'ISO (YYYY-MM-DD)', format: (day, month, year) => `${year}-${month}-${day}`, parse: (text) => new Date(text) } }; // Add styles const styleSheet = document.createElement("style"); styleSheet.textContent = styles; document.head.appendChild(styleSheet); function initializeSorter(container) { // Create control buttons const controlsDiv = document.createElement('div'); controlsDiv.className = 'sort-controls'; const alphabeticalButton = document.createElement('button'); alphabeticalButton.textContent = 'Sort A-Z'; alphabeticalButton.className = 'sort-button'; const dateButton = document.createElement('button'); dateButton.textContent = 'Sort by Latest Update'; dateButton.className = 'sort-button'; const formatButton = document.createElement('button'); formatButton.className = 'sort-button'; let currentFormat = 'US'; // Default format // Store original dates to prevent conversion errors const originalDates = new Map(); function updateFormatButtonText() { formatButton.textContent = `Format: ${dateFormats[currentFormat].label}`; } updateFormatButtonText(); controlsDiv.appendChild(alphabeticalButton); controlsDiv.appendChild(dateButton); controlsDiv.appendChild(formatButton); container.parentElement.insertBefore(controlsDiv, container); // Store original dates when first encountering them container.querySelectorAll('.shared-downloadCard').forEach(card => { const dateSpan = card.querySelector('.border-t span.ml-5'); if (dateSpan && !originalDates.has(card)) { const dateParts = dateSpan.textContent.trim().split('/'); // Store as day, month, year originalDates.set(card, { day: dateParts[0], month: dateParts[1], year: dateParts[2] }); } }); function updateAllDates() { container.querySelectorAll('.shared-downloadCard').forEach(card => { const dateSpan = card.querySelector('.border-t span.ml-5'); if (dateSpan && originalDates.has(card)) { const { day, month, year } = originalDates.get(card); if (currentFormat === 'ISO') { dateSpan.textContent = dateFormats.ISO.format(day, month, year); } else if (currentFormat === 'US') { dateSpan.textContent = dateFormats.US.format(day, month, year); } else { dateSpan.textContent = dateFormats.EU.format(day, month, year); } } }); } // Initial date conversion updateAllDates(); function getTeamBoxes() { return Array.from(container.querySelectorAll('.shared-downloadCard')); } function getTeamName(box) { const link = box.querySelector('a[download]'); return link ? link.textContent.trim() : ''; } function getLastUpdated(box) { if (originalDates.has(box)) { const { day, month, year } = originalDates.get(box); // Always use ISO format for date comparison return new Date(`${year}-${month}-${day}`); } return new Date(0); } function sortBoxes(sortFunction) { const boxes = getTeamBoxes(); if (boxes.length === 0) return; const sortedBoxes = [...boxes].sort(sortFunction); sortedBoxes.forEach(box => container.appendChild(box)); } function sortAlphabetically() { sortBoxes((a, b) => getTeamName(a).localeCompare(getTeamName(b))); } function sortByDate() { sortBoxes((a, b) => { const dateCompare = getLastUpdated(b) - getLastUpdated(a); return dateCompare === 0 ? getTeamName(a).localeCompare(getTeamName(b)) : dateCompare; }); } alphabeticalButton.addEventListener('click', sortAlphabetically); dateButton.addEventListener('click', sortByDate); formatButton.addEventListener('click', () => { // Cycle through formats: US -> EU -> ISO -> US const formats = Object.keys(dateFormats); const currentIndex = formats.indexOf(currentFormat); currentFormat = formats[(currentIndex + 1) % formats.length]; updateFormatButtonText(); updateAllDates(); }); // Initial sort setTimeout(sortAlphabetically, 1000); } // Watch for content to load const observer = new MutationObserver((mutations, obs) => { const downloadCards = document.querySelectorAll('.shared-downloadCard'); if (downloadCards.length > 0) { const container = downloadCards[0].parentElement; if (container && !document.querySelector('.sort-controls')) { obs.disconnect(); initializeSorter(container); } } }); observer.observe(document.body, { childList: true, subtree: true }); // Fallback timeout setTimeout(() => { observer.disconnect(); const downloadCards = document.querySelectorAll('.shared-downloadCard'); if (downloadCards.length > 0) { const container = downloadCards[0].parentElement; if (container && !document.querySelector('.sort-controls')) { initializeSorter(container); } } }, 10000); })();