@entryscape/rdforms 10.4.0 → 10.5.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/dist/rdforms.bmd.js +4 -4
- package/dist/rdforms.bootstrap.js +10 -10
- package/dist/rdforms.jquery.js +3 -3
- package/dist/rdforms.node.js +1 -1
- package/dist/rdforms.react.js +67 -67
- package/package.json +2 -2
- package/src/model/ChoiceBinding.js +0 -8
- package/src/template/Item.js +2 -0
- package/src/utils.js +1 -1
- package/src/view/Editor.js +15 -8
- package/src/view/View.js +13 -4
- package/src/view/jquery/text.js +17 -20
- package/src/view/jquery/util.js +170 -0
- package/src/view/react/buttons.js +13 -2
- package/src/view/react/choiceEditors/CheckBoxesEditor.js +87 -0
- package/src/view/react/choiceEditors/index.js +9 -0
- package/src/view/react/components.js +4 -2
- package/src/view/react/date.js +113 -120
- package/src/view/react/labels.js +18 -14
- package/src/view/react/textEditors.js +1 -1
- package/src/view/resources/nls.json +2 -0
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"application profile",
|
|
9
9
|
"linked data"
|
|
10
10
|
],
|
|
11
|
-
"version": "10.
|
|
11
|
+
"version": "10.5.0",
|
|
12
12
|
"main": "dist/rdforms.node.js",
|
|
13
13
|
"browser": "dist/rdforms.react.js",
|
|
14
14
|
"module": "main.js",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@emotion/react": "^11.4.1",
|
|
20
20
|
"@emotion/styled": "^11.3.0",
|
|
21
|
-
"@entryscape/rdfjson": "^2.5.
|
|
21
|
+
"@entryscape/rdfjson": "^2.5.4",
|
|
22
22
|
"@mui/icons-material": "^5.0.3",
|
|
23
23
|
"@mui/lab": "^5.0.0-alpha.51",
|
|
24
24
|
"@mui/material": "^5.0.3",
|
|
@@ -30,14 +30,6 @@ export default class ChoiceBinding extends ValueBinding {
|
|
|
30
30
|
return this._choice;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
remove() {
|
|
34
|
-
this.setValue(null);
|
|
35
|
-
// Removed line below as it is also done in superclass
|
|
36
|
-
// and therefore causes an error
|
|
37
|
-
// this._parent.removeChildBinding(this);
|
|
38
|
-
super.remove();
|
|
39
|
-
}
|
|
40
|
-
|
|
41
33
|
setValue(value, choice, silent) {
|
|
42
34
|
super.setValue(value, choice, silent);
|
|
43
35
|
const oldval = this.getValue();
|
package/src/template/Item.js
CHANGED
package/src/utils.js
CHANGED
|
@@ -3,7 +3,7 @@ import { cloneDeep } from 'lodash-es';
|
|
|
3
3
|
import system from './model/system';
|
|
4
4
|
|
|
5
5
|
const getLocalizedValue = (hash) => {
|
|
6
|
-
const locale = moment.locale();
|
|
6
|
+
const locale = moment.locale('sv');
|
|
7
7
|
if (hash == null) {
|
|
8
8
|
return { precision: 'none' };
|
|
9
9
|
} else if (typeof hash === 'string') {
|
package/src/view/Editor.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import renderingContext from './renderingContext';
|
|
2
2
|
import Presenter from './Presenter';
|
|
3
3
|
import * as engine from '../model/engine';
|
|
4
|
-
import {bindingReport} from '../model/validate';
|
|
4
|
+
import { bindingReport } from '../model/validate';
|
|
5
5
|
|
|
6
6
|
const showNow = (editor, item, bindings, includeLevel) => {
|
|
7
7
|
// Invisible should be created as components and hidden using display: none
|
|
8
8
|
// Otherwise certain extentions such as autoUUID does not work.
|
|
9
|
-
/*if (item.hasStyle('invisible')) {
|
|
9
|
+
/* if (item.hasStyle('invisible')) {
|
|
10
10
|
return false;
|
|
11
|
-
}*/
|
|
11
|
+
} */
|
|
12
12
|
if (item.hasStyle('presenterOnly')) {
|
|
13
13
|
return false;
|
|
14
14
|
}
|
|
@@ -135,6 +135,7 @@ export default class Editor extends Presenter {
|
|
|
135
135
|
return showNow(this, item, bindings, this.includeLevel);
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
// eslint-disable-next-line class-methods-use-this
|
|
138
139
|
skipBinding(/* binding */) {
|
|
139
140
|
return false;
|
|
140
141
|
}
|
|
@@ -185,16 +186,16 @@ export default class Editor extends Presenter {
|
|
|
185
186
|
if (firstBinding.getItem().hasStyle('nonEditable')) {
|
|
186
187
|
return this.addComponent(newRow, firstBinding);
|
|
187
188
|
}
|
|
188
|
-
return renderingContext.addEditorTable(newRow, firstBinding, {view: this});
|
|
189
|
+
return renderingContext.addEditorTable(newRow, firstBinding, { view: this });
|
|
189
190
|
}
|
|
190
191
|
|
|
191
192
|
fillTable(table, bindings) {
|
|
192
|
-
renderingContext.fillEditorTable(table, bindings, {view: this});
|
|
193
|
+
renderingContext.fillEditorTable(table, bindings, { view: this });
|
|
193
194
|
}
|
|
194
195
|
|
|
195
196
|
preRenderView() {
|
|
196
197
|
renderingContext.preEditorViewRenderer(this.domNode, this.binding, {
|
|
197
|
-
view: this, inEditor: true, topLevel: this.topLevel, hideAddress: this.hideAddress
|
|
198
|
+
view: this, inEditor: true, topLevel: this.topLevel, hideAddress: this.hideAddress,
|
|
198
199
|
});
|
|
199
200
|
}
|
|
200
201
|
|
|
@@ -209,7 +210,7 @@ export default class Editor extends Presenter {
|
|
|
209
210
|
|
|
210
211
|
createRowNode(lastRowNode, binding, item) {
|
|
211
212
|
if (binding == null && item.hasStyle('nonEditable')) {
|
|
212
|
-
return;
|
|
213
|
+
return undefined;
|
|
213
214
|
}
|
|
214
215
|
const newNode = super.createRowNode(lastRowNode, binding, item);
|
|
215
216
|
if (item.getType() === 'choice' && typeof item.getProperty() === 'undefined') {
|
|
@@ -255,4 +256,10 @@ export default class Editor extends Presenter {
|
|
|
255
256
|
}
|
|
256
257
|
return newNode;
|
|
257
258
|
}
|
|
258
|
-
|
|
259
|
+
|
|
260
|
+
// eslint-disable-next-line class-methods-use-this
|
|
261
|
+
isMultiValued(item) {
|
|
262
|
+
return renderingContext.multiValueSupport &&
|
|
263
|
+
(item.hasStyle('horizontalCheckBoxes') || item.hasStyle('verticalCheckBoxes'));
|
|
264
|
+
}
|
|
265
|
+
}
|
package/src/view/View.js
CHANGED
|
@@ -180,11 +180,16 @@ export default class View {
|
|
|
180
180
|
|
|
181
181
|
// Non table case
|
|
182
182
|
} else if (bindings.length > 0) {
|
|
183
|
-
|
|
184
|
-
// Add row with label if first row of same item or the binding is a group.
|
|
183
|
+
if (this.isMultiValued(item)) {
|
|
185
184
|
this.context = { view: this };
|
|
186
|
-
lastRow = this.addRow(lastRow, bindings[
|
|
187
|
-
|
|
185
|
+
lastRow = this.addRow(lastRow, bindings[0], true);
|
|
186
|
+
} else {
|
|
187
|
+
for (let i = 0; i < bindings.length; i++) {
|
|
188
|
+
// Add row with label if first row of same item or the binding is a group.
|
|
189
|
+
this.context = { view: this };
|
|
190
|
+
lastRow = this.addRow(lastRow, bindings[i], i === 0 ||
|
|
191
|
+
bindings[i] instanceof GroupBinding);
|
|
192
|
+
}
|
|
188
193
|
}
|
|
189
194
|
} else {
|
|
190
195
|
lastRow = this.createRowNode(lastRow, null, item);
|
|
@@ -346,4 +351,8 @@ export default class View {
|
|
|
346
351
|
this._labelIndex[binding.getHash()] = idx;
|
|
347
352
|
return idx;
|
|
348
353
|
}
|
|
354
|
+
|
|
355
|
+
isMultiValued(item) {
|
|
356
|
+
return false;
|
|
357
|
+
}
|
|
349
358
|
}
|
package/src/view/jquery/text.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import moment from 'moment';
|
|
2
2
|
import { escape } from 'lodash-es';
|
|
3
|
-
import { fromDuration } from './util';
|
|
3
|
+
import { getDatePresentation, fromDuration } from './util';
|
|
4
4
|
import renderingContext from '../renderingContext';
|
|
5
5
|
import utils from '../../utils';
|
|
6
6
|
import system from '../../model/system';
|
|
7
7
|
|
|
8
|
+
|
|
8
9
|
const presenters = renderingContext.presenterRegistry;
|
|
9
10
|
|
|
10
11
|
// Presenter for URIs.
|
|
@@ -117,33 +118,29 @@ presenters.itemtype('text').register((fieldDiv, binding, context) => {
|
|
|
117
118
|
// Presenter for duration
|
|
118
119
|
presenters.itemtype('text').datatype('xsd:duration').register((fieldDiv, binding, context) => {
|
|
119
120
|
const data = fromDuration(binding.getValue());
|
|
120
|
-
const bundle = context.view.messages
|
|
121
|
+
const bundle = context.view.messages;
|
|
121
122
|
const node = jquery('<div>').appendTo(fieldDiv)[0];
|
|
122
123
|
['years', 'months', 'days', 'hours', 'minutes'].forEach((key) => {
|
|
123
124
|
if (data.hasOwnProperty(key)) {
|
|
124
|
-
jquery(`<span class="durationlabel">${bundle[
|
|
125
|
+
jquery(`<span class="durationlabel">${bundle[`duration_${key}`]}:</span><span class="durationValue">${data[key]}</span>`)
|
|
125
126
|
.appendTo(node);
|
|
126
127
|
}
|
|
127
128
|
});
|
|
128
129
|
});
|
|
129
130
|
|
|
130
|
-
const datePresenter = (fieldDiv, binding
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
} else if (data.length > 4) {
|
|
138
|
-
str = moment(data).format('LL');
|
|
139
|
-
} else {
|
|
140
|
-
str = moment(data).format('YYYY');
|
|
141
|
-
}
|
|
142
|
-
jquery('<div>').html(str).appendTo(fieldDiv);
|
|
143
|
-
} catch (e) {
|
|
144
|
-
console.warn(`Could not present date, expected ISO8601 format in the form 2001-01-01 (potentially with time given after a 'T' character as well) but found '${data}' instead.`);
|
|
145
|
-
}
|
|
131
|
+
const datePresenter = (fieldDiv, binding) => {
|
|
132
|
+
try {
|
|
133
|
+
const pres = getDatePresentation(binding);
|
|
134
|
+
jquery('<div>').html(pres).appendTo(fieldDiv);
|
|
135
|
+
} catch (e) {
|
|
136
|
+
console.warn(`Could not present date, expected ISO8601 format in the form 2001-01-01
|
|
137
|
+
(potentially with time given after a 'T' character as well) but found '${binding.getValue()}' instead.`);
|
|
146
138
|
}
|
|
147
139
|
};
|
|
140
|
+
presenters.itemtype('text').datatype('xsd:dateTime').register(datePresenter);
|
|
148
141
|
presenters.itemtype('text').datatype('xsd:date').register(datePresenter);
|
|
149
|
-
presenters.itemtype('text').datatype('
|
|
142
|
+
presenters.itemtype('text').datatype('xsd:time').register(datePresenter);
|
|
143
|
+
presenters.itemtype('text').datatype('xsd:gYear').register(datePresenter);
|
|
144
|
+
presenters.itemtype('text').datatype('xsd:gYearMonth').register(datePresenter);
|
|
145
|
+
presenters.itemtype('text').datatype('xsd:gMonthDay').register(datePresenter);
|
|
146
|
+
presenters.itemtype('text').datatype('dcterms:W3CDTF').register(datePresenter);
|
package/src/view/jquery/util.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import moment from 'moment';
|
|
2
|
+
|
|
1
3
|
export const fromDuration = (value) => {
|
|
2
4
|
const f = val => (val && val.length > 1 ? parseInt(val[0], 10) : 0);
|
|
3
5
|
const years = f(value.match(/([0-9])*Y/));
|
|
@@ -29,3 +31,171 @@ export const toDuration = (data) => {
|
|
|
29
31
|
}
|
|
30
32
|
return null;
|
|
31
33
|
};
|
|
34
|
+
|
|
35
|
+
export const getDate = (value) => {
|
|
36
|
+
try {
|
|
37
|
+
// xsd:time
|
|
38
|
+
if (value.includes(':') && !value.includes('T')) {
|
|
39
|
+
const datePart = new Date().toISOString().substr(0, 11);
|
|
40
|
+
const timeDate = new Date(`${datePart}${value}`);
|
|
41
|
+
timeDate.setMinutes(timeDate.getMinutes() + timeDate.getTimezoneOffset());
|
|
42
|
+
return timeDate;
|
|
43
|
+
}
|
|
44
|
+
// all other cases
|
|
45
|
+
return new Date(value);
|
|
46
|
+
} catch (e) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const getDatatype = (datatype) => {
|
|
52
|
+
switch (datatype) {
|
|
53
|
+
case 'http://www.w3.org/2001/XMLSchema#dateTime':
|
|
54
|
+
case 'http://purl.org/dc/terms/W3CDTF':
|
|
55
|
+
return 'DateTime';
|
|
56
|
+
case 'http://www.w3.org/2001/XMLSchema#date':
|
|
57
|
+
return 'Date';
|
|
58
|
+
case 'http://www.w3.org/2001/XMLSchema#gYear':
|
|
59
|
+
return 'Year';
|
|
60
|
+
case 'http://www.w3.org/2001/XMLSchema#time':
|
|
61
|
+
return 'Time';
|
|
62
|
+
case 'http://www.w3.org/2001/XMLSchema#gYearMonth':
|
|
63
|
+
return 'YearMonth';
|
|
64
|
+
case 'http://www.w3.org/2001/XMLSchema#gMonthDay':
|
|
65
|
+
return 'MonthDay';
|
|
66
|
+
default:
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const getDatatypeFromItem = (item) => {
|
|
72
|
+
const dt = item.getDatatype();
|
|
73
|
+
if (Array.isArray(dt)) {
|
|
74
|
+
return getDatatype(dt[0]);
|
|
75
|
+
}
|
|
76
|
+
return getDatatype(dt);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const getDatatypeFromValue = (data) => {
|
|
80
|
+
if (data.indexOf('T') > 0) {
|
|
81
|
+
return 'DateTime';
|
|
82
|
+
} else if (data.indexOf(':') > 0) {
|
|
83
|
+
return 'Time';
|
|
84
|
+
} else if (/^\d\d\d\d-\d\d$/.test(data)) {
|
|
85
|
+
return 'YearMonth';
|
|
86
|
+
} else if (/^\d\d-\d\d$/.test(data)) {
|
|
87
|
+
return 'MonthDay';
|
|
88
|
+
} else if (data.length > 4) {
|
|
89
|
+
return 'Date';
|
|
90
|
+
}
|
|
91
|
+
return 'Year';
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export const getDatatypeURI = (datatype) => {
|
|
95
|
+
switch (datatype) {
|
|
96
|
+
case 'DateTime':
|
|
97
|
+
return 'http://www.w3.org/2001/XMLSchema#dateTime';
|
|
98
|
+
case 'Date':
|
|
99
|
+
return 'http://www.w3.org/2001/XMLSchema#date';
|
|
100
|
+
case 'Time':
|
|
101
|
+
return 'http://www.w3.org/2001/XMLSchema#time';
|
|
102
|
+
case 'Year':
|
|
103
|
+
return 'http://www.w3.org/2001/XMLSchema#gYear';
|
|
104
|
+
case 'YearMonth':
|
|
105
|
+
return 'http://www.w3.org/2001/XMLSchema#gYearMonth';
|
|
106
|
+
case 'MonthDay':
|
|
107
|
+
return 'http://www.w3.org/2001/XMLSchema#gMonthDay';
|
|
108
|
+
default:
|
|
109
|
+
return '';
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export const getDateValue = (value, datatype) => {
|
|
114
|
+
if (value) {
|
|
115
|
+
switch (datatype) {
|
|
116
|
+
case 'DateTime':
|
|
117
|
+
return value.toISOString();
|
|
118
|
+
case 'Date':
|
|
119
|
+
// Since we cut of the timezone section at the end we need to compensate for it
|
|
120
|
+
value.setMinutes(value.getMinutes() - value.getTimezoneOffset());
|
|
121
|
+
return value.toISOString().substr(0, 10);
|
|
122
|
+
case 'YearMonth':
|
|
123
|
+
// Since we cut of the timezone section at the end we need to compensate for it
|
|
124
|
+
value.setMinutes(value.getMinutes() - value.getTimezoneOffset());
|
|
125
|
+
return value.toISOString().substr(0, 7);
|
|
126
|
+
case 'MonthDay':
|
|
127
|
+
// Since we cut of the timezone section at the end we need to compensate for it
|
|
128
|
+
value.setMinutes(value.getMinutes() - value.getTimezoneOffset());
|
|
129
|
+
return value.toISOString().substr(5, 5);
|
|
130
|
+
case 'Time':
|
|
131
|
+
value.setMinutes(value.getMinutes() - value.getTimezoneOffset());
|
|
132
|
+
return value.toISOString().substr(11);
|
|
133
|
+
case 'Year':
|
|
134
|
+
// Since we cut of the timezone section at the end we need to compensate for it
|
|
135
|
+
value.setMinutes(value.getMinutes() - value.getTimezoneOffset());
|
|
136
|
+
return value.toISOString().substr(0, 4);
|
|
137
|
+
default:
|
|
138
|
+
return '';
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return '';
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export const getDatePresentationFromDatatype = (datatype, date) => {
|
|
145
|
+
switch (datatype) {
|
|
146
|
+
case 'DateTime':
|
|
147
|
+
return moment(date).format('lll');
|
|
148
|
+
case 'Date':
|
|
149
|
+
return moment(date).format('LL');
|
|
150
|
+
case 'Time':
|
|
151
|
+
return moment(date).format('LT');
|
|
152
|
+
case 'Year':
|
|
153
|
+
return moment(date).format('YYYY');
|
|
154
|
+
case 'YearMonth':
|
|
155
|
+
return moment(date).format('MMMM YYYY');
|
|
156
|
+
case 'MonthDay':
|
|
157
|
+
return moment(date).format('D MMMM');
|
|
158
|
+
default:
|
|
159
|
+
return '';
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
export const getAllowedDateAlternatives = (item) => {
|
|
164
|
+
const dateAllowedDataAlternatives = {};
|
|
165
|
+
const dt = item.getDatatype();
|
|
166
|
+
const alts = Array.isArray(dt) ? dt : [dt];
|
|
167
|
+
alts.forEach((datatype) => {
|
|
168
|
+
const alt = getDatatype(datatype);
|
|
169
|
+
if (alt) {
|
|
170
|
+
dateAllowedDataAlternatives[alt] = true;
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
return dateAllowedDataAlternatives;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
export const getDatePresentation = (binding) => {
|
|
177
|
+
const data = binding.getValue();
|
|
178
|
+
if (data != null && data !== '') {
|
|
179
|
+
const item = binding.getItem();
|
|
180
|
+
const date = getDate(data);
|
|
181
|
+
if (date) {
|
|
182
|
+
const valueDatatype = getDatatypeFromValue(data);
|
|
183
|
+
const datatypeDatatype = getDatatype(binding.getDatatype());
|
|
184
|
+
const itemSuggestedDatatype = getDatatypeFromItem(item);
|
|
185
|
+
const allowed = getAllowedDateAlternatives(item);
|
|
186
|
+
let datatype;
|
|
187
|
+
if (allowed[datatypeDatatype]) {
|
|
188
|
+
// This is always the case unless "relaxedDatatypeMatch" is specified
|
|
189
|
+
datatype = datatypeDatatype;
|
|
190
|
+
} else if (allowed[valueDatatype]) {
|
|
191
|
+
// If the detected datatype from the value is supported
|
|
192
|
+
datatype = valueDatatype;
|
|
193
|
+
} else {
|
|
194
|
+
// Rely on the datatype from the item if everything else fails
|
|
195
|
+
datatype = itemSuggestedDatatype;
|
|
196
|
+
}
|
|
197
|
+
return getDatePresentationFromDatatype(datatype, date);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return undefined;
|
|
201
|
+
};
|
|
@@ -14,9 +14,13 @@ renderingContext.addExpandButton = (rowDiv, labelDiv, item, context) => {
|
|
|
14
14
|
|
|
15
15
|
const isClearButton = (binding, context) => {
|
|
16
16
|
const item = binding.getItem();
|
|
17
|
+
const notDeprecated = !item.hasStyle('deprecated');
|
|
18
|
+
if (context.view.isMultiValued(item) && notDeprecated) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
17
21
|
const cardTr = binding.getCardinalityTracker();
|
|
18
22
|
const showOne = context.view.showNow(binding.getItem(), []);
|
|
19
|
-
return
|
|
23
|
+
return notDeprecated &&
|
|
20
24
|
(cardTr.isMin() || (cardTr.getCardinality() === 1 && showOne && cardTr.isDepsOk()));
|
|
21
25
|
};
|
|
22
26
|
renderingContext.addRemoveButton = (rowDiv, binding, context) => () => {
|
|
@@ -61,6 +65,13 @@ renderingContext.addRemoveButton = (rowDiv, binding, context) => () => {
|
|
|
61
65
|
binding.setLanguage('');
|
|
62
66
|
}
|
|
63
67
|
}
|
|
68
|
+
} else if (context.view.isMultiValued(item)) {
|
|
69
|
+
// This case corresponds to multivalued and deprecated.
|
|
70
|
+
// Slice so we have a copy of the array... since it will change behind the scenes otherwise
|
|
71
|
+
binding.getParent().getChildBindingsFor(item).slice(0).forEach((b) => {
|
|
72
|
+
b.remove();
|
|
73
|
+
});
|
|
74
|
+
rowDiv.parent.destroy();
|
|
64
75
|
} else {
|
|
65
76
|
binding.remove();
|
|
66
77
|
rowDiv.destroy();
|
|
@@ -77,8 +88,8 @@ renderingContext.addRemoveButton = (rowDiv, binding, context) => () => {
|
|
|
77
88
|
};
|
|
78
89
|
|
|
79
90
|
renderingContext.addCreateChildButton = (rowDiv, labelDiv, binding, context) => () => {
|
|
80
|
-
const cardTr = binding.getCardinalityTracker();
|
|
81
91
|
const item = binding.getItem();
|
|
92
|
+
const cardTr = binding.getCardinalityTracker();
|
|
82
93
|
const [disabled, setDisabled] = useState(cardTr.isMax() || !cardTr.isDepsOk() || item.hasStyle('deprecated'));
|
|
83
94
|
useEffect(() => {
|
|
84
95
|
context.rememberParent = binding.getParent(); // If the current binding is removed and the label is not redrawn
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/* eslint-disable no-unused-vars */
|
|
2
|
+
import React, { useState, useEffect, useMemo } from 'react';
|
|
3
|
+
import FormControlLabel from '@mui/material/FormControlLabel';
|
|
4
|
+
import Checkbox from '@mui/material/Checkbox';
|
|
5
|
+
import { FormGroup } from '@mui/material';
|
|
6
|
+
import { useLocalizedSortedChoices, useName } from '../hooks';
|
|
7
|
+
import * as engine from '../../../model/engine';
|
|
8
|
+
|
|
9
|
+
const CheckOption = (props) => {
|
|
10
|
+
const { choice, binding, onChoiceChange } = props;
|
|
11
|
+
const [checked, setChecked] = React.useState(choice.value === binding.getValue());
|
|
12
|
+
|
|
13
|
+
const handleChange = (evt) => {
|
|
14
|
+
binding.setChoice(evt.target.checked ? choice.original : null);
|
|
15
|
+
setChecked(evt.target.checked);
|
|
16
|
+
onChoiceChange();
|
|
17
|
+
};
|
|
18
|
+
return <FormControlLabel
|
|
19
|
+
label={choice.label} control={<Checkbox checked={checked} onChange={handleChange}/>}
|
|
20
|
+
{...(choice.mismatch ? { className: 'mismatch' } : {})}
|
|
21
|
+
title={choice.description || choice.seeAlso || choice.value}/>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default function CheckBoxesEditor(props) {
|
|
25
|
+
const [resetCount, setResetCount] = React.useState(0);
|
|
26
|
+
const binding = props.binding;
|
|
27
|
+
const item = binding.getItem();
|
|
28
|
+
const choices = useLocalizedSortedChoices(binding);
|
|
29
|
+
const choiceBindingPairs = useMemo(() => {
|
|
30
|
+
const parentBinding = binding.getParent();
|
|
31
|
+
const val2binding = {};
|
|
32
|
+
// eslint-disable-next-line no-return-assign
|
|
33
|
+
parentBinding.getChildBindingsFor(item).forEach(b => (val2binding[b.getValue()] = b));
|
|
34
|
+
const pairs = choices.map((c) => {
|
|
35
|
+
const existingbinding = val2binding[c.value];
|
|
36
|
+
if (existingbinding) {
|
|
37
|
+
delete val2binding[c.value];
|
|
38
|
+
return [c, existingbinding];
|
|
39
|
+
}
|
|
40
|
+
return [c, engine.create(parentBinding, item)];
|
|
41
|
+
});
|
|
42
|
+
// Add checks for values that are non-conforming (should have mismatch on their choices).
|
|
43
|
+
Object.values(val2binding).forEach((b) => {
|
|
44
|
+
const choice = b.getChoice();
|
|
45
|
+
if (choice) {
|
|
46
|
+
pairs.push([choice, b]);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
return pairs;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const [error, setError] = useState(binding.getChoice()?.mismatch === true);
|
|
53
|
+
const row = item.hasStyle('verticalCheckboxes') ? {} : { row: true };
|
|
54
|
+
|
|
55
|
+
const onChoiceChange = () => {
|
|
56
|
+
const newError = choiceBindingPairs.find(pair => pair[1].getChoice()
|
|
57
|
+
&& pair[1].getChoice().mismatch) !== undefined;
|
|
58
|
+
if (newError !== error) {
|
|
59
|
+
setError(newError);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
props.field.toggleClass('mismatchReport', error);
|
|
65
|
+
}, [error]);
|
|
66
|
+
|
|
67
|
+
props.context.clear = () => {
|
|
68
|
+
choiceBindingPairs.forEach(pair => pair[1].setChoice(null));
|
|
69
|
+
setError(false);
|
|
70
|
+
setResetCount(resetCount + 1);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<><FormGroup {...row}>
|
|
75
|
+
{choiceBindingPairs.map(pair => (
|
|
76
|
+
<CheckOption key={`${resetCount}-${pair[1].getHash()}`}
|
|
77
|
+
choice={pair[0]}
|
|
78
|
+
binding={pair[1]}
|
|
79
|
+
onChoiceChange={onChoiceChange} />
|
|
80
|
+
))}
|
|
81
|
+
</FormGroup>{error && (
|
|
82
|
+
<div key="warning" className="rdformsWarning">
|
|
83
|
+
{props.context.view.messages.wrongValueField}
|
|
84
|
+
</div>
|
|
85
|
+
)}</>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import renderingContext from '../../renderingContext';
|
|
4
4
|
import RadioButtonsEditor from './RadioButtonsEditor';
|
|
5
|
+
import CheckBoxesEditor from './CheckBoxesEditor';
|
|
5
6
|
import ChoiceSelector from './ChoiceSelector';
|
|
6
7
|
import ChoiceLookup from './ChoiceLookup';
|
|
7
8
|
import ChoiceLookupAndInlineSearch from './ChoiceLookupAndInlineSearch';
|
|
@@ -27,6 +28,14 @@ editors.itemtype('choice').choices().check(radioCheck).register((fieldDiv, bindi
|
|
|
27
28
|
field={fieldDiv}/>);
|
|
28
29
|
});
|
|
29
30
|
|
|
31
|
+
const checkBoxComponent = (fieldDiv, binding, context) => {
|
|
32
|
+
// eslint-disable-next-line no-new
|
|
33
|
+
fieldDiv.appendChild(<CheckBoxesEditor key={binding.getHash()} binding={binding} context={context}
|
|
34
|
+
field={fieldDiv}/>);
|
|
35
|
+
};
|
|
36
|
+
editors.itemtype('choice').choices().style('verticalCheckBoxes').register(checkBoxComponent);
|
|
37
|
+
editors.itemtype('choice').choices().style('horizontalCheckBoxes').register(checkBoxComponent);
|
|
38
|
+
|
|
30
39
|
editors.itemtype('choice').choices().register((fieldDiv, binding, context) => {
|
|
31
40
|
fieldDiv.appendChild(<ChoiceSelector key={binding.getHash()} binding={binding} context={context} field={fieldDiv}/>);
|
|
32
41
|
});
|
|
@@ -95,11 +95,11 @@ const newStruct = (Tag, parent) => {
|
|
|
95
95
|
// -- START: Initial methods used before react kicks in.
|
|
96
96
|
toggleClass: (clsStr, addOrNot) => toggleClass(firstClsSet, clsStr, addOrNot),
|
|
97
97
|
domQuery: selector => (selectorInClasses(selector, firstClsSet) ? ext : findStruct(selector, firstChildArr)),
|
|
98
|
-
appendChild: struct => {
|
|
98
|
+
appendChild: (struct) => {
|
|
99
99
|
firstChildArr.push(struct);
|
|
100
100
|
},
|
|
101
101
|
appendAfter: (struct, sibling) => {
|
|
102
|
-
firstChildArr.splice(firstChildArr.indexOf(sibling) + 1, 0, struct)
|
|
102
|
+
firstChildArr.splice(firstChildArr.indexOf(sibling) + 1, 0, struct);
|
|
103
103
|
},
|
|
104
104
|
text: (str) => {
|
|
105
105
|
firstTextStr = str;
|
|
@@ -248,3 +248,5 @@ renderingContext.renderValidationMessage = (fieldDiv, type, message) => {
|
|
|
248
248
|
fieldDiv.appendChild(<div className="rdformsValidationMessageWrapper" key={ `rdforms_valcount_${validationCounter}`}
|
|
249
249
|
><ValidationIcon/><span className="rdformsValidationMessage">{message}</span></div>);
|
|
250
250
|
};
|
|
251
|
+
|
|
252
|
+
renderingContext.multiValueSupport = true;
|