UNPKG

oda-framework

Version:

It's an ES Progressive Framework based on the technology of Web Components and designed especially for creating custom UI/UX of any complexity for web and cross-platform PWA mobile applications.

334 lines (333 loc) 9.41 kB
ODA({ is: 'oda-grid', template: /*html*/` <style> :host{ @apply --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; @apply --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" @tap.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{ @apply --horizontal; align-items: center; } </style> <oda-button :disabled="currentPage === 0" @tap="_toFirst" icon="bootstrap:chevron-double-left"></oda-button> <oda-button :disabled="currentPage === 0" @tap="_toPrevious" icon="bootstrap:chevron-left"></oda-button> <oda-button :label="currentPage + 1 + '/' + pageCount" @tap="showDD"></oda-button> <oda-button :disabled="currentPage === pageCount - 1 || pageCount === 0" @tap="_toNext" icon="bootstrap:chevron-right"></oda-button> <oda-button :disabled="currentPage === pageCount - 1 || pageCount === 0" @tap="_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; }, });