kempo-ui 0.0.78 → 0.0.79
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.
- package/.github/skills/highlight-code/SKILL.md +17 -30
- package/bin/highlight_code.js +34 -7
- package/dist/components/Table.js +35 -2
- package/dist/components/tableControls/DeleteSelected.js +7 -0
- package/docs/components/table.html +2 -1
- package/docs/components/tableServerSync.html +143 -0
- package/docs/icons/delete_sweep.svg +1 -0
- package/docs/src/components/Table.js +35 -2
- package/docs/src/components/tableControls/DeleteSelected.js +7 -0
- package/icons/delete_sweep.svg +1 -0
- package/package.json +2 -1
- package/src/components/Table.js +135 -68
- package/src/components/tableControls/DeleteSelected.js +27 -0
|
@@ -11,47 +11,34 @@ Use this skill whenever you need syntax-highlighted HTML to embed in a documenta
|
|
|
11
11
|
|
|
12
12
|
## Usage
|
|
13
13
|
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
Or via npx:
|
|
19
|
-
```bash
|
|
20
|
-
npx kempo-highlightcode <lang> "<code>"
|
|
14
|
+
```powershell
|
|
15
|
+
node bin/highlight_code.js <lang> <code>
|
|
21
16
|
```
|
|
22
17
|
|
|
23
18
|
**Supported languages:** `html`, `css`, `js` / `javascript`, `ts` / `typescript`, `json`, `md` / `markdown`, `sh` / `bash`, `xml`
|
|
24
19
|
|
|
25
20
|
## Output
|
|
26
21
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
## Example
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
npm run highlightcode -- html "<p>Hello World</p>"
|
|
33
|
-
```
|
|
22
|
+
Prints the inner highlighted content (hljs spans, no `<pre><code>` wrapper) to stdout, with `<br>` tags instead of newlines — a single line suitable for embedding in HTML.
|
|
34
23
|
|
|
35
|
-
|
|
36
|
-
```
|
|
37
|
-
<span class="hljs-tag"><<span class="hljs-name">p</span>></span>Hello World<span class="hljs-tag"></<span class="hljs-name">p</span>></span>
|
|
38
|
-
```
|
|
24
|
+
Input is automatically beautified before highlighting, so you can pass minified code.
|
|
39
25
|
|
|
40
|
-
##
|
|
26
|
+
## Workflow for Updating Doc Code Samples
|
|
41
27
|
|
|
42
|
-
|
|
28
|
+
Run the script with minified code as a single argument, capture to `$hl`, then use PowerShell's `.Replace()` to patch the HTML file:
|
|
43
29
|
|
|
44
30
|
```powershell
|
|
45
|
-
$
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
"@
|
|
50
|
-
node bin/highlight_code.js js $code
|
|
31
|
+
$hl = node bin/highlight_code.js xml "<k-table id=myExample></k-table><script type=module>doSomething('foo');</script>"
|
|
32
|
+
$html = [System.IO.File]::ReadAllText((Resolve-Path 'docs/components/my-component.html'))
|
|
33
|
+
$old = [regex]::Match($html, '(?s)<pre><code class="hljs xml">.*?</code></pre>').Value
|
|
34
|
+
[System.IO.File]::WriteAllText((Resolve-Path 'docs/components/my-component.html'), $html.Replace($old, "<pre><code class=`"hljs xml`">$hl</code></pre>"))
|
|
51
35
|
```
|
|
52
36
|
|
|
53
|
-
##
|
|
37
|
+
## Important Notes
|
|
54
38
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
39
|
+
- Use **outer double-quotes** for the PowerShell argument string, and **single-quotes** for JS string literals inside. This preserves all quoting correctly through to node.
|
|
40
|
+
- HTML attribute values should be **unquoted** in the argument (`id=foo` not `id="foo"`) — the beautifier adds consistent formatting anyway.
|
|
41
|
+
- Use `[System.IO.File]::ReadAllText` / `WriteAllText` + `.Replace()` (not `-replace`) to avoid regex interpretation of the replacement string.
|
|
42
|
+
- If a page has multiple `<pre><code>` blocks, adjust the regex to match the specific one (e.g. match by a nearby unique string, or loop with an index).
|
|
43
|
+
- The beautifier handles indentation and formatting automatically.
|
|
44
|
+
- Output uses `<br>` instead of `\n`, keeping the block on one line in the HTML source.
|
package/bin/highlight_code.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { highlight } from '../tools/highlight.js';
|
|
3
|
+
import beautify from 'js-beautify';
|
|
3
4
|
|
|
4
5
|
const LANG_ALIASES = {
|
|
5
6
|
js: 'javascript',
|
|
@@ -16,11 +17,17 @@ const LANG_ALIASES = {
|
|
|
16
17
|
markdown: 'markdown'
|
|
17
18
|
};
|
|
18
19
|
|
|
20
|
+
const BEAUTIFY_OPTIONS = {
|
|
21
|
+
indent_size: 2,
|
|
22
|
+
wrap_line_length: 0,
|
|
23
|
+
preserve_newlines: false,
|
|
24
|
+
max_preserve_newlines: 0
|
|
25
|
+
};
|
|
26
|
+
|
|
19
27
|
const args = process.argv.slice(2);
|
|
20
28
|
|
|
21
|
-
if(args.length <
|
|
22
|
-
console.error('Usage:
|
|
23
|
-
console.error('Example: kempo-highlightcode html "<p>Hello World</p>"');
|
|
29
|
+
if(args.length < 1){
|
|
30
|
+
console.error('Usage: node bin/highlight_code.js <lang> <code>');
|
|
24
31
|
process.exit(1);
|
|
25
32
|
}
|
|
26
33
|
|
|
@@ -33,7 +40,27 @@ if(!lang){
|
|
|
33
40
|
process.exit(1);
|
|
34
41
|
}
|
|
35
42
|
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
const beautifyCode = (code) => {
|
|
44
|
+
const fns = { javascript: beautify.js, css: beautify.css, html: beautify.html, xml: beautify.html };
|
|
45
|
+
const fn = fns[lang] || beautify.js;
|
|
46
|
+
return fn(code, BEAUTIFY_OPTIONS);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const run = (code) => {
|
|
50
|
+
const formatted = beautifyCode(code);
|
|
51
|
+
const full = highlight(formatted, lang);
|
|
52
|
+
process.stdout.write(
|
|
53
|
+
full
|
|
54
|
+
.replace(/^<pre><code class="hljs [^"]*">/, '')
|
|
55
|
+
.replace(/<\/code><\/pre>\n?$/, '')
|
|
56
|
+
.replace(/\n/g, '<br>') + '\n'
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
if(rest.length > 0){
|
|
61
|
+
run(rest.join(' '));
|
|
62
|
+
} else {
|
|
63
|
+
const chunks = [];
|
|
64
|
+
process.stdin.on('data', chunk => chunks.push(chunk));
|
|
65
|
+
process.stdin.on('end', () => run(chunks.join('')));
|
|
66
|
+
}
|
package/dist/components/Table.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{html,css,unsafeStatic,literal}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";import{toTitleCase}from"../utils/string.js";import{boolExists}from"../utils/propConverters.js";const selected=Symbol("selected"),hidden=Symbol("hidden"),index=Symbol("index"),editing=Symbol("editing");export default class Table extends ShadowComponent{static properties={enablePages:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-pages"},pageSize:{type:Number,reflect:!0,attribute:"page-size"},currentPage:{type:Number,reflect:!0,attribute:"current-page"},pageSizeOptions:{type:Array,attribute:"page-size-options"},enableSelection:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-selection"},enableSorting:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-sorting"},caseSensitiveFilters:{type:Boolean,reflect:!0,converter:boolExists,attribute:"case-sensitive-filters"},fields:{type:Array},records:{type:Array},filters:{type:Array},sort:{type:Array},columnSizes:{type:Object},fetchPending:{type:Boolean}};constructor(e={}){super(),void 0===this.pageSize&&(this.pageSize=50),void 0===this.currentPage&&(this.currentPage=1),void 0===this.pageSizeOptions&&(this.pageSizeOptions=[10,25,50,100,500]),void 0===this.records&&(this.records=e.records||[]),void 0===this.fields&&(this.fields=e.fields||[]),void 0===this.filters&&(this.filters=e.filters||[]),void 0===this.sort&&(this.sort=[]),void 0===this.columnSizes&&(this.columnSizes={}),void 0===this.fetchPending&&(this.fetchPending=!1)}handleSelectAllChange=e=>{e.target.checked?this.selectAllOnPage():this.deselectAllOnPage()};handleFieldClick=e=>{const t=this.sort.find(t=>t.name===e),s=!t||!t.asc;this.sortBy(e,s)};handleRecordSelectionChange=(e,t)=>{e[selected]=!!t.target.checked,this.requestUpdate(),this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0}))};firstUpdated(){this.setData({records:this.records,fields:this.fields,filters:this.filters})}childrenUpdated(){this.requestUpdate()}updated(e){if(super.updated(e),this.enableSelection){const e=this.shadowRoot.getElementById("select-all");e&&(e.checked=this.allOnPageSelected())}}renderColgroupTemplate(){const e=[];return this.enableSelection&&e.push(html`<col style="width: 40px" />`),this.hasBeforeControls()&&e.push(html`<col style="width: ${this.columnSizes.beforeControls}px" />`),this.fields.forEach(({size:t,hidden:s})=>{s||e.push(t?html`<col style="width: ${t}px" />`:html`<col />`)}),this.hasAfterControls()&&e.push(html`<col style="width: ${this.columnSizes.afterControls}px" />`),e}getColumnCount(){let e=0;return this.enableSelection&&e++,this.hasBeforeControls()&&e++,this.fields.forEach(({hidden:t})=>{t||e++}),this.hasAfterControls()&&e++,e}renderFieldsTemplate(){const e=[];return this.enableSelection&&e.push(html`
|
|
1
|
+
import{html,css,unsafeStatic,literal}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";import{toTitleCase}from"../utils/string.js";import{boolExists}from"../utils/propConverters.js";const selected=Symbol("selected"),hidden=Symbol("hidden"),index=Symbol("index"),editing=Symbol("editing");export default class Table extends ShadowComponent{static properties={enablePages:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-pages"},pageSize:{type:Number,reflect:!0,attribute:"page-size"},currentPage:{type:Number,reflect:!0,attribute:"current-page"},pageSizeOptions:{type:Array,attribute:"page-size-options"},enableSelection:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-selection"},enableSorting:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-sorting"},caseSensitiveFilters:{type:Boolean,reflect:!0,converter:boolExists,attribute:"case-sensitive-filters"},requestEdit:{type:Boolean,reflect:!0,converter:boolExists,attribute:"request-edit"},requestDelete:{type:Boolean,reflect:!0,converter:boolExists,attribute:"request-delete"},fields:{type:Array},records:{type:Array},filters:{type:Array},sort:{type:Array},columnSizes:{type:Object},fetchPending:{type:Boolean}};constructor(e={}){super(),void 0===this.pageSize&&(this.pageSize=50),void 0===this.currentPage&&(this.currentPage=1),void 0===this.pageSizeOptions&&(this.pageSizeOptions=[10,25,50,100,500]),void 0===this.records&&(this.records=e.records||[]),void 0===this.fields&&(this.fields=e.fields||[]),void 0===this.filters&&(this.filters=e.filters||[]),void 0===this.sort&&(this.sort=[]),void 0===this.columnSizes&&(this.columnSizes={}),void 0===this.fetchPending&&(this.fetchPending=!1),void 0===this.requestEdit&&(this.requestEdit=!1),void 0===this.requestDelete&&(this.requestDelete=!1)}handleSelectAllChange=e=>{e.target.checked?this.selectAllOnPage():this.deselectAllOnPage()};handleFieldClick=e=>{const t=this.sort.find(t=>t.name===e),s=!t||!t.asc;this.sortBy(e,s)};handleRecordSelectionChange=(e,t)=>{e[selected]=!!t.target.checked,this.requestUpdate(),this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0}))};firstUpdated(){this.setData({records:this.records,fields:this.fields,filters:this.filters})}childrenUpdated(){this.requestUpdate()}updated(e){if(super.updated(e),this.enableSelection){const e=this.shadowRoot.getElementById("select-all");e&&(e.checked=this.allOnPageSelected())}}renderColgroupTemplate(){const e=[];return this.enableSelection&&e.push(html`<col style="width: 40px" />`),this.hasBeforeControls()&&e.push(html`<col style="width: ${this.columnSizes.beforeControls}px" />`),this.fields.forEach(({size:t,hidden:s})=>{s||e.push(t?html`<col style="width: ${t}px" />`:html`<col />`)}),this.hasAfterControls()&&e.push(html`<col style="width: ${this.columnSizes.afterControls}px" />`),e}getColumnCount(){let e=0;return this.enableSelection&&e++,this.hasBeforeControls()&&e++,this.fields.forEach(({hidden:t})=>{t||e++}),this.hasAfterControls()&&e++,e}renderFieldsTemplate(){const e=[];return this.enableSelection&&e.push(html`
|
|
2
2
|
<th class="controls field-select">
|
|
3
3
|
<input type="checkbox" id="select-all" @change=${this.handleSelectAllChange} />
|
|
4
4
|
</th>
|
|
@@ -40,7 +40,7 @@ import{html,css,unsafeStatic,literal}from"../lit-all.min.js";import ShadowCompon
|
|
|
40
40
|
<td class="cell controls controls-after">
|
|
41
41
|
${e}
|
|
42
42
|
</td>
|
|
43
|
-
`}hasBeforeControls(){return!!this.querySelector('[slot="before"]')}hasAfterControls(){return!!this.querySelector('[slot="after"]')}hasTopControls(){return!!this.querySelector('[slot="top"]')}hasBottomControls(){return!!this.querySelector(":scope > :not([slot])")}editRecord(e){e[editing]=!0;const t=this.shadowRoot.querySelector(`.record[data-index="${e[index]}"]`);t&&(t.classList.add("editing"),t.setAttribute("editing","true"),t.querySelectorAll(".cell[data-field]").forEach(t=>{const s=t.dataset.field,i=this.fields.find(e=>e.name===s);if(i){const r=e[s]||"";if(t.innerHTML="",i.calculator){const s=document.createElement("input");s.disabled=!0,s.value=i.calculator(e,this),t.appendChild(s)}else if(i.editor)t.appendChild(i.editor(r));else{const e=i.type||typeof r,s=Table.editors[e]||Table.editors.string;t.appendChild(s(r))}}})),this.dispatchEvent(new CustomEvent("editingChange",{detail:{record:e,editing:!0},bubbles:!0}))}saveEditedRecord(e){const t=this.shadowRoot.querySelector(`.record[data-index="${e[index]}"]`);t&&(t.querySelectorAll(".cell[data-field]").forEach(t=>{const s=t.dataset.field,i=this.fields.find(e=>e.name===s);if(i&&!i.calculator){const i=t.querySelector("input, select");i&&(e[s]=i.value)}}),e[editing]=!1,t.classList.remove("editing"),t.removeAttribute("editing"),t.querySelectorAll(".cell[data-field]").forEach(t=>{const s=t.dataset.field,i=this.fields.find(e=>e.name===s);if(i){const r=e[s]||"";i.calculator?t.textContent=i.calculator(e,this):i.formatter?t.innerHTML=i.formatter(r):t.textContent=r}})),this.dispatchEvent(new CustomEvent("editingChange",{detail:{record:e,editing:!1},bubbles:!0}))}cancelEditedRecord(e){e[editing]=!1;const t=this.shadowRoot.querySelector(`.record[data-index="${e[index]}"]`);t&&(t.classList.remove("editing"),t.removeAttribute("editing"),t.querySelectorAll(".cell[data-field]").forEach(t=>{const s=t.dataset.field,i=this.fields.find(e=>e.name===s);if(i){const r=e[s]||"";i.calculator?t.textContent=i.calculator(e,this):i.formatter?t.innerHTML=i.formatter(r):t.textContent=r}})),this.dispatchEvent(new CustomEvent("editingChange",{detail:{record:e,editing:!1},bubbles:!0}))}recordIsEditing(e){return e[editing]}getCurrentPage(){return this.currentPage}getTotalPages(){return Math.ceil(this.getDisplayedRecords().length/this.pageSize)}setPage(e){e<1||e>this.getTotalPages()||(this.currentPage=e,this.requestUpdate(),this.dispatchEvent(new CustomEvent("pageChange",{bubbles:!0})))}firstPage(){1!==this.currentPage&&this.setPage(1)}nextPage(){this.currentPage<this.getTotalPages()&&this.setPage(this.currentPage+1)}prevPage(){this.currentPage>1&&this.setPage(this.currentPage-1)}lastPage(){this.currentPage!==this.getTotalPages()&&this.setPage(this.getTotalPages())}setPageSize(e){this.pageSize=e,this.currentPage=1,this.requestUpdate(),this.dispatchEvent(new CustomEvent("pageSizeChange",{bubbles:!0}))}getPageSize(){return this.pageSize}getPageSizeOptions(){return this.pageSizeOptions}getFieldLabel(e){const t=this.fields.find(t=>t.name===e);return t?t.label:toTitleCase(e)}setPageSizeOptions(e){this.pageSizeOptions=e,this.requestUpdate()}setData({records:e=!1,fields:t=!1,pageSize:s=!1,pageSizeOptions:i=!1,currentPage:r=!1,enableSelection:o}={}){let n=!1,l=this.getTotalPages(),a=this.currentPage;e&&(this.records=e.map(e=>({...e})),this.records.forEach((e,t)=>{e[index]=t,e[selected]=!1,e[hidden]=!1,e[editing]=!1}),this.fields=t||Table.extractFieldsFromRecords(this.records),n=!0),s&&(this.pageSize=s,n=!0),i&&(this.pageSizeOptions=i),r&&(this.currentPage=r,n=!0),void 0!==o&&(this.enableSelection=o,n=!0),n&&this.requestUpdate();const d=this.getTotalPages();d!==l&&this.dispatchEvent(new CustomEvent("pageCountChanged",{detail:{totalPages:this.getTotalPages()},bubbles:!0})),a>d&&this.setPage(d)}setRecords(e,t){let s=this.getTotalPages(),i=this.currentPage;this.records=e.map(e=>({...e})),this.records.forEach((e,t)=>{e[index]=t,e[selected]=!1,e[hidden]=!1,e[editing]=!1}),this.fields=t||Table.extractFieldsFromRecords(this.records),this.requestUpdate(),this.dispatchEvent(new CustomEvent("recordsSet",{detail:{records:e},bubbles:!0}));const r=this.getTotalPages();r!==s&&this.dispatchEvent(new CustomEvent("pageCountChanged",{detail:{totalPages:this.getTotalPages()},bubbles:!0})),i>r&&this.setPage(r)}setupFetchRecords(e,t){const s=this.records.length,i=this.getTotalPages();if(s<e){this.records.length=e,this.records.fill(null,s),this.requestUpdate();const t=this.getTotalPages();t!==i&&setTimeout(()=>{this.dispatchEvent(new CustomEvent("pageCountChanged",{detail:{totalPages:t},bubbles:!0}))},0)}this.addEventListener("fetchRecords",async e=>{if(this.fetchPending)return;this.fetchPending=!0;const{start:s,count:i}=e.detail,r=await t(s,i);r.forEach((e,t)=>{e[index]=s+t,void 0===e[selected]&&(e[selected]=!1),void 0===e[hidden]&&(e[hidden]=!1),void 0===e[editing]&&(e[editing]=!1)}),this.records.splice(s,r.length,...r),this.fetchPending=!1,this.requestUpdate()})}addRecord(e){e[selected]=!1,e[hidden]=!1,e[index]=this.records.length,this.records.push(e),this.requestUpdate(),this.dispatchEvent(new CustomEvent("recordAdded",{detail:{record:e},bubbles:!0}))}updateRecord(e,t){let s=!1,i=this.records.find(t=>t===e);if(i||void 0===e[index]||(i=this.records[e[index]]),Object.keys(t).forEach(e=>{i.hasOwnProperty(e)&&(i[e]=t[e],s=!0)}),s){const e=(this.currentPage-1)*this.pageSize,t=e+this.pageSize;(!this.enablePages||i[index]>=e&&i[index]<t)&&this.requestUpdate()}}deleteRecord(e){let t=this.records.find(t=>t===e),s=this.getTotalPages();if(t||void 0===e[index]||(t=this.records[e[index]]),t){const e=this.records.indexOf(t);this.records.splice(e,1),this.records.forEach((e,t)=>{e[index]=t}),this.requestUpdate(),this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0})),this.dispatchEvent(new CustomEvent("recordDeleted",{detail:{index:e},bubbles:!0}));const i=this.getTotalPages();this.currentPage>i&&this.setPage(i),i!==s&&this.dispatchEvent(new CustomEvent("pageCountChanged",{detail:{totalPages:i},bubbles:!0}))}}deleteSelected(){let e=this.getTotalPages();this.getSelectedRecords().forEach(e=>{let t=this.records.find(t=>t===e);if(t||void 0===e[index]||(t=this.records[e[index]]),t){const e=this.records.indexOf(t);this.records.splice(e,1)}}),this.records.forEach((e,t)=>{e[index]=t}),this.requestUpdate();const t=this.getTotalPages();this.currentPage>t&&this.setPage(t),t!==e&&this.dispatchEvent(new CustomEvent("pageCountChanged",{detail:{totalPages:t},bubbles:!0})),this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0}))}getSelectedRecords(){return this.records.filter(e=>e[selected])}selectAllOnPage(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);for(let s=e;s<t;s++)this.records[s][selected]=!0;this.requestUpdate(),setTimeout(()=>{this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0}))},0)}deselectAllOnPage(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);for(let s=e;s<t;s++)this.records[s][selected]=!1;this.requestUpdate(),setTimeout(()=>{this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0}))},0)}allOnPageSelected(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);for(let s=e;s<t;s++)if(!this.records[s][selected])return!1;return!0}sortBy(e,t=!0){this.sort=this.sort.filter(t=>t.name!==e),this.sort.push({name:e,asc:t}),this.requestUpdate()}hideRecord(e){let t=this.records.find(t=>t===e);t||void 0===e[index]||(t=this.records[e[index]]),t&&(t[hidden]=!0,this.requestUpdate(),this.dispatchEvent(new CustomEvent("recordHidden",{bubbles:!0})))}showRecord(e){let t=this.records.find(t=>t===e);t||void 0===e[index]||(t=this.records[e[index]]),t&&(t[hidden]=!1,this.requestUpdate(),this.dispatchEvent(new CustomEvent("recordShown",{bubbles:!0})))}showAllRecords(){this.records.forEach(e=>{e[hidden]=!1}),this.filters.length&&(this.filters=[],this.dispatchEvent(new CustomEvent("filterRemoved",{bubbles:!0})),this.dispatchEvent(new CustomEvent("filterChange",{bubbles:!0}))),this.requestUpdate(),this.dispatchEvent(new CustomEvent("recordShown",{bubbles:!0})),this.dispatchEvent(new CustomEvent("allRecordsShown",{bubbles:!0}))}addFilter(e,t,s){this.filters.push({field:e,condition:t,value:s}),this.dispatchEvent(new CustomEvent("filterAdded",{bubbles:!0})),this.dispatchEvent(new CustomEvent("filterChange",{bubbles:!0})),this.requestUpdate()}removeFilter(e,t,s,i=!0){const r=this.filters.findIndex(i=>i.field===e&&i.condition===t&&i.value===s);-1!==r&&(this.records.forEach(i=>{this.testFilter(i,e,t,s)||(i[hidden]=!1)}),this.filters.splice(r,1),this.dispatchEvent(new CustomEvent("filterRemoved",{bubbles:!0})),this.dispatchEvent(new CustomEvent("filterChange",{bubbles:!0})),i&&this.requestUpdate())}testFilter(e,t,s,i){let r=e[t],o=i;switch(this.caseSensitiveFilters||"string"!=typeof r||"string"!=typeof i||(r=r.toLowerCase(),o=i.toLowerCase()),s){case"equals":return r===o;case"not-equals":return r!==o;case"contains":return r.includes(o);case"not-contains":return!r.includes(o);case"greater-than":return r>o;case"less-than":return r<o;case"greater-than-or-equal":return r>=o;case"less-than-or-equal":return r<=o;default:return!0}}removeAllFilters(){this.filters.length&&([...this.filters].forEach(({field:e,condition:t,value:s})=>{this.removeFilter(e,t,s,!1)}),this.requestUpdate())}search(e){const t=e.trim().toLowerCase();let s=!1;this.records.forEach(e=>{if(e[hidden])return;let i=!1;this.fields.forEach(({name:s})=>{(e[s]?.toString().toLowerCase()||"").includes(t)&&(i=!0)}),e[hidden]!==!i&&(e[hidden]=!i,s=!0)}),s&&(this.dispatchEvent(new CustomEvent("recordHidden",{bubbles:!0})),this.requestUpdate()),this.dispatchEvent(new CustomEvent("search",{detail:{term:e},bubbles:!0}))}getDisplayedRecords(){this.filters.forEach(({field:e,condition:t,value:s})=>{this.records.forEach(i=>{null!==i&&(this.testFilter(i,e,t,s)||(i[hidden]=!0))})});let e=this.records.filter(e=>null===e||!e[hidden]);return this.sort.forEach(({name:t,asc:s})=>{e.sort((e,i)=>null===e||null===i?0:e[t]<i[t]?s?-1:1:e[t]>i[t]?s?1:-1:0)}),e}getHiddenRecords(){return this.records.filter(e=>e[hidden])}calculateColumnSizes(){const e=Array.from(this.querySelectorAll('[slot="before"]')),t=Array.from(this.querySelectorAll('[slot="after"]')),s={beforeControls:e.reduce((e,t)=>e+(t.maxWidth||40),0),afterControls:t.reduce((e,t)=>e+(t.maxWidth||40),0)},i=[...e,...t].some(e=>void 0===e.maxWidth);return JSON.stringify(this.columnSizes)!==JSON.stringify(s)&&(this.columnSizes=s),i&&setTimeout(()=>this.calculateColumnSizes(),0),this.columnSizes}setFieldHiddenState(e,t){const s=this.fields.find(t=>t.name===e);s&&(s.hidden=t,this.calculateColumnSizes(),this.requestUpdate(),this.dispatchEvent(new CustomEvent("fieldVisibilityChanged",{detail:{field:s},bubbles:!0})),this.dispatchEvent(new CustomEvent(t?"fieldHidden":"fieldShown",{detail:{field:s},bubbles:!0})))}hideField(e){this.setFieldHiddenState(e,!0)}showField(e){this.setFieldHiddenState(e,!1)}reorderFields(e){const t=[];e.forEach(e=>{const s=this.fields.find(t=>t.name===e);s&&t.push(s)}),this.fields=t,this.requestUpdate()}render(){return this.records&&this.fields?(this.calculateColumnSizes(),this.hasTopControls()?this.setAttribute("top-controls","true"):this.removeAttribute("top-controls"),this.hasBottomControls()?this.setAttribute("bottom-controls","true"):this.removeAttribute("bottom-controls"),html`
|
|
43
|
+
`}hasBeforeControls(){return!!this.querySelector('[slot="before"]')}hasAfterControls(){return!!this.querySelector('[slot="after"]')}hasTopControls(){return!!this.querySelector('[slot="top"]')}hasBottomControls(){return!!this.querySelector(":scope > :not([slot])")}editRecord(e){e[editing]=!0;const t=this.shadowRoot.querySelector(`.record[data-index="${e[index]}"]`);t&&(t.classList.add("editing"),t.setAttribute("editing","true"),t.querySelectorAll(".cell[data-field]").forEach(t=>{const s=t.dataset.field,i=this.fields.find(e=>e.name===s);if(i){const r=e[s]||"";if(t.innerHTML="",i.calculator){const s=document.createElement("input");s.disabled=!0,s.value=i.calculator(e,this),t.appendChild(s)}else if(i.editor)t.appendChild(i.editor(r));else{const e=i.type||typeof r,s=Table.editors[e]||Table.editors.string;t.appendChild(s(r))}}})),this.dispatchEvent(new CustomEvent("editingChange",{detail:{record:e,editing:!0},bubbles:!0}))}saveEditedRecord(e){const t=this.shadowRoot.querySelector(`.record[data-index="${e[index]}"]`),s={};t&&t.querySelectorAll(".cell[data-field]").forEach(e=>{const t=e.dataset.field,i=this.fields.find(e=>e.name===t);if(i&&!i.calculator){const i=e.querySelector("input, select");i&&(s[t]=i.value)}});const i=()=>{Object.assign(e,s),e[editing]=!1,t&&(t.classList.remove("editing"),t.removeAttribute("editing"),t.querySelectorAll(".cell[data-field]").forEach(t=>{const s=t.dataset.field,i=this.fields.find(e=>e.name===s);if(i){const r=e[s]||"";i.calculator?t.textContent=i.calculator(e,this):i.formatter?t.innerHTML=i.formatter(r):t.textContent=r}})),this.dispatchEvent(new CustomEvent("editingChange",{detail:{record:e,editing:!1},bubbles:!0}))};if(Object.keys(s).some(t=>String(e[t]??"")!==s[t]))if(this.requestEdit){t?.classList.add("pending");const r=()=>{t?.classList.remove("pending"),i()},o=()=>{t?.classList.remove("pending")};this.dispatchEvent(new CustomEvent("requestSave",{detail:{record:e,newData:s,approve:r,reject:o},bubbles:!0}))}else i();else this.cancelEditedRecord(e)}cancelEditedRecord(e){e[editing]=!1;const t=this.shadowRoot.querySelector(`.record[data-index="${e[index]}"]`);t&&(t.classList.remove("editing"),t.removeAttribute("editing"),t.querySelectorAll(".cell[data-field]").forEach(t=>{const s=t.dataset.field,i=this.fields.find(e=>e.name===s);if(i){const r=e[s]||"";i.calculator?t.textContent=i.calculator(e,this):i.formatter?t.innerHTML=i.formatter(r):t.textContent=r}})),this.dispatchEvent(new CustomEvent("editingChange",{detail:{record:e,editing:!1},bubbles:!0}))}recordIsEditing(e){return e[editing]}getCurrentPage(){return this.currentPage}getTotalPages(){return Math.ceil(this.getDisplayedRecords().length/this.pageSize)}setPage(e){e<1||e>this.getTotalPages()||(this.currentPage=e,this.requestUpdate(),this.dispatchEvent(new CustomEvent("pageChange",{bubbles:!0})))}firstPage(){1!==this.currentPage&&this.setPage(1)}nextPage(){this.currentPage<this.getTotalPages()&&this.setPage(this.currentPage+1)}prevPage(){this.currentPage>1&&this.setPage(this.currentPage-1)}lastPage(){this.currentPage!==this.getTotalPages()&&this.setPage(this.getTotalPages())}setPageSize(e){this.pageSize=e,this.currentPage=1,this.requestUpdate(),this.dispatchEvent(new CustomEvent("pageSizeChange",{bubbles:!0}))}getPageSize(){return this.pageSize}getPageSizeOptions(){return this.pageSizeOptions}getFieldLabel(e){const t=this.fields.find(t=>t.name===e);return t?t.label:toTitleCase(e)}setPageSizeOptions(e){this.pageSizeOptions=e,this.requestUpdate()}setData({records:e=!1,fields:t=!1,pageSize:s=!1,pageSizeOptions:i=!1,currentPage:r=!1,enableSelection:o}={}){let n=!1,l=this.getTotalPages(),a=this.currentPage;e&&(this.records=e.map(e=>({...e})),this.records.forEach((e,t)=>{e[index]=t,e[selected]=!1,e[hidden]=!1,e[editing]=!1}),this.fields=t||Table.extractFieldsFromRecords(this.records),n=!0),s&&(this.pageSize=s,n=!0),i&&(this.pageSizeOptions=i),r&&(this.currentPage=r,n=!0),void 0!==o&&(this.enableSelection=o,n=!0),n&&this.requestUpdate();const d=this.getTotalPages();d!==l&&this.dispatchEvent(new CustomEvent("pageCountChanged",{detail:{totalPages:this.getTotalPages()},bubbles:!0})),a>d&&this.setPage(d)}setRecords(e,t){let s=this.getTotalPages(),i=this.currentPage;this.records=e.map(e=>({...e})),this.records.forEach((e,t)=>{e[index]=t,e[selected]=!1,e[hidden]=!1,e[editing]=!1}),this.fields=t||Table.extractFieldsFromRecords(this.records),this.requestUpdate(),this.dispatchEvent(new CustomEvent("recordsSet",{detail:{records:e},bubbles:!0}));const r=this.getTotalPages();r!==s&&this.dispatchEvent(new CustomEvent("pageCountChanged",{detail:{totalPages:this.getTotalPages()},bubbles:!0})),i>r&&this.setPage(r)}setupFetchRecords(e,t){const s=this.records.length,i=this.getTotalPages();if(s<e){this.records.length=e,this.records.fill(null,s),this.requestUpdate();const t=this.getTotalPages();t!==i&&setTimeout(()=>{this.dispatchEvent(new CustomEvent("pageCountChanged",{detail:{totalPages:t},bubbles:!0}))},0)}this.addEventListener("fetchRecords",async e=>{if(this.fetchPending)return;this.fetchPending=!0;const{start:s,count:i}=e.detail,r=await t(s,i);r.forEach((e,t)=>{e[index]=s+t,void 0===e[selected]&&(e[selected]=!1),void 0===e[hidden]&&(e[hidden]=!1),void 0===e[editing]&&(e[editing]=!1)}),this.records.splice(s,r.length,...r),this.fetchPending=!1,this.requestUpdate()})}addRecord(e){e[selected]=!1,e[hidden]=!1,e[index]=this.records.length,this.records.push(e),this.requestUpdate(),this.dispatchEvent(new CustomEvent("recordAdded",{detail:{record:e},bubbles:!0}))}updateRecord(e,t){let s=!1,i=this.records.find(t=>t===e);if(i||void 0===e[index]||(i=this.records[e[index]]),Object.keys(t).forEach(e=>{i.hasOwnProperty(e)&&(i[e]=t[e],s=!0)}),s){const e=(this.currentPage-1)*this.pageSize,t=e+this.pageSize;(!this.enablePages||i[index]>=e&&i[index]<t)&&this.requestUpdate()}}deleteRecord(e){let t=this.records.find(t=>t===e);const s=this.getTotalPages();if(t||void 0===e[index]||(t=this.records[e[index]]),!t)return;const i=()=>{const e=this.records.indexOf(t);this.records.splice(e,1),this.records.forEach((e,t)=>{e[index]=t}),this.requestUpdate(),this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0})),this.dispatchEvent(new CustomEvent("recordDeleted",{detail:{index:e},bubbles:!0}));const i=this.getTotalPages();this.currentPage>i&&this.setPage(i),i!==s&&this.dispatchEvent(new CustomEvent("pageCountChanged",{detail:{totalPages:i},bubbles:!0}))};if(this.requestDelete){const e=this.shadowRoot.querySelector(`.record[data-index="${t[index]}"]`);e?.classList.add("pending");const s=()=>{e?.classList.remove("pending"),i()},r=()=>{e?.classList.remove("pending")};this.dispatchEvent(new CustomEvent("requestDelete",{detail:{records:[t],approve:s,reject:r},bubbles:!0}))}else i()}deleteSelected(){const e=this.getTotalPages(),t=this.getSelectedRecords().map(e=>this.records.find(t=>t===e)??(void 0!==e[index]?this.records[e[index]]:null)).filter(Boolean);if(!t.length)return;const s=()=>{t.forEach(e=>{const t=this.records.indexOf(e);-1!==t&&this.records.splice(t,1)}),this.records.forEach((e,t)=>{e[index]=t}),this.requestUpdate();const s=this.getTotalPages();this.currentPage>s&&this.setPage(s),s!==e&&this.dispatchEvent(new CustomEvent("pageCountChanged",{detail:{totalPages:s},bubbles:!0})),this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0}))};if(this.requestDelete){const e=t.map(e=>this.shadowRoot.querySelector(`.record[data-index="${e[index]}"]`)).filter(Boolean);e.forEach(e=>e.classList.add("pending"));const i=()=>{e.forEach(e=>e.classList.remove("pending")),s()},r=()=>{e.forEach(e=>e.classList.remove("pending"))};this.dispatchEvent(new CustomEvent("requestDelete",{detail:{records:t,approve:i,reject:r},bubbles:!0}))}else s()}getSelectedRecords(){return this.records.filter(e=>e[selected])}selectAllOnPage(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);for(let s=e;s<t;s++)this.records[s][selected]=!0;this.requestUpdate(),setTimeout(()=>{this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0}))},0)}deselectAllOnPage(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);for(let s=e;s<t;s++)this.records[s][selected]=!1;this.requestUpdate(),setTimeout(()=>{this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0}))},0)}allOnPageSelected(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);for(let s=e;s<t;s++)if(!this.records[s][selected])return!1;return!0}sortBy(e,t=!0){this.sort=this.sort.filter(t=>t.name!==e),this.sort.push({name:e,asc:t}),this.requestUpdate()}hideRecord(e){let t=this.records.find(t=>t===e);t||void 0===e[index]||(t=this.records[e[index]]),t&&(t[hidden]=!0,this.requestUpdate(),this.dispatchEvent(new CustomEvent("recordHidden",{bubbles:!0})))}showRecord(e){let t=this.records.find(t=>t===e);t||void 0===e[index]||(t=this.records[e[index]]),t&&(t[hidden]=!1,this.requestUpdate(),this.dispatchEvent(new CustomEvent("recordShown",{bubbles:!0})))}showAllRecords(){this.records.forEach(e=>{e[hidden]=!1}),this.filters.length&&(this.filters=[],this.dispatchEvent(new CustomEvent("filterRemoved",{bubbles:!0})),this.dispatchEvent(new CustomEvent("filterChange",{bubbles:!0}))),this.requestUpdate(),this.dispatchEvent(new CustomEvent("recordShown",{bubbles:!0})),this.dispatchEvent(new CustomEvent("allRecordsShown",{bubbles:!0}))}addFilter(e,t,s){this.filters.push({field:e,condition:t,value:s}),this.dispatchEvent(new CustomEvent("filterAdded",{bubbles:!0})),this.dispatchEvent(new CustomEvent("filterChange",{bubbles:!0})),this.requestUpdate()}removeFilter(e,t,s,i=!0){const r=this.filters.findIndex(i=>i.field===e&&i.condition===t&&i.value===s);-1!==r&&(this.records.forEach(i=>{this.testFilter(i,e,t,s)||(i[hidden]=!1)}),this.filters.splice(r,1),this.dispatchEvent(new CustomEvent("filterRemoved",{bubbles:!0})),this.dispatchEvent(new CustomEvent("filterChange",{bubbles:!0})),i&&this.requestUpdate())}testFilter(e,t,s,i){let r=e[t],o=i;switch(this.caseSensitiveFilters||"string"!=typeof r||"string"!=typeof i||(r=r.toLowerCase(),o=i.toLowerCase()),s){case"equals":return r===o;case"not-equals":return r!==o;case"contains":return r.includes(o);case"not-contains":return!r.includes(o);case"greater-than":return r>o;case"less-than":return r<o;case"greater-than-or-equal":return r>=o;case"less-than-or-equal":return r<=o;default:return!0}}removeAllFilters(){this.filters.length&&([...this.filters].forEach(({field:e,condition:t,value:s})=>{this.removeFilter(e,t,s,!1)}),this.requestUpdate())}search(e){const t=e.trim().toLowerCase();let s=!1;this.records.forEach(e=>{if(e[hidden])return;let i=!1;this.fields.forEach(({name:s})=>{(e[s]?.toString().toLowerCase()||"").includes(t)&&(i=!0)}),e[hidden]!==!i&&(e[hidden]=!i,s=!0)}),s&&(this.dispatchEvent(new CustomEvent("recordHidden",{bubbles:!0})),this.requestUpdate()),this.dispatchEvent(new CustomEvent("search",{detail:{term:e},bubbles:!0}))}getDisplayedRecords(){this.filters.forEach(({field:e,condition:t,value:s})=>{this.records.forEach(i=>{null!==i&&(this.testFilter(i,e,t,s)||(i[hidden]=!0))})});let e=this.records.filter(e=>null===e||!e[hidden]);return this.sort.forEach(({name:t,asc:s})=>{e.sort((e,i)=>null===e||null===i?0:e[t]<i[t]?s?-1:1:e[t]>i[t]?s?1:-1:0)}),e}getHiddenRecords(){return this.records.filter(e=>e[hidden])}calculateColumnSizes(){const e=Array.from(this.querySelectorAll('[slot="before"]')),t=Array.from(this.querySelectorAll('[slot="after"]')),s={beforeControls:e.reduce((e,t)=>e+(t.maxWidth||40),0),afterControls:t.reduce((e,t)=>e+(t.maxWidth||40),0)},i=[...e,...t].some(e=>void 0===e.maxWidth);return JSON.stringify(this.columnSizes)!==JSON.stringify(s)&&(this.columnSizes=s),i&&setTimeout(()=>this.calculateColumnSizes(),0),this.columnSizes}setFieldHiddenState(e,t){const s=this.fields.find(t=>t.name===e);s&&(s.hidden=t,this.calculateColumnSizes(),this.requestUpdate(),this.dispatchEvent(new CustomEvent("fieldVisibilityChanged",{detail:{field:s},bubbles:!0})),this.dispatchEvent(new CustomEvent(t?"fieldHidden":"fieldShown",{detail:{field:s},bubbles:!0})))}hideField(e){this.setFieldHiddenState(e,!0)}showField(e){this.setFieldHiddenState(e,!1)}reorderFields(e){const t=[];e.forEach(e=>{const s=this.fields.find(t=>t.name===e);s&&t.push(s)}),this.fields=t,this.requestUpdate()}render(){return this.records&&this.fields?(this.calculateColumnSizes(),this.hasTopControls()?this.setAttribute("top-controls","true"):this.removeAttribute("top-controls"),this.hasBottomControls()?this.setAttribute("bottom-controls","true"):this.removeAttribute("bottom-controls"),html`
|
|
44
44
|
<div id="wrapper">
|
|
45
45
|
<div id="top"><slot name="top"></slot></div>
|
|
46
46
|
<div id="table-container">
|
|
@@ -122,10 +122,43 @@ import{html,css,unsafeStatic,literal}from"../lit-all.min.js";import ShadowCompon
|
|
|
122
122
|
tbody tr:last-child td {
|
|
123
123
|
border-bottom: none;
|
|
124
124
|
}
|
|
125
|
+
tr.editing td.cell[data-field] {
|
|
126
|
+
padding: 0;
|
|
127
|
+
}
|
|
128
|
+
tr.editing td.cell[data-field] input,
|
|
129
|
+
tr.editing td.cell[data-field] select {
|
|
130
|
+
width: 100%;
|
|
131
|
+
height: 100%;
|
|
132
|
+
box-sizing: border-box;
|
|
133
|
+
}
|
|
134
|
+
tr.pending {
|
|
135
|
+
pointer-events: none;
|
|
136
|
+
}
|
|
137
|
+
tr.pending td {
|
|
138
|
+
position: relative;
|
|
139
|
+
overflow: hidden;
|
|
140
|
+
}
|
|
141
|
+
tr.pending td::before {
|
|
142
|
+
content: '';
|
|
143
|
+
position: absolute;
|
|
144
|
+
inset: 0;
|
|
145
|
+
background: linear-gradient(90deg, transparent, rgba(128, 128, 128, 0.15), transparent);
|
|
146
|
+
transform: translateX(-100%);
|
|
147
|
+
animation: row-pending 1.2s ease-in-out infinite;
|
|
148
|
+
}
|
|
149
|
+
@keyframes row-pending {
|
|
150
|
+
0% { transform: translateX(-100%); }
|
|
151
|
+
100% { transform: translateX(100%); }
|
|
152
|
+
}
|
|
125
153
|
th.controls,
|
|
126
154
|
td.controls {
|
|
127
155
|
padding: 0;
|
|
128
156
|
}
|
|
157
|
+
td.controls-after,
|
|
158
|
+
td.controls-before {
|
|
159
|
+
display: flex;
|
|
160
|
+
align-items: center;
|
|
161
|
+
}
|
|
129
162
|
.field-select,
|
|
130
163
|
.selection {
|
|
131
164
|
width: 40px;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import TableControl from"./TableControl.js";import{html}from"../../lit-all.min.js";import"../Icon.js";export default class DeleteSelected extends TableControl{deleteSelected=()=>{this.table.deleteSelected()};render(){return html`
|
|
2
|
+
<button class="no-btn icon-btn" title="Delete Selected" @click="${this.deleteSelected}">
|
|
3
|
+
<slot>
|
|
4
|
+
<k-icon name="delete_sweep"></k-icon>
|
|
5
|
+
</slot>
|
|
6
|
+
</button>
|
|
7
|
+
`}}customElements.define("k-tc-delete-selected",DeleteSelected);
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
<a href="./tableSorting.html">Sorting</a><br />
|
|
35
35
|
<a href="./tableFieldSortHide.html">Field Sorting and Hiding</a><br />
|
|
36
36
|
<a href="./tableFetchRecords.html">Fetching Records</a><br />
|
|
37
|
+
<a href="./tableServerSync.html">Server Sync</a><br />
|
|
37
38
|
<h6 class="mt"><a href="#jsRef" class="no-link">JavaScript Reference</a></h6>
|
|
38
39
|
<a href="#constructor">Constructor</a><br />
|
|
39
40
|
<a href="#requirements">Requirements</a><br />
|
|
@@ -50,7 +51,7 @@
|
|
|
50
51
|
<p>In HTML create a <code><k-table></code>, and then in JavaScript call the <code>setData</code> method passing in an options object containing your data.</p>
|
|
51
52
|
|
|
52
53
|
<k-card label="HTML">
|
|
53
|
-
<pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">k-table</span> <span class="hljs-attr">id</span>=<span class="hljs-string">
|
|
54
|
+
<pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">k-table</span> <span class="hljs-attr">id</span>=<span class="hljs-string">basicUsageExample</span>></span><span class="hljs-tag"></<span class="hljs-name">k-table</span>></span><br><span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">module</span>></span><span class="language-javascript"><br> <span class="hljs-keyword">await</span> <span class="hljs-variable language_">window</span>.<span class="hljs-property">customElements</span>.<span class="hljs-title function_">whenDefined</span>(<span class="hljs-string">'k-table'</span>);<br> <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">'basicUsageExample'</span>).<span class="hljs-title function_">setData</span>({<br> <span class="hljs-attr">records</span>: [{<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> <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> <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> <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"></<span class="hljs-name">script</span>></span></code></pre>
|
|
54
55
|
</k-card>
|
|
55
56
|
<k-card label="Results">
|
|
56
57
|
<k-table id="basicUsageExample"></k-table>
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Server Sync - Table - Kempo Docs - A Web Components Solution</title>
|
|
7
|
+
<link rel="icon" type="image/png" sizes="48x48" href="../media/icon48.png">
|
|
8
|
+
<link rel="manifest" href="../manifest.json" />
|
|
9
|
+
<link rel="stylesheet" href="../kempo-vars.css" />
|
|
10
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/kempo-css@1.3.11/dist/kempo.min.css" />
|
|
11
|
+
<link rel="stylesheet" href="../kempo-hljs.css" />
|
|
12
|
+
<link rel="stylesheet" href="../styles.css" />
|
|
13
|
+
<script>window.litDisableBundleWarning = true;</script>
|
|
14
|
+
<script>
|
|
15
|
+
window.contacts = [];
|
|
16
|
+
function generateContact(){
|
|
17
|
+
const maleNames = [
|
|
18
|
+
"Liam", "Noah", "Oliver", "Elijah", "William", "James", "Benjamin",
|
|
19
|
+
"Lucas", "Henry", "Alexander", "Mason", "Michael", "Ethan", "Daniel",
|
|
20
|
+
"Jacob", "Logan", "Jackson", "Levi", "Sebastian", "Mateo", "Jack",
|
|
21
|
+
"Owen", "Theodore", "Aiden", "Samuel", "Joseph", "John", "David",
|
|
22
|
+
"Wyatt", "Matthew"
|
|
23
|
+
];
|
|
24
|
+
const femaleNames = [
|
|
25
|
+
"Olivia", "Emma", "Ava", "Sophia", "Isabella", "Mia", "Amelia",
|
|
26
|
+
"Harper", "Evelyn", "Abigail", "Emily", "Ella", "Elizabeth",
|
|
27
|
+
"Camila", "Luna", "Sofia", "Avery", "Mila", "Aria", "Scarlett",
|
|
28
|
+
"Penelope", "Layla", "Chloe", "Victoria", "Madison", "Eleanor",
|
|
29
|
+
"Grace", "Nora", "Riley", "Zoey"
|
|
30
|
+
];
|
|
31
|
+
const lastNames = [
|
|
32
|
+
"Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller",
|
|
33
|
+
"Davis", "Rodriguez", "Martinez", "Hernandez", "Lopez", "Gonzalez",
|
|
34
|
+
"Wilson", "Anderson", "Thomas", "Taylor", "Moore", "Jackson", "Martin",
|
|
35
|
+
"Lee", "Perez", "Thompson", "White", "Harris", "Sanchez", "Clark",
|
|
36
|
+
"Ramirez", "Lewis", "Robinson"
|
|
37
|
+
];
|
|
38
|
+
const gender = Math.random() > 0.5 ? 'm' : 'f';
|
|
39
|
+
const firstName = gender === 'm' ? maleNames[Math.floor(Math.random() * maleNames.length)] : femaleNames[Math.floor(Math.random() * femaleNames.length)];
|
|
40
|
+
const lastName = lastNames[Math.floor(Math.random() * lastNames.length)];
|
|
41
|
+
const name = `${firstName} ${lastName}`;
|
|
42
|
+
const email = `${firstName.toLowerCase()}.${lastName.toLowerCase()}@mailserver.com`;
|
|
43
|
+
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')}`;
|
|
44
|
+
const phoneNumber = `(${Math.floor(Math.random() * 900) + 100}) ${Math.floor(Math.random() * 900) + 100}-${Math.floor(Math.random() * 9000) + 1000}`;
|
|
45
|
+
return { name, email, birthday, phoneNumber, gender };
|
|
46
|
+
}
|
|
47
|
+
for(let i = 0; i < 10; i++){
|
|
48
|
+
contacts.push(generateContact());
|
|
49
|
+
}
|
|
50
|
+
</script>
|
|
51
|
+
</head>
|
|
52
|
+
<body>
|
|
53
|
+
<k-import src="../nav-1.inc.html"></k-import>
|
|
54
|
+
<h1 class="ta-center">Table - Server Sync</h1>
|
|
55
|
+
<main>
|
|
56
|
+
<a href="./table.html"><h5>Back to Table Component Documentation</h5></a>
|
|
57
|
+
|
|
58
|
+
<p>
|
|
59
|
+
The table supports an optional server-sync workflow for saving edits and deleting records. When the
|
|
60
|
+
<code>request-edit</code> attribute is present, calling <code>saveEditedRecord()</code> fires a
|
|
61
|
+
<code>requestSave</code> event instead of applying the changes immediately. When the <code>request-delete</code>
|
|
62
|
+
attribute is present, calling <code>deleteRecord()</code> or <code>deleteSelected()</code> fires a
|
|
63
|
+
<code>requestDelete</code> event instead of deleting immediately.
|
|
64
|
+
</p>
|
|
65
|
+
<p>
|
|
66
|
+
Both events expose an <code>approve()</code> function on <code>event.detail</code>. Call it once the server
|
|
67
|
+
operation succeeds to commit the change. If the operation fails, simply do not call <code>approve()</code> —
|
|
68
|
+
the record stays in its current state so the user can retry. <code>requestSave</code> also provides
|
|
69
|
+
<code>event.detail.record</code> (the original record) and <code>event.detail.newData</code> (the values
|
|
70
|
+
read from the editor inputs). <code>requestDelete</code> provides <code>event.detail.records</code>, an
|
|
71
|
+
array of the records targeted for deletion.
|
|
72
|
+
</p>
|
|
73
|
+
<p>
|
|
74
|
+
The example below mocks a server call that takes 1–3 seconds and randomly fails 50% of the time.
|
|
75
|
+
Toasts are used to notify the user of success or failure.
|
|
76
|
+
</p>
|
|
77
|
+
|
|
78
|
+
<pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">k-table</span> <span class="hljs-attr">id</span>=<span class="hljs-string">serverSyncExample</span> <span class="hljs-attr">enable-selection</span> <span class="hljs-attr">request-edit</span> <span class="hljs-attr">request-delete</span>></span><span class="hljs-tag"><<span class="hljs-name">k-tc-edit</span> <span class="hljs-attr">slot</span>=<span class="hljs-string">after</span>></span><span class="hljs-tag"></<span class="hljs-name">k-tc-edit</span>></span><span class="hljs-tag"><<span class="hljs-name">k-tc-delete-record</span> <span class="hljs-attr">slot</span>=<span class="hljs-string">after</span>></span><span class="hljs-tag"></<span class="hljs-name">k-tc-delete-record</span>></span><span class="hljs-tag"><<span class="hljs-name">k-tc-delete-selected</span> <span class="hljs-attr">slot</span>=<span class="hljs-string">top</span>></span><span class="hljs-tag"></<span class="hljs-name">k-tc-delete-selected</span>></span><span class="hljs-tag"></<span class="hljs-name">k-table</span>></span><br><span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">module</span>></span><span class="language-javascript"><br> <span class="hljs-keyword">import</span> <span class="hljs-title class_">Toast</span> <span class="hljs-keyword">from</span> <span class="hljs-string">'/src/components/Toast.js'</span>;<br> <span class="hljs-keyword">await</span> <span class="hljs-variable language_">window</span>.<span class="hljs-property">customElements</span>.<span class="hljs-title function_">whenDefined</span>(<span class="hljs-string">'k-table'</span>);<br> <span class="hljs-keyword">const</span> table = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">'serverSyncExample'</span>);<br> <span class="hljs-keyword">const</span> <span class="hljs-title function_">mockServer</span> = (<span class="hljs-params"></span>) => <span class="hljs-keyword">new</span> <span class="hljs-title class_">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =></span> {<br> <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> {<br> <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">random</span>() < <span class="hljs-number">0.8</span> ? <span class="hljs-title function_">resolve</span>() : <span class="hljs-title function_">reject</span>();<br> }, <span class="hljs-number">1000</span> + <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">random</span>() * <span class="hljs-number">2000</span>);<br> });<br> table.<span class="hljs-title function_">setData</span>({<br> <span class="hljs-attr">records</span>: contacts,<br> <span class="hljs-attr">fields</span>: [{<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> <span class="hljs-attr">name</span>: <span class="hljs-string">'email'</span>,<br> <span class="hljs-attr">label</span>: <span class="hljs-string">'Email'</span><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> <span class="hljs-attr">type</span>: <span class="hljs-string">'date'</span><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> <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> =></span> v === <span class="hljs-string">'m'</span> ? <span class="hljs-string">'Male'</span> : <span class="hljs-string">'Female'</span><br> }]<br> });<br> table.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">'requestSave'</span>, <span class="hljs-title function_">async</span> ({<br> <span class="hljs-attr">detail</span>: {<br> approve,<br> reject<br> }<br> }) => {<br> <span class="hljs-keyword">try</span> {<br> <span class="hljs-keyword">await</span> <span class="hljs-title function_">mockServer</span>();<br> <span class="hljs-title function_">approve</span>();<br> <span class="hljs-title class_">Toast</span>.<span class="hljs-title function_">success</span>(<span class="hljs-string">'Record saved.'</span>, {<br> <span class="hljs-attr">timeout</span>: <span class="hljs-number">3000</span><br> });<br> } <span class="hljs-keyword">catch</span> {<br> <span class="hljs-title function_">reject</span>();<br> <span class="hljs-title class_">Toast</span>.<span class="hljs-title function_">error</span>(<span class="hljs-string">'Save failed. The record remains open for editing.'</span>, {<br> <span class="hljs-attr">timeout</span>: <span class="hljs-number">5000</span><br> });<br> }<br> });<br> table.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">'requestDelete'</span>, <span class="hljs-title function_">async</span> ({<br> <span class="hljs-attr">detail</span>: {<br> records,<br> approve,<br> reject<br> }<br> }) => {<br> <span class="hljs-keyword">const</span> count = records.<span class="hljs-property">length</span>;<br> <span class="hljs-keyword">try</span> {<br> <span class="hljs-keyword">await</span> <span class="hljs-title function_">mockServer</span>();<br> <span class="hljs-title function_">approve</span>();<br> <span class="hljs-title class_">Toast</span>.<span class="hljs-title function_">success</span>(count === <span class="hljs-number">1</span> ? <span class="hljs-string">'1 record deleted.'</span> : count + <span class="hljs-string">' records deleted.'</span>, {<br> <span class="hljs-attr">timeout</span>: <span class="hljs-number">3000</span><br> });<br> } <span class="hljs-keyword">catch</span> {<br> <span class="hljs-title function_">reject</span>();<br> <span class="hljs-title class_">Toast</span>.<span class="hljs-title function_">error</span>(<span class="hljs-string">'Delete failed. Please try again.'</span>, {<br> <span class="hljs-attr">timeout</span>: <span class="hljs-number">5000</span><br> });<br> }<br> });<br></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span></code></pre>
|
|
79
|
+
<k-table
|
|
80
|
+
id="serverSyncExample"
|
|
81
|
+
enable-selection
|
|
82
|
+
request-edit
|
|
83
|
+
request-delete
|
|
84
|
+
>
|
|
85
|
+
<k-tc-edit slot="after"></k-tc-edit>
|
|
86
|
+
<k-tc-delete-record slot="after"></k-tc-delete-record>
|
|
87
|
+
<k-tc-delete-selected slot="top"></k-tc-delete-selected>
|
|
88
|
+
</k-table>
|
|
89
|
+
<script type="module">
|
|
90
|
+
import Toast from '../src/components/Toast.js';
|
|
91
|
+
await window.customElements.whenDefined('k-table');
|
|
92
|
+
const table = document.getElementById('serverSyncExample');
|
|
93
|
+
|
|
94
|
+
const mockServer = () => new Promise((resolve, reject) => {
|
|
95
|
+
setTimeout(() => {
|
|
96
|
+
Math.random() < 0.8 ? resolve() : reject();
|
|
97
|
+
}, 1000 + Math.random() * 2000);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
table.setData({
|
|
101
|
+
records: contacts,
|
|
102
|
+
fields: [
|
|
103
|
+
{ name: 'name', label: 'Name' },
|
|
104
|
+
{ name: 'email', label: 'Email' },
|
|
105
|
+
{ name: 'birthday', label: 'Birthday', type: 'date' },
|
|
106
|
+
{ name: 'phoneNumber', label: 'Phone Number' },
|
|
107
|
+
{ name: 'gender', label: 'Gender', formatter: v => v === 'm' ? 'Male' : 'Female' }
|
|
108
|
+
]
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
table.addEventListener('requestSave', async ({ detail: { approve, reject } }) => {
|
|
112
|
+
try {
|
|
113
|
+
await mockServer();
|
|
114
|
+
approve();
|
|
115
|
+
Toast.success('Record saved.', { timeout: 3000 });
|
|
116
|
+
} catch {
|
|
117
|
+
reject();
|
|
118
|
+
Toast.error('Save failed. The record remains open for editing.', { timeout: 5000 });
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
table.addEventListener('requestDelete', async ({ detail: { records, approve, reject } }) => {
|
|
123
|
+
const count = records.length;
|
|
124
|
+
try {
|
|
125
|
+
await mockServer();
|
|
126
|
+
approve();
|
|
127
|
+
Toast.success(count === 1 ? '1 record deleted.' : count + ' records deleted.', { timeout: 3000 });
|
|
128
|
+
} catch {
|
|
129
|
+
reject();
|
|
130
|
+
Toast.error('Delete failed. Please try again.', { timeout: 5000 });
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
</script>
|
|
134
|
+
</main>
|
|
135
|
+
<div style="height: 33.333vh"></div>
|
|
136
|
+
<script type="module" src="../src/components/Import.js"></script>
|
|
137
|
+
<script type="module" src="../src/components/Table.js"></script>
|
|
138
|
+
<script type="module" src="../src/components/tableControls/Edit.js"></script>
|
|
139
|
+
<script type="module" src="../src/components/tableControls/DeleteRecord.js"></script>
|
|
140
|
+
<script type="module" src="../src/components/tableControls/DeleteSelected.js"></script>
|
|
141
|
+
<script type="module" src="../src/components/Toast.js"></script>
|
|
142
|
+
</body>
|
|
143
|
+
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="currentColor" d="M600-240v-80h160v80H600Zm0-320v-80h280v80H600Zm0 160v-80h240v80H600ZM120-640H80v-80h160v-60h160v60h160v80h-40v360q0 33-23.5 56.5T440-200H200q-33 0-56.5-23.5T120-280v-360Zm80 0v360h240v-360H200Zm0 0v360-360Z"/></svg>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{html,css,unsafeStatic,literal}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";import{toTitleCase}from"../utils/string.js";import{boolExists}from"../utils/propConverters.js";const selected=Symbol("selected"),hidden=Symbol("hidden"),index=Symbol("index"),editing=Symbol("editing");export default class Table extends ShadowComponent{static properties={enablePages:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-pages"},pageSize:{type:Number,reflect:!0,attribute:"page-size"},currentPage:{type:Number,reflect:!0,attribute:"current-page"},pageSizeOptions:{type:Array,attribute:"page-size-options"},enableSelection:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-selection"},enableSorting:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-sorting"},caseSensitiveFilters:{type:Boolean,reflect:!0,converter:boolExists,attribute:"case-sensitive-filters"},fields:{type:Array},records:{type:Array},filters:{type:Array},sort:{type:Array},columnSizes:{type:Object},fetchPending:{type:Boolean}};constructor(e={}){super(),void 0===this.pageSize&&(this.pageSize=50),void 0===this.currentPage&&(this.currentPage=1),void 0===this.pageSizeOptions&&(this.pageSizeOptions=[10,25,50,100,500]),void 0===this.records&&(this.records=e.records||[]),void 0===this.fields&&(this.fields=e.fields||[]),void 0===this.filters&&(this.filters=e.filters||[]),void 0===this.sort&&(this.sort=[]),void 0===this.columnSizes&&(this.columnSizes={}),void 0===this.fetchPending&&(this.fetchPending=!1)}handleSelectAllChange=e=>{e.target.checked?this.selectAllOnPage():this.deselectAllOnPage()};handleFieldClick=e=>{const t=this.sort.find(t=>t.name===e),s=!t||!t.asc;this.sortBy(e,s)};handleRecordSelectionChange=(e,t)=>{e[selected]=!!t.target.checked,this.requestUpdate(),this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0}))};firstUpdated(){this.setData({records:this.records,fields:this.fields,filters:this.filters})}childrenUpdated(){this.requestUpdate()}updated(e){if(super.updated(e),this.enableSelection){const e=this.shadowRoot.getElementById("select-all");e&&(e.checked=this.allOnPageSelected())}}renderColgroupTemplate(){const e=[];return this.enableSelection&&e.push(html`<col style="width: 40px" />`),this.hasBeforeControls()&&e.push(html`<col style="width: ${this.columnSizes.beforeControls}px" />`),this.fields.forEach(({size:t,hidden:s})=>{s||e.push(t?html`<col style="width: ${t}px" />`:html`<col />`)}),this.hasAfterControls()&&e.push(html`<col style="width: ${this.columnSizes.afterControls}px" />`),e}getColumnCount(){let e=0;return this.enableSelection&&e++,this.hasBeforeControls()&&e++,this.fields.forEach(({hidden:t})=>{t||e++}),this.hasAfterControls()&&e++,e}renderFieldsTemplate(){const e=[];return this.enableSelection&&e.push(html`
|
|
1
|
+
import{html,css,unsafeStatic,literal}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";import{toTitleCase}from"../utils/string.js";import{boolExists}from"../utils/propConverters.js";const selected=Symbol("selected"),hidden=Symbol("hidden"),index=Symbol("index"),editing=Symbol("editing");export default class Table extends ShadowComponent{static properties={enablePages:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-pages"},pageSize:{type:Number,reflect:!0,attribute:"page-size"},currentPage:{type:Number,reflect:!0,attribute:"current-page"},pageSizeOptions:{type:Array,attribute:"page-size-options"},enableSelection:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-selection"},enableSorting:{type:Boolean,reflect:!0,converter:boolExists,attribute:"enable-sorting"},caseSensitiveFilters:{type:Boolean,reflect:!0,converter:boolExists,attribute:"case-sensitive-filters"},requestEdit:{type:Boolean,reflect:!0,converter:boolExists,attribute:"request-edit"},requestDelete:{type:Boolean,reflect:!0,converter:boolExists,attribute:"request-delete"},fields:{type:Array},records:{type:Array},filters:{type:Array},sort:{type:Array},columnSizes:{type:Object},fetchPending:{type:Boolean}};constructor(e={}){super(),void 0===this.pageSize&&(this.pageSize=50),void 0===this.currentPage&&(this.currentPage=1),void 0===this.pageSizeOptions&&(this.pageSizeOptions=[10,25,50,100,500]),void 0===this.records&&(this.records=e.records||[]),void 0===this.fields&&(this.fields=e.fields||[]),void 0===this.filters&&(this.filters=e.filters||[]),void 0===this.sort&&(this.sort=[]),void 0===this.columnSizes&&(this.columnSizes={}),void 0===this.fetchPending&&(this.fetchPending=!1),void 0===this.requestEdit&&(this.requestEdit=!1),void 0===this.requestDelete&&(this.requestDelete=!1)}handleSelectAllChange=e=>{e.target.checked?this.selectAllOnPage():this.deselectAllOnPage()};handleFieldClick=e=>{const t=this.sort.find(t=>t.name===e),s=!t||!t.asc;this.sortBy(e,s)};handleRecordSelectionChange=(e,t)=>{e[selected]=!!t.target.checked,this.requestUpdate(),this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0}))};firstUpdated(){this.setData({records:this.records,fields:this.fields,filters:this.filters})}childrenUpdated(){this.requestUpdate()}updated(e){if(super.updated(e),this.enableSelection){const e=this.shadowRoot.getElementById("select-all");e&&(e.checked=this.allOnPageSelected())}}renderColgroupTemplate(){const e=[];return this.enableSelection&&e.push(html`<col style="width: 40px" />`),this.hasBeforeControls()&&e.push(html`<col style="width: ${this.columnSizes.beforeControls}px" />`),this.fields.forEach(({size:t,hidden:s})=>{s||e.push(t?html`<col style="width: ${t}px" />`:html`<col />`)}),this.hasAfterControls()&&e.push(html`<col style="width: ${this.columnSizes.afterControls}px" />`),e}getColumnCount(){let e=0;return this.enableSelection&&e++,this.hasBeforeControls()&&e++,this.fields.forEach(({hidden:t})=>{t||e++}),this.hasAfterControls()&&e++,e}renderFieldsTemplate(){const e=[];return this.enableSelection&&e.push(html`
|
|
2
2
|
<th class="controls field-select">
|
|
3
3
|
<input type="checkbox" id="select-all" @change=${this.handleSelectAllChange} />
|
|
4
4
|
</th>
|
|
@@ -40,7 +40,7 @@ import{html,css,unsafeStatic,literal}from"../lit-all.min.js";import ShadowCompon
|
|
|
40
40
|
<td class="cell controls controls-after">
|
|
41
41
|
${e}
|
|
42
42
|
</td>
|
|
43
|
-
`}hasBeforeControls(){return!!this.querySelector('[slot="before"]')}hasAfterControls(){return!!this.querySelector('[slot="after"]')}hasTopControls(){return!!this.querySelector('[slot="top"]')}hasBottomControls(){return!!this.querySelector(":scope > :not([slot])")}editRecord(e){e[editing]=!0;const t=this.shadowRoot.querySelector(`.record[data-index="${e[index]}"]`);t&&(t.classList.add("editing"),t.setAttribute("editing","true"),t.querySelectorAll(".cell[data-field]").forEach(t=>{const s=t.dataset.field,i=this.fields.find(e=>e.name===s);if(i){const r=e[s]||"";if(t.innerHTML="",i.calculator){const s=document.createElement("input");s.disabled=!0,s.value=i.calculator(e,this),t.appendChild(s)}else if(i.editor)t.appendChild(i.editor(r));else{const e=i.type||typeof r,s=Table.editors[e]||Table.editors.string;t.appendChild(s(r))}}})),this.dispatchEvent(new CustomEvent("editingChange",{detail:{record:e,editing:!0},bubbles:!0}))}saveEditedRecord(e){const t=this.shadowRoot.querySelector(`.record[data-index="${e[index]}"]`);t&&(t.querySelectorAll(".cell[data-field]").forEach(t=>{const s=t.dataset.field,i=this.fields.find(e=>e.name===s);if(i&&!i.calculator){const i=t.querySelector("input, select");i&&(e[s]=i.value)}}),e[editing]=!1,t.classList.remove("editing"),t.removeAttribute("editing"),t.querySelectorAll(".cell[data-field]").forEach(t=>{const s=t.dataset.field,i=this.fields.find(e=>e.name===s);if(i){const r=e[s]||"";i.calculator?t.textContent=i.calculator(e,this):i.formatter?t.innerHTML=i.formatter(r):t.textContent=r}})),this.dispatchEvent(new CustomEvent("editingChange",{detail:{record:e,editing:!1},bubbles:!0}))}cancelEditedRecord(e){e[editing]=!1;const t=this.shadowRoot.querySelector(`.record[data-index="${e[index]}"]`);t&&(t.classList.remove("editing"),t.removeAttribute("editing"),t.querySelectorAll(".cell[data-field]").forEach(t=>{const s=t.dataset.field,i=this.fields.find(e=>e.name===s);if(i){const r=e[s]||"";i.calculator?t.textContent=i.calculator(e,this):i.formatter?t.innerHTML=i.formatter(r):t.textContent=r}})),this.dispatchEvent(new CustomEvent("editingChange",{detail:{record:e,editing:!1},bubbles:!0}))}recordIsEditing(e){return e[editing]}getCurrentPage(){return this.currentPage}getTotalPages(){return Math.ceil(this.getDisplayedRecords().length/this.pageSize)}setPage(e){e<1||e>this.getTotalPages()||(this.currentPage=e,this.requestUpdate(),this.dispatchEvent(new CustomEvent("pageChange",{bubbles:!0})))}firstPage(){1!==this.currentPage&&this.setPage(1)}nextPage(){this.currentPage<this.getTotalPages()&&this.setPage(this.currentPage+1)}prevPage(){this.currentPage>1&&this.setPage(this.currentPage-1)}lastPage(){this.currentPage!==this.getTotalPages()&&this.setPage(this.getTotalPages())}setPageSize(e){this.pageSize=e,this.currentPage=1,this.requestUpdate(),this.dispatchEvent(new CustomEvent("pageSizeChange",{bubbles:!0}))}getPageSize(){return this.pageSize}getPageSizeOptions(){return this.pageSizeOptions}getFieldLabel(e){const t=this.fields.find(t=>t.name===e);return t?t.label:toTitleCase(e)}setPageSizeOptions(e){this.pageSizeOptions=e,this.requestUpdate()}setData({records:e=!1,fields:t=!1,pageSize:s=!1,pageSizeOptions:i=!1,currentPage:r=!1,enableSelection:o}={}){let n=!1,l=this.getTotalPages(),a=this.currentPage;e&&(this.records=e.map(e=>({...e})),this.records.forEach((e,t)=>{e[index]=t,e[selected]=!1,e[hidden]=!1,e[editing]=!1}),this.fields=t||Table.extractFieldsFromRecords(this.records),n=!0),s&&(this.pageSize=s,n=!0),i&&(this.pageSizeOptions=i),r&&(this.currentPage=r,n=!0),void 0!==o&&(this.enableSelection=o,n=!0),n&&this.requestUpdate();const d=this.getTotalPages();d!==l&&this.dispatchEvent(new CustomEvent("pageCountChanged",{detail:{totalPages:this.getTotalPages()},bubbles:!0})),a>d&&this.setPage(d)}setRecords(e,t){let s=this.getTotalPages(),i=this.currentPage;this.records=e.map(e=>({...e})),this.records.forEach((e,t)=>{e[index]=t,e[selected]=!1,e[hidden]=!1,e[editing]=!1}),this.fields=t||Table.extractFieldsFromRecords(this.records),this.requestUpdate(),this.dispatchEvent(new CustomEvent("recordsSet",{detail:{records:e},bubbles:!0}));const r=this.getTotalPages();r!==s&&this.dispatchEvent(new CustomEvent("pageCountChanged",{detail:{totalPages:this.getTotalPages()},bubbles:!0})),i>r&&this.setPage(r)}setupFetchRecords(e,t){const s=this.records.length,i=this.getTotalPages();if(s<e){this.records.length=e,this.records.fill(null,s),this.requestUpdate();const t=this.getTotalPages();t!==i&&setTimeout(()=>{this.dispatchEvent(new CustomEvent("pageCountChanged",{detail:{totalPages:t},bubbles:!0}))},0)}this.addEventListener("fetchRecords",async e=>{if(this.fetchPending)return;this.fetchPending=!0;const{start:s,count:i}=e.detail,r=await t(s,i);r.forEach((e,t)=>{e[index]=s+t,void 0===e[selected]&&(e[selected]=!1),void 0===e[hidden]&&(e[hidden]=!1),void 0===e[editing]&&(e[editing]=!1)}),this.records.splice(s,r.length,...r),this.fetchPending=!1,this.requestUpdate()})}addRecord(e){e[selected]=!1,e[hidden]=!1,e[index]=this.records.length,this.records.push(e),this.requestUpdate(),this.dispatchEvent(new CustomEvent("recordAdded",{detail:{record:e},bubbles:!0}))}updateRecord(e,t){let s=!1,i=this.records.find(t=>t===e);if(i||void 0===e[index]||(i=this.records[e[index]]),Object.keys(t).forEach(e=>{i.hasOwnProperty(e)&&(i[e]=t[e],s=!0)}),s){const e=(this.currentPage-1)*this.pageSize,t=e+this.pageSize;(!this.enablePages||i[index]>=e&&i[index]<t)&&this.requestUpdate()}}deleteRecord(e){let t=this.records.find(t=>t===e),s=this.getTotalPages();if(t||void 0===e[index]||(t=this.records[e[index]]),t){const e=this.records.indexOf(t);this.records.splice(e,1),this.records.forEach((e,t)=>{e[index]=t}),this.requestUpdate(),this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0})),this.dispatchEvent(new CustomEvent("recordDeleted",{detail:{index:e},bubbles:!0}));const i=this.getTotalPages();this.currentPage>i&&this.setPage(i),i!==s&&this.dispatchEvent(new CustomEvent("pageCountChanged",{detail:{totalPages:i},bubbles:!0}))}}deleteSelected(){let e=this.getTotalPages();this.getSelectedRecords().forEach(e=>{let t=this.records.find(t=>t===e);if(t||void 0===e[index]||(t=this.records[e[index]]),t){const e=this.records.indexOf(t);this.records.splice(e,1)}}),this.records.forEach((e,t)=>{e[index]=t}),this.requestUpdate();const t=this.getTotalPages();this.currentPage>t&&this.setPage(t),t!==e&&this.dispatchEvent(new CustomEvent("pageCountChanged",{detail:{totalPages:t},bubbles:!0})),this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0}))}getSelectedRecords(){return this.records.filter(e=>e[selected])}selectAllOnPage(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);for(let s=e;s<t;s++)this.records[s][selected]=!0;this.requestUpdate(),setTimeout(()=>{this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0}))},0)}deselectAllOnPage(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);for(let s=e;s<t;s++)this.records[s][selected]=!1;this.requestUpdate(),setTimeout(()=>{this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0}))},0)}allOnPageSelected(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);for(let s=e;s<t;s++)if(!this.records[s][selected])return!1;return!0}sortBy(e,t=!0){this.sort=this.sort.filter(t=>t.name!==e),this.sort.push({name:e,asc:t}),this.requestUpdate()}hideRecord(e){let t=this.records.find(t=>t===e);t||void 0===e[index]||(t=this.records[e[index]]),t&&(t[hidden]=!0,this.requestUpdate(),this.dispatchEvent(new CustomEvent("recordHidden",{bubbles:!0})))}showRecord(e){let t=this.records.find(t=>t===e);t||void 0===e[index]||(t=this.records[e[index]]),t&&(t[hidden]=!1,this.requestUpdate(),this.dispatchEvent(new CustomEvent("recordShown",{bubbles:!0})))}showAllRecords(){this.records.forEach(e=>{e[hidden]=!1}),this.filters.length&&(this.filters=[],this.dispatchEvent(new CustomEvent("filterRemoved",{bubbles:!0})),this.dispatchEvent(new CustomEvent("filterChange",{bubbles:!0}))),this.requestUpdate(),this.dispatchEvent(new CustomEvent("recordShown",{bubbles:!0})),this.dispatchEvent(new CustomEvent("allRecordsShown",{bubbles:!0}))}addFilter(e,t,s){this.filters.push({field:e,condition:t,value:s}),this.dispatchEvent(new CustomEvent("filterAdded",{bubbles:!0})),this.dispatchEvent(new CustomEvent("filterChange",{bubbles:!0})),this.requestUpdate()}removeFilter(e,t,s,i=!0){const r=this.filters.findIndex(i=>i.field===e&&i.condition===t&&i.value===s);-1!==r&&(this.records.forEach(i=>{this.testFilter(i,e,t,s)||(i[hidden]=!1)}),this.filters.splice(r,1),this.dispatchEvent(new CustomEvent("filterRemoved",{bubbles:!0})),this.dispatchEvent(new CustomEvent("filterChange",{bubbles:!0})),i&&this.requestUpdate())}testFilter(e,t,s,i){let r=e[t],o=i;switch(this.caseSensitiveFilters||"string"!=typeof r||"string"!=typeof i||(r=r.toLowerCase(),o=i.toLowerCase()),s){case"equals":return r===o;case"not-equals":return r!==o;case"contains":return r.includes(o);case"not-contains":return!r.includes(o);case"greater-than":return r>o;case"less-than":return r<o;case"greater-than-or-equal":return r>=o;case"less-than-or-equal":return r<=o;default:return!0}}removeAllFilters(){this.filters.length&&([...this.filters].forEach(({field:e,condition:t,value:s})=>{this.removeFilter(e,t,s,!1)}),this.requestUpdate())}search(e){const t=e.trim().toLowerCase();let s=!1;this.records.forEach(e=>{if(e[hidden])return;let i=!1;this.fields.forEach(({name:s})=>{(e[s]?.toString().toLowerCase()||"").includes(t)&&(i=!0)}),e[hidden]!==!i&&(e[hidden]=!i,s=!0)}),s&&(this.dispatchEvent(new CustomEvent("recordHidden",{bubbles:!0})),this.requestUpdate()),this.dispatchEvent(new CustomEvent("search",{detail:{term:e},bubbles:!0}))}getDisplayedRecords(){this.filters.forEach(({field:e,condition:t,value:s})=>{this.records.forEach(i=>{null!==i&&(this.testFilter(i,e,t,s)||(i[hidden]=!0))})});let e=this.records.filter(e=>null===e||!e[hidden]);return this.sort.forEach(({name:t,asc:s})=>{e.sort((e,i)=>null===e||null===i?0:e[t]<i[t]?s?-1:1:e[t]>i[t]?s?1:-1:0)}),e}getHiddenRecords(){return this.records.filter(e=>e[hidden])}calculateColumnSizes(){const e=Array.from(this.querySelectorAll('[slot="before"]')),t=Array.from(this.querySelectorAll('[slot="after"]')),s={beforeControls:e.reduce((e,t)=>e+(t.maxWidth||40),0),afterControls:t.reduce((e,t)=>e+(t.maxWidth||40),0)},i=[...e,...t].some(e=>void 0===e.maxWidth);return JSON.stringify(this.columnSizes)!==JSON.stringify(s)&&(this.columnSizes=s),i&&setTimeout(()=>this.calculateColumnSizes(),0),this.columnSizes}setFieldHiddenState(e,t){const s=this.fields.find(t=>t.name===e);s&&(s.hidden=t,this.calculateColumnSizes(),this.requestUpdate(),this.dispatchEvent(new CustomEvent("fieldVisibilityChanged",{detail:{field:s},bubbles:!0})),this.dispatchEvent(new CustomEvent(t?"fieldHidden":"fieldShown",{detail:{field:s},bubbles:!0})))}hideField(e){this.setFieldHiddenState(e,!0)}showField(e){this.setFieldHiddenState(e,!1)}reorderFields(e){const t=[];e.forEach(e=>{const s=this.fields.find(t=>t.name===e);s&&t.push(s)}),this.fields=t,this.requestUpdate()}render(){return this.records&&this.fields?(this.calculateColumnSizes(),this.hasTopControls()?this.setAttribute("top-controls","true"):this.removeAttribute("top-controls"),this.hasBottomControls()?this.setAttribute("bottom-controls","true"):this.removeAttribute("bottom-controls"),html`
|
|
43
|
+
`}hasBeforeControls(){return!!this.querySelector('[slot="before"]')}hasAfterControls(){return!!this.querySelector('[slot="after"]')}hasTopControls(){return!!this.querySelector('[slot="top"]')}hasBottomControls(){return!!this.querySelector(":scope > :not([slot])")}editRecord(e){e[editing]=!0;const t=this.shadowRoot.querySelector(`.record[data-index="${e[index]}"]`);t&&(t.classList.add("editing"),t.setAttribute("editing","true"),t.querySelectorAll(".cell[data-field]").forEach(t=>{const s=t.dataset.field,i=this.fields.find(e=>e.name===s);if(i){const r=e[s]||"";if(t.innerHTML="",i.calculator){const s=document.createElement("input");s.disabled=!0,s.value=i.calculator(e,this),t.appendChild(s)}else if(i.editor)t.appendChild(i.editor(r));else{const e=i.type||typeof r,s=Table.editors[e]||Table.editors.string;t.appendChild(s(r))}}})),this.dispatchEvent(new CustomEvent("editingChange",{detail:{record:e,editing:!0},bubbles:!0}))}saveEditedRecord(e){const t=this.shadowRoot.querySelector(`.record[data-index="${e[index]}"]`),s={};t&&t.querySelectorAll(".cell[data-field]").forEach(e=>{const t=e.dataset.field,i=this.fields.find(e=>e.name===t);if(i&&!i.calculator){const i=e.querySelector("input, select");i&&(s[t]=i.value)}});const i=()=>{Object.assign(e,s),e[editing]=!1,t&&(t.classList.remove("editing"),t.removeAttribute("editing"),t.querySelectorAll(".cell[data-field]").forEach(t=>{const s=t.dataset.field,i=this.fields.find(e=>e.name===s);if(i){const r=e[s]||"";i.calculator?t.textContent=i.calculator(e,this):i.formatter?t.innerHTML=i.formatter(r):t.textContent=r}})),this.dispatchEvent(new CustomEvent("editingChange",{detail:{record:e,editing:!1},bubbles:!0}))};if(Object.keys(s).some(t=>String(e[t]??"")!==s[t]))if(this.requestEdit){t?.classList.add("pending");const r=()=>{t?.classList.remove("pending"),i()},o=()=>{t?.classList.remove("pending")};this.dispatchEvent(new CustomEvent("requestSave",{detail:{record:e,newData:s,approve:r,reject:o},bubbles:!0}))}else i();else this.cancelEditedRecord(e)}cancelEditedRecord(e){e[editing]=!1;const t=this.shadowRoot.querySelector(`.record[data-index="${e[index]}"]`);t&&(t.classList.remove("editing"),t.removeAttribute("editing"),t.querySelectorAll(".cell[data-field]").forEach(t=>{const s=t.dataset.field,i=this.fields.find(e=>e.name===s);if(i){const r=e[s]||"";i.calculator?t.textContent=i.calculator(e,this):i.formatter?t.innerHTML=i.formatter(r):t.textContent=r}})),this.dispatchEvent(new CustomEvent("editingChange",{detail:{record:e,editing:!1},bubbles:!0}))}recordIsEditing(e){return e[editing]}getCurrentPage(){return this.currentPage}getTotalPages(){return Math.ceil(this.getDisplayedRecords().length/this.pageSize)}setPage(e){e<1||e>this.getTotalPages()||(this.currentPage=e,this.requestUpdate(),this.dispatchEvent(new CustomEvent("pageChange",{bubbles:!0})))}firstPage(){1!==this.currentPage&&this.setPage(1)}nextPage(){this.currentPage<this.getTotalPages()&&this.setPage(this.currentPage+1)}prevPage(){this.currentPage>1&&this.setPage(this.currentPage-1)}lastPage(){this.currentPage!==this.getTotalPages()&&this.setPage(this.getTotalPages())}setPageSize(e){this.pageSize=e,this.currentPage=1,this.requestUpdate(),this.dispatchEvent(new CustomEvent("pageSizeChange",{bubbles:!0}))}getPageSize(){return this.pageSize}getPageSizeOptions(){return this.pageSizeOptions}getFieldLabel(e){const t=this.fields.find(t=>t.name===e);return t?t.label:toTitleCase(e)}setPageSizeOptions(e){this.pageSizeOptions=e,this.requestUpdate()}setData({records:e=!1,fields:t=!1,pageSize:s=!1,pageSizeOptions:i=!1,currentPage:r=!1,enableSelection:o}={}){let n=!1,l=this.getTotalPages(),a=this.currentPage;e&&(this.records=e.map(e=>({...e})),this.records.forEach((e,t)=>{e[index]=t,e[selected]=!1,e[hidden]=!1,e[editing]=!1}),this.fields=t||Table.extractFieldsFromRecords(this.records),n=!0),s&&(this.pageSize=s,n=!0),i&&(this.pageSizeOptions=i),r&&(this.currentPage=r,n=!0),void 0!==o&&(this.enableSelection=o,n=!0),n&&this.requestUpdate();const d=this.getTotalPages();d!==l&&this.dispatchEvent(new CustomEvent("pageCountChanged",{detail:{totalPages:this.getTotalPages()},bubbles:!0})),a>d&&this.setPage(d)}setRecords(e,t){let s=this.getTotalPages(),i=this.currentPage;this.records=e.map(e=>({...e})),this.records.forEach((e,t)=>{e[index]=t,e[selected]=!1,e[hidden]=!1,e[editing]=!1}),this.fields=t||Table.extractFieldsFromRecords(this.records),this.requestUpdate(),this.dispatchEvent(new CustomEvent("recordsSet",{detail:{records:e},bubbles:!0}));const r=this.getTotalPages();r!==s&&this.dispatchEvent(new CustomEvent("pageCountChanged",{detail:{totalPages:this.getTotalPages()},bubbles:!0})),i>r&&this.setPage(r)}setupFetchRecords(e,t){const s=this.records.length,i=this.getTotalPages();if(s<e){this.records.length=e,this.records.fill(null,s),this.requestUpdate();const t=this.getTotalPages();t!==i&&setTimeout(()=>{this.dispatchEvent(new CustomEvent("pageCountChanged",{detail:{totalPages:t},bubbles:!0}))},0)}this.addEventListener("fetchRecords",async e=>{if(this.fetchPending)return;this.fetchPending=!0;const{start:s,count:i}=e.detail,r=await t(s,i);r.forEach((e,t)=>{e[index]=s+t,void 0===e[selected]&&(e[selected]=!1),void 0===e[hidden]&&(e[hidden]=!1),void 0===e[editing]&&(e[editing]=!1)}),this.records.splice(s,r.length,...r),this.fetchPending=!1,this.requestUpdate()})}addRecord(e){e[selected]=!1,e[hidden]=!1,e[index]=this.records.length,this.records.push(e),this.requestUpdate(),this.dispatchEvent(new CustomEvent("recordAdded",{detail:{record:e},bubbles:!0}))}updateRecord(e,t){let s=!1,i=this.records.find(t=>t===e);if(i||void 0===e[index]||(i=this.records[e[index]]),Object.keys(t).forEach(e=>{i.hasOwnProperty(e)&&(i[e]=t[e],s=!0)}),s){const e=(this.currentPage-1)*this.pageSize,t=e+this.pageSize;(!this.enablePages||i[index]>=e&&i[index]<t)&&this.requestUpdate()}}deleteRecord(e){let t=this.records.find(t=>t===e);const s=this.getTotalPages();if(t||void 0===e[index]||(t=this.records[e[index]]),!t)return;const i=()=>{const e=this.records.indexOf(t);this.records.splice(e,1),this.records.forEach((e,t)=>{e[index]=t}),this.requestUpdate(),this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0})),this.dispatchEvent(new CustomEvent("recordDeleted",{detail:{index:e},bubbles:!0}));const i=this.getTotalPages();this.currentPage>i&&this.setPage(i),i!==s&&this.dispatchEvent(new CustomEvent("pageCountChanged",{detail:{totalPages:i},bubbles:!0}))};if(this.requestDelete){const e=this.shadowRoot.querySelector(`.record[data-index="${t[index]}"]`);e?.classList.add("pending");const s=()=>{e?.classList.remove("pending"),i()},r=()=>{e?.classList.remove("pending")};this.dispatchEvent(new CustomEvent("requestDelete",{detail:{records:[t],approve:s,reject:r},bubbles:!0}))}else i()}deleteSelected(){const e=this.getTotalPages(),t=this.getSelectedRecords().map(e=>this.records.find(t=>t===e)??(void 0!==e[index]?this.records[e[index]]:null)).filter(Boolean);if(!t.length)return;const s=()=>{t.forEach(e=>{const t=this.records.indexOf(e);-1!==t&&this.records.splice(t,1)}),this.records.forEach((e,t)=>{e[index]=t}),this.requestUpdate();const s=this.getTotalPages();this.currentPage>s&&this.setPage(s),s!==e&&this.dispatchEvent(new CustomEvent("pageCountChanged",{detail:{totalPages:s},bubbles:!0})),this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0}))};if(this.requestDelete){const e=t.map(e=>this.shadowRoot.querySelector(`.record[data-index="${e[index]}"]`)).filter(Boolean);e.forEach(e=>e.classList.add("pending"));const i=()=>{e.forEach(e=>e.classList.remove("pending")),s()},r=()=>{e.forEach(e=>e.classList.remove("pending"))};this.dispatchEvent(new CustomEvent("requestDelete",{detail:{records:t,approve:i,reject:r},bubbles:!0}))}else s()}getSelectedRecords(){return this.records.filter(e=>e[selected])}selectAllOnPage(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);for(let s=e;s<t;s++)this.records[s][selected]=!0;this.requestUpdate(),setTimeout(()=>{this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0}))},0)}deselectAllOnPage(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);for(let s=e;s<t;s++)this.records[s][selected]=!1;this.requestUpdate(),setTimeout(()=>{this.dispatchEvent(new CustomEvent("selectionChange",{bubbles:!0}))},0)}allOnPageSelected(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);for(let s=e;s<t;s++)if(!this.records[s][selected])return!1;return!0}sortBy(e,t=!0){this.sort=this.sort.filter(t=>t.name!==e),this.sort.push({name:e,asc:t}),this.requestUpdate()}hideRecord(e){let t=this.records.find(t=>t===e);t||void 0===e[index]||(t=this.records[e[index]]),t&&(t[hidden]=!0,this.requestUpdate(),this.dispatchEvent(new CustomEvent("recordHidden",{bubbles:!0})))}showRecord(e){let t=this.records.find(t=>t===e);t||void 0===e[index]||(t=this.records[e[index]]),t&&(t[hidden]=!1,this.requestUpdate(),this.dispatchEvent(new CustomEvent("recordShown",{bubbles:!0})))}showAllRecords(){this.records.forEach(e=>{e[hidden]=!1}),this.filters.length&&(this.filters=[],this.dispatchEvent(new CustomEvent("filterRemoved",{bubbles:!0})),this.dispatchEvent(new CustomEvent("filterChange",{bubbles:!0}))),this.requestUpdate(),this.dispatchEvent(new CustomEvent("recordShown",{bubbles:!0})),this.dispatchEvent(new CustomEvent("allRecordsShown",{bubbles:!0}))}addFilter(e,t,s){this.filters.push({field:e,condition:t,value:s}),this.dispatchEvent(new CustomEvent("filterAdded",{bubbles:!0})),this.dispatchEvent(new CustomEvent("filterChange",{bubbles:!0})),this.requestUpdate()}removeFilter(e,t,s,i=!0){const r=this.filters.findIndex(i=>i.field===e&&i.condition===t&&i.value===s);-1!==r&&(this.records.forEach(i=>{this.testFilter(i,e,t,s)||(i[hidden]=!1)}),this.filters.splice(r,1),this.dispatchEvent(new CustomEvent("filterRemoved",{bubbles:!0})),this.dispatchEvent(new CustomEvent("filterChange",{bubbles:!0})),i&&this.requestUpdate())}testFilter(e,t,s,i){let r=e[t],o=i;switch(this.caseSensitiveFilters||"string"!=typeof r||"string"!=typeof i||(r=r.toLowerCase(),o=i.toLowerCase()),s){case"equals":return r===o;case"not-equals":return r!==o;case"contains":return r.includes(o);case"not-contains":return!r.includes(o);case"greater-than":return r>o;case"less-than":return r<o;case"greater-than-or-equal":return r>=o;case"less-than-or-equal":return r<=o;default:return!0}}removeAllFilters(){this.filters.length&&([...this.filters].forEach(({field:e,condition:t,value:s})=>{this.removeFilter(e,t,s,!1)}),this.requestUpdate())}search(e){const t=e.trim().toLowerCase();let s=!1;this.records.forEach(e=>{if(e[hidden])return;let i=!1;this.fields.forEach(({name:s})=>{(e[s]?.toString().toLowerCase()||"").includes(t)&&(i=!0)}),e[hidden]!==!i&&(e[hidden]=!i,s=!0)}),s&&(this.dispatchEvent(new CustomEvent("recordHidden",{bubbles:!0})),this.requestUpdate()),this.dispatchEvent(new CustomEvent("search",{detail:{term:e},bubbles:!0}))}getDisplayedRecords(){this.filters.forEach(({field:e,condition:t,value:s})=>{this.records.forEach(i=>{null!==i&&(this.testFilter(i,e,t,s)||(i[hidden]=!0))})});let e=this.records.filter(e=>null===e||!e[hidden]);return this.sort.forEach(({name:t,asc:s})=>{e.sort((e,i)=>null===e||null===i?0:e[t]<i[t]?s?-1:1:e[t]>i[t]?s?1:-1:0)}),e}getHiddenRecords(){return this.records.filter(e=>e[hidden])}calculateColumnSizes(){const e=Array.from(this.querySelectorAll('[slot="before"]')),t=Array.from(this.querySelectorAll('[slot="after"]')),s={beforeControls:e.reduce((e,t)=>e+(t.maxWidth||40),0),afterControls:t.reduce((e,t)=>e+(t.maxWidth||40),0)},i=[...e,...t].some(e=>void 0===e.maxWidth);return JSON.stringify(this.columnSizes)!==JSON.stringify(s)&&(this.columnSizes=s),i&&setTimeout(()=>this.calculateColumnSizes(),0),this.columnSizes}setFieldHiddenState(e,t){const s=this.fields.find(t=>t.name===e);s&&(s.hidden=t,this.calculateColumnSizes(),this.requestUpdate(),this.dispatchEvent(new CustomEvent("fieldVisibilityChanged",{detail:{field:s},bubbles:!0})),this.dispatchEvent(new CustomEvent(t?"fieldHidden":"fieldShown",{detail:{field:s},bubbles:!0})))}hideField(e){this.setFieldHiddenState(e,!0)}showField(e){this.setFieldHiddenState(e,!1)}reorderFields(e){const t=[];e.forEach(e=>{const s=this.fields.find(t=>t.name===e);s&&t.push(s)}),this.fields=t,this.requestUpdate()}render(){return this.records&&this.fields?(this.calculateColumnSizes(),this.hasTopControls()?this.setAttribute("top-controls","true"):this.removeAttribute("top-controls"),this.hasBottomControls()?this.setAttribute("bottom-controls","true"):this.removeAttribute("bottom-controls"),html`
|
|
44
44
|
<div id="wrapper">
|
|
45
45
|
<div id="top"><slot name="top"></slot></div>
|
|
46
46
|
<div id="table-container">
|
|
@@ -122,10 +122,43 @@ import{html,css,unsafeStatic,literal}from"../lit-all.min.js";import ShadowCompon
|
|
|
122
122
|
tbody tr:last-child td {
|
|
123
123
|
border-bottom: none;
|
|
124
124
|
}
|
|
125
|
+
tr.editing td.cell[data-field] {
|
|
126
|
+
padding: 0;
|
|
127
|
+
}
|
|
128
|
+
tr.editing td.cell[data-field] input,
|
|
129
|
+
tr.editing td.cell[data-field] select {
|
|
130
|
+
width: 100%;
|
|
131
|
+
height: 100%;
|
|
132
|
+
box-sizing: border-box;
|
|
133
|
+
}
|
|
134
|
+
tr.pending {
|
|
135
|
+
pointer-events: none;
|
|
136
|
+
}
|
|
137
|
+
tr.pending td {
|
|
138
|
+
position: relative;
|
|
139
|
+
overflow: hidden;
|
|
140
|
+
}
|
|
141
|
+
tr.pending td::before {
|
|
142
|
+
content: '';
|
|
143
|
+
position: absolute;
|
|
144
|
+
inset: 0;
|
|
145
|
+
background: linear-gradient(90deg, transparent, rgba(128, 128, 128, 0.15), transparent);
|
|
146
|
+
transform: translateX(-100%);
|
|
147
|
+
animation: row-pending 1.2s ease-in-out infinite;
|
|
148
|
+
}
|
|
149
|
+
@keyframes row-pending {
|
|
150
|
+
0% { transform: translateX(-100%); }
|
|
151
|
+
100% { transform: translateX(100%); }
|
|
152
|
+
}
|
|
125
153
|
th.controls,
|
|
126
154
|
td.controls {
|
|
127
155
|
padding: 0;
|
|
128
156
|
}
|
|
157
|
+
td.controls-after,
|
|
158
|
+
td.controls-before {
|
|
159
|
+
display: flex;
|
|
160
|
+
align-items: center;
|
|
161
|
+
}
|
|
129
162
|
.field-select,
|
|
130
163
|
.selection {
|
|
131
164
|
width: 40px;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import TableControl from"./TableControl.js";import{html}from"../../lit-all.min.js";import"../Icon.js";export default class DeleteSelected extends TableControl{deleteSelected=()=>{this.table.deleteSelected()};render(){return html`
|
|
2
|
+
<button class="no-btn icon-btn" title="Delete Selected" @click="${this.deleteSelected}">
|
|
3
|
+
<slot>
|
|
4
|
+
<k-icon name="delete_sweep"></k-icon>
|
|
5
|
+
</slot>
|
|
6
|
+
</button>
|
|
7
|
+
`}}customElements.define("k-tc-delete-selected",DeleteSelected);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="currentColor" d="M600-240v-80h160v80H600Zm0-320v-80h280v80H600Zm0 160v-80h240v80H600ZM120-640H80v-80h160v-60h160v60h160v80h-40v360q0 33-23.5 56.5T440-200H200q-33 0-56.5-23.5T120-280v-360Zm80 0v360h240v-360H200Zm0 0v360-360Z"/></svg>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kempo-ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.79",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A Lit based web-component library",
|
|
6
6
|
"main": "index.js",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"homepage": "https://github.com/dustinpoissant/kempo-ui#readme",
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"highlight.js": "^11.11.1",
|
|
39
|
+
"js-beautify": "^1.15.4",
|
|
39
40
|
"kempo-server": "^1.8.2",
|
|
40
41
|
"kempo-testing-framework": "^1.4.0",
|
|
41
42
|
"terser": "^5.43.1"
|
package/src/components/Table.js
CHANGED
|
@@ -17,6 +17,8 @@ export default class Table extends ShadowComponent {
|
|
|
17
17
|
enableSelection: { type: Boolean, reflect: true, converter: boolExists, attribute: 'enable-selection' },
|
|
18
18
|
enableSorting: { type: Boolean, reflect: true, converter: boolExists, attribute: 'enable-sorting' },
|
|
19
19
|
caseSensitiveFilters: { type: Boolean, reflect: true, converter: boolExists, attribute: 'case-sensitive-filters' },
|
|
20
|
+
requestEdit: { type: Boolean, reflect: true, converter: boolExists, attribute: 'request-edit' },
|
|
21
|
+
requestDelete: { type: Boolean, reflect: true, converter: boolExists, attribute: 'request-delete' },
|
|
20
22
|
fields: { type: Array },
|
|
21
23
|
records: { type: Array },
|
|
22
24
|
filters: { type: Array },
|
|
@@ -38,6 +40,8 @@ export default class Table extends ShadowComponent {
|
|
|
38
40
|
if(this.sort === undefined) this.sort = [];
|
|
39
41
|
if(this.columnSizes === undefined) this.columnSizes = {};
|
|
40
42
|
if(this.fetchPending === undefined) this.fetchPending = false;
|
|
43
|
+
if(this.requestEdit === undefined) this.requestEdit = false;
|
|
44
|
+
if(this.requestDelete === undefined) this.requestDelete = false;
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
/*
|
|
@@ -358,39 +362,59 @@ export default class Table extends ShadowComponent {
|
|
|
358
362
|
|
|
359
363
|
saveEditedRecord(record) {
|
|
360
364
|
const recordEl = this.shadowRoot.querySelector(`.record[data-index="${record[index]}"]`);
|
|
365
|
+
const newData = {};
|
|
361
366
|
if(recordEl){
|
|
362
367
|
recordEl.querySelectorAll('.cell[data-field]').forEach($cell => {
|
|
363
368
|
const field = $cell.dataset.field;
|
|
364
369
|
const fieldDef = this.fields.find(f => f.name === field);
|
|
365
370
|
if(fieldDef && !fieldDef.calculator){
|
|
366
371
|
const $input = $cell.querySelector('input, select');
|
|
367
|
-
if($input)
|
|
368
|
-
record[field] = $input.value;
|
|
369
|
-
}
|
|
372
|
+
if($input) newData[field] = $input.value;
|
|
370
373
|
}
|
|
371
374
|
});
|
|
375
|
+
}
|
|
376
|
+
const commit = () => {
|
|
377
|
+
Object.assign(record, newData);
|
|
372
378
|
record[editing] = false;
|
|
373
|
-
recordEl
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
379
|
+
if(recordEl){
|
|
380
|
+
recordEl.classList.remove('editing');
|
|
381
|
+
recordEl.removeAttribute('editing');
|
|
382
|
+
recordEl.querySelectorAll('.cell[data-field]').forEach($cell => {
|
|
383
|
+
const field = $cell.dataset.field;
|
|
384
|
+
const fieldDef = this.fields.find(f => f.name === field);
|
|
385
|
+
if(fieldDef){
|
|
386
|
+
const value = record[field] || '';
|
|
387
|
+
if(fieldDef.calculator){
|
|
388
|
+
$cell.textContent = fieldDef.calculator(record, this);
|
|
389
|
+
} else if(fieldDef.formatter){
|
|
390
|
+
$cell.innerHTML = fieldDef.formatter(value);
|
|
391
|
+
} else {
|
|
392
|
+
$cell.textContent = value;
|
|
393
|
+
}
|
|
386
394
|
}
|
|
387
|
-
}
|
|
388
|
-
}
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
this.dispatchEvent(new CustomEvent('editingChange', {
|
|
398
|
+
detail: { record, editing: false },
|
|
399
|
+
bubbles: true
|
|
400
|
+
}));
|
|
401
|
+
};
|
|
402
|
+
const hasChanges = Object.keys(newData).some(key => String(record[key] ?? '') !== newData[key]);
|
|
403
|
+
if(!hasChanges){
|
|
404
|
+
this.cancelEditedRecord(record);
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
if(this.requestEdit){
|
|
408
|
+
recordEl?.classList.add('pending');
|
|
409
|
+
const wrappedCommit = () => { recordEl?.classList.remove('pending'); commit(); };
|
|
410
|
+
const reject = () => { recordEl?.classList.remove('pending'); };
|
|
411
|
+
this.dispatchEvent(new CustomEvent('requestSave', {
|
|
412
|
+
detail: { record, newData, approve: wrappedCommit, reject },
|
|
413
|
+
bubbles: true
|
|
414
|
+
}));
|
|
415
|
+
} else {
|
|
416
|
+
commit();
|
|
389
417
|
}
|
|
390
|
-
this.dispatchEvent(new CustomEvent('editingChange', {
|
|
391
|
-
detail: { record, editing: false },
|
|
392
|
-
bubbles: true
|
|
393
|
-
}));
|
|
394
418
|
}
|
|
395
419
|
|
|
396
420
|
cancelEditedRecord(record) {
|
|
@@ -649,69 +673,79 @@ export default class Table extends ShadowComponent {
|
|
|
649
673
|
|
|
650
674
|
deleteRecord(record) {
|
|
651
675
|
let originalRecord = this.records.find(r => r === record);
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
if
|
|
655
|
-
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
if (originalRecord) {
|
|
676
|
+
const totalPagesBefore = this.getTotalPages();
|
|
677
|
+
if(!originalRecord && record[index] !== undefined) originalRecord = this.records[record[index]];
|
|
678
|
+
if(!originalRecord) return;
|
|
679
|
+
const commit = () => {
|
|
659
680
|
const recordIndex = this.records.indexOf(originalRecord);
|
|
660
681
|
this.records.splice(recordIndex, 1);
|
|
661
|
-
this.records.forEach((rec, idx) => {
|
|
662
|
-
rec[index] = idx;
|
|
663
|
-
});
|
|
682
|
+
this.records.forEach((rec, idx) => { rec[index] = idx; });
|
|
664
683
|
this.requestUpdate();
|
|
665
684
|
this.dispatchEvent(new CustomEvent('selectionChange', { bubbles: true }));
|
|
666
|
-
this.dispatchEvent(new CustomEvent('recordDeleted', {
|
|
685
|
+
this.dispatchEvent(new CustomEvent('recordDeleted', {
|
|
667
686
|
detail: { index: recordIndex },
|
|
668
|
-
bubbles: true
|
|
687
|
+
bubbles: true
|
|
669
688
|
}));
|
|
670
|
-
|
|
671
689
|
const totalPages = this.getTotalPages();
|
|
672
|
-
if
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
if (totalPages !== totalPagesBefore) {
|
|
676
|
-
this.dispatchEvent(new CustomEvent('pageCountChanged', {
|
|
690
|
+
if(this.currentPage > totalPages) this.setPage(totalPages);
|
|
691
|
+
if(totalPages !== totalPagesBefore){
|
|
692
|
+
this.dispatchEvent(new CustomEvent('pageCountChanged', {
|
|
677
693
|
detail: { totalPages },
|
|
678
|
-
bubbles: true
|
|
694
|
+
bubbles: true
|
|
679
695
|
}));
|
|
680
696
|
}
|
|
697
|
+
};
|
|
698
|
+
if(this.requestDelete){
|
|
699
|
+
const recordEl = this.shadowRoot.querySelector(`.record[data-index="${originalRecord[index]}"]`);
|
|
700
|
+
recordEl?.classList.add('pending');
|
|
701
|
+
const wrappedCommit = () => { recordEl?.classList.remove('pending'); commit(); };
|
|
702
|
+
const reject = () => { recordEl?.classList.remove('pending'); };
|
|
703
|
+
this.dispatchEvent(new CustomEvent('requestDelete', {
|
|
704
|
+
detail: { records: [originalRecord], approve: wrappedCommit, reject },
|
|
705
|
+
bubbles: true
|
|
706
|
+
}));
|
|
707
|
+
} else {
|
|
708
|
+
commit();
|
|
681
709
|
}
|
|
682
710
|
}
|
|
683
711
|
|
|
684
712
|
deleteSelected() {
|
|
685
|
-
|
|
686
|
-
const
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
713
|
+
const totalPagesBefore = this.getTotalPages();
|
|
714
|
+
const originalRecords = this.getSelectedRecords()
|
|
715
|
+
.map(record => this.records.find(r => r === record) ?? (record[index] !== undefined ? this.records[record[index]] : null))
|
|
716
|
+
.filter(Boolean);
|
|
717
|
+
if(!originalRecords.length) return;
|
|
718
|
+
const commit = () => {
|
|
719
|
+
originalRecords.forEach(record => {
|
|
720
|
+
const i = this.records.indexOf(record);
|
|
721
|
+
if(i !== -1) this.records.splice(i, 1);
|
|
722
|
+
});
|
|
723
|
+
this.records.forEach((rec, idx) => { rec[index] = idx; });
|
|
724
|
+
this.requestUpdate();
|
|
725
|
+
const totalPages = this.getTotalPages();
|
|
726
|
+
if(this.currentPage > totalPages) this.setPage(totalPages);
|
|
727
|
+
if(totalPages !== totalPagesBefore){
|
|
728
|
+
this.dispatchEvent(new CustomEvent('pageCountChanged', {
|
|
729
|
+
detail: { totalPages },
|
|
730
|
+
bubbles: true
|
|
731
|
+
}));
|
|
696
732
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
this.
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
this.
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
this.dispatchEvent(new CustomEvent('pageCountChanged', {
|
|
710
|
-
detail: { totalPages },
|
|
711
|
-
bubbles: true
|
|
733
|
+
this.dispatchEvent(new CustomEvent('selectionChange', { bubbles: true }));
|
|
734
|
+
};
|
|
735
|
+
if(this.requestDelete){
|
|
736
|
+
const rowEls = originalRecords
|
|
737
|
+
.map(r => this.shadowRoot.querySelector(`.record[data-index="${r[index]}"]`))
|
|
738
|
+
.filter(Boolean);
|
|
739
|
+
rowEls.forEach(el => el.classList.add('pending'));
|
|
740
|
+
const wrappedCommit = () => { rowEls.forEach(el => el.classList.remove('pending')); commit(); };
|
|
741
|
+
const reject = () => { rowEls.forEach(el => el.classList.remove('pending')); };
|
|
742
|
+
this.dispatchEvent(new CustomEvent('requestDelete', {
|
|
743
|
+
detail: { records: originalRecords, approve: wrappedCommit, reject },
|
|
744
|
+
bubbles: true
|
|
712
745
|
}));
|
|
746
|
+
} else {
|
|
747
|
+
commit();
|
|
713
748
|
}
|
|
714
|
-
this.dispatchEvent(new CustomEvent('selectionChange', { bubbles: true }));
|
|
715
749
|
}
|
|
716
750
|
|
|
717
751
|
getSelectedRecords() {
|
|
@@ -1065,10 +1099,43 @@ export default class Table extends ShadowComponent {
|
|
|
1065
1099
|
tbody tr:last-child td {
|
|
1066
1100
|
border-bottom: none;
|
|
1067
1101
|
}
|
|
1102
|
+
tr.editing td.cell[data-field] {
|
|
1103
|
+
padding: 0;
|
|
1104
|
+
}
|
|
1105
|
+
tr.editing td.cell[data-field] input,
|
|
1106
|
+
tr.editing td.cell[data-field] select {
|
|
1107
|
+
width: 100%;
|
|
1108
|
+
height: 100%;
|
|
1109
|
+
box-sizing: border-box;
|
|
1110
|
+
}
|
|
1111
|
+
tr.pending {
|
|
1112
|
+
pointer-events: none;
|
|
1113
|
+
}
|
|
1114
|
+
tr.pending td {
|
|
1115
|
+
position: relative;
|
|
1116
|
+
overflow: hidden;
|
|
1117
|
+
}
|
|
1118
|
+
tr.pending td::before {
|
|
1119
|
+
content: '';
|
|
1120
|
+
position: absolute;
|
|
1121
|
+
inset: 0;
|
|
1122
|
+
background: linear-gradient(90deg, transparent, rgba(128, 128, 128, 0.15), transparent);
|
|
1123
|
+
transform: translateX(-100%);
|
|
1124
|
+
animation: row-pending 1.2s ease-in-out infinite;
|
|
1125
|
+
}
|
|
1126
|
+
@keyframes row-pending {
|
|
1127
|
+
0% { transform: translateX(-100%); }
|
|
1128
|
+
100% { transform: translateX(100%); }
|
|
1129
|
+
}
|
|
1068
1130
|
th.controls,
|
|
1069
1131
|
td.controls {
|
|
1070
1132
|
padding: 0;
|
|
1071
1133
|
}
|
|
1134
|
+
td.controls-after,
|
|
1135
|
+
td.controls-before {
|
|
1136
|
+
display: flex;
|
|
1137
|
+
align-items: center;
|
|
1138
|
+
}
|
|
1072
1139
|
.field-select,
|
|
1073
1140
|
.selection {
|
|
1074
1141
|
width: 40px;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import TableControl from './TableControl.js';
|
|
2
|
+
import { html } from '../../lit-all.min.js';
|
|
3
|
+
import '../Icon.js';
|
|
4
|
+
|
|
5
|
+
export default class DeleteSelected extends TableControl {
|
|
6
|
+
/*
|
|
7
|
+
Public Methods
|
|
8
|
+
*/
|
|
9
|
+
deleteSelected = () => {
|
|
10
|
+
this.table.deleteSelected();
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
Rendering
|
|
15
|
+
*/
|
|
16
|
+
render() {
|
|
17
|
+
return html`
|
|
18
|
+
<button class="no-btn icon-btn" title="Delete Selected" @click="${this.deleteSelected}">
|
|
19
|
+
<slot>
|
|
20
|
+
<k-icon name="delete_sweep"></k-icon>
|
|
21
|
+
</slot>
|
|
22
|
+
</button>
|
|
23
|
+
`;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
customElements.define('k-tc-delete-selected', DeleteSelected);
|