@coreui/data-grid 0.1.0-rc.0 → 0.3.0-rc.0
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/README.md +9 -6
- package/dist/css/data-grid.css +156 -38
- package/dist/css/data-grid.css.map +1 -1
- package/dist/css/data-grid.min.css +2 -2
- package/dist/css/data-grid.min.css.map +1 -1
- package/dist/css/data-grid.standalone.css +1066 -0
- package/dist/css/data-grid.standalone.css.map +1 -0
- package/dist/css/data-grid.standalone.min.css +5 -0
- package/dist/css/data-grid.standalone.min.css.map +1 -0
- package/dist/js/clipboard.cjs +56 -0
- package/dist/js/clipboard.cjs.map +1 -0
- package/dist/js/clipboard.mjs +54 -0
- package/dist/js/clipboard.mjs.map +1 -0
- package/dist/js/csv.cjs +36 -59
- package/dist/js/csv.cjs.map +1 -1
- package/dist/js/csv.mjs +35 -55
- package/dist/js/csv.mjs.map +1 -1
- package/dist/js/data-grid.esm.js +14108 -9331
- package/dist/js/data-grid.esm.js.map +1 -1
- package/dist/js/data-grid.esm.min.js +6 -6
- package/dist/js/data-grid.esm.min.js.map +1 -1
- package/dist/js/data-grid.js +14408 -9634
- package/dist/js/data-grid.js.map +1 -1
- package/dist/js/data-grid.lite.esm.js +10507 -0
- package/dist/js/data-grid.lite.esm.js.map +1 -0
- package/dist/js/data-grid.lite.esm.min.js +8 -0
- package/dist/js/data-grid.lite.esm.min.js.map +1 -0
- package/dist/js/data-grid.lite.js +10520 -0
- package/dist/js/data-grid.lite.js.map +1 -0
- package/dist/js/data-grid.lite.min.js +8 -0
- package/dist/js/data-grid.lite.min.js.map +1 -0
- package/dist/js/data-grid.lite.mjs +10507 -0
- package/dist/js/data-grid.lite.mjs.map +1 -0
- package/dist/js/data-grid.min.js +6 -6
- package/dist/js/data-grid.min.js.map +1 -1
- package/dist/js/data-grid.mjs +14108 -9331
- package/dist/js/data-grid.mjs.map +1 -1
- package/dist/js/direction.cjs +26 -0
- package/dist/js/direction.cjs.map +1 -0
- package/dist/js/direction.mjs +24 -0
- package/dist/js/direction.mjs.map +1 -0
- package/dist/js/drag.cjs +467 -0
- package/dist/js/drag.cjs.map +1 -0
- package/dist/js/drag.mjs +464 -0
- package/dist/js/drag.mjs.map +1 -0
- package/dist/js/export-table-BdabEbJG.mjs +26 -0
- package/dist/js/export-table-BdabEbJG.mjs.map +1 -0
- package/dist/js/export-table-D762wrZ1.cjs +55 -0
- package/dist/js/export-table-D762wrZ1.cjs.map +1 -0
- package/dist/js/filters.cjs +89 -132
- package/dist/js/filters.cjs.map +1 -1
- package/dist/js/filters.mjs +88 -128
- package/dist/js/filters.mjs.map +1 -1
- package/dist/js/labels.cjs +65 -70
- package/dist/js/labels.cjs.map +1 -1
- package/dist/js/labels.mjs +64 -66
- package/dist/js/labels.mjs.map +1 -1
- package/dist/js/print.cjs +66 -0
- package/dist/js/print.cjs.map +1 -0
- package/dist/js/print.mjs +64 -0
- package/dist/js/print.mjs.map +1 -0
- package/dist/js/validate.cjs +43 -0
- package/dist/js/validate.cjs.map +1 -0
- package/dist/js/validate.mjs +42 -0
- package/dist/js/validate.mjs.map +1 -0
- package/dist/js/xlsx.cjs +240 -0
- package/dist/js/xlsx.cjs.map +1 -0
- package/dist/js/xlsx.mjs +238 -0
- package/dist/js/xlsx.mjs.map +1 -0
- package/dist/types/base-component.d.ts +28 -18
- package/dist/types/data-grid.d.ts +26 -13
- package/dist/types/dom/data.d.ts +15 -0
- package/dist/types/dom/event-handler.d.ts +21 -10
- package/dist/types/dom/manipulator.d.ts +15 -8
- package/dist/types/engine/active-cell.d.ts +1 -0
- package/dist/types/engine/data-source.d.ts +1 -1
- package/dist/types/engine/features-lite.d.ts +25 -0
- package/dist/types/engine/features.d.ts +35 -0
- package/dist/types/engine/table.d.ts +3 -3
- package/dist/types/engine/validate.d.mts +1 -0
- package/dist/types/engine/validate.d.ts +20 -0
- package/dist/types/engine/virtualizer.d.ts +2 -0
- package/dist/types/icons.d.ts +6 -4
- package/dist/types/index-lite.d.mts +1 -0
- package/dist/types/index-lite.d.ts +19 -0
- package/dist/types/index.d.ts +11 -2
- package/dist/types/types.d.ts +53 -31
- package/dist/types/ui/body.d.ts +6 -3
- package/dist/types/ui/header.d.ts +3 -2
- package/dist/types/ui/loading.d.ts +1 -1
- package/dist/types/ui/pinning.d.ts +1 -1
- package/dist/types/ui/toolbar.d.ts +10 -2
- package/dist/types/util/clipboard.d.mts +1 -0
- package/dist/types/util/clipboard.d.ts +29 -0
- package/dist/types/util/config.d.ts +27 -10
- package/dist/types/util/csv.d.ts +5 -5
- package/dist/types/util/direction.d.mts +1 -0
- package/dist/types/util/direction.d.ts +17 -0
- package/dist/types/util/drag.d.mts +1 -0
- package/dist/types/util/drag.d.ts +48 -0
- package/dist/types/util/export-table.d.ts +47 -0
- package/dist/types/util/index.d.ts +66 -10
- package/dist/types/util/print.d.mts +1 -0
- package/dist/types/util/print.d.ts +32 -0
- package/dist/types/util/sanitizer.d.ts +15 -11
- package/dist/types/util/xlsx.d.mts +1 -0
- package/dist/types/util/xlsx.d.ts +17 -0
- package/dist/types/util/zip.d.ts +11 -0
- package/package.json +101 -10
- package/scss/_base.scss +13 -0
- package/scss/_config.scss +14 -0
- package/scss/_functions.scss +1 -0
- package/scss/_mixins.scss +1 -0
- package/scss/base/_buttons.scss +113 -0
- package/scss/base/_forms.scss +157 -0
- package/scss/base/_helpers.scss +24 -0
- package/scss/base/_pagination.scss +100 -0
- package/scss/base/_reboot.scss +93 -0
- package/scss/base/_root.scss +85 -0
- package/scss/base/_spinner.scss +45 -0
- package/scss/base/_table.scss +78 -0
- package/scss/components/_data-grid.scss +807 -0
- package/scss/data-grid.scss +7 -555
- package/scss/data-grid.standalone.scss +16 -0
- package/scss/functions/_defaults.scss +25 -0
- package/scss/mixins/_tokens.scss +12 -0
- package/src/{base-component.js → base-component.ts} +21 -17
- package/src/data-grid.ts +523 -201
- package/src/dom/{data.js → data.ts} +13 -10
- package/src/dom/event-handler.ts +380 -0
- package/src/dom/{manipulator.js → manipulator.ts} +11 -11
- package/src/engine/active-cell.ts +10 -3
- package/src/engine/data-source.ts +7 -3
- package/src/engine/features-lite.ts +47 -0
- package/src/engine/features.ts +68 -0
- package/src/engine/table.ts +86 -45
- package/src/engine/validate.ts +64 -0
- package/src/engine/virtualizer.ts +17 -1
- package/src/icons.ts +11 -5
- package/src/index-lite.ts +85 -0
- package/src/index.ts +30 -2
- package/src/labels.ts +6 -4
- package/src/types.ts +87 -32
- package/src/ui/body.ts +73 -17
- package/src/ui/header.ts +51 -26
- package/src/ui/loading.ts +2 -2
- package/src/ui/pinning.ts +16 -16
- package/src/ui/toolbar.ts +27 -3
- package/src/util/clipboard.ts +112 -0
- package/src/util/{config.js → config.ts} +25 -11
- package/src/util/csv.ts +11 -30
- package/src/util/direction.ts +37 -0
- package/src/util/drag.ts +832 -0
- package/src/util/export-table.ts +86 -0
- package/src/util/{index.js → index.ts} +55 -35
- package/src/util/print.ts +125 -0
- package/src/util/{sanitizer.js → sanitizer.ts} +17 -13
- package/src/util/xlsx.ts +183 -0
- package/src/util/zip.ts +170 -0
- package/src/base-component.d.ts +0 -19
- package/src/dom/event-handler.d.ts +0 -11
- package/src/dom/event-handler.js +0 -331
- package/src/dom/manipulator.d.ts +0 -9
- package/src/util/config.d.ts +0 -11
- package/src/util/index.d.ts +0 -10
- package/src/util/sanitizer.d.ts +0 -11
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* --------------------------------------------------------------------------
|
|
3
|
+
* CoreUI PRO data-grid util/export-table.ts
|
|
4
|
+
* License (https://coreui.io/pro/license/)
|
|
5
|
+
* --------------------------------------------------------------------------
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { DataGridItem } from '../types'
|
|
9
|
+
|
|
10
|
+
// Typed structurally, not as one edition's table: TFeatures is invariant in v9,
|
|
11
|
+
// so the vanilla grid and each framework binding (whose adapter registers its
|
|
12
|
+
// own reactivity feature) have mutually incompatible Table types even though
|
|
13
|
+
// they expose the same row/column surface an export needs. Everything beyond
|
|
14
|
+
// the core row model is optional - a reduced feature set exports whatever
|
|
15
|
+
// layout/scope its features can express and falls back to core for the rest.
|
|
16
|
+
|
|
17
|
+
export interface ExportColumnMeta {
|
|
18
|
+
label?: string
|
|
19
|
+
formatter?: (value: unknown, item: DataGridItem) => string
|
|
20
|
+
width?: number
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ExportColumn {
|
|
24
|
+
id: string
|
|
25
|
+
columnDef: { meta?: unknown }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ExportRow {
|
|
29
|
+
original: DataGridItem
|
|
30
|
+
getValue: (columnId: string) => unknown
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface ExportTable {
|
|
34
|
+
getAllLeafColumns: () => ExportColumn[]
|
|
35
|
+
getCenterVisibleLeafColumns?: () => ExportColumn[]
|
|
36
|
+
getCoreRowModel: () => { rows: ExportRow[] }
|
|
37
|
+
getEndVisibleLeafColumns?: () => ExportColumn[]
|
|
38
|
+
getFilteredRowModel?: () => { rows: ExportRow[] }
|
|
39
|
+
getSelectedRowModel?: () => { rows: ExportRow[] }
|
|
40
|
+
getSortedRowModel?: () => { rows: ExportRow[] }
|
|
41
|
+
getStartVisibleLeafColumns?: () => ExportColumn[]
|
|
42
|
+
getVisibleLeafColumns?: () => ExportColumn[]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type ExportScope = 'filtered' | 'all' | 'selected'
|
|
46
|
+
|
|
47
|
+
export const rowsFor = (table: ExportTable, scope: ExportScope | undefined): ExportRow[] => {
|
|
48
|
+
if (scope === 'all') {
|
|
49
|
+
return table.getCoreRowModel().rows
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (scope === 'selected') {
|
|
53
|
+
return table.getSelectedRowModel?.().rows ?? []
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return (table.getSortedRowModel ?? table.getFilteredRowModel ?? table.getCoreRowModel)().rows
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Exports follow the rendered layout: pinning, column order and visibility -
|
|
60
|
+
// as far as the registered features track them.
|
|
61
|
+
export const columnsFor = (table: ExportTable): ExportColumn[] => {
|
|
62
|
+
if (table.getCenterVisibleLeafColumns) {
|
|
63
|
+
return [
|
|
64
|
+
...(table.getStartVisibleLeafColumns?.() ?? []),
|
|
65
|
+
...table.getCenterVisibleLeafColumns(),
|
|
66
|
+
...(table.getEndVisibleLeafColumns?.() ?? [])
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return table.getVisibleLeafColumns?.() ?? table.getAllLeafColumns()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export const headerFor = (column: ExportColumn): string =>
|
|
74
|
+
String((column.columnDef.meta as ExportColumnMeta)?.label ?? column.id)
|
|
75
|
+
|
|
76
|
+
// A column formatter is author intent and matches what the grid renders, so
|
|
77
|
+
// exports honor it - which also means a formatted number leaves as text.
|
|
78
|
+
export const formatterFor = (column: ExportColumn): ExportColumnMeta['formatter'] =>
|
|
79
|
+
(column.columnDef.meta as ExportColumnMeta)?.formatter
|
|
80
|
+
|
|
81
|
+
// The author's declared column width in px. Deliberately NOT column.getSize():
|
|
82
|
+
// that returns table-core's 150 px default whenever the grid does not track
|
|
83
|
+
// sizing, which would force an arbitrary width on every exported column. A
|
|
84
|
+
// consequence is that an interactive resize is not carried into the export.
|
|
85
|
+
export const widthFor = (column: ExportColumn): number | undefined =>
|
|
86
|
+
(column.columnDef.meta as ExportColumnMeta)?.width
|
|
@@ -1,14 +1,30 @@
|
|
|
1
|
-
// Vendored from https://github.com/coreui/coreui-pro/blob/
|
|
1
|
+
// Vendored from https://github.com/coreui/coreui-pro/blob/e9355580e/js/src/util/index.ts — sync manually
|
|
2
2
|
/**
|
|
3
3
|
* --------------------------------------------------------------------------
|
|
4
|
-
* CoreUI util/index.
|
|
4
|
+
* CoreUI util/index.ts
|
|
5
5
|
* Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE)
|
|
6
6
|
*
|
|
7
|
-
* This is a modified version of the Bootstrap's util/index.
|
|
7
|
+
* This is a modified version of the Bootstrap's util/index.ts
|
|
8
8
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|
9
9
|
* --------------------------------------------------------------------------
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Types
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// The jQuery bridge is untyped on purpose: jQuery is optional at runtime and we
|
|
17
|
+
// only ever touch `.jquery`, index 0, and the plugin registration surface.
|
|
18
|
+
type JQueryLike = { jquery?: unknown, [index: number]: HTMLElement }
|
|
19
|
+
type JQueryStatic = ((selector: unknown) => any) & Record<string, any> & { fn: Record<string, any> }
|
|
20
|
+
type JQueryPlugin = { NAME: string, jQueryInterface: (...args: any[]) => unknown }
|
|
21
|
+
|
|
22
|
+
declare global {
|
|
23
|
+
interface Window {
|
|
24
|
+
jQuery?: JQueryStatic
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
12
28
|
const MAX_UID = 1_000_000
|
|
13
29
|
const MILLISECONDS_MULTIPLIER = 1000
|
|
14
30
|
const TRANSITION_END = 'transitionend'
|
|
@@ -18,29 +34,31 @@ const TRANSITION_END = 'transitionend'
|
|
|
18
34
|
* @param {string} selector
|
|
19
35
|
* @returns {string}
|
|
20
36
|
*/
|
|
21
|
-
const parseSelector = selector => {
|
|
22
|
-
|
|
37
|
+
const parseSelector = (selector: string): string => {
|
|
38
|
+
// The `window.CSS` checks guard against ancient browsers, so check them as
|
|
39
|
+
// untyped values instead of letting tsc call them always-defined
|
|
40
|
+
if (selector && (window as any).CSS && (window as any).CSS.escape) {
|
|
23
41
|
// document.querySelector needs escaping to handle IDs (html5+) containing for instance /
|
|
24
|
-
selector = selector.replace(/#([^\s"#']+)/g, (match, id) => `#${CSS.escape(id)}`)
|
|
42
|
+
selector = selector.replace(/#([^\s"#']+)/g, (match, id: string) => `#${CSS.escape(id)}`)
|
|
25
43
|
}
|
|
26
44
|
|
|
27
45
|
return selector
|
|
28
46
|
}
|
|
29
47
|
|
|
30
48
|
// Shout-out Angus Croll (https://goo.gl/pxwQGp)
|
|
31
|
-
const toType = object => {
|
|
49
|
+
const toType = (object: unknown): string => {
|
|
32
50
|
if (object === null || object === undefined) {
|
|
33
51
|
return `${object}`
|
|
34
52
|
}
|
|
35
53
|
|
|
36
|
-
return Object.prototype.toString.call(object).match(/\s([a-z]+)/i)[1].toLowerCase()
|
|
54
|
+
return Object.prototype.toString.call(object).match(/\s([a-z]+)/i)![1].toLowerCase()
|
|
37
55
|
}
|
|
38
56
|
|
|
39
57
|
/**
|
|
40
58
|
* Public Util API
|
|
41
59
|
*/
|
|
42
60
|
|
|
43
|
-
const getUID = prefix => {
|
|
61
|
+
const getUID = (prefix: string): string => {
|
|
44
62
|
do {
|
|
45
63
|
prefix += Math.floor(Math.random() * MAX_UID)
|
|
46
64
|
} while (document.getElementById(prefix))
|
|
@@ -48,7 +66,7 @@ const getUID = prefix => {
|
|
|
48
66
|
return prefix
|
|
49
67
|
}
|
|
50
68
|
|
|
51
|
-
const getTransitionDurationFromElement = element => {
|
|
69
|
+
const getTransitionDurationFromElement = (element: Element | null): number => {
|
|
52
70
|
if (!element) {
|
|
53
71
|
return 0
|
|
54
72
|
}
|
|
@@ -71,26 +89,26 @@ const getTransitionDurationFromElement = element => {
|
|
|
71
89
|
return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER
|
|
72
90
|
}
|
|
73
91
|
|
|
74
|
-
const triggerTransitionEnd = element => {
|
|
92
|
+
const triggerTransitionEnd = (element: Element): void => {
|
|
75
93
|
element.dispatchEvent(new Event(TRANSITION_END))
|
|
76
94
|
}
|
|
77
95
|
|
|
78
|
-
const isElement = object => {
|
|
96
|
+
const isElement = (object: unknown): object is Element => {
|
|
79
97
|
if (!object || typeof object !== 'object') {
|
|
80
98
|
return false
|
|
81
99
|
}
|
|
82
100
|
|
|
83
|
-
if (typeof object.jquery !== 'undefined') {
|
|
84
|
-
object = object[0]
|
|
101
|
+
if (typeof (object as JQueryLike).jquery !== 'undefined') {
|
|
102
|
+
object = (object as JQueryLike)[0]
|
|
85
103
|
}
|
|
86
104
|
|
|
87
|
-
return typeof object.nodeType !== 'undefined'
|
|
105
|
+
return typeof (object as Element).nodeType !== 'undefined'
|
|
88
106
|
}
|
|
89
107
|
|
|
90
|
-
const getElement = object => {
|
|
108
|
+
const getElement = (object: unknown): HTMLElement | null => {
|
|
91
109
|
// it's a jQuery object or a node element
|
|
92
110
|
if (isElement(object)) {
|
|
93
|
-
return object.jquery ? object[0] : object
|
|
111
|
+
return (object as unknown as JQueryLike).jquery ? (object as unknown as JQueryLike)[0] : object as HTMLElement
|
|
94
112
|
}
|
|
95
113
|
|
|
96
114
|
if (typeof object === 'string' && object.length > 0) {
|
|
@@ -100,7 +118,7 @@ const getElement = object => {
|
|
|
100
118
|
return null
|
|
101
119
|
}
|
|
102
120
|
|
|
103
|
-
const isVisible = element => {
|
|
121
|
+
const isVisible = (element: unknown): boolean => {
|
|
104
122
|
if (!isElement(element) || element.getClientRects().length === 0) {
|
|
105
123
|
return false
|
|
106
124
|
}
|
|
@@ -127,7 +145,7 @@ const isVisible = element => {
|
|
|
127
145
|
return elementIsVisible
|
|
128
146
|
}
|
|
129
147
|
|
|
130
|
-
const isDisabled = element => {
|
|
148
|
+
const isDisabled = (element: Element | null | undefined): boolean => {
|
|
131
149
|
if (!element || element.nodeType !== Node.ELEMENT_NODE) {
|
|
132
150
|
return true
|
|
133
151
|
}
|
|
@@ -136,14 +154,14 @@ const isDisabled = element => {
|
|
|
136
154
|
return true
|
|
137
155
|
}
|
|
138
156
|
|
|
139
|
-
if (typeof element.disabled !== 'undefined') {
|
|
140
|
-
return element.disabled
|
|
157
|
+
if (typeof (element as HTMLInputElement).disabled !== 'undefined') {
|
|
158
|
+
return (element as HTMLInputElement).disabled
|
|
141
159
|
}
|
|
142
160
|
|
|
143
161
|
return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'
|
|
144
162
|
}
|
|
145
163
|
|
|
146
|
-
const findShadowRoot = element => {
|
|
164
|
+
const findShadowRoot = (element: Node): ShadowRoot | null => {
|
|
147
165
|
if (!document.documentElement.attachShadow) {
|
|
148
166
|
return null
|
|
149
167
|
}
|
|
@@ -166,7 +184,7 @@ const findShadowRoot = element => {
|
|
|
166
184
|
return findShadowRoot(element.parentNode)
|
|
167
185
|
}
|
|
168
186
|
|
|
169
|
-
const noop = () => {}
|
|
187
|
+
const noop = (): void => {}
|
|
170
188
|
|
|
171
189
|
/**
|
|
172
190
|
* Trick to restart an element's animation
|
|
@@ -176,11 +194,11 @@ const noop = () => {}
|
|
|
176
194
|
*
|
|
177
195
|
* @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
|
|
178
196
|
*/
|
|
179
|
-
const reflow = element => {
|
|
180
|
-
element.offsetHeight // eslint-disable-line no-unused-expressions
|
|
197
|
+
const reflow = (element: HTMLElement): void => {
|
|
198
|
+
element.offsetHeight // eslint-disable-line @typescript-eslint/no-unused-expressions
|
|
181
199
|
}
|
|
182
200
|
|
|
183
|
-
const getjQuery = () => {
|
|
201
|
+
const getjQuery = (): JQueryStatic | null => {
|
|
184
202
|
if (window.jQuery && !document.body.hasAttribute('data-coreui-no-jquery')) {
|
|
185
203
|
return window.jQuery
|
|
186
204
|
}
|
|
@@ -188,9 +206,9 @@ const getjQuery = () => {
|
|
|
188
206
|
return null
|
|
189
207
|
}
|
|
190
208
|
|
|
191
|
-
const DOMContentLoadedCallbacks = []
|
|
209
|
+
const DOMContentLoadedCallbacks: Array<() => void> = []
|
|
192
210
|
|
|
193
|
-
const onDOMContentLoaded = callback => {
|
|
211
|
+
const onDOMContentLoaded = (callback: () => void): void => {
|
|
194
212
|
if (document.readyState === 'loading') {
|
|
195
213
|
// add listener on the first call when the document is in loading state
|
|
196
214
|
if (!DOMContentLoadedCallbacks.length) {
|
|
@@ -207,9 +225,9 @@ const onDOMContentLoaded = callback => {
|
|
|
207
225
|
}
|
|
208
226
|
}
|
|
209
227
|
|
|
210
|
-
const isRTL = () => document.documentElement.dir === 'rtl'
|
|
228
|
+
const isRTL = (): boolean => document.documentElement.dir === 'rtl'
|
|
211
229
|
|
|
212
|
-
const defineJQueryPlugin = plugin => {
|
|
230
|
+
const defineJQueryPlugin = (plugin: JQueryPlugin): void => {
|
|
213
231
|
onDOMContentLoaded(() => {
|
|
214
232
|
const $ = getjQuery()
|
|
215
233
|
/* istanbul ignore if */
|
|
@@ -226,11 +244,11 @@ const defineJQueryPlugin = plugin => {
|
|
|
226
244
|
})
|
|
227
245
|
}
|
|
228
246
|
|
|
229
|
-
const execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {
|
|
230
|
-
return typeof possibleCallback === 'function' ? possibleCallback.call(...args) : defaultValue
|
|
247
|
+
const execute = <T = any>(possibleCallback: T | ((...functionArgs: any[]) => T), args: any[] = [], defaultValue: T | ((...functionArgs: any[]) => T) = possibleCallback): T => {
|
|
248
|
+
return typeof possibleCallback === 'function' ? (possibleCallback as (...functionArgs: any[]) => T).call(...args as [any, ...any[]]) : defaultValue as T
|
|
231
249
|
}
|
|
232
250
|
|
|
233
|
-
const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {
|
|
251
|
+
const executeAfterTransition = (callback: () => void, transitionElement: Element, waitForTransition = true): void => {
|
|
234
252
|
if (!waitForTransition) {
|
|
235
253
|
execute(callback)
|
|
236
254
|
return
|
|
@@ -241,7 +259,7 @@ const executeAfterTransition = (callback, transitionElement, waitForTransition =
|
|
|
241
259
|
|
|
242
260
|
let called = false
|
|
243
261
|
|
|
244
|
-
const handler = ({ target }) => {
|
|
262
|
+
const handler = ({ target }: Event): void => {
|
|
245
263
|
if (target !== transitionElement) {
|
|
246
264
|
return
|
|
247
265
|
}
|
|
@@ -268,7 +286,9 @@ const executeAfterTransition = (callback, transitionElement, waitForTransition =
|
|
|
268
286
|
* @param isCycleAllowed
|
|
269
287
|
* @return {Element|elem} The proper element
|
|
270
288
|
*/
|
|
271
|
-
|
|
289
|
+
// `isCycleAllowed` is optional here where upstream requires it: our callers
|
|
290
|
+
// omit it, and adding the argument to match would change the emitted code.
|
|
291
|
+
const getNextActiveElement = <T>(list: T[], activeElement: T, shouldGetNext: boolean, isCycleAllowed?: boolean): T => {
|
|
272
292
|
const listLength = list.length
|
|
273
293
|
let index = list.indexOf(activeElement)
|
|
274
294
|
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* --------------------------------------------------------------------------
|
|
3
|
+
* CoreUI PRO data-grid util/print.ts
|
|
4
|
+
* License (https://coreui.io/pro/license/)
|
|
5
|
+
* --------------------------------------------------------------------------
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { DataGridItem } from '../types'
|
|
9
|
+
|
|
10
|
+
// Printing a virtualized grid straight from the DOM would print the twenty
|
|
11
|
+
// rows that happen to be in the window, and a paginated one would print the
|
|
12
|
+
// current page. Neither is what anyone means by "print this table", so the
|
|
13
|
+
// grid renders a plain, complete table into the document, prints that, and
|
|
14
|
+
// throws it away. The print stylesheet hides everything else on the page.
|
|
15
|
+
|
|
16
|
+
const CLASS_NAME_PRINT_ROOT = 'data-grid-print-root'
|
|
17
|
+
|
|
18
|
+
export interface PrintColumn {
|
|
19
|
+
id: string
|
|
20
|
+
label: string
|
|
21
|
+
formatter?: (value: unknown, item: DataGridItem) => string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface PrintRow {
|
|
25
|
+
getValue: (columnId: string) => unknown
|
|
26
|
+
original: DataGridItem
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface PrintTable {
|
|
30
|
+
// The rows BEFORE pagination: the whole result of the user's sorting and
|
|
31
|
+
// filtering, which is the table they think they are printing.
|
|
32
|
+
getSortedRowModel?: () => { rows: PrintRow[] }
|
|
33
|
+
getFilteredRowModel?: () => { rows: PrintRow[] }
|
|
34
|
+
getCoreRowModel: () => { rows: PrintRow[] }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface PrintOptions {
|
|
38
|
+
// Printed above the table. Omitted entirely when not set.
|
|
39
|
+
title?: string
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// The widest row model the registered features expose — feature sets without
|
|
43
|
+
// sorting or filtering fall back to the core one.
|
|
44
|
+
const printRows = (table: PrintTable): PrintRow[] => {
|
|
45
|
+
if (typeof table.getSortedRowModel === 'function') {
|
|
46
|
+
return table.getSortedRowModel().rows
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (typeof table.getFilteredRowModel === 'function') {
|
|
50
|
+
return table.getFilteredRowModel().rows
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return table.getCoreRowModel().rows
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const createPrintTable = (
|
|
57
|
+
table: PrintTable,
|
|
58
|
+
columns: PrintColumn[],
|
|
59
|
+
options: PrintOptions = {}
|
|
60
|
+
): HTMLElement => {
|
|
61
|
+
const root = document.createElement('div')
|
|
62
|
+
root.className = CLASS_NAME_PRINT_ROOT
|
|
63
|
+
|
|
64
|
+
if (options.title) {
|
|
65
|
+
const heading = document.createElement('h1')
|
|
66
|
+
heading.textContent = options.title
|
|
67
|
+
root.append(heading)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const tableElement = document.createElement('table')
|
|
71
|
+
tableElement.classList.add('table')
|
|
72
|
+
|
|
73
|
+
const head = document.createElement('thead')
|
|
74
|
+
const headRow = document.createElement('tr')
|
|
75
|
+
for (const column of columns) {
|
|
76
|
+
const cell = document.createElement('th')
|
|
77
|
+
cell.scope = 'col'
|
|
78
|
+
cell.textContent = column.label
|
|
79
|
+
headRow.append(cell)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
head.append(headRow)
|
|
83
|
+
|
|
84
|
+
const body = document.createElement('tbody')
|
|
85
|
+
for (const row of printRows(table)) {
|
|
86
|
+
const rowElement = document.createElement('tr')
|
|
87
|
+
for (const column of columns) {
|
|
88
|
+
const cell = document.createElement('td')
|
|
89
|
+
const value = row.getValue(column.id)
|
|
90
|
+
// textContent, never innerHTML: a custom cell renderer's markup is not
|
|
91
|
+
// reachable here, and the printed page must not become an injection
|
|
92
|
+
// surface for the data.
|
|
93
|
+
cell.textContent = column.formatter ? column.formatter(value, row.original) : String(value ?? '')
|
|
94
|
+
rowElement.append(cell)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
body.append(rowElement)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
tableElement.append(head, body)
|
|
101
|
+
root.append(tableElement)
|
|
102
|
+
|
|
103
|
+
return root
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export const printGrid = (table: PrintTable, columns: PrintColumn[], options: PrintOptions = {}): void => {
|
|
107
|
+
const root = createPrintTable(table, columns, options)
|
|
108
|
+
document.body.append(root)
|
|
109
|
+
|
|
110
|
+
// afterprint fires on every browser we support; the finally is the safety
|
|
111
|
+
// net for a print dialog that never opens (a headless or blocked context),
|
|
112
|
+
// where leaving the clone in the document would be worse than a flicker.
|
|
113
|
+
const cleanup = () => {
|
|
114
|
+
root.remove()
|
|
115
|
+
window.removeEventListener('afterprint', cleanup)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
window.addEventListener('afterprint', cleanup)
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
window.print()
|
|
122
|
+
} finally {
|
|
123
|
+
cleanup()
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
// Vendored from https://github.com/coreui/coreui-pro/blob/
|
|
1
|
+
// Vendored from https://github.com/coreui/coreui-pro/blob/e9355580e/js/src/util/sanitizer.ts — sync manually
|
|
2
2
|
/**
|
|
3
3
|
* --------------------------------------------------------------------------
|
|
4
|
-
* CoreUI util/sanitizer.
|
|
4
|
+
* CoreUI util/sanitizer.ts
|
|
5
5
|
* Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE)
|
|
6
6
|
*
|
|
7
|
-
* This is a modified version of the Bootstrap's util/sanitizer.
|
|
7
|
+
* This is a modified version of the Bootstrap's util/sanitizer.ts
|
|
8
8
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|
9
9
|
* --------------------------------------------------------------------------
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
type SanitizerAllowList = Record<string, Array<string | RegExp>>
|
|
13
|
+
|
|
12
14
|
// js-docs-start allow-list
|
|
13
15
|
const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
|
|
14
16
|
|
|
15
|
-
export const DefaultAllowlist = {
|
|
17
|
+
export const DefaultAllowlist: SanitizerAllowList = {
|
|
16
18
|
// Global attributes allowed on any supplied element below.
|
|
17
19
|
'*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
|
|
18
20
|
a: ['target', 'href', 'title', 'rel'],
|
|
@@ -51,7 +53,7 @@ export const DefaultAllowlist = {
|
|
|
51
53
|
// js-docs-end allow-list
|
|
52
54
|
|
|
53
55
|
// js-docs-start svg-allow-list
|
|
54
|
-
export const SVGAllowlist = {
|
|
56
|
+
export const SVGAllowlist: SanitizerAllowList = {
|
|
55
57
|
...DefaultAllowlist,
|
|
56
58
|
svg: ['xmlns', 'version', 'baseprofile', 'width', 'height', 'viewbox', 'preserveaspectratio', 'aria-hidden', 'role', 'focusable', 'fill', 'stroke', 'stroke-width', 'stroke-linecap', 'stroke-linejoin'],
|
|
57
59
|
g: ['id', 'class', 'transform', 'style'],
|
|
@@ -79,7 +81,7 @@ export const SVGAllowlist = {
|
|
|
79
81
|
}
|
|
80
82
|
// js-docs-end svg-allow-list
|
|
81
83
|
|
|
82
|
-
const ESCAPE_HTML_MAP = {
|
|
84
|
+
const ESCAPE_HTML_MAP: Record<string, string> = {
|
|
83
85
|
'&': '&',
|
|
84
86
|
'<': '<',
|
|
85
87
|
'>': '>',
|
|
@@ -87,7 +89,7 @@ const ESCAPE_HTML_MAP = {
|
|
|
87
89
|
"'": '''
|
|
88
90
|
}
|
|
89
91
|
|
|
90
|
-
export function escapeHtml(unsafeText) {
|
|
92
|
+
export function escapeHtml(unsafeText: string): string {
|
|
91
93
|
return String(unsafeText).replace(/[&<>"']/g, character => ESCAPE_HTML_MAP[character])
|
|
92
94
|
}
|
|
93
95
|
|
|
@@ -110,12 +112,12 @@ const uriAttributes = new Set([
|
|
|
110
112
|
*/
|
|
111
113
|
const SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i
|
|
112
114
|
|
|
113
|
-
const allowedAttribute = (attribute, allowedAttributeList) => {
|
|
115
|
+
const allowedAttribute = (attribute: Attr, allowedAttributeList: Array<string | RegExp>): boolean => {
|
|
114
116
|
const attributeName = attribute.nodeName.toLowerCase()
|
|
115
117
|
|
|
116
118
|
if (allowedAttributeList.includes(attributeName)) {
|
|
117
119
|
if (uriAttributes.has(attributeName)) {
|
|
118
|
-
return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue))
|
|
120
|
+
return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue!))
|
|
119
121
|
}
|
|
120
122
|
|
|
121
123
|
return true
|
|
@@ -126,7 +128,7 @@ const allowedAttribute = (attribute, allowedAttributeList) => {
|
|
|
126
128
|
.some(regex => regex.test(attributeName))
|
|
127
129
|
}
|
|
128
130
|
|
|
129
|
-
export function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {
|
|
131
|
+
export function sanitizeHtml(unsafeHtml: string, allowList: SanitizerAllowList, sanitizeFunction?: ((unsafeHtml: string) => string) | null): string {
|
|
130
132
|
if (!unsafeHtml.length) {
|
|
131
133
|
return unsafeHtml
|
|
132
134
|
}
|
|
@@ -137,7 +139,7 @@ export function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {
|
|
|
137
139
|
|
|
138
140
|
const domParser = new window.DOMParser()
|
|
139
141
|
const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')
|
|
140
|
-
const elements = [].concat(...createdDocument.body.querySelectorAll('*'))
|
|
142
|
+
const elements = ([] as Element[]).concat(...createdDocument.body.querySelectorAll('*'))
|
|
141
143
|
|
|
142
144
|
for (const element of elements) {
|
|
143
145
|
const elementName = element.nodeName.toLowerCase()
|
|
@@ -148,8 +150,8 @@ export function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {
|
|
|
148
150
|
continue
|
|
149
151
|
}
|
|
150
152
|
|
|
151
|
-
const attributeList = [].concat(...element.attributes)
|
|
152
|
-
const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || [])
|
|
153
|
+
const attributeList = ([] as Attr[]).concat(...element.attributes)
|
|
154
|
+
const allowedAttributes = ([] as Array<string | RegExp>).concat(allowList['*'] || [], allowList[elementName] || [])
|
|
153
155
|
|
|
154
156
|
for (const attribute of attributeList) {
|
|
155
157
|
if (!allowedAttribute(attribute, allowedAttributes)) {
|
|
@@ -160,3 +162,5 @@ export function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {
|
|
|
160
162
|
|
|
161
163
|
return createdDocument.body.innerHTML
|
|
162
164
|
}
|
|
165
|
+
|
|
166
|
+
export type { SanitizerAllowList }
|