@plone/volto 14.0.0-alpha.33 → 14.0.0-alpha.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/README.md +4 -1
- package/package.json +1 -1
- package/src/actions/schema/schema.js +4 -2
- package/src/actions/schema/schema.test.js +10 -0
- package/src/actions/vocabularies/vocabularies.js +3 -10
- package/src/actions/vocabularies/vocabularies.test.js +26 -0
- package/src/components/manage/Add/Add.jsx +1 -1
- package/src/components/manage/Blocks/Block/Edit.jsx +6 -1
- package/src/components/manage/Blocks/HeroImageLeft/schema.js +1 -1
- package/src/components/manage/Blocks/Listing/schema.js +2 -0
- package/src/components/manage/Edit/Edit.jsx +4 -1
- package/src/components/manage/Sidebar/ObjectBrowserBody.jsx +1 -1
- package/src/components/manage/Sidebar/SidebarPopup.stories.jsx +42 -0
- package/src/components/manage/Widgets/AlignWidget.jsx +14 -6
- package/src/components/manage/Widgets/AlignWidget.stories.jsx +38 -0
- package/src/components/manage/Widgets/ArrayWidget.stories.jsx +2 -2
- package/src/components/manage/Widgets/CheckboxWidget.jsx +9 -0
- package/src/components/manage/Widgets/CheckboxWidget.stories.jsx +38 -0
- package/src/components/manage/Widgets/DatetimeWidget.jsx +9 -0
- package/src/components/manage/Widgets/DatetimeWidget.stories.jsx +38 -0
- package/src/components/manage/Widgets/EmailWidget.jsx +10 -3
- package/src/components/manage/Widgets/EmailWidget.stories.jsx +38 -0
- package/src/components/manage/Widgets/FileWidget.jsx +18 -0
- package/src/components/manage/Widgets/FileWidget.stories.jsx +38 -0
- package/src/components/manage/Widgets/NumberWidget.jsx +9 -2
- package/src/components/manage/Widgets/NumberWidget.stories.jsx +39 -0
- package/src/components/manage/Widgets/ObjectBrowserWidget.stories.js +1 -1
- package/src/components/manage/Widgets/ObjectListWidget.jsx +26 -0
- package/src/components/manage/Widgets/ObjectListWidget.stories.js +166 -44
- package/src/components/manage/Widgets/ObjectWidget.jsx +4 -10
- package/src/components/manage/Widgets/ObjectWidget.stories.jsx +157 -0
- package/src/components/manage/Widgets/PasswordWidget.jsx +9 -2
- package/src/components/manage/Widgets/PasswordWidget.stories.jsx +38 -0
- package/src/components/manage/Widgets/QueryWidget.jsx +1 -3
- package/src/components/manage/Widgets/QueryWidget.stories.jsx +38 -0
- package/src/components/manage/Widgets/SelectWidget.stories.jsx +1 -1
- package/src/components/manage/Widgets/TextWidget.jsx +4 -3
- package/src/components/manage/Widgets/TextWidget.stories.jsx +38 -0
- package/src/components/manage/Widgets/TextareaWidget.jsx +10 -3
- package/src/components/manage/Widgets/TextareaWidget.stories.jsx +38 -0
- package/src/components/manage/Widgets/UrlWidget.jsx +12 -4
- package/src/components/manage/Widgets/UrlWidget.stories.jsx +38 -0
- package/src/components/manage/Widgets/WysiwygWidget.jsx +11 -3
- package/src/components/manage/Widgets/WysiwygWidget.stories.jsx +41 -0
- package/src/components/theme/Anontools/Anontools.jsx +0 -2
- package/src/components/theme/Anontools/Anontools.stories.jsx +24 -0
- package/src/components/theme/Breadcrumbs/Breadcrumbs.jsx +2 -5
- package/src/components/theme/Breadcrumbs/Breadcrumbs.stories.jsx +30 -0
- package/src/components/theme/Navigation/ContextNavigation.stories.js +27 -29
- package/src/components/theme/Navigation/NavItem.jsx +36 -0
- package/src/components/theme/Navigation/NavItems.jsx +2 -15
- package/src/components/theme/Navigation/Navigation.test.jsx +26 -0
- package/src/components/theme/View/RenderBlocks.jsx +10 -2
- package/src/config/Blocks.jsx +8 -0
- package/src/helpers/Blocks/Blocks.js +45 -3
- package/src/helpers/Blocks/Blocks.test.js +212 -0
- package/src/helpers/Extensions/withBlockExtensions.js +42 -2
- package/src/helpers/Extensions/withBlockSchemaEnhancer.js +77 -3
- package/src/helpers/Url/Url.js +2 -1
- package/src/helpers/Url/Url.test.js +7 -0
- package/src/helpers/Vocabularies/Vocabularies.js +12 -0
- package/src/helpers/index.js +2 -0
- package/src/storybook.jsx +50 -0
- package/src/components/manage/Sidebar/SidebarPopup.stories.mdx +0 -41
- package/src/components/theme/Anontools/Anontools.stories.mdx +0 -18
- package/src/components/theme/Breadcrumbs/Breadcrumbs.stories.mdx +0 -30
|
@@ -14,6 +14,8 @@ import {
|
|
|
14
14
|
nextBlockId,
|
|
15
15
|
previousBlockId,
|
|
16
16
|
visitBlocks,
|
|
17
|
+
applyBlockDefaults,
|
|
18
|
+
applySchemaDefaults,
|
|
17
19
|
} from './Blocks';
|
|
18
20
|
|
|
19
21
|
import config from '@plone/volto/registry';
|
|
@@ -31,6 +33,131 @@ config.blocks.blocksConfig.text = {
|
|
|
31
33
|
(data.text?.blocks?.length === 1 && data.text.blocks[0].text === '');
|
|
32
34
|
return !isEmpty;
|
|
33
35
|
},
|
|
36
|
+
blockSchema: ({ data }) => ({
|
|
37
|
+
fieldsets: [
|
|
38
|
+
{
|
|
39
|
+
id: 'default',
|
|
40
|
+
fields: ['title', 'description', 'nonDefault'],
|
|
41
|
+
title: 'Default',
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
properties: {
|
|
45
|
+
title: {
|
|
46
|
+
default: 'Default title',
|
|
47
|
+
},
|
|
48
|
+
description: {
|
|
49
|
+
default: 'Default description',
|
|
50
|
+
},
|
|
51
|
+
nonDefault: {
|
|
52
|
+
title: 'Non default',
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
}),
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
config.blocks.blocksConfig.enhancedBlock = {
|
|
59
|
+
id: 'enhancedBlock',
|
|
60
|
+
title: 'Text',
|
|
61
|
+
group: 'text',
|
|
62
|
+
restricted: false,
|
|
63
|
+
mostUsed: false,
|
|
64
|
+
blockHasOwnFocusManagement: true,
|
|
65
|
+
blockHasValue: (data) => {
|
|
66
|
+
const isEmpty =
|
|
67
|
+
!data.text ||
|
|
68
|
+
(data.text?.blocks?.length === 1 && data.text.blocks[0].text === '');
|
|
69
|
+
return !isEmpty;
|
|
70
|
+
},
|
|
71
|
+
schemaEnhancer: ({ schema, formData }) => {
|
|
72
|
+
schema.fieldsets[0].fields.push('extra');
|
|
73
|
+
schema.properties.extra = { default: 'Extra value' };
|
|
74
|
+
return schema;
|
|
75
|
+
},
|
|
76
|
+
variations: [
|
|
77
|
+
{
|
|
78
|
+
id: 'firstVariation',
|
|
79
|
+
schemaEnhancer: ({ schema, formData }) => {
|
|
80
|
+
schema.fieldsets[0].fields.push('extraVariationField');
|
|
81
|
+
schema.properties['extraVariationField'] = {
|
|
82
|
+
default: 'Extra variation field',
|
|
83
|
+
};
|
|
84
|
+
return schema;
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
blockSchema: ({ data }) => ({
|
|
89
|
+
fieldsets: [
|
|
90
|
+
{
|
|
91
|
+
id: 'default',
|
|
92
|
+
fields: ['title', 'description', 'nonDefault'],
|
|
93
|
+
title: 'Default',
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
properties: {
|
|
97
|
+
title: {
|
|
98
|
+
default: 'Default title',
|
|
99
|
+
},
|
|
100
|
+
description: {
|
|
101
|
+
default: 'Default description',
|
|
102
|
+
},
|
|
103
|
+
nonDefault: {
|
|
104
|
+
title: 'Non default',
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
}),
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
config.blocks.blocksConfig.enhancedBlockCase2 = {
|
|
111
|
+
id: 'enhancedBlockCase2',
|
|
112
|
+
title: 'Text',
|
|
113
|
+
group: 'text',
|
|
114
|
+
restricted: false,
|
|
115
|
+
mostUsed: false,
|
|
116
|
+
blockHasOwnFocusManagement: true,
|
|
117
|
+
blockHasValue: (data) => {
|
|
118
|
+
const isEmpty =
|
|
119
|
+
!data.text ||
|
|
120
|
+
(data.text?.blocks?.length === 1 && data.text.blocks[0].text === '');
|
|
121
|
+
return !isEmpty;
|
|
122
|
+
},
|
|
123
|
+
schemaEnhancer: ({ schema, formData }) => {
|
|
124
|
+
schema.fieldsets[0].fields.push('extra');
|
|
125
|
+
schema.properties.extra = {
|
|
126
|
+
default: 'Extra value from block schema enhancer',
|
|
127
|
+
};
|
|
128
|
+
return schema;
|
|
129
|
+
},
|
|
130
|
+
variations: [
|
|
131
|
+
{
|
|
132
|
+
id: 'firstVariation',
|
|
133
|
+
schemaEnhancer: ({ schema, formData }) => {
|
|
134
|
+
schema.properties['extra'] = {
|
|
135
|
+
default: 'Extra variation field',
|
|
136
|
+
};
|
|
137
|
+
return schema;
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
blockSchema: ({ data }) => ({
|
|
142
|
+
fieldsets: [
|
|
143
|
+
{
|
|
144
|
+
id: 'default',
|
|
145
|
+
fields: ['title', 'description', 'nonDefault'],
|
|
146
|
+
title: 'Default',
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
properties: {
|
|
150
|
+
title: {
|
|
151
|
+
default: 'Default title',
|
|
152
|
+
},
|
|
153
|
+
description: {
|
|
154
|
+
default: 'Default description',
|
|
155
|
+
},
|
|
156
|
+
nonDefault: {
|
|
157
|
+
title: 'Non default',
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
}),
|
|
34
161
|
};
|
|
35
162
|
|
|
36
163
|
config.settings.defaultBlockType = 'text';
|
|
@@ -361,4 +488,89 @@ describe('Blocks', () => {
|
|
|
361
488
|
expect(a.length).toBe(13);
|
|
362
489
|
});
|
|
363
490
|
});
|
|
491
|
+
|
|
492
|
+
describe('applySchemaDefaults', () => {
|
|
493
|
+
it('Sets data according to schema default values', () => {
|
|
494
|
+
const data = {
|
|
495
|
+
'@type': 'text',
|
|
496
|
+
description: 'already filled',
|
|
497
|
+
};
|
|
498
|
+
const schema = config.blocks.blocksConfig.text.blockSchema({ data });
|
|
499
|
+
expect(applySchemaDefaults({ schema, data })).toEqual({
|
|
500
|
+
'@type': 'text',
|
|
501
|
+
title: 'Default title',
|
|
502
|
+
description: 'already filled',
|
|
503
|
+
});
|
|
504
|
+
});
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
describe('applyBlockDefaults', () => {
|
|
508
|
+
it('Sets data according to schema default values', () => {
|
|
509
|
+
const data = {
|
|
510
|
+
'@type': 'text',
|
|
511
|
+
description: 'already filled',
|
|
512
|
+
};
|
|
513
|
+
expect(applyBlockDefaults({ data })).toEqual({
|
|
514
|
+
'@type': 'text',
|
|
515
|
+
title: 'Default title',
|
|
516
|
+
description: 'already filled',
|
|
517
|
+
});
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
it('Does not do anything if there is no schema for block', () => {
|
|
521
|
+
const data = {
|
|
522
|
+
'@type': 'missing',
|
|
523
|
+
description: 'already filled',
|
|
524
|
+
};
|
|
525
|
+
expect(applyBlockDefaults({ data })).toEqual({
|
|
526
|
+
'@type': 'missing',
|
|
527
|
+
description: 'already filled',
|
|
528
|
+
});
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
it('Supports block schema enhancers', () => {
|
|
532
|
+
const data = {
|
|
533
|
+
'@type': 'enhancedBlock',
|
|
534
|
+
description: 'already filled',
|
|
535
|
+
// variation: 'firstVariation',
|
|
536
|
+
};
|
|
537
|
+
expect(applyBlockDefaults({ data })).toEqual({
|
|
538
|
+
'@type': 'enhancedBlock',
|
|
539
|
+
title: 'Default title',
|
|
540
|
+
description: 'already filled',
|
|
541
|
+
extra: 'Extra value',
|
|
542
|
+
});
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
it('Supports block schema enhancers coming from variations', () => {
|
|
546
|
+
const data = {
|
|
547
|
+
'@type': 'enhancedBlock',
|
|
548
|
+
description: 'already filled',
|
|
549
|
+
variation: 'firstVariation',
|
|
550
|
+
};
|
|
551
|
+
expect(applyBlockDefaults({ data })).toEqual({
|
|
552
|
+
'@type': 'enhancedBlock',
|
|
553
|
+
title: 'Default title',
|
|
554
|
+
description: 'already filled',
|
|
555
|
+
extra: 'Extra value',
|
|
556
|
+
extraVariationField: 'Extra variation field',
|
|
557
|
+
variation: 'firstVariation',
|
|
558
|
+
});
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
it('Block schema enhancers override variations', () => {
|
|
562
|
+
const data = {
|
|
563
|
+
'@type': 'enhancedBlockCase2',
|
|
564
|
+
description: 'already filled',
|
|
565
|
+
variation: 'firstVariation',
|
|
566
|
+
};
|
|
567
|
+
expect(applyBlockDefaults({ data })).toEqual({
|
|
568
|
+
'@type': 'enhancedBlockCase2',
|
|
569
|
+
title: 'Default title',
|
|
570
|
+
description: 'already filled',
|
|
571
|
+
extra: 'Extra value from block schema enhancer',
|
|
572
|
+
variation: 'firstVariation',
|
|
573
|
+
});
|
|
574
|
+
});
|
|
575
|
+
});
|
|
364
576
|
});
|
|
@@ -17,8 +17,40 @@ export function resolveExtension(name, extensions, data) {
|
|
|
17
17
|
return index !== -1 ? extensions[index] : undefined;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
/**
|
|
21
|
+
* A block can declare extensions and variations like:
|
|
22
|
+
*
|
|
23
|
+
* {
|
|
24
|
+
* variations: [
|
|
25
|
+
* {
|
|
26
|
+
* id: "summary",
|
|
27
|
+
* isDefault: true,
|
|
28
|
+
* template: Something
|
|
29
|
+
* }
|
|
30
|
+
* ],
|
|
31
|
+
* extensions: {
|
|
32
|
+
* 'extensionA': {
|
|
33
|
+
* items: [
|
|
34
|
+
* // something similar to variations
|
|
35
|
+
* ]
|
|
36
|
+
* }
|
|
37
|
+
* }
|
|
38
|
+
* }
|
|
39
|
+
*
|
|
40
|
+
* Exactly what an extension and what a variation represent is only up to the
|
|
41
|
+
* block. A block should incorporate these extension mechanisms and it should
|
|
42
|
+
* define what information is needed from them.
|
|
43
|
+
*
|
|
44
|
+
* resolveBlockExtensions will return an object with
|
|
45
|
+
* `{ extensions, resolvedExtensions}`, where:
|
|
46
|
+
*
|
|
47
|
+
* - extensions is the blocksConfig extensions object for that block
|
|
48
|
+
* - resolvedExtensions is an object with
|
|
49
|
+
* `{ variation, <someExtensionA>, <someExtensionB> }` and each of these
|
|
50
|
+
* fields hold the coresponding definition object from the block's
|
|
51
|
+
* configuration.
|
|
52
|
+
*/
|
|
53
|
+
export function resolveBlockExtensions(data) {
|
|
22
54
|
const block_type = data['@type'];
|
|
23
55
|
const { extensions = {}, variations = [] } = config.blocks.blocksConfig[
|
|
24
56
|
block_type
|
|
@@ -43,6 +75,12 @@ export default (WrappedComponent) => (props) => {
|
|
|
43
75
|
resolvedExtensions.variation = variation;
|
|
44
76
|
}
|
|
45
77
|
|
|
78
|
+
return { extensions, resolvedExtensions };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const withBlockExtensions = (WrappedComponent) => (props) => {
|
|
82
|
+
const { data } = props;
|
|
83
|
+
const { extensions, resolvedExtensions } = resolveBlockExtensions(data);
|
|
46
84
|
return (
|
|
47
85
|
<WrappedComponent
|
|
48
86
|
{...resolvedExtensions}
|
|
@@ -51,3 +89,5 @@ export default (WrappedComponent) => (props) => {
|
|
|
51
89
|
/>
|
|
52
90
|
);
|
|
53
91
|
};
|
|
92
|
+
|
|
93
|
+
export default withBlockExtensions;
|
|
@@ -59,6 +59,39 @@ export const addExtensionFieldToSchema = ({
|
|
|
59
59
|
return schema;
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* A generic HOC that provides "schema enhancer functionality" for any custom
|
|
64
|
+
* block extension.
|
|
65
|
+
*
|
|
66
|
+
* This enables blocks to have additional "variations", beyond the usual
|
|
67
|
+
* `variations` field. This function is not directly used by Volto.
|
|
68
|
+
*
|
|
69
|
+
* To be used with a block configuration like:
|
|
70
|
+
*
|
|
71
|
+
* ```
|
|
72
|
+
* {
|
|
73
|
+
* id: 'someBlockId',
|
|
74
|
+
* extensions: {
|
|
75
|
+
* '<someExtensionName>': {
|
|
76
|
+
* items: [
|
|
77
|
+
* {
|
|
78
|
+
* id: 'selectFacet',
|
|
79
|
+
* title: 'Select',
|
|
80
|
+
* view: SelectFacet,
|
|
81
|
+
* isDefault: true,
|
|
82
|
+
* },
|
|
83
|
+
* {
|
|
84
|
+
* id: 'checkboxFacet',
|
|
85
|
+
* title: 'Checkbox',
|
|
86
|
+
* view: CheckboxFacet,
|
|
87
|
+
* isDefault: false,
|
|
88
|
+
* },
|
|
89
|
+
* ]
|
|
90
|
+
* }
|
|
91
|
+
* }
|
|
92
|
+
* }
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
62
95
|
export const withBlockSchemaEnhancer = (
|
|
63
96
|
FormComponent,
|
|
64
97
|
extensionName = 'vendor',
|
|
@@ -111,6 +144,36 @@ export const withBlockSchemaEnhancer = (
|
|
|
111
144
|
return <FormComponent {...props} schema={schema} />;
|
|
112
145
|
};
|
|
113
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Apply block variation schema enhancers to the provided schema, using block
|
|
149
|
+
* information from the provided block data (as `formData`).
|
|
150
|
+
*
|
|
151
|
+
* Blocks can be enhanced with variations declared like:
|
|
152
|
+
*
|
|
153
|
+
* ```
|
|
154
|
+
* {
|
|
155
|
+
* id: 'searchBlock',
|
|
156
|
+
* schemaEnhancer: ({schema, formData, intl}) => schema,
|
|
157
|
+
* variations: [
|
|
158
|
+
* {
|
|
159
|
+
* id: 'facetsRightSide',
|
|
160
|
+
* title: 'Facets on right side',
|
|
161
|
+
* view: RightColumnFacets,
|
|
162
|
+
* isDefault: true,
|
|
163
|
+
* },
|
|
164
|
+
* {
|
|
165
|
+
* id: 'facetsLeftSide',
|
|
166
|
+
* title: 'Facets on left side',
|
|
167
|
+
* view: LeftColumnFacets,
|
|
168
|
+
* isDefault: false,
|
|
169
|
+
* schemaEnhancer: ({schema, formData, intl}) => schema,
|
|
170
|
+
* },
|
|
171
|
+
* ],
|
|
172
|
+
*
|
|
173
|
+
* ```
|
|
174
|
+
* Notice that each variation can declare an option schema enhancer, and each
|
|
175
|
+
* block supports an optional `schemaEnhancer` function.
|
|
176
|
+
*/
|
|
114
177
|
export const applySchemaEnhancer = ({
|
|
115
178
|
schema: originalSchema,
|
|
116
179
|
formData,
|
|
@@ -123,11 +186,15 @@ export const applySchemaEnhancer = ({
|
|
|
123
186
|
const variations = blocks?.blocksConfig[blockType]?.variations || [];
|
|
124
187
|
|
|
125
188
|
if (variations.length === 0) {
|
|
126
|
-
// No variations present but
|
|
127
|
-
//
|
|
189
|
+
// No variations present but we finalize the schema with a schemaEnhancer
|
|
190
|
+
// in the block config (if present)
|
|
128
191
|
schemaEnhancer = blocks.blocksConfig?.[blockType]?.schemaEnhancer;
|
|
129
192
|
if (schemaEnhancer)
|
|
130
|
-
schema = schemaEnhancer({
|
|
193
|
+
schema = schemaEnhancer({
|
|
194
|
+
schema: cloneDeep(originalSchema),
|
|
195
|
+
formData,
|
|
196
|
+
intl,
|
|
197
|
+
});
|
|
131
198
|
return schema || originalSchema;
|
|
132
199
|
}
|
|
133
200
|
|
|
@@ -148,6 +215,13 @@ export const applySchemaEnhancer = ({
|
|
|
148
215
|
return schema || originalSchema;
|
|
149
216
|
};
|
|
150
217
|
|
|
218
|
+
/**
|
|
219
|
+
* A HOC that enhances the incoming schema prop with block variations support
|
|
220
|
+
* by:
|
|
221
|
+
*
|
|
222
|
+
* - applies the selected variation's schema enhancer
|
|
223
|
+
* - adds the variation selection input (as a choice widget)
|
|
224
|
+
*/
|
|
151
225
|
export const withVariationSchemaEnhancer = (FormComponent) => (props) => {
|
|
152
226
|
const { formData, schema: originalSchema } = props;
|
|
153
227
|
const intl = useIntl();
|
package/src/helpers/Url/Url.js
CHANGED
|
@@ -176,7 +176,8 @@ export function isInternalURL(url) {
|
|
|
176
176
|
return (
|
|
177
177
|
url &&
|
|
178
178
|
(url.indexOf(settings.publicURL) !== -1 ||
|
|
179
|
-
|
|
179
|
+
(settings.internalApiPath &&
|
|
180
|
+
url.indexOf(settings.internalApiPath) !== -1) ||
|
|
180
181
|
url.indexOf(settings.apiPath) !== -1 ||
|
|
181
182
|
url.charAt(0) === '/' ||
|
|
182
183
|
url.charAt(0) === '.' ||
|
|
@@ -171,6 +171,13 @@ describe('Url', () => {
|
|
|
171
171
|
expect(isInternalURL(href)).toBe(true);
|
|
172
172
|
settings.internalApiPath = saved;
|
|
173
173
|
});
|
|
174
|
+
it('tells if an URL is external if settings.internalApiPath is empty', () => {
|
|
175
|
+
const href = `http://google.com`;
|
|
176
|
+
const saved = settings.internalApiPath;
|
|
177
|
+
settings.internalApiPath = '';
|
|
178
|
+
expect(isInternalURL(href)).toBe(false);
|
|
179
|
+
settings.internalApiPath = saved;
|
|
180
|
+
});
|
|
174
181
|
it('tells if an URL is internal if it is an anchor', () => {
|
|
175
182
|
const href = '#anchor';
|
|
176
183
|
expect(isInternalURL(href)).toBe(true);
|
|
@@ -53,6 +53,18 @@ export function getVocabFromItems(props) {
|
|
|
53
53
|
: false;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Get vocabulary given a URL (coming from a Schema) or from a vocabulary name.
|
|
58
|
+
* @function getVocabName
|
|
59
|
+
* @param {string} vocabNameOrURL
|
|
60
|
+
* @returns {string} Vocabulary name
|
|
61
|
+
*/
|
|
62
|
+
export function getVocabName(vocabNameOrURL) {
|
|
63
|
+
return vocabNameOrURL.indexOf('@vocabularies') > -1
|
|
64
|
+
? vocabNameOrURL.split('@vocabularies/')[1]
|
|
65
|
+
: vocabNameOrURL;
|
|
66
|
+
}
|
|
67
|
+
|
|
56
68
|
/**
|
|
57
69
|
* Get Fields vocabulary
|
|
58
70
|
* @function getFieldsVocabulary
|
package/src/helpers/index.js
CHANGED
|
@@ -49,6 +49,8 @@ export {
|
|
|
49
49
|
mutateBlock,
|
|
50
50
|
nextBlockId,
|
|
51
51
|
previousBlockId,
|
|
52
|
+
applyBlockDefaults,
|
|
53
|
+
applySchemaDefaults,
|
|
52
54
|
} from '@plone/volto/helpers/Blocks/Blocks';
|
|
53
55
|
export BodyClass from '@plone/volto/helpers/BodyClass/BodyClass';
|
|
54
56
|
export ScrollToTop from '@plone/volto/helpers/ScrollToTop/ScrollToTop';
|
package/src/storybook.jsx
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import PropTypes from 'prop-types';
|
|
2
|
+
import { createBrowserHistory } from 'history';
|
|
2
3
|
import React, { Component } from 'react';
|
|
3
4
|
import { Provider } from 'react-redux';
|
|
4
5
|
import { StaticRouter } from 'react-router-dom';
|
|
5
6
|
import { IntlProvider } from 'react-intl';
|
|
6
7
|
import { PluggablesProvider } from '@plone/volto/components/manage/Pluggable';
|
|
7
8
|
import configureStore from 'redux-mock-store';
|
|
9
|
+
import configureRealStore from '@plone/volto/store';
|
|
8
10
|
|
|
9
11
|
const initialState = () => ({
|
|
10
12
|
router: {
|
|
@@ -1350,6 +1352,7 @@ const initialState = () => ({
|
|
|
1350
1352
|
toolbar: {
|
|
1351
1353
|
expanded: true,
|
|
1352
1354
|
},
|
|
1355
|
+
lazyLibraries: {},
|
|
1353
1356
|
});
|
|
1354
1357
|
|
|
1355
1358
|
/**
|
|
@@ -1402,3 +1405,50 @@ export default class Wrapper extends Component {
|
|
|
1402
1405
|
);
|
|
1403
1406
|
}
|
|
1404
1407
|
}
|
|
1408
|
+
|
|
1409
|
+
export class RealStoreWrapper extends Component {
|
|
1410
|
+
/**
|
|
1411
|
+
* Property types.
|
|
1412
|
+
* @property {Object} propTypes Property types.
|
|
1413
|
+
* @static
|
|
1414
|
+
*/
|
|
1415
|
+
static propTypes = {
|
|
1416
|
+
pathname: PropTypes.string,
|
|
1417
|
+
anonymous: PropTypes.bool,
|
|
1418
|
+
customStore: PropTypes.object,
|
|
1419
|
+
};
|
|
1420
|
+
|
|
1421
|
+
customState() {
|
|
1422
|
+
let state = initialState();
|
|
1423
|
+
if (this.props.anonymous) {
|
|
1424
|
+
state.userSession.token = null;
|
|
1425
|
+
}
|
|
1426
|
+
if (this.props.customStore) {
|
|
1427
|
+
state = {
|
|
1428
|
+
...state,
|
|
1429
|
+
...this.props.customStore,
|
|
1430
|
+
};
|
|
1431
|
+
}
|
|
1432
|
+
return state;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
render() {
|
|
1436
|
+
// If thunk is not included there's a complaint about async actions
|
|
1437
|
+
const history = createBrowserHistory();
|
|
1438
|
+
const store = configureRealStore(this.customState(), history);
|
|
1439
|
+
|
|
1440
|
+
return (
|
|
1441
|
+
<Provider store={store}>
|
|
1442
|
+
<PluggablesProvider>
|
|
1443
|
+
<IntlProvider locale="en">
|
|
1444
|
+
<StaticRouter location={this.props.location}>
|
|
1445
|
+
<div className="volto-storybook-container">
|
|
1446
|
+
{this.props.children}
|
|
1447
|
+
</div>
|
|
1448
|
+
</StaticRouter>
|
|
1449
|
+
</IntlProvider>
|
|
1450
|
+
</PluggablesProvider>
|
|
1451
|
+
</Provider>
|
|
1452
|
+
);
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { Meta, Story, Canvas, ArgsTable } from '@storybook/addon-docs/blocks';
|
|
2
|
-
import SidebarPopup from './SidebarPopup';
|
|
3
|
-
|
|
4
|
-
<Meta
|
|
5
|
-
title="SidebarPopup"
|
|
6
|
-
argTypes={{
|
|
7
|
-
open: { control: 'boolean' },
|
|
8
|
-
close: { control: 'boolean' },
|
|
9
|
-
}}
|
|
10
|
-
/>
|
|
11
|
-
|
|
12
|
-
# SidebarPopup
|
|
13
|
-
|
|
14
|
-
```jsx static
|
|
15
|
-
<SidebarPopup open={true}>Sidebar content</SidebarPopup>
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
export const CustomSidebarPopup = (args) => (
|
|
19
|
-
<SidebarPopup {...args}>
|
|
20
|
-
<div style={{ padding: '1em' }}>
|
|
21
|
-
<h1>What Is Volto</h1>
|
|
22
|
-
<p>
|
|
23
|
-
Volto is a React-based frontend for content management systems,
|
|
24
|
-
currently supporting three backend implementations: Plone, Guillotina
|
|
25
|
-
and a NodeJS reference implementation.
|
|
26
|
-
</p>
|
|
27
|
-
<p>
|
|
28
|
-
Plone is a powerful, flexible Content Management Solution that is easy
|
|
29
|
-
to install, use and extend..
|
|
30
|
-
</p>
|
|
31
|
-
</div>
|
|
32
|
-
</SidebarPopup>
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
<Story name="SidebarPopup" args={{ open: true }}>
|
|
36
|
-
{CustomSidebarPopup.bind({})}
|
|
37
|
-
</Story>
|
|
38
|
-
|
|
39
|
-
## Props
|
|
40
|
-
|
|
41
|
-
<ArgsTable of={SidebarPopup} />
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { Meta, Story, Canvas, ArgsTable } from '@storybook/addon-docs/blocks';
|
|
2
|
-
import { Anontools as AnontoolsComponent } from './Anontools';
|
|
3
|
-
|
|
4
|
-
<Meta title="Anontools" />
|
|
5
|
-
|
|
6
|
-
# Anontools
|
|
7
|
-
|
|
8
|
-
With `MDX` we can define a story for `Breadcrumbs` right in the middle of our
|
|
9
|
-
markdown documentation. Use the `args` for defining Storybook controls handlers.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export const Anontools = (args) => <AnontoolsComponent userSession={{ token: null }} content={{ '@id': 'myid' } } />;
|
|
13
|
-
|
|
14
|
-
<Story name="Anontools">{Anontools.bind({})}</Story>
|
|
15
|
-
|
|
16
|
-
# Props
|
|
17
|
-
|
|
18
|
-
<ArgsTable of={AnontoolsComponent} />
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { Meta, Story, Canvas, ArgsTable } from '@storybook/addon-docs/blocks';
|
|
2
|
-
import { BreadcrumbsComponent } from './Breadcrumbs';
|
|
3
|
-
import { injectIntl } from 'react-intl';
|
|
4
|
-
|
|
5
|
-
<Meta title="Breadcrumbs" />
|
|
6
|
-
|
|
7
|
-
# Breadcrumbs
|
|
8
|
-
|
|
9
|
-
With `MDX` we can define a story for `Breadcrumbs` right in the middle of our
|
|
10
|
-
markdown documentation. Use the `args` for defining Storybook controls handlers.
|
|
11
|
-
|
|
12
|
-
export const Breadcrumbs = (args) => (
|
|
13
|
-
<BreadcrumbsComponent
|
|
14
|
-
pathname=""
|
|
15
|
-
items={[
|
|
16
|
-
{
|
|
17
|
-
'@id': 'https://volto.kitconcept.com/api/Members',
|
|
18
|
-
title: 'Users',
|
|
19
|
-
},
|
|
20
|
-
]}
|
|
21
|
-
getBreadcrumbs={() => {}}
|
|
22
|
-
{...args}
|
|
23
|
-
/>
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
<Story name="Breadcrumbs">{injectIntl(Breadcrumbs).bind({})}</Story>
|
|
27
|
-
|
|
28
|
-
# Props
|
|
29
|
-
|
|
30
|
-
<ArgsTable of={BreadcrumbsComponent} />
|