// ==UserScript== // @name Keylol Table Sort // @namespace http://tampermonkey.net/ // @version 0.30 // @description 对keylol琪露诺折扣贴表格按价格或折扣排序 // @author 冰雪聪明琪露诺 // @match https://keylol.com/t* // @grant none // @downloadURL none // ==/UserScript== (function() { 'use strict'; let currentOptionsContainer = null; function setupSort() { if (currentOptionsContainer) { currentOptionsContainer.remove(); currentOptionsContainer = null; } const table = document.querySelector('.t_fsz table.t_table'); if (!table) return; const priceHeaderCell = Array.from(table.querySelector('tr').cells).find(cell => cell.textContent.includes('商店价格')); const reviewHeaderCell = Array.from(table.querySelector('tr').cells).find(cell => cell.textContent.includes('游戏评价')); if (!priceHeaderCell || !reviewHeaderCell) return; currentOptionsContainer = document.createElement('div'); Object.assign(currentOptionsContainer.style, { position: 'absolute', display: 'none', backgroundColor: 'white', border: '1px solid #ccc', padding: '5px', zIndex: '100' }); currentOptionsContainer.className = 'keylol-sort-options'; const priceSortOptions = [ { text: '按价格排序(升序)', fn: (a, b, idx) => parseFloat(a.cells[idx].textContent.match(/¥(\d+\.\d+)/)[1]) - parseFloat(b.cells[idx].textContent.match(/¥(\d+\.\d+)/)[1]) }, { text: '按价格排序(降序)', fn: (a, b, idx) => parseFloat(b.cells[idx].textContent.match(/¥(\d+\.\d+)/)[1]) - parseFloat(a.cells[idx].textContent.match(/¥(\d+\.\d+)/)[1]) }, { text: '按折扣排序(升序)', fn: (a, b, idx) => parseFloat(a.cells[idx].textContent.match(/-(\d+)%/)[1]) - parseFloat(b.cells[idx].textContent.match(/-(\d+)%/)[1]) }, { text: '按折扣排序(降序)', fn: (a, b, idx) => parseFloat(b.cells[idx].textContent.match(/-(\d+)%/)[1]) - parseFloat(a.cells[idx].textContent.match(/-(\d+)%/)[1]) } ]; const reviewSortOptions = [ { text: '按好评率排序(升序)', fn: (a, b, idx) => { const ratingA = parseFloat(a.cells[idx].textContent.match(/(\d+)%/)[1]); const ratingB = parseFloat(b.cells[idx].textContent.match(/(\d+)%/)[1]); return ratingA === ratingB ? parseInt(a.cells[idx].textContent.match(/(\d+)篇/)[1]) - parseInt(b.cells[idx].textContent.match(/(\d+)篇/)[1]) : ratingA - ratingB; } }, { text: '按好评率排序(降序)', fn: (a, b, idx) => { const ratingA = parseFloat(a.cells[idx].textContent.match(/(\d+)%/)[1]); const ratingB = parseFloat(b.cells[idx].textContent.match(/(\d+)%/)[1]); return ratingA === ratingB ? parseInt(b.cells[idx].textContent.match(/(\d+)篇/)[1]) - parseInt(a.cells[idx].textContent.match(/(\d+)篇/)[1]) : ratingB - ratingA; } }, { text: '按评测数排序(升序)', fn: (a, b, idx) => parseInt(a.cells[idx].textContent.match(/(\d+)篇/)[1]) - parseInt(b.cells[idx].textContent.match(/(\d+)篇/)[1]) }, { text: '按评测数排序(降序)', fn: (a, b, idx) => parseInt(b.cells[idx].textContent.match(/(\d+)篇/)[1]) - parseInt(a.cells[idx].textContent.match(/(\d+)篇/)[1]) } ]; const showOptions = (headerCell, options, index) => { headerCell.addEventListener('click', function() { currentOptionsContainer.innerHTML = ''; options.forEach(option => { const opt = document.createElement('div'); opt.textContent = option.text; opt.style.cursor = 'pointer'; opt.style.padding = '5px'; opt.addEventListener('click', () => { sortTable(table, option.fn, index); currentOptionsContainer.style.display = 'none'; }); currentOptionsContainer.appendChild(opt); }); const rect = this.getBoundingClientRect(); const scrollTop = window.pageYOffset || document.documentElement.scrollTop; const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft; currentOptionsContainer.style.left = rect.left + scrollLeft + 'px'; currentOptionsContainer.style.top = rect.bottom + scrollTop + 'px'; currentOptionsContainer.style.display = 'block'; }); }; const priceIndex = Array.from(table.rows[0].cells).findIndex(cell => cell.textContent.includes('商店价格')); const reviewIndex = Array.from(table.rows[0].cells).findIndex(cell => cell.textContent.includes('游戏评价')); showOptions(priceHeaderCell, priceSortOptions, priceIndex); showOptions(reviewHeaderCell, reviewSortOptions, reviewIndex); document.body.appendChild(currentOptionsContainer); } function sortTable(table, sortFunction, index) { const rows = Array.from(table.rows).slice(1); rows.sort((a, b) => sortFunction(a, b, index)); while (table.rows.length > 1) { table.deleteRow(1); } rows.forEach(row => table.appendChild(row)); } document.body.addEventListener('click', function(e) { if (e.target.closest('.tindex li, div[style*="text-align: center;margin-top: 10px;"] a')) { setTimeout(setupSort, 1000); } }); setTimeout(setupSort, 1000); })();