oda-framework
Version:
334 lines (333 loc) • 9.41 kB
JavaScript
ODA({
is: 'oda-grid',
template: /*html*/`
<style>
:host{
--vertical;
overflow: auto;
}
:host > oda-grid-head{
top: 0px;
position: sticky;
}
}
:host > oda-grid-foot{
bottom: 0px;
position: sticky;
}
:host > oda-grid-pagination-panel{
position: sticky;
left: 0;
}
</style>
<div style="display: table;" class="flex">
<oda-grid-head></oda-grid-head>
<oda-grid-body id="body"></oda-grid-body>
<!-- <oda-grid-foot></oda-grid-foot> -->
</div>
<oda-grid-pagination-panel></oda-grid-pagination-panel>
`,
$pdp: {
columns: {
set(n) {
this._columns = n?.map?.(c => ({ $column: c })) || [];
}
},
_columns: [],
rows: [],
_rows: {
get() {
return this.rows.map(r => ({ $data: r }));
}
},
rowHeight: 32,
allRowsCount: 0,
get screenLength() {
return ~~((this.offsetHeight - 3 * this.rowHeight) / this.rowHeight);
},
screenFrom: 0,
screen: {
get() {
return {
from: this.screenFrom,
length: this.screenLength
};
}
},
focusedRow: null,
valueCellTemplate: 'oda-grid-cell-value',
emptyRow: {},
sorts: [],
currentPage: {
$def: 0,
set(n) {
this.currentPage = n;
this.screenFrom = n * this.screenLength;
this.screen = undefined;
}
},
},
get bodyHeight() {
return this.$('#body')?.offsetHeight;
},
$listeners: {
resize() {
this.screenLength = undefined;
}
},
onRowDblClick(row) {
},
onRowClick(row) {
if (row === this.emptyRow) {
this.focusedRow = null;
return;
}
this.focusedRow = row;
}
});
ODA({
is: 'oda-grid-body',
template: /*html*/`
<style>
:host{
display: table-row-group;
}
</style>
<oda-grid-row ~for="_rows" :row="$for.item" ~style="{outline: focusedRow === $for.item ? '1px solid var(--focused-color)' : ''}"></oda-grid-row>
`
});
ODA({
is: 'oda-grid-head',
template: /*html*/`
<style>
:host{
display: table-header-group;
}
</style>
<oda-grid-head-row ~for="_rows" :row="$for.item" ~style="{outline: focusedRow === $for.item ? '1px solid var(--focused-color)' : ''}"></oda-grid-head-row>
`,
_rows: {
get() {
return [Object.fromEntries(this._columns.map(c => [c.$column.name, (c.$column.label || c.$column.name)]))].map(r => ({ $data: r }));
}
}
});
ODA({
is: 'oda-grid-foot',
template: /*html*/`
<style>
:host{
display: table-footer-group;
}
</style>
`,
_rows: {
get() {
return [Object.fromEntries(this._columns.map(c => [c.$column.name, (c.$column.label || c.$column.name)]))].map(r => ({ $data: r }));
}
}
});
ODA({
is: 'oda-grid-row',
template: /*html*/`
<style>
:host{
display: table-row;
}
</style>
<oda-grid-cell ~for="cells" :column="_columns[$for.index]" :row></oda-grid-cell>
`,
row: null,
get cells() {
return this._columns.map(c => this.row[c.$column.name]);
},
$listeners: {
dblclick(e) {
this.onRowDblClick(this.row);
},
tap(e) {
this.onRowClick(this.row);
}
}
});
ODA({
is: 'oda-grid-head-row',
template: /*html*/`
<style>
:host{
display: table-row;
}
</style>
<oda-grid-head-cell ~for="cells" :column="_columns[$for.index]" :row :value-cell-template="'oda-grid-cell-value'"></oda-grid-head-cell>
`,
row: null,
get cells() {
return this._columns.map(c => this.row[c.$column.name]);
},
$listeners: {
dblclick(e) {
this.onRowDblClick(this.row);
},
tap(e) {
this.onRowClick(this.row);
}
},
onRowDblClick() {
return;
}
});
ODA({
is: 'oda-grid-cell',
template: /*html*/`
<style>
:host{
display: table-cell;
border: {{isEmpty ? '1px solid transparent' : '1px solid gray'}};
box-sizing: border-box;
padding: 0px 8px;
vertical-align: middle;
background-color: var(--content-background);
height: {{rowHeight}}px;
}
{{''}}
</style>
<div ~is="_cellValueTemplate" :column :row></div>
`,
column: null,
row: null,
isEmpty: {
get() {
return this.row === this.emptyRow;
}
},
get _cellValueTemplate() {
if (this.isEmpty) return 'div';
return this.row?.cellValueTemplate || this.column?.cellValueTemplate || this.valueCellTemplate;
}
});
ODA({
is: 'oda-grid-head-cell',
template: /*html*/`
<style>
:host{
display: table-cell;
border: 1px solid gray;
box-sizing: border-box;
padding: 0px 8px;
vertical-align: middle;
--header;
height: {{rowHeight}}px;
resize: horizontal;
overflow: hidden;
}
:host .dimmed{
opacity: 0.3;
}
{{''}}
</style>
<div class="horizontal" style="align-items: center">
<oda-grid-cell-value :column :row class="flex"></oda-grid-cell-value>
<oda-icon :icon="sortIcon" .stop="onSortTap" ~class="{dimmed: !column.sort}" :bubble="sortIndex" style="margin-left: 4px;"></oda-icon>
</div>
`,
get sortIcon() {
return this.column.sort === 'a'
? 'iconoir:sort-down'
: this.column.sort === 'd'
? 'iconoir:sort-up'
: 'iconoir:sort';
},
column: null,
row: null,
get _cellValueTemplate() {
return this.row?.cellValueTemplate || this.column?.cellValueTemplate || this.valueCellTemplate;
},
onSortTap() {
this.column.sort = this.column.sort === 'a'
? 'd'
: this.column.sort === 'd'
? ''
: 'a';
const idx = this.sorts.indexOf(this.column);
if (this.column.sort) {
if (!~idx) {
this.sorts.push(this.column);
}
}
else {
if (~idx) {
this.sorts.splice(idx, 1);
}
}
},
get sortIndex() {
return this.sorts.indexOf(this.column) + 1;
},
$listeners: {
resize() {
this.column.width = this.offsetWidth;
}
}
});
ODA({
is: 'oda-grid-cell-value',
template: /*html*/`
<div>{{value}}</div>
`,
column: null,
row: null,
value: {
get() {
return this.row.$data[this.column.$column.name] || '';
}
}
});
ODA({
is: 'oda-grid-pagination-panel', imports: '@oda/button, @oda/menu',
template: /*html*/`
<style>
:host{
--horizontal;
align-items: center;
}
</style>
<oda-button :disabled="currentPage === 0" ="_toFirst" icon="bootstrap:chevron-double-left"></oda-button>
<oda-button :disabled="currentPage === 0" ="_toPrevious" icon="bootstrap:chevron-left"></oda-button>
<oda-button :label="currentPage + 1 + '/' + pageCount" ="showDD"></oda-button>
<oda-button :disabled="currentPage === pageCount - 1 || pageCount === 0" ="_toNext" icon="bootstrap:chevron-right"></oda-button>
<oda-button :disabled="currentPage === pageCount - 1 || pageCount === 0" ="_toLast" icon="bootstrap:chevron-double-right"></oda-button>
<!-- <oda-button ~for="buttons" ~props="$for.item" :focused="currentPage === $for.item.index"></oda-button> -->
`,
pages: {
get() {
const result = [];
for (let i = 0; i < this.pageCount; i++) {
result.push({ label: String(i + 1), val: i });
}
return result;
}
},
pageCount: {
get() {
return Math.ceil(this.allRowsCount / this.screenLength);
}
},
async showDD() {
const res = await ODA.showDropdown('oda-menu', { parent: this, items: this.pages });
const page = res?.control?.focusedItem;
if (!page) return;
this.currentPage = page.val;
},
_toFirst() {
this.currentPage = 0;
},
_toPrevious() {
this.currentPage--;
},
_toNext() {
this.currentPage++;
},
_toLast() {
this.currentPage = this.pageCount - 1;
},
});