@entryscape/rdforms 10.6.2 → 10.7.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.
Files changed (43) hide show
  1. package/dist/rdforms.bmd.js +7 -5
  2. package/dist/rdforms.bootstrap.js +17 -15
  3. package/dist/rdforms.jquery.js +6 -4
  4. package/dist/rdforms.node.js +273 -3
  5. package/dist/rdforms.react.js +79 -77
  6. package/package.json +4 -3
  7. package/src/template/Item.js +2 -1
  8. package/src/view/Presenter.js +32 -3
  9. package/src/view/Registry.js +1 -1
  10. package/src/view/ValidationPresenter.js +2 -2
  11. package/src/view/View.js +52 -10
  12. package/src/view/bmd/DateTimeMD.js +12 -14
  13. package/src/view/bmd/Selectize.js +5 -4
  14. package/src/view/bmd/style.css +9 -1
  15. package/src/view/bootstrap/DateTimeBootstrapDatepicker.js +6 -4
  16. package/src/view/bootstrap/RadioButtonsEditor.js +5 -2
  17. package/src/view/bootstrap/Select2.js +8 -5
  18. package/src/view/bootstrap/buttons.js +9 -5
  19. package/src/view/bootstrap/choice.js +6 -4
  20. package/src/view/bootstrap/durationEditor.js +3 -2
  21. package/src/view/bootstrap/labels.js +26 -15
  22. package/src/view/bootstrap/style.css +9 -3
  23. package/src/view/bootstrap/text.js +7 -4
  24. package/src/view/jquery/labels.js +15 -0
  25. package/src/view/jquery/text.js +3 -3
  26. package/src/view/react/buttons.js +3 -0
  27. package/src/view/react/choiceEditors/CheckBoxesEditor.js +8 -3
  28. package/src/view/react/choiceEditors/ChoiceLookup.js +4 -2
  29. package/src/view/react/choiceEditors/ChoiceLookupAndInlineSearch.js +24 -15
  30. package/src/view/react/choiceEditors/ChoiceSelector.js +7 -4
  31. package/src/view/react/choiceEditors/RadioButtonsEditor.js +8 -4
  32. package/src/view/react/choiceEditors/ShowButton.js +1 -0
  33. package/src/view/react/date.js +7 -5
  34. package/src/view/react/duration.js +4 -2
  35. package/src/view/react/hooks.js +3 -0
  36. package/src/view/react/labels.js +40 -4
  37. package/src/view/react/style.css +6 -6
  38. package/src/view/react/text.js +2 -2
  39. package/src/view/react/textEditors.js +5 -0
  40. package/src/view/renderingContext.js +5 -0
  41. package/src/view/resources/rdforms.css +39 -17
  42. package/src/view/{jquery/util.js → viewUtils.js} +11 -0
  43. package/src/view/react/util.js +0 -31
@@ -108,13 +108,14 @@
108
108
  font-size: small;
109
109
  }
110
110
 
111
- .rdformsFieldControl>.fa.action {
111
+ .rdformsFieldControl>.fas.action {
112
112
  float: right;
113
113
  position: initial;
114
114
  margin-top: 8px;
115
115
  }
116
116
 
117
- .fa.action.disabled {
117
+ .fas.action:disabled,
118
+ .fas.action.disabled {
118
119
  cursor: default;
119
120
  }
120
121
 
@@ -185,7 +186,6 @@
185
186
  /* Autoexpand style */
186
187
  .rdforms .rdformsFields textarea.form-control {
187
188
  display: block;
188
- box-sizing: padding-box;
189
189
  overflow-x: hidden;
190
190
  overflow-y: auto;
191
191
  }
@@ -248,4 +248,10 @@
248
248
 
249
249
  .rdformsValidator .rdformsValidationMessageWrapper {
250
250
  margin-left: -22px;
251
+ }
252
+
253
+ .rdformsActionButton {
254
+ border: none;
255
+ background: transparent;
256
+ padding: 0;
251
257
  }
@@ -2,6 +2,8 @@ import moment from 'moment';
2
2
  import durationEditor from './durationEditor';
3
3
  import renderingContext from '../renderingContext';
4
4
  import utils from '../../utils';
5
+ import { getNamedGraphId } from '../viewUtils';
6
+
5
7
 
6
8
  /**
7
9
  * Try to guess the number of rows needed for a textarea element by looking at the value of the element
@@ -107,9 +109,10 @@ registerPattern('^(\\d+(\\.\\d+)?)$', 'xsd:decimal');
107
109
  editors.itemtype('text').register((fieldDiv, binding, context) => {
108
110
  const item = binding.getItem();
109
111
  let $input;
112
+ const disabledAttr = getNamedGraphId(binding, context) ? 'disabled' : '';
110
113
  if (item.hasStyle('multiline')) {
111
114
  const originalNrOfLines = countLines(binding.getGist());
112
- $input = jquery(`<textarea class="form-control rdformsFieldInput autoExpand" placeholder="${item.getPlaceholder() || ''}" rows="${originalNrOfLines}">`);
115
+ $input = jquery(`<textarea ${disabledAttr} class="form-control rdformsFieldInput autoExpand" placeholder="${item.getPlaceholder() || ''}" rows="${originalNrOfLines}">`);
113
116
  $input.on('input focus', function () {
114
117
  if (this.baseScrollHeight === undefined) {
115
118
  const originalHeight = $input.height();
@@ -121,9 +124,9 @@ editors.itemtype('text').register((fieldDiv, binding, context) => {
121
124
  this.rows = rows;
122
125
  });
123
126
  } else if (item.hasStyle('email')) {
124
- $input = jquery(`<input type="email" class="form-control rdformsFieldInput" placeholder="${item.getPlaceholder() || ''}">`);
127
+ $input = jquery(`<input ${disabledAttr} type="email" class="form-control rdformsFieldInput" placeholder="${item.getPlaceholder() || ''}">`);
125
128
  } else {
126
- $input = jquery(`<input type="text" class="form-control rdformsFieldInput" placeholder="${item.getPlaceholder() || ''}">`);
129
+ $input = jquery(`<input ${disabledAttr} type="text" class="form-control rdformsFieldInput" placeholder="${item.getPlaceholder() || ''}">`);
127
130
  }
128
131
  $input.val(binding.getGist())
129
132
  .appendTo(fieldDiv);
@@ -156,7 +159,7 @@ editors.itemtype('text').register((fieldDiv, binding, context) => {
156
159
  if (nodeType === 'LANGUAGE_LITERAL' || nodeType === 'PLAIN_LITERAL') {
157
160
  jquery(fieldDiv).addClass('rdformsLangcontrolledfield');
158
161
  jquery(context.controlDiv).addClass('rdformsLangFieldControl');
159
- const $lselect = jquery('<select class="form-control rdformsLanguage">')
162
+ const $lselect = jquery(`<select ${disabledAttr} class="form-control rdformsLanguage">`)
160
163
  .appendTo(context.controlDiv);
161
164
  let primaryLangs = renderingContext.getPrimaryLanguageList();
162
165
  let langList = renderingContext.getNonPrimaryLanguageList();
@@ -20,6 +20,21 @@ renderingContext.renderPresenterLabel = (rowNode, binding, item, context, labelR
20
20
  if (context) {
21
21
  context.labelNode = $labelDiv[0];
22
22
  }
23
+ const view = context.view;
24
+ if (item.hasStyle('showDescriptionInPresent') || view.showDescription) {
25
+ // An item is compact if it is exclicitly set as compact or
26
+ // the view is set as compact and the item is not explicitly set as not compact AND
27
+ // we are at the top
28
+ const compactField = item.hasStyle('compact') ||
29
+ (view.compact && !item.hasStyle('nonCompact') && (
30
+ (view.topLevel && item.getType() !== 'group') ||
31
+ (view.parentView && view.parentView.topLevel && view.binding.getItem().hasStyle('heading'))));
32
+ const desc = item.getDescription();
33
+ if (!compactField && desc) {
34
+ jquery('<div class="rdformsDescription" tabindex="0">').text(desc).appendTo(rowNode);
35
+ }
36
+ }
37
+
23
38
  renderingContext.attachItemInfo(item, $labelDiv[0], context);
24
39
  };
25
40
 
@@ -1,6 +1,6 @@
1
1
  import moment from 'moment';
2
2
  import { escape } from 'lodash-es';
3
- import { getDatePresentation, fromDuration } from './util';
3
+ import { getDatePresentation, fromDuration } from '../viewUtils';
4
4
  import renderingContext from '../renderingContext';
5
5
  import utils from '../../utils';
6
6
  import system from '../../model/system';
@@ -122,7 +122,7 @@ presenters.itemtype('text').datatype('xsd:duration').register((fieldDiv, binding
122
122
  const node = jquery('<div>').appendTo(fieldDiv)[0];
123
123
  ['years', 'months', 'days', 'hours', 'minutes'].forEach((key) => {
124
124
  if (data.hasOwnProperty(key)) {
125
- jquery(`<span class="durationlabel">${bundle[`duration_${key}`]}:</span><span class="durationValue">${data[key]}</span>`)
125
+ jquery(`<span class="durationLabel">${bundle[`duration_${key}`]}:</span><span class="durationValue">${data[key]}</span>`)
126
126
  .appendTo(node);
127
127
  }
128
128
  });
@@ -143,4 +143,4 @@ presenters.itemtype('text').datatype('xsd:time').register(datePresenter);
143
143
  presenters.itemtype('text').datatype('xsd:gYear').register(datePresenter);
144
144
  presenters.itemtype('text').datatype('xsd:gYearMonth').register(datePresenter);
145
145
  presenters.itemtype('text').datatype('xsd:gMonthDay').register(datePresenter);
146
- presenters.itemtype('text').datatype('dcterms:W3CDTF').register(datePresenter);
146
+ presenters.itemtype('text').datatype('dcterms:W3CDTF').register(datePresenter);
@@ -7,6 +7,7 @@ import AddIcon from '@mui/icons-material/Add';
7
7
  import IconButton from '@mui/material/IconButton';
8
8
  import renderingContext from '../renderingContext';
9
9
  import * as engine from '../../model/engine';
10
+ import { useNamedGraphId } from './hooks';
10
11
 
11
12
  renderingContext.addExpandButton = (rowDiv, labelDiv, item, context) => {
12
13
  console.log('Expand button not yet supported');
@@ -78,10 +79,12 @@ renderingContext.addRemoveButton = (rowDiv, binding, context) => () => {
78
79
  }
79
80
  });
80
81
 
82
+ const ngId = useNamedGraphId(binding, context);
81
83
  const title = clear ? context.view.messages.edit_clear : context.view.messages.edit_remove;
82
84
  return <IconButton
83
85
  size="small"
84
86
  aria-label={title}
87
+ disabled={!!ngId}
85
88
  title={title}
86
89
  onClick={onClick}
87
90
  >{clear ? (<CancelIcon fontSize="small"/>) : (<RemoveCircleIcon fontSize="small"/>)}</IconButton>;
@@ -3,9 +3,11 @@ import React, { useState, useEffect, useMemo } from 'react';
3
3
  import FormControlLabel from '@mui/material/FormControlLabel';
4
4
  import Checkbox from '@mui/material/Checkbox';
5
5
  import { FormGroup } from '@mui/material';
6
- import { useLocalizedSortedChoices, useName } from '../hooks';
6
+ import { useLocalizedSortedChoices, useNamedGraphId } from '../hooks';
7
+ import { getNamedGraphId } from '../../viewUtils';
7
8
  import * as engine from '../../../model/engine';
8
9
 
10
+
9
11
  const CheckOption = (props) => {
10
12
  const { choice, binding, onChoiceChange } = props;
11
13
  const [checked, setChecked] = React.useState(choice.value === binding.getValue());
@@ -16,6 +18,7 @@ const CheckOption = (props) => {
16
18
  onChoiceChange();
17
19
  };
18
20
  return <FormControlLabel
21
+ disabled={props.disabled}
19
22
  label={choice.label} control={<Checkbox checked={checked} onChange={handleChange}/>}
20
23
  {...(choice.mismatch ? { className: 'mismatch' } : {})}
21
24
  title={choice.description || choice.seeAlso || choice.value}/>;
@@ -35,9 +38,9 @@ export default function CheckBoxesEditor(props) {
35
38
  const existingbinding = val2binding[c.value];
36
39
  if (existingbinding) {
37
40
  delete val2binding[c.value];
38
- return [c, existingbinding];
41
+ return [c, existingbinding, getNamedGraphId(existingbinding, props.context)];
39
42
  }
40
- return [c, engine.create(parentBinding, item)];
43
+ return [c, engine.create(parentBinding, item), undefined];
41
44
  });
42
45
  // Add checks for values that are non-conforming (should have mismatch on their choices).
43
46
  Object.values(val2binding).forEach((b) => {
@@ -70,12 +73,14 @@ export default function CheckBoxesEditor(props) {
70
73
  setResetCount(resetCount + 1);
71
74
  };
72
75
 
76
+ const ngId = useNamedGraphId(binding, props.context);
73
77
  return (
74
78
  <><FormGroup {...row}>
75
79
  {choiceBindingPairs.map(pair => (
76
80
  <CheckOption key={`${resetCount}-${pair[1].getHash()}`}
77
81
  choice={pair[0]}
78
82
  binding={pair[1]}
83
+ disabled={!!pair[2] || !!ngId}
79
84
  onChoiceChange={onChoiceChange} />
80
85
  ))}
81
86
  </FormGroup>{error && (
@@ -2,7 +2,7 @@
2
2
  import React, { useState, useEffect } from 'react';
3
3
  import TextField from '@mui/material/TextField';
4
4
  import renderingContext from '../../renderingContext';
5
- import { loadLocalizedChoice } from '../hooks';
5
+ import { loadLocalizedChoice, useNamedGraphId } from '../hooks';
6
6
  import utils from '../../../utils';
7
7
  import ShowButton from './ShowButton';
8
8
 
@@ -38,10 +38,11 @@ export default (props) => {
38
38
  }, props.field);
39
39
  };
40
40
 
41
+ const ngId = useNamedGraphId(binding, props.context);
41
42
  return <><TextField
42
43
  inputProps={{ 'aria-labelledby': labelledBy }}
43
44
  className="rdformsSearch"
44
- disabled {...(choice && choice.mismatch ? { mismatch: true } : {})}
45
+ disabled {...(!!ngId || (choice && choice.mismatch) ? { mismatch: true } : {})}
45
46
  title={title}
46
47
  value={label}
47
48
  placeholder={binding.getItem().getPlaceholder()}
@@ -49,6 +50,7 @@ export default (props) => {
49
50
  variant={renderingContext.materialVariant}
50
51
  /><ShowButton
51
52
  {... props}
53
+ disabled={!!ngId}
52
54
  onClick={choiceSelectorHandler}/>{ error && (<div key="warning" className="rdformsWarning">{
53
55
  props.context.view.messages.wrongValueField}</div>)}</>;
54
56
  };
@@ -1,11 +1,11 @@
1
- /* eslint-disable no-unused-vars */
1
+ /* eslint-disable no-unused-vars,quotes */
2
2
  import React, { useState, useEffect } from 'react';
3
3
  import TextField from '@mui/material/TextField';
4
4
  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 { editLocalizedChoice, loadLocalizedChoice } from '../hooks';
8
+ import { editLocalizedChoice, loadLocalizedChoice, useNamedGraphId } from '../hooks';
9
9
  import ShowButton from './ShowButton';
10
10
 
11
11
  let globalChoiceQueryThrottle;
@@ -78,7 +78,8 @@ export default (props) => {
78
78
  setOpen(true);
79
79
  }
80
80
  }}
81
- variant={renderingContext.materialVariant} />
81
+ variant={renderingContext.materialVariant}
82
+ />
82
83
  );
83
84
  };
84
85
 
@@ -97,6 +98,8 @@ export default (props) => {
97
98
  });
98
99
  };
99
100
 
101
+ const ngId = useNamedGraphId(binding, props.context);
102
+ const UpgradeComponent = value && value.original.upgradeComponent;
100
103
  return (
101
104
  <>
102
105
  <Autocomplete
@@ -105,29 +108,35 @@ export default (props) => {
105
108
  fullWidth={false}
106
109
  value={value}
107
110
  options={options}
108
- filterOptions={(fopts) => fopts}
111
+ filterOptions={fopts => fopts}
109
112
  open={open}
110
113
  onOpen={() => setOpen(true)}
111
114
  onClose={() => setOpen(false)}
112
115
  onInputChange={(event, newInputValue) => setInputValue(newInputValue)}
113
116
  onChange={onChange}
117
+ disabled={!!ngId}
114
118
  isOptionEqualToValue={(option, choice) => option.value === choice.value}
115
- getOptionLabel={(choice) =>
119
+ getOptionLabel={choice =>
116
120
  choice === null ? '' : choice.label || choice.value
117
121
  }
118
- getOptionDisabled={(option) => option.mismatch === true}
122
+ getOptionDisabled={option => option.mismatch === true}
119
123
  renderInput={renderInput}
124
+ disablePortal
120
125
  />
121
- <ShowButton {...props} onClick={showHandler} />
126
+ <ShowButton {...props} onClick={showHandler} disabled={!!ngId}/>
122
127
  {value && value.original.upgrade && (
123
- <IconButton
124
- aria-label={props.context.view.messages.edit_upgrade}
125
- title={props.context.view.messages.edit_upgrade}
126
- onClick={upgradeHandler}
127
- >
128
- <BuildIcon />
129
- </IconButton>
130
- )}
128
+ <>
129
+ <IconButton
130
+ aria-label={props.context.view.messages.edit_upgrade}
131
+ title={props.context.view.messages.edit_upgrade}
132
+ disabled={!!ngId}
133
+ onClick={upgradeHandler}
134
+ >
135
+ <BuildIcon />
136
+ </IconButton>
137
+ {UpgradeComponent}
138
+ </>
139
+ )}
131
140
  {error && (
132
141
  <div key="warning" className="rdformsWarning">
133
142
  {props.context.view.messages.wrongValueField}
@@ -1,9 +1,9 @@
1
- /* eslint-disable no-unused-vars */
1
+ /* eslint-disable no-unused-vars,quotes */
2
2
  import React, { useState, useEffect } from 'react';
3
3
  import TextField from '@mui/material/TextField';
4
4
  import Autocomplete from '@mui/material/Autocomplete';
5
5
  import renderingContext from '../../renderingContext';
6
- import { useLocalizedSortedChoices, useLocalizedChoice } from '../hooks';
6
+ import { useLocalizedSortedChoices, useLocalizedChoice, useNamedGraphId } from '../hooks';
7
7
 
8
8
  /**
9
9
  * Autocomplete with fixed choices.
@@ -50,6 +50,7 @@ export default (props) => {
50
50
  setError(newChoice.original.mismatch === true);
51
51
  };
52
52
 
53
+ const ngId = useNamedGraphId(binding, props.context);
53
54
  return (
54
55
  <>
55
56
  <Autocomplete
@@ -58,11 +59,13 @@ export default (props) => {
58
59
  value={value}
59
60
  options={choices}
60
61
  onChange={handleChange}
62
+ disabled={!!ngId}
61
63
  isOptionEqualToValue={(option, choice) => option.value === choice.value}
62
- getOptionLabel={(choice) => (choice === null ? '' : choice.label)}
63
- getOptionDisabled={(option) => option.mismatch === true}
64
+ getOptionLabel={choice => (choice === null ? '' : choice.label)}
65
+ getOptionDisabled={option => option.mismatch === true}
64
66
  filterSelectedOptions
65
67
  renderInput={renderInput}
68
+ disablePortal
66
69
  />
67
70
  {error && (
68
71
  <div key="warning" className="rdformsWarning">
@@ -1,12 +1,13 @@
1
- /* eslint-disable no-unused-vars */
1
+ /* eslint-disable no-unused-vars,quotes */
2
2
  import React, { useState, useEffect } from 'react';
3
3
  import Radio from '@mui/material/Radio';
4
4
  import RadioGroup from '@mui/material/RadioGroup';
5
5
  import FormControlLabel from '@mui/material/FormControlLabel';
6
6
  import FormControl from '@mui/material/FormControl';
7
- import { useLocalizedSortedChoices, useName } from '../hooks';
7
+ import { useLocalizedSortedChoices, useName, useNamedGraphId } from '../hooks';
8
8
 
9
9
  const ChoiceOption = props => <FormControlLabel
10
+ disabled={props.disabled}
10
11
  label={props.choice.label} value={props.choice.value} control={<Radio/>}
11
12
  {...(props.choice.mismatch ? { className: 'mismatch' } : {})}
12
13
  title={props.choice.description || props.choice.seeAlso || props.choice.value}/>;
@@ -46,6 +47,7 @@ export default function RadioButtonsEditor(props) {
46
47
  };
47
48
  }, []);
48
49
 
50
+ const ngId = useNamedGraphId(binding, props.context);
49
51
  return (
50
52
  <>
51
53
  <FormControl component="fieldset">
@@ -57,8 +59,10 @@ export default function RadioButtonsEditor(props) {
57
59
  value={value}
58
60
  onChange={handleChange}
59
61
  >
60
- {choices.map((choice) => (
61
- <ChoiceOption key={choice.value} choice={choice} />
62
+ {choices.map(choice => (
63
+ <ChoiceOption key={choice.value}
64
+ disabled={!!ngId}
65
+ choice={choice} />
62
66
  ))}
63
67
  </RadioGroup>
64
68
  </FormControl>
@@ -24,6 +24,7 @@ export default (props) => {
24
24
  props.context.view.messages.edit_browse;
25
25
  if (props.context.chooser.show) {
26
26
  return <IconButton
27
+ disabled={props.disabled}
27
28
  aria-label={title}
28
29
  title={title}
29
30
  onClick={props.onClick}
@@ -16,8 +16,8 @@ import {
16
16
  getDateValue,
17
17
  getAllowedDateAlternatives,
18
18
  getDatePresentation,
19
- } from '../jquery/util';
20
-
19
+ } from '../viewUtils';
20
+ import { useNamedGraphId } from './hooks';
21
21
 
22
22
  const getDatatypeFromBinding = binding => getDatatype(binding.getDatatype()) || getDatatypeFromItem(binding.getItem());
23
23
 
@@ -118,10 +118,11 @@ const dateEditor = (fieldDiv, binding, context) => {
118
118
  'aria-labelledby': context.view.getLabelIndex(binding),
119
119
  variant: renderingContext.materialVariant,
120
120
  };
121
+ const ngId = useNamedGraphId(binding, context);
121
122
  const visibleDatePicker = alternatives.Date || alternatives.DateTime || alternatives.Year
122
123
  || alternatives.YearMonth || alternatives.MonthDay;
123
- const enabledDatePicker = selectedDatatype === 'DateTime' || selectedDatatype === 'Date'
124
- || selectedDatatype === 'Year' || selectedDatatype === 'YearMonth' || selectedDatatype === 'MonthDay';
124
+ const enabledDatePicker = !ngId && (selectedDatatype === 'DateTime' || selectedDatatype === 'Date'
125
+ || selectedDatatype === 'Year' || selectedDatatype === 'YearMonth' || selectedDatatype === 'MonthDay');
125
126
  return (
126
127
  <LocalizationProvider dateAdapter={DateAdapter}>
127
128
  <span className="rdformsDatePicker">
@@ -146,7 +147,7 @@ const dateEditor = (fieldDiv, binding, context) => {
146
147
  <TimePicker
147
148
  renderInput={props => <TextField {...props} {...inputProps} />}
148
149
  label={bundle.date_time}
149
- {...(selectedDatatype === 'DateTime' || selectedDatatype === 'Time' ? {} : { disabled: true })}
150
+ {...(!ngId && (selectedDatatype === 'DateTime' || selectedDatatype === 'Time') ? {} : { disabled: true })}
150
151
  KeyboardButtonProps={{
151
152
  'aria-label': bundle.date_openTimePicker,
152
153
  }}
@@ -162,6 +163,7 @@ const dateEditor = (fieldDiv, binding, context) => {
162
163
  value={selectedDatatype}
163
164
  inputProps={inputProps}
164
165
  onChange={onDatatypeChange}
166
+ disabled={!!ngId}
165
167
  >
166
168
  {alternatives.Year && (
167
169
  <MenuItem value="Year">{bundle.date_year}</MenuItem>
@@ -2,7 +2,8 @@
2
2
  import React, { useState, useEffect, useMemo } from 'react';
3
3
  import TextField from '@mui/material/TextField';
4
4
  import renderingContext from '../renderingContext';
5
- import { toDuration, fromDuration } from './util';
5
+ import { toDuration, fromDuration } from '../viewUtils';
6
+ import { useNamedGraphId } from './hooks';
6
7
 
7
8
  const keys = ['years', 'months', 'days', 'hours', 'minutes'];
8
9
  const editors = renderingContext.editorRegistry;
@@ -44,11 +45,12 @@ editors.itemtype('text').datatype('xsd:duration').register((fieldDiv, binding, c
44
45
  }, {}));
45
46
 
46
47
  const descBy = context.view.getLabelIndex(binding);
47
-
48
+ const ngId = useNamedGraphId(binding, context);
48
49
  return <>{keys.map(key => (<TextField
49
50
  key={key}
50
51
  className="rdformsDurationInput"
51
52
  value={`${duration[key] || ''}`}
53
+ disabled={!!ngId}
52
54
  label={bundle[`duration_${key}`]}
53
55
  type="number"
54
56
  onChange={onChange[key]}
@@ -1,5 +1,6 @@
1
1
  import { useState, useEffect, useMemo } from 'react';
2
2
  import utils from '../../utils';
3
+ import { getNamedGraphId } from '../viewUtils';
3
4
 
4
5
  /**
5
6
  * Wraps a choice in an object where the current label, and description is localized.
@@ -91,3 +92,5 @@ export const useName = () => useMemo(() => {
91
92
  nameCounter += 1;
92
93
  return `_rdforms_${nameCounter}`;
93
94
  }, []);
95
+
96
+ export const useNamedGraphId = (binding, context) => useMemo(() => getNamedGraphId(binding, context));
@@ -74,12 +74,30 @@ renderingContext.renderPresenterLabel = (rowNode, binding, item, context) => {
74
74
  } else {
75
75
  label = '';
76
76
  }
77
+
78
+ const view = context.view;
79
+ let description;
80
+ if (item.hasStyle('showDescriptionInPresent') || view.showDescription) {
81
+ // An item is compact if it is exclicitly set as compact or
82
+ // the view is set as compact and the item is not explicitly set as not compact AND
83
+ // we are at the top
84
+ const compactField = item.hasStyle('compact') ||
85
+ (view.compact && !item.hasStyle('nonCompact') && (
86
+ (view.topLevel && item.getType() !== 'group') ||
87
+ (view.parentView && view.parentView.topLevel && view.binding.getItem().hasStyle('heading'))));
88
+ const desc = view instanceof Editor ? item.getEditDescription() || item.getDescription() :
89
+ item.getDescription();
90
+ if (!compactField && desc) {
91
+ description = <div className="rdformsDescription" tabIndex="0">{desc}</div>;
92
+ }
93
+ }
94
+
77
95
  const labelId = binding ? context.view.createLabelIndex(binding) : undefined;
78
96
  label = item.hasStyle('heading') ?
79
97
  <h2 tabIndex="0" id={labelId} className="rdformsLabelRow"><span className="rdformsLabel">{label}</span></h2> :
80
98
  <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>);
99
+ rowNode.appendChild(<><ItemTooltip key={`${binding ? binding.getHash() : item._internalId}_label` }
100
+ context={context} item={item}>{label}</ItemTooltip>{description}</>);
83
101
  };
84
102
 
85
103
  renderingContext.renderEditorLabel = (rowNode, binding, item, context) => {
@@ -113,9 +131,27 @@ renderingContext.renderEditorLabel = (rowNode, binding, item, context) => {
113
131
  } else if (item.getType() === 'group' && !context.view.showAsTable(item)) {
114
132
  Button = renderingContext.addRemoveButton(rowNode, binding, context);
115
133
  }
134
+
135
+ const view = context.view;
136
+ let description;
137
+ if (item.hasStyle('showDescriptionInEdit') || view.showDescription) {
138
+ // An item is compact if it is exclicitly set as compact or
139
+ // the view is set as compact and the item is not explicitly set as not compact AND
140
+ // we are at the top
141
+ const compactField = item.hasStyle('compact') ||
142
+ (view.compact && !item.hasStyle('nonCompact') && (
143
+ (view.topLevel && item.getType() !== 'group') ||
144
+ (view.parentView && view.parentView.topLevel && view.binding.getItem().hasStyle('heading'))));
145
+ const desc = view instanceof Editor ? item.getEditDescription() || item.getDescription() :
146
+ item.getDescription();
147
+ if (!compactField && desc) {
148
+ description = <div className="rdformsDescription" tabIndex="0">{desc}</div>;
149
+ }
150
+ }
151
+
116
152
  const labelId = context.view.createLabelIndex(binding);
117
- rowNode.appendChild(<div key={`${binding.getHash()}_label`} id={labelId} className="rdformsLabelRow">{
118
- label}{mark}{Button && <Button></Button>}</div>);
153
+ rowNode.appendChild(<><div key={`${binding.getHash()}_label`} id={labelId} className="rdformsLabelRow">{
154
+ label}{mark}{Button && <Button></Button>}</div>{description}</>);
119
155
  }
120
156
  };
121
157
 
@@ -133,7 +133,7 @@
133
133
  }
134
134
 
135
135
  .rdformsEditor .rdformsLangControl {
136
- width: calc(33.33% - 8px);
136
+ width: calc(33.33% - 4px);
137
137
  }
138
138
 
139
139
  /* Duration */
@@ -205,10 +205,6 @@ div.MuiTooltip-tooltip {
205
205
  margin-right: 11px;
206
206
  }
207
207
 
208
- .rdformsEditor .rdformsLangControl {
209
- width: calc(33.33% - 8px);
210
- }
211
-
212
208
  .rdformsDependency {
213
209
  display: none;
214
210
  }
@@ -227,4 +223,8 @@ div.MuiTooltip-tooltip {
227
223
  font-size: 10px;
228
224
  font-weight: bolder;
229
225
  font-family: sans-serif;
230
- }
226
+ }
227
+
228
+ .rdformsHeading>.rdformsDescription {
229
+ margin: -20px 0 20px;
230
+ }
@@ -3,7 +3,7 @@ import React, { useState, useEffect, useMemo } from 'react';
3
3
  import moment from 'moment';
4
4
  import system from '../../model/system';
5
5
  import renderingContext from '../renderingContext';
6
- import { fromDuration } from './util';
6
+ import { fromDuration } from '../viewUtils';
7
7
  import utils from '../../utils';
8
8
 
9
9
 
@@ -13,7 +13,7 @@ presenters.itemtype('text').datatype('xsd:duration').register((fieldDiv, binding
13
13
  const data = fromDuration(binding.getValue());
14
14
  const keys = ['years', 'months', 'days', 'hours', 'minutes'];
15
15
  fieldDiv.appendChild(<div key={binding.getHash()}>{keys.map(key => (
16
- data[key] && <React.Fragment key={key}><span className="durationlabel">{
16
+ data[key] && <React.Fragment key={key}><span className="durationLabel">{
17
17
  context.view.messages[`duration_${key}`]}:</span><span className="durationValue">{data[key]}</span></React.Fragment>
18
18
  ))}</div>);
19
19
  });
@@ -10,6 +10,7 @@ import Select from '@mui/material/Select';
10
10
  import moment from 'moment';
11
11
  import renderingContext from '../renderingContext';
12
12
  import utils from '../../utils';
13
+ import { useNamedGraphId } from './hooks';
13
14
 
14
15
  const LanguageControl = (props) => {
15
16
  const [lang, setLang] = useState(props.binding.getLanguage() || '');
@@ -38,10 +39,12 @@ const LanguageControl = (props) => {
38
39
  };
39
40
  }, []);
40
41
 
42
+ const ngId = useNamedGraphId(props.binding, props.context);
41
43
  return <FormControl className="rdformsLangControl" variant={renderingContext.materialVariant}>
42
44
  <Select
43
45
  inputProps={{ 'aria-labelledby': props.labelledby }}
44
46
  value={lang}
47
+ disabled={!!ngId}
45
48
  onChange={onLangChange}>
46
49
  {langs.map(langOption => (langOption === null ?
47
50
  (<MenuItem key="_none" value="_none" disabled>─────</MenuItem>) :
@@ -90,11 +93,13 @@ editors.itemtype('text').register((fieldDiv, binding, context) => {
90
93
  },
91
94
  };
92
95
  const bundle = context.view.messages;
96
+ const ngId = useNamedGraphId(binding, context);
93
97
  return <><TextField
94
98
  className={extLink || langlit ? 'rdformsTwoThirds' : ''}
95
99
  multiline={multiline}
96
100
  placeholder={item.getPlaceholder()}
97
101
  error={!valid}
102
+ disabled={!!ngId}
98
103
  helperText={!valid ? item.getHelp() || '' : ''}
99
104
  variant={renderingContext.materialVariant} inputProps={iprops}
100
105
  />{extLink && (value != null || value === '') &&
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-unused-vars */
1
2
  import Registry from './Registry';
2
3
  import system from '../model/system';
3
4
  import nls from './resources/nls';
@@ -328,7 +329,9 @@ const groupPresenter = (fieldDiv, binding, context) => {
328
329
  messages: context.view.messages,
329
330
  binding,
330
331
  topLevel: false,
332
+ compact: context.view.compact,
331
333
  showLanguage: context.view.showLanguage,
334
+ showDescription: context.view.showDescription,
332
335
  defaultLanguage: context.view.defaultLanguage,
333
336
  filterTranslations: context.view.filterTranslations,
334
337
  includeLevel: context.view.includeLevel, // Copied from groupEditor, was this.includeLevel but that 'this' does not make sense here
@@ -346,6 +349,8 @@ const groupEditor = (fieldDiv, binding, context) => {
346
349
  languages: context.view.languages,
347
350
  binding,
348
351
  topLevel: false,
352
+ compact: context.view.compact,
353
+ showDescription: context.view.showDescription,
349
354
  includeLevel: context.view.includeLevel,
350
355
  }, fieldDiv);
351
356
  context.view._subEditors.push(subView);