@danielgindi/dgtable.js 2.0.7 → 2.0.8

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.
Files changed (67) hide show
  1. package/README.md +547 -282
  2. package/dist/SelectionHelper.d.ts +24 -0
  3. package/dist/SelectionHelper.d.ts.map +1 -0
  4. package/dist/by_column_filter.d.ts +14 -0
  5. package/dist/by_column_filter.d.ts.map +1 -0
  6. package/dist/cell_preview.d.ts +28 -0
  7. package/dist/cell_preview.d.ts.map +1 -0
  8. package/dist/column_collection.d.ts +41 -0
  9. package/dist/column_collection.d.ts.map +1 -0
  10. package/dist/column_resize.d.ts +25 -0
  11. package/dist/column_resize.d.ts.map +1 -0
  12. package/dist/constants.d.ts +19 -0
  13. package/dist/constants.d.ts.map +1 -0
  14. package/dist/header_events.d.ts +63 -0
  15. package/dist/header_events.d.ts.map +1 -0
  16. package/dist/helpers.d.ts +50 -0
  17. package/dist/helpers.d.ts.map +1 -0
  18. package/dist/index.d.ts +166 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/internal.d.ts +56 -0
  21. package/dist/internal.d.ts.map +1 -0
  22. package/dist/lib.cjs.js +6909 -3929
  23. package/dist/lib.cjs.js.map +1 -1
  24. package/dist/lib.cjs.min.js +2 -2
  25. package/dist/lib.cjs.min.js.map +1 -1
  26. package/dist/lib.es6.js +6911 -3931
  27. package/dist/lib.es6.js.map +1 -1
  28. package/dist/lib.es6.min.js +2 -2
  29. package/dist/lib.es6.min.js.map +1 -1
  30. package/dist/lib.umd.js +9251 -4346
  31. package/dist/lib.umd.js.map +1 -1
  32. package/dist/lib.umd.min.js +2 -2
  33. package/dist/lib.umd.min.js.map +1 -1
  34. package/dist/private_types.d.ts +145 -0
  35. package/dist/private_types.d.ts.map +1 -0
  36. package/dist/rendering.d.ts +57 -0
  37. package/dist/rendering.d.ts.map +1 -0
  38. package/dist/row_collection.d.ts +38 -0
  39. package/dist/row_collection.d.ts.map +1 -0
  40. package/dist/types.d.ts +221 -0
  41. package/dist/types.d.ts.map +1 -0
  42. package/dist/util.d.ts +9 -0
  43. package/dist/util.d.ts.map +1 -0
  44. package/eslint.config.mjs +1 -0
  45. package/package.json +17 -12
  46. package/src/SelectionHelper.ts +90 -0
  47. package/src/by_column_filter.ts +36 -0
  48. package/src/cell_preview.ts +325 -0
  49. package/src/column_collection.ts +131 -0
  50. package/src/column_resize.ts +363 -0
  51. package/src/constants.ts +22 -0
  52. package/src/header_events.ts +369 -0
  53. package/src/helpers.ts +291 -0
  54. package/src/index.ts +1628 -0
  55. package/src/internal.ts +263 -0
  56. package/src/private_types.ts +156 -0
  57. package/src/rendering.ts +771 -0
  58. package/src/row_collection.ts +197 -0
  59. package/src/types.ts +265 -0
  60. package/src/util.ts +27 -0
  61. package/tsconfig.json +38 -0
  62. package/src/SelectionHelper.js +0 -65
  63. package/src/by_column_filter.js +0 -25
  64. package/src/column_collection.js +0 -153
  65. package/src/index.js +0 -3991
  66. package/src/row_collection.js +0 -183
  67. package/src/util.js +0 -17
package/README.md CHANGED
@@ -1,288 +1,553 @@
1
- DGTable.js
2
- ==========
3
-
4
- This is a table View for vanilla JS, which is meant to be high-performance, and allow simple user interactions with the UI, such as:
5
- * Sorting
6
- * Sorting by more than one column
7
- * Moving columns
8
- * Resizing columns
9
- * Full cell preview when hovering
10
- * Native RTL support
11
- * Variable row height
12
-
13
- Other features implemented are:
14
- * Mix absolute column widths with relative column widths
15
- * Virtual table mode (to supply high performance with hundreds of thousands of rows). This is the default.
16
- * Non-virtual table mode is fully supported, but for giant amounts of data it is not recommended.
17
- * Option to set a fixed width for the table so resizing (relative) columns will still make sure the table will not be less (and/or more) than the specified width.
18
- * Option to have both scrollbars inside the table. (set `width: DGTable.Width.SCROLL`)
19
-
20
- `jquery.dgtable` users:
21
- * Older `jquery.dgtable` can either keep using `jquery.dgtable`, or migrate to this new version which is more lightweight.
22
- * The new version's API is the same as the old one, except that:
23
- * No `$el` property
24
- * No auto-clear of jQuery data.
25
- * There is now an `emit` method instead of `trigger`.
26
- * Event arguments are now always a single value/object.
27
- * Props on DOM elements are now: `'columnName'` on a cell, `'index'/'vIndex'` on a row, `'columnName'/rowIndex'/'rowVIndex'` on a cellPreview
28
-
29
- My TODO list:
30
- * TODO: Have a simple and accurate API documentation here in the readme
31
-
32
- ## Dev environment
33
-
34
- * Using grunt over Node.js to automate validating and building.
35
- * After installing Node.js, use `npm install`, and `npm install -g grunt-cli` to prepare building environment.
36
- * Use `grunt style` to just test for correct styling.
37
- * Use `grunt build` or just `grunt` to compile for release.
38
- * I am using Google Closure Compiler, because UglifyJS does not work with the JSDoc, and there's a major difference in size & performance of the output code.
39
- * Some features of jshint are disabled because it does not work well with JSDoc which is used for Google Closue Compiler.
40
- * Indentations in my editor are set to 4 spaces, and jshint validates that.
41
-
42
- ## Me
43
- * Hi! I am Daniel Cohen Gindi. Or in short- Daniel.
44
- * danielgindi@gmail.com is my email address.
45
- * That's all you need to know.
46
-
47
- ## Help
48
-
49
- I have invested, and investing, a lot of time in this project.
50
- If you want to help, you could:
51
- * Actually code, and issue pull requests
52
- * Test the library under different conditions and browsers
53
- * Create more demo pages
54
- * Spread the word
55
- *
56
- [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=G22LPLJ79NBYQ)
57
-
58
- ## API
59
-
60
- To create a new table, just use `var myTable = new DGTable(INIT_OPTIONS)`.
61
-
62
- #### `INIT_OPTIONS`
63
-
64
- * **columns**: `COLUMN_OPTIONS[]` (Array of COLUMN_OPTIONS objects)
65
- * **name**: `string` Name of the column
66
- * **label**: `string=name` Used for the header of this column
67
- * **dataPath**: `string=name` Path to the data to show (Defaults to `name`)
68
- * **comparePath**: `string=name` Path to the data to use for comparison (Defaults to `dataPath`)
69
- * **width**: `number|string`
70
- * A simple number (i.e `10`, `30`, `50`) will set an absolute width for the column.
71
- * A percentage (i.e `'30%'`) or a 0-1 decimal value (i.e `0.2`, `0.7`) will set a relative width for the column, out of the full table's width.
72
- * Any other value, like `0`, `null` etc. will set an automatic width mode, base of the header's content length.
73
- * **resizable**: `boolean=true` Is this column resizable?
74
- * **sortable**: `boolean=true` Is this column sortable?
75
- * **movable**: `boolean=true` Is this column movable?
76
- * **visible**: `boolean=true` Is this column visible?
77
- * **cellClasses**: `string` Classes to add to the DOM element of this cell
78
- * **ignoreMin**: `boolean=false` Should this column ignore the minimum width specified for the table columns?
79
- * **height**: `number` Suggested height for the table
80
- * **width**: `DGTable.Width=DGTable.Width.NONE` The way that the width of the table will be handled
81
- * `DGTable.Width.NONE`: No special handling
82
- * `DGTable.Width.AUTO`: Sets the width automatically
83
- * `DGTable.Width.SCROLL`: Creates a horizontal scroll when required
84
- * **virtualTable**: `boolean=true` When set, the table will work in virtual mode, which means only the visible rows are rendered. Rows must have fixed height in this mode.
85
- * **estimatedRowHeight**: `number?` Sets the estimated row height for the table. This is used for virtual table mode, to calculate the estimated scroll size. Will be auto calculated by default.
86
- * **resizableColumns**: `boolean=true` Turns on or off the resizable columns globally.
87
- * **movableColumns**: `boolean=true` Turns on or off the movable columns globally.
88
- * **sortableColumns**: `number=1` How many columns can you sort by, one after another?
89
- * **adjustColumnWidthForSortArrow**: `boolean=true` When set, the columns will automatically grow to accommodate for the sort arrow.
90
- * **relativeWidthGrowsToFillWidth**: `boolean=true` When set, relative width columns automatically grow to fill the table's width.
91
- * **relativeWidthShrinksToFillWidth**: `boolean=false` When set, relative width columns automatically shrink to fill the table's width.
92
- * **convertColumnWidthsToRelative**: `boolean=false` When set, auto-width columns are automatically converted to relatives.
93
- * **autoFillTableWidth**: `boolean=false` When set, columns are stretched proportionally to fill the table width (only if there is space left). Will supersede `relativeWidthGrowsToFillWidth` in the future.
94
- * **allowCancelSort**: `boolean=true` When set, the sorting arrows will have 3 modes - asc, desc, and cancelled.
95
- * **cellClasses**: `string` Classes to add to the DOM element of all cells
96
- * **sortColumn**: `string|string[]|COLUMN_SORT_OPTIONS|COLUMN_SORT_OPTIONS[]` Columns to sort by
97
- * Can be a column or an array of columns.
98
- * Each column is a `string` or a `COLUMN_SORT_OPTIONS`:
99
- * **column**: `string` Column name
100
- * **descending**: `boolean=false` Is this column sorted in descending order?
101
- * **cellFormatter**: `Function(string value, string columnName, Object rowData)string` *(optional)* A formatter function which will return the HTML for the cell. By default the formatter is a plain HTML formatter.
102
- * **headerCellFormatter**: `Function(string value, string columnName)string` *(optional)* A formatter function which will return the HTML for the cell's header. By default the formatter is a plain HTML formatter.
103
- * **rowsBufferSize**: `number=10` The size of the rows buffer, for virtual table
104
- * **minColumnWidth**: `number=35` In pixels, the minimum width for a column
105
- * **resizeAreaWidth**: `number=8` The size of the area where you can drag to resize.
106
- * **onComparatorRequired**: `function(columnName: string, descending: boolean, defaultComparator: function(a,b):number):{function(a,b):number}` A callback that can pass a comparator function for each column and mode as required.
107
- * **resizerClassName**: `string='dgtable-resize'` Class name for the dragged resizing element (showing when resizing a column)
108
- * **tableClassName**: `string='dgtable'` Class name for the table
109
- * **allowCellPreview**: `boolean=true` When set, hovering on truncated cells will show a preview of the full content.
110
- * **allowHeaderCellPreview**: `boolean=true` Allow for toggling off **allowCellPreview** for headers specifically.
111
- * **cellPreviewAutoBackground**: `boolean=true` When set, the preview cell will receive its background automatically from the cell.
112
- * **cellPreviewClassName**: `string='dgtable-cell-preview'` Class name for the cell preview element
113
- * **className**: `string='dgtable-wrapper'` Element class name.
114
- * **el**: `Element?` Optional element to take over
115
- * **filter**: `Function(row: Object, args: Object): boolean` *(optional)* A filter function for using with the `filter` method
116
-
117
- #### Events triggered by DGTable:
118
-
119
- * `renderskeleton`: The table is re-drawing it's base elements, including headers. Will always be followed by a `render` event.
120
- * `render`: The table has finished rendering (after adding rows etc.).
121
- * `cellpreview`: We are about to show a cell preview - `{ el: Element, rowIndex: number|null, name: string, rowData: Object|null, cell: Element, cellEl: Element }`
122
- * At this stage you can prevent showing the preview, by calling `table.hideCellPreview`
123
- * `cellpreviewdestroy`: Cell preview element is about to be destroyed after hiding - `{ el: Element, name: string, filteredRowIndex: number|null, rowIndex: Object|null, cell: Element, cellEl: Element }`
124
- * You can use this event to release any resources that you may have used in `cellPreview` event.
125
- * `headerrowcreate`: The header row has just been created - `Element`
126
- * `headerrowdestroy`: Called just before removing the header row DOM element from the table - `Element`
127
- * `rowcreate`: A row has just been created - `{ filteredRowIndex: number, rowIndex: number, rowEl: Element, rowData: Object }`
128
- * `rowclick`: A row has just been created - `{ event: MouseEvent, rowIndex: number, rowIndex: number, rowEl: Element, rowData: Object }`
129
- * `rowdestroy`: Called just before removing a row DOM element from the table - `Element`
130
- * `addrows`: Data rows have been added to the table - `({ count: number, clear: boolean })`
131
- * `addcolumn`: A column was added - `string` (the column's name)
132
- * `removecolumn`: A column was removed - `string` (the column's name)
133
- * `movecolumn`: A column was moved - `({ name: string, src: number, dest: number })`
134
- * `showcolumn`: A column was shown - `string` (the column's name)
135
- * `hidecolumn`: A column was hidden - `string` (the column's name)
136
- * `columnwidth`: A column was resized - `({ name: string, width: number|string, oldWidth: number|string })`
137
- * `filter`: A filter was applied - `any` - the arguments passed to the filter method
138
- * `filterclear`: A filter was cleared
139
- * `sort`: The data was sorted - `{ sorts: { "column": "column's name", "descending": true|false }[], resort: true|undefined, comparator: Function }`
140
- * `headercontextmenu`: A context menu should be shown for a header cell - `({ columnName: string, pageX: number, pageY: number, bounds: { left: number, top: number, width: number, height: number } })`
141
-
142
- - Member functions:
143
- * `on(eventName, {Function?} callback)`: Adds an event listener
144
- * `once(eventName, {Function?} callback)`: Adds a one-shot event listener
145
- * `off(eventName, {Function?} callback)`: Removes an event listener
146
- * `render()`: Renders the view. Should be called after adding to the DOM, and when the viewport has changed and the table has no knowledge of it.
147
- * `clearAndRender({boolean} render = true)`: Forces a full render of the table
148
- * `setColumns({COLUMN_OPTIONS[]} columns, {boolean} render = true) {DGTable}`: Sets the table columns
149
- * `addColumn({COLUMN_OPTIONS} columnData, {string|number} before = -1, {boolean} render = true) {DGTable}`: Add a column to the table
150
- * **columnData**: Column properties. Same manner as in the **columns** options when initializing the DGTable
151
- * **before**: Column name or order to be inserted before.
152
- * *returns* Self, to allow for call chaining.
153
- * `removeColumn({string} column, {boolean} render = true) {DGTable}`: Remove a column from the table
154
- * **column**: Column name
155
- * *returns* Self, to allow for call chaining.
156
- * `setFilter({Function(row: Object, args: Object): boolean} filterFunc) {DGTable}`: Sets a new filtering function, set null for default.
157
- * **filterFunc**: The filtering function receives a row and an options object, and returns true for any row that passes the filter.
158
- * *returns* Self, to allow for call chaining.
159
- * `setCellFormatter({Function(value: *, columnName: string, row: Object):string|null} formatter) {DGTable}`: Sets a new cell formatter.
160
- * **formatter**: The cell formatter. Should return an HTML.
161
- * *returns* Self, to allow for call chaining.
162
- * `setHeaderCellFormatter({Function(label: string, columnName: string):string|null} formatter) {DGTable}`: Sets a new header cell formatter.
163
- * **formatter**: The cell formatter. Should return an HTML.
164
- * *returns* Self, to allow for call chaining.
165
- * `filter({Object} args) {DGTable}`: Filter the visible rows in the table
166
- * **args**: Options to pass to the filtering function
167
- * *returns* Self, to allow for call chaining.
168
- * `filter({{column: string, keyword: string, caseSensitive: boolean}} args) {DGTable}`: Syntax for default filtering function.
169
- * **args.column**: Name of the column to filter on
170
- * **args.keyword**: Tests the specified column if contains this keyword
171
- * **args.caseSensitive**: Use caseSensitive filtering
172
- * *returns* Self, to allow for call chaining.
173
- * `clearFilter() {DGTable}`: Clears the current filter
174
- * *returns* Self, to allow for call chaining.
175
- * `setColumnLabel({string} column, {string} label) {DGTable}`: Set a new label to a column
176
- * **column**: Name of the column
177
- * **label**: New label for the column
178
- * *returns* Self, to allow for call chaining.
179
- * `moveColumn({string|number} src, {string|number} dest, visibleOnly = true) {DGTable}`: Move a column to a new position
180
- * **src**: Name or position of the column to be moved
181
- * **dest**: Name of the column currently in the desired position, or the position itself
182
- * **visibleOnly**: Should consider only visible columns and visible-relative indexes
183
- * *returns* Self, to allow for call chaining.
184
- * `sort({string?} column, {boolean?} descending, {boolean=false} add) {DGTable}`: Sort the table. This does not render automatically, so you may need to call render() too.
185
- * **src**: Name of the column to sort on
186
- * **descending**: Sort in descending order (if not specified, defaults to false or reverses current descending mode if sorting by same column)
187
- * **add**: Should this sort be on top of the existing sort? (For multiple column sort)
188
- * *returns* Self, to allow for call chaining.
189
- * `resort() {DGTable}`: Re-sort the table using current sort specifiers. This does not render automatically, so you may need to call render() too.
190
- * *returns* Self, to allow for call chaining.
191
- * `setColumnVisible({string} column, {boolean} visible) {DGTable}`: Show or hide a column
192
- * **column**: Unique column name
193
- * **visible**: New visibility mode for the column
194
- * *returns* Self, to allow for call chaining.
195
- * `isColumnVisible({string} column, {boolean} visible) {boolean}`: Get the visibility mode of a column
196
- * *returns* True if visible
197
- * `setMinColumnWidth({number} minColumnWidth) {DGTable}`: Globally set the minimum column width
198
- * **minColumnWidth**: Minimum column width
199
- * *returns* Self, to allow for call chaining.
200
- * `getMinColumnWidth() {number}`: Get the current minimum column width
201
- * *returns* Minimum column width
202
- * `setSortableColumns({number} sortableColumns) {DGTable}`: Set the limit on concurrent columns sortedh
203
- * **sortableColumns**: Minimum column width
204
- * *returns* Self, to allow for call chaining.
205
- * `getSortableColumns() {number}`: Get the limit on concurrent columns sorted
206
- * *returns* How many sortable columns are allowed?
207
- * `getHeaderRowElement() {Element}`: Get the DOM element of the header row
208
- * *returns* a DOM element
209
- * `setMovableColumns({boolean} movableColumns) {DGTable}`: *Undocumented yet*
210
- * `getMovableColumns() {boolean}`: *Undocumented yet*
211
- * `setResizableColumns({boolean} resizableColumns) {DGTable}`: *Undocumented yet*
212
- * `getResizableColumns() {boolean}`: *Undocumented yet*
213
- * `setOnComparatorRequired({function(columnName: string, descending: boolean, defaultComparator: function(a,b):number):{function(a,b):number}}|null comparatorCallback) {DGTable}`: Sets a functions that supplies comparators dynamically
214
- * **comparatorCallback**: a function that returns the comparator for a specific column
215
- * `setCustomSortingProvider({{function(data: any[], sort: function(any[]):any[]):any[]}|null} customSortingProvider) {DGTable}`: sets custom sorting function for a data set
216
- * **customSortingProvider**: provides a custom sorting function (not the comparator, but a sort() alternative) for a data set
217
- * `setColumnWidth({string} column, {number|string} width) {DGTable}`: *Undocumented yet*
218
- * `getColumnWidth({string} column) {string|null}`: *Undocumented yet*
219
- * `getColumnConfig({string} column name) {SERIALIZED_COLUMN}`: *Undocumented yet*
220
- * `getColumnsConfig() {Object}`: *Undocumented yet*
221
- * `getSortedColumns() {Array.<SERIALIZED_COLUMN_SORT>}`: *Undocumented yet*
222
- * `getHtmlForRowCell(row: number, columnName: string) {string}`: Returns the HTML for specified cell in a row.
223
- * **row**: Index of row
224
- * **columnName**: Name of cell
225
- * *returns* HTML for cell. By default cell content is *not* HTML encoded, you should encode appropriately in your `cellFormatter`.
226
- * `getHtmlForRowDataCell(rowData: Object, columnName: string) {string|null}`: Returns the HTML string for a specific cell. Can be used externally for special cases (i.e. when setting a fresh HTML in the cell preview through the callback).
227
- * **rowData**: Actual row data
228
- * **columnName**: Name of column
229
- * *returns* string for the specified cell
230
- * `getDataForRow(rowIndex: number): Object`: Gets the row data for a specific row
231
- * *returns* row data at the specified index, out of all rows (not filtered)
232
- * `getRowCount(): number`: Gets the number of rows
233
- * *returns* the number of rows
234
- * `getIndexForRow(row: Object): number`: Finds the index of the specified row
235
- * *returns* the index of the specified row
236
- * `getFilteredRowCount(): number`: Gets the number of filtered rows
237
- * *returns* the number of rows in the filtered set (defaults to full row count if no filtering is active)
238
- * `getIndexForFilteredRow(row: Object): number`: Finds the index of the specified row within the filtered results
239
- * *returns* the index of the specified row
240
- * `getDataForFilteredRow(row: number): Object`: *Undocumented yet*
241
- * `getRowElement(rowIndex: number): Element`: Returns the element of the specified row (unfiltered index)
242
- * `getRowYPos(rowIndex: number): number?`: Returns the Y pos of the specified row (unfiltered index)
243
- * `tableWidthChanged() {DGTable}`: *Undocumented yet*
244
- * `tableHeightChanged() {DGTable}`: *Undocumented yet*
245
- * `addRows({Object[]} data, {number} at = -1, {boolean} resort = false, {boolean} render = true) {DGTable}`: Adds the specified rows at the specified position, and optionally resorts the data
246
- * `removeRow({number} rowIndex, {boolean} render = true) {DGTable}`: Removes one row at the specified position
247
- * `removeRows({number} rowIndex, {number} count, {boolean} render = true) {DGTable}`: Removes rows at the specified position
248
- * `refreshRow({number} rowIndex) {DGTable}`: Refreshes the row specified
249
- * *returns* Self
250
- * `refreshAllVirtualRows() {DGTable}`: Refreshes all virtual rows
251
- * *returns* Self
252
- * `setRows(data: Object[], resort: boolean=false) {DGTable}`: Rests the table rows to the provided array of rows.
253
- * **data**: New rows for the table
254
- * **resort**: Should re-sort the table?
255
- * *returns* Self, to allow for call chaining.
256
- * `getUrlForElementContent({string} id) {string?}`: *Undocumented yet*
257
- * `isWorkerSupported() {boolean}`: *Undocumented yet*
258
- * `createWebWorker({string} url) {Worker?}`: *Undocumented yet*
259
- * `unbindWebWorker({Worker} worker) {DGTable}`: *Undocumented yet*
260
- * `hideCellPreview() {DGTable}`: Hide any cell preview showing currently, or prevent showing a cell preview from within the `cellpreview` event.
261
- * `destroy()`: Destroy the table and free all of its memory.
1
+ # DGTable.js
262
2
 
263
- ## License
3
+ A high-performance virtual table component for vanilla JavaScript.
264
4
 
265
- All the code here is under MIT license. Which means you could do virtually anything with the code.
266
- I will appreciate it very much if you keep an attribution where appropriate.
5
+ [![npm version](https://badge.fury.io/js/@danielgindi%2Fdgtable.svg)](https://www.npmjs.com/package/@danielgindi/dgtable)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
267
7
 
268
- The MIT License (MIT)
269
-
270
- Copyright (c) 2013 Daniel Cohen Gindi (danielgindi@gmail.com)
8
+ ## Features
9
+
10
+ - **High Performance** - Virtual scrolling renders only visible rows, handling hundreds of thousands of rows smoothly
11
+ - **Column Management** - Sort, resize, reorder, and hide/show columns
12
+ - **Multi-column Sorting** - Sort by multiple columns simultaneously
13
+ - **Flexible Column Widths** - Mix absolute, relative, and auto-calculated widths
14
+ - **Cell Preview** - Hover tooltips for truncated cell content
15
+ - **Sticky Columns** - Pin columns to the start or end of the table
16
+ - **RTL Support** - Native right-to-left language support
17
+ - **Variable Row Height** - Support for rows with different heights
18
+ - **Filtering** - Built-in filtering with custom filter function support
19
+ - **Web Worker Support** - Load data asynchronously via Web Workers
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install @danielgindi/dgtable
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ```javascript
30
+ import DGTable from '@danielgindi/dgtable';
31
+
32
+ const table = new DGTable({
33
+ columns: [
34
+ { name: 'id', label: 'ID', width: 80 },
35
+ { name: 'name', label: 'Name', width: '30%' },
36
+ { name: 'email', label: 'Email' },
37
+ ],
38
+ height: 400,
39
+ virtualTable: true,
40
+ });
41
+
42
+ document.getElementById('container').appendChild(table.el);
43
+
44
+ table.setRows([
45
+ { id: 1, name: 'John Doe', email: 'john@example.com' },
46
+ { id: 2, name: 'Jane Smith', email: 'jane@example.com' },
47
+ ]);
48
+
49
+ table.render();
50
+ ```
51
+
52
+ ## Migration from jquery.dgtable
53
+
54
+ If you're migrating from the older jQuery version:
55
+
56
+ - No `$el` property - use `table.el` instead
57
+ - No auto-clear of jQuery data
58
+ - Use `emit()` instead of `trigger()` for events
59
+ - Event arguments are now always a single value/object
60
+ - DOM element properties: `'columnName'` on cells, `'index'/'vIndex'` on rows
61
+
62
+ ---
63
+
64
+ ## API Reference
65
+
66
+ ### Constructor Options
67
+
68
+ ```typescript
69
+ new DGTable(options?: DGTableOptions)
70
+ ```
71
+
72
+ #### Table Options
73
+
74
+ | Option | Type | Default | Description |
75
+ |--------|------|---------|-------------|
76
+ | `el` | `Element` | - | Optional existing element to use as container |
77
+ | `className` | `string` | `'dgtable-wrapper'` | CSS class for the wrapper element |
78
+ | `height` | `number` | - | Table height in pixels |
79
+ | `width` | `DGTable.Width` | `NONE` | Width handling mode: `NONE`, `AUTO`, or `SCROLL` |
80
+ | `virtualTable` | `boolean` | `true` | Enable virtual scrolling (recommended for large datasets) |
81
+ | `estimatedRowHeight` | `number` | `40` | Estimated row height for virtual scrolling calculations |
82
+ | `rowsBufferSize` | `number` | `3` | Number of rows to render outside visible area |
83
+
84
+ #### Column Options
85
+
86
+ | Option | Type | Default | Description |
87
+ |--------|------|---------|-------------|
88
+ | `columns` | `ColumnOptions[]` | `[]` | Array of column definitions |
89
+ | `minColumnWidth` | `number` | `35` | Minimum column width in pixels |
90
+ | `resizableColumns` | `boolean` | `true` | Allow column resizing |
91
+ | `movableColumns` | `boolean` | `true` | Allow column reordering |
92
+ | `sortableColumns` | `number` | `1` | Maximum number of columns to sort by |
93
+ | `allowCancelSort` | `boolean` | `true` | Allow cycling through asc → desc → none |
94
+ | `adjustColumnWidthForSortArrow` | `boolean` | `true` | Auto-expand columns for sort indicator |
95
+ | `relativeWidthGrowsToFillWidth` | `boolean` | `true` | Expand relative columns to fill space |
96
+ | `relativeWidthShrinksToFillWidth` | `boolean` | `false` | Shrink relative columns to fit |
97
+ | `convertColumnWidthsToRelative` | `boolean` | `false` | Convert auto widths to relative |
98
+ | `autoFillTableWidth` | `boolean` | `false` | Stretch columns to fill table width |
99
+ | `resizeAreaWidth` | `number` | `8` | Width of resize drag area in pixels |
100
+
101
+ #### Column Definition
102
+
103
+ ```typescript
104
+ {
105
+ name: string; // Required: unique identifier
106
+ label?: string; // Header text (defaults to name)
107
+ width?: number | string; // number (px), '30%', or 0.3 (relative)
108
+ dataPath?: string | string[]; // Path to data (defaults to [name])
109
+ comparePath?: string | string[]; // Path for sorting (defaults to dataPath)
110
+ resizable?: boolean; // Allow resizing this column (default: true)
111
+ sortable?: boolean; // Allow sorting by this column (default: true)
112
+ movable?: boolean; // Allow moving this column (default: true)
113
+ visible?: boolean; // Column visibility (default: true)
114
+ sticky?: 'start' | 'end' | false | null; // Pin to start or end
115
+ cellClasses?: string; // Additional CSS classes for cells
116
+ ignoreMin?: boolean; // Ignore minColumnWidth for this column
117
+ order?: number; // Column order
118
+ }
119
+ ```
120
+
121
+ #### Formatting & Filtering
122
+
123
+ | Option | Type | Description |
124
+ |--------|------|-------------|
125
+ | `cellFormatter` | `(value: unknown, columnName: string, rowData: RowData) => string` | Custom cell HTML renderer |
126
+ | `headerCellFormatter` | `(label: string, columnName: string) => string` | Custom header cell renderer |
127
+ | `filter` | `(row: RowData, args: unknown) => boolean` | Custom filter function |
128
+ | `sortColumn` | `string \| string[] \| ColumnSortOptions \| ColumnSortOptions[]` | Initial sort configuration |
129
+ | `onComparatorRequired` | `(columnName: string, descending: boolean, defaultComparator: ComparatorFunction) => ComparatorFunction` | Custom comparator provider |
130
+ | `customSortingProvider` | `(data: RowData[], sort: (data: RowData[]) => RowData[]) => RowData[]` | Custom sorting implementation |
131
+
132
+ #### Styling
133
+
134
+ | Option | Type | Default | Description |
135
+ |--------|------|---------|-------------|
136
+ | `tableClassName` | `string` | `'dgtable'` | Base CSS class for the table |
137
+ | `cellClasses` | `string` | `''` | Additional classes for all cells |
138
+ | `resizerClassName` | `string` | `'dgtable-resize'` | Class for resize handle |
139
+ | `cellPreviewClassName` | `string` | `'dgtable-cell-preview'` | Class for cell preview |
140
+ | `allowCellPreview` | `boolean` | `true` | Show preview on hover |
141
+ | `allowHeaderCellPreview` | `boolean` | `true` | Show preview for headers |
142
+ | `cellPreviewAutoBackground` | `boolean` | `true` | Match preview background to cell |
143
+ | `resizeAreaWidth` | `number` | `8` | Width of resize drag area |
144
+
145
+ ---
146
+
147
+ ### Methods
148
+
149
+ #### Rendering
150
+
151
+ ```javascript
152
+ table.render() // Render the table
153
+ table.clearAndRender(render=true) // Force full re-render
154
+ ```
155
+
156
+ #### Column Management
157
+
158
+ ```javascript
159
+ table.setColumns(columns, render=true) // Replace all columns
160
+ table.addColumn(columnData, before=-1, render) // Add a column
161
+ table.removeColumn(columnName, render=true) // Remove a column
162
+ table.setColumnLabel(column, label) // Update column label
163
+ table.moveColumn(src, dest, visibleOnly=true) // Reorder columns
164
+ table.setColumnVisible(column, visible) // Show/hide column
165
+ table.isColumnVisible(column) // Check visibility
166
+ table.setColumnWidth(column, width) // Set column width
167
+ table.getColumnWidth(column) // Get column width
168
+ table.getColumnConfig(column) // Get column config
169
+ table.getColumnsConfig() // Get all columns config
170
+ ```
171
+
172
+ #### Sorting
173
+
174
+ ```javascript
175
+ table.sort(column, descending, add=false) // Sort by column
176
+ table.resort() // Re-apply current sort
177
+ table.getSortedColumns() // Get current sort state
178
+ table.setSortableColumns(count) // Set max sortable columns
179
+ table.getSortableColumns() // Get max sortable columns
180
+ ```
181
+
182
+ #### Data Management
183
+
184
+ ```javascript
185
+ table.setRows(data, resort=false) // Replace all rows
186
+ table.addRows(data, at=-1, resort=false, render=true) // Add rows
187
+ table.removeRow(rowIndex, render=true) // Remove one row
188
+ table.removeRows(rowIndex, count, render=true) // Remove multiple rows
189
+ table.refreshRow(rowIndex, render=true) // Refresh a row
190
+ table.refreshAllVirtualRows() // Refresh all visible rows
191
+
192
+ table.getRowCount() // Total row count
193
+ table.getFilteredRowCount() // Filtered row count
194
+ table.getDataForRow(rowIndex) // Get row data by index
195
+ table.getDataForFilteredRow(filteredIndex) // Get filtered row data
196
+ table.getIndexForRow(rowData) // Find row index
197
+ table.getIndexForFilteredRow(rowData) // Find filtered row index
198
+ table.getRowElement(rowIndex) // Get row DOM element
199
+ table.getRowYPos(rowIndex) // Get row Y position
200
+ ```
201
+
202
+ #### Filtering
203
+
204
+ ```javascript
205
+ table.setFilter(filterFn) // Set custom filter function
206
+ table.filter(args) // Apply filter with arguments
207
+ table.clearFilter() // Clear active filter
208
+
209
+ // Built-in filter example:
210
+ table.filter({ column: 'name', keyword: 'john', caseSensitive: false });
211
+ ```
212
+
213
+ #### Formatters
214
+
215
+ ```javascript
216
+ table.setCellFormatter(fn) // Set cell formatter
217
+ table.setHeaderCellFormatter(fn) // Set header formatter
218
+ table.getHtmlForRowCell(rowIndex, columnName) // Get cell HTML
219
+ table.getHtmlForRowDataCell(rowData, columnName) // Get cell HTML from data
220
+ ```
221
+
222
+ #### Layout
223
+
224
+ ```javascript
225
+ table.tableWidthChanged(forceUpdate=false, renderColumns=true) // Notify width change
226
+ table.tableHeightChanged() // Notify height change
227
+ table.setMinColumnWidth(width) // Set global min width
228
+ table.getMinColumnWidth() // Get global min width
229
+ ```
230
+
231
+ #### Cell Preview
232
+
233
+ ```javascript
234
+ table.hideCellPreview() // Hide or prevent cell preview
235
+ table.abortCellPreview() // Alias for hideCellPreview()
236
+ ```
237
+
238
+ #### Column Features
239
+
240
+ ```javascript
241
+ table.setMovableColumns(movable) // Enable/disable column moving
242
+ table.getMovableColumns() // Get movable state
243
+ table.setResizableColumns(resizable) // Enable/disable column resizing
244
+ table.getResizableColumns() // Get resizable state
245
+ ```
246
+
247
+ #### Sorting Customization
248
+
249
+ ```javascript
250
+ table.setOnComparatorRequired(callback) // Set comparator provider
251
+ table.setCustomSortingProvider(provider) // Set custom sort provider
252
+ ```
253
+
254
+ #### Web Workers
255
+
256
+ ```javascript
257
+ table.isWorkerSupported() // Check Web Worker support
258
+ table.createWebWorker(url, start=true, resort=false) // Create worker
259
+ table.unbindWebWorker(worker) // Unbind worker
260
+ table.getUrlForElementContent(elementId) // Create blob URL from element
261
+ ```
262
+
263
+ #### DOM Access
264
+
265
+ ```javascript
266
+ table.el // The table wrapper element
267
+ table.getHeaderRowElement() // Get header row element
268
+ ```
269
+
270
+ #### Events
271
+
272
+ ```typescript
273
+ // TypeScript users get full autocompletion and type checking!
274
+ table.on('rowclick', (data) => {
275
+ // data is typed as RowClickEvent
276
+ console.log(data.rowIndex, data.rowData);
277
+ });
278
+
279
+ // Custom events are also supported (for using table as event bus)
280
+ table.on('my-custom-event', (data) => {
281
+ // data is typed as `unknown` by default
282
+ console.log(data);
283
+ });
284
+
285
+ // You can specify the type for custom events
286
+ table.on<{ customField: string }>('my-typed-event', (data) => {
287
+ console.log(data.customField); // TypeScript knows the type
288
+ });
289
+
290
+ table.on(event, handler) // Add event listener (typed for built-in events)
291
+ table.once(event, handler) // Add one-time listener (typed)
292
+ table.off(event, handler) // Remove listener
293
+ table.emit(event, data) // Emit event (typed for built-in events)
294
+ ```
295
+
296
+ #### Lifecycle
297
+
298
+ ```javascript
299
+ table.destroy() // Destroy table and free memory
300
+ table.close() // Alias for destroy()
301
+ table.remove() // Alias for destroy()
302
+ ```
303
+
304
+ ---
305
+
306
+ ### Events
307
+
308
+ Subscribe to events using `table.on(eventName, handler)`.
309
+
310
+ Built-in events have fully typed handlers with autocompletion. You can also use the table's event system as an event bus for your own custom events.
311
+
312
+ #### Rendering Events
313
+
314
+ | Event | Data Type | Description |
315
+ |-------|-----------|-------------|
316
+ | `render` | `undefined` | Table finished rendering |
317
+ | `renderskeleton` | `undefined` | Table structure rebuilt |
318
+
319
+ #### Row Events
320
+
321
+ | Event | Data Type | Description |
322
+ |-------|-----------|-------------|
323
+ | `rowcreate` | `RowCreateEvent` | Row element created |
324
+ | `rowclick` | `RowClickEvent` | Row clicked |
325
+ | `rowdestroy` | `HTMLElement` | Row element about to be removed |
326
+
327
+ ```typescript
328
+ interface RowCreateEvent {
329
+ filteredRowIndex: number; // Index in filtered data
330
+ rowIndex: number; // Index in original data
331
+ rowEl: HTMLElement; // The row DOM element
332
+ rowData: RowData; // The row data object
333
+ }
334
+
335
+ interface RowClickEvent {
336
+ event: MouseEvent; // The original mouse event
337
+ filteredRowIndex: number; // Index in filtered data
338
+ rowIndex: number; // Index in original data
339
+ rowEl: HTMLElement; // The row DOM element
340
+ rowData: RowData; // The row data object
341
+ }
342
+ ```
343
+
344
+ #### Cell Preview Events
345
+
346
+ | Event | Data Type | Description |
347
+ |-------|-----------|-------------|
348
+ | `cellpreview` | `CellPreviewEvent` | Cell preview showing |
349
+ | `cellpreviewdestroy` | `CellPreviewDestroyEvent` | Cell preview hiding |
350
+
351
+ ```typescript
352
+ interface CellPreviewEvent {
353
+ el: Element | null; // Preview element's first child
354
+ name: string; // Column name
355
+ rowIndex: number | null; // Row index (null for header)
356
+ rowData: RowData | null; // Row data (null for header)
357
+ cell: HTMLElement; // Original cell element
358
+ cellEl: HTMLElement; // Cell's inner element
359
+ }
360
+
361
+ interface CellPreviewDestroyEvent {
362
+ el: ChildNode | null; // Preview element's first child
363
+ name: string; // Column name
364
+ rowIndex: number | null; // Row index (null for header)
365
+ rowData: RowData | null; // Row data (null for header)
366
+ cell: HTMLElement | null; // Original cell element
367
+ cellEl: ChildNode | null; // Cell's inner element
368
+ }
369
+ ```
370
+
371
+ #### Header Events
372
+
373
+ | Event | Data Type | Description |
374
+ |-------|-----------|-------------|
375
+ | `headerrowcreate` | `HTMLElement` | Header row created |
376
+ | `headercontextmenu` | `HeaderContextMenuEvent` | Header right-click |
377
+
378
+ ```typescript
379
+ interface HeaderContextMenuEvent {
380
+ columnName: string; // Column that was right-clicked
381
+ pageX: number; // Mouse X position
382
+ pageY: number; // Mouse Y position
383
+ bounds: { // Cell bounds
384
+ left: number;
385
+ top: number;
386
+ width: number;
387
+ height: number;
388
+ };
389
+ }
390
+ ```
391
+
392
+ #### Column Events
393
+
394
+ | Event | Data Type | Description |
395
+ |-------|-----------|-------------|
396
+ | `addcolumn` | `string` | Column name added |
397
+ | `removecolumn` | `string` | Column name removed |
398
+ | `movecolumn` | `MoveColumnEvent` | Column moved |
399
+ | `showcolumn` | `string` | Column name shown |
400
+ | `hidecolumn` | `string` | Column name hidden |
401
+ | `columnwidth` | `ColumnWidthEvent` | Column resized |
402
+
403
+ ```typescript
404
+ interface MoveColumnEvent {
405
+ name: string; // Column name
406
+ src: number; // Original order position
407
+ dest: number; // New order position
408
+ }
409
+
410
+ interface ColumnWidthEvent {
411
+ name: string; // Column name
412
+ width: number; // New width
413
+ oldWidth: number; // Previous width
414
+ }
415
+ ```
416
+
417
+ #### Data Events
418
+
419
+ | Event | Data Type | Description |
420
+ |-------|-----------|-------------|
421
+ | `addrows` | `AddRowsEvent` | Rows added |
422
+ | `sort` | `SortEvent` | Data sorted |
423
+ | `filter` | `unknown` | Filter applied (filter args) |
424
+ | `filterclear` | `{}` | Filter cleared |
425
+
426
+ ```typescript
427
+ interface AddRowsEvent {
428
+ count: number; // Number of rows added
429
+ clear: boolean; // Whether table was cleared first
430
+ }
431
+
432
+ interface SortEvent {
433
+ sorts: SerializedColumnSort[]; // Current sort state
434
+ resort?: boolean; // True if re-sorting existing data
435
+ }
436
+ ```
437
+
438
+ #### Example Usage
439
+
440
+ ```typescript
441
+ // Row click handler
442
+ table.on('rowclick', (data) => {
443
+ console.log('Clicked row:', data.rowIndex, data.rowData);
444
+ });
445
+
446
+ // Column resize handler
447
+ table.on('columnwidth', (data) => {
448
+ console.log(`Column ${data.name} resized from ${data.oldWidth} to ${data.width}`);
449
+ });
450
+
451
+ // Sort handler
452
+ table.on('sort', (data) => {
453
+ console.log('Sorted by:', data.sorts);
454
+ });
455
+
456
+ // Cell preview handler
457
+ table.on('cellpreview', (data) => {
458
+ // Customize preview content
459
+ if (data.el) {
460
+ data.el.innerHTML += '<span class="custom-badge">Preview</span>';
461
+ }
462
+ });
463
+ ```
464
+
465
+ ---
466
+
467
+ ## TypeScript Types
468
+
469
+ The library exports the following types for TypeScript users:
470
+
471
+ ```typescript
472
+ import type {
473
+ // Configuration types
474
+ DGTableOptions, // Constructor options
475
+ ColumnOptions, // Column definition
476
+ ColumnSortOptions, // Sort specification { column, descending? }
477
+ SerializedColumn, // Saved column config
478
+ SerializedColumnSort, // Saved sort config
479
+ RowData, // Row data (Record<string, unknown>)
271
480
 
272
- Permission is hereby granted, free of charge, to any person obtaining a copy
273
- of this software and associated documentation files (the "Software"), to deal
274
- in the Software without restriction, including without limitation the rights
275
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
276
- copies of the Software, and to permit persons to whom the Software is
277
- furnished to do so, subject to the following conditions:
481
+ // Function types
482
+ CellFormatter, // Cell formatter function
483
+ HeaderCellFormatter, // Header cell formatter function
484
+ FilterFunction, // Filter function
485
+ ComparatorFunction, // Row comparator function
486
+ OnComparatorRequired, // Comparator provider callback
487
+ CustomSortingProvider, // Custom sorting function
278
488
 
279
- The above copyright notice and this permission notice shall be included in all
280
- copies or substantial portions of the Software.
489
+ // Event types
490
+ RowCreateEvent, // 'rowcreate' event data
491
+ RowClickEvent, // 'rowclick' event data
492
+ CellPreviewEvent, // 'cellpreview' event data
493
+ CellPreviewDestroyEvent, // 'cellpreviewdestroy' event data
494
+ HeaderContextMenuEvent, // 'headercontextmenu' event data
495
+ MoveColumnEvent, // 'movecolumn' event data
496
+ ColumnWidthEvent, // 'columnwidth' event data
497
+ AddRowsEvent, // 'addrows' event data
498
+ SortEvent, // 'sort' event data
281
499
 
282
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
283
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
284
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
285
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
286
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
287
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
288
- SOFTWARE.
500
+ // Event map (for advanced typing)
501
+ DGTableEventMap, // Maps event names to their data types
502
+ } from '@danielgindi/dgtable';
503
+ ```
504
+
505
+ The `DGTableEventMap` interface provides full autocompletion when using `.on()`, `.once()`, `.off()`, and `.emit()`:
506
+
507
+ ```typescript
508
+ // Event names autocomplete, and handler receives correctly typed data
509
+ table.on('rowclick', (data) => {
510
+ // TypeScript knows: data.event, data.rowIndex, data.rowData, etc.
511
+ console.log(`Clicked row ${data.rowIndex}`);
512
+ });
513
+
514
+ table.on('columnwidth', (data) => {
515
+ // TypeScript knows: data.name, data.width, data.oldWidth
516
+ console.log(`Column ${data.name} resized to ${data.width}px`);
517
+ });
518
+ ```
519
+
520
+ ---
521
+
522
+ ## Development
523
+
524
+ ```bash
525
+ # Install dependencies
526
+ npm install
527
+
528
+ # Build
529
+ npm run build
530
+
531
+ # Lint
532
+ npm run lint
533
+ ```
534
+
535
+ ## Author
536
+
537
+ **Daniel Cohen Gindi** - danielgindi@gmail.com
538
+
539
+ ## Contributing
540
+
541
+ Contributions are welcome! Please feel free to:
542
+
543
+ - Report bugs and issues
544
+ - Submit pull requests
545
+ - Improve documentation
546
+ - Share your use cases
547
+
548
+ ## License
549
+
550
+ MIT License - see [LICENSE](LICENSE) for details.
551
+
552
+ Copyright (c) 2013-present Daniel Cohen Gindi
553
+