@plone/volto 14.0.1 → 14.2.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 (218) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/locales/ca/LC_MESSAGES/volto.po +12 -2
  3. package/locales/ca.json +1 -1
  4. package/locales/de/LC_MESSAGES/volto.po +12 -2
  5. package/locales/de.json +1 -1
  6. package/locales/en/LC_MESSAGES/volto.po +12 -2
  7. package/locales/en.json +1 -1
  8. package/locales/es/LC_MESSAGES/volto.po +12 -2
  9. package/locales/es.json +1 -1
  10. package/locales/eu/LC_MESSAGES/volto.po +12 -2
  11. package/locales/eu.json +1 -1
  12. package/locales/fr/LC_MESSAGES/volto.po +12 -2
  13. package/locales/fr.json +1 -1
  14. package/locales/it/LC_MESSAGES/volto.po +12 -2
  15. package/locales/it.json +1 -1
  16. package/locales/ja/LC_MESSAGES/volto.po +12 -2
  17. package/locales/ja.json +1 -1
  18. package/locales/nl/LC_MESSAGES/volto.po +12 -2
  19. package/locales/nl.json +1 -1
  20. package/locales/pt/LC_MESSAGES/volto.po +12 -2
  21. package/locales/pt.json +1 -1
  22. package/locales/pt_BR/LC_MESSAGES/volto.po +12 -2
  23. package/locales/pt_BR.json +1 -1
  24. package/locales/ro/LC_MESSAGES/volto.po +12 -2
  25. package/locales/ro.json +1 -1
  26. package/locales/volto.pot +12 -2
  27. package/package.json +2 -1
  28. package/public/icon.svg +13 -0
  29. package/src/actions/vocabularies/vocabularies.js +15 -3
  30. package/src/components/index.js +1 -0
  31. package/src/components/manage/Add/Add.jsx +1 -0
  32. package/src/components/manage/Blocks/HeroImageLeft/Edit.jsx +1 -1
  33. package/src/components/manage/Blocks/Listing/getAsyncData.js +1 -1
  34. package/src/components/manage/Blocks/Text/Edit.jsx +19 -0
  35. package/src/components/manage/Edit/Edit.jsx +1 -0
  36. package/src/components/manage/Form/Form.jsx +32 -6
  37. package/src/components/manage/Form/UndoToolbar.jsx +78 -0
  38. package/src/components/manage/Multilingual/TranslationObject.jsx +1 -0
  39. package/src/components/manage/Widgets/AlignWidget.stories.jsx +5 -21
  40. package/src/components/manage/Widgets/ArrayWidget.jsx +88 -88
  41. package/src/components/manage/Widgets/ArrayWidget.stories.jsx +37 -64
  42. package/src/components/manage/Widgets/CheckboxWidget.stories.jsx +5 -22
  43. package/src/components/manage/Widgets/DatetimeWidget.jsx +65 -74
  44. package/src/components/manage/Widgets/DatetimeWidget.stories.jsx +7 -23
  45. package/src/components/manage/Widgets/DatetimeWidget.test.jsx +17 -15
  46. package/src/components/manage/Widgets/EmailWidget.stories.jsx +5 -22
  47. package/src/components/manage/Widgets/FileWidget.stories.jsx +5 -22
  48. package/src/components/manage/Widgets/NumberWidget.stories.jsx +5 -23
  49. package/src/components/manage/Widgets/ObjectBrowserWidget.stories.js +24 -32
  50. package/src/components/manage/Widgets/ObjectListWidget.stories.js +44 -44
  51. package/src/components/manage/Widgets/ObjectWidget.stories.jsx +13 -28
  52. package/src/components/manage/Widgets/PasswordWidget.stories.jsx +5 -22
  53. package/src/components/manage/Widgets/QueryWidget.jsx +2 -2
  54. package/src/components/manage/Widgets/QueryWidget.stories.jsx +1637 -22
  55. package/src/components/manage/Widgets/SelectAutoComplete.jsx +79 -48
  56. package/src/components/manage/Widgets/SelectAutoComplete.test.jsx +16 -0
  57. package/src/components/manage/Widgets/SelectAutocompleteWidget.stories.jsx +161 -0
  58. package/src/components/manage/Widgets/SelectUtils.js +90 -30
  59. package/src/components/manage/Widgets/SelectUtils.test.jsx +76 -1
  60. package/src/components/manage/Widgets/SelectWidget.jsx +26 -37
  61. package/src/components/manage/Widgets/SelectWidget.stories.jsx +96 -28
  62. package/src/components/manage/Widgets/TextWidget.stories.jsx +5 -22
  63. package/src/components/manage/Widgets/TextareaWidget.stories.jsx +5 -22
  64. package/src/components/manage/Widgets/TokenWidget.jsx +19 -17
  65. package/src/components/manage/Widgets/TokenWidget.stories.jsx +141 -0
  66. package/src/components/manage/Widgets/UrlWidget.stories.jsx +5 -21
  67. package/src/components/manage/Widgets/VocabularyTermsWidget.stories.js +27 -64
  68. package/src/components/manage/Widgets/WysiwygWidget.stories.jsx +5 -22
  69. package/src/components/manage/Widgets/story.jsx +38 -0
  70. package/src/components/theme/ContactForm/ContactForm.jsx +1 -0
  71. package/src/components/theme/ContactForm/ContactForm.stories.jsx +126 -0
  72. package/src/components/theme/CorsError/CorsError.jsx +2 -2
  73. package/src/config/Blocks.jsx +8 -1
  74. package/src/config/Loadables.jsx +2 -0
  75. package/src/config/index.js +3 -0
  76. package/src/helpers/Html/Html.jsx +2 -12
  77. package/src/helpers/UndoManager/useUndoManager.js +102 -0
  78. package/src/helpers/index.js +1 -0
  79. package/src/reducers/vocabularies/vocabularies.js +13 -2
  80. package/src/store.js +1 -1
  81. package/src/storybook.jsx +55 -0
  82. package/theme/themes/pastanaga/extras/time-picker-overrides.less +1 -1
  83. package/include/python3.8/Python-ast.h +0 -715
  84. package/include/python3.8/Python.h +0 -160
  85. package/include/python3.8/abstract.h +0 -844
  86. package/include/python3.8/asdl.h +0 -46
  87. package/include/python3.8/ast.h +0 -37
  88. package/include/python3.8/bitset.h +0 -23
  89. package/include/python3.8/bltinmodule.h +0 -14
  90. package/include/python3.8/boolobject.h +0 -34
  91. package/include/python3.8/bytearrayobject.h +0 -62
  92. package/include/python3.8/bytes_methods.h +0 -69
  93. package/include/python3.8/bytesobject.h +0 -224
  94. package/include/python3.8/cellobject.h +0 -29
  95. package/include/python3.8/ceval.h +0 -231
  96. package/include/python3.8/classobject.h +0 -59
  97. package/include/python3.8/code.h +0 -180
  98. package/include/python3.8/codecs.h +0 -240
  99. package/include/python3.8/compile.h +0 -106
  100. package/include/python3.8/complexobject.h +0 -69
  101. package/include/python3.8/context.h +0 -84
  102. package/include/python3.8/cpython/abstract.h +0 -319
  103. package/include/python3.8/cpython/dictobject.h +0 -94
  104. package/include/python3.8/cpython/fileobject.h +0 -24
  105. package/include/python3.8/cpython/initconfig.h +0 -434
  106. package/include/python3.8/cpython/interpreteridobject.h +0 -19
  107. package/include/python3.8/cpython/object.h +0 -470
  108. package/include/python3.8/cpython/objimpl.h +0 -113
  109. package/include/python3.8/cpython/pyerrors.h +0 -188
  110. package/include/python3.8/cpython/pylifecycle.h +0 -78
  111. package/include/python3.8/cpython/pymem.h +0 -108
  112. package/include/python3.8/cpython/pystate.h +0 -252
  113. package/include/python3.8/cpython/sysmodule.h +0 -21
  114. package/include/python3.8/cpython/traceback.h +0 -22
  115. package/include/python3.8/cpython/tupleobject.h +0 -36
  116. package/include/python3.8/cpython/unicodeobject.h +0 -1239
  117. package/include/python3.8/datetime.h +0 -259
  118. package/include/python3.8/descrobject.h +0 -108
  119. package/include/python3.8/dictobject.h +0 -94
  120. package/include/python3.8/dtoa.h +0 -19
  121. package/include/python3.8/dynamic_annotations.h +0 -499
  122. package/include/python3.8/enumobject.h +0 -17
  123. package/include/python3.8/errcode.h +0 -38
  124. package/include/python3.8/eval.h +0 -37
  125. package/include/python3.8/fileobject.h +0 -49
  126. package/include/python3.8/fileutils.h +0 -185
  127. package/include/python3.8/floatobject.h +0 -130
  128. package/include/python3.8/frameobject.h +0 -92
  129. package/include/python3.8/funcobject.h +0 -104
  130. package/include/python3.8/genobject.h +0 -109
  131. package/include/python3.8/graminit.h +0 -94
  132. package/include/python3.8/grammar.h +0 -77
  133. package/include/python3.8/import.h +0 -149
  134. package/include/python3.8/internal/pycore_accu.h +0 -39
  135. package/include/python3.8/internal/pycore_atomic.h +0 -558
  136. package/include/python3.8/internal/pycore_ceval.h +0 -37
  137. package/include/python3.8/internal/pycore_code.h +0 -27
  138. package/include/python3.8/internal/pycore_condvar.h +0 -95
  139. package/include/python3.8/internal/pycore_context.h +0 -42
  140. package/include/python3.8/internal/pycore_fileutils.h +0 -54
  141. package/include/python3.8/internal/pycore_getopt.h +0 -22
  142. package/include/python3.8/internal/pycore_gil.h +0 -50
  143. package/include/python3.8/internal/pycore_hamt.h +0 -116
  144. package/include/python3.8/internal/pycore_initconfig.h +0 -166
  145. package/include/python3.8/internal/pycore_object.h +0 -81
  146. package/include/python3.8/internal/pycore_pathconfig.h +0 -75
  147. package/include/python3.8/internal/pycore_pyerrors.h +0 -62
  148. package/include/python3.8/internal/pycore_pyhash.h +0 -10
  149. package/include/python3.8/internal/pycore_pylifecycle.h +0 -118
  150. package/include/python3.8/internal/pycore_pymem.h +0 -212
  151. package/include/python3.8/internal/pycore_pystate.h +0 -326
  152. package/include/python3.8/internal/pycore_traceback.h +0 -96
  153. package/include/python3.8/internal/pycore_tupleobject.h +0 -19
  154. package/include/python3.8/internal/pycore_warnings.h +0 -25
  155. package/include/python3.8/interpreteridobject.h +0 -17
  156. package/include/python3.8/intrcheck.h +0 -33
  157. package/include/python3.8/iterobject.h +0 -25
  158. package/include/python3.8/listobject.h +0 -81
  159. package/include/python3.8/longintrepr.h +0 -99
  160. package/include/python3.8/longobject.h +0 -242
  161. package/include/python3.8/marshal.h +0 -28
  162. package/include/python3.8/memoryobject.h +0 -72
  163. package/include/python3.8/methodobject.h +0 -131
  164. package/include/python3.8/modsupport.h +0 -248
  165. package/include/python3.8/moduleobject.h +0 -90
  166. package/include/python3.8/namespaceobject.h +0 -19
  167. package/include/python3.8/node.h +0 -48
  168. package/include/python3.8/object.h +0 -753
  169. package/include/python3.8/objimpl.h +0 -284
  170. package/include/python3.8/odictobject.h +0 -43
  171. package/include/python3.8/opcode.h +0 -148
  172. package/include/python3.8/osdefs.h +0 -51
  173. package/include/python3.8/osmodule.h +0 -17
  174. package/include/python3.8/parsetok.h +0 -110
  175. package/include/python3.8/patchlevel.h +0 -35
  176. package/include/python3.8/picklebufobject.h +0 -31
  177. package/include/python3.8/py_curses.h +0 -100
  178. package/include/python3.8/pyarena.h +0 -64
  179. package/include/python3.8/pycapsule.h +0 -59
  180. package/include/python3.8/pyconfig.h +0 -1665
  181. package/include/python3.8/pyctype.h +0 -39
  182. package/include/python3.8/pydebug.h +0 -40
  183. package/include/python3.8/pydtrace.h +0 -59
  184. package/include/python3.8/pydtrace_probes.h +0 -228
  185. package/include/python3.8/pyerrors.h +0 -335
  186. package/include/python3.8/pyexpat.h +0 -55
  187. package/include/python3.8/pyfpe.h +0 -12
  188. package/include/python3.8/pyhash.h +0 -145
  189. package/include/python3.8/pylifecycle.h +0 -75
  190. package/include/python3.8/pymacconfig.h +0 -102
  191. package/include/python3.8/pymacro.h +0 -106
  192. package/include/python3.8/pymath.h +0 -230
  193. package/include/python3.8/pymem.h +0 -150
  194. package/include/python3.8/pyport.h +0 -850
  195. package/include/python3.8/pystate.h +0 -136
  196. package/include/python3.8/pystrcmp.h +0 -23
  197. package/include/python3.8/pystrhex.h +0 -22
  198. package/include/python3.8/pystrtod.h +0 -45
  199. package/include/python3.8/pythonrun.h +0 -210
  200. package/include/python3.8/pythread.h +0 -161
  201. package/include/python3.8/pytime.h +0 -246
  202. package/include/python3.8/rangeobject.h +0 -27
  203. package/include/python3.8/setobject.h +0 -108
  204. package/include/python3.8/sliceobject.h +0 -65
  205. package/include/python3.8/structmember.h +0 -74
  206. package/include/python3.8/structseq.h +0 -49
  207. package/include/python3.8/symtable.h +0 -123
  208. package/include/python3.8/sysmodule.h +0 -41
  209. package/include/python3.8/token.h +0 -92
  210. package/include/python3.8/traceback.h +0 -28
  211. package/include/python3.8/tracemalloc.h +0 -38
  212. package/include/python3.8/tupleobject.h +0 -48
  213. package/include/python3.8/typeslots.h +0 -85
  214. package/include/python3.8/ucnhash.h +0 -36
  215. package/include/python3.8/unicodeobject.h +0 -1044
  216. package/include/python3.8/warnings.h +0 -67
  217. package/include/python3.8/weakrefobject.h +0 -86
  218. package/src/components/theme/ContactForm/ContactForm.stories.mdx +0 -39
@@ -1,17 +1,19 @@
1
1
  import VocabularyTermsWidget from './VocabularyTermsWidget';
2
- import Wrapper from '@plone/volto/storybook';
3
2
  import React from 'react';
4
3
 
5
- const customStore = {
6
- userSession: { token: '1234' },
7
- intl: {
8
- locale: 'en',
9
- messages: {},
10
- },
11
- };
4
+ import WidgetStory from './story';
12
5
 
13
- const WrappedJSONField = (args) => {
14
- const [value, setValue] = React.useState({
6
+ export const JSONField = WidgetStory.bind({
7
+ props: { id: 'simplevocabulary', title: 'Vocabulary terms' },
8
+ widget: VocabularyTermsWidget,
9
+ customStore: {
10
+ userSession: { token: '1234' },
11
+ intl: {
12
+ locale: 'en',
13
+ messages: {},
14
+ },
15
+ },
16
+ initialValue: {
15
17
  items: [
16
18
  {
17
19
  token: 'talk',
@@ -30,60 +32,24 @@ const WrappedJSONField = (args) => {
30
32
  },
31
33
  },
32
34
  ],
33
- });
34
- const onChange = (block, value) => setValue(value);
35
-
36
- return (
37
- <Wrapper
38
- location={{ pathname: '/folder2/folder21/doc212' }}
39
- customStore={customStore}
40
- >
41
- <div className="ui segment form attached">
42
- <VocabularyTermsWidget
43
- {...args}
44
- id="simplevocabulary"
45
- title="Vocabulary terms"
46
- block="testBlock"
47
- value={value}
48
- onChange={onChange}
49
- />
50
- <pre>{JSON.stringify(value, null, 4)}</pre>
51
- </div>
52
- </Wrapper>
53
- );
54
- };
35
+ },
36
+ });
55
37
 
56
- const WrappedSimple = (args) => {
57
- const [value, setValue] = React.useState({
38
+ export const Simple = WidgetStory.bind({
39
+ props: { id: 'simplevocabulary', title: 'Vocabulary terms' },
40
+ widget: VocabularyTermsWidget,
41
+ customStore: {
42
+ userSession: { token: '1234' },
43
+ intl: {
44
+ locale: 'en',
45
+ messages: {},
46
+ },
47
+ },
48
+ initialValue: {
58
49
  '001': 'manual',
59
50
  '002': 'questions & answers',
60
- });
61
- const onChange = (block, value) => setValue(value);
62
-
63
- return (
64
- <Wrapper
65
- location={{ pathname: '/folder2/folder21/doc212' }}
66
- customStore={customStore}
67
- >
68
- <div className="ui segment form attached">
69
- <VocabularyTermsWidget
70
- {...args}
71
- id="Simple"
72
- title="Vocabulary terms"
73
- block="testBlock"
74
- value={value}
75
- value_type={{
76
- schema: {
77
- type: 'string',
78
- },
79
- }}
80
- onChange={onChange}
81
- />
82
- <pre>{JSON.stringify(value, null, 4)}</pre>
83
- </div>
84
- </Wrapper>
85
- );
86
- };
51
+ },
52
+ });
87
53
 
88
54
  export default {
89
55
  title: 'Widgets/Vocabulary',
@@ -96,6 +62,3 @@ export default {
96
62
  ),
97
63
  ],
98
64
  };
99
-
100
- export const JSONField = () => <WrappedJSONField />;
101
- export const Simple = () => <WrappedSimple />;
@@ -1,28 +1,11 @@
1
1
  import React from 'react';
2
2
  import WysiwygWidget from './WysiwygWidget';
3
- import Wrapper from '@plone/volto/storybook';
3
+ import WidgetStory from './story';
4
4
 
5
- const WysiwygWidgetComponent = ({ children, ...args }) => {
6
- const [value, setValue] = React.useState('');
7
- const onChange = (block, value) => setValue(value);
8
- return (
9
- <Wrapper location={{ pathname: '/folder2/folder21/doc212' }}>
10
- <div className="ui segment form attached" style={{ width: '400px' }}>
11
- <WysiwygWidget
12
- {...args}
13
- id="field"
14
- title="Wysiwyg"
15
- block="testBlock"
16
- value={value}
17
- onChange={onChange}
18
- />
19
- </div>
20
- <pre>Value: {JSON.stringify(value, null, 4)}</pre>
21
- </Wrapper>
22
- );
23
- };
24
-
25
- export const Wysiwyg = WysiwygWidgetComponent.bind({});
5
+ export const Wysiwyg = WidgetStory.bind({
6
+ props: { id: 'text', title: 'Rich text' },
7
+ widget: WysiwygWidget,
8
+ });
26
9
 
27
10
  export default {
28
11
  title: 'Widgets/Wysiwyg',
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import {
3
+ RealStoreWrapper as Wrapper,
4
+ FormUndoWrapper,
5
+ } from '@plone/volto/storybook';
6
+
7
+ export default function StoryComponent({ children, ...args }) {
8
+ const Widget = this.widget;
9
+ const props = this.props || {};
10
+ return (
11
+ <Wrapper
12
+ location={{ pathname: '/folder2/folder21/doc212' }}
13
+ customStore={this.customStore}
14
+ >
15
+ <FormUndoWrapper
16
+ initialState={{
17
+ value: args.value || args.initialValue || this.initialValue,
18
+ }}
19
+ showControls={this.showUndoControls ?? true}
20
+ >
21
+ {({ state, onChange }) => (
22
+ <div className="ui segment form attached" style={{ width: '400px' }}>
23
+ <Widget
24
+ id="field"
25
+ title="Field"
26
+ block="block"
27
+ {...args}
28
+ {...props}
29
+ value={state.value}
30
+ onChange={(block, value) => onChange({ value })}
31
+ />
32
+ <pre>Value: {JSON.stringify(state.value, null, 4)}</pre>
33
+ </div>
34
+ )}
35
+ </FormUndoWrapper>
36
+ </Wrapper>
37
+ );
38
+ }
@@ -221,6 +221,7 @@ export class ContactFormComponent extends Component {
221
221
  <Portal node={document.getElementById('toolbar')}>
222
222
  <Toolbar
223
223
  pathname={this.props.pathname}
224
+ hideDefaultViewButtons
224
225
  inner={
225
226
  <Link
226
227
  to={`${getBaseUrl(this.props.pathname)}`}
@@ -0,0 +1,126 @@
1
+ import React from 'react';
2
+ import { ContactFormComponent } from './ContactForm';
3
+ import { injectIntl } from 'react-intl';
4
+ import { RealStoreWrapper as Wrapper } from '@plone/volto/storybook';
5
+
6
+ const IntlContactFormComponent = injectIntl(ContactFormComponent);
7
+
8
+ const actions = {
9
+ actions: {
10
+ error: null,
11
+ actions: {
12
+ document_actions: [],
13
+ object: [
14
+ {
15
+ icon: '',
16
+ id: 'view',
17
+ title: 'View',
18
+ },
19
+ {
20
+ icon: '',
21
+ id: 'edit',
22
+ title: 'Edit',
23
+ },
24
+ {
25
+ icon: '',
26
+ id: 'folderContents',
27
+ title: 'Contents',
28
+ },
29
+ {
30
+ icon: '',
31
+ id: 'history',
32
+ title: 'History',
33
+ },
34
+ {
35
+ icon: '',
36
+ id: 'local_roles',
37
+ title: 'Sharing',
38
+ },
39
+ ],
40
+ object_buttons: [],
41
+ portal_tabs: [
42
+ {
43
+ icon: '',
44
+ id: 'index_html',
45
+ title: 'Home',
46
+ },
47
+ ],
48
+ site_actions: [
49
+ {
50
+ icon: '',
51
+ id: 'sitemap',
52
+ title: 'Site Map',
53
+ },
54
+ {
55
+ icon: '',
56
+ id: 'accessibility',
57
+ title: 'Accessibility',
58
+ },
59
+ {
60
+ icon: '',
61
+ id: 'contact',
62
+ title: 'Contact',
63
+ },
64
+ ],
65
+ user: [
66
+ {
67
+ icon: '',
68
+ id: 'preferences',
69
+ title: 'Preferences',
70
+ },
71
+ {
72
+ icon: '',
73
+ id: 'dashboard',
74
+ title: 'Dashboard',
75
+ },
76
+ {
77
+ icon: '',
78
+ id: 'plone_setup',
79
+ title: 'Site Setup',
80
+ },
81
+ {
82
+ icon: '',
83
+ id: 'logout',
84
+ title: 'Log out',
85
+ },
86
+ ],
87
+ },
88
+ loaded: true,
89
+ loading: false,
90
+ },
91
+ };
92
+
93
+ function StoryComponent(props) {
94
+ return (
95
+ <Wrapper customStore={{ actions, unlockRequest: {} }}>
96
+ <div id="toolbar" style={{ display: 'none' }} />
97
+ <IntlContactFormComponent
98
+ {...props}
99
+ pathname="/contact"
100
+ error={props.error ? { message: props.error } : null}
101
+ />
102
+ </Wrapper>
103
+ );
104
+ }
105
+
106
+ export const ContactForm = StoryComponent.bind({});
107
+ ContactForm.args = {
108
+ error: { message: 'Something' },
109
+ loading: false,
110
+ loaded: true,
111
+ };
112
+
113
+ export default {
114
+ title: 'Public components/Contact Form',
115
+ component: ContactFormComponent,
116
+ decorators: [
117
+ (Story) => (
118
+ <div className="ui segment form attached" style={{ width: '400px' }}>
119
+ <Story />
120
+ </div>
121
+ ),
122
+ ],
123
+ argTypes: {
124
+ error: { control: 'text' },
125
+ },
126
+ };
@@ -61,8 +61,8 @@ const CorsError = () => (
61
61
  }}
62
62
  >
63
63
  <FormattedMessage
64
- id="The backend server of your website is not anwering, we apologize for the inconvenience. Please try to re-load the page and try again. If the problem persists please contact the site administrators."
65
- defaultMessage="The backend server of your website is not anwering, we apologize for the inconvenience. Please try to re-load the page and try again. If the problem persists please contact the site administrators."
64
+ id="The backend server of your website is not answering, we apologize for the inconvenience. Please try to re-load the page and try again. If the problem persists please contact the site administrators."
65
+ defaultMessage="The backend server of your website is not answering, we apologize for the inconvenience. Please try to re-load the page and try again. If the problem persists please contact the site administrators."
66
66
  />
67
67
  </p>
68
68
 
@@ -454,5 +454,12 @@ const blocksConfig = {
454
454
  const requiredBlocks = ['title'];
455
455
 
456
456
  const initialBlocks = {};
457
+ const initialBlocksFocus = {}; //{Document:'title'}
457
458
 
458
- export { groupBlocksOrder, requiredBlocks, blocksConfig, initialBlocks };
459
+ export {
460
+ groupBlocksOrder,
461
+ requiredBlocks,
462
+ blocksConfig,
463
+ initialBlocks,
464
+ initialBlocksFocus,
465
+ };
@@ -27,4 +27,6 @@ export const loadables = {
27
27
  },
28
28
  ),
29
29
  diffLib: loadable.lib(() => import('diff')),
30
+ moment: loadable.lib(() => import('moment')),
31
+ reactDates: loadable.lib(() => import('react-dates')),
30
32
  };
@@ -26,6 +26,7 @@ import {
26
26
  requiredBlocks,
27
27
  blocksConfig,
28
28
  initialBlocks,
29
+ initialBlocksFocus,
29
30
  } from './Blocks';
30
31
  import { loadables } from './Loadables';
31
32
 
@@ -157,6 +158,7 @@ let config = {
157
158
  showSelfRegistration: false,
158
159
  contentMetadataTagsImageField: 'image',
159
160
  hasWorkingCopySupport: false,
161
+ maxUndoLevels: 200, // undo history size for the main form
160
162
  },
161
163
  widgets: {
162
164
  ...widgetMapping,
@@ -173,6 +175,7 @@ let config = {
173
175
  blocksConfig,
174
176
  groupBlocksOrder,
175
177
  initialBlocks,
178
+ initialBlocksFocus,
176
179
  showEditBlocksInBabelView: false,
177
180
  },
178
181
  addonRoutes: [],
@@ -123,23 +123,13 @@ class Html extends Component {
123
123
  }}
124
124
  />
125
125
 
126
+ <link rel="icon" href="/favicon.ico" sizes="any" />
127
+ <link rel="icon" href="/icon.svg" type="image/svg+xml" />
126
128
  <link
127
129
  rel="apple-touch-icon"
128
130
  sizes="180x180"
129
131
  href="/apple-touch-icon.png"
130
132
  />
131
- <link
132
- rel="icon"
133
- type="image/png"
134
- sizes="32x32"
135
- href="/favicon-32x32.png"
136
- />
137
- <link
138
- rel="icon"
139
- type="image/png"
140
- sizes="16x16"
141
- href="/favicon-16x16.png"
142
- />
143
133
  <link rel="manifest" href="/site.webmanifest" />
144
134
  <meta name="generator" content="Plone 6 - https://plone.org" />
145
135
  <meta name="viewport" content="width=device-width, initial-scale=1" />
@@ -0,0 +1,102 @@
1
+ import React from 'react';
2
+ import Undoo from 'undoo';
3
+
4
+ // Code based on Apache-2.0 License
5
+ // https://github.com/reaviz/reaflow/blob/78d60aa04f514947a17097c906efdbbd6bae5080/src/helpers/useUndo.ts
6
+
7
+ const useUndoManager = (
8
+ state,
9
+ onUndoRedo,
10
+ { maxUndoLevels, enableHotKeys = true },
11
+ ) => {
12
+ const [canUndo, setCanUndo] = React.useState(false);
13
+ const [canRedo, setCanRedo] = React.useState(false);
14
+ const manager = React.useRef(new Undoo({ maxLength: maxUndoLevels }));
15
+ // Reference:
16
+ // https://reactjs.org/docs/hooks-faq.html#how-to-read-an-often-changing-value-from-usecallback
17
+ const callbackRef = React.useRef(onUndoRedo);
18
+ React.useEffect(() => {
19
+ callbackRef.current = onUndoRedo;
20
+ }, [onUndoRedo]);
21
+
22
+ const doUndo = React.useCallback(() => {
23
+ manager.current.undo(({ state }) => {
24
+ const nextUndo = manager.current.canUndo();
25
+ const nextRedo = manager.current.canRedo();
26
+ setCanUndo(nextUndo);
27
+ setCanRedo(nextRedo);
28
+
29
+ callbackRef.current({
30
+ state,
31
+ type: 'undo',
32
+ canUndo: nextUndo,
33
+ canRedo: nextRedo,
34
+ });
35
+ });
36
+ }, []);
37
+
38
+ React.useEffect(() => {
39
+ manager.current.save({
40
+ state,
41
+ });
42
+
43
+ setCanUndo(manager.current.canUndo());
44
+ setCanRedo(manager.current.canRedo());
45
+ }, [state]);
46
+
47
+ const doRedo = React.useCallback(() => {
48
+ manager.current.redo(({ state }) => {
49
+ const nextUndo = manager.current.canUndo();
50
+ const nextRedo = manager.current.canRedo();
51
+ setCanUndo(nextUndo);
52
+ setCanRedo(nextRedo);
53
+
54
+ callbackRef.current({
55
+ state,
56
+ type: 'redo',
57
+ canUndo: nextUndo,
58
+ canRedo: nextRedo,
59
+ });
60
+ });
61
+ }, []);
62
+
63
+ const handleKeys = React.useCallback(
64
+ (event) => {
65
+ const keyName = event.key;
66
+
67
+ if (keyName === 'Control' || keyName === 'Meta') {
68
+ // do not alert when only Control key is pressed.
69
+ return;
70
+ }
71
+ if (event.ctrlKey || event.metaKey) {
72
+ if (keyName === 'z') {
73
+ event.preventDefault();
74
+ event.stopPropagation();
75
+ doUndo();
76
+ } else if (keyName === 'y') {
77
+ event.preventDefault();
78
+ event.stopPropagation();
79
+ doRedo();
80
+ }
81
+ } else {
82
+ return;
83
+ }
84
+ },
85
+ [doUndo, doRedo],
86
+ );
87
+
88
+ React.useEffect(() => {
89
+ if (!enableHotKeys) return;
90
+ document.addEventListener('keydown', handleKeys);
91
+ return () => document.removeEventListener('keydown', handleKeys);
92
+ }, [enableHotKeys, handleKeys]);
93
+
94
+ return {
95
+ doUndo,
96
+ doRedo,
97
+ canUndo,
98
+ canRedo,
99
+ };
100
+ };
101
+
102
+ export default useUndoManager;
@@ -89,3 +89,4 @@ export { userHasRoles } from './User/User';
89
89
  export { useDetectClickOutside } from './Utils/useDetectClickOutside';
90
90
  export { usePrevious } from './Utils/usePrevious';
91
91
  export { usePagination } from './Utils/usePagination';
92
+ export useUndoManager from './UndoManager/useUndoManager';
@@ -71,6 +71,7 @@ export default function vocabularies(state = initialState, action = {}) {
71
71
  [action.vocabulary]: {
72
72
  ...vocabState,
73
73
  subrequests: {
74
+ ...vocabState.subrequests,
74
75
  [action.subrequest]: {
75
76
  ...subrequestState,
76
77
  error: null,
@@ -141,8 +142,18 @@ export default function vocabularies(state = initialState, action = {}) {
141
142
  ...subrequestState,
142
143
  error: null,
143
144
  loaded: true,
144
- loading: !!(vocabState[action.subrequest].loading - 1),
145
- [action.token]: action.result.items[0].title,
145
+ loading: !!(subrequestState.loading - 1),
146
+ ...(action.token && {
147
+ [action.token]: action.result.items[0].title,
148
+ }),
149
+ ...(action.tokens && {
150
+ items: [
151
+ ...action.result.items.map((item) => ({
152
+ label: item.title,
153
+ value: item.token,
154
+ })),
155
+ ],
156
+ }),
146
157
  },
147
158
  },
148
159
  },
package/src/store.js CHANGED
@@ -15,7 +15,7 @@ const configureStore = (initialState, history, apiHelper) => {
15
15
  routerMiddleware(history),
16
16
  crashReporter,
17
17
  thunk,
18
- api(apiHelper),
18
+ ...(apiHelper ? [api(apiHelper)] : []),
19
19
  ...(__CLIENT__
20
20
  ? [save({ states: config.settings.persistentReducers, debounce: 500 })]
21
21
  : []),
package/src/storybook.jsx CHANGED
@@ -1,10 +1,12 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import { createBrowserHistory } from 'history';
3
3
  import React, { Component } from 'react';
4
+ import { Button } from 'semantic-ui-react';
4
5
  import { Provider } from 'react-redux';
5
6
  import { StaticRouter } from 'react-router-dom';
6
7
  import { IntlProvider } from 'react-intl';
7
8
  import { PluggablesProvider } from '@plone/volto/components/manage/Pluggable';
9
+ import { useUndoManager } from '@plone/volto/helpers';
8
10
  import configureStore from 'redux-mock-store';
9
11
  import configureRealStore from '@plone/volto/store';
10
12
 
@@ -612,6 +614,11 @@ const initialState = () => ({
612
614
  items: [],
613
615
  },
614
616
  content: {
617
+ unlock: {
618
+ loaded: false,
619
+ loading: false,
620
+ error: null,
621
+ },
615
622
  create: {
616
623
  loaded: false,
617
624
  loading: false,
@@ -1452,3 +1459,51 @@ export class RealStoreWrapper extends Component {
1452
1459
  );
1453
1460
  }
1454
1461
  }
1462
+
1463
+ export const FormUndoWrapper = ({
1464
+ initialState = {},
1465
+ children,
1466
+ showControls = true,
1467
+ }) => {
1468
+ const [state, setState] = React.useState(initialState);
1469
+
1470
+ const onUndoRedo = React.useCallback(({ state }) => setState(state), []);
1471
+
1472
+ const { doUndo, doRedo, canUndo, canRedo } = useUndoManager(
1473
+ state,
1474
+ onUndoRedo,
1475
+ {
1476
+ maxUndoLevels: 200,
1477
+ },
1478
+ );
1479
+
1480
+ return (
1481
+ <div>
1482
+ <div>{children({ state, onChange: setState })}</div>
1483
+ {showControls && (
1484
+ <div>
1485
+ <Button
1486
+ size="mini"
1487
+ compact
1488
+ className="undo"
1489
+ onClick={() => doUndo()}
1490
+ aria-label="Undo"
1491
+ disabled={!canUndo}
1492
+ >
1493
+ Undo
1494
+ </Button>
1495
+ <Button
1496
+ size="mini"
1497
+ compact
1498
+ className="redo"
1499
+ onClick={() => doRedo()}
1500
+ aria-label="Redo"
1501
+ disabled={!canRedo}
1502
+ >
1503
+ Redo
1504
+ </Button>
1505
+ </div>
1506
+ )}
1507
+ </div>
1508
+ );
1509
+ };
@@ -34,8 +34,8 @@
34
34
  max-width: none;
35
35
 
36
36
  .rc-time-picker-panel-inner {
37
- width: @timePickerWidthNarrow;
38
37
  right: 84px;
38
+ width: @timePickerWidthNarrow;
39
39
  }
40
40
  }
41
41