I am writing a plugin for Obsidian (using their API), hoping to achieve wiki-like table sorting, i.e. clickable headers that can sort the table in ascending (1st click), then descending (2nd click), then finally restoring the original order (3rd click).
I wrote the following code that registers a click DOM event with a callback that checks whether the click was performed inside a table and if so, it sorts the table, essentially by reordering tr elements. However, I am not sure how to restore the table to the original state on the third click.
this.registerDomEvent(document, 'click', (evt: MouseEvent) => {
const htmlEl = (<HTMLInputElement>evt.target);
const th = htmlEl.closest('thead th');
if (th == null) { return; }
const table = htmlEl.closest('table');
const tbody = table.querySelector('tbody');
const thArray = Array.from(th.parentNode.children);
const thIdx = thArray.indexOf(th);
// all other th's are reset
thArray.forEach((th, i) => {
if (i != thIdx) {
th.removeAttribute("class");
}
});
// set clicked th class
th.className = this.classNames[
(this.classNames.indexOf(th.className) + 1) % this.classNames.length
];
const ascending = th.className === "header-sort-up";
Array.from(tbody.querySelectorAll('tr:nth-child(n)'))
.sort(this.compareFn(thIdx, ascending))
.forEach(tr => tbody.appendChild(tr));
});
One idea I had was to make use of the localStorage to store the original innerHTML of the table, but I think this will not scale well for persistent, long-term usage, and lots of tables. Moreover, I don't want to add extra dependencies, if possible.