@entryscape/rdforms 10.5.2 → 10.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/rdforms.bmd.js +5 -5
  2. package/dist/rdforms.bootstrap.js +9 -9
  3. package/dist/rdforms.jquery.js +3 -3
  4. package/dist/rdforms.node.js +3 -3
  5. package/dist/rdforms.react.js +27 -27
  6. package/index.bmd.js +5 -4
  7. package/package.json +2 -1
  8. package/src/model/CODES.js +17 -0
  9. package/src/model/CardinalityTracker.js +2 -1
  10. package/src/model/ChoiceBinding.js +7 -1
  11. package/src/model/engine.js +1 -19
  12. package/src/model/validate.js +21 -20
  13. package/src/template/Item.js +46 -51
  14. package/src/view/Editor.js +8 -3
  15. package/src/view/Presenter.js +2 -1
  16. package/src/view/ValidationPresenter.js +2 -1
  17. package/src/view/View.js +6 -3
  18. package/src/view/bootstrap/RadioButtonsEditor.js +4 -4
  19. package/src/view/bootstrap/choice.js +1 -1
  20. package/src/view/bootstrap/labels.js +12 -17
  21. package/src/view/bootstrap/style.css +11 -0
  22. package/src/view/bootstrap/table.js +5 -1
  23. package/src/view/bootstrap/text.js +29 -11
  24. package/src/view/jquery/components.js +12 -4
  25. package/src/view/jquery/labels.js +5 -1
  26. package/src/view/react/buttons.js +1 -1
  27. package/src/view/react/choice.js +16 -7
  28. package/src/view/react/choiceEditors/CheckBoxesEditor.js +1 -1
  29. package/src/view/react/choiceEditors/ChoiceLookup.js +2 -1
  30. package/src/view/react/choiceEditors/ChoiceLookupAndInlineSearch.js +6 -5
  31. package/src/view/react/choiceEditors/ChoiceSelector.js +2 -1
  32. package/src/view/react/choiceEditors/RadioButtonsEditor.js +2 -2
  33. package/src/view/react/components.js +6 -6
  34. package/src/view/react/date.js +0 -16
  35. package/src/view/react/hooks.js +17 -9
  36. package/src/view/react/labels.js +13 -8
  37. package/src/view/react/textEditors.js +5 -0
  38. package/src/view/renderingContext.js +2 -2
  39. package/src/view/resources/rdforms.css +1 -2
@@ -32,18 +32,21 @@ editors.itemtype('text').datatype('xsd:duration').register(durationEditor);
32
32
  tb.set('value', '');
33
33
  }; */
34
34
 
35
- const addChangeListener = (inp, binding, regex, extLink) => {
35
+ const addChangeListener = (inp, binding, regex, extLink, help) => {
36
36
  let to = null;
37
37
  const s = () => {
38
38
  to = null;
39
- const val = inp.val();
39
+ const val = inp.val().trim();
40
40
  let disableExtLink = true;
41
- if (!regex || regex.test(val)) {
41
+ if (val === '' || !regex || regex.test(val)) {
42
42
  binding.setGist(val);
43
43
  if (extLink && val) {
44
44
  extLink.prop('href', binding.getValue());
45
45
  disableExtLink = false;
46
46
  }
47
+ help.toggleClass('rdformsHelpActive', false);
48
+ } else {
49
+ help.toggleClass('rdformsHelpActive', true);
47
50
  }
48
51
  if (extLink) {
49
52
  extLink.toggleClass('rdformsExtLinkDisabled', disableExtLink);
@@ -63,19 +66,27 @@ const registerPattern = (pattern, datatype) => {
63
66
  const regex = new RegExp(pattern);
64
67
  editors.itemtype('text').datatype(datatype)
65
68
  .register((fieldDiv, binding, context) => {
66
- const $input = jquery('<input type="text" class="form-control rdformsFieldInput">');
69
+ const $input = jquery(`<input type="text" class="form-control rdformsFieldInput"
70
+ placeholder="${binding.getItem().getPlaceholder() || ''}">`);
67
71
  $input.val(binding.getGist())
68
72
  .attr('pattern', pattern)
69
73
  .appendTo(fieldDiv);
70
74
 
75
+ const help = binding.getItem().getHelp();
76
+ let $help;
77
+ if (help) {
78
+ $help = jquery(`<span class="rdformsHelp">${help}</span>`);
79
+ $help.appendTo(fieldDiv);
80
+ }
81
+
71
82
  if (binding.getItem().hasStyle('externalLink')) {
72
83
  const $extLink = jquery(`<a class="fas fa-external-link-alt rdformsExtLink ${renderingContext.getExtLinkClass()}" target="_blank">`);
73
84
  $extLink.appendTo(context.controlDiv);
74
85
  jquery(fieldDiv).addClass('rdformsExtLinkControl');
75
- addChangeListener($input, binding, regex, $extLink);
86
+ addChangeListener($input, binding, regex, $extLink, $help);
76
87
  $input.keyup();
77
88
  } else {
78
- addChangeListener($input, binding, regex);
89
+ addChangeListener($input, binding, regex, undefined, $help);
79
90
  }
80
91
 
81
92
 
@@ -98,7 +109,7 @@ editors.itemtype('text').register((fieldDiv, binding, context) => {
98
109
  let $input;
99
110
  if (item.hasStyle('multiline')) {
100
111
  const originalNrOfLines = countLines(binding.getGist());
101
- $input = jquery(`<textarea class="form-control rdformsFieldInput autoExpand" rows="${originalNrOfLines}">`);
112
+ $input = jquery(`<textarea class="form-control rdformsFieldInput autoExpand" placeholder="${item.getPlaceholder() || ''}" rows="${originalNrOfLines}">`);
102
113
  $input.on('input focus', function () {
103
114
  if (this.baseScrollHeight === undefined) {
104
115
  const originalHeight = $input.height();
@@ -110,13 +121,20 @@ editors.itemtype('text').register((fieldDiv, binding, context) => {
110
121
  this.rows = rows;
111
122
  });
112
123
  } else if (item.hasStyle('email')) {
113
- $input = jquery('<input type="email" class="form-control rdformsFieldInput">');
124
+ $input = jquery(`<input type="email" class="form-control rdformsFieldInput" placeholder="${item.getPlaceholder() || ''}">`);
114
125
  } else {
115
- $input = jquery('<input type="text" class="form-control rdformsFieldInput">');
126
+ $input = jquery(`<input type="text" class="form-control rdformsFieldInput" placeholder="${item.getPlaceholder() || ''}">`);
116
127
  }
117
128
  $input.val(binding.getGist())
118
129
  .appendTo(fieldDiv);
119
130
 
131
+ const help = item.getHelp();
132
+ let $help;
133
+ if (help) {
134
+ $help = jquery(`<span class="rdformsHelp">${help}</span>`);
135
+ $help.appendTo(fieldDiv);
136
+ }
137
+
120
138
  const pattern = item.getPattern();
121
139
  let regex = null;
122
140
  if (pattern != null) {
@@ -127,10 +145,10 @@ editors.itemtype('text').register((fieldDiv, binding, context) => {
127
145
  const $extLink = jquery(`<a class="fas fa-external-link-alt rdformsExtLink ${renderingContext.getExtLinkClass()}" target="_blank">`);
128
146
  $extLink.appendTo(context.controlDiv);
129
147
  jquery(fieldDiv).addClass('rdformsExtLinkControl');
130
- addChangeListener($input, binding, regex, $extLink);
148
+ addChangeListener($input, binding, regex, $extLink, $help);
131
149
  $input.keyup();
132
150
  } else {
133
- addChangeListener($input, binding, regex);
151
+ addChangeListener($input, binding, regex, undefined, $help);
134
152
  }
135
153
 
136
154
  // If language control should be present
@@ -4,12 +4,20 @@ import './text';
4
4
  import './choice';
5
5
  import './table';
6
6
 
7
+ const createElement = (nodeStr, id) => {
8
+ const el = document.createElement(nodeStr);
9
+ if (id) {
10
+ el.id = id;
11
+ }
12
+ return el;
13
+ };
14
+
7
15
  renderingContext.domQuery = (selector, node) => node.querySelector(selector);
8
16
 
9
- renderingContext.domCreate = (nodeStr, parent) => parent.appendChild(document.createElement(nodeStr));
17
+ renderingContext.domCreate = (nodeStr, parent, id) => parent.appendChild(createElement(nodeStr, id));
10
18
 
11
- renderingContext.domCreateAfter = (nodeStr, sibling) =>
12
- sibling.parentNode.insertBefore(document.createElement(nodeStr), sibling.nextSibling);
19
+ renderingContext.domCreateAfter = (nodeStr, sibling, id) =>
20
+ sibling.parentNode.insertBefore(createElement(nodeStr, id), sibling.nextSibling);
13
21
 
14
22
  renderingContext.domSetAttr = (node, attr, value) => {
15
23
  if (value === '' || value === null) {
@@ -33,4 +41,4 @@ renderingContext.domClassToggle = (node, classStr, addOrRemove) => {
33
41
  });
34
42
  };
35
43
 
36
- renderingContext.prePresenterViewRenderer = renderingContext.preEditorViewRenderer;
44
+ renderingContext.prePresenterViewRenderer = renderingContext.preEditorViewRenderer;
@@ -1,8 +1,9 @@
1
1
  import jquery from 'jquery';
2
2
  import renderingContext from '../renderingContext';
3
+ import Editor from '../Editor';
3
4
 
4
5
  renderingContext.renderPresenterLabel = (rowNode, binding, item, context, labelRow) => {
5
- let label = item.getLabel();
6
+ let label = context.view instanceof Editor ? item.getEditLabel() || item.getLabel() : item.getLabel();
6
7
  if (label != null && label !== '') {
7
8
  label = label.charAt(0).toUpperCase() + label.slice(1);
8
9
  } else {
@@ -10,6 +11,9 @@ renderingContext.renderPresenterLabel = (rowNode, binding, item, context, labelR
10
11
  }
11
12
 
12
13
  const $labelDiv = jquery('<div class="rdformsLabel" tabindex="0">').text(label).appendTo(rowNode);
14
+ if (binding) {
15
+ $labelDiv.attr('id', context.view.createLabelIndex(binding));
16
+ }
13
17
  if (labelRow) {
14
18
  $labelDiv.addClass('rdformsLabelRow');
15
19
  }
@@ -104,7 +104,7 @@ renderingContext.addCreateChildButton = (rowDiv, labelDiv, binding, context) =>
104
104
  context.view.addRow(rowDiv, nBinding); // not the first binding...
105
105
  }
106
106
  };
107
- let label = item.getLabel();
107
+ let label = item.getEditLabel() || item.getLabel();
108
108
  if (label != null && label !== '') {
109
109
  label = label.charAt(0).toUpperCase() + label.slice(1);
110
110
  } else {
@@ -3,20 +3,26 @@ import React, { useState, useEffect } from 'react';
3
3
  import renderingContext from '../renderingContext';
4
4
  import system from '../../model/system';
5
5
  import utils from '../../utils';
6
+ import { Editor } from './Wrappers';
6
7
 
7
8
  // -------------- Presenters ----------------
8
9
  const presenters = renderingContext.presenterRegistry;
9
10
 
10
- const choicify = func => (fieldDiv, binding) => {
11
+ const choicify = func => (fieldDiv, binding, context) => {
11
12
  const choice = binding.getChoice();
13
+ const isEditor = context.view instanceof Editor;
12
14
  let desc;
13
15
  if (!choice) {
14
16
  return;
15
17
  }
16
- if (choice.description) {
18
+
19
+ if (isEditor && choice.editdescription) {
20
+ desc = utils.getLocalizedValue(choice.editdescription).value;
21
+ } else if (choice.description) {
17
22
  desc = utils.getLocalizedValue(choice.description).value;
18
23
  }
19
- func(fieldDiv, binding, choice, desc);
24
+
25
+ func(fieldDiv, binding, choice, desc, isEditor);
20
26
  };
21
27
 
22
28
  // Presenter for image.
@@ -34,13 +40,16 @@ presenters.itemtype('choice').style('stars').register(choicify(
34
40
  }
35
41
  }));
36
42
 
43
+ const getLocalizedLabel = (choice, isEditor) =>
44
+ utils.getLocalizedValue(isEditor ? choice.editlabel || choice.label : choice.label);
45
+
37
46
  // Presenter for choices.
38
47
  presenters.itemtype('choice').register(choicify(
39
- (fieldDiv, binding, choice, desc) => {
48
+ (fieldDiv, binding, choice, desc, isEditor) => {
40
49
  const item = binding.getItem();
41
50
  const title = desc || choice.seeAlso || choice.value;
42
51
  if ((item.hasStaticChoices() && !item.hasStyle('externalLink')) || item.hasStyle('noLink')) {
43
- const locValue = utils.getLocalizedValue(choice.label);
52
+ const locValue = getLocalizedLabel(choice, isEditor);
44
53
  const langAttr = locValue.lang ? { lang: locValue.lang } : {};
45
54
  fieldDiv.appendChild(<div key={binding.getHash()} {...langAttr} title={title} src={choice.value
46
55
  }>{locValue.value}</div>);
@@ -55,11 +64,11 @@ presenters.itemtype('choice').register(choicify(
55
64
  delete attrs.component;
56
65
 
57
66
  fieldDiv.appendChild(React.createElement(() => {
58
- const [locValue, setLocValue] = useState(utils.getLocalizedValue(choice.label));
67
+ const [locValue, setLocValue] = useState(getLocalizedLabel(choice, isEditor));
59
68
  useEffect(() => {
60
69
  if (choice.load != null) {
61
70
  choice.load(() => {
62
- setLocValue(utils.getLocalizedValue(choice.label));
71
+ setLocValue(getLocalizedLabel(choice, isEditor));
63
72
  });
64
73
  }
65
74
  }, []);
@@ -25,7 +25,7 @@ export default function CheckBoxesEditor(props) {
25
25
  const [resetCount, setResetCount] = React.useState(0);
26
26
  const binding = props.binding;
27
27
  const item = binding.getItem();
28
- const choices = useLocalizedSortedChoices(binding);
28
+ const choices = useLocalizedSortedChoices(binding, true);
29
29
  const choiceBindingPairs = useMemo(() => {
30
30
  const parentBinding = binding.getParent();
31
31
  const val2binding = {};
@@ -8,7 +8,7 @@ import ShowButton from './ShowButton';
8
8
 
9
9
  export default (props) => {
10
10
  const binding = props.binding;
11
- const [choice, setChoice] = loadLocalizedChoice(binding);
11
+ const [choice, setChoice] = loadLocalizedChoice(binding, true);
12
12
  const [error, setError] = useState(binding.getChoice()?.mismatch === true);
13
13
 
14
14
  useEffect(() => {
@@ -44,6 +44,7 @@ export default (props) => {
44
44
  disabled {...(choice && choice.mismatch ? { mismatch: true } : {})}
45
45
  title={title}
46
46
  value={label}
47
+ placeholder={binding.getItem().getPlaceholder()}
47
48
  error={error}
48
49
  variant={renderingContext.materialVariant}
49
50
  /><ShowButton
@@ -5,7 +5,7 @@ import Autocomplete from '@mui/material/Autocomplete';
5
5
  import BuildIcon from '@mui/icons-material/Build';
6
6
  import IconButton from '@mui/material/IconButton';
7
7
  import renderingContext from '../../renderingContext';
8
- import { loadLocalizedChoice, localizedChoice } from '../hooks';
8
+ import { editLocalizedChoice, loadLocalizedChoice } from '../hooks';
9
9
  import ShowButton from './ShowButton';
10
10
 
11
11
  let globalChoiceQueryThrottle;
@@ -13,7 +13,7 @@ let globalChoiceQueryThrottle;
13
13
  export default (props) => {
14
14
  const binding = props.binding;
15
15
  const [options, setOptions] = useState([]);
16
- const [value, setValue] = loadLocalizedChoice(binding, options);
16
+ const [value, setValue] = loadLocalizedChoice(binding, true);
17
17
  const [inputValue, setInputValue] = useState('');
18
18
  const [open, setOpen] = useState(false);
19
19
  const [error, setError] = useState(binding.getChoice()?.mismatch === true);
@@ -51,7 +51,7 @@ export default (props) => {
51
51
  globalChoiceQueryThrottle = undefined;
52
52
  props.context.chooser.search(binding.getItem(), inputValue.trimStart()).then((results) => {
53
53
  if (active) {
54
- setOptions(results.map(localizedChoice));
54
+ setOptions(results.map(editLocalizedChoice));
55
55
  }
56
56
  });
57
57
  }, 200);
@@ -71,6 +71,7 @@ export default (props) => {
71
71
  aria-labelledby={labelledBy}
72
72
  {...params}
73
73
  {...(value && value.mismatch ? { error: true } : {})}
74
+ placeholder={binding.getItem().getPlaceholder()}
74
75
  onKeyDown={({ key, keyCode }) => {
75
76
  const isEnterKey = key === 'Enter' || keyCode === 13;
76
77
  if (isEnterKey && !open) {
@@ -84,14 +85,14 @@ export default (props) => {
84
85
  const showHandler = () => {
85
86
  renderingContext.openChoiceSelector(props.binding, (selectedChoice) => {
86
87
  binding.setChoice(selectedChoice);
87
- setValue(localizedChoice(selectedChoice));
88
+ setValue(editLocalizedChoice(selectedChoice));
88
89
  setError(selectedChoice.mismatch === true);
89
90
  }, props.field);
90
91
  };
91
92
 
92
93
  const upgradeHandler = () => {
93
94
  value.original.upgrade(props.binding, (upgradedChoice) => {
94
- setValue(localizedChoice(upgradedChoice));
95
+ setValue(editLocalizedChoice(upgradedChoice));
95
96
  setError(upgradedChoice.mismatch === true);
96
97
  });
97
98
  };
@@ -15,7 +15,7 @@ import { useLocalizedSortedChoices, useLocalizedChoice } from '../hooks';
15
15
  */
16
16
  export default (props) => {
17
17
  const binding = props.binding;
18
- const choices = useLocalizedSortedChoices(binding);
18
+ const choices = useLocalizedSortedChoices(binding, true);
19
19
  const [value, setValue] = useLocalizedChoice(binding, choices);
20
20
  const [error, setError] = useState(binding.getChoice()?.mismatch === true);
21
21
 
@@ -37,6 +37,7 @@ export default (props) => {
37
37
  params.inputProps['aria-labelledby'] = labelledBy;
38
38
  return (
39
39
  <TextField
40
+ placeholder={binding.getItem().getPlaceholder()}
40
41
  {...params}
41
42
  {...(value && value.mismatch ? { error: true } : {})}
42
43
  variant={renderingContext.materialVariant}
@@ -15,7 +15,7 @@ export default function RadioButtonsEditor(props) {
15
15
  const binding = props.binding;
16
16
  const item = binding.getItem();
17
17
  const name = useName();
18
- const choices = useLocalizedSortedChoices(binding);
18
+ const choices = useLocalizedSortedChoices(binding, true);
19
19
  const [error, setError] = useState(binding.getChoice()?.mismatch === true);
20
20
  const [value, setValue] = useState(() => {
21
21
  const choice = binding.getChoice();
@@ -52,7 +52,7 @@ export default function RadioButtonsEditor(props) {
52
52
  <RadioGroup
53
53
  {...row}
54
54
  key="radio"
55
- aria-label={item.getLabel()}
55
+ aria-label={item.getEditLabel() || item.getLabel()}
56
56
  name={name}
57
57
  value={value}
58
58
  onChange={handleChange}
@@ -83,7 +83,7 @@ let structId = 0;
83
83
  * Note that all update of state variables are done by replacing the value (even for arrays and sets) to allow
84
84
  * correct diffing of react.
85
85
  */
86
- const newStruct = (Tag, parent) => {
86
+ const newStruct = (Tag, parent, nodeId) => {
87
87
  const firstClsSet = new Set();
88
88
  let firstChildArr = [];
89
89
  let firstTextStr;
@@ -153,7 +153,7 @@ const newStruct = (Tag, parent) => {
153
153
  };
154
154
  // -- END
155
155
  return (
156
- <Tag className={clsSet.join(' ')}>
156
+ <Tag id={nodeId} className={clsSet.join(' ')}>
157
157
  {childArr.map((child, index) => getReactComponent(child, index))}
158
158
  {text}
159
159
  </Tag>
@@ -166,15 +166,15 @@ const newStruct = (Tag, parent) => {
166
166
 
167
167
  renderingContext.domQuery = (selector, struct) => struct.domQuery(selector);
168
168
 
169
- renderingContext.domCreate = (nodeStr, parentStruct) => {
170
- const struct = newStruct(nodeStr, parentStruct);
169
+ renderingContext.domCreate = (nodeStr, parentStruct, nodeId) => {
170
+ const struct = newStruct(nodeStr, parentStruct, nodeId);
171
171
  parentStruct.appendChild(struct);
172
172
  return struct;
173
173
  };
174
174
 
175
- renderingContext.domCreateAfter = (nodeStr, siblingStruct) => {
175
+ renderingContext.domCreateAfter = (nodeStr, siblingStruct, nodeId) => {
176
176
  if (siblingStruct.parent) {
177
- const struct = newStruct(nodeStr, siblingStruct.parent);
177
+ const struct = newStruct(nodeStr, siblingStruct.parent, nodeId);
178
178
  siblingStruct.parent.appendAfter(struct, siblingStruct);
179
179
  return struct;
180
180
  }
@@ -140,14 +140,6 @@ const dateEditor = (fieldDiv, binding, context) => {
140
140
  onChange={onDateChange}
141
141
  autoOk={true}
142
142
  mask={datePickerConfig.mask[selectedDatatype]}
143
- PopperProps={{
144
- modifiers: [
145
- {
146
- name: 'flip',
147
- enabled: false,
148
- },
149
- ],
150
- }}
151
143
  />
152
144
  )}
153
145
  {(alternatives.DateTime || alternatives.Time) && (
@@ -162,14 +154,6 @@ const dateEditor = (fieldDiv, binding, context) => {
162
154
  onChange={onDateChange}
163
155
  ampm={false}
164
156
  autoOk={true}
165
- PopperProps={{
166
- modifiers: [
167
- {
168
- name: 'flip',
169
- enabled: false,
170
- },
171
- ],
172
- }}
173
157
  />
174
158
  )}
175
159
  {!onlyOneAlternative && (
@@ -3,18 +3,24 @@ import utils from '../../utils';
3
3
 
4
4
  /**
5
5
  * Wraps a choice in an object where the current label, and description is localized.
6
+ *
6
7
  * @param {Object} choice an original choice object with label and descriptions being maps with language strings
8
+ * @param {isEditor} true means we are in edit mode and editLabel or editDescription have preference if they exist.
7
9
  * @return {Object}
8
10
  */
9
- export const localizedChoice = choice => ({
11
+ export const localizedChoice = (choice, isEditor) => ({
10
12
  value: choice.value,
11
- label: utils.getLocalizedValue(choice.label).value,
12
- description: choice.description ? utils.getLocalizedValue(choice.description).value : undefined,
13
+ label: utils.getLocalizedValue(isEditor ? choice.editlabel || choice.label : choice.label).value,
14
+ description: choice.description || choice.editdescription ?
15
+ (utils.getLocalizedValue(isEditor ? choice.editdescription || choice.description : choice.description).value)
16
+ : undefined,
13
17
  seeAlso: choice.seeAlso,
14
18
  mismatch: choice.mismatch,
15
19
  original: choice,
16
20
  });
17
21
 
22
+ export const editLocalizedChoice = choice => localizedChoice(choice, true);
23
+
18
24
  /**
19
25
  * Use choices from a binding with localized labels and sorted.
20
26
  * A copy is returned with precalculated labels to allow sorting, use the original property on each choice
@@ -24,9 +30,9 @@ export const localizedChoice = choice => ({
24
30
  * @param {Binding} binding
25
31
  * @return {Array}
26
32
  */
27
- export const useLocalizedSortedChoices = binding => useMemo(() => {
33
+ export const useLocalizedSortedChoices = (binding, isEditor) => useMemo(() => {
28
34
  const item = binding.getItem();
29
- const choices = item.getChoices().map(localizedChoice);
35
+ const choices = item.getChoices().map(isEditor ? editLocalizedChoice : localizedChoice);
30
36
  if (!item.hasStyle('preserveOrderOfChoices')) {
31
37
  choices.sort((c1, c2) => (c1.label < c2.label ? -1 : 1));
32
38
  }
@@ -56,18 +62,20 @@ export const useLocalizedChoice = (binding, choices) => useState(() => {
56
62
  * Returns a localized choice, may trigger a load step to get a more fleshed out version of the choice,
57
63
  * i.e. with label, description and seeAlso.
58
64
  * @param {Binding} binding
65
+ * @param {boolean} isEditor if true any editlabel or editdescription takes precedence
59
66
  */
60
- export const loadLocalizedChoice = (binding) => {
67
+ export const loadLocalizedChoice = (binding, isEditor) => {
68
+ const localize = isEditor ? editLocalizedChoice : localizedChoice;
61
69
  const [choice, setChoice] = useState(() => {
62
70
  const originalChoice = binding.getChoice() || null;
63
- return originalChoice ? localizedChoice(originalChoice) : null;
71
+ return originalChoice ? localize(originalChoice) : null;
64
72
  });
65
73
  useEffect(() => {
66
74
  if (choice && choice.original.load) {
67
75
  choice.original.load(() => {
68
- setChoice(localizedChoice(choice.original));
76
+ setChoice(localize(choice.original));
69
77
  }, () => {
70
- setChoice(localizedChoice(choice.original));
78
+ setChoice(localize(choice.original));
71
79
  });
72
80
  }
73
81
  }, []);
@@ -4,7 +4,8 @@ import Tooltip, { tooltipClasses } from '@mui/material/Tooltip';
4
4
  import { styled } from '@mui/material/styles';
5
5
  import ClickAwayListener from '@mui/material/ClickAwayListener';
6
6
  import renderingContext from '../renderingContext';
7
- import { CODES } from '../../model/engine';
7
+ import { Editor } from './Wrappers';
8
+ import CODES from '../../model/CODES';
8
9
 
9
10
  const StyledTooltip = styled(
10
11
  forwardRef(({ className, ...props }, ref) => (
@@ -37,7 +38,9 @@ const ItemTooltip = (props) => {
37
38
  if (property) {
38
39
  propinfo = <div className="rdformsProperty"><a target="_blank" href={property}>{property}</a></div>;
39
40
  }
40
- const description = props.item.getDescription() || (property ? '' : props.context.view.messages.info_missing || '');
41
+ const description = props.context.view instanceof Editor ?
42
+ props.item.getEditDescription() || props.item.getDescription() : props.item.getDescription()
43
+ || (property ? '' : props.context.view.messages.info_missing || '');
41
44
 
42
45
  return (
43
46
  <ClickAwayListener onClickAway={handleTooltipClose}>
@@ -64,24 +67,26 @@ const ItemTooltip = (props) => {
64
67
  };
65
68
 
66
69
  renderingContext.renderPresenterLabel = (rowNode, binding, item, context) => {
67
- let label = item.getLabel();
70
+ let label = context.view instanceof Editor ?
71
+ item.getEditLabel() || item.getLabel() : item.getLabel();
68
72
  if (label != null && label !== '') {
69
73
  label = label.charAt(0).toUpperCase() + label.slice(1);
70
74
  } else {
71
75
  label = '';
72
76
  }
77
+ const labelId = binding ? context.view.createLabelIndex(binding) : undefined;
73
78
  label = item.hasStyle('heading') ?
74
- <h2 tabIndex="0" className="rdformsLabelRow"><span className="rdformsLabel">{label}</span></h2> :
75
- <span tabIndex="0" className="rdformsLabelRow"><span className="rdformsLabel">{label}</span></span>;
76
- rowNode.appendChild(<ItemTooltip key={`${binding ? binding.getHash() : item._internalId}_label` } context={context} item={item
77
- }>{label}</ItemTooltip>);
79
+ <h2 tabIndex="0" id={labelId} className="rdformsLabelRow"><span className="rdformsLabel">{label}</span></h2> :
80
+ <span tabIndex="0" id={labelId} className="rdformsLabelRow"><span className="rdformsLabel">{label}</span></span>;
81
+ rowNode.appendChild(<ItemTooltip key={`${binding ? binding.getHash() : item._internalId}_label` }
82
+ context={context} item={item}>{label}</ItemTooltip>);
78
83
  };
79
84
 
80
85
  renderingContext.renderEditorLabel = (rowNode, binding, item, context) => {
81
86
  if (item.hasStyle('nonEditable') || item.hasStyle('heading')) {
82
87
  renderingContext.renderPresenterLabel(rowNode, binding, item, context, true);
83
88
  } else {
84
- let label = item.getLabel();
89
+ let label = item.getEditLabel() || item.getLabel();
85
90
  if (label != null && label !== '') {
86
91
  label = label.charAt(0).toUpperCase() + label.slice(1);
87
92
  } else {
@@ -93,7 +93,9 @@ editors.itemtype('text').register((fieldDiv, binding, context) => {
93
93
  return <><TextField
94
94
  className={extLink || langlit ? 'rdformsTwoThirds' : ''}
95
95
  multiline={multiline}
96
+ placeholder={item.getPlaceholder()}
96
97
  error={!valid}
98
+ helperText={!valid ? item.getHelp() || '' : ''}
97
99
  variant={renderingContext.materialVariant} inputProps={iprops}
98
100
  />{extLink && (value != null || value === '') &&
99
101
  (<IconButton aria-label={bundle.openLinkExternally} disabled={!valid} target='_blank' href={value}
@@ -107,6 +109,7 @@ editors.itemtype('text').register((fieldDiv, binding, context) => {
107
109
 
108
110
  const bindToPattern = pattern => (fieldDiv, binding, context) => {
109
111
  const regex = pattern ? new RegExp(pattern) : null;
112
+ const item = binding.getItem();
110
113
 
111
114
  const TextComp = () => {
112
115
  const [gist, setGist] = useState(binding.getGist());
@@ -131,6 +134,8 @@ const bindToPattern = pattern => (fieldDiv, binding, context) => {
131
134
  };
132
135
  return <TextField
133
136
  error={!valid}
137
+ placeholder={item.getPlaceholder()}
138
+ helperText={!valid ? item.getHelp() || '' : ''}
134
139
  variant={renderingContext.materialVariant} inputProps={iprops}
135
140
  />;
136
141
  };
@@ -58,9 +58,9 @@ const defaultLanguages = [
58
58
  const renderingContext = {
59
59
  domQuery(/* selector, node */) {
60
60
  },
61
- domCreate(/* domStr, node */) {
61
+ domCreate(/* domStr, node, id */) {
62
62
  },
63
- domCreateAfter(/* domStr, node */) {
63
+ domCreateAfter(/* domStr, node, id */) {
64
64
  },
65
65
  domClassToggle(/* node, classStr, addOrRemove */) {
66
66
  },
@@ -314,7 +314,7 @@ a.rdformsUrl:hover {
314
314
  padding-right: 55px;
315
315
  position: relative;
316
316
  }
317
-
317
+
318
318
  .rdformsEditor .rdformsField .rdformsChoiceLabel {
319
319
  margin-left: 0.2em;
320
320
  margin-right: 1em;
@@ -475,7 +475,6 @@ a.rdformsUrl:hover {
475
475
 
476
476
  .compact .rdformsRow.rdformsTopLevel {
477
477
  display: table;
478
- width: 98%;
479
478
  }
480
479
  .compact .rdformsRow.rdformsTopLevel>div {
481
480
  display: table-cell;