Last active
April 1, 2019 22:02
-
-
Save davismj/1aa5983bde49715e95174211fa5ce174 to your computer and use it in GitHub Desktop.
Table example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<require from="fancy-table.css"></require> | |
<require from="table-custom-element"></require> | |
<require from="value-converters"></require> | |
<require from="sortable-custom-attribute"></require> | |
<require from="reorderable-custom-attribute"></require> | |
<require from="resizable-custom-attribute"></require> | |
<require from="table-custom-element"></require> | |
<require from="row-custom-element"></require> | |
<style> | |
table { width: 100%; table-layout: fixed; } | |
.align-right { text-align: right; } | |
.align-center { text-align: center; } | |
.actions { margin-bottom: 0.5em; } | |
.action { cursor: pointer; } | |
.button { border: 1px solid; margin: 0.25em; padding: 0.25em; cursor: pointer; } | |
.button.active { background: skyblue; } | |
/*.arrow::after { content: "►"; }*/ | |
.rotate { display: inline-block; transition: transform 0.25s ease-in-out } | |
.rotate.ninety { transform: rotate(90deg); } | |
</style> | |
<compose view="details.html"></compose> | |
<!--<div class="actions">--> | |
<!-- <button click.delegate="increaseProfitByFactor(2)">double profits</button>--> | |
<!-- <button click.delegate="increaseProfitByFactor(0.5)">halve profits</button>--> | |
<!--</div>--> | |
<!--<div class="filters"></div>--> | |
<!-- | |
Selectable adds checkboxes. | |
All columns are resizable, reodrerable by default. | |
resizable="false", reorderable="false" to opt out | |
paged adds $page, paged="5" sets the page size | |
--> | |
<!--<ess-table selectable paged sort-change.delegate="updateSort($event.detail)">--> | |
<table mousedown.delegate="startResize($event)" mousemove.delegate="resize($event)"> | |
<thead><tr sort-change.delegate="updateSort($event.detail)"> | |
<td style="width: 24px;"><!-- expand --></td> | |
<td style="width: 24px;"> | |
<input type="checkbox" change.delegate="toggleAll()" element.ref="allCheckbox" /> | |
</td> | |
<th sortable="name" resizable reorderable>Name</th> | |
<th sortable="industry" resizable reorderable>Industry</th> | |
<th sortable="revenue" resizable reorderable>Revenue</th> | |
<th sortable="profit" resizable reorderable>Profit</th> | |
<th sortable="employees" resizable reorderable>Employees</th> | |
<td><!-- actions --></td> | |
</tr></thead> | |
<template repeat.for="company of data"> | |
<tr class="row"> | |
<td class="action"> | |
<i class="arrow rotate ${expanded ? 'ninety' : ''}" click.delegate="expanded = !expanded">►</i> | |
</td> | |
<td> | |
<input type="checkbox" checked.bind="selected" model.bind="company" change.delegate="toggleCheckbox()" /> | |
</td> | |
<td>${company.name}</td> | |
<td>${company.industry}</td> | |
<td class="align-right">${company.revenue | cash}</td> | |
<td class="align-right">${company.profit | cash}</td> | |
<td class="align-right">${company.employees | integer}</td> | |
<td> | |
<a class="action">save</a> | |
<a class="action">delete</a> | |
<a class="action">edit</a> | |
</td> | |
</tr> | |
<tr if.bind="expanded"> | |
<td></td> | |
<td colspan="6"> | |
<table class="table" style="width: 100%"> | |
<tr> | |
<th>Name again</th> | |
<th>More profits</th> | |
</tr> | |
<tr class="row" repeat.for="i of 2"> | |
<td>${company.name} again</td> | |
<td>${company.profit * (i + 0.5) | cash}</td> | |
</tr> | |
</table> | |
</td> | |
</tr> | |
</template> | |
</table> | |
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const DATA = [{"id":1,"name":"Great Haperdohl LLC","industry":"Energy","revenue":7463223593,"profit":285235056,"employees":4538421,"stockType":"Private"},{"id":2,"name":"Flaberdune Cartel","industry":"Healthcare","revenue":8247505676,"profit":459460530,"employees":6258914,"stockType":"Public"},{"id":3,"name":"Ittabito LLC","industry":"Retail","revenue":1114822061,"profit":79793676,"employees":1069455,"stockType":"Public"},{"id":4,"name":"Mangus Company","industry":"Professional Services","revenue":8340589421,"profit":771667109,"employees":694463,"stockType":"Public"},{"id":5,"name":"Big Haperdohl Inc","industry":"Energy","revenue":490059500,"profit":-42947038,"employees":350512,"stockType":"Private"},{"id":6,"name":"Peders and Niptune GmbH","industry":"Professional Services","revenue":162387372,"profit":8181461,"employees":121730,"stockType":"Public"},{"id":7,"name":"Big Kantorset LLP","industry":"Energy","revenue":4055472550,"profit":75701215,"employees":2790938,"stockType":"Private"},{"id":8,"name":"The Mangus Company","industry":"Healthcare","revenue":373545503,"profit":30470421,"employees":331892,"stockType":"Private"},{"id":9,"name":"Frick, Hangdi, and Xu Company","industry":"Healthcare","revenue":9805204865,"profit":643754088,"employees":1149239,"stockType":"Private"},{"id":10,"name":"Flaberdune Cartel","industry":"Professional Services","revenue":4249188928,"profit":354068669,"employees":3843675,"stockType":"Private"},{"id":11,"name":"Silamoon LLC","industry":"Healthcare","revenue":3421276636,"profit":148162077,"employees":321634,"stockType":"Private"},{"id":12,"name":"Mots and Pots Inc","industry":"Professional Services","revenue":4340435672,"profit":-114223324,"employees":4043964,"stockType":"Public"},{"id":13,"name":"Wat Mangus Cartel","industry":"Retail","revenue":3339881999,"profit":-22380287,"employees":1206667,"stockType":"Private"},{"id":14,"name":"Oranges Mangus LLC","industry":"Energy","revenue":6286356219,"profit":-351413220,"employees":131026,"stockType":"Private"},{"id":15,"name":"Getchoo LLC","industry":"Technology","revenue":7678922123,"profit":136010373,"employees":279408,"stockType":"Public"},{"id":16,"name":"Rapsure GmbH","industry":"Finance","revenue":698889498,"profit":10756224,"employees":526695,"stockType":"Public"},{"id":17,"name":"Candzer GmbH","industry":"Retail","revenue":120560040,"profit":-8007905,"employees":82564,"stockType":"Private"},{"id":18,"name":"Frick, Hangdi, and Xu Company","industry":"Energy","revenue":2371535427,"profit":-112806171,"employees":938876,"stockType":"Private"},{"id":19,"name":"Ittabito Inc","industry":"Energy","revenue":2144384009,"profit":-117252392,"employees":1129640,"stockType":"Private"},{"id":20,"name":"Peders and Niptune LLC","industry":"Healthcare","revenue":7303398308,"profit":129639389,"employees":2240585,"stockType":"Private"},{"id":21,"name":"Great Cangrue Inc","industry":"Technology","revenue":3636652542,"profit":-44434312,"employees":1022928,"stockType":"Public"},{"id":22,"name":"Mangus GmbH","industry":"Technology","revenue":2900647213,"profit":-237141150,"employees":1702733,"stockType":"Public"},{"id":23,"name":"Zimmerman Company","industry":"Finance","revenue":1001198218,"profit":-85353111,"employees":352132,"stockType":"Public"},{"id":24,"name":"Womp Company","industry":"Healthcare","revenue":3438414715,"profit":-322919836,"employees":2461858,"stockType":"Private"},{"id":25,"name":"Floor So Clean Cartel","industry":"Energy","revenue":4238467958,"profit":138732159,"employees":156166,"stockType":"Private"},{"id":26,"name":"Zimmerman Inc","industry":"Professional Services","revenue":7357175505,"profit":287755105,"employees":5676009,"stockType":"Public"},{"id":27,"name":"Big Womp LLC","industry":"Professional Services","revenue":4771430545,"profit":304224653,"employees":4427484,"stockType":"Public"},{"id":28,"name":"Ignis Pati LLC","industry":"Finance","revenue":9941703051,"profit":616489181,"employees":2498462,"stockType":"Public"},{"id":29,"name":"Wat Ignis Pati GmbH","industry":"Professional Services","revenue":174481683,"profit":-13104758,"employees":151642,"stockType":"Private"},{"id":30,"name":"Floor So Clean Company","industry":"Retail","revenue":9649291625,"profit":-131008101,"employees":8204372,"stockType":"Public"},{"id":31,"name":"Getchoo Company","industry":"Retail","revenue":4451349341,"profit":-52022004,"employees":2406274,"stockType":"Public"},{"id":32,"name":"The Kantorset LLC","industry":"Healthcare","revenue":3888584251,"profit":-71043859,"employees":1820945,"stockType":"Public"},{"id":33,"name":"Big Frick, Hangdi, and Xu Inc","industry":"Technology","revenue":604589367,"profit":53479734,"employees":428306,"stockType":"Private"},{"id":34,"name":"Hearty GmbH","industry":"Finance","revenue":8106593659,"profit":128248000,"employees":5038297,"stockType":"Public"},{"id":35,"name":"Haperdohl Inc","industry":"Energy","revenue":3297825689,"profit":640745,"employees":2873213,"stockType":"Private"},{"id":36,"name":"Silamoon LLC","industry":"Healthcare","revenue":5392488359,"profit":330650370,"employees":3306660,"stockType":"Private"},{"id":37,"name":"Piperdoodle LLP","industry":"Finance","revenue":7296209823,"profit":-538813402,"employees":174872,"stockType":"Private"},{"id":38,"name":"Great Silamoon GmbH","industry":"Retail","revenue":6231676938,"profit":247010311,"employees":2656258,"stockType":"Public"},{"id":39,"name":"Candzer Company","industry":"Finance","revenue":9410542678,"profit":-331736614,"employees":2776780,"stockType":"Public"},{"id":40,"name":"Getchoo Company","industry":"Finance","revenue":9792999127,"profit":569734102,"employees":7281382,"stockType":"Private"},{"id":41,"name":"Wat Getchoo Company","industry":"Energy","revenue":3299755916,"profit":-128685420,"employees":161743,"stockType":"Public"},{"id":42,"name":"The King Fantastic LLP","industry":"Healthcare","revenue":7572331205,"profit":105483529,"employees":1074510,"stockType":"Private"},{"id":43,"name":"The King Fantastic Cartel","industry":"Energy","revenue":8022791039,"profit":-633801512,"employees":494130,"stockType":"Private"},{"id":44,"name":"Great Cangrue Company","industry":"Healthcare","revenue":7510077193,"profit":160131345,"employees":3076648,"stockType":"Public"},{"id":45,"name":"Silamoon GmbH","industry":"Finance","revenue":5305266880,"profit":213164715,"employees":419699,"stockType":"Private"},{"id":46,"name":"Hearty LLP","industry":"Retail","revenue":6728822897,"profit":495128896,"employees":2374175,"stockType":"Public"},{"id":47,"name":"Great Cangrue GmbH","industry":"Professional Services","revenue":2422821081,"profit":-16366750,"employees":1245701,"stockType":"Private"},{"id":48,"name":"Zimmerman Inc","industry":"Energy","revenue":1703558834,"profit":-120234329,"employees":803013,"stockType":"Public"},{"id":49,"name":"Big Silamoon GmbH","industry":"Retail","revenue":9170148057,"profit":-458072837,"employees":4456824,"stockType":"Public"},{"id":50,"name":"Piperdoodle Company","industry":"Healthcare","revenue":4011156171,"profit":-135574071,"employees":2334006,"stockType":"Public"},{"id":51,"name":"Womp GmbH","industry":"Technology","revenue":4838827336,"profit":-244319393,"employees":1266332,"stockType":"Private"},{"id":52,"name":"Big Womp LLC","industry":"Energy","revenue":8832195965,"profit":147898282,"employees":4865141,"stockType":"Public"},{"id":53,"name":"Ignis Pati LLC","industry":"Healthcare","revenue":1183441467,"profit":27578833,"employees":879324,"stockType":"Public"},{"id":54,"name":"Haperdohl LLP","industry":"Professional Services","revenue":169604533,"profit":8502283,"employees":165033,"stockType":"Public"},{"id":55,"name":"King Fantastic LLP","industry":"Retail","revenue":2235648104,"profit":-132165307,"employees":685697,"stockType":"Public"},{"id":56,"name":"Flaberdune Cartel","industry":"Technology","revenue":7095514270,"profit":-679682123,"employees":1803033,"stockType":"Private"},{"id":57,"name":"King Fantastic GmbH","industry":"Technology","revenue":1956840532,"profit":180526916,"employees":1632932,"stockType":"Public"},{"id":58,"name":"Peders and Niptune LLC","industry":"Finance","revenue":842888169,"profit":53615200,"employees":203997,"stockType":"Private"},{"id":59,"name":"Mangus Company","industry":"Technology","revenue":492148100,"profit":-24071097,"employees":192729,"stockType":"Private"},{"id":60,"name":"Mangus LLC","industry":"Healthcare","revenue":7322298157,"profit":327578895,"employees":1722482,"stockType":"Private"},{"id":61,"name":"Candzer GmbH","industry":"Professional Services","revenue":5649051234,"profit":329111062,"employees":3616350,"stockType":"Private"},{"id":62,"name":"Piperdoodle Company","industry":"Professional Services","revenue":2918793589,"profit":-270705812,"employees":2471837,"stockType":"Private"},{"id":63,"name":"The Getchoo Cartel","industry":"Technology","revenue":2039084921,"profit":-159996954,"employees":175981,"stockType":"Private"},{"id":64,"name":"King Fantastic GmbH","industry":"Healthcare","revenue":7954465372,"profit":-57155707,"employees":1358609,"stockType":"Public"},{"id":65,"name":"Rapsure Cartel","industry":"Technology","revenue":132331482,"profit":1016025,"employees":132237,"stockType":"Private"},{"id":66,"name":"Getchoo LLC","industry":"Energy","revenue":8924185236,"profit":492226842,"employees":6056595,"stockType":"Public"},{"id":67,"name":"Ignis Pati LLP","industry":"Energy","revenue":2335131094,"profit":-186654888,"employees":2012776,"stockType":"Public"},{"id":68,"name":"Rapsure Inc","industry":"Technology","revenue":2960057029,"profit":262547631,"employees":94620,"stockType":"Private"},{"id":69,"name":"Flaberdune Company","industry":"Technology","revenue":4384485834,"profit":335437900,"employees":4296098,"stockType":"Private"},{"id":70,"name":"Wat Hearty Cartel","industry":"Energy","revenue":6038941840,"profit":-123289504,"employees":3607309,"stockType":"Private"},{"id":71,"name":"The Zimmerman Company","industry":"Healthcare","revenue":9818258474,"profit":790437232,"employees":512591,"stockType":"Public"},{"id":72,"name":"Wat Ittabito LLC","industry":"Finance","revenue":7574500151,"profit":172655006,"employees":2991242,"stockType":"Private"},{"id":73,"name":"Candzer LLP","industry":"Technology","revenue":9356692941,"profit":919266001,"employees":8408063,"stockType":"Private"},{"id":74,"name":"King Fantastic Company","industry":"Technology","revenue":5215405800,"profit":153687063,"employees":3845172,"stockType":"Public"},{"id":75,"name":"Ignis Pati LLC","industry":"Energy","revenue":2245136505,"profit":141471584,"employees":731537,"stockType":"Public"},{"id":76,"name":"Oranges Rapsure Inc","industry":"Energy","revenue":3942699594,"profit":132858250,"employees":3737869,"stockType":"Private"},{"id":77,"name":"Candzer Inc","industry":"Professional Services","revenue":7154405999,"profit":-434519708,"employees":5254072,"stockType":"Private"},{"id":78,"name":"Wat Haperdohl LLC","industry":"Healthcare","revenue":9796004524,"profit":580314820,"employees":1675503,"stockType":"Public"},{"id":79,"name":"Hearty LLC","industry":"Healthcare","revenue":2505779177,"profit":-71478939,"employees":283905,"stockType":"Private"},{"id":80,"name":"Zimmerman Cartel","industry":"Energy","revenue":6789437387,"profit":-424834943,"employees":4112823,"stockType":"Public"},{"id":81,"name":"Wat Getchoo GmbH","industry":"Professional Services","revenue":7994720840,"profit":547784112,"employees":7694058,"stockType":"Private"},{"id":82,"name":"Rapsure Company","industry":"Retail","revenue":5625018710,"profit":-196916829,"employees":1703942,"stockType":"Private"},{"id":83,"name":"King Fantastic LLC","industry":"Healthcare","revenue":2258164807,"profit":-78141393,"employees":1495958,"stockType":"Public"},{"id":84,"name":"Flaberdune Cartel","industry":"Finance","revenue":9965090221,"profit":-184324222,"employees":9368819,"stockType":"Private"},{"id":85,"name":"Kantorset Inc","industry":"Finance","revenue":6119440819,"profit":381614905,"employees":5906024,"stockType":"Public"},{"id":86,"name":"Kantorset Inc","industry":"Professional Services","revenue":8736268747,"profit":789782735,"employees":2892410,"stockType":"Public"},{"id":87,"name":"Peders and Niptune LLP","industry":"Professional Services","revenue":5382053789,"profit":117453642,"employees":767198,"stockType":"Public"},{"id":88,"name":"Hearty LLC","industry":"Finance","revenue":5289313634,"profit":-111456091,"employees":5270825,"stockType":"Public"},{"id":89,"name":"Floor So Clean LLC","industry":"Healthcare","revenue":5069411670,"profit":390950918,"employees":544575,"stockType":"Public"},{"id":90,"name":"Getchoo Cartel","industry":"Energy","revenue":2733883180,"profit":-173507636,"employees":867753,"stockType":"Private"},{"id":91,"name":"Silamoon Cartel","industry":"Finance","revenue":5465300140,"profit":-519423445,"employees":3417287,"stockType":"Public"},{"id":92,"name":"Womp Company","industry":"Technology","revenue":8556887131,"profit":-425066747,"employees":4546350,"stockType":"Private"},{"id":93,"name":"Wat Ittabito Cartel","industry":"Energy","revenue":4013235453,"profit":-87674586,"employees":213018,"stockType":"Public"},{"id":94,"name":"Wat Hearty GmbH","industry":"Professional Services","revenue":249513915,"profit":17011352,"employees":125438,"stockType":"Public"},{"id":95,"name":"The Candzer LLC","industry":"Professional Services","revenue":1842955767,"profit":-141851809,"employees":994072,"stockType":"Private"},{"id":96,"name":"Piperdoodle GmbH","industry":"Technology","revenue":1667899196,"profit":13001807,"employees":885172,"stockType":"Public"},{"id":97,"name":"Zimmerman LLC","industry":"Professional Services","revenue":8033493573,"profit":774916979,"employees":2765446,"stockType":"Private"},{"id":98,"name":"Hearty LLC","industry":"Professional Services","revenue":9504728500,"profit":-246514623,"employees":4773786,"stockType":"Private"},{"id":99,"name":"Peders and Niptune Inc","industry":"Finance","revenue":7952550485,"profit":-330785855,"employees":4164307,"stockType":"Private"},{"id":100,"name":"Cangrue Cartel","industry":"Healthcare","revenue":8379023796,"profit":472987607,"employees":305778,"stockType":"Public"}] | |
export class App { | |
sorters = []; | |
selected = []; | |
page = 0; | |
pages = DATA.length / 10; | |
attached() { | |
const resize = () => { | |
const { resizing, target, move } = this; | |
if (resizing) { | |
debugger; | |
target.clientWidth += move; | |
this.move = 0; | |
} | |
requestAnimationFrame(resize); | |
}; | |
resize(); | |
} | |
target = null; | |
resizing = false; | |
move = 0; | |
startResize(event) { | |
if (event.offsetX < 0) { | |
this.resizing = true; | |
this.target = event.target; | |
} | |
} | |
resize(event) { | |
if (this.resizing) { | |
this.move += event.movementX; | |
} | |
} | |
activate() { | |
const { sorters, page } = this; | |
return Promise.all([ | |
this.getData({ sorters, page }).then((data) => this.data = data), | |
this.loadConfig() | |
]); | |
} | |
getData({ sorters, page } = {}) { | |
sorters = sorters || []; | |
page = page || 0; | |
let data = DATA.slice(); | |
data = SortValueConverter.prototype.toView(DATA, sorters); | |
data = data.slice(10 * page, 10 * (page + 1)); | |
return Promise.resolve(data); | |
} | |
loadConfig() { | |
return Promise.resolve({ | |
columns: [] | |
}); | |
} | |
increaseProfitByFactor(k) { | |
this.selected.forEach(s => s.profit *= k); | |
} | |
toggleAll() { | |
if (this.selected.length < this.data.length) { | |
this.selected = this.data.slice(); | |
} else { | |
this.selected = []; | |
} | |
} | |
toggleCheckbox() { | |
const { length } = this.selected; | |
if (length === 0) { | |
this.allCheckbox.checked = false; | |
this.allCheckbox.indeterminate = false; | |
} else if (length === this.data.length) { | |
this.allCheckbox.checked = true; | |
this.allCheckbox.indeterminate = false; | |
} else { | |
this.allCheckbox.checked = false; | |
this.allCheckbox.indeterminate = true; | |
} | |
} | |
updateSort(newSort) { | |
const idx = this.getSortIndex(newSort[0]); | |
if (idx !== null) { | |
this.sorters.splice(idx, 1); | |
} | |
if (newSort[1]) { | |
this.sorters.push(newSort); | |
} | |
this.activate(); | |
} | |
updatePage(page) { | |
this.page = page; | |
this.activate(); | |
} | |
getSortIndex(property) { | |
const idx = this.sorters.findIndex((s) => s[0] === property); | |
return idx > -1 ? idx : null; | |
} | |
} | |
export class SortValueConverter { | |
toView(arr, sorters) { | |
arr = arr.slice(); | |
sorters.forEach(([prop, dir]) => { | |
const s = dir === 'desc' ? -1 : 1; | |
arr = arr.sort((a, b) => { | |
const aProp = a[prop]; | |
const bProp = b[prop]; | |
if (aProp < bProp) { | |
return -s; | |
} else if (aProp > bProp) { | |
return s; | |
} else { | |
return 0; | |
} | |
}); | |
}); | |
return arr; | |
} | |
} | |
export class DoubleValueConverter { | |
toView(arr) { | |
return arr.reduce((a, i) => a = a.concat([i, i]), []); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<style>em::before { content: "NOTE: "; font-size: 0.8em; font-weight: bold; }</style> | |
<section style="margin-bottom: 1em;"> | |
<style>label { display: block; }</style> | |
<p>This example will demonstrate how to build Aurelia table-oriented tools that achieve the following:</p> | |
<label> | |
<input type="checkbox" checked /> | |
<span>declarative column definition</span> | |
<b>(44535)</b> | |
<em>through default templating</em> | |
</label> | |
<label> | |
<input type="checkbox" checked /> | |
<span>action columns (select, cancel, save, etc), including multi-select column with checkboxes for bulk actions</span> | |
<b>(44535)</b> | |
</label> | |
<label> | |
<input type="checkbox" checked /> | |
<span>(server side) cascading sort</span> | |
<b>(44535)</b> | |
</label> | |
<label> | |
<input type="checkbox" checked /> | |
<span>(server side) pagination</span> | |
<b>(44535)</b> | |
</label> | |
<label> | |
<input type="checkbox" checked /> | |
<span>hierarchy (detail tables)</span> | |
<b>(44535)</b> | |
<em>no ie11 support!</em> | |
</label> | |
<label> | |
<input type="checkbox" /> | |
<span>(server side) filter</span> | |
<b>(46554)</b> | |
</label> | |
<label> | |
<input type="checkbox" checked /> | |
<span>resizable columns</span> | |
<b>(46554)</b> | |
</label> | |
<label> | |
<input type="checkbox" checked /> | |
<span>auto-fit widths</span> | |
<b>(46554)</b> | |
</label> | |
<label> | |
<input type="checkbox" /> | |
<span>column visibility</span> | |
<b>(46554)</b> | |
</label> | |
<label> | |
<input type="checkbox" /> | |
<span>column reordering</span> | |
<b>(46554)</b> | |
</label> | |
<label> | |
<input type="checkbox" /> | |
<span>persist table settings</span> | |
<b>(46554)</b> | |
</label> | |
<label> | |
<input type="checkbox" /> | |
<span>"freeze" column header row at top when scrolling</span> | |
<b>(46554)</b> | |
</label> | |
<label> | |
<input type="checkbox" /> | |
<span>(server side) filter</span> | |
</label> | |
<label> | |
<input type="checkbox" /> | |
<span>(client side) cascading sort</span> | |
<em>not demoed here, but follows trivially from this construction</em> | |
</label> | |
<label> | |
<input type="checkbox" /> | |
<span>(client side) pagination</span> | |
<em>not demoed here, but follows trivially from this construction</em> | |
</label> | |
<label> | |
<input type="checkbox" /> | |
<span>(client side) filter</span> | |
</label> | |
</section> | |
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Resizable */ | |
.resize-handle { | |
position: absolute; | |
right: -4px; | |
top: 0; | |
background: red; | |
height: 100%; | |
width: 8px; | |
cursor: col-resize; | |
} | |
[resizable] { | |
position: relative; | |
box-sizing: content-box; | |
padding: 1vh 1vw; | |
transition: width 0.05s; | |
} | |
/* Reorderable */ | |
.reorder-handle { | |
height: 0.8em; | |
width: 0.8em; | |
border-radius: 50%; | |
background: green; | |
float: right; | |
cursor: grab; | |
} | |
[reorderable] { | |
} | |
td:not(.dragging), th:not(.dragging) { | |
transition: transform 0.25s ease-in-out; | |
} | |
/* Sortable */ | |
[sortable] { | |
cursor: pointer; | |
} | |
.sort-asc:before, .sort-desc:before { | |
content: attr(data-sort-index); | |
margin-right: 0.5rem; | |
font-size: 0.8em; | |
} | |
.sort-asc:after { | |
content: '▲'; | |
margin-left: 0.5rem; | |
} | |
.sort-desc:after { | |
content: '▼'; | |
margin-left: 0.5rem; | |
} | |
.table { | |
display: grid; | |
grid-template-columns: repeat(auto-fit); | |
max-width: 100%; | |
} | |
thead td, | |
thead th { | |
} | |
.row { | |
} | |
.cell { | |
padding: 0.2em; | |
} | |
.action { | |
font-weight: bold; | |
font-size: 0.8em; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<title>Table Example</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
</head> | |
<body aurelia-app="main"> | |
<h1>Loading...</h1> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.6/system.js"></script> | |
<script src="https://rawgit.com/aurelia-ui-toolkits/aurelia-materialize-bundles/0.30.0/config2.js"></script> | |
<script> | |
System.import('aurelia-bootstrapper'); | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/******************************************************************************* | |
* The following two lines enable async/await without using babel's | |
* "runtime" transformer. Uncomment the lines if you intend to use async/await. | |
* | |
* More info here: https://github.com/jdanyow/aurelia-plunker/issues/2 | |
*/ | |
//import regeneratorRuntime from 'babel-runtime/regenerator'; | |
//window.regeneratorRuntime = regeneratorRuntime; | |
/******************************************************************************/ | |
import 'materialize'; | |
export function configure(aurelia) { | |
aurelia.use | |
.standardConfiguration() | |
.developmentLogging() | |
.plugin('aurelia-materialize-bridge', bridge => bridge.useAll() ); | |
aurelia.start().then(a => a.setRoot()); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div> | |
<a class="button ${page === i ? 'active' : ''}" repeat.for="i of pages" click.delegate="updatePage(i)">${i + 1}</a> | |
</div> | |
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function midpoints(el) { | |
const { top, left, height, width } = el.getBoundingClientRect(); | |
return { | |
x: left + width / 2, | |
y: top + height / 2 | |
}; | |
} | |
function indexOf(el) { | |
return Array.from(el.parentElement.children).indexOf(el); | |
} | |
const handle = document.createElement('div'); | |
handle.classList.add('reorder-handle'); | |
export class ReorderableCustomAttribute { | |
static inject = [Element]; | |
constructor(element) { | |
this.element = element; | |
this.handle = handle.cloneNode(); | |
} | |
attached() { | |
this.element.appendChild(this.handle); | |
const index = this.index = indexOf(this.element); | |
const table = this.element.closest('table'); | |
this.column = Array.from(table.querySelectorAll(`tr > :nth-child(${index+1}`)); | |
const midpoint = midpoints(this.element).x; | |
const swap = (event) => { | |
if (this.dragging) return; | |
const sgn = event.detail.index < index ? -1 : 1; | |
if (sgn * (midpoint - event.detail.x) > 0) { | |
this.move(sgn * event.detail.width, 0); | |
event.detail.dragged.index = this.index | |
this.index = event.detail.index | |
} | |
}; | |
const drag = ({ clientX, clientY, pageX }) => { | |
if (this.dragging) { | |
const dx = clientX - this.x; | |
const dy = clientY - this.y; | |
this.move(dx, dy); | |
table.dispatchEvent(new CustomEvent('dragover', { detail: { | |
index: this.index, | |
x: clientX, | |
width: this.element.clientWidth, | |
dragged: this | |
}})); | |
} | |
} | |
const cancel = () => { | |
this.dragging = false; | |
this.column.forEach((cell) => cell.classList.remove('dragging')); | |
document.removeEventListener('mousemove', drag); | |
document.removeEventListener('mouseup', cancel); | |
table.dispatchEvent(new CustomEvent('dragend', { | |
detail: { index: this.index, dragged: this } | |
})); | |
} | |
table.addEventListener('dragover', swap); | |
table.addEventListener('dragend', (event) => { | |
if (index === event.detail.index) { | |
for (let i = this.column.length-1; i >= 0; i--) { | |
const shifted = this.column[i]; | |
const dragged = event.detail.dragged.column[i]; | |
const parent = shifted.parentElement; | |
parent.insertBefore(dragged, shifted.nextSibling); | |
} | |
} | |
if (this !== event.detail.dragged) { | |
} | |
this.move(0, 0); | |
}); | |
this.handle.addEventListener('mousedown', ({ clientX, clientY }) => { | |
this.dragging = true; | |
this.column.forEach((cell) => cell.classList.add('dragging')); | |
this.x = clientX; | |
this.y = clientY; | |
document.addEventListener('mousemove', drag); | |
document.addEventListener('mouseup', cancel); | |
}); | |
this.handle.addEventListener('click', (event) => event.stopPropagation()); | |
} | |
move(dx, dy) { | |
this.column.forEach((cell) => cell.style.transform = `translate(${dx}px, ${dy}px)`); | |
} | |
reorder(dx, pageX) { | |
// if dx < 0 | |
// for each header from index-1 to 0 | |
// if pagex is less than right for a header element | |
// then select each idx-th element and insert after the next element | |
// if dx > 0 | |
// for each header from index+1 to length | |
// if pagex is more than left for a header element | |
// then select each idx-th element and insert it before the previouse element | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function isResizable(el) { | |
return el && el.hasAttribute('resizable'); | |
} | |
function midpoint(el) { | |
const { left, width } = el.getBoundingClientRect(); | |
return left + width / 2; | |
} | |
const handle = document.createElement('div'); | |
handle.classList.add('resize-handle'); | |
export class ResizableCustomAttribute { | |
static inject = [Element]; | |
constructor(element) { | |
this.element = element; | |
this.handle = handle.cloneNode(); | |
} | |
attached() { | |
this.element.appendChild(this.handle); | |
this.autofit(); | |
const resize = ({ clientX }) => { | |
if (this.resizing) { | |
const el = this.element; | |
const dx = clientX - this.x; | |
console.log(el.clientWidth, dx,); | |
this.resize(el, this.width + dx); | |
const next = el.nextSibling; | |
if (next) { | |
this.resize(next, next.clientWidth - dx); | |
} | |
} | |
}; | |
const cancel = () => { | |
this.resizing = false; | |
document.removeEventListener('mouseup', cancel); | |
document.removeEventListener('mouseup', resize); | |
}; | |
const autofit = () => this.autofit(); | |
this.handle.addEventListener('mousedown', (event) => { | |
this.x = midpoint(this.handle); | |
this.width = this.element.clientWidth; | |
this.resizing = true; | |
document.addEventListener('mouseup', cancel); | |
document.addEventListener('mousemove', resize); | |
}); | |
this.handle.addEventListener('click', (event) => event.stopPropagation()); | |
this.handle.addEventListener('dblclick', autofit); | |
} | |
resize(el, width) { | |
el.style.width = `${width}px`; | |
} | |
autofit() { | |
const table = this.element.closest('table'); | |
const parent = this.element.parentElement; | |
const index = Array.from(parent.children).indexOf(this.element); | |
const range = document.createRange(); | |
const width = Math.max( | |
...Array.from(table.querySelectorAll(`tr > :nth-child(${index+1})`)) | |
.map((cell) => { | |
const range = document.createRange(); | |
range.selectNodeContents(cell.childNodes[0]); | |
return range.getBoundingClientRect().width; | |
}) | |
); | |
this.resize(this.element, width); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { containerless, inlineView } from 'aurelia-framework'; | |
@containerless | |
@inlineView('<template><slot></slot></template>') | |
export class EssRowCustomElement { | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { bindable, inject } from 'aurelia-framework'; | |
const DIRS = { | |
0: null, | |
1: 'asc', | |
2: 'desc' | |
} | |
@inject(Element) | |
export class SortableCustomAttribute { | |
sort = Object.freeze([this.value, DIRS[this.dir]]); | |
dir = 0; | |
constructor(element) { | |
this.element = element; | |
} | |
attached() { | |
this.element.addEventListener('click', (event) => { | |
this.dir = (this.dir + 1) % 3; | |
this.sort = Object.freeze([this.value, DIRS[this.dir]]); | |
this.element.dispatchEvent(new CustomEvent('sort-change', { | |
bubbles: true, | |
detail: this.sort | |
})); | |
this.updateClass(); | |
}); | |
} | |
updateClass() { | |
const dir = DIRS[this.dir]; | |
if (dir === 'asc') { | |
this.element.classList.add('sort-asc'); | |
} | |
else if (dir === 'desc') { | |
this.element.classList.remove('sort-asc'); | |
this.element.classList.add('sort-desc'); | |
} else { | |
this.element.classList.remove('sort-desc'); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<style> | |
ess-table { | |
display: grid; | |
grid-auto-columns: min-content; | |
} | |
ess-cell, ess-header { | |
padding: 1vh 1vw; | |
} | |
</style> | |
<slot></slot> | |
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export class EssTableCustomElement { | |
} | |
// export class PagedCustomAttribute { | |
// pageLength = 10; | |
// page = 0; | |
// bind(bindingContext, overrideContext) { | |
// this.context = overrideContext; | |
// this.setPage(0); | |
// } | |
// setPage(page) { | |
// this.page = this.context.$page = page; | |
// } | |
// } | |
// export class PagedValueConverter { | |
// } | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<table mousedown.delegate="startResize($event)" mousemove.delegate="resize($event)"> | |
<thead><tr sort-change.delegate="updateSort($event.detail)"> | |
<td style="width: 24px;"><!-- expand --></td> | |
<td style="width: 24px;"> | |
<input type="checkbox" change.delegate="toggleAll()" element.ref="allCheckbox" /> | |
</td> | |
<th sortable="name" resizable reorderable>Name</th> | |
<th sortable="industry" resizable reorderable>Industry</th> | |
<th sortable="revenue" resizable reorderable>Revenue</th> | |
<th sortable="profit" resizable reorderable>Profit</th> | |
<th sortable="employees" resizable reorderable>Employees</th> | |
<td><!-- actions --></td> | |
</tr></thead> | |
<template repeat.for="company of data"> | |
<tr class="row"> | |
<td class="action"> | |
<i class="arrow rotate ${expanded ? 'ninety' : ''}" click.delegate="expanded = !expanded">►</i> | |
</td> | |
<td> | |
<input type="checkbox" checked.bind="selected" model.bind="company" change.delegate="toggleCheckbox()" /> | |
</td> | |
<td>${company.name}</td> | |
<td>${company.industry}</td> | |
<td class="align-right">${company.revenue | cash}</td> | |
<td class="align-right">${company.profit | cash}</td> | |
<td class="align-right">${company.employees | integer}</td> | |
<td> | |
<a class="action">save</a> | |
<a class="action">delete</a> | |
<a class="action">edit</a> | |
</td> | |
</tr> | |
<tr if.bind="expanded"> | |
<td></td> | |
<td colspan="6"> | |
<table class="table" style="width: 100%"> | |
<tr> | |
<th>Name again</th> | |
<th>More profits</th> | |
</tr> | |
<tr class="row" repeat.for="i of 2"> | |
<td>${company.name} again</td> | |
<td>${company.profit * (i + 0.5) | cash}</td> | |
</tr> | |
</table> | |
</td> | |
</tr> | |
</template> | |
</table> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function pad(num, digits = 3) { | |
num = num.toString(); | |
while (num.length < digits) { | |
num = '0' + num; | |
} | |
return num; | |
} | |
export class CashValueConverter { | |
toView(val) { | |
if (typeof(val) !== 'number') { | |
return val; | |
} | |
const sign = Math.sign(val) < 0 ? '-' : ''; | |
const decimal = val % 1; | |
const places = []; | |
val = Math.abs(Math.trunc(val)); | |
while (val > 1) { | |
places.unshift(val % 1000); | |
val = Math.floor(val / 1000) | |
} | |
return `${sign}\$${places.map((p, i) => pad(p, i > 0 ? 3 : 0)).join(',')}.${decimal.toFixed(2).slice(2)}` | |
} | |
} | |
export class IntegerValueConverter { | |
toView(val) { | |
if (typeof(val) !== 'number') { | |
return val; | |
} | |
const places = []; | |
while (val > 1) { | |
places.unshift(val % 1000); | |
val = Math.floor(val / 1000) | |
} | |
return `${places.map((p, i) => pad(p, i > 0 ? 3 : 0)).join(',')}` | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment