Skip to content

Commit 52b4fef

Browse files
committed
Allow collapsing and remember collapsed columns
1 parent caa9e87 commit 52b4fef

File tree

3 files changed

+139
-36
lines changed

3 files changed

+139
-36
lines changed

www/index.css

+69-7
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ table th {
9090
background-color: var(--table-head-bg);
9191
border-top: var(--table-cell-border);
9292
border-bottom: var(--table-cell-border);
93+
/* Avoid ugly text selection while clicking to sort/collapse */
94+
user-select: none;
95+
-moz-user-select: none;
96+
-webkit-user-select: none;
97+
-ms-user-select: none;
9398
}
9499

95100
table th.pad {
@@ -133,28 +138,70 @@ table span.argtype {
133138
display: none;
134139
}
135140

136-
.fakelink {
137-
text-decoration: underline;
138-
cursor: pointer;
139-
}
140-
141141
table td.unknown {
142142
font-family: sans-serif;
143143
font-style: italic;
144144
}
145145

146-
table th.ascending::before, table th.descending::before, table td.bad::after, table td.esoteric::after {
147-
font-family: 'Noto Color Emoji';
146+
#compact-sig-toggle {
147+
text-decoration: underline;
148+
}
149+
150+
#compact-sig-toggle::before { display: inline-block; content: '['; }
151+
#compact-sig-toggle::after { display: inline-block; content: ']'; }
152+
153+
/* Collapse columns through CSS trickery so that JS only has to add/remove words
154+
* from the table's data-collapse attribute. */
155+
156+
table th > .collapse-toggle::before {
157+
content: '[-]';
158+
}
159+
160+
/* Show [+] instead of [-] for collapsed columns */
161+
table[data-collapse~="name"] th[data-column="name"] > .collapse-toggle::before,
162+
table[data-collapse~="symbol"] th[data-column="symbol"] > .collapse-toggle::before,
163+
table[data-collapse~="location"] th[data-column="location"] > .collapse-toggle::before,
164+
table[data-collapse~="kconfig"] th[data-column="kconfig"] > .collapse-toggle::before,
165+
table[data-collapse~="signature"] th[data-column="signature"] > .collapse-toggle::before {
166+
content: '[+]';
167+
}
168+
169+
/* No column title for collapsed columns, just the toggle */
170+
table[data-collapse~="name"] th[data-column="name"] > .collapsible,
171+
table[data-collapse~="symbol"] th[data-column="symbol"] > .collapsible,
172+
table[data-collapse~="location"] th[data-column="location"] > .collapsible,
173+
table[data-collapse~="kconfig"] th[data-column="kconfig"] > .collapsible,
174+
table[data-collapse~="signature"] th[data-column="signature"] > .collapsible {
175+
display: none;
176+
}
177+
178+
/* Hide the content of collapsed columns */
179+
table[data-collapse~="name"] td[data-column="name"],
180+
table[data-collapse~="symbol"] td[data-column="symbol"],
181+
table[data-collapse~="location"] td[data-column="location"],
182+
table[data-collapse~="kconfig"] td[data-column="kconfig"],
183+
table[data-collapse~="signature"] td[data-column="signature"] {
184+
overflow: hidden;
185+
white-space: nowrap;
186+
text-overflow: ellipsis;
187+
max-width: 0px;
188+
opacity: 0.5;
148189
}
149190

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

194+
table th.ascending::before, table th.descending::before, table td.bad::after, table td.esoteric::after {
195+
font-family: 'Noto Color Emoji';
196+
}
197+
153198
table th.ascending::before { content: '\2b07\fe0f\202f'; }
154199
table th.descending::before { content: '\2b06\fe0f\202f'; }
155200
table td.bad::after { content: '\2002\26a0\fe0f'; }
156201
table td.esoteric::after { content: '\2002\1f984\fe0f'; }
157202

203+
/* Hover effects */
204+
158205
@media (any-hover: hover) {
159206
table th.sortable:hover {
160207
cursor: pointer;
@@ -168,4 +215,19 @@ table td.esoteric::after { content: '\2002\1f984\fe0f'; }
168215
table a:hover {
169216
text-decoration: underline;
170217
}
218+
219+
table .collapse-toggle:hover {
220+
cursor: pointer;
221+
text-shadow: 0px 0px 3px var(--main-fg);
222+
}
223+
224+
#compact-sig-toggle:hover {
225+
cursor: pointer;
226+
}
227+
228+
#compact-sig-toggle:hover::before,
229+
#compact-sig-toggle:hover::after {
230+
text-decoration: none;
231+
text-shadow: 0px 0px 3px var(--main-fg);
232+
}
171233
}

www/index.html

+6-6
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ <h3>
3737
<table>
3838
<tr>
3939
<th class="pad" colspan="6"></th>
40-
<th>Signature [<span class="fakelink" id="compact-sig-toggle"></span>]</th>
40+
<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>
4141
</tr>
4242
<tr>
43-
<th class="sortable ascending" colspan="2" title="Click to sort">Number</th>
44-
<th class="sortable" title="Click to sort">Name</th>
45-
<th class="sortable" title="Click to sort">Symbol</th>
46-
<th class="sortable" title="Click to sort">Definition location</th>
47-
<th class="sortable" title="Click to sort">Kconfig</th>
43+
<th class="sortable ascending" colspan="2" title="Click to sort by this column">Number</th>
44+
<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>
45+
<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>
46+
<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>
47+
<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>
4848
</tr>
4949
</table>
5050
<h3 id="summary"></h3>

www/index.js

+64-23
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,12 @@ function sortTable(e) {
259259
if (updateInProgress)
260260
return
261261

262-
const header = e.target
263-
const idx = Array.from(header.parentNode.children).indexOf(e.target)
262+
// Ignore click on the collapse toggle inside the <th>
263+
if (e.target.classList.contains('collapse-toggle'))
264+
return
265+
266+
const header = e.currentTarget
267+
const idx = Array.from(header.parentNode.children).indexOf(e.currentTarget)
264268
const rows = Array.from(tableEl.querySelectorAll('tr')).slice(2)
265269
const desc = header.classList.contains('ascending')
266270
const body = rows[0].parentElement
@@ -291,22 +295,39 @@ function sortTable(e) {
291295
header.classList.add(desc ? 'descending' : 'ascending')
292296
}
293297

298+
function toggleCollapseColumn(e) {
299+
if (updateInProgress)
300+
return
301+
302+
const columnName = e.currentTarget.parentElement.dataset.column
303+
const collapsed = (tableEl.dataset.collapse ?? '').trim().split(' ').filter(Boolean)
304+
305+
if (collapsed.includes(columnName)) {
306+
collapsed.splice(collapsed.indexOf(columnName), 1)
307+
} else {
308+
collapsed.push(columnName)
309+
}
310+
311+
tableEl.dataset.collapse = collapsed.join(' ')
312+
localStorage.setItem('collapsedColumns', tableEl.dataset.collapse)
313+
}
314+
294315
function fillRow(row, tag, sc, maxArgs) {
295-
const ndec = document.createElement('td')
296-
const nhex = document.createElement('td')
297-
const name = document.createElement('td')
298-
const sym = document.createElement('td')
299-
const loc = document.createElement('td')
300-
const kcfg = document.createElement('td')
301-
let argsLeft = compactSignature ? 0 : sc.signature?.length ? maxArgs - sc.signature?.length : maxArgs;
316+
const cells = [
317+
document.createElement('td'), document.createElement('td'),
318+
document.createElement('td'), document.createElement('td'),
319+
document.createElement('td'), document.createElement('td')
320+
]
321+
const [ndec, nhex, name, sym, loc, kcfg] = cells
322+
let argsLeft = compactSignature ? 0 : sc.signature?.length ? maxArgs - sc.signature?.length : maxArgs
302323

303324
row.addEventListener('click', highlightRow)
304-
row.appendChild(ndec)
305-
row.appendChild(nhex)
306-
row.appendChild(name)
307-
row.appendChild(sym)
308-
row.appendChild(loc)
309-
row.appendChild(kcfg)
325+
cells.forEach(el => row.appendChild(el))
326+
327+
name.dataset.column = 'name'
328+
sym.dataset.column = 'symbol'
329+
loc.dataset.column = 'location'
330+
kcfg.dataset.column = 'kconfig'
310331

311332
ndec.textContent = sc.number
312333
nhex.textContent = `0x${sc.number.toString(16)}`
@@ -355,11 +376,13 @@ function fillRow(row, tag, sc, maxArgs) {
355376
const sig = document.createElement('td')
356377
sig.textContent = 'unknown signature'
357378
sig.classList.add('unknown')
379+
sig.dataset.column = 'signature'
358380
row.appendChild(sig)
359381
argsLeft--
360382
} else if (compactSignature) {
361383
// Compact signature: single column containing comma-separated args
362384
const sig = document.createElement('td')
385+
sig.dataset.column = 'signature'
363386
row.appendChild(sig)
364387

365388
if (sc.signature.length > 0) {
@@ -408,13 +431,17 @@ function fillRow(row, tag, sc, maxArgs) {
408431
td.appendChild(name)
409432
}
410433

434+
td.dataset.column = 'signature'
411435
row.appendChild(td)
412436
}
413437
}
414438

415439
// Append multiple <td> elements to be able to style column borders
416-
for (let i = 0; i < argsLeft; i++)
417-
row.appendChild(document.createElement('td'))
440+
for (let i = 0; i < argsLeft; i++) {
441+
const td = document.createElement('td')
442+
td.dataset.column = 'signature'
443+
row.appendChild(td)
444+
}
418445
}
419446

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

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

@@ -434,7 +461,11 @@ function fillTable(syscallTable, tag) {
434461
if (compactSignature) {
435462
// Compact signature: single column containing comma-separated args
436463
const th = document.createElement('th')
437-
th.textContent = `Arguments (${argRegs.join(', ')})`
464+
const title = document.createElement('span')
465+
title.classList.add('collapsible')
466+
title.textContent = `Arguments (${argRegs.join(', ')})`
467+
th.dataset.column = 'signature'
468+
th.appendChild(title)
438469
header2.appendChild(th)
439470
} else {
440471
// Expanded signature: one column per argument
@@ -443,7 +474,11 @@ function fillTable(syscallTable, tag) {
443474
// that should never happen (why publish such a table to begin with?).
444475
for (let i = 0; i < maxArgs; i++) {
445476
const th = document.createElement('th')
446-
th.textContent = `Arg\u00a0${i + 1}\u00a0(${argRegs[i]})`
477+
const title = document.createElement('span')
478+
title.classList.add('collapsible')
479+
title.textContent = `Arg\u00a0${i + 1}\u00a0(${argRegs[i]})`
480+
th.dataset.column = 'signature'
481+
th.appendChild(title)
447482
header2.appendChild(th)
448483
}
449484
}
@@ -459,7 +494,6 @@ function fillTable(syscallTable, tag) {
459494
tableEl.appendChild(row)
460495
}
461496

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

471-
// Could be optimized... but I could also not care less for now
472505
const tag = getSelection().pop()
473506
compactSignature = !compactSignature
474507
localStorage.setItem('compactSignature', compactSignature)
508+
// Could be optimized... but I could also not care less for now
475509
fillTable(currentSyscallTable, tag)
476510
}
477511

@@ -562,12 +596,17 @@ function toggleTheme() {
562596
}
563597

564598
function restoreSettings() {
565-
let theme = localStorage.getItem('theme')
599+
/* This one is global */
566600
compactSignature = localStorage.getItem('compactSignature') === 'true'
567601

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

606+
const collapsedColumns = localStorage.getItem('collapsedColumns')
607+
if (collapsedColumns)
608+
tableEl.dataset.collapse = collapsedColumns
609+
571610
setTheme(theme)
572611
}
573612

@@ -605,6 +644,8 @@ async function setup() {
605644
tagSelectEl.addEventListener('change', tagSelectChangeHandler)
606645
themeToggleEl.addEventListener('click', toggleTheme)
607646
compactSigToggleEl.addEventListener('click', toggleCompactSignature)
647+
tableEl.querySelectorAll('th.sortable').forEach(el => el.addEventListener('click', sortTable))
648+
tableEl.querySelectorAll('th > .collapse-toggle').forEach(el => el.addEventListener('click', toggleCollapseColumn))
608649
window.addEventListener('popstate', historyPopStateHandler)
609650
}
610651

0 commit comments

Comments
 (0)