tablevu 0.3.0-beta.2 → 0.3.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,560 +0,0 @@
1
- (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vue')) :
3
- typeof define === 'function' && define.amd ? define(['exports', 'vue'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.tablevu = {}, global.Vue));
5
- })(this, (function (exports, vue) { 'use strict';
6
-
7
- function adaptArray(props, data) {
8
- const d = Array.isArray(data) ? [...data] : [];
9
- return new Promise((resolve, reject) => {
10
- try {
11
- // Filter & Search //
12
- if (props.filter || props.search) {
13
- const searchableCols = props.cols
14
- ?.map((m, i) => ({ index: i, searchable: m.searchable !== false }))
15
- .filter(q => q.searchable)
16
- .map(m => m.index) || [];
17
- let filtered = d;
18
- if (props.filter) {
19
- filtered = filtered.filter(row => {
20
- return Object.entries(props.filter).every(([key, value]) => {
21
- return row[key] === value;
22
- });
23
- });
24
- }
25
- if (props.search && searchableCols.length > 0) {
26
- const searchLower = props.search.toLowerCase();
27
- filtered = filtered.filter(row => {
28
- return searchableCols.some(colIndex => {
29
- const col = props.cols?.[colIndex];
30
- if (!col)
31
- return false;
32
- const val = row[col.name];
33
- return val && String(val).toLowerCase().includes(searchLower);
34
- });
35
- });
36
- }
37
- // Update d with filtered results
38
- d.length = 0;
39
- d.push(...filtered);
40
- }
41
- // Sort //
42
- if (props.sort && props.sort.length > 0) {
43
- for (let i = props.sort.length - 1; i >= 0; i--) {
44
- const s = props.sort[i];
45
- let field;
46
- if (s.index !== undefined && s.index >= 0 && props.cols?.[s.index]) {
47
- field = props.cols[s.index].name;
48
- }
49
- else {
50
- field = s.name || '';
51
- }
52
- if (!field)
53
- continue;
54
- const dir = s.dir === 'desc' ? -1 : 1;
55
- d.sort((a, b) => {
56
- const av = a[field];
57
- const bv = b[field];
58
- if (av === bv)
59
- return 0;
60
- if (av === null || av === undefined)
61
- return 1;
62
- if (bv === null || bv === undefined)
63
- return -1;
64
- return (av > bv ? 1 : -1) * dir;
65
- });
66
- }
67
- }
68
- // Paging //
69
- let result = d;
70
- if (props.pageSize && props.pageSize > 0) {
71
- const start = (props.currPage - 1) * props.pageSize;
72
- const end = props.currPage * props.pageSize;
73
- result = d.slice(start, end);
74
- }
75
- resolve({ rows: result, count: d.length });
76
- }
77
- catch (err) {
78
- reject(err);
79
- }
80
- });
81
- }
82
-
83
- const TablevuStatus = {
84
- Error: -1,
85
- Ready: 0,
86
- Loading: 1
87
- };
88
- const tablevu = {
89
- props: {
90
- settings: { type: Object, default: null },
91
- data: { type: [Array, Function] },
92
- group: { type: [String, Object] },
93
- search: { type: String },
94
- filter: { type: [Array, Object] },
95
- command: { type: Array, default: () => [] },
96
- rowid: { type: String },
97
- onRowClick: { type: Function },
98
- onRowDblClick: { type: Function },
99
- class: { type: String, default: 'table' },
100
- style: { type: String, default: null }
101
- },
102
- emits: ['onRowClick', 'onRowDblClick'],
103
- setup(props, { attrs, slots, emit, expose }) {
104
- let rows = [];
105
- let rowg = [];
106
- let grps = [];
107
- let adapter = null;
108
- let timer = null;
109
- const spec = vue.reactive({
110
- caption: null,
111
- group: {
112
- value: (props.settings && props.settings.group) ? props.settings.group.value : props.group ? props.group : null,
113
- content: (props.settings && props.settings.group) ? props.settings.group.content : null,
114
- expandAll: true,
115
- class: 'table-light'
116
- },
117
- page: {
118
- count: 0,
119
- size: (props.settings && props.settings.page) ? props.settings.page.size : 0,
120
- current: 0,
121
- type: null
122
- },
123
- sort: (props.settings && props.settings.sort) ? props.settings.sort : [],
124
- columns: (props.settings && props.settings.columns) ? props.settings.columns : [],
125
- footer: {
126
- button: {
127
- class: (props.settings && props.settings.footer && props.settings.footer.button && props.settings.footer.button.class) || 'btn'
128
- }
129
- },
130
- status: TablevuStatus.Ready,
131
- time: null,
132
- search: null,
133
- filter: null,
134
- onData: (props.settings && props.settings.onData) ? props.settings.onData : undefined
135
- });
136
- if (props.data) {
137
- if (Array.isArray(props.data)) {
138
- adapter = adaptArray;
139
- }
140
- else {
141
- adapter = props.data;
142
- }
143
- }
144
- if (props.search)
145
- spec.search = props.search;
146
- vue.watch(() => props.search, (n, o) => {
147
- const x = parseInt(String(props.settings?.searchMinChar)) || 3;
148
- if (timer) {
149
- clearTimeout(timer);
150
- timer = null;
151
- }
152
- if (n && n.length > x) {
153
- spec.search = n;
154
- timer = setTimeout(() => { refresh(); timer = null; }, 444);
155
- }
156
- else if (o && o.length > x && (n == undefined || n == null || n.length <= x)) {
157
- spec.search = null;
158
- timer = setTimeout(() => { refresh(); timer = null; }, 444);
159
- }
160
- });
161
- if (props.filter)
162
- spec.filter = props.filter;
163
- vue.watch(() => props.filter, () => {
164
- if (props.filter)
165
- spec.filter = props.filter;
166
- else
167
- spec.filter = null;
168
- refresh();
169
- }, { deep: true });
170
- vue.watch(() => props.command, (n, o) => {
171
- if (n && n.length > 0) {
172
- const c = props.command[n.length - 1];
173
- if (c && c.name) {
174
- switch (c.name.toLowerCase()) {
175
- case 'refresh':
176
- refresh();
177
- break;
178
- case 'first':
179
- first();
180
- break;
181
- case 'prior':
182
- prior();
183
- break;
184
- case 'next':
185
- next();
186
- break;
187
- case 'last':
188
- last();
189
- break;
190
- default: console.log('Unknown command');
191
- }
192
- }
193
- props.command.length = 0;
194
- }
195
- }, { deep: true });
196
- function prepareGroup(g, r) {
197
- grps = [];
198
- rowg = [];
199
- for (let i = 0; i < r.length; i++) {
200
- let v = null;
201
- let c = null;
202
- const o = r[i];
203
- if (g.value) {
204
- if (typeof g.value == 'function')
205
- v = g.value(o);
206
- else
207
- v = o[g.value];
208
- }
209
- else if (typeof g == 'function') {
210
- v = g(o);
211
- }
212
- else {
213
- if (typeof g == 'bigint' || typeof g == 'number') {
214
- const l = parseFloat(String(g));
215
- if (l)
216
- v = o[l];
217
- }
218
- else if (typeof g == 'string')
219
- v = o[g];
220
- }
221
- if (g.content) {
222
- if (typeof g.content == 'function')
223
- c = g.content(o);
224
- else
225
- c = o[g.content];
226
- }
227
- let n = grps.findIndex(f => f.group == v);
228
- if (n == -1) {
229
- n = grps.push({ group: v, content: c, expand: spec.group.expandAll }) - 1;
230
- }
231
- rowg.push(n);
232
- }
233
- }
234
- function first() { page(1); }
235
- function prior() {
236
- if (spec.page.current > 1) {
237
- page(spec.page.current - 1);
238
- }
239
- else {
240
- page(spec.page.current);
241
- }
242
- }
243
- function next() { page(spec.page.current + 1); }
244
- function last() { page(spec.page.count); }
245
- function go() {
246
- let p;
247
- let g = spec.page.current;
248
- do {
249
- p = prompt(undefined, String(spec.page.current));
250
- g = parseInt(p || '0');
251
- } while (p && isNaN(g));
252
- if (g && g > 0 && g != spec.page.current)
253
- page(g);
254
- }
255
- function refresh() { page(spec.page.current); }
256
- function orderby(ind, dir) {
257
- if (spec.sort && spec.sort.length > 0) {
258
- let l = spec.sort.findIndex(f => f.index == ind);
259
- if (l < 0) {
260
- let n = spec.columns[ind]?.name;
261
- l = spec.sort.findIndex(f => f.name == n);
262
- }
263
- if (l == 0) {
264
- spec.sort[l].dir = dir ? dir : (spec.sort[0].dir ? null : 'desc');
265
- }
266
- else if (l > 0) {
267
- spec.sort.splice(l, 1);
268
- }
269
- if (l != 0) {
270
- spec.sort.unshift({ index: ind, dir: dir ? dir : null });
271
- }
272
- if (spec.sort.length > 2) {
273
- spec.sort.pop();
274
- }
275
- }
276
- else {
277
- spec.sort.push({ index: ind, dir: dir ? dir : null });
278
- }
279
- page(spec.page.current);
280
- }
281
- function page(currentPage) {
282
- let dat = null;
283
- if (props.data) {
284
- if (Array.isArray(props.data))
285
- dat = props.data;
286
- }
287
- else
288
- return;
289
- spec.status = TablevuStatus.Loading;
290
- if (adapter) {
291
- adapter({
292
- pageSize: spec.page.size,
293
- currPage: currentPage,
294
- sort: spec.sort,
295
- cols: spec.columns,
296
- filter: spec.filter,
297
- search: spec.search
298
- }, dat).then(ada => {
299
- if (spec.onData)
300
- rows = spec.onData(ada.rows);
301
- else
302
- rows = ada.rows;
303
- const groupValue = spec.group.value;
304
- if (groupValue && (typeof groupValue == 'string' || typeof groupValue == 'number' || typeof groupValue == 'bigint' || (typeof groupValue == 'object' && groupValue.value)))
305
- prepareGroup(spec.group, rows);
306
- spec.page.count = (ada.count > 0 && spec.page.size > 0) ? Math.ceil(ada.count / spec.page.size) : 0;
307
- spec.page.current = currentPage;
308
- spec.status = TablevuStatus.Ready;
309
- spec.time = Date.now();
310
- }).catch(err => {
311
- console.error(err);
312
- spec.status = TablevuStatus.Error;
313
- });
314
- }
315
- }
316
- function renderValue(col, val) {
317
- if (val) {
318
- let v;
319
- if (col.type == 'datetime' || col.type == 'date' || col.type == 'time') {
320
- const t = new Date(val);
321
- if (col.type == 'date')
322
- v = t.toLocaleDateString();
323
- else if (col.type == 'time')
324
- v = t.toLocaleTimeString();
325
- else
326
- v = t.toLocaleString();
327
- }
328
- else {
329
- if (col.type == 'numeric') {
330
- v = parseFloat(val);
331
- }
332
- else {
333
- if (col.type == 'integer') {
334
- v = parseInt(val);
335
- }
336
- else
337
- v = val;
338
- }
339
- }
340
- return v;
341
- }
342
- else
343
- return '';
344
- }
345
- function renderCell(col, val) {
346
- const o = { style: {} };
347
- if (col.colspan && col.colspan > 1)
348
- o.colspan = col.colspan;
349
- if (col.style)
350
- o.style = { ...o.style, ...col.style };
351
- if (col.align)
352
- o.style['text-align'] = col.align;
353
- if (col.width)
354
- o.style['max-width'] = col.width;
355
- const v = renderValue(col, val);
356
- return vue.h('td', o, v);
357
- }
358
- function renderCustomCell(col, row) {
359
- const o = { style: {} };
360
- if (col.colspan && col.colspan > 1)
361
- o.colspan = col.colspan;
362
- if (col.style)
363
- o.style = { ...o.style, ...col.style };
364
- if (col.align)
365
- o.style['text-align'] = col.align;
366
- if (col.width)
367
- o.style['max-width'] = col.width;
368
- const f = col.render(row);
369
- return vue.h('td', o, f);
370
- }
371
- function renderGroup(grp) {
372
- const b = vue.h('button', {
373
- title: String(grp.expand),
374
- onClick: (event) => {
375
- grp.expand = !grp.expand;
376
- event.currentTarget.value = grp.expand ? '▼' : '►';
377
- spec.time = Date.now();
378
- event.preventDefault();
379
- },
380
- style: { padding: 0, margin: '0 6px 0 0', width: '12px', height: '100%', border: 'none', outline: '0', backgroundColor: 'transparent' }
381
- }, grp.expand ? '▼' : '►');
382
- const v = grp.content || grp.group;
383
- return vue.h('tr', {}, vue.h('td', { colspan: spec.columns.length, class: spec.group.class }, [b, v]));
384
- }
385
- function renderRow(index, row) {
386
- const o = { key: index, index: index };
387
- if (props.rowid)
388
- o.rowid = row[props.rowid];
389
- const r = [];
390
- for (let i = 0; i < spec.columns.length; i++) {
391
- const c = spec.columns[i];
392
- if (c.render) {
393
- r.push(renderCustomCell(c, row));
394
- }
395
- else {
396
- let v;
397
- if (c.depth) {
398
- v = row;
399
- for (let j = 0; j < c.depth.length; j++) {
400
- if (v)
401
- v = v[c.depth[j]];
402
- }
403
- }
404
- else {
405
- v = row[c.name];
406
- }
407
- r.push(renderCell(c, v));
408
- }
409
- }
410
- o.ondblclick = (event) => {
411
- const target = event.currentTarget;
412
- const idx = target.getAttribute('index');
413
- if (idx !== null) {
414
- const rowData = rows[parseInt(idx)];
415
- emit('onRowDblClick', event, rowData);
416
- }
417
- };
418
- if (props.onRowClick) {
419
- o.onClick = (event) => {
420
- const target = event.currentTarget;
421
- const idx = target.getAttribute('index');
422
- if (idx !== null) {
423
- const rowData = rows[parseInt(idx)];
424
- props.onRowClick(event, rowData);
425
- }
426
- };
427
- }
428
- return vue.h('tr', o, r);
429
- }
430
- function renderHeader() {
431
- const ar = [];
432
- for (let i = 0; i < spec.columns.length; i++) {
433
- const cl = [];
434
- if (spec.columns[i].label)
435
- cl.push(vue.h('span', spec.columns[i].label));
436
- else
437
- cl.push(vue.h('span', spec.columns[i].name));
438
- if (spec.sort && spec.sort.length > 0 && spec.sort[0].index == i) {
439
- if (spec.sort[0].dir == 'desc')
440
- cl.push(vue.h('span', { style: { float: 'right' } }, '▼'));
441
- else
442
- cl.push(vue.h('span', { style: { float: 'right' } }, '▲'));
443
- }
444
- const ch = { position: 'relative' };
445
- if (spec.columns[i].width) {
446
- ch.width = spec.columns[i].width;
447
- ch.minWidth = spec.columns[i].width;
448
- ch.maxWidth = spec.columns[i].width;
449
- }
450
- const cy = { display: 'block', 'font-weight': 500, textDecoration: 'none', textAlign: 'center' };
451
- let a;
452
- let f;
453
- if (spec.columns[i].popup) {
454
- const r = vue.ref(null);
455
- const c = [
456
- vue.h('a', { href: '#', onClick: (event) => { orderby(i); event.preventDefault(); }, style: { display: 'block', textDecoration: 'none', color: 'black', fontWeight: 'initial', padding: '.25rem' } }, 'Order by Ascending'),
457
- vue.h('a', { href: '#', onClick: (event) => { orderby(i, 'desc'); event.preventDefault(); }, style: { display: 'block', textDecoration: 'none', color: 'black', fontWeight: 'initial', padding: '.25rem' } }, 'Order by Descending'),
458
- ];
459
- a = vue.h('a', {
460
- href: '#',
461
- onClick: (event) => {
462
- if (r.value && r.value.style && r.value.style.display && r.value.style.display == 'block')
463
- r.value.style.display = 'none';
464
- else if (r.value && r.value.style)
465
- r.value.style.display = 'block';
466
- event.preventDefault();
467
- },
468
- style: cy
469
- }, cl);
470
- f = vue.h('div', {
471
- ref: r,
472
- style: { position: 'absolute', display: 'none', width: spec.columns[i].width || '12rem', height: 'fit-content', border: '1px solid lightgray', backgroundColor: 'whitesmoke', zIndex: 1, left: 0, top: '2rem', bottom: 0, right: 0, padding: '.25rem' }
473
- }, c);
474
- }
475
- else
476
- a = vue.h('a', { href: '#', onClick: (event) => { orderby(i); event.preventDefault(); }, style: cy }, cl);
477
- if (spec.columns[i].filter) ;
478
- ar.push(vue.h('th', { colspan: null, style: ch }, [a, f]));
479
- }
480
- const tr = vue.h('tr', {}, ar);
481
- return [tr];
482
- }
483
- function renderBody() {
484
- const dr = [];
485
- if (rows && rows.length > 0) {
486
- if (grps && grps.length > 0) {
487
- const r = [];
488
- for (let g = 0; g < grps.length; g++)
489
- r.push({ index: g, childs: [] });
490
- for (let i = 0; i < rows.length; i++) {
491
- const x = rowg[i];
492
- r[x].childs.push(renderRow(i, rows[i]));
493
- }
494
- for (let g = 0; g < grps.length; g++) {
495
- dr.push(renderGroup(grps[g]));
496
- if (grps[g].expand)
497
- dr.push(r[g].childs);
498
- }
499
- }
500
- else {
501
- for (let i = 0; i < rows.length; i++) {
502
- dr.push(renderRow(i, rows[i]));
503
- }
504
- }
505
- }
506
- return dr;
507
- }
508
- function renderFooter() {
509
- const fr = vue.h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: first, disabled: spec.page.current == 1 }, '◀◀');
510
- const ls = vue.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 }, '▶▶');
511
- const pg = vue.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) : ''));
512
- const pr = vue.h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: prior, disabled: spec.page.current == 1 }, '◀');
513
- const nx = vue.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 }, '▶');
514
- const td = vue.h('td', { colspan: spec.columns.length, align: 'center' }, [fr, pr, pg, nx, ls]);
515
- const tr = vue.h('tr', {}, [td]);
516
- return [tr];
517
- }
518
- function renderCaption() {
519
- return null;
520
- }
521
- if (spec.columns.length == 0) {
522
- console.error('Columns not defined !');
523
- }
524
- for (let i = 0; i < spec.columns.length; i++)
525
- if (spec.columns[i].name && spec.columns[i].name.indexOf('.') > -1) {
526
- spec.columns[i].depth = spec.columns[i].name.split('.');
527
- }
528
- page(1);
529
- vue.onMounted(() => {
530
- // mounted hook
531
- });
532
- return {
533
- spec, renderHeader, renderBody, renderFooter, renderCaption
534
- };
535
- },
536
- render(props) {
537
- let prps = { class: 'tablevu' };
538
- if (props.class)
539
- prps.class = 'tablevu ' + props.class;
540
- if (props.style)
541
- prps.style = props.style;
542
- const cntn = [];
543
- cntn.push(vue.h('thead', {}, this.renderHeader()));
544
- if (this.spec.status == TablevuStatus.Ready)
545
- cntn.push(vue.h('tbody', { 'data-time': this.spec.time }, this.renderBody()));
546
- if (this.spec.caption)
547
- cntn.push(vue.h('caption', {}, this.renderCaption()));
548
- if (this.spec.status == TablevuStatus.Ready)
549
- if (this.spec.page.size > 0)
550
- cntn.push(vue.h('tfoot', {}, this.renderFooter()));
551
- return vue.h('table', prps, cntn);
552
- }
553
- };
554
-
555
- exports.TablevuStatus = TablevuStatus;
556
- exports.default = tablevu;
557
-
558
- Object.defineProperty(exports, '__esModule', { value: true });
559
-
560
- }));
@@ -1,19 +0,0 @@
1
- const param = (uri, header, props) => {
2
- const url = new URL(uri);
3
- // Paging //
4
- if (props.pageSize && props.currentPage) {
5
- url.searchParams.append('skip', String(props.pageSize * (props.currentPage - 1)));
6
- url.searchParams.append('top', String(props.pageSize));
7
- }
8
- // Filter //
9
- if (props.search)
10
- url.searchParams.append('search', props.search);
11
- // Order //
12
- if (props.order && props.order.length > 0 && props.cols) {
13
- url.searchParams.append('orderby', props.order.map(m => props.cols?.[m.index]?.name || '').join(','));
14
- url.searchParams.append('orderdir', props.order.map(m => m.type ? m.type : 'asc').join(','));
15
- }
16
- return new Request(url, header);
17
- };
18
-
19
- export { param as default };
@@ -1,29 +0,0 @@
1
- (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
- typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.tablevu = {}));
5
- })(this, (function (exports) { 'use strict';
6
-
7
- const param = (uri, header, props) => {
8
- const url = new URL(uri);
9
- // Paging //
10
- if (props.pageSize && props.currentPage) {
11
- url.searchParams.append('skip', String(props.pageSize * (props.currentPage - 1)));
12
- url.searchParams.append('top', String(props.pageSize));
13
- }
14
- // Filter //
15
- if (props.search)
16
- url.searchParams.append('search', props.search);
17
- // Order //
18
- if (props.order && props.order.length > 0 && props.cols) {
19
- url.searchParams.append('orderby', props.order.map(m => props.cols?.[m.index]?.name || '').join(','));
20
- url.searchParams.append('orderdir', props.order.map(m => m.type ? m.type : 'asc').join(','));
21
- }
22
- return new Request(url, header);
23
- };
24
-
25
- exports.default = param;
26
-
27
- Object.defineProperty(exports, '__esModule', { value: true });
28
-
29
- }));
package/dist/webapi.d.ts DELETED
@@ -1,15 +0,0 @@
1
- interface WebApiProps {
2
- pageSize?: number;
3
- currentPage?: number;
4
- search?: string;
5
- order?: {
6
- index: number;
7
- type?: string;
8
- }[];
9
- cols?: {
10
- name: string;
11
- type?: string;
12
- }[];
13
- }
14
- declare const param: (uri: string, header: any, props: WebApiProps) => Request;
15
- export default param;