-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmonkey2.js
More file actions
85 lines (77 loc) · 2.79 KB
/
Copy pathmonkey2.js
File metadata and controls
85 lines (77 loc) · 2.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// ==UserScript==
// @name npm-versions-sort-gpt
// @namespace http://tampermonkey.net/
// @version 1.1
// @description Enable sorting by Version, Downloads, and Published columns in NPM package version table
// @match https://www.npmjs.com/package/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=npmjs.com
// @grant none
// ==/UserScript==
;(function () {
'use strict'
const mainDiv = document.querySelector('#main')
console.log(mainDiv)
const waitForTable = () => {
const table = mainDiv.querySelector('table[aria-labelledby="version-history"]')
console.log(table)
// debugger
if (table) {
enhanceTable(table)
} else {
setTimeout(waitForTable, 500)
}
}
const enhanceTable = table => {
const thead = table.querySelector('thead')
const rows = [...table.querySelectorAll('tbody tr')]
if (!thead || rows.length === 0) return
let currentSort = { colIndex: -1, asc: true }
// 插入排序样式
const style = document.createElement('style')
style.textContent = `
th.sortable { cursor: pointer; user-select: none; position: relative; }
th.sortable::after {
content: '⇅'; font-size: 0.8em; margin-left: 6px; opacity: 0.3;
}
th.sortable.asc::after { content: '↑'; opacity: 0.8; }
th.sortable.desc::after { content: '↓'; opacity: 0.8; }
`
document.head.appendChild(style)
const headers = [...thead.querySelectorAll('th')]
headers.forEach((th, i) => {
const label = th.textContent.trim().toLowerCase()
if (['version', 'downloads', 'published'].includes(label)) {
th.classList.add('sortable')
th.addEventListener('click', () => {
const asc = currentSort.colIndex === i ? !currentSort.asc : true
currentSort = { colIndex: i, asc }
headers.forEach(h => h.classList.remove('asc', 'desc'))
th.classList.add(asc ? 'asc' : 'desc')
sortRows(rows, i, asc)
const tbody = table.querySelector('tbody')
tbody.innerHTML = ''
rows.forEach(row => tbody.appendChild(row))
})
}
})
}
const sortRows = (rows, colIndex, asc) => {
rows.sort((a, b) => {
const getText = tr => tr.children[colIndex].textContent.trim()
let aText = getText(a)
let bText = getText(b)
if (/downloads/i.test(aText) || /\d+[,.\d]*/.test(aText)) {
const parseNum = t => parseInt(t.replace(/[,]/g, '')) || 0
aText = parseNum(aText)
bText = parseNum(bText)
} else if (/\d{4}-\d{2}-\d{2}/.test(aText)) {
aText = new Date(aText).getTime()
bText = new Date(bText).getTime()
}
if (aText > bText) return asc ? 1 : -1
if (aText < bText) return asc ? -1 : 1
return 0
})
}
waitForTable()
})()