tablevu 0.3.0-beta.2 → 0.3.0-beta.3

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/dist/array.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { TablevuSort, TablevuColumn } from './table';
1
+ import type { TablevuSort, TablevuColumn } from './types';
2
2
  export interface ArrayAdapterParams {
3
3
  pageSize?: number;
4
4
  currPage?: number;
package/dist/table.d.ts CHANGED
@@ -1,115 +1,5 @@
1
1
  import { PropType, EmitsOptions } from 'vue';
2
- export type TablevuStatus = -1 | 0 | 1;
3
- export declare const TablevuStatus: {
4
- Error: TablevuStatus;
5
- Ready: TablevuStatus;
6
- Loading: TablevuStatus;
7
- };
8
- export interface TablevuColumn {
9
- name: string;
10
- label?: string;
11
- type?: 'string' | 'number' | 'numeric' | 'integer' | 'date' | 'time' | 'datetime' | 'boolean';
12
- align?: 'left' | 'center' | 'right';
13
- width?: string;
14
- style?: Record<string, string>;
15
- render?: (row: any) => any;
16
- colspan?: number;
17
- depth?: string[];
18
- header?: {
19
- colspan?: number;
20
- style?: Record<string, string>;
21
- align?: string;
22
- };
23
- popup?: boolean;
24
- filter?: any;
25
- }
26
- export interface TablevuSort {
27
- index?: number;
28
- name?: string;
29
- dir?: 'asc' | 'desc' | null | string;
30
- }
31
- export interface TablevuGroup {
32
- value?: string | number | bigint | ((row: any) => any);
33
- content?: string | number | ((row: any) => any);
34
- expandAll?: boolean;
35
- class?: string;
36
- }
37
- export interface TablevuPageSettings {
38
- size?: number;
39
- type?: 'incremental' | 'dynamic';
40
- }
41
- export interface TablevuFooterSettings {
42
- button?: {
43
- class?: string;
44
- };
45
- }
46
- export interface TablevuSettings {
47
- group?: TablevuGroup;
48
- page?: TablevuPageSettings;
49
- sort?: TablevuSort[];
50
- columns?: TablevuColumn[];
51
- searchMinChar?: number;
52
- footer?: TablevuFooterSettings;
53
- onData?: (rows: any[]) => any[];
54
- }
55
- export interface TablevuProps {
56
- settings?: TablevuSettings;
57
- data?: any[] | ((params: any, data: any[]) => Promise<any>);
58
- group?: string | object;
59
- search?: string;
60
- filter?: any;
61
- command?: Array<{
62
- name: string;
63
- }>;
64
- rowid?: string;
65
- onRowClick?: (event: MouseEvent, row: any) => void;
66
- onRowDblClick?: (event: MouseEvent, row: any) => void;
67
- class?: string;
68
- style?: string;
69
- }
70
- export interface TablevuEmits {
71
- (e: 'onRowClick', event: MouseEvent, row: any): void;
72
- (e: 'onRowDblClick', event: MouseEvent, row: any): void;
73
- }
74
- interface AdapterResult {
75
- rows: any[];
76
- count: number;
77
- }
78
- type AdapterFunction = (params: {
79
- pageSize: number;
80
- currPage: number;
81
- sort: TablevuSort[];
82
- cols: TablevuColumn[];
83
- filter: any;
84
- search: string | null;
85
- }, data: any[]) => Promise<AdapterResult>;
86
- interface TablevuSpec {
87
- caption: any;
88
- group: TablevuGroup & {
89
- value: any;
90
- content: any;
91
- expandAll: boolean;
92
- class: string;
93
- };
94
- page: {
95
- count: number;
96
- size: number;
97
- current: number;
98
- type: string | null;
99
- };
100
- sort: TablevuSort[];
101
- columns: TablevuColumn[];
102
- footer: {
103
- button: {
104
- class: string;
105
- };
106
- };
107
- status: TablevuStatus;
108
- time: number | null;
109
- search: string | null;
110
- filter: any;
111
- onData?: (rows: any[]) => any[];
112
- }
2
+ import type { TablevuSettings, TablevuProps, TablevuSpec, AdapterFunction } from './types';
113
3
  interface TableSetupReturn {
114
4
  spec: TablevuSpec;
115
5
  renderHeader: () => any[];
@@ -135,12 +25,6 @@ declare const tablevu: {
135
25
  readonly filter: {
136
26
  readonly type: PropType<any>;
137
27
  };
138
- readonly command: {
139
- readonly type: PropType<Array<{
140
- name: string;
141
- }>>;
142
- readonly default: () => never[];
143
- };
144
28
  readonly rowid: {
145
29
  readonly type: PropType<string>;
146
30
  };
@@ -160,12 +44,7 @@ declare const tablevu: {
160
44
  };
161
45
  };
162
46
  emits: EmitsOptions;
163
- setup(props: TablevuProps, { attrs, slots, emit, expose }: {
164
- attrs: any;
165
- slots: any;
166
- emit: any;
167
- expose: any;
168
- }): TableSetupReturn;
47
+ setup(props: TablevuProps, { attrs, slots, emit, expose }: any): TableSetupReturn;
169
48
  render(props: TablevuProps): import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
170
49
  [key: string]: any;
171
50
  }>;
@@ -81,6 +81,7 @@ const TablevuStatus = {
81
81
  Ready: 0,
82
82
  Loading: 1
83
83
  };
84
+
84
85
  const tablevu = {
85
86
  props: {
86
87
  settings: { type: Object, default: null },
@@ -88,14 +89,13 @@ const tablevu = {
88
89
  group: { type: [String, Object] },
89
90
  search: { type: String },
90
91
  filter: { type: [Array, Object] },
91
- command: { type: Array, default: () => [] },
92
92
  rowid: { type: String },
93
93
  onRowClick: { type: Function },
94
94
  onRowDblClick: { type: Function },
95
95
  class: { type: String, default: 'table' },
96
96
  style: { type: String, default: null }
97
97
  },
98
- emits: ['onRowClick', 'onRowDblClick'],
98
+ emits: ['onRowClick', 'onRowDblClick', 'selectionChange', 'columnVisibilityChange'],
99
99
  setup(props, { attrs, slots, emit, expose }) {
100
100
  let rows = [];
101
101
  let rowg = [];
@@ -105,16 +105,16 @@ const tablevu = {
105
105
  const spec = reactive({
106
106
  caption: null,
107
107
  group: {
108
- value: (props.settings && props.settings.group) ? props.settings.group.value : props.group ? props.group : null,
109
- content: (props.settings && props.settings.group) ? props.settings.group.content : null,
108
+ value: (props.settings && props.settings.group) ? props.settings.group.value : props.group ? props.group : undefined,
109
+ content: (props.settings && props.settings.group) ? props.settings.group.content : undefined,
110
110
  expandAll: true,
111
111
  class: 'table-light'
112
112
  },
113
113
  page: {
114
114
  count: 0,
115
- size: (props.settings && props.settings.page) ? props.settings.page.size : 0,
115
+ size: (props.settings && props.settings.page) ? (props.settings.page.size || 0) : 0,
116
116
  current: 0,
117
- type: null
117
+ type: undefined
118
118
  },
119
119
  sort: (props.settings && props.settings.sort) ? props.settings.sort : [],
120
120
  columns: (props.settings && props.settings.columns) ? props.settings.columns : [],
@@ -127,7 +127,11 @@ const tablevu = {
127
127
  time: null,
128
128
  search: null,
129
129
  filter: null,
130
- onData: (props.settings && props.settings.onData) ? props.settings.onData : undefined
130
+ onData: (props.settings && props.settings.onData) ? props.settings.onData : undefined,
131
+ selectedRows: [],
132
+ columnWidths: {},
133
+ columnOrder: [],
134
+ columnVisibility: {}
131
135
  });
132
136
  if (props.data) {
133
137
  if (Array.isArray(props.data)) {
@@ -163,32 +167,6 @@ const tablevu = {
163
167
  spec.filter = null;
164
168
  refresh();
165
169
  }, { deep: true });
166
- watch(() => props.command, (n, o) => {
167
- if (n && n.length > 0) {
168
- const c = props.command[n.length - 1];
169
- if (c && c.name) {
170
- switch (c.name.toLowerCase()) {
171
- case 'refresh':
172
- refresh();
173
- break;
174
- case 'first':
175
- first();
176
- break;
177
- case 'prior':
178
- prior();
179
- break;
180
- case 'next':
181
- next();
182
- break;
183
- case 'last':
184
- last();
185
- break;
186
- default: console.log('Unknown command');
187
- }
188
- }
189
- props.command.length = 0;
190
- }
191
- }, { deep: true });
192
170
  function prepareGroup(g, r) {
193
171
  grps = [];
194
172
  rowg = [];
@@ -227,28 +205,26 @@ const tablevu = {
227
205
  rowg.push(n);
228
206
  }
229
207
  }
230
- function first() { page(1); }
208
+ function first() { loadPage(1); }
231
209
  function prior() {
232
210
  if (spec.page.current > 1) {
233
- page(spec.page.current - 1);
211
+ loadPage(spec.page.current - 1);
234
212
  }
235
213
  else {
236
- page(spec.page.current);
214
+ loadPage(spec.page.current);
237
215
  }
238
216
  }
239
- function next() { page(spec.page.current + 1); }
240
- function last() { page(spec.page.count); }
241
- function go() {
242
- let p;
243
- let g = spec.page.current;
244
- do {
245
- p = prompt(undefined, String(spec.page.current));
246
- g = parseInt(p || '0');
247
- } while (p && isNaN(g));
248
- if (g && g > 0 && g != spec.page.current)
249
- page(g);
217
+ function next() { loadPage(spec.page.current + 1); }
218
+ function last() { loadPage(spec.page.count); }
219
+ // Navigate to specific page number
220
+ function page(currentPage) {
221
+ if (currentPage < 1)
222
+ currentPage = 1;
223
+ if (currentPage > spec.page.count && spec.page.count > 0)
224
+ currentPage = spec.page.count;
225
+ loadPage(currentPage);
250
226
  }
251
- function refresh() { page(spec.page.current); }
227
+ function refresh() { loadPage(spec.page.current); }
252
228
  function orderby(ind, dir) {
253
229
  if (spec.sort && spec.sort.length > 0) {
254
230
  let l = spec.sort.findIndex(f => f.index == ind);
@@ -272,9 +248,10 @@ const tablevu = {
272
248
  else {
273
249
  spec.sort.push({ index: ind, dir: dir ? dir : null });
274
250
  }
275
- page(spec.page.current);
251
+ loadPage(spec.page.current);
276
252
  }
277
- function page(currentPage) {
253
+ // Internal load function (alias for adapter call)
254
+ function loadPage(currentPage) {
278
255
  let dat = null;
279
256
  if (props.data) {
280
257
  if (Array.isArray(props.data))
@@ -284,8 +261,9 @@ const tablevu = {
284
261
  return;
285
262
  spec.status = TablevuStatus.Loading;
286
263
  if (adapter) {
264
+ const pageSize = spec.page.size || 20;
287
265
  adapter({
288
- pageSize: spec.page.size,
266
+ pageSize,
289
267
  currPage: currentPage,
290
268
  sort: spec.sort,
291
269
  cols: spec.columns,
@@ -299,7 +277,7 @@ const tablevu = {
299
277
  const groupValue = spec.group.value;
300
278
  if (groupValue && (typeof groupValue == 'string' || typeof groupValue == 'number' || typeof groupValue == 'bigint' || (typeof groupValue == 'object' && groupValue.value)))
301
279
  prepareGroup(spec.group, rows);
302
- spec.page.count = (ada.count > 0 && spec.page.size > 0) ? Math.ceil(ada.count / spec.page.size) : 0;
280
+ spec.page.count = (ada.count > 0 && pageSize > 0) ? Math.ceil(ada.count / pageSize) : 0;
303
281
  spec.page.current = currentPage;
304
282
  spec.status = TablevuStatus.Ready;
305
283
  spec.time = Date.now();
@@ -361,8 +339,8 @@ const tablevu = {
361
339
  o.style['text-align'] = col.align;
362
340
  if (col.width)
363
341
  o.style['max-width'] = col.width;
364
- const f = col.render(row);
365
- return h('td', o, f);
342
+ const f = col.render?.(row) ?? '';
343
+ return h('td', { ...o, innerHTML: f });
366
344
  }
367
345
  function renderGroup(grp) {
368
346
  const b = h('button', {
@@ -421,6 +399,10 @@ const tablevu = {
421
399
  }
422
400
  };
423
401
  }
402
+ // Selection
403
+ if (spec.selectedRows.some(s => s[props.rowid || 'id'] === row[props.rowid || 'id'])) {
404
+ o.class = (o.class || '') + ' selected';
405
+ }
424
406
  return h('tr', o, r);
425
407
  }
426
408
  function renderHeader() {
@@ -471,7 +453,10 @@ const tablevu = {
471
453
  else
472
454
  a = h('a', { href: '#', onClick: (event) => { orderby(i); event.preventDefault(); }, style: cy }, cl);
473
455
  if (spec.columns[i].filter) ;
474
- ar.push(h('th', { colspan: null, style: ch }, [a, f]));
456
+ ar.push(h('th', {
457
+ colspan: null,
458
+ style: ch
459
+ }, [a, f]));
475
460
  }
476
461
  const tr = h('tr', {}, ar);
477
462
  return [tr];
@@ -499,14 +484,34 @@ const tablevu = {
499
484
  }
500
485
  }
501
486
  }
487
+ else if (spec.settings?.emptyMessage) {
488
+ dr.push(h('tr', {}, h('td', { colspan: spec.columns.length, style: { textAlign: 'center', padding: '2rem', color: '#666' } }, spec.settings.emptyMessage)));
489
+ }
502
490
  return dr;
503
491
  }
492
+ // Prompt user for page number and navigate
493
+ function goToPage() {
494
+ const input = prompt('Page number:', String(spec.page.current));
495
+ if (input) {
496
+ const pageNum = parseInt(input, 10);
497
+ if (!isNaN(pageNum) && pageNum > 0 && pageNum !== spec.page.current) {
498
+ page(pageNum);
499
+ }
500
+ }
501
+ }
502
+ function makeHandler(fn) {
503
+ return (e) => {
504
+ e.preventDefault();
505
+ e.stopPropagation();
506
+ fn();
507
+ };
508
+ }
504
509
  function renderFooter() {
505
- const fr = h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: first, disabled: spec.page.current == 1 }, '◀◀');
506
- const ls = h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: last, disabled: spec.page.count == 0 || spec.page.current == spec.page.count }, '▶▶');
507
- const pg = h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: go }, spec.page.current + (spec.page.count > 0 ? (' / ' + spec.page.count) : ''));
508
- const pr = h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: prior, disabled: spec.page.current == 1 }, '◀');
509
- const nx = h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: next, disabled: spec.page.count > 0 && spec.page.current == spec.page.count }, '▶');
510
+ const fr = h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: makeHandler(first), disabled: spec.page.current == 1 }, '◀◀');
511
+ const ls = h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: makeHandler(last), disabled: spec.page.count == 0 || spec.page.current == spec.page.count }, '▶▶');
512
+ const pg = h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: makeHandler(goToPage) }, spec.page.current + (spec.page.count > 0 ? (' / ' + spec.page.count) : ''));
513
+ const pr = h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: makeHandler(prior), disabled: spec.page.current == 1 }, '◀');
514
+ const nx = h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: makeHandler(next), disabled: spec.page.count > 0 && spec.page.current == spec.page.count }, '▶');
510
515
  const td = h('td', { colspan: spec.columns.length, align: 'center' }, [fr, pr, pg, nx, ls]);
511
516
  const tr = h('tr', {}, [td]);
512
517
  return [tr];
@@ -514,19 +519,41 @@ const tablevu = {
514
519
  function renderCaption() {
515
520
  return null;
516
521
  }
522
+ // Initialize column metadata
517
523
  if (spec.columns.length == 0) {
518
524
  console.error('Columns not defined !');
519
525
  }
520
- for (let i = 0; i < spec.columns.length; i++)
526
+ for (let i = 0; i < spec.columns.length; i++) {
521
527
  if (spec.columns[i].name && spec.columns[i].name.indexOf('.') > -1) {
522
528
  spec.columns[i].depth = spec.columns[i].name.split('.');
523
529
  }
524
- page(1);
530
+ // Initialize visibility
531
+ if (spec.columns[i].visible === undefined) {
532
+ spec.columns[i].visible = true;
533
+ spec.columnVisibility[spec.columns[i].name] = true;
534
+ }
535
+ }
536
+ loadPage(1);
537
+ // Expose methods for external access via ref
538
+ expose({
539
+ first,
540
+ prior,
541
+ next,
542
+ last,
543
+ page,
544
+ refresh,
545
+ orderby,
546
+ getSelectedRows: () => spec.selectedRows,
547
+ setSelectedRows: (rows) => { spec.selectedRows = rows; }
548
+ });
525
549
  onMounted(() => {
526
550
  // mounted hook
527
551
  });
528
552
  return {
529
- spec, renderHeader, renderBody, renderFooter, renderCaption
553
+ spec, renderHeader, renderBody, renderFooter, renderCaption,
554
+ first, prior, next, last, page, refresh, orderby,
555
+ getSelectedRows: () => spec.selectedRows,
556
+ setSelectedRows: (rows) => { spec.selectedRows = rows; }
530
557
  };
531
558
  },
532
559
  render(props) {
@@ -1072,4 +1099,4 @@ const param = (uri, header, props) => {
1072
1099
  return new Request(url, header);
1073
1100
  };
1074
1101
 
1075
- export { tablevu as TableVu, TablevuStatus, adaptArray, toODataFilter as buildFilter, odata, param as webapi };
1102
+ export { tablevu as TableVu, adaptArray, toODataFilter as buildFilter, odata, param as webapi };