|
| 1 | +import { list, mount, patch, createBlock, withKey } from 'blockdom'; |
| 2 | + |
| 3 | +let idCounter = 1; |
| 4 | +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"], |
| 5 | + colours = ["red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black", "orange"], |
| 6 | + nouns = ["table", "chair", "house", "bbq", "desk", "car", "pony", "cookie", "sandwich", "burger", "pizza", "mouse", "keyboard"]; |
| 7 | + |
| 8 | +function _random(max) { return Math.round(Math.random() * 1000) % max; }; |
| 9 | + |
| 10 | +function buildData(count) { |
| 11 | + let data = new Array(count); |
| 12 | + for (let i = 0; i < count; i++) { |
| 13 | + const label = `${adjectives[_random(adjectives.length)]} ${colours[_random(colours.length)]} ${nouns[_random(nouns.length)]}`; |
| 14 | + data[i] = { |
| 15 | + id: idCounter++, |
| 16 | + label, |
| 17 | + } |
| 18 | + } |
| 19 | + return data; |
| 20 | +} |
| 21 | + |
| 22 | +function createStore(onUpdate) { |
| 23 | + let rows = []; |
| 24 | + let selectedRowId = null; |
| 25 | + |
| 26 | + return { |
| 27 | + get rows() { return rows }, |
| 28 | + get selectedRowId() { return selectedRowId }, |
| 29 | + run() { |
| 30 | + rows = buildData(1000); |
| 31 | + selectedRowId = null; |
| 32 | + onUpdate(); |
| 33 | + }, |
| 34 | + runLots() { |
| 35 | + rows = buildData(10000); |
| 36 | + selectedRowId = null; |
| 37 | + onUpdate() |
| 38 | + }, |
| 39 | + add() { |
| 40 | + rows = rows.concat(buildData(1000)); |
| 41 | + onUpdate() |
| 42 | + }, |
| 43 | + update() { |
| 44 | + let index = 0; |
| 45 | + while (index < rows.length) { |
| 46 | + rows[index].label = rows[index].label + " !!!"; |
| 47 | + index += 10; |
| 48 | + } |
| 49 | + onUpdate() |
| 50 | + }, |
| 51 | + clear() { |
| 52 | + rows = []; |
| 53 | + selectedRowId = null; |
| 54 | + onUpdate() |
| 55 | + }, |
| 56 | + swapRows() { |
| 57 | + if (rows.length > 998) { |
| 58 | + let tmp = rows[1]; |
| 59 | + rows[1] = rows[998]; |
| 60 | + rows[998] = tmp; |
| 61 | + } |
| 62 | + onUpdate() |
| 63 | + }, |
| 64 | + selectRow(id) { |
| 65 | + selectedRowId = id; |
| 66 | + onUpdate() |
| 67 | + }, |
| 68 | + removeRow(id) { |
| 69 | + rows.splice(rows.findIndex(row => row.id === id), 1); |
| 70 | + onUpdate() |
| 71 | + } |
| 72 | + } |
| 73 | +} |
| 74 | + |
| 75 | +// --------------------------------------------------------------------------- |
| 76 | + |
| 77 | +const rowBlock = createBlock(` |
| 78 | + <tr block-attribute-2="class"> |
| 79 | + <td class="col-md-1"><block-text-0/></td> |
| 80 | + <td class="col-md-4"> |
| 81 | + <a block-handler-3="click"><block-text-1/></a> |
| 82 | + </td> |
| 83 | + <td class="col-md-1"> |
| 84 | + <a block-handler-4="click"> |
| 85 | + <span class='glyphicon glyphicon-remove' aria-hidden="true" /> |
| 86 | + </a> |
| 87 | + </td> |
| 88 | + <td class='col-md-6'/> |
| 89 | + </tr>`); |
| 90 | + |
| 91 | +const mainBlock = createBlock(` |
| 92 | + <div class='container'> |
| 93 | + <div class='jumbotron'> |
| 94 | + <div class='row'> |
| 95 | + <div class='col-md-6'> |
| 96 | + <h1>blockdom keyed</h1> |
| 97 | + </div> |
| 98 | + <div class='col-md-6'> |
| 99 | + <div class='row'> |
| 100 | + <div class="col-sm-6 smallpad"> |
| 101 | + <button type="button" class="btn btn-primary btn-block" id="run" block-handler-0="click">Create 1,000 rows</button> |
| 102 | + </div> |
| 103 | + <div class="col-sm-6 smallpad"> |
| 104 | + <button type="button" class="btn btn-primary btn-block" id="runlots" block-handler-1="click">Create 10,000 rows</button> |
| 105 | + </div> |
| 106 | + <div class="col-sm-6 smallpad"> |
| 107 | + <button type="button" class="btn btn-primary btn-block" id="add" block-handler-2="click">Append 1,000 rows</button> |
| 108 | + </div> |
| 109 | + <div class="col-sm-6 smallpad"> |
| 110 | + <button type="button" class="btn btn-primary btn-block" id="update" block-handler-3="click">Update every 10th row</button> |
| 111 | + </div> |
| 112 | + <div class="col-sm-6 smallpad"> |
| 113 | + <button type="button" class="btn btn-primary btn-block" id="clear" block-handler-4="click">Clear</button> |
| 114 | + </div> |
| 115 | + <div class="col-sm-6 smallpad"> |
| 116 | + <button type="button" class="btn btn-primary btn-block" id="swaprows" block-handler-5="click">Swap Rows</button> |
| 117 | + </div> |
| 118 | + </div> |
| 119 | + </div> |
| 120 | + </div> |
| 121 | + </div> |
| 122 | + <table class='table table-hover table-striped test-data'> |
| 123 | + <tbody> |
| 124 | + <block-child-0/> |
| 125 | + </tbody> |
| 126 | + </table> |
| 127 | + <span class='preloadicon glyphicon glyphicon-remove' aria-hidden="true" /> |
| 128 | + </div>`); |
| 129 | + |
| 130 | +// --------------------------------------------------------------------------- |
| 131 | + |
| 132 | +function render(store, cache, nextCache) { |
| 133 | + const data = [store.run, store.runLots, store.add, store.update, store.clear, store.swapRows]; |
| 134 | + let { rows, selectedRowId } = store; |
| 135 | + |
| 136 | + return mainBlock(data, [list(rows.map(row => { |
| 137 | + const isSelected = row.id === selectedRowId; |
| 138 | + const elem = cache[row.id] |
| 139 | + if (elem) { |
| 140 | + if (elem.memo[0] === row.label && elem.memo[1] === isSelected) { |
| 141 | + return (nextCache[row.id] = elem); |
| 142 | + } |
| 143 | + } |
| 144 | + const result = rowBlock([ |
| 145 | + row.id, |
| 146 | + row.label, |
| 147 | + isSelected ? "danger" : "", |
| 148 | + [store.selectRow, row.id], |
| 149 | + [store.removeRow, row.id], |
| 150 | + ]); |
| 151 | + result.memo = [row.label, isSelected]; |
| 152 | + nextCache[row.id] = result; |
| 153 | + return withKey(result, row.id); |
| 154 | + }))]) |
| 155 | +} |
| 156 | + |
| 157 | +// --------------------------------------------------------------------------- |
| 158 | + |
| 159 | +const store = createStore(update); |
| 160 | + |
| 161 | +let cache = {}; |
| 162 | +let app = render(store, {}, cache); |
| 163 | +mount(app, document.body); |
| 164 | + |
| 165 | +function update() { |
| 166 | + let nextCache = {}; |
| 167 | + patch(app, render(store, cache, nextCache)); |
| 168 | + cache = nextCache; |
| 169 | +} |
| 170 | + |
0 commit comments