您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Sort and filter buslog route collection table
// ==UserScript== // @name Buslog Table Sorter & Filter with Toggle // @namespace http://tampermonkey.net/ // @version 1.3 // @description Sort and filter buslog route collection table // @author petabyte // @match https://busmiles.uk/buslog/*/routecollection // @grant none // ==/UserScript== (function () { 'use strict'; function createFilterUI(operators, onChange) { if (document.getElementById('operator-filter-container')) return null; const wrapper = document.createElement('div'); wrapper.id = 'operator-filter-wrapper'; wrapper.style.marginBottom = '10px'; const toggleButton = document.createElement('button'); toggleButton.textContent = 'Hide Filter'; toggleButton.style.marginBottom = '5px'; toggleButton.style.padding = '5px 10px'; toggleButton.style.cursor = 'pointer'; toggleButton.style.border = '1px solid #ccc'; toggleButton.style.borderRadius = '5px'; toggleButton.style.backgroundColor = '#eee'; toggleButton.style.fontSize = '14px'; const container = document.createElement('div'); container.id = 'operator-filter-container'; container.style.marginTop = '5px'; container.style.padding = '10px'; container.style.border = '1px solid #ccc'; container.style.backgroundColor = '#f9f9f9'; container.style.borderRadius = '6px'; toggleButton.addEventListener('click', () => { if (container.style.display === 'none') { container.style.display = ''; toggleButton.textContent = 'Hide Filter'; } else { container.style.display = 'none'; toggleButton.textContent = 'Show Filter'; } }); const label = document.createElement('strong'); label.textContent = 'Filter by operator: '; container.appendChild(label); operators.forEach(op => { const id = `filter-${op.replace(/\s+/g, '-')}`; const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.checked = true; checkbox.id = id; checkbox.dataset.operator = op; checkbox.addEventListener('change', () => { const active = Array.from(container.querySelectorAll('input[type="checkbox"]:checked')) .map(cb => cb.dataset.operator); onChange(active); }); const lbl = document.createElement('label'); lbl.htmlFor = id; lbl.style.marginRight = '10px'; lbl.style.marginLeft = '5px'; lbl.appendChild(document.createTextNode(op)); container.appendChild(checkbox); container.appendChild(lbl); }); wrapper.appendChild(toggleButton); wrapper.appendChild(container); return wrapper; } function makeSortableAndFilterable() { const table = document.querySelector("table.table"); if (!table) return; const headers = table.querySelectorAll("thead th"); const rows = Array.from(table.querySelectorAll("tbody tr")); const tbody = table.querySelector("tbody"); let currentSortIndex = -1; let currentSortAsc = true; const operatorIndex = 0; const allOperators = Array.from(new Set(rows.map(row => row.children[operatorIndex].textContent.trim()))).sort(); const filterUI = createFilterUI(allOperators, applyFilter); if (filterUI) { table.parentElement.insertBefore(filterUI, table); } let visibleOperators = new Set(allOperators); function applyFilter(activeOperators) { visibleOperators = new Set(activeOperators); renderRows(); } function renderRows() { const filteredRows = rows.filter(row => { const op = row.children[operatorIndex].textContent.trim(); return visibleOperators.has(op); }); const sortedRows = [...filteredRows]; if (currentSortIndex !== -1) { sortedRows.sort((a, b) => { const tdA = a.children[currentSortIndex].textContent.trim(); const tdB = b.children[currentSortIndex].textContent.trim(); const numA = parseFloat(tdA.replace(/[^\d.]/g, "")); const numB = parseFloat(tdB.replace(/[^\d.]/g, "")); const isNumber = !isNaN(numA) && !isNaN(numB); let compare; if (isNumber) { compare = numA - numB; } else { compare = tdA.localeCompare(tdB, undefined, { sensitivity: 'base' }); } return currentSortAsc ? compare : -compare; }); } tbody.innerHTML = ''; sortedRows.forEach(row => tbody.appendChild(row)); } headers.forEach((th, i) => { const span = document.createElement("span"); span.style.marginLeft = "0.5em"; th.appendChild(span); th.style.cursor = "pointer"; th.addEventListener("click", () => { const isAsc = currentSortIndex === i ? !currentSortAsc : true; currentSortIndex = i; currentSortAsc = isAsc; headers.forEach((header, j) => { header.querySelector("span").textContent = j === i ? (isAsc ? "▲" : "▼") : ""; }); renderRows(); }); }); renderRows(); } function waitForTable() { const observer = new MutationObserver(() => { const table = document.querySelector("table.table"); if (table && !document.getElementById('operator-filter-wrapper')) { makeSortableAndFilterable(); } }); observer.observe(document.body, { childList: true, subtree: true }); } window.addEventListener("load", () => { waitForTable(); }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址