kempo 2.7.3 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import Component from"./Component.js";import Icon from"./Icon.js";import{toTitleCase}from"../utils/string.js";export default class Table extends Component{constructor(e=!1,t=!1,o={before:[],after:[],top:[],bottom:[]}){super(),this.registerProps({fields:[],records:[],controls:{before:[],after:[],top:[],bottom:[]}}),e&&this.setData(e,t,o)}async render(e){return!!await super.render(e)&&(this.renderControls(this.controls.top,"top"),this.renderFields(),this.renderRecords(),this.renderControls(this.controls.bottom,"bottom"),!0)}renderFields(){const e=this.controls?.before?.length?"<th></th>":"",t=this.controls?.after?.length?"<th></th>":"";this.shadowRoot.getElementById("fields").innerHTML=`${e}${this.fields.map((({label:e})=>`<th>${e}</th>`)).join("")}${t}`}renderRecords(){const e=this.shadowRoot.getElementById("records");e.innerHTML="",this.records.forEach((t=>{const o=document.createElement("tr");this.controls?.before?.length&&o.appendChild(this.renderRowControls(this.controls.before,t)),this.fields.forEach((({name:e})=>{const n=document.createElement("td");let r=t[e]||"";Array.isArray(r)&&(r=r.join(", ")),n.innerHTML=r,o.appendChild(n)})),this.controls?.after?.length&&o.appendChild(this.renderRowControls(this.controls.after,t)),e.appendChild(o)}))}renderRowControls(e=[],t){const o=document.createElement("td");return e.forEach((({html:e,icon:n,action:r,render:s})=>{if(e)o.appendChild(document.createRange().createContextualFragment(e));else if(s&&"function"==typeof s){const e=s(this,t);e instanceof HTMLElement?o.appendChild(e):"string"==typeof e&&o.appendChild(document.createRange().createContextualFragment(e))}else if(n){const e=document.createElement("button");e.appendChild(new Icon(n)),r&&e.addEventListener("click",(()=>r(this,t))),o.appendChild(e)}})),o}renderControls(e=[],t){const o=document.createElement("div");e.forEach((({html:e,icon:t,action:n,render:r})=>{if(e)o.appendChild(document.createRange().createContextualFragment(e));else if(r&&"function"==typeof r){const e=r(this);e instanceof HTMLElement?o.appendChild(e):"string"==typeof e&&o.appendChild(document.createRange().createContextualFragment(e))}else if(t){const e=document.createElement("button");e.appendChild(new Icon(t)),n&&e.addEventListener("click",(()=>n(this))),o.appendChild(e)}})),this.shadowRoot.getElementById(t).innerHTML="",this.shadowRoot.getElementById(t).appendChild(o)}setData(e,t=!1,o={before:[],after:[],top:[],bottom:[]}){this.records=e,this.fields=t||Table.extractFieldsFromRecords(this.records),this.controls=o,this.renderControls(this.controls.top,"top"),this.renderFields(),this.renderRecords(),this.renderControls(this.controls.bottom,"bottom")}get shadowTemplate(){return`\n ${super.shadowTemplate}\n <div class="responsive-table">\n <div id="top"></div>\n <table>\n <thead id="fields"></thead>\n <tbody id="records"></tbody>\n </table>\n <div id="bottom"></div>\n </div>\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n display: block;\n margin-bottom: var(--spacer);\n }\n `}static extractFieldsFromRecords(e,t=100){const o=new Set;return e.slice(0,t).forEach((e=>{Object.keys(e).forEach((e=>o.add(e)))})),[...o].map((e=>({name:e,label:toTitleCase(e)})))}}window.customElements.define("k-table",Table);
1
+ import Component from"./Component.js";import Icon from"./Icon.js";import{toTitleCase}from"../utils/string.js";import{onEvent,dispatchEvent}from"../utils/element.js";export default class Table extends Component{static controls={prevPage:{render:e=>{const t=document.createElement("button");return t.classList.add("pq"),t.appendChild(new Icon("chevron-left")),onEvent(t,"click",(()=>e.prevPage())),onEvent(e,"pageChange",(()=>{t.disabled=1===e.getCurrentPage()})),t}},nextPage:{render:e=>{const t=document.createElement("button");return t.classList.add("pq"),t.appendChild(new Icon("chevron-right")),onEvent(t,"click",(()=>e.nextPage())),onEvent(e,"pageChange",(()=>{t.disabled=e.getCurrentPage()===e.getTotalPages()})),t}},pageSelect:{render:e=>new PageSelect(e)},pageSize:{render:e=>new PageSize(e)},spacer:{html:'<div class="flex"></div>'}};constructor({records:e=[],fields:t=[],controls:n={before:[],after:[],top:[],bottom:[]},pageSize:s=100,pageSizeOptions:r=[10,25,50,100,500],currentPage:a=1}={}){super(),this.registerProps({fields:t,records:e,controls:n,pageSize:s,pageSizeOptions:r,currentPage:a})}async render(e){return!!await super.render(e)&&(this.setData({records:this.records,fields:this.fields,controls:this.controls,pageSize:this.pageSize,pageSizeOptions:this.pageSizeOptions,currentPage:this.currentPage}),!0)}renderFields(){if(!this.rendered)return;const e=this.controls?.before?.length?"<th></th>":"",t=this.controls?.after?.length?"<th></th>":"";this.shadowRoot.getElementById("fields").innerHTML=`${e}${this.fields.map((({label:e})=>`<th>${e}</th>`)).join("")}${t}`}renderRecords(){if(!this.rendered)return;const e=this.shadowRoot.getElementById("records");e.innerHTML="";const t=(this.currentPage-1)*this.pageSize,n=t+this.pageSize;this.records.slice(t,n).forEach(((s,r)=>{const a=document.createElement("tr");this.controls?.before?.length&&a.appendChild(this.renderRowControls(this.controls.before,s,t+r)),this.fields.forEach((({name:e,formatter:r,calculator:o})=>{const i=document.createElement("td");if(null===s)i.innerHTML="Loading...",dispatchEvent(this,"fetchRecords",{start:t,end:n});else{let t;o?t=o(s,this):(t=s[e]||"",Array.isArray(t)?t=r?t.map(r).join(", "):t.join(", "):r&&(t=r(t))),i.innerHTML=t}a.appendChild(i)})),this.controls?.after?.length&&a.appendChild(this.renderRowControls(this.controls.after,s,t+r)),e.appendChild(a)}))}renderRowControls(e=[],t,n){if(!this.rendered)return;const s=document.createElement("td");return e.forEach((({html:e,icon:r,action:a,render:o})=>{if(e)s.appendChild(document.createRange().createContextualFragment(e));else if(o&&"function"==typeof o){const e=o(this,t,n);e instanceof HTMLElement?s.appendChild(e):"string"==typeof e&&s.appendChild(document.createRange().createContextualFragment(e))}else if(r){const e=document.createElement("button");e.classList.add("pq"),e.appendChild(new Icon(r)),a&&onEvent(e,"click",(()=>a(this,t,n))),s.appendChild(e)}})),s}renderControls(e=[],t){if(!this.rendered)return;const n=this.shadowRoot.getElementById(t);n.innerHTML="",e.forEach((({html:e,icon:t,action:s,render:r})=>{if(e)n.appendChild(document.createRange().createContextualFragment(e));else if(r&&"function"==typeof r){const e=r(this);e instanceof HTMLElement?n.appendChild(e):"string"==typeof e&&n.appendChild(document.createRange().createContextualFragment(e))}else if(t){const e=document.createElement("button");e.classList.add("pq"),e.appendChild(new Icon(t)),s&&onEvent(e,"click",(()=>s(this))),n.appendChild(e)}}))}getCurrentPage(){return this.currentPage}getTotalPages(){return Math.ceil(this.records.length/this.pageSize)}setPage(e){e<1||e>this.getTotalPages()||(this.currentPage=e,this.renderRecords(),dispatchEvent(this,"pageChange"))}nextPage(){this.currentPage<this.getTotalPages()&&this.setPage(this.currentPage+1)}prevPage(){this.currentPage>1&&this.setPage(this.currentPage-1)}setPageSize(e){this.pageSize=e,this.currentPage=1,this.renderRecords(),dispatchEvent(this,"pageSizeChange")}setData({records:e=!1,fields:t=!1,controls:n=!1,pageSize:s=!1,pageSizeOptions:r=!1,currentPage:a=!1}={}){let o=!1,i=!1;e&&(this.records=e,this.fields=t||Table.extractFieldsFromRecords(this.records),o=!0),s&&(this.pageSize=s,o=!0),r&&(this.pageSizeOptions=r),n&&(this.controls=n,i=!0),a&&(this.currentPage=a,o=!0),o&&(this.renderFields(),this.renderRecords()),i&&(this.renderControls(this.controls.top,"top"),this.renderControls(this.controls.bottom,"bottom"))}setRecords(e){this.records=e,this.currentPage=1,this.renderRecords(),dispatchEvent(this,"recordsSet",{records:e})}setupFetchRecords(e,t){const n=this.records.length;n<e&&(this.records.length=e,this.records.fill(null,n)),onEvent(this,"fetchRecords",(async e=>{const{start:n,end:s}=e.detail,r=await t(n,s-n);this.records.splice(n,r.length,...r),this.renderRecords()}))}addRecord(e){this.records.push(e),this.renderRecords(),dispatchEvent(this,"recordAdded",{record:e})}updateRecord(e,t){this.records[e]=t;const n=(this.currentPage-1)*this.pageSize,s=n+this.pageSize;e>=n&&e<s&&this.renderRecords()}deleteRecord(e){e>=0&&e<this.records.length&&(this.records.splice(e,1),this.renderRecords(),dispatchEvent(this,"recordDeleted",{index:e}))}get shadowTemplate(){return`\n ${super.shadowTemplate}\n <div class="responsive-table">\n <div id="top"></div>\n <table class="b0">\n <thead id="fields"></thead>\n <tbody id="records"></tbody>\n </table>\n <div id="bottom"></div>\n </div>\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n display: block;\n margin-bottom: var(--spacer);\n border: 1px solid var(--c_border);\n border-radius: var(--radius);\n }\n #top, #bottom {\n display: flex;\n }\n th {\n border-top: none;\n }\n tr:last-child td:first-child {\n border-bottom-left-radius: 0;\n }\n tr:last-child td:last-child {\n border-bottom-right-radius: 0;\n }\n tr:last-child td {\n border-bottom: none;\n }\n th:first-child, td:first-child {\n border-left: none;\n }\n th:last-child, td:last-child {\n border-right: none;\n }\n #top:not(:empty) {\n border-bottom: 1px solid var(--c_border);\n }\n #bottom:not(:empty) {\n border-top: 1px solid var(--c_border);\n }\n `}static extractFieldsFromRecords(e,t=100){const n=new Set;return e.slice(0,t).forEach((e=>{Object.keys(e).forEach((e=>n.add(e)))})),[...n].map((e=>({name:e,label:toTitleCase(e)})))}}window.customElements.define("k-table",Table);class PageSelect extends Component{constructor(e){super(),this.table=e,this.classList.add("mxq")}connectedCallback(){this.render()}async render(){return!!await super.render()&&(this.updateOptions(),!0)}updateOptions(){const e=this.shadowRoot.getElementById("pageSelect");e.innerHTML="";for(let t=1;t<=this.table.getTotalPages();t++){const n=document.createElement("option");n.value=t,n.textContent=t,e.appendChild(n)}e.value=this.table.getCurrentPage();this.shadowRoot.getElementById("totalPages").textContent=this.table.getTotalPages(),onEvent(e,"change",(()=>{this.table.setPage(parseInt(e.value))})),onEvent(this.table,"pageSizeChange",(()=>{this.updateOptions()})),onEvent(this.table,"pageChange",(()=>{e.value=this.table.getCurrentPage()}))}get shadowTemplate(){return'\n <select id="pageSelect" class="mxq"></select>\n <label> out of <span id="totalPages"></span></label>\n '}get shadowStyles(){return"\n :host {\n display: inline-flex;\n width: max-content;\n align-items: baseline;\n }\n #pageSelect, label {\n display: inline;\n }\n label {\n white-space: nowrap;\n }\n "}}window.customElements.define("k-table-page-select",PageSelect);class PageSize extends Component{constructor(e){super(),this.table=e,this.classList.add("mxq")}connectedCallback(){this.render()}async render(){if(await super.render()){const e=this.shadowRoot.getElementById("pageSizeSelect");return this.table.pageSizeOptions.forEach((t=>{const n=document.createElement("option");n.value=t,n.textContent=t,e.appendChild(n)})),e.value=this.table.pageSize,onEvent(e,"change",(()=>{this.table.setPageSize(parseInt(e.value))})),onEvent(this.table,"pageSizeChange",(()=>{e.value=this.table.pageSize})),!0}return!1}get shadowTemplate(){return'\n <label for="pageSizeSelect">Page Size: </label>\n <select id="pageSizeSelect" class="mxq"></select>\n '}get shadowStyles(){return"\n :host {\n display: inline-flex;\n width: max-content;\n align-items: baseline;\n }\n label {\n white-space: nowrap;\n }\n "}}window.customElements.define("k-table-page-size",PageSize);
@@ -1 +1 @@
1
- import Component from"./Component.js";import{onEvent,dispatchEvent}from"../utils/element.js";import"./Icon.js";const storageWatcher=Symbol("storageWatcher"),clickHandler=Symbol("clickHandler");export default class ThemeSwitcher extends Component{constructor(){super(),this[storageWatcher]=()=>{this.currentTheme=ThemeSwitcher.getCurrentTheme()},this[clickHandler]=()=>{const e=ThemeSwitcher.getCurrentTheme();"auto"===e&&ThemeSwitcher.setTheme("light"),"light"===e&&ThemeSwitcher.setTheme("dark"),"dark"===e&&ThemeSwitcher.setTheme("auto")},this.registerAttribute("currentTheme",ThemeSwitcher.getCurrentTheme())}async render(e){return!!await super.render(e)&&(onEvent(window,"storage",this[storageWatcher]),onEvent(this.shadowRoot.getElementById("toggle"),"click",this[clickHandler]),!0)}disconnectedCallback(){super.disconnectedCallback(),offEvent(this.shadowRoot.getElementById("toggle"),"click",this[clickHandler])}get shadowTemplate(){return'\n <button\n id="toggle"\n class="no-btn"\n >\n <k-icon\n id="autoMode"\n name="mode-auto"\n class="mode"\n ></k-icon>\n <k-icon\n id="lightMode"\n name="mode-light"\n class="mode"\n ></k-icon>\n <k-icon\n id="darkMode"\n name="mode-dark"\n class="mode"\n ></k-icon>\n </button>\n '}get shadowStyles(){return'\n :host {\n --padding: var(--spacer);\n\n display: flex;\n }\n #toggle {\n padding: var(--padding);\n }\n .mode {\n display: none;\n }\n :host([current-theme="auto"]) #autoMode,\n :host([current-theme="light"]) #lightMode,\n :host([current-theme="dark"]) #darkMode {\n display: block;\n }\n '}static setTheme(e){localStorage.setItem("theme",e),document.documentElement.setAttribute("theme",e),dispatchEvent(window,"storage",{theme:e})}static getCurrentTheme(){let e=document.documentElement.getAttribute("theme");return e||(e=localStorage.getItem("theme")),e}}const colorSchemeQuery=window.matchMedia("(prefers-color-scheme: dark)"),colorSchemeChangeHandler=e=>document.documentElement.setAttribute("auto-theme",e.matches?"dark":"light");colorSchemeQuery.addEventListener("change",colorSchemeChangeHandler),colorSchemeChangeHandler(colorSchemeQuery),ThemeSwitcher.setTheme(ThemeSwitcher.getCurrentTheme()),window.customElements.define("k-theme-switcher",ThemeSwitcher);
1
+ import Component from"./Component.js";import{onEvent,dispatchEvent}from"../utils/element.js";import"./Icon.js";const storageWatcher=Symbol("storageWatcher"),clickHandler=Symbol("clickHandler");export default class ThemeSwitcher extends Component{constructor(){super(),this[storageWatcher]=()=>{this.currentTheme=ThemeSwitcher.getCurrentTheme()},this[clickHandler]=()=>{const e=ThemeSwitcher.getCurrentTheme();"auto"===e&&ThemeSwitcher.setTheme("light"),"light"===e&&ThemeSwitcher.setTheme("dark"),"dark"===e&&ThemeSwitcher.setTheme("auto")},this.registerAttribute("currentTheme",ThemeSwitcher.getCurrentTheme())}async render(e){return!!await super.render(e)&&(onEvent(window,"storage",this[storageWatcher]),onEvent(this.shadowRoot.getElementById("toggle"),"click",this[clickHandler]),!0)}disconnectedCallback(){super.disconnectedCallback(),offEvent(this.shadowRoot.getElementById("toggle"),"click",this[clickHandler])}get shadowTemplate(){return'\n <button\n id="toggle"\n class="no-btn"\n >\n <k-icon\n id="autoMode"\n name="mode-auto"\n class="mode"\n ></k-icon>\n <k-icon\n id="lightMode"\n name="mode-light"\n class="mode"\n ></k-icon>\n <k-icon\n id="darkMode"\n name="mode-dark"\n class="mode"\n ></k-icon>\n </button>\n '}get shadowStyles(){return'\n :host {\n --padding: var(--spacer);\n\n display: flex;\n }\n #toggle {\n padding: var(--padding);\n }\n .mode {\n display: none;\n }\n :host([current-theme="auto"]) #autoMode,\n :host([current-theme="light"]) #lightMode,\n :host([current-theme="dark"]) #darkMode {\n display: block;\n }\n '}static setTheme(e){localStorage.setItem("theme",e),document.documentElement.setAttribute("theme",e),dispatchEvent(window,"storage",{theme:e})}static getCurrentTheme(){let e=document.documentElement.getAttribute("theme");return e||(e=localStorage.getItem("theme")),e||"auto"}}const colorSchemeQuery=window.matchMedia("(prefers-color-scheme: dark)"),colorSchemeChangeHandler=e=>document.documentElement.setAttribute("auto-theme",e.matches?"dark":"light");colorSchemeQuery.addEventListener("change",colorSchemeChangeHandler),colorSchemeChangeHandler(colorSchemeQuery),ThemeSwitcher.setTheme(ThemeSwitcher.getCurrentTheme()),window.customElements.define("k-theme-switcher",ThemeSwitcher);
@@ -6,6 +6,45 @@
6
6
  <title>Table - Components - Kempo Docs - A Web Components Solution</title>
7
7
  <link rel="stylesheet" href="../kempo/kempo-vars.css" /><link rel="stylesheet" href="../kempo/kempo-styles.css" />
8
8
  <link rel="stylesheet" href="../kempo/kempo-hljs.css" />
9
+ <script type="module" src="../kempo/components/Table.js"></script>
10
+ <script>
11
+
12
+ window.contacts = [];
13
+ function generateContact(){
14
+ const maleNames = [
15
+ "Liam", "Noah", "Oliver", "Elijah", "William", "James", "Benjamin",
16
+ "Lucas", "Henry", "Alexander", "Mason", "Michael", "Ethan", "Daniel",
17
+ "Jacob", "Logan", "Jackson", "Levi", "Sebastian", "Mateo", "Jack",
18
+ "Owen", "Theodore", "Aiden", "Samuel", "Joseph", "John", "David",
19
+ "Wyatt", "Matthew"
20
+ ];
21
+ const femaleNames = [
22
+ "Olivia", "Emma", "Ava", "Sophia", "Isabella", "Mia", "Amelia",
23
+ "Harper", "Evelyn", "Abigail", "Emily", "Ella", "Elizabeth",
24
+ "Camila", "Luna", "Sofia", "Avery", "Mila", "Aria", "Scarlett",
25
+ "Penelope", "Layla", "Chloe", "Victoria", "Madison", "Eleanor",
26
+ "Grace", "Nora", "Riley", "Zoey"
27
+ ];
28
+ const lastNames = [
29
+ "Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller",
30
+ "Davis", "Rodriguez", "Martinez", "Hernandez", "Lopez", "Gonzalez",
31
+ "Wilson", "Anderson", "Thomas", "Taylor", "Moore", "Jackson", "Martin",
32
+ "Lee", "Perez", "Thompson", "White", "Harris", "Sanchez", "Clark",
33
+ "Ramirez", "Lewis", "Robinson"
34
+ ];
35
+ const gender = Math.random() > 0.5 ? 'm' : 'f';
36
+ const firstName = gender === 'm' ? maleNames[Math.floor(Math.random() * maleNames.length)] : femaleNames[Math.floor(Math.random() * femaleNames.length)];
37
+ const lastName = lastNames[Math.floor(Math.random() * lastNames.length)];
38
+ const name = `${firstName} ${lastName}`;
39
+ const email = `${firstName.toLowerCase()}.${lastName.toLowerCase()}@mailserver.com`;
40
+ const birthday = `${Math.floor(Math.random() * 100) + 1920}-${String(Math.floor(Math.random() * 12) + 1).padStart(2, '0')}-${String(Math.floor(Math.random() * 28) + 1).padStart(2, '0')}`;
41
+ const phoneNumber = `(${Math.floor(Math.random() * 900) + 100}) ${Math.floor(Math.random() * 900) + 100}-${Math.floor(Math.random() * 9000) + 1000}`;
42
+ return { name, email, birthday, phoneNumber, gender };
43
+ }
44
+ for (let i = 0; i < 100; i++) {
45
+ contacts.push(generateContact());
46
+ };
47
+ </script>
9
48
  </head>
10
49
  <body>
11
50
  <k-import src="../nav-1.inc.html"></k-import>
@@ -16,13 +55,17 @@
16
55
  >
17
56
  <summary class="p">Table of Contents</summary>
18
57
  <div class="m mt0 pl">
58
+ <h6>Examples</h6>
19
59
  <a href="#basicUsage">Basic Usage</a><br />
20
60
  <a href="#customFields">Custom Fields</a><br />
61
+ <a href="#topBottomControls">Top and Bottom Controls</a><br />
62
+ <a href="#rowControls">Row Controls</a><br />
63
+ <a href="#pagination">Pagination</a><br />
64
+ <h6 class="mt">JavaScript Reference</h6>
21
65
  <a href="#constructor">Constructor</a><br />
22
66
  <a href="#requirements">Requirements</a><br />
23
67
  <a href="#properties">Properties</a><br />
24
68
  <a href="#methods">Methods</a><br />
25
- <a href="#controls">Row Controls</a><br />
26
69
  </div>
27
70
  </details>
28
71
 
@@ -30,151 +73,207 @@
30
73
  <p>The <code>&lt;k-table></code> component is used to render data into a <code>&lt;table></code> using JavaScript.</p>
31
74
 
32
75
  <h3 id="basicUsage"><a href="#basicUsage" class="no-link">Basic Usage</a></h3>
33
- <p>In HTML create a <code>&lt;k-table></code>, and then in JavaScript call the <code>setData</code> method passing in an array of objects containing your data.</p>
76
+ <p>In HTML create a <code>&lt;k-table></code>, and then in JavaScript call the <code>setData</code> method passing in an options object containing your data.</p>
34
77
 
35
- <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-table</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"contacts"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">k-table</span>&gt;</span><br /><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span>&gt;</span><span class="javascript"><br /> <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'contacts'</span>).setData([<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">"Dustin"</span>,<br /> <span class="hljs-attr">phoneNumber</span>: <span class="hljs-string">"(111) 111-1111"</span>,<br /> <span class="hljs-attr">emailAddress</span>: <span class="hljs-string">"dustin@mailserver.com"</span>,<br /> <span class="hljs-attr">gender</span>: <span class="hljs-string">"Male"</span><br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">"Kayla"</span>,<br /> <span class="hljs-attr">phoneNumber</span>: <span class="hljs-string">"(222) 222-2222"</span>,<br /> <span class="hljs-attr">emailAddress</span>: <span class="hljs-string">"kayla@mailserver.com"</span>,<br /> <span class="hljs-attr">gender</span>: <span class="hljs-string">"Female"</span><br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">"Alexander"</span>,<br /> <span class="hljs-attr">phoneNumber</span>: <span class="hljs-string">"(333) 333-33333"</span>,<br /> <span class="hljs-attr">emailAddress</span>: <span class="hljs-string">"alex@mailserver.com"</span>,<br /> <span class="hljs-attr">gender</span>: <span class="hljs-string">"Male"</span><br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">"Amelia"</span>,<br /> <span class="hljs-attr">phoneNumber</span>: <span class="hljs-string">"(444) 444-44444"</span>,<br /> <span class="hljs-attr">emailAddress</span>: <span class="hljs-string">"amelia@mailserver.com"</span>,<br /> <span class="hljs-attr">gender</span>: <span class="hljs-string">"Female"</span><br /> },<br /> ]);<br /></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
36
- <script type="module" src="../kempo/components/Table.js"></script>
37
- <k-table id="contacts"></k-table>
78
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-table</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"basicUsageExample"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">k-table</span>&gt;</span><br /><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span>&gt;</span><span class="javascript"><br /> <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'basicUsageExample'</span>).setData({<br /> records: [<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">"Dustin"</span>,<br /> <span class="hljs-attr">phoneNumber</span>: <span class="hljs-string">"(111) 111-1111"</span>,<br /> <span class="hljs-attr">emailAddress</span>: <span class="hljs-string">"dustin@mailserver.com"</span>,<br /> <span class="hljs-attr">gender</span>: <span class="hljs-string">"Male"</span><br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">"Kayla"</span>,<br /> <span class="hljs-attr">phoneNumber</span>: <span class="hljs-string">"(222) 222-2222"</span>,<br /> <span class="hljs-attr">emailAddress</span>: <span class="hljs-string">"kayla@mailserver.com"</span>,<br /> <span class="hljs-attr">gender</span>: <span class="hljs-string">"Female"</span><br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">"Alexander"</span>,<br /> <span class="hljs-attr">phoneNumber</span>: <span class="hljs-string">"(333) 333-33333"</span>,<br /> <span class="hljs-attr">emailAddress</span>: <span class="hljs-string">"alex@mailserver.com"</span>,<br /> <span class="hljs-attr">gender</span>: <span class="hljs-string">"Male"</span><br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">"Amelia"</span>,<br /> <span class="hljs-attr">phoneNumber</span>: <span class="hljs-string">"(444) 444-44444"</span>,<br /> <span class="hljs-attr">emailAddress</span>: <span class="hljs-string">"amelia@mailserver.com"</span>,<br /> <span class="hljs-attr">gender</span>: <span class="hljs-string">"Female"</span><br /> },<br /> ]<br /> });<br /></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
79
+ <k-table id="basicUsageExample"></k-table>
38
80
  <script type="module">
39
- document.getElementById('contacts').setData([
40
- {
41
- name: "Dustin",
42
- phoneNumber: "(111) 111-1111",
43
- emailAddress: "dustin@mailserver.com",
44
- gender: "Male"
45
- },
46
- {
47
- name: "Kayla",
48
- phoneNumber: "(222) 222-2222",
49
- emailAddress: "kayla@mailserver.com",
50
- gender: "Female"
51
- },
52
- {
53
- name: "Alexander",
54
- phoneNumber: "(333) 333-33333",
55
- emailAddress: "alex@mailserver.com",
56
- gender: "Male"
57
- },
58
- {
59
- name: "Amelia",
60
- phoneNumber: "(444) 444-44444",
61
- emailAddress: "amelia@mailserver.com",
62
- gender: "Female"
63
- },
64
- ]);
81
+ document.getElementById('basicUsageExample').setData({
82
+ records: [
83
+ {
84
+ name: "Dustin",
85
+ phoneNumber: "(111) 111-1111",
86
+ emailAddress: "dustin@mailserver.com",
87
+ gender: "Male"
88
+ },
89
+ {
90
+ name: "Kayla",
91
+ phoneNumber: "(222) 222-2222",
92
+ emailAddress: "kayla@mailserver.com",
93
+ gender: "Female"
94
+ },
95
+ {
96
+ name: "Alexander",
97
+ phoneNumber: "(333) 333-33333",
98
+ emailAddress: "alex@mailserver.com",
99
+ gender: "Male"
100
+ },
101
+ {
102
+ name: "Amelia",
103
+ phoneNumber: "(444) 444-44444",
104
+ emailAddress: "amelia@mailserver.com",
105
+ gender: "Female"
106
+ },
107
+ ]
108
+ });
65
109
  </script>
66
110
 
67
111
  <h3 id="customFields"><a href="#customFields" class="no-link">Custom Fields</a></h3>
68
- <p>Use the second paramter of <code>setData</code> to define custom fields.</p>
69
- <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-table</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"movies"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">k-table</span>&gt;</span><br /><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span>&gt;</span><span class="javascript"><br /> <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'movies'</span>).setData([<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">'Good Will Hunting'</span>,<br /> <span class="hljs-attr">year</span>: <span class="hljs-number">1997</span>,<br /> <span class="hljs-attr">lead</span>: <span class="hljs-string">'Matt Damon'</span>,<br /> <span class="hljs-attr">budget</span>: <span class="hljs-number">10000000</span><br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">'A Few Good Men'</span>,<br /> <span class="hljs-attr">year</span>: <span class="hljs-number">1992</span>,<br /> <span class="hljs-attr">lead</span>: <span class="hljs-string">'Tom Cruise'</span>,<br /> <span class="hljs-attr">prod</span>: <span class="hljs-string">'Castle Rock Entertainment'</span><br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">'The Silence of the Lambs'</span>,<br /> <span class="hljs-attr">year</span>: <span class="hljs-number">1991</span>,<br /> <span class="hljs-attr">lead</span>: <span class="hljs-string">'Jodie Foster'</span>,<br /> <span class="hljs-attr">prequel</span>: <span class="hljs-string">'Red Dragon'</span><br /> }<br /> ],[<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">"name"</span>,<br /> <span class="hljs-attr">label</span>: <span class="hljs-string">"Name"</span><br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">'year'</span>,<br /> <span class="hljs-attr">label</span>: <span class="hljs-string">'Year'</span><br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">'prod'</span>,<br /> <span class="hljs-attr">label</span>: <span class="hljs-string">'Production Company'</span><br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">'lead'</span>,<br /> <span class="hljs-attr">label</span>: <span class="hljs-string">'Lead Actor / Actress'</span><br /> }<br /> ]);<br /></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
70
- <k-table id="movies"></k-table>
71
- <script type="module">
72
- document.getElementById('movies').setData([
73
- {
74
- name: 'Good Will Hunting',
75
- year: 1997,
76
- lead: 'Matt Damon',
77
- budget: 10000000
78
- },
79
- {
80
- name: 'A Few Good Men',
81
- year: 1992,
82
- lead: 'Tom Cruise',
83
- prod: 'Castle Rock Entertainment'
84
- },
85
- {
86
- name: 'The Silence of the Lambs',
87
- year: 1991,
88
- lead: 'Jodie Foster',
89
- prequel: 'Red Dragon'
90
- }
91
- ],[
92
- {
93
- name: "name",
94
- label: "Name"
95
- },
96
- {
97
- name: 'year',
98
- label: 'Year'
99
- },
100
- {
101
- name: 'prod',
102
- label: 'Production Company'
103
- },
104
- {
105
- name: 'lead',
106
- label: 'Lead Actor / Actress'
107
- }
108
- ]);
109
- </script>
110
-
111
- <h3 id="controls"><a href="#controls" class="no-link">Row Controls</a></h3>
112
- <p>The table component can display controls before or after each row. Each control is defined by an icon name, a callback function, and optionally an HTML string or a render function. All controls are combined into a single <code>&lt;td&gt;</code> with each control being a button.</p>
113
-
114
-
115
- <k-table id="contacts2"></k-table>
112
+ <p>Use the <code>fields</code> property of the options object in <code>setData</code> to define custom fields. This is useful for hiding fields, reordering fields, changing the labels, formatting the output, or creating a calculated field.</p>
113
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-table</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"customFieldsExample"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">k-table</span>&gt;</span><br /><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span>&gt;</span><span class="javascript"><br /> <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'customFieldsExample'</span>).setData({<br /> records: contacts.slice(<span class="hljs-number">0</span>,<span class="hljs-number">10</span>),<br /> fields: [<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">"name"</span>,<br /> <span class="hljs-attr">label</span>: <span class="hljs-string">"Name"</span><br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">'phoneNumber'</span>,<br /> <span class="hljs-attr">label</span>: <span class="hljs-string">'Phone Number'</span><br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">'email'</span>,<br /> <span class="hljs-attr">label</span>: <span class="hljs-string">'Email Address'</span><br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">'birthday'</span>,<br /> <span class="hljs-attr">label</span>: <span class="hljs-string">'Birthday'</span><br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">'age'</span>,<br /> <span class="hljs-attr">label</span>: <span class="hljs-string">'Age'</span>,<br /> <span class="hljs-attr">calculator</span>: <span class="hljs-function">(<span class="hljs-params">record</span>) =&gt;</span> {<br /> <span class="hljs-comment">// record.birthday is a string in the format "YYYY-MM-DD"</span><br /> <span class="hljs-keyword">const</span> today = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>();<br /> <span class="hljs-keyword">const</span> birthDate = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(record.birthday);<br /> <span class="hljs-keyword">let</span> age = today.getFullYear() - birthDate.getFullYear();<br /> <span class="hljs-keyword">const</span> monthDifference = today.getMonth() - birthDate.getMonth();<br /> <span class="hljs-keyword">if</span> (monthDifference &lt; <span class="hljs-number">0</span> || (monthDifference === <span class="hljs-number">0</span> &amp;&amp; today.getDate() &lt; birthDate.getDate())) {<br /> age--;<br /> }<br /> <span class="hljs-keyword">return</span> age;<br /> }<br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">'gender'</span>,<br /> <span class="hljs-attr">label</span>: <span class="hljs-string">'Gender'</span>,<br /> <span class="hljs-attr">formatter</span>: <span class="hljs-function">(<span class="hljs-params">v</span>) =&gt;</span> v===<span class="hljs-string">'m'</span>?<span class="hljs-string">'Male'</span>:<span class="hljs-string">'Female'</span> <span class="hljs-comment">// original value is "m" or "f"</span><br /> }<br /> ]<br /> });<br /></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
114
+ <k-table id="customFieldsExample"></k-table>
116
115
  <script type="module">
117
- document.getElementById('contacts2').setData([
118
- {
119
- name: "Dustin",
120
- phoneNumber: "(111) 111-1111",
121
- emailAddress: "dustin@mailserver.com",
122
- gender: "Male"
123
- },
124
- {
125
- name: "Kayla",
126
- phoneNumber: "(222) 222-2222",
127
- emailAddress: "kayla@mailserver.com",
128
- gender: "Female"
129
- }
130
- ], false, {
131
- before: [
116
+ document.getElementById('customFieldsExample').setData({
117
+ records: contacts.slice(0,10),
118
+ fields: [
132
119
  {
133
- icon: 'edit',
134
- action: (table, record) => console.log('Edit', table, record)
135
- }
136
- ],
137
- after: [
120
+ name: "name",
121
+ label: "Name"
122
+ },
138
123
  {
139
- icon: 'delete',
140
- action: (table, record) => console.log('Delete', table, record)
124
+ name: 'phoneNumber',
125
+ label: 'Phone Number'
141
126
  },
142
127
  {
143
- html: '<span>Custom HTML</span>'
128
+ name: 'email',
129
+ label: 'Email Address'
144
130
  },
145
131
  {
146
- render: (table, record) => `<a href="mailto:${record.emailAddress}">Email</a>`
147
- }
148
- ],
149
- top: [
132
+ name: 'birthday',
133
+ label: 'Birthday'
134
+ },
150
135
  {
151
- icon: 'add',
152
- action: (table) => console.log('Add', table)
153
- }
154
- ],
155
- bottom: [
136
+ name: 'age',
137
+ label: 'Age',
138
+ calculator: (record) => {
139
+ // record.birthday is a string in the format "YYYY-MM-DD"
140
+ const today = new Date();
141
+ const birthDate = new Date(record.birthday);
142
+ let age = today.getFullYear() - birthDate.getFullYear();
143
+ const monthDifference = today.getMonth() - birthDate.getMonth();
144
+ if (monthDifference < 0 || (monthDifference === 0 && today.getDate() < birthDate.getDate())) {
145
+ age--;
146
+ }
147
+ return age;
148
+ }
149
+ },
156
150
  {
157
- icon: 'refresh',
158
- action: (table) => console.log('Refresh', table)
151
+ name: 'gender',
152
+ label: 'Gender',
153
+ formatter: (v) => v==='m'?'Male':'Female' // original value is "m" or "f"
159
154
  }
160
155
  ]
161
156
  });
162
157
  </script>
163
158
 
164
- <h3 id="constructor"><a href="#consttructor" class="no-link">Constructor</a></h3>
159
+ <h3 id="topBottomControls"><a href="#topBottomControls" class="no-link">Top and Bottom Controls</a></h3>
160
+ <p>The table component can display controls at the top and bottom of the table. These controls can be used for pagination, adding new records, or any other actions. Each control is defined by an icon name, a callback function, and optionally an HTML string or a render function.</p>
161
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-table</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"topBottomControlsExample"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">k-table</span>&gt;</span><br /><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span>&gt;</span><span class="javascript"><br /> <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'topBottomControlsExample'</span>).setData({<br /> records: contacts.slice(<span class="hljs-number">10</span>, <span class="hljs-number">20</span>),<br /> controls: {<br /> <span class="hljs-attr">top</span>: [<br /> {<br /> <span class="hljs-attr">icon</span>: <span class="hljs-string">'add'</span>,<br /> <span class="hljs-attr">action</span>: <span class="hljs-function">(<span class="hljs-params">table</span>) =&gt;</span> table.addRecord(generateContact())<br /> }<br /> ],<br /> <span class="hljs-attr">bottom</span>: [<br /> {<br /> <span class="hljs-attr">icon</span>: <span class="hljs-string">'refresh'</span>,<br /> <span class="hljs-attr">action</span>: <span class="hljs-function">(<span class="hljs-params">table</span>) =&gt;</span> {<br /> contacts = contacts.sort(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> <span class="hljs-built_in">Math</span>.random() - <span class="hljs-number">0.5</span>);<br /> table.setRecords(contacts.slice(<span class="hljs-number">0</span>, <span class="hljs-number">10</span>));<br /> }<br /> }<br /> ]<br /> }<br /> });<br /></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
162
+ <k-table id="topBottomControlsExample"></k-table>
163
+ <script type="module">
164
+ document.getElementById('topBottomControlsExample').setData({
165
+ records: contacts.slice(10, 20),
166
+ controls: {
167
+ top: [
168
+ {
169
+ icon: 'add',
170
+ action: (table) => table.addRecord(generateContact())
171
+ }
172
+ ],
173
+ bottom: [
174
+ {
175
+ icon: 'refresh',
176
+ action: (table) => {
177
+ contacts = contacts.sort(() => Math.random() - 0.5);
178
+ table.setRecords(contacts.slice(0, 10));
179
+ }
180
+ }
181
+ ]
182
+ }
183
+ });
184
+ </script>
185
+
186
+ <h3 id="rowControls"><a href="#rowControls" class="no-link">Row Controls</a></h3>
187
+ <p>The table component can display controls before or after each row. Each control is defined by an icon name, a callback function, and optionally an HTML string or a render function.</p>
188
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-table</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"rowControlsExample"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">k-table</span>&gt;</span><br /><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span>&gt;</span><span class="javascript"><br /> <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'rowControlsExample'</span>).setData({<br /> records: contacts.slice(20, 25),<br /> controls: {<br /> <span class="hljs-attr">before</span>: [<br /> {<br /> <span class="hljs-attr">html</span>: <span class="hljs-string">'&lt;span&gt;Custom HTML&lt;/span&gt; '</span><br /> },<br /> {<br /> <span class="hljs-attr">render</span>: <span class="hljs-function">(<span class="hljs-params">table, record</span>) =&gt;</span> {<br /> <span class="hljs-keyword">return</span> <span class="hljs-string">`&lt;button onclick="alert('<span class="hljs-subst">${record.name}</span>')"&gt;Alert&lt;/button&gt;`</span>;<br /> }<br /> }<br /> ],<br /> <span class="hljs-attr">after</span>: [<br /> {<br /> <span class="hljs-attr">icon</span>: <span class="hljs-string">'edit'</span>,<br /> <span class="hljs-attr">action</span>: <span class="hljs-function">(<span class="hljs-params">table, record, index</span>) =&gt;</span> {<br /> <span class="hljs-keyword">const</span> newName = prompt(<span class="hljs-string">"Enter a new name:"</span>, record.name);<br /> <span class="hljs-keyword">if</span> (newName) {<br /> record.name = newName;<br /> table.updateRecord(index, record);<br /> }<br /> }<br /> },<br /> {<br /> <span class="hljs-attr">icon</span>: <span class="hljs-string">'delete'</span>,<br /> <span class="hljs-attr">action</span>: <span class="hljs-function">(<span class="hljs-params">table, record, index</span>) =&gt;</span> {<br /> table.deleteRecord(index);<br /> }<br /> }<br /> ]<br /> }<br /> });<br /></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
189
+ <k-table id="rowControlsExample"></k-table>
190
+ <script type="module">
191
+ document.getElementById('rowControlsExample').setData({
192
+ records: contacts.slice(20, 25),
193
+ controls: {
194
+ before: [
195
+ {
196
+ html: '<span>Custom HTML</span> '
197
+ },
198
+ {
199
+ render: (table, record) => {
200
+ return `<button onclick="alert('${record.name}')">Alert</button>`;
201
+ }
202
+ }
203
+ ],
204
+ after: [
205
+ {
206
+ icon: 'edit',
207
+ action: (table, record, index) => {
208
+ const newName = prompt("Enter a new name:", record.name);
209
+ if (newName) {
210
+ record.name = newName;
211
+ table.updateRecord(index, record);
212
+ }
213
+ }
214
+ },
215
+ {
216
+ icon: 'delete',
217
+ action: (table, record, index) => {
218
+ table.deleteRecord(index);
219
+ }
220
+ }
221
+ ]
222
+ }
223
+ });
224
+ </script>
225
+
226
+
227
+ <h3 id="pagination"><a href="#pagination" class="no-link">Pagination</a></h3>
228
+ <p>The table component supports pagination. You can set the page size and navigate through pages using the provided methods.</p>
229
+ <p>There are some predefined controls that you can use directly from <code>Table.controls</code>. These controls include:</p>
230
+ <ul>
231
+ <li><code>prevPage</code>: A control to navigate to the previous page.</li>
232
+ <li><code>nextPage</code>: A control to navigate to the next page.</li>
233
+ <li><code>pageSelect</code>: A control to select a specific page.</li>
234
+ <li><code>spacer</code>: A spacer that flexes to separate the other controls to before it to the left, and after it to the far right.</li>
235
+ <li><code>pageSize</code>: A control to select the number of records per page.</li>
236
+ </ul>
237
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-table</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"paginationExample"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">k-table</span>&gt;</span><br /><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span>&gt;</span><span class="javascript"><br /> <span class="hljs-keyword">import</span> Table <span class="hljs-keyword">from</span> <span class="hljs-string">'../kempo/components/Table.js'</span>;<br /> <span class="hljs-keyword">const</span> $paginationExample = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'paginationExample'</span>);<br /> $paginationExample.setData({<br /> <span class="hljs-attr">records</span>: contacts,<br /> <span class="hljs-attr">controls</span>: {<br /> <span class="hljs-attr">bottom</span>: [<br /> Table.controls.prevPage,<br /> Table.controls.nextPage,<br /> Table.controls.pageSelect,<br /> Table.controls.spacer,<br /> Table.controls.pageSize<br /> ]<br /> },<br /> <span class="hljs-attr">pageSize</span>: <span class="hljs-number">10</span>,<br /> <span class="hljs-attr">pageSizeOptions</span>: [<span class="hljs-number">5</span>, <span class="hljs-number">10</span>, <span class="hljs-number">20</span>]<br /> });<br /></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
238
+ <k-table id="paginationExample"></k-table>
239
+ <script type="module">
240
+ import Table from '../kempo/components/Table.js';
241
+ const $paginationExample = document.getElementById('paginationExample');
242
+ $paginationExample.setData({
243
+ records: contacts,
244
+ controls: {
245
+ bottom: [
246
+ Table.controls.prevPage,
247
+ Table.controls.nextPage,
248
+ Table.controls.pageSelect,
249
+ Table.controls.spacer,
250
+ Table.controls.pageSize
251
+ ]
252
+ },
253
+ pageSize: 10,
254
+ pageSizeOptions: [5, 10, 20]
255
+ });
256
+ </script>
257
+
258
+
259
+ <h2>JavaScript Reference</h2>
260
+ <h3 id="constructor"><a href="#constructor" class="no-link">Constructor</a></h3>
165
261
  <h6>Extends <a href="./component.html">Component</a></h6>
166
262
  <h5>
167
263
  <code>new Table()</code><br />
168
- <code>new Table(<i>&lt;Array>object</i> records)</code><br />
169
- <code>new Table(<i>&lt;Array>object</i> records, <i>&lt;Array>object</i> fields)</code>
264
+ <code>new Table(<i>&lt;Array>object</i> options)</code>
170
265
  </h5>
171
266
 
172
- <h4>Paramters</h4>
173
- <h5><code><i>&lt;Array>object</i> records</code></h5>
174
- <p>An array of objects that represent the records to be shown in the table.</p>
175
-
176
- <h5><code><i>&lt;Array>object</i> fields</code></h5>
177
- <p>An array of objects that represents the feilds of the table, each object must contain a <code>name</code> and a <code>label</code>. If this parameter is ommitted the fields will be automatically generated from the first 100 records.</p>
267
+ <h4>Parameters</h4>
268
+ <h5><code><i>object</i> options</code></h5>
269
+ <p>An object containing the initial configuration for the table. The options object can contain the following properties:</p>
270
+ <ul>
271
+ <li><code>records</code>: An array of objects representing the records to be shown in the table.</li>
272
+ <li><code>fields</code>: An array of objects representing the fields of the table, each object must contain a <code>name</code> and a <code>label</code>. If this property is omitted, the fields will be automatically generated from the first 100 records.</li>
273
+ <li><code>controls</code>: An object containing optional arrays of controls to be displayed before and/or after each row. Each control is defined by an icon name, a callback function, and optionally an HTML string or a render function. The <code>controls</code> object can contain the optional <code>before</code> and <code>after</code> properties, which are arrays of objects containing the <code>icon</code> (string), <code>action</code> (function), <code>html</code> (string), and <code>render</code> (function). If <code>html</code> is present, it overrides the icon and is rendered in its place. If <code>render</code> is present, it is used to render the control.</li>
274
+ <li><code>pageSize</code>: The number of records to display per page.</li>
275
+ <li><code>pageSizeOptions</code>: An array of numbers representing the available page size options.</li>
276
+ </ul>
178
277
 
179
278
  <h3 id="requirements"><a href="#requirements" class="no-link">Requirements</a></h3>
180
279
  <ul>
@@ -183,49 +282,58 @@
183
282
 
184
283
  <h3 id="properties"><a href="#properties" class="no-link">Properties</a></h3>
185
284
  <h5><code>fields<i>: &lt;Array>object</i></code></h5>
186
- <p>An array of objects containing a <code>name</code> and <code>label</code> that represent the fields to be displayed.</p>
285
+ <p>An array of objects containing a <code>name</code>, <code>label</code>, <code>renderer</code> function, and <code>calculator</code> function that represent the fields to be displayed. The <code>renderer</code> function can be used to customize the display of the field, and the <code>calculator</code> function can be used to calculate the value of the field based on other fields in the record.</p>
187
286
 
188
287
  <h5><code>records<i>: &lt;Array>object</i></code></h5>
189
288
  <p>An array of objects containing the data that will be the records of the table, where the object keys match the field names.</p>
190
289
 
191
- <h5><code><i>object</i> controls</code></h5>
192
- <p>An object containing optional arrays of controls to be displayed before and/or after each row. Each control is defined by an icon name, a callback function, and optionally an HTML string or a render function. The <code>controls</code> object can contain the optional <code>before</code> and <code>after</code> properties, which are arrays of objects containing the <code>icon</code> (string), <code>action</code> (function), <code>html</code> (string), and <code>render</code> (function). If <code>html</code> is present, it overrides the icon and is rendered in its place. If <code>render</code> is present, it is used to render the control.</p>
193
- <p>Example:</p>
194
- <pre><code class="hljs javascript">{
195
- before: [
196
- {
197
- icon: 'edit',
198
- action: (record, table) => console.log('Edit', record, table)
199
- }
200
- ],
201
- after: [
202
- {
203
- icon: 'delete',
204
- action: (record, table) => console.log('Delete', record, table)
205
- },
206
- {
207
- html: '<span>Custom HTML</span>'
208
- },
209
- {
210
- render: (record, table) => `&lt;button onclick="console.log('Rendered Action', ${record}, ${table})">Rendered Button&lt;/button>`
211
- }
212
- ]
213
- }</code></pre>
290
+ <h5><code>controls<i>: object</i></code></h5>
291
+ <p>An object containing optional arrays of controls to be displayed before and/or after each row, or above and below the table. Each control is defined by an icon name, a callback function, and optionally an HTML string or a render function. The <code>controls</code> object can contain the optional <code>before</code>, <code>after</code>, <code>top</code>, and <code>bottom</code> properties, which are arrays of objects containing the <code>icon</code> (string), <code>action</code> (function), <code>html</code> (string), and <code>render</code> (function). If <code>html</code> is present, it overrides the icon and is rendered in its place. If <code>render</code> is present, it is used to render the control. Controls in the <code>before</code> or <code>after</code> arrays receive the record and index as the 2nd and 3rd parameters in the action function and the renderer function.</p>
292
+
293
+ <h5><code>pageSize<i>: number</i></code></h5>
294
+ <p>The number of records to display per page.</p>
295
+
296
+ <h5><code>pageSizeOptions<i>: &lt;Array>number</i></code></h5>
297
+ <p>An array of numbers representing the available page size options.</p>
214
298
 
215
299
  <h3 id="methods"><a href="#methods" class="no-link">Methods</a></h3>
216
300
 
217
- <h5><code>setData(<i>&lt;Array>object</i> records, <i>&lt;Array>object</i> fields)<i>: undefined</i></code></h5>
218
- <p>Sets the records and the fields and renders the table, if no fields are provided then they will be automatically generated from the keys of the first 100 records.</p>
301
+ <h5><code>setData(<i>object</i> options)<i>: undefined</i></code></h5>
302
+ <p>Sets the records and the fields and renders the table. If no fields are provided, they will be automatically generated from the keys of the first 100 records. The options object can contain the following properties:</p>
303
+ <ul>
304
+ <li><code>records</code>: An array of objects representing the records to be shown in the table.</li>
305
+ <li><code>fields</code>: An array of objects representing the fields of the table, each object must contain a <code>name</code> and a <code>label</code>. If this property is omitted, the fields will be automatically generated from the first 100 records.</li>
306
+ <li><code>controls</code>: An object containing optional arrays of controls to be displayed before and/or after each row. Each control is defined by an icon name, a callback function, and optionally an HTML string or a render function. The <code>controls</code> object can contain the optional <code>before</code> and <code>after</code> properties, which are arrays of objects containing the <code>icon</code> (string), <code>action</code> (function), <code>html</code> (string), and <code>render</code> (function). If <code>html</code> is present, it overrides the icon and is rendered in its place. If <code>render</code> is present, it is used to render the control.</li>
307
+ <li><code>pageSize</code>: The number of records to display per page.</li>
308
+ <li><code>pageSizeOptions</code>: An array of numbers representing the available page size options.</li>
309
+ </ul>
219
310
 
220
311
  <h5><code>renderFields()<i>: undefined</i></code></h5>
221
- <p>Renders the fields as table headers, this is called automatically by setData, you should never have to call it.</p>
312
+ <p>Renders the fields as table headers. This is called automatically by setData, you should never have to call it.</p>
222
313
 
223
314
  <h5><code>renderRecords()<i>: undefined</i></code></h5>
224
- <p>Renders the records as table row, this is called automatically by setData, you should never have to call it.</p>
315
+ <p>Renders the records as table rows. This is called automatically by setData, you should never have to call it.</p>
316
+
317
+ <h5><code>addRecord(<i>object</i> record)<i>: undefined</i></code></h5>
318
+ <p>Adds a new record to the table.</p>
319
+
320
+ <h5><code>updateRecord(<i>number</i> index, <i>object</i> record)<i>: undefined</i></code></h5>
321
+ <p>Updates an existing record at the specified index.</p>
322
+
323
+ <h5><code>deleteRecord(<i>number</i> index)<i>: undefined</i></code></h5>
324
+ <p>Deletes a record at the specified index.</p>
325
+
326
+ <h5><code>setRecords(<i>Array</i> records)<i>: undefined</i></code></h5>
327
+ <p>Sets the records for the table and re-renders the rows.</p>
328
+
329
+ <h5><code>setPageSize(<i>number</i> pageSize)<i>: undefined</i></code></h5>
330
+ <p>Sets the number of records to display per page.</p>
331
+
332
+ <h5><code>goToPage(<i>number</i> pageNumber)<i>: undefined</i></code></h5>
333
+ <p>Navigates to the specified page number.</p>
225
334
 
226
335
  </main>
227
336
  <div style="height: 33.333vh"></div>
228
337
  <script type="module" src="../kempo/components/Import.js"></script>
229
-
230
338
  </body>
231
339
  </html>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="currentColor" d="M440-440H200v-80h240v-240h80v240h240v80H520v240h-80v-240Z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="currentColor" d="m313-440 224 224-57 56-320-320 320-320 57 56-224 224h487v80H313Z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="currentColor" d="M647-440H160v-80h487L423-744l57-56 320 320-320 320-57-56 224-224Z"/></svg>