Skip to content

Commit

Permalink
Allow collapsing and remember collapsed columns
Browse files Browse the repository at this point in the history
  • Loading branch information
mebeim committed Mar 29, 2024
1 parent caa9e87 commit 52b4fef
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 36 deletions.
76 changes: 69 additions & 7 deletions www/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ table th {
background-color: var(--table-head-bg);
border-top: var(--table-cell-border);
border-bottom: var(--table-cell-border);
/* Avoid ugly text selection while clicking to sort/collapse */
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}

table th.pad {
Expand Down Expand Up @@ -133,28 +138,70 @@ table span.argtype {
display: none;
}

.fakelink {
text-decoration: underline;
cursor: pointer;
}

table td.unknown {
font-family: sans-serif;
font-style: italic;
}

table th.ascending::before, table th.descending::before, table td.bad::after, table td.esoteric::after {
font-family: 'Noto Color Emoji';
#compact-sig-toggle {
text-decoration: underline;
}

#compact-sig-toggle::before { display: inline-block; content: '['; }
#compact-sig-toggle::after { display: inline-block; content: ']'; }

/* Collapse columns through CSS trickery so that JS only has to add/remove words
* from the table's data-collapse attribute. */

table th > .collapse-toggle::before {
content: '[-]';
}

/* Show [+] instead of [-] for collapsed columns */
table[data-collapse~="name"] th[data-column="name"] > .collapse-toggle::before,
table[data-collapse~="symbol"] th[data-column="symbol"] > .collapse-toggle::before,
table[data-collapse~="location"] th[data-column="location"] > .collapse-toggle::before,
table[data-collapse~="kconfig"] th[data-column="kconfig"] > .collapse-toggle::before,
table[data-collapse~="signature"] th[data-column="signature"] > .collapse-toggle::before {
content: '[+]';
}

/* No column title for collapsed columns, just the toggle */
table[data-collapse~="name"] th[data-column="name"] > .collapsible,
table[data-collapse~="symbol"] th[data-column="symbol"] > .collapsible,
table[data-collapse~="location"] th[data-column="location"] > .collapsible,
table[data-collapse~="kconfig"] th[data-column="kconfig"] > .collapsible,
table[data-collapse~="signature"] th[data-column="signature"] > .collapsible {
display: none;
}

/* Hide the content of collapsed columns */
table[data-collapse~="name"] td[data-column="name"],
table[data-collapse~="symbol"] td[data-column="symbol"],
table[data-collapse~="location"] td[data-column="location"],
table[data-collapse~="kconfig"] td[data-column="kconfig"],
table[data-collapse~="signature"] td[data-column="signature"] {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
max-width: 0px;
opacity: 0.5;
}

/* Emojis! Use U+202f (narrow no-break space) to space header sort arrows and
U+2002 (en space) to space emojis for bad locations and esoteric syscalls. */

table th.ascending::before, table th.descending::before, table td.bad::after, table td.esoteric::after {
font-family: 'Noto Color Emoji';
}

table th.ascending::before { content: '\2b07\fe0f\202f'; }
table th.descending::before { content: '\2b06\fe0f\202f'; }
table td.bad::after { content: '\2002\26a0\fe0f'; }
table td.esoteric::after { content: '\2002\1f984\fe0f'; }

/* Hover effects */

@media (any-hover: hover) {
table th.sortable:hover {
cursor: pointer;
Expand All @@ -168,4 +215,19 @@ table td.esoteric::after { content: '\2002\1f984\fe0f'; }
table a:hover {
text-decoration: underline;
}

table .collapse-toggle:hover {
cursor: pointer;
text-shadow: 0px 0px 3px var(--main-fg);
}

#compact-sig-toggle:hover {
cursor: pointer;
}

#compact-sig-toggle:hover::before,
#compact-sig-toggle:hover::after {
text-decoration: none;
text-shadow: 0px 0px 3px var(--main-fg);
}
}
12 changes: 6 additions & 6 deletions www/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ <h3>
<table>
<tr>
<th class="pad" colspan="6"></th>
<th>Signature [<span class="fakelink" id="compact-sig-toggle"></span>]</th>
<th data-column="signature"><span class="collapse-toggle" title="Click to expand/collapse"></span><span class="collapsible"> Signature <span id="compact-sig-toggle" title="Click to toggle between compact C-style and extended multi-column arguments"></span></span></th>
</tr>
<tr>
<th class="sortable ascending" colspan="2" title="Click to sort">Number</th>
<th class="sortable" title="Click to sort">Name</th>
<th class="sortable" title="Click to sort">Symbol</th>
<th class="sortable" title="Click to sort">Definition location</th>
<th class="sortable" title="Click to sort">Kconfig</th>
<th class="sortable ascending" colspan="2" title="Click to sort by this column">Number</th>
<th class="sortable" data-column="name" title="Click to sort by this column"><span class="collapse-toggle" title="Click to expand/collapse"></span><span class="collapsible"> Name</span></th>
<th class="sortable" data-column="symbol" title="Click to sort by this column"><span class="collapse-toggle" title="Click to expand/collapse"></span><span class="collapsible"> Symbol</span></th>
<th class="sortable" data-column="location" title="Click to sort by this column"><span class="collapse-toggle" title="Click to expand/collapse"></span><span class="collapsible"> Definition location</span></th>
<th class="sortable" data-column="kconfig" title="Click to sort by this column"><span class="collapse-toggle" title="Click to expand/collapse"></span><span class="collapsible"> Kconfig</span></th>
</tr>
</table>
<h3 id="summary"></h3>
Expand Down
87 changes: 64 additions & 23 deletions www/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,12 @@ function sortTable(e) {
if (updateInProgress)
return

const header = e.target
const idx = Array.from(header.parentNode.children).indexOf(e.target)
// Ignore click on the collapse toggle inside the <th>
if (e.target.classList.contains('collapse-toggle'))
return

const header = e.currentTarget
const idx = Array.from(header.parentNode.children).indexOf(e.currentTarget)
const rows = Array.from(tableEl.querySelectorAll('tr')).slice(2)
const desc = header.classList.contains('ascending')
const body = rows[0].parentElement
Expand Down Expand Up @@ -291,22 +295,39 @@ function sortTable(e) {
header.classList.add(desc ? 'descending' : 'ascending')
}

function toggleCollapseColumn(e) {
if (updateInProgress)
return

const columnName = e.currentTarget.parentElement.dataset.column
const collapsed = (tableEl.dataset.collapse ?? '').trim().split(' ').filter(Boolean)

if (collapsed.includes(columnName)) {
collapsed.splice(collapsed.indexOf(columnName), 1)
} else {
collapsed.push(columnName)
}

tableEl.dataset.collapse = collapsed.join(' ')
localStorage.setItem('collapsedColumns', tableEl.dataset.collapse)
}

function fillRow(row, tag, sc, maxArgs) {
const ndec = document.createElement('td')
const nhex = document.createElement('td')
const name = document.createElement('td')
const sym = document.createElement('td')
const loc = document.createElement('td')
const kcfg = document.createElement('td')
let argsLeft = compactSignature ? 0 : sc.signature?.length ? maxArgs - sc.signature?.length : maxArgs;
const cells = [
document.createElement('td'), document.createElement('td'),
document.createElement('td'), document.createElement('td'),
document.createElement('td'), document.createElement('td')
]
const [ndec, nhex, name, sym, loc, kcfg] = cells
let argsLeft = compactSignature ? 0 : sc.signature?.length ? maxArgs - sc.signature?.length : maxArgs

row.addEventListener('click', highlightRow)
row.appendChild(ndec)
row.appendChild(nhex)
row.appendChild(name)
row.appendChild(sym)
row.appendChild(loc)
row.appendChild(kcfg)
cells.forEach(el => row.appendChild(el))

name.dataset.column = 'name'
sym.dataset.column = 'symbol'
loc.dataset.column = 'location'
kcfg.dataset.column = 'kconfig'

ndec.textContent = sc.number
nhex.textContent = `0x${sc.number.toString(16)}`
Expand Down Expand Up @@ -355,11 +376,13 @@ function fillRow(row, tag, sc, maxArgs) {
const sig = document.createElement('td')
sig.textContent = 'unknown signature'
sig.classList.add('unknown')
sig.dataset.column = 'signature'
row.appendChild(sig)
argsLeft--
} else if (compactSignature) {
// Compact signature: single column containing comma-separated args
const sig = document.createElement('td')
sig.dataset.column = 'signature'
row.appendChild(sig)

if (sc.signature.length > 0) {
Expand Down Expand Up @@ -408,13 +431,17 @@ function fillRow(row, tag, sc, maxArgs) {
td.appendChild(name)
}

td.dataset.column = 'signature'
row.appendChild(td)
}
}

// Append multiple <td> elements to be able to style column borders
for (let i = 0; i < argsLeft; i++)
row.appendChild(document.createElement('td'))
for (let i = 0; i < argsLeft; i++) {
const td = document.createElement('td')
td.dataset.column = 'signature'
row.appendChild(td)
}
}

function fillTable(syscallTable, tag) {
Expand All @@ -423,7 +450,7 @@ function fillTable(syscallTable, tag) {
const maxArgs = syscallTable.syscalls.reduce((acc, sc) => Math.max(acc, sc.signature?.length || 0), 0)
const [header1, header2] = tableEl.querySelectorAll('tr')

compactSigToggleEl.textContent = compactSignature ? 'expand' : 'collapse'
compactSigToggleEl.textContent = compactSignature ? 'compact' : 'extended'
header1.children[1].colSpan = maxArgs
header2.children[0].textContent = `Number${numReg ? '\u00a0(' + numReg + ')' : ''}`

Expand All @@ -434,7 +461,11 @@ function fillTable(syscallTable, tag) {
if (compactSignature) {
// Compact signature: single column containing comma-separated args
const th = document.createElement('th')
th.textContent = `Arguments (${argRegs.join(', ')})`
const title = document.createElement('span')
title.classList.add('collapsible')
title.textContent = `Arguments (${argRegs.join(', ')})`
th.dataset.column = 'signature'
th.appendChild(title)
header2.appendChild(th)
} else {
// Expanded signature: one column per argument
Expand All @@ -443,7 +474,11 @@ function fillTable(syscallTable, tag) {
// that should never happen (why publish such a table to begin with?).
for (let i = 0; i < maxArgs; i++) {
const th = document.createElement('th')
th.textContent = `Arg\u00a0${i + 1}\u00a0(${argRegs[i]})`
const title = document.createElement('span')
title.classList.add('collapsible')
title.textContent = `Arg\u00a0${i + 1}\u00a0(${argRegs[i]})`
th.dataset.column = 'signature'
th.appendChild(title)
header2.appendChild(th)
}
}
Expand All @@ -459,7 +494,6 @@ function fillTable(syscallTable, tag) {
tableEl.appendChild(row)
}

tableEl.querySelectorAll('th.sortable').forEach(el => el.addEventListener('click', sortTable))
document.getElementById('container').classList.remove('invisible')
document.getElementById('loading').classList.add('invisible')
}
Expand All @@ -468,10 +502,10 @@ function toggleCompactSignature() {
if (updateInProgress)
return

// Could be optimized... but I could also not care less for now
const tag = getSelection().pop()
compactSignature = !compactSignature
localStorage.setItem('compactSignature', compactSignature)
// Could be optimized... but I could also not care less for now
fillTable(currentSyscallTable, tag)
}

Expand Down Expand Up @@ -562,12 +596,17 @@ function toggleTheme() {
}

function restoreSettings() {
let theme = localStorage.getItem('theme')
/* This one is global */
compactSignature = localStorage.getItem('compactSignature') === 'true'

let theme = localStorage.getItem('theme')
if (!theme)
theme = window.matchMedia?.('(prefers-color-scheme: dark)')?.matches ? 'dark' : 'light';

const collapsedColumns = localStorage.getItem('collapsedColumns')
if (collapsedColumns)
tableEl.dataset.collapse = collapsedColumns

setTheme(theme)
}

Expand Down Expand Up @@ -605,6 +644,8 @@ async function setup() {
tagSelectEl.addEventListener('change', tagSelectChangeHandler)
themeToggleEl.addEventListener('click', toggleTheme)
compactSigToggleEl.addEventListener('click', toggleCompactSignature)
tableEl.querySelectorAll('th.sortable').forEach(el => el.addEventListener('click', sortTable))
tableEl.querySelectorAll('th > .collapse-toggle').forEach(el => el.addEventListener('click', toggleCollapseColumn))
window.addEventListener('popstate', historyPopStateHandler)
}

Expand Down

0 comments on commit 52b4fef

Please sign in to comment.