@operato/data-grist 0.3.13 → 0.3.17
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 +47 -0
- package/assets/images/no-image.png +0 -0
- package/custom-elements.json +2382 -1803
- package/demo/index.html +41 -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 -131
- package/dist/src/data-card/data-card.js.map +1 -1
- package/dist/src/data-card/record-card.d.ts +0 -3
- package/dist/src/data-card/record-card.js +22 -71
- package/dist/src/data-card/record-card.js.map +1 -1
- package/dist/src/data-grid/data-grid-body.d.ts +7 -1
- package/dist/src/data-grid/data-grid-body.js +26 -5
- package/dist/src/data-grid/data-grid-body.js.map +1 -1
- package/dist/src/data-grid/data-grid-field.js +1 -1
- 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 -4
- package/dist/src/data-grid/data-grid.js +12 -132
- 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 +3 -0
- 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 -131
- package/dist/src/data-list/data-list.js.map +1 -1
- package/dist/src/data-list/record-partial.d.ts +0 -2
- package/dist/src/data-list/record-partial.js +7 -58
- package/dist/src/data-list/record-partial.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/image-editor.d.ts +9 -0
- package/dist/src/editors/image-editor.js +53 -0
- package/dist/src/editors/image-editor.js.map +1 -0
- package/dist/src/editors/image-input.d.ts +7 -0
- package/dist/src/editors/image-input.js +31 -0
- package/dist/src/editors/image-input.js.map +1 -0
- package/dist/src/editors/index.d.ts +1 -0
- package/dist/src/editors/index.js +1 -0
- package/dist/src/editors/index.js.map +1 -1
- package/dist/src/editors/input-editors copy.d.ts +75 -0
- package/dist/src/editors/input-editors copy.js +373 -0
- package/dist/src/editors/input-editors copy.js.map +1 -0
- package/dist/src/editors/input-editors.d.ts +1 -8
- package/dist/src/editors/input-editors.js +3 -47
- package/dist/src/editors/input-editors.js.map +1 -1
- package/dist/src/editors/registry.d.ts +1 -1
- package/dist/src/editors/registry.js +2 -1
- package/dist/src/editors/registry.js.map +1 -1
- package/dist/src/handlers/record-view-handler.d.ts +1 -2
- package/dist/src/handlers/record-view-handler.js +5 -35
- package/dist/src/handlers/record-view-handler.js.map +1 -1
- package/dist/src/handlers/select-row-toggle.d.ts +1 -1
- package/dist/src/handlers/select-row-toggle.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 +24 -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 +22 -0
- package/dist/src/record-view/event-handlers/record-view-body-keydown-handler.js.map +1 -0
- package/dist/src/record-view/index.d.ts +1 -0
- package/dist/src/record-view/index.js +1 -0
- package/dist/src/record-view/index.js.map +1 -1
- package/dist/src/record-view/record-creator copy.d.ts +13 -0
- package/dist/src/record-view/record-creator copy.js +90 -0
- package/dist/src/record-view/record-creator copy.js.map +1 -0
- package/dist/src/record-view/record-creator-backup.d.ts +13 -0
- package/dist/src/record-view/record-creator-backup.js +90 -0
- package/dist/src/record-view/record-creator-backup.js.map +1 -0
- package/dist/src/record-view/record-creator.d.ts +16 -0
- package/dist/src/record-view/record-creator.js +145 -0
- package/dist/src/record-view/record-creator.js.map +1 -0
- package/dist/src/record-view/record-view-body.d.ts +3 -4
- package/dist/src/record-view/record-view-body.js +15 -42
- package/dist/src/record-view/record-view-body.js.map +1 -1
- package/dist/src/record-view/record-view-handler.d.ts +9 -0
- package/dist/src/record-view/record-view-handler.js +57 -0
- package/dist/src/record-view/record-view-handler.js.map +1 -0
- package/dist/src/record-view/record-view.d.ts +5 -1
- package/dist/src/record-view/record-view.js +61 -36
- 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 -158
- package/src/data-card/record-card.ts +30 -87
- package/src/data-grid/data-grid-body.ts +43 -6
- package/src/data-grid/data-grid-field.ts +1 -1
- package/src/data-grid/data-grid-header.ts +11 -1
- package/src/data-grid/data-grid.ts +25 -143
- package/src/data-grist.ts +4 -0
- package/src/data-list/data-list.ts +4 -158
- package/src/data-list/record-partial.ts +14 -73
- package/src/data-manipulator.ts +201 -0
- package/src/editors/image-input.ts +29 -0
- package/src/editors/index.ts +1 -0
- package/src/editors/input-editors.ts +5 -48
- package/src/editors/registry.ts +3 -4
- package/src/handlers/record-view-handler.ts +8 -44
- package/src/handlers/select-row-toggle.ts +1 -2
- package/src/record-view/event-handlers/record-view-body-click-handler.ts +30 -0
- package/src/record-view/event-handlers/record-view-body-keydown-handler.ts +26 -0
- package/src/record-view/index.ts +1 -0
- package/src/record-view/record-creator.ts +180 -0
- package/src/record-view/record-view-body.ts +16 -55
- package/src/record-view/record-view-handler.ts +86 -0
- package/src/record-view/record-view.ts +69 -42
- package/src/renderers/image-renderer.ts +14 -5
- package/src/sorters/sorters-control.ts +111 -0
- package/src/types.ts +10 -3
- package/yarn-error.log +16718 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import '@material/mwc-icon'
|
|
2
|
+
import './record-view'
|
|
3
|
+
|
|
4
|
+
import { html, LitElement } from 'lit'
|
|
5
|
+
import { customElement, property, state } from 'lit/decorators.js'
|
|
6
|
+
|
|
7
|
+
import { OxPopup } from '@operato/popup'
|
|
8
|
+
|
|
9
|
+
import { DataGrist } from '../data-grist'
|
|
10
|
+
import { ColumnConfig, GristRecord } from '../types'
|
|
11
|
+
import { RecordView } from './record-view'
|
|
12
|
+
|
|
13
|
+
@customElement('ox-record-creator')
|
|
14
|
+
export class RecordCreator extends LitElement {
|
|
15
|
+
@state() grist?: DataGrist
|
|
16
|
+
|
|
17
|
+
@property({ type: Object }) callback?: (operation: { [key: string]: any }) => boolean
|
|
18
|
+
@property({ type: Boolean, attribute: 'light-popup' }) lightPopup: boolean = false
|
|
19
|
+
|
|
20
|
+
constructor() {
|
|
21
|
+
super()
|
|
22
|
+
|
|
23
|
+
this.addEventListener('click', (e: Event) => {
|
|
24
|
+
e.preventDefault()
|
|
25
|
+
e.stopPropagation()
|
|
26
|
+
|
|
27
|
+
if (this.lightPopup) {
|
|
28
|
+
this.lightPopupRecordView()
|
|
29
|
+
} else {
|
|
30
|
+
this.popupRecordView()
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
connectedCallback(): void {
|
|
36
|
+
super.connectedCallback()
|
|
37
|
+
|
|
38
|
+
this.grist = this.closest('ox-grist') as DataGrist
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
render() {
|
|
42
|
+
return html`<slot></slot>`
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
lightPopupRecordView() {
|
|
46
|
+
const config = this.grist!.compiledConfig
|
|
47
|
+
var title = 'create'
|
|
48
|
+
const rowIndex = -1
|
|
49
|
+
var record: GristRecord = {}
|
|
50
|
+
const columns = config.columns
|
|
51
|
+
|
|
52
|
+
var popup = OxPopup.open({
|
|
53
|
+
template: html`
|
|
54
|
+
<div title>${title}</div>
|
|
55
|
+
<ox-record-view
|
|
56
|
+
only-for-edit
|
|
57
|
+
@field-change=${(e: CustomEvent) => {
|
|
58
|
+
const view = e.currentTarget as RecordView
|
|
59
|
+
|
|
60
|
+
var { after, before, column, record, row } = (e as CustomEvent).detail as {
|
|
61
|
+
after: any
|
|
62
|
+
before: any
|
|
63
|
+
column: ColumnConfig
|
|
64
|
+
record: GristRecord
|
|
65
|
+
row: number
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
var validation = column.validation
|
|
69
|
+
if (validation && typeof validation == 'function') {
|
|
70
|
+
if (!validation.call(this, after, before, record, column)) {
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
view.record = {
|
|
76
|
+
...record,
|
|
77
|
+
[column.name]: after
|
|
78
|
+
}
|
|
79
|
+
}}
|
|
80
|
+
.columns=${columns}
|
|
81
|
+
.record=${record}
|
|
82
|
+
.rowIndex=${rowIndex}
|
|
83
|
+
@reset=${(e: Event) => {
|
|
84
|
+
const view = e.currentTarget as RecordView
|
|
85
|
+
view.record = {}
|
|
86
|
+
}}
|
|
87
|
+
@cancel=${(e: Event) => {
|
|
88
|
+
popup.close()
|
|
89
|
+
}}
|
|
90
|
+
@ok=${(e: Event) => {
|
|
91
|
+
popup.close()
|
|
92
|
+
|
|
93
|
+
const view = e.currentTarget as RecordView
|
|
94
|
+
|
|
95
|
+
this.dispatchEvent(
|
|
96
|
+
new CustomEvent('ok', {
|
|
97
|
+
bubbles: true,
|
|
98
|
+
composed: true,
|
|
99
|
+
detail: view.record
|
|
100
|
+
})
|
|
101
|
+
)
|
|
102
|
+
}}
|
|
103
|
+
></ox-record-view>
|
|
104
|
+
`,
|
|
105
|
+
parent: document.body
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
popupRecordView() {
|
|
110
|
+
const config = this.grist!.compiledConfig
|
|
111
|
+
const rowIndex = -1
|
|
112
|
+
var record: GristRecord = {}
|
|
113
|
+
const columns = config.columns
|
|
114
|
+
|
|
115
|
+
var title = 'create'
|
|
116
|
+
|
|
117
|
+
var recordView = document.createElement('ox-record-view') as RecordView
|
|
118
|
+
|
|
119
|
+
recordView.setAttribute('only-for-edit', '')
|
|
120
|
+
recordView.columns = columns
|
|
121
|
+
recordView.record = record
|
|
122
|
+
recordView.rowIndex = rowIndex
|
|
123
|
+
|
|
124
|
+
document.dispatchEvent(
|
|
125
|
+
new CustomEvent('open-popup', {
|
|
126
|
+
detail: {
|
|
127
|
+
template: recordView,
|
|
128
|
+
options: {
|
|
129
|
+
backdrop: true,
|
|
130
|
+
size: 'large',
|
|
131
|
+
title
|
|
132
|
+
},
|
|
133
|
+
callback: (popup: any) => {
|
|
134
|
+
recordView.addEventListener('reset', (e: Event) => {
|
|
135
|
+
const view = e.currentTarget as RecordView
|
|
136
|
+
view.record = {}
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
recordView.addEventListener('cancel', (e: Event) => {
|
|
140
|
+
popup.close()
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
recordView.addEventListener('ok', async (e: Event) => {
|
|
144
|
+
const view = e.currentTarget as RecordView
|
|
145
|
+
if (await this.callback?.(view.record)) {
|
|
146
|
+
popup.close()
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
recordView.addEventListener('field-change', (e: Event) => {
|
|
151
|
+
const view = e.currentTarget as RecordView
|
|
152
|
+
|
|
153
|
+
var { after, before, column, record, row } = (e as CustomEvent).detail as {
|
|
154
|
+
after: any
|
|
155
|
+
before: any
|
|
156
|
+
column: ColumnConfig
|
|
157
|
+
record: GristRecord
|
|
158
|
+
row: number
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
var validation = column.validation
|
|
162
|
+
if (validation && typeof validation == 'function') {
|
|
163
|
+
if (!validation.call(this, after, before, record, column)) {
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
view.record = {
|
|
169
|
+
...record,
|
|
170
|
+
[column.name]: after
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
popup.onclosed = () => {}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
})
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
@@ -5,11 +5,9 @@ import { css, html, LitElement } from 'lit'
|
|
|
5
5
|
import { customElement, property } from 'lit/decorators.js'
|
|
6
6
|
|
|
7
7
|
import { ZERO_RECORD } from '../configure/zero-config'
|
|
8
|
-
import { DataGridField } from '../data-grid/data-grid-field'
|
|
9
8
|
import { ColumnConfig, GristRecord } from '../types'
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const KEY_ESC = 27
|
|
9
|
+
import { recordViewBodyClickHandler } from './event-handlers/record-view-body-click-handler'
|
|
10
|
+
import { recordViewBodyKeydownHandler } from './event-handlers/record-view-body-keydown-handler'
|
|
13
11
|
|
|
14
12
|
@customElement('ox-record-view-body')
|
|
15
13
|
export class RecordViewBody extends LitElement {
|
|
@@ -20,10 +18,7 @@ export class RecordViewBody extends LitElement {
|
|
|
20
18
|
grid-template-columns: 1fr 2fr;
|
|
21
19
|
grid-auto-rows: min-content;
|
|
22
20
|
grid-gap: var(--record-view-gap);
|
|
23
|
-
background-color: var(--record-view-background-color);
|
|
24
21
|
padding: var(--record-view-padding);
|
|
25
|
-
|
|
26
|
-
overflow-y: auto;
|
|
27
22
|
}
|
|
28
23
|
|
|
29
24
|
label {
|
|
@@ -49,6 +44,7 @@ export class RecordViewBody extends LitElement {
|
|
|
49
44
|
}
|
|
50
45
|
|
|
51
46
|
ox-grid-field {
|
|
47
|
+
border-top: none;
|
|
52
48
|
border-bottom: var(--record-view-border-bottom);
|
|
53
49
|
font: var(--record-view-font);
|
|
54
50
|
color: var(--record-view-color);
|
|
@@ -56,7 +52,6 @@ export class RecordViewBody extends LitElement {
|
|
|
56
52
|
}
|
|
57
53
|
|
|
58
54
|
ox-grid-field[editing='true'] {
|
|
59
|
-
border-top: none;
|
|
60
55
|
border-bottom: var(--record-view-edit-border-bottom);
|
|
61
56
|
}
|
|
62
57
|
|
|
@@ -70,12 +65,21 @@ export class RecordViewBody extends LitElement {
|
|
|
70
65
|
@property({ type: Array }) columns: ColumnConfig[] = []
|
|
71
66
|
@property({ type: Object }) record: GristRecord = ZERO_RECORD
|
|
72
67
|
@property({ type: Number }) rowIndex: number = -1
|
|
68
|
+
@property({ type: Boolean, attribute: 'only-for-edit' }) onlyForEdit: boolean = false
|
|
69
|
+
|
|
70
|
+
public currentTarget: any
|
|
73
71
|
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
connectedCallback() {
|
|
73
|
+
super.connectedCallback()
|
|
74
|
+
|
|
75
|
+
this.setAttribute('tabindex', '0')
|
|
76
|
+
|
|
77
|
+
this.renderRoot.addEventListener('keydown', recordViewBodyKeydownHandler.bind(this))
|
|
78
|
+
this.renderRoot.addEventListener('click', recordViewBodyClickHandler.bind(this))
|
|
79
|
+
}
|
|
76
80
|
|
|
77
81
|
render() {
|
|
78
|
-
var columns = this.columns.filter(column => !column.hidden && column.type
|
|
82
|
+
var columns = this.columns.filter(column => !column.hidden && column.type !== 'gutter')
|
|
79
83
|
var record = this.record
|
|
80
84
|
var rowIndex = this.rowIndex
|
|
81
85
|
|
|
@@ -92,56 +96,13 @@ export class RecordViewBody extends LitElement {
|
|
|
92
96
|
.record=${record}
|
|
93
97
|
.value=${record[column.name]}
|
|
94
98
|
?dirty=${!!dirtyFields[column.name]}
|
|
99
|
+
?editing=${this.onlyForEdit}
|
|
95
100
|
></ox-grid-field>
|
|
96
101
|
`
|
|
97
102
|
})}
|
|
98
103
|
`
|
|
99
104
|
}
|
|
100
105
|
|
|
101
|
-
firstUpdated() {
|
|
102
|
-
this.renderRoot.addEventListener('click', e => {
|
|
103
|
-
e.stopPropagation()
|
|
104
|
-
|
|
105
|
-
/* target should be 'ox-grid-field' */
|
|
106
|
-
var target = e.target as DataGridField
|
|
107
|
-
|
|
108
|
-
if (this.editTarget) {
|
|
109
|
-
this.editTarget.removeAttribute('editing')
|
|
110
|
-
this.editTarget = null
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (target.tagName !== 'OX-GRID-FIELD' || !target.column.record.editable) {
|
|
114
|
-
return
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
this.editTarget = target
|
|
118
|
-
target.setAttribute('editing', 'true')
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
this._focusedListener = (e: KeyboardEvent) => {
|
|
122
|
-
var keyCode = e.keyCode
|
|
123
|
-
switch (keyCode) {
|
|
124
|
-
case KEY_ESC:
|
|
125
|
-
/* TODO 편집이 취소되어야 한다. */
|
|
126
|
-
case KEY_ENTER:
|
|
127
|
-
if (this.editTarget) {
|
|
128
|
-
this.editTarget.removeAttribute('editing')
|
|
129
|
-
this.editTarget = null
|
|
130
|
-
}
|
|
131
|
-
break
|
|
132
|
-
|
|
133
|
-
default:
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
window.addEventListener('keydown', this._focusedListener)
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
disconnectedCallback() {
|
|
140
|
-
super.disconnectedCallback()
|
|
141
|
-
|
|
142
|
-
window.removeEventListener('keydown', this._focusedListener)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
106
|
_renderLabel(column: ColumnConfig) {
|
|
146
107
|
var { renderer } = column.header
|
|
147
108
|
var title = renderer.call(this, column)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { RecordCard } from '../data-card/record-card'
|
|
2
|
+
import { DataGridBody } from '../data-grid/data-grid-body'
|
|
3
|
+
import { DataGridField } from '../data-grid/data-grid-field'
|
|
4
|
+
import { RecordPartial } from '../data-list/record-partial'
|
|
5
|
+
import { RecordView } from '../record-view/record-view'
|
|
6
|
+
import { ColumnConfig, GristRecord } from '../types'
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* handler들은 ox-grid-field 로부터 호출되는 것을 전제로 하며,
|
|
10
|
+
* 전반적인 처리를 위해서, columns 및 data 정보를 포함해서 제공할 수 있어야 한다.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export const RecordViewHandler = function (
|
|
14
|
+
columns: ColumnConfig[],
|
|
15
|
+
record: GristRecord,
|
|
16
|
+
rowIndex: number,
|
|
17
|
+
field: DataGridField | RecordCard | RecordPartial | DataGridBody,
|
|
18
|
+
popupOptions: { [key: string]: any },
|
|
19
|
+
closeCallback?: () => void
|
|
20
|
+
): RecordView {
|
|
21
|
+
var recordView = document.createElement('ox-record-view') as RecordView
|
|
22
|
+
|
|
23
|
+
recordView.columns = columns
|
|
24
|
+
recordView.record = record
|
|
25
|
+
recordView.rowIndex = rowIndex
|
|
26
|
+
|
|
27
|
+
document.dispatchEvent(
|
|
28
|
+
new CustomEvent('open-popup', {
|
|
29
|
+
detail: {
|
|
30
|
+
template: recordView,
|
|
31
|
+
options: {
|
|
32
|
+
backdrop: true,
|
|
33
|
+
size: 'large',
|
|
34
|
+
title: record['name'],
|
|
35
|
+
...popupOptions
|
|
36
|
+
},
|
|
37
|
+
callback: (popup: any) => {
|
|
38
|
+
recordView.addEventListener('field-change', (e: Event) => {
|
|
39
|
+
field.dispatchEvent(
|
|
40
|
+
new CustomEvent('field-change', {
|
|
41
|
+
bubbles: true,
|
|
42
|
+
composed: true,
|
|
43
|
+
detail: (e as any).detail
|
|
44
|
+
})
|
|
45
|
+
)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
recordView.addEventListener('reset', (e: Event) => {
|
|
49
|
+
field.dispatchEvent(
|
|
50
|
+
new CustomEvent('record-reset', {
|
|
51
|
+
bubbles: true,
|
|
52
|
+
composed: true,
|
|
53
|
+
detail: {
|
|
54
|
+
record: record,
|
|
55
|
+
row: rowIndex
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
recordView.addEventListener('cancel', (e: Event) => {
|
|
62
|
+
field.dispatchEvent(
|
|
63
|
+
new CustomEvent('record-reset', {
|
|
64
|
+
bubbles: true,
|
|
65
|
+
composed: true,
|
|
66
|
+
detail: {
|
|
67
|
+
record: record,
|
|
68
|
+
row: rowIndex
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
)
|
|
72
|
+
popup.close()
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
recordView.addEventListener('ok', (e: Event) => {
|
|
76
|
+
popup.close()
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
popup.onclosed = closeCallback
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
} as any)
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
return recordView
|
|
86
|
+
}
|
|
@@ -1,63 +1,80 @@
|
|
|
1
1
|
import '@material/mwc-icon'
|
|
2
2
|
import './record-view-body'
|
|
3
|
+
import '@operato/input/ox-input-file.js'
|
|
4
|
+
import '../data-grid/data-grid-field'
|
|
3
5
|
|
|
4
6
|
import { css, html, LitElement } from 'lit'
|
|
5
7
|
import { customElement, property } from 'lit/decorators.js'
|
|
6
8
|
|
|
9
|
+
import { ScrollbarStyles } from '@operato/styles'
|
|
10
|
+
|
|
7
11
|
import { ZERO_RECORD } from '../configure/zero-config'
|
|
8
12
|
import { ColumnConfig, GristRecord } from '../types'
|
|
9
13
|
|
|
10
14
|
@customElement('ox-record-view')
|
|
11
15
|
export class RecordView extends LitElement {
|
|
12
|
-
static styles =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
16
|
+
static styles = [
|
|
17
|
+
ScrollbarStyles,
|
|
18
|
+
css`
|
|
19
|
+
:host {
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
background-color: var(--record-view-background-color);
|
|
23
|
+
|
|
24
|
+
max-height: 80vh;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
ox-record-view-body {
|
|
28
|
+
flex: 1;
|
|
29
|
+
overflow-y: auto;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
[footer] {
|
|
33
|
+
display: flex;
|
|
34
|
+
text-align: right;
|
|
35
|
+
background-color: var(--record-view-footer-background);
|
|
36
|
+
box-shadow: var(--context-toolbar-shadow-line);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
[footer] button {
|
|
40
|
+
flex: 1;
|
|
41
|
+
background-color: transparent;
|
|
42
|
+
border: var(--record-view-footer-button-border);
|
|
43
|
+
border-width: var(--record-view-footer-button-border-width);
|
|
44
|
+
color: var(--record-view-footer-button-color);
|
|
45
|
+
font-size: var(--record-view-footer-button-font);
|
|
46
|
+
line-height: 3;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
[footer] button * {
|
|
50
|
+
vertical-align: middle;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
[footer] button mwc-icon {
|
|
54
|
+
margin-top: -3px;
|
|
55
|
+
margin-right: 5px;
|
|
56
|
+
font-size: var(--record-view-footer-iconbutton-size);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
[footer] button[ok] {
|
|
60
|
+
background-color: var(--record-view-footer-focus-background);
|
|
61
|
+
}
|
|
62
|
+
`
|
|
63
|
+
]
|
|
53
64
|
|
|
54
65
|
@property({ type: Array }) columns: ColumnConfig[] = []
|
|
55
66
|
@property({ type: Object }) record: GristRecord = ZERO_RECORD
|
|
56
67
|
@property({ type: Number }) rowIndex: number = -1
|
|
68
|
+
@property({ type: Boolean, attribute: 'only-for-edit' }) onlyForEdit: boolean = false
|
|
57
69
|
|
|
58
70
|
render() {
|
|
59
71
|
return html`
|
|
60
|
-
<ox-record-view-body
|
|
72
|
+
<ox-record-view-body
|
|
73
|
+
.columns=${this.columns}
|
|
74
|
+
.record=${this.record}
|
|
75
|
+
.rowIndex=${this.rowIndex}
|
|
76
|
+
?only-for-edit=${this.onlyForEdit}
|
|
77
|
+
>
|
|
61
78
|
</ox-record-view-body>
|
|
62
79
|
<div footer>
|
|
63
80
|
<button @click=${this.onReset.bind(this)}><mwc-icon>refresh</mwc-icon>Reset</button>
|
|
@@ -67,7 +84,13 @@ export class RecordView extends LitElement {
|
|
|
67
84
|
`
|
|
68
85
|
}
|
|
69
86
|
|
|
87
|
+
firstUpdated() {
|
|
88
|
+
this.setAttribute('tabindex', '0')
|
|
89
|
+
}
|
|
90
|
+
|
|
70
91
|
onReset() {
|
|
92
|
+
this.focus()
|
|
93
|
+
|
|
71
94
|
this.dispatchEvent(
|
|
72
95
|
new CustomEvent('reset', {
|
|
73
96
|
detail: this.record
|
|
@@ -76,6 +99,8 @@ export class RecordView extends LitElement {
|
|
|
76
99
|
}
|
|
77
100
|
|
|
78
101
|
onCancel() {
|
|
102
|
+
this.focus()
|
|
103
|
+
|
|
79
104
|
this.dispatchEvent(
|
|
80
105
|
new CustomEvent('cancel', {
|
|
81
106
|
detail: this.record
|
|
@@ -84,6 +109,8 @@ export class RecordView extends LitElement {
|
|
|
84
109
|
}
|
|
85
110
|
|
|
86
111
|
onOK() {
|
|
112
|
+
this.focus()
|
|
113
|
+
|
|
87
114
|
this.dispatchEvent(
|
|
88
115
|
new CustomEvent('ok', {
|
|
89
116
|
detail: this.record
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import { FieldRenderer } from '../types'
|
|
2
1
|
import { html } from 'lit'
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
if (!value) return html``
|
|
3
|
+
import { FieldRenderer } from '../types'
|
|
6
4
|
|
|
5
|
+
const IMAGE_FALLBACK = new URL('../../../assets/images/no-image.png', import.meta.url).href
|
|
6
|
+
|
|
7
|
+
export const ImageRenderer: FieldRenderer = (value, column, record, rowIndex, field) => {
|
|
7
8
|
let src: string
|
|
8
9
|
|
|
9
|
-
if (
|
|
10
|
+
if (!value) {
|
|
11
|
+
src = IMAGE_FALLBACK
|
|
12
|
+
} else if (typeof value === 'string') {
|
|
10
13
|
src = value
|
|
11
14
|
} else {
|
|
12
15
|
src = URL.createObjectURL(value)
|
|
@@ -15,5 +18,11 @@ export const ImageRenderer: FieldRenderer = (value, column, record, rowIndex, fi
|
|
|
15
18
|
|
|
16
19
|
const { width, height } = column.record.options || {}
|
|
17
20
|
|
|
18
|
-
return html` <img
|
|
21
|
+
return html` <img
|
|
22
|
+
src=${src}
|
|
23
|
+
width=${width}
|
|
24
|
+
height=${height}
|
|
25
|
+
style="max-width: 100%;"
|
|
26
|
+
onerror="this.src !== '${IMAGE_FALLBACK}' && (this.src = '${IMAGE_FALLBACK}')"
|
|
27
|
+
/>`
|
|
19
28
|
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { css, html, LitElement, PropertyValues, TemplateResult } from 'lit'
|
|
2
|
+
import { customElement, state } from 'lit/decorators.js'
|
|
3
|
+
|
|
4
|
+
import { DataGrist } from '../data-grist'
|
|
5
|
+
import { ColumnConfig, GristConfig, SorterConfig } from '../types'
|
|
6
|
+
|
|
7
|
+
@customElement('ox-sorters-control')
|
|
8
|
+
export class SortersControl extends LitElement {
|
|
9
|
+
static styles = [
|
|
10
|
+
css`
|
|
11
|
+
:host {
|
|
12
|
+
display: block;
|
|
13
|
+
}
|
|
14
|
+
`
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
@state() config!: GristConfig
|
|
18
|
+
@state() columns: ColumnConfig[] = []
|
|
19
|
+
@state() sorters: SorterConfig[] = []
|
|
20
|
+
|
|
21
|
+
connectedCallback(): void {
|
|
22
|
+
super.connectedCallback()
|
|
23
|
+
|
|
24
|
+
const grist = this.closest('ox-grist') as DataGrist
|
|
25
|
+
|
|
26
|
+
if (grist) {
|
|
27
|
+
this.config = grist.config
|
|
28
|
+
|
|
29
|
+
this.closest('ox-grist')?.addEventListener('sorters-change', e => {
|
|
30
|
+
this.sorters = (e as CustomEvent).detail as SorterConfig[]
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
updated(changes: PropertyValues<this>) {
|
|
36
|
+
if (changes.has('config')) {
|
|
37
|
+
const sorters = this.config.sorters || []
|
|
38
|
+
|
|
39
|
+
this.columns = sorters
|
|
40
|
+
.map(({ name }) => this.config.columns.find(column => column.name === name))
|
|
41
|
+
.filter(column => !!column) as ColumnConfig[]
|
|
42
|
+
|
|
43
|
+
this.sorters = this.config.sorters || []
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
render(): TemplateResult {
|
|
48
|
+
const columns = this.columns
|
|
49
|
+
|
|
50
|
+
const current = this.sorters || []
|
|
51
|
+
|
|
52
|
+
return html`
|
|
53
|
+
${columns.map(column => {
|
|
54
|
+
const { name } = column
|
|
55
|
+
var rank = current.findIndex(sorter => sorter.name === name) + 1
|
|
56
|
+
var desc = rank !== 0 ? current[rank - 1].desc : null
|
|
57
|
+
|
|
58
|
+
if (current.length <= 1) {
|
|
59
|
+
rank = 0
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return html`
|
|
63
|
+
<div
|
|
64
|
+
option
|
|
65
|
+
@click=${(e: MouseEvent) => {
|
|
66
|
+
this.onChangeSort(name)
|
|
67
|
+
}}
|
|
68
|
+
>
|
|
69
|
+
${column.header /*.renderer.call(this, column) */}
|
|
70
|
+
${desc === null
|
|
71
|
+
? html``
|
|
72
|
+
: html`
|
|
73
|
+
<mwc-icon>${desc ? 'keyboard_arrow_up' : 'keyboard_arrow_down'}</mwc-icon>
|
|
74
|
+
${rank === 0 ? html`` : html`<sub>${rank}</sub>`}
|
|
75
|
+
`}
|
|
76
|
+
</div>
|
|
77
|
+
`
|
|
78
|
+
})}
|
|
79
|
+
`
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
onChangeSort(name: string) {
|
|
83
|
+
var sorters = [...this.sorters]
|
|
84
|
+
|
|
85
|
+
var idx = sorters.findIndex(sorter => sorter.name == name)
|
|
86
|
+
if (idx !== -1) {
|
|
87
|
+
let sorter = sorters[idx]
|
|
88
|
+
if (sorter.desc) {
|
|
89
|
+
sorters.splice(idx, 1)
|
|
90
|
+
} else {
|
|
91
|
+
sorter.desc = true
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
var sorter = {
|
|
95
|
+
name
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
sorters.push(sorter)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
this.sorters = sorters
|
|
102
|
+
|
|
103
|
+
this.dispatchEvent(
|
|
104
|
+
new CustomEvent('sorters-change', {
|
|
105
|
+
bubbles: true,
|
|
106
|
+
composed: true,
|
|
107
|
+
detail: this.sorters
|
|
108
|
+
})
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
}
|