@operato/data-grist 0.3.9 → 0.3.16
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/CHANGELOG.md +71 -0
- package/assets/images/no-image.png +0 -0
- package/custom-elements.json +747 -180
- package/demo/index.html +38 -62
- package/dist/src/configure/list-option-builder.js +0 -2
- package/dist/src/configure/list-option-builder.js.map +1 -1
- package/dist/src/configure/zero-config.d.ts +0 -1
- package/dist/src/configure/zero-config.js +0 -2
- package/dist/src/configure/zero-config.js.map +1 -1
- package/dist/src/data-card/data-card.d.ts +3 -6
- package/dist/src/data-card/data-card.js +3 -130
- package/dist/src/data-card/data-card.js.map +1 -1
- package/dist/src/data-card/record-card.d.ts +0 -1
- package/dist/src/data-card/record-card.js +16 -13
- package/dist/src/data-card/record-card.js.map +1 -1
- package/dist/src/data-grid/data-grid-body.d.ts +1 -1
- package/dist/src/data-grid/data-grid-body.js +5 -5
- package/dist/src/data-grid/data-grid-body.js.map +1 -1
- package/dist/src/data-grid/data-grid-field.d.ts +1 -1
- package/dist/src/data-grid/data-grid-field.js +4 -2
- package/dist/src/data-grid/data-grid-field.js.map +1 -1
- package/dist/src/data-grid/data-grid-header.d.ts +1 -0
- package/dist/src/data-grid/data-grid-header.js +9 -1
- package/dist/src/data-grid/data-grid-header.js.map +1 -1
- package/dist/src/data-grid/data-grid.d.ts +8 -5
- package/dist/src/data-grid/data-grid.js +7 -133
- package/dist/src/data-grid/data-grid.js.map +1 -1
- package/dist/src/data-grist.d.ts +1 -0
- package/dist/src/data-grist.js +4 -4
- package/dist/src/data-grist.js.map +1 -1
- package/dist/src/data-list/data-list.d.ts +3 -6
- package/dist/src/data-list/data-list.js +3 -130
- package/dist/src/data-list/data-list.js.map +1 -1
- package/dist/src/data-manipulator.d.ts +20 -0
- package/dist/src/data-manipulator.js +148 -0
- package/dist/src/data-manipulator.js.map +1 -0
- package/dist/src/editors/registry.d.ts +1 -1
- package/dist/src/editors/registry.js.map +1 -1
- package/dist/src/gutters/gutter-button.js +1 -0
- package/dist/src/gutters/gutter-button.js.map +1 -1
- package/dist/src/gutters/gutter-row-selector.js +1 -0
- package/dist/src/gutters/gutter-row-selector.js.map +1 -1
- package/dist/src/record-view/event-handlers/record-view-body-click-handler.d.ts +7 -0
- package/dist/src/record-view/event-handlers/record-view-body-click-handler.js +22 -0
- package/dist/src/record-view/event-handlers/record-view-body-click-handler.js.map +1 -0
- package/dist/src/record-view/event-handlers/record-view-body-keydown-handler.d.ts +7 -0
- package/dist/src/record-view/event-handlers/record-view-body-keydown-handler.js +96 -0
- package/dist/src/record-view/event-handlers/record-view-body-keydown-handler.js.map +1 -0
- package/dist/src/record-view/record-creator.d.ts +13 -0
- package/dist/src/record-view/record-creator.js +90 -0
- package/dist/src/record-view/record-creator.js.map +1 -0
- package/dist/src/record-view/record-view-body.d.ts +4 -5
- package/dist/src/record-view/record-view-body.js +19 -44
- package/dist/src/record-view/record-view-body.js.map +1 -1
- package/dist/src/record-view/record-view.d.ts +7 -2
- package/dist/src/record-view/record-view.js +114 -41
- package/dist/src/record-view/record-view.js.map +1 -1
- package/dist/src/renderers/image-renderer.js +12 -4
- package/dist/src/renderers/image-renderer.js.map +1 -1
- package/dist/src/sorters/sorters-control.d.ts +12 -0
- package/dist/src/sorters/sorters-control.js +106 -0
- package/dist/src/sorters/sorters-control.js.map +1 -0
- package/dist/src/types.d.ts +2 -3
- package/dist/src/types.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -8
- package/src/configure/list-option-builder.ts +0 -2
- package/src/configure/zero-config.ts +0 -2
- package/src/data-card/data-card.ts +4 -156
- package/src/data-card/record-card.ts +17 -14
- package/src/data-grid/data-grid-body.ts +6 -6
- package/src/data-grid/data-grid-field.ts +5 -3
- package/src/data-grid/data-grid-header.ts +11 -1
- package/src/data-grid/data-grid.ts +19 -149
- package/src/data-grist.ts +5 -4
- package/src/data-list/data-list.ts +4 -156
- package/src/data-manipulator.ts +201 -0
- package/src/editors/registry.ts +2 -3
- package/src/gutters/gutter-button.ts +3 -2
- package/src/gutters/gutter-row-selector.ts +3 -2
- package/src/record-view/event-handlers/record-view-body-click-handler.ts +28 -0
- package/src/record-view/event-handlers/record-view-body-keydown-handler.ts +115 -0
- package/src/record-view/record-creator.ts +111 -0
- package/src/record-view/record-view-body.ts +21 -58
- package/src/record-view/record-view.ts +123 -48
- package/src/renderers/image-renderer.ts +14 -5
- package/src/sorters/sorters-control.ts +111 -0
- package/src/types.ts +10 -3
- package/themes/grist-theme.css +2 -22
- package/yarn-error.log +16718 -0
|
@@ -6,6 +6,7 @@ import { customElement, property, state } from 'lit/decorators.js'
|
|
|
6
6
|
import throttle from 'lodash-es/throttle'
|
|
7
7
|
|
|
8
8
|
import { OxPopup } from '@operato/popup'
|
|
9
|
+
import { closestElement } from '@operato/utils'
|
|
9
10
|
|
|
10
11
|
import { ZERO_COLUMNS, ZERO_CONFIG, ZERO_DATA } from '../configure/zero-config'
|
|
11
12
|
import { FilterStyles } from '../filters/filter-styles'
|
|
@@ -24,7 +25,7 @@ export class DataGridHeader extends LitElement {
|
|
|
24
25
|
overflow: hidden;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
div[column] {
|
|
28
29
|
display: flex;
|
|
29
30
|
|
|
30
31
|
white-space: nowrap;
|
|
@@ -119,6 +120,15 @@ export class DataGridHeader extends LitElement {
|
|
|
119
120
|
private _lastAccVal?: number
|
|
120
121
|
private _throttledNotifier?: any
|
|
121
122
|
|
|
123
|
+
connectedCallback() {
|
|
124
|
+
super.connectedCallback()
|
|
125
|
+
|
|
126
|
+
const grid = closestElement('ox-grist', this)
|
|
127
|
+
grid?.addEventListener('sorters-change', (e: Event) => {
|
|
128
|
+
this._sorters = (e as CustomEvent).detail
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
|
|
122
132
|
render() {
|
|
123
133
|
var columns = this.columns || []
|
|
124
134
|
|
|
@@ -2,20 +2,21 @@ import './data-grid-header'
|
|
|
2
2
|
import './data-grid-body'
|
|
3
3
|
import './data-grid-footer'
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import { LitElement, PropertyValues, css, html } from 'lit'
|
|
7
|
-
import { ZERO_CONFIG, ZERO_DATA } from '../configure/zero-config'
|
|
5
|
+
import { css, html, LitElement, PropertyValues } from 'lit'
|
|
8
6
|
import { customElement, property, query } from 'lit/decorators.js'
|
|
9
7
|
|
|
10
|
-
import { DataGridHeader } from './data-grid-header'
|
|
11
8
|
import { ScrollbarStyles } from '@operato/styles'
|
|
9
|
+
|
|
10
|
+
import { DataManipulator } from '../data-manipulator'
|
|
11
|
+
import { ColumnConfig, GristRecord, PaginationConfig } from '../types'
|
|
12
12
|
import { supportsPassive } from '../utils'
|
|
13
|
+
import { DataGridHeader } from './data-grid-header'
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* DataGrid
|
|
16
17
|
*/
|
|
17
18
|
@customElement('ox-grid')
|
|
18
|
-
export class DataGrid extends
|
|
19
|
+
export class DataGrid extends DataManipulator {
|
|
19
20
|
static styles = [
|
|
20
21
|
ScrollbarStyles,
|
|
21
22
|
css`
|
|
@@ -40,8 +41,6 @@ export class DataGrid extends LitElement {
|
|
|
40
41
|
`
|
|
41
42
|
]
|
|
42
43
|
|
|
43
|
-
@property({ type: Object }) config: GristConfig = ZERO_CONFIG
|
|
44
|
-
@property({ type: Object }) data: GristData = ZERO_DATA
|
|
45
44
|
@property({ type: Object }) focused?: { row: number; column: number }
|
|
46
45
|
|
|
47
46
|
@query('ox-grid-body', true) body!: LitElement
|
|
@@ -82,70 +81,11 @@ export class DataGrid extends LitElement {
|
|
|
82
81
|
this.body.requestUpdate()
|
|
83
82
|
})
|
|
84
83
|
|
|
85
|
-
this.addEventListener('select-record-change', e => {
|
|
86
|
-
var {
|
|
87
|
-
records: selectedRecords,
|
|
88
|
-
added = [],
|
|
89
|
-
removed = []
|
|
90
|
-
} = (e as CustomEvent).detail as {
|
|
91
|
-
records: GristRecord[]
|
|
92
|
-
added: GristRecord[]
|
|
93
|
-
removed: GristRecord[]
|
|
94
|
-
}
|
|
95
|
-
var { records } = this.data
|
|
96
|
-
var { selectable } = this.config.rows
|
|
97
|
-
|
|
98
|
-
if (!records) {
|
|
99
|
-
return
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (selectable && !selectable.multiple) {
|
|
103
|
-
records.forEach(record => (record['__selected__'] = false))
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (selectedRecords) {
|
|
107
|
-
records.forEach(record => (record['__selected__'] = false))
|
|
108
|
-
selectedRecords.forEach(record => (record['__selected__'] = true))
|
|
109
|
-
} else {
|
|
110
|
-
removed.forEach(record => (record['__selected__'] = false))
|
|
111
|
-
added.forEach(record => (record['__selected__'] = true))
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
this.header.requestUpdate()
|
|
115
|
-
this.body.requestUpdate()
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
/* field change processing */
|
|
119
|
-
this.addEventListener('field-change', e => {
|
|
120
|
-
var { after, before, column, record, row } = (e as CustomEvent).detail
|
|
121
|
-
|
|
122
|
-
/* compare changes */
|
|
123
|
-
if (after === before) {
|
|
124
|
-
return
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
var validation = column.validation
|
|
128
|
-
if (validation && typeof (validation == 'function')) {
|
|
129
|
-
if (!validation.call(this, after, before, record, column)) {
|
|
130
|
-
return
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
this.onRecordChanged({ [column.name]: after }, row, column)
|
|
135
|
-
})
|
|
136
|
-
|
|
137
84
|
this.addEventListener('focus-change', e => {
|
|
138
85
|
this.focused = (e as CustomEvent).detail
|
|
139
86
|
this.focus()
|
|
140
87
|
this.requestUpdate()
|
|
141
88
|
})
|
|
142
|
-
|
|
143
|
-
/* record reset processing */
|
|
144
|
-
this.addEventListener('record-reset', e => {
|
|
145
|
-
var { record, row } = (e as CustomEvent).detail
|
|
146
|
-
|
|
147
|
-
this.onRecordChanged(record['__origin__'], row, null)
|
|
148
|
-
})
|
|
149
89
|
}
|
|
150
90
|
|
|
151
91
|
onWheelEvent(e: WheelEvent) {
|
|
@@ -155,89 +95,19 @@ export class DataGrid extends LitElement {
|
|
|
155
95
|
supportsPassive || e.preventDefault()
|
|
156
96
|
}
|
|
157
97
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
var wantToAppend = false
|
|
172
|
-
|
|
173
|
-
if (!recordData) {
|
|
174
|
-
if (!beforeRecord) {
|
|
175
|
-
/* recordData가 없고, beforeRecord도 없다면, 레코드 생성 중에 리셋된 경우이므로 아무것도 하지 않는다. */
|
|
176
|
-
this.requestUpdate()
|
|
177
|
-
return
|
|
178
|
-
} else {
|
|
179
|
-
/*
|
|
180
|
-
* beforeRecord가 있는데, 빈데이타로 업데이트하고자 한다면,
|
|
181
|
-
* 삭제하고자 하는 의도로 이해된다. (주의 필요)
|
|
182
|
-
*/
|
|
183
|
-
if (beforeRecord['__dirty__'] == '+') {
|
|
184
|
-
wantToDelete = true
|
|
185
|
-
} else {
|
|
186
|
-
afterRecord = {
|
|
187
|
-
...beforeRecord,
|
|
188
|
-
__dirty__: '-'
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
} else {
|
|
193
|
-
if (!beforeRecord) {
|
|
194
|
-
/* 기존 레코드가 없는 경우에는 새로운 레코드가 생성된다 */
|
|
195
|
-
afterRecord = {
|
|
196
|
-
...recordData,
|
|
197
|
-
__dirty__: '+'
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
wantToAppend = true
|
|
201
|
-
} else {
|
|
202
|
-
let beforeDirty = beforeRecord.__dirty__
|
|
203
|
-
if (beforeDirty == '+') {
|
|
204
|
-
/* 기존에 새로 생성된 레코드가 있었으며 계속 수정중이다. */
|
|
205
|
-
afterRecord = {
|
|
206
|
-
...beforeRecord,
|
|
207
|
-
...recordData,
|
|
208
|
-
__dirty__: '+'
|
|
209
|
-
}
|
|
210
|
-
} else {
|
|
211
|
-
/* 기존에 레코드가 있었으며 계속 수정중이다. */
|
|
212
|
-
afterRecord = {
|
|
213
|
-
...beforeRecord,
|
|
214
|
-
...recordData,
|
|
215
|
-
__dirty__: 'M'
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if (wantToAppend) {
|
|
222
|
-
records.push(afterRecord!)
|
|
223
|
-
} else if (wantToDelete) {
|
|
224
|
-
records.splice(row, 1)
|
|
225
|
-
} else {
|
|
226
|
-
records.splice(row, 1, afterRecord!)
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
this.dispatchEvent(
|
|
230
|
-
new CustomEvent('record-change', {
|
|
231
|
-
bubbles: true,
|
|
232
|
-
composed: true,
|
|
233
|
-
detail: {
|
|
234
|
-
before: beforeRecord,
|
|
235
|
-
after: afterRecord!,
|
|
236
|
-
column,
|
|
237
|
-
row
|
|
238
|
-
}
|
|
239
|
-
})
|
|
240
|
-
)
|
|
98
|
+
onSelectRecordChanged({
|
|
99
|
+
selectedRecords,
|
|
100
|
+
added,
|
|
101
|
+
removed
|
|
102
|
+
}: {
|
|
103
|
+
selectedRecords: GristRecord[]
|
|
104
|
+
added: GristRecord[]
|
|
105
|
+
removed: GristRecord[]
|
|
106
|
+
}): void {
|
|
107
|
+
super.onSelectRecordChanged({ selectedRecords, added, removed })
|
|
108
|
+
|
|
109
|
+
this.header.requestUpdate()
|
|
110
|
+
this.body.requestUpdate()
|
|
241
111
|
}
|
|
242
112
|
|
|
243
113
|
updated(changes: PropertyValues<this>) {
|
package/src/data-grist.ts
CHANGED
|
@@ -275,6 +275,10 @@ export class DataGrist extends LitElement implements DataConsumer {
|
|
|
275
275
|
}
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
+
get compiledConfig(): GristConfig {
|
|
279
|
+
return this._config
|
|
280
|
+
}
|
|
281
|
+
|
|
278
282
|
get sorters(): SortersConfig | undefined {
|
|
279
283
|
return this._config?.sorters
|
|
280
284
|
}
|
|
@@ -392,15 +396,12 @@ export class DataGrist extends LitElement implements DataConsumer {
|
|
|
392
396
|
* @method
|
|
393
397
|
*/
|
|
394
398
|
reset() {
|
|
395
|
-
if (!ZERO_PAGINATION) {
|
|
396
|
-
console.error('ZERO_PAGINATION', ZERO_PAGINATION)
|
|
397
|
-
}
|
|
398
399
|
var {
|
|
399
400
|
limit = ZERO_PAGINATION.limit,
|
|
400
401
|
page = ZERO_PAGINATION.page,
|
|
401
402
|
total = ZERO_PAGINATION.total,
|
|
402
403
|
records = []
|
|
403
|
-
} = this.data
|
|
404
|
+
} = this.data || ZERO_PAGINATION
|
|
404
405
|
|
|
405
406
|
/* 원본 데이타를 남기고, 복사본(_data)을 사용한다. */
|
|
406
407
|
records = records.map((record, idx) => {
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import '@material/mwc-icon'
|
|
2
2
|
import './record-partial'
|
|
3
3
|
|
|
4
|
-
import { css, html,
|
|
4
|
+
import { css, html, PropertyValues } from 'lit'
|
|
5
5
|
import { customElement, property } from 'lit/decorators.js'
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { DataManipulator } from '../data-manipulator'
|
|
8
|
+
import { GristRecord } from '../types'
|
|
9
9
|
|
|
10
10
|
@customElement('ox-list')
|
|
11
|
-
export class DataList extends
|
|
11
|
+
export class DataList extends DataManipulator {
|
|
12
12
|
static styles = [
|
|
13
13
|
css`
|
|
14
14
|
:host {
|
|
@@ -42,8 +42,6 @@ export class DataList extends LitElement {
|
|
|
42
42
|
`
|
|
43
43
|
]
|
|
44
44
|
|
|
45
|
-
@property({ type: Object }) config: GristConfig = ZERO_CONFIG
|
|
46
|
-
@property({ type: Object }) data: GristData = ZERO_DATA
|
|
47
45
|
@property({ type: Boolean }) isTop: boolean = false
|
|
48
46
|
@property({ type: Array }) private _records: GristRecord[] = []
|
|
49
47
|
|
|
@@ -71,156 +69,6 @@ export class DataList extends LitElement {
|
|
|
71
69
|
|
|
72
70
|
this.isTop = this.scrollTop == 0
|
|
73
71
|
})
|
|
74
|
-
|
|
75
|
-
this.addEventListener('select-record-change', e => {
|
|
76
|
-
var {
|
|
77
|
-
records: selectedRecords,
|
|
78
|
-
added = [],
|
|
79
|
-
removed = []
|
|
80
|
-
} = (e as CustomEvent).detail as {
|
|
81
|
-
records: GristRecord[]
|
|
82
|
-
added: GristRecord[]
|
|
83
|
-
removed: GristRecord[]
|
|
84
|
-
}
|
|
85
|
-
var { records } = this.data || {}
|
|
86
|
-
var { selectable = false } = this.config.rows || {}
|
|
87
|
-
|
|
88
|
-
if (!records || !selectable) {
|
|
89
|
-
return
|
|
90
|
-
} else if (selectable && !selectable.multiple) {
|
|
91
|
-
records.forEach(record => (record['__selected__'] = false))
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (selectedRecords) {
|
|
95
|
-
records.forEach(record => (record['__selected__'] = false))
|
|
96
|
-
selectedRecords.forEach(record => (record['__selected__'] = true))
|
|
97
|
-
} else {
|
|
98
|
-
removed.forEach(record => (record['__selected__'] = false))
|
|
99
|
-
added.forEach(record => (record['__selected__'] = true))
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
this.requestUpdate()
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
/* field change processing */
|
|
106
|
-
this.addEventListener('field-change', e => {
|
|
107
|
-
var { after, before, column, record, row } = (e as CustomEvent).detail as {
|
|
108
|
-
after: any
|
|
109
|
-
before: any
|
|
110
|
-
column: ColumnConfig
|
|
111
|
-
record: GristRecord
|
|
112
|
-
row: number
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/* compare changes */
|
|
116
|
-
if (after === before) {
|
|
117
|
-
return
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
var validation = column.validation
|
|
121
|
-
if (validation && typeof validation == 'function') {
|
|
122
|
-
if (!validation.call(this, after, before, record, column)) {
|
|
123
|
-
return
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
this.onRecordChanged({ [column.name]: after }, row, column)
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
/* record reset processing */
|
|
131
|
-
this.addEventListener('record-reset', e => {
|
|
132
|
-
var { record, row } = (e as CustomEvent).detail as {
|
|
133
|
-
record: GristRecord
|
|
134
|
-
row: number
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
this.onRecordChanged(record['__origin__'], row, null)
|
|
138
|
-
})
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
onRecordChanged(
|
|
142
|
-
recordData: GristRecord,
|
|
143
|
-
row: number,
|
|
144
|
-
column: ColumnConfig | null /* TODO column should be removed */
|
|
145
|
-
) {
|
|
146
|
-
// TODO 오브젝트나 배열 타입인 경우 deepCompare 후에 변경 적용 여부를 결정한다.
|
|
147
|
-
|
|
148
|
-
/* 빈 그리드로 시작한 경우, data 설정이 되어있지 않을 수 있다. */
|
|
149
|
-
var records = this.data.records
|
|
150
|
-
|
|
151
|
-
var beforeRecord = records[row]
|
|
152
|
-
var afterRecord: GristRecord
|
|
153
|
-
var wantToDelete = false
|
|
154
|
-
var wantToAppend = false
|
|
155
|
-
|
|
156
|
-
if (!recordData) {
|
|
157
|
-
if (!beforeRecord) {
|
|
158
|
-
/* recordData가 없고, beforeRecord도 없다면, 레코드 생성 중에 리셋된 경우이므로 아무것도 하지 않는다. */
|
|
159
|
-
this.requestUpdate()
|
|
160
|
-
return
|
|
161
|
-
} else {
|
|
162
|
-
/*
|
|
163
|
-
* beforeRecord가 있는데, 빈데이타로 업데이트하고자 한다면,
|
|
164
|
-
* 삭제하고자 하는 의도로 이해된다. (주의 필요)
|
|
165
|
-
*/
|
|
166
|
-
if (beforeRecord['__dirty__'] == '+') {
|
|
167
|
-
wantToDelete = true
|
|
168
|
-
} else {
|
|
169
|
-
afterRecord = {
|
|
170
|
-
...beforeRecord,
|
|
171
|
-
__dirty__: '-'
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
} else {
|
|
176
|
-
if (!beforeRecord) {
|
|
177
|
-
/* 기존 레코드가 없는 경우에는 새로운 레코드가 생성된다 */
|
|
178
|
-
afterRecord = {
|
|
179
|
-
...recordData,
|
|
180
|
-
__dirty__: '+'
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
wantToAppend = true
|
|
184
|
-
} else {
|
|
185
|
-
let beforeDirty = beforeRecord['__dirty__']
|
|
186
|
-
if (beforeDirty == '+') {
|
|
187
|
-
/* 기존에 새로 생성된 레코드가 있었으며 계속 수정중이다. */
|
|
188
|
-
afterRecord = {
|
|
189
|
-
...beforeRecord,
|
|
190
|
-
...recordData,
|
|
191
|
-
__dirty__: '+'
|
|
192
|
-
}
|
|
193
|
-
} else {
|
|
194
|
-
/* 기존에 레코드가 있었으며 계속 수정중이다. */
|
|
195
|
-
afterRecord = {
|
|
196
|
-
...beforeRecord,
|
|
197
|
-
...recordData,
|
|
198
|
-
__dirty__: 'M'
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (wantToAppend) {
|
|
205
|
-
records.push(afterRecord!)
|
|
206
|
-
} else if (wantToDelete) {
|
|
207
|
-
records.splice(row, 1)
|
|
208
|
-
} else {
|
|
209
|
-
records.splice(row, 1, afterRecord!)
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
this.dispatchEvent(
|
|
213
|
-
new CustomEvent('record-change', {
|
|
214
|
-
bubbles: true,
|
|
215
|
-
composed: true,
|
|
216
|
-
detail: {
|
|
217
|
-
before: beforeRecord,
|
|
218
|
-
after: afterRecord!,
|
|
219
|
-
column,
|
|
220
|
-
row
|
|
221
|
-
}
|
|
222
|
-
})
|
|
223
|
-
)
|
|
224
72
|
}
|
|
225
73
|
|
|
226
74
|
updated(changes: PropertyValues<this>) {
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { LitElement } from 'lit'
|
|
2
|
+
import { property } from 'lit/decorators.js'
|
|
3
|
+
|
|
4
|
+
import { ZERO_CONFIG, ZERO_DATA } from './configure/zero-config'
|
|
5
|
+
import { ColumnConfig, GristConfig, GristData, GristRecord } from './types'
|
|
6
|
+
|
|
7
|
+
export class DataManipulator extends LitElement {
|
|
8
|
+
@property({ type: Object }) config: GristConfig = ZERO_CONFIG
|
|
9
|
+
@property({ type: Object }) data: GristData = ZERO_DATA
|
|
10
|
+
|
|
11
|
+
constructor() {
|
|
12
|
+
super()
|
|
13
|
+
|
|
14
|
+
this.addEventListener('select-record-change', e => {
|
|
15
|
+
var {
|
|
16
|
+
records: selectedRecords,
|
|
17
|
+
added = [],
|
|
18
|
+
removed = []
|
|
19
|
+
} = (e as CustomEvent).detail as {
|
|
20
|
+
records: GristRecord[]
|
|
21
|
+
added: GristRecord[]
|
|
22
|
+
removed: GristRecord[]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
this.onSelectRecordChanged({
|
|
26
|
+
selectedRecords,
|
|
27
|
+
added,
|
|
28
|
+
removed
|
|
29
|
+
})
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
/* field change processing */
|
|
33
|
+
this.addEventListener('field-change', e => {
|
|
34
|
+
var { after, before, column, record, row } = (e as CustomEvent).detail as {
|
|
35
|
+
after: any
|
|
36
|
+
before: any
|
|
37
|
+
column: ColumnConfig
|
|
38
|
+
record: GristRecord
|
|
39
|
+
row: number
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
this.onFieldChange({ after, before, column, record, row })
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
/* record reset processing */
|
|
46
|
+
this.addEventListener('record-reset', e => {
|
|
47
|
+
var { record, row } = (e as CustomEvent).detail as {
|
|
48
|
+
record: GristRecord
|
|
49
|
+
row: number
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this.onRecordChanged(record['__origin__'], row, null)
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
onFieldChange({
|
|
57
|
+
after,
|
|
58
|
+
before,
|
|
59
|
+
column,
|
|
60
|
+
record,
|
|
61
|
+
row
|
|
62
|
+
}: {
|
|
63
|
+
after: any
|
|
64
|
+
before: any
|
|
65
|
+
column: ColumnConfig
|
|
66
|
+
record: GristRecord
|
|
67
|
+
row: number
|
|
68
|
+
}) {
|
|
69
|
+
/* compare changes */
|
|
70
|
+
if (after === before) {
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
var validation = column.validation
|
|
75
|
+
if (validation && typeof validation == 'function') {
|
|
76
|
+
if (!validation.call(this, after, before, record, column)) {
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
this.onRecordChanged({ [column.name]: after }, row, column)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
onSelectRecordChanged({
|
|
85
|
+
selectedRecords,
|
|
86
|
+
added = [],
|
|
87
|
+
removed = []
|
|
88
|
+
}: {
|
|
89
|
+
selectedRecords: GristRecord[]
|
|
90
|
+
added: GristRecord[]
|
|
91
|
+
removed: GristRecord[]
|
|
92
|
+
}) {
|
|
93
|
+
var { records } = this.data || {}
|
|
94
|
+
var { selectable = false } = this.config.rows || {}
|
|
95
|
+
|
|
96
|
+
if (!records || !selectable) {
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (selectable && !selectable.multiple) {
|
|
101
|
+
records.forEach(record => (record['__selected__'] = false))
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (selectedRecords) {
|
|
105
|
+
records.forEach(record => (record['__selected__'] = false))
|
|
106
|
+
selectedRecords.forEach(record => (record['__selected__'] = true))
|
|
107
|
+
} else {
|
|
108
|
+
removed.forEach(record => (record['__selected__'] = false))
|
|
109
|
+
added.forEach(record => (record['__selected__'] = true))
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
this.requestUpdate()
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
onRecordChanged(
|
|
116
|
+
recordData: GristRecord,
|
|
117
|
+
row: number,
|
|
118
|
+
column: ColumnConfig | null /* TODO column should be removed */
|
|
119
|
+
) {
|
|
120
|
+
// TODO 오브젝트나 배열 타입인 경우 deepCompare 후에 변경 적용 여부를 결정한다.
|
|
121
|
+
|
|
122
|
+
/* 빈 그리드로 시작한 경우, data 설정이 되어있지 않을 수 있다. */
|
|
123
|
+
var records = this.data.records
|
|
124
|
+
|
|
125
|
+
var beforeRecord = records[row]
|
|
126
|
+
var afterRecord: GristRecord
|
|
127
|
+
var wantToDelete = false
|
|
128
|
+
var wantToAppend = false
|
|
129
|
+
|
|
130
|
+
if (!recordData) {
|
|
131
|
+
if (!beforeRecord) {
|
|
132
|
+
/* recordData가 없고, beforeRecord도 없다면, 레코드 생성 중에 리셋된 경우이므로 아무것도 하지 않는다. */
|
|
133
|
+
this.requestUpdate()
|
|
134
|
+
return
|
|
135
|
+
} else {
|
|
136
|
+
/*
|
|
137
|
+
* beforeRecord가 있는데, 빈데이타로 업데이트하고자 한다면,
|
|
138
|
+
* 삭제하고자 하는 의도로 이해된다. (주의 필요)
|
|
139
|
+
*/
|
|
140
|
+
if (beforeRecord['__dirty__'] == '+') {
|
|
141
|
+
wantToDelete = true
|
|
142
|
+
} else {
|
|
143
|
+
afterRecord = {
|
|
144
|
+
...beforeRecord,
|
|
145
|
+
__dirty__: '-'
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
} else {
|
|
150
|
+
if (!beforeRecord) {
|
|
151
|
+
/* 기존 레코드가 없는 경우에는 새로운 레코드가 생성된다 */
|
|
152
|
+
afterRecord = {
|
|
153
|
+
...recordData,
|
|
154
|
+
__dirty__: '+'
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
wantToAppend = true
|
|
158
|
+
} else {
|
|
159
|
+
let beforeDirty = beforeRecord['__dirty__']
|
|
160
|
+
if (beforeDirty == '+') {
|
|
161
|
+
/* 기존에 새로 생성된 레코드가 있었으며 계속 수정중이다. */
|
|
162
|
+
afterRecord = {
|
|
163
|
+
...beforeRecord,
|
|
164
|
+
...recordData,
|
|
165
|
+
__dirty__: '+'
|
|
166
|
+
}
|
|
167
|
+
} else {
|
|
168
|
+
/* 기존에 레코드가 있었으며 계속 수정중이다. */
|
|
169
|
+
afterRecord = {
|
|
170
|
+
...beforeRecord,
|
|
171
|
+
...recordData,
|
|
172
|
+
__dirty__: 'M'
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (wantToAppend) {
|
|
179
|
+
records.push(afterRecord!)
|
|
180
|
+
} else if (wantToDelete) {
|
|
181
|
+
records.splice(row, 1)
|
|
182
|
+
} else {
|
|
183
|
+
records.splice(row, 1, afterRecord!)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
this.dispatchEvent(
|
|
187
|
+
new CustomEvent('record-change', {
|
|
188
|
+
bubbles: true,
|
|
189
|
+
composed: true,
|
|
190
|
+
detail: {
|
|
191
|
+
before: beforeRecord,
|
|
192
|
+
after: afterRecord!,
|
|
193
|
+
column,
|
|
194
|
+
row
|
|
195
|
+
}
|
|
196
|
+
})
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
this.requestUpdate()
|
|
200
|
+
}
|
|
201
|
+
}
|
package/src/editors/registry.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { DataGridField } from '../data-grid/data-grid-field'
|
|
2
|
+
import { ColumnConfig, FieldEditor, GristRecord } from '../types'
|
|
1
3
|
import {
|
|
2
4
|
CheckboxInput,
|
|
3
5
|
ColorInput,
|
|
@@ -15,9 +17,6 @@ import {
|
|
|
15
17
|
TimeInput,
|
|
16
18
|
WeekInput
|
|
17
19
|
} from './input-editors'
|
|
18
|
-
import { ColumnConfig, FieldEditor, GristRecord } from '../types'
|
|
19
|
-
|
|
20
|
-
import { DataGridField } from '../data-grid/data-grid-field'
|
|
21
20
|
|
|
22
21
|
var EDITORS: { [name: string]: { new (): InputEditor } } = {
|
|
23
22
|
string: TextInput,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import '@material/mwc-icon'
|
|
2
2
|
|
|
3
|
-
import { FieldRenderer, HeaderRenderer } from '../types'
|
|
4
|
-
|
|
5
3
|
import { html } from 'lit'
|
|
6
4
|
|
|
5
|
+
import { FieldRenderer, HeaderRenderer } from '../types'
|
|
6
|
+
|
|
7
7
|
export class GutterButton {
|
|
8
8
|
static instance(config: any = {}) {
|
|
9
9
|
var { icon = 'edit' } = config
|
|
@@ -27,6 +27,7 @@ export class GutterButton {
|
|
|
27
27
|
} as HeaderRenderer
|
|
28
28
|
},
|
|
29
29
|
record: {
|
|
30
|
+
align: 'center',
|
|
30
31
|
renderer: function (value, column, record, rowIndex, field) {
|
|
31
32
|
return html` <mwc-icon style=${inlineRecordStyle}>${iconFn(record)}</mwc-icon> `
|
|
32
33
|
} as FieldRenderer
|