|
| 1 | +const adjectives = ['pretty', 'large', 'big', 'small', 'tall', 'short', 'long', 'handsome', 'plain', 'quaint', 'clean', 'elegant', 'easy', 'angry', 'crazy', 'helpful', 'mushy', 'odd', 'unsightly', 'adorable', 'important', 'inexpensive', 'cheap', 'expensive', 'fancy']; |
| 2 | +const colours = ['red', 'yellow', 'blue', 'green', 'pink', 'brown', 'purple', 'brown', 'white', 'black', 'orange']; |
| 3 | +const nouns = ['table', 'chair', 'house', 'bbq', 'desk', 'car', 'pony', 'cookie', 'sandwich', 'burger', 'pizza', 'mouse', 'keyboard']; |
| 4 | + |
| 5 | +const pick = dict => dict[Math.round(Math.random() * 1000) % dict.length]; |
| 6 | + |
| 7 | +let ID = 1, rows = [], selection; |
| 8 | +const ROW = Symbol(), ACTION = Symbol(); |
| 9 | + |
| 10 | +const rowTemplate = document.querySelector('#rowTemplate').content.firstChild; |
| 11 | +const table = document.querySelector('table'); |
| 12 | +let tbody = document.querySelector('tbody'); |
| 13 | + |
| 14 | +const {cloneNode, insertBefore} = Node.prototype; |
| 15 | +const clone = (cloneNode.bind(rowTemplate, true)); |
| 16 | +const insert = ((row, before = null) => insertBefore.call(tbody, row, before)); |
| 17 | + |
| 18 | +const build = (() => { |
| 19 | + const tr = clone(); |
| 20 | + const td1 = tr.firstChild, td2 = td1.nextSibling, td3 = td2.nextSibling; |
| 21 | + const a1 = td2.firstChild, a2 = td3.firstChild; |
| 22 | + const label = `${pick(adjectives)} ${pick(colours)} ${pick(nouns)}`; |
| 23 | + td1.firstChild.nodeValue = ID++; |
| 24 | + (tr.label = a1.firstChild).nodeValue = label; |
| 25 | + a1[ACTION] = select, a2[ACTION] = remove; |
| 26 | + return insert(a1[ROW] = a2[ROW] = tr); |
| 27 | +}); |
| 28 | + |
| 29 | +const create = count => [...Array(count)].map(build); |
| 30 | + |
| 31 | +const select = (set => row => { |
| 32 | + set('remove'), selection = row, set('add'); |
| 33 | +})(setter => selection?.classList[setter]('danger')); |
| 34 | + |
| 35 | +const remove = (match => row => { |
| 36 | + rows = rows.filter(match, row), row.remove(); |
| 37 | +})(function (row) { return row !== this; }); |
| 38 | + |
| 39 | +const clear = () => { |
| 40 | + rows = [], selection = null; |
| 41 | + const clone = tbody.cloneNode(); |
| 42 | + tbody.remove(), insertBefore.call(table, tbody = clone, null); |
| 43 | +}; |
| 44 | + |
| 45 | +document.querySelectorAll('button').forEach(function (button) { |
| 46 | + button.addEventListener('click', this[button.id]); |
| 47 | +}, { |
| 48 | + run () { clear(), rows = create(1000); }, |
| 49 | + runlots () { clear(), rows = create(10000); }, |
| 50 | + add () { rows = [...rows, ...create(1000)]; }, |
| 51 | + clear, |
| 52 | + update () { |
| 53 | + for (let i = 0; i < rows.length; i += 10) |
| 54 | + rows[i].label.nodeValue += ' !!!'; |
| 55 | + }, |
| 56 | + swaprows () { |
| 57 | + if (rows.length > 998) |
| 58 | + insert(rows[1], rows[998]), insert(rows[998], rows[2]), |
| 59 | + [rows[1], rows[998]] = [rows[998], rows[1]]; |
| 60 | + } |
| 61 | +}); |
| 62 | + |
| 63 | +table.addEventListener('click', e => { |
| 64 | + let {target: t} = e; |
| 65 | + e.stopPropagation(), (t[ACTION] ?? (t = t.parentNode)[ACTION])?.(t[ROW]); |
| 66 | +}); |
| 67 | + |
0 commit comments