@eeacms/volto-eea-website-theme 3.5.4 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -21
- package/package.json +1 -1
- package/src/components/manage/Blocks/Title/variations/WebReport.test.jsx +134 -0
- package/src/components/theme/Widgets/ContributorsViewWidget.jsx +23 -0
- package/src/components/theme/Widgets/ContributorsViewWidget.test.jsx +60 -0
- package/src/components/theme/Widgets/CreatorsViewWidget.jsx +23 -0
- package/src/components/theme/Widgets/CreatorsViewWidget.test.jsx +60 -0
- package/src/components/theme/Widgets/ImageViewWidget.jsx +3 -0
- package/src/components/theme/Widgets/UserSelectWidget.jsx +331 -0
- package/src/components/theme/Widgets/UserSelectWidget.test.jsx +255 -0
- package/src/customizations/volto/actions/vocabularies/vocabularies.js +89 -0
- package/src/customizations/volto/actions/vocabularies/vocabularies.js.diff +32 -0
- package/src/customizations/volto/actions/vocabularies/vocabularies.js.md +4 -0
- package/src/customizations/volto/actions/vocabularies/vocabularies.test.js +57 -0
- package/src/customizations/volto/actions/vocabularies/vocabularies.test.js.diff +45 -0
- package/src/customizations/volto/components/manage/Diff/DiffField.diff +150 -0
- package/src/customizations/volto/components/manage/Diff/DiffField.jsx +387 -0
- package/src/customizations/volto/components/manage/Diff/DiffField.txt +1 -0
- package/src/hocs/withRootNavigation.test.jsx +70 -0
- package/src/index.js +14 -3
@@ -0,0 +1,57 @@
|
|
1
|
+
import { getVocabulary } from './vocabularies';
|
2
|
+
import { GET_VOCABULARY } from '@plone/volto/constants/ActionTypes';
|
3
|
+
|
4
|
+
describe('Vocabularies actions', () => {
|
5
|
+
describe('getVocabulary', () => {
|
6
|
+
it('should create an action to get a vocabulary', () => {
|
7
|
+
const vocabNameOrURL = 'plone.app.vocabularies.Keywords';
|
8
|
+
const query = 'john';
|
9
|
+
const action = getVocabulary({ vocabNameOrURL, query });
|
10
|
+
|
11
|
+
expect(action.type).toEqual(GET_VOCABULARY);
|
12
|
+
expect(action.vocabulary).toEqual(vocabNameOrURL);
|
13
|
+
expect(action.request.op).toEqual('get');
|
14
|
+
expect(action.request.path).toEqual(
|
15
|
+
`/@vocabularies/${vocabNameOrURL}?b_start=0&title=${query}`,
|
16
|
+
);
|
17
|
+
});
|
18
|
+
it('should create an action to get a vocabulary if a URL is passed', () => {
|
19
|
+
const vocabNameOrURL =
|
20
|
+
'http://localhost:3000/@vocabularies/plone.app.vocabularies.Keywords';
|
21
|
+
const query = 'john';
|
22
|
+
const action = getVocabulary({ vocabNameOrURL, query });
|
23
|
+
|
24
|
+
expect(action.type).toEqual(GET_VOCABULARY);
|
25
|
+
expect(action.vocabulary).toEqual(vocabNameOrURL);
|
26
|
+
expect(action.request.op).toEqual('get');
|
27
|
+
expect(action.request.path).toEqual(
|
28
|
+
`/@vocabularies/plone.app.vocabularies.Keywords?b_start=0&title=${query}`,
|
29
|
+
);
|
30
|
+
});
|
31
|
+
it('should create an action to get a vocabulary if a URL with path is passed', () => {
|
32
|
+
const vocabNameOrURL =
|
33
|
+
'http://localhost:3000/de/foo/bar/@vocabularies/plone.app.vocabularies.Keywords';
|
34
|
+
const query = 'john';
|
35
|
+
const action = getVocabulary({ vocabNameOrURL, query });
|
36
|
+
|
37
|
+
expect(action.type).toEqual(GET_VOCABULARY);
|
38
|
+
expect(action.vocabulary).toEqual(vocabNameOrURL);
|
39
|
+
expect(action.request.op).toEqual('get');
|
40
|
+
expect(action.request.path).toEqual(
|
41
|
+
`/de/foo/bar/@vocabularies/plone.app.vocabularies.Keywords?b_start=0&title=${query}`,
|
42
|
+
);
|
43
|
+
});
|
44
|
+
it('should create an action to get a vocabulary if an b_size=-1 is passed', () => {
|
45
|
+
const vocabNameOrURL =
|
46
|
+
'http://localhost:3000/de/foo/bar/@vocabularies/plone.app.vocabularies.Keywords';
|
47
|
+
const action = getVocabulary({ vocabNameOrURL, size: -1 });
|
48
|
+
|
49
|
+
expect(action.type).toEqual(GET_VOCABULARY);
|
50
|
+
expect(action.vocabulary).toEqual(vocabNameOrURL);
|
51
|
+
expect(action.request.op).toEqual('get');
|
52
|
+
expect(action.request.path).toEqual(
|
53
|
+
`/de/foo/bar/@vocabularies/plone.app.vocabularies.Keywords?b_start=0&b_size=-1`,
|
54
|
+
);
|
55
|
+
});
|
56
|
+
});
|
57
|
+
});
|
@@ -0,0 +1,45 @@
|
|
1
|
+
diff --git a/src/customizations/volto/actions/vocabularies/vocabularies.test.js b/src/customizations/volto/actions/vocabularies/vocabularies.test.js
|
2
|
+
index b7deafc..ca4fc8a 100644
|
3
|
+
--- a/src/customizations/volto/actions/vocabularies/vocabularies.test.js
|
4
|
+
+++ b/src/customizations/volto/actions/vocabularies/vocabularies.test.js
|
5
|
+
@@ -17,7 +17,7 @@ describe('Vocabularies actions', () => {
|
6
|
+
});
|
7
|
+
it('should create an action to get a vocabulary if a URL is passed', () => {
|
8
|
+
const vocabNameOrURL =
|
9
|
+
- 'http://localhost:8080/@vocabularies/plone.app.vocabularies.Keywords';
|
10
|
+
+ 'http://localhost:3000/@vocabularies/plone.app.vocabularies.Keywords';
|
11
|
+
const query = 'john';
|
12
|
+
const action = getVocabulary({ vocabNameOrURL, query });
|
13
|
+
|
14
|
+
@@ -30,7 +30,7 @@ describe('Vocabularies actions', () => {
|
15
|
+
});
|
16
|
+
it('should create an action to get a vocabulary if a URL with path is passed', () => {
|
17
|
+
const vocabNameOrURL =
|
18
|
+
- 'http://localhost:8080/de/foo/bar/@vocabularies/plone.app.vocabularies.Keywords';
|
19
|
+
+ 'http://localhost:3000/de/foo/bar/@vocabularies/plone.app.vocabularies.Keywords';
|
20
|
+
const query = 'john';
|
21
|
+
const action = getVocabulary({ vocabNameOrURL, query });
|
22
|
+
|
23
|
+
@@ -38,19 +38,19 @@ describe('Vocabularies actions', () => {
|
24
|
+
expect(action.vocabulary).toEqual(vocabNameOrURL);
|
25
|
+
expect(action.request.op).toEqual('get');
|
26
|
+
expect(action.request.path).toEqual(
|
27
|
+
- `/@vocabularies/plone.app.vocabularies.Keywords?b_start=0&title=${query}`,
|
28
|
+
+ `/de/foo/bar/@vocabularies/plone.app.vocabularies.Keywords?b_start=0&title=${query}`,
|
29
|
+
);
|
30
|
+
});
|
31
|
+
it('should create an action to get a vocabulary if an b_size=-1 is passed', () => {
|
32
|
+
const vocabNameOrURL =
|
33
|
+
- 'http://localhost:8080/de/foo/bar/@vocabularies/plone.app.vocabularies.Keywords';
|
34
|
+
+ 'http://localhost:3000/de/foo/bar/@vocabularies/plone.app.vocabularies.Keywords';
|
35
|
+
const action = getVocabulary({ vocabNameOrURL, size: -1 });
|
36
|
+
|
37
|
+
expect(action.type).toEqual(GET_VOCABULARY);
|
38
|
+
expect(action.vocabulary).toEqual(vocabNameOrURL);
|
39
|
+
expect(action.request.op).toEqual('get');
|
40
|
+
expect(action.request.path).toEqual(
|
41
|
+
- `/@vocabularies/plone.app.vocabularies.Keywords?b_start=0&b_size=-1`,
|
42
|
+
+ `/de/foo/bar/@vocabularies/plone.app.vocabularies.Keywords?b_start=0&b_size=-1`,
|
43
|
+
);
|
44
|
+
});
|
45
|
+
});
|
@@ -0,0 +1,150 @@
|
|
1
|
+
diff --git a/src/customizations/volto/components/manage/Diff/DiffField.jsx b/src/customizations/volto/components/manage/Diff/DiffField.jsx
|
2
|
+
index a9bad2a..5d306e5 100644
|
3
|
+
--- a/src/customizations/volto/components/manage/Diff/DiffField.jsx
|
4
|
+
+++ b/src/customizations/volto/components/manage/Diff/DiffField.jsx
|
5
|
+
@@ -135,6 +135,17 @@ const formatDiffPart = (part, value, side) => {
|
6
|
+
}
|
7
|
+
};
|
8
|
+
|
9
|
+
+const getWidgetByBehavior = (behavior) =>
|
10
|
+
+ config.widgets.views.behavior?.[behavior] || null;
|
11
|
+
+
|
12
|
+
+const getWidgetByFactory = (factory) =>
|
13
|
+
+ config.widgets.views.factory?.[factory] || null;
|
14
|
+
+
|
15
|
+
+const getDefaultWidget =
|
16
|
+
+ () =>
|
17
|
+
+ ({ diff }) =>
|
18
|
+
+ diff;
|
19
|
+
+
|
20
|
+
/**
|
21
|
+
* Diff field component.
|
22
|
+
* @function DiffField
|
23
|
+
@@ -164,8 +175,11 @@ const DiffField = ({
|
24
|
+
splitWords(String(twoStr)),
|
25
|
+
);
|
26
|
+
};
|
27
|
+
-
|
28
|
+
let parts, oneArray, twoArray;
|
29
|
+
+ const Widget =
|
30
|
+
+ getWidgetByBehavior(schema.behavior) ||
|
31
|
+
+ getWidgetByFactory(schema.factory) ||
|
32
|
+
+ getDefaultWidget();
|
33
|
+
if (schema.widget) {
|
34
|
+
switch (schema.widget) {
|
35
|
+
case 'richtext':
|
36
|
+
@@ -272,33 +286,49 @@ const DiffField = ({
|
37
|
+
{view === 'split' && (
|
38
|
+
<Grid.Row>
|
39
|
+
<Grid.Column width={6} verticalAlign="top">
|
40
|
+
- <span
|
41
|
+
- dangerouslySetInnerHTML={{
|
42
|
+
- __html: join(
|
43
|
+
- map(parts, (part) => {
|
44
|
+
- let combined = (part.value || []).reduce((acc, value) => {
|
45
|
+
- return acc + formatDiffPart(part, value, 'left');
|
46
|
+
- }, '');
|
47
|
+
- return combined;
|
48
|
+
- }),
|
49
|
+
- '',
|
50
|
+
- ),
|
51
|
+
- }}
|
52
|
+
+ <Widget
|
53
|
+
+ value={one}
|
54
|
+
+ diff={
|
55
|
+
+ <span
|
56
|
+
+ dangerouslySetInnerHTML={{
|
57
|
+
+ __html: join(
|
58
|
+
+ map(parts, (part) => {
|
59
|
+
+ let combined = (part.value || []).reduce(
|
60
|
+
+ (acc, value) => {
|
61
|
+
+ return acc + formatDiffPart(part, value, 'left');
|
62
|
+
+ },
|
63
|
+
+ '',
|
64
|
+
+ );
|
65
|
+
+ return combined;
|
66
|
+
+ }),
|
67
|
+
+ '',
|
68
|
+
+ ),
|
69
|
+
+ }}
|
70
|
+
+ />
|
71
|
+
+ }
|
72
|
+
/>
|
73
|
+
</Grid.Column>
|
74
|
+
<Grid.Column width={6} verticalAlign="top">
|
75
|
+
- <span
|
76
|
+
- dangerouslySetInnerHTML={{
|
77
|
+
- __html: join(
|
78
|
+
- map(parts, (part) => {
|
79
|
+
- let combined = (part.value || []).reduce((acc, value) => {
|
80
|
+
- return acc + formatDiffPart(part, value, 'right');
|
81
|
+
- }, '');
|
82
|
+
- return combined;
|
83
|
+
- }),
|
84
|
+
- '',
|
85
|
+
- ),
|
86
|
+
- }}
|
87
|
+
+ <Widget
|
88
|
+
+ value={two}
|
89
|
+
+ diff={
|
90
|
+
+ <span
|
91
|
+
+ dangerouslySetInnerHTML={{
|
92
|
+
+ __html: join(
|
93
|
+
+ map(parts, (part) => {
|
94
|
+
+ let combined = (part.value || []).reduce(
|
95
|
+
+ (acc, value) => {
|
96
|
+
+ return acc + formatDiffPart(part, value, 'right');
|
97
|
+
+ },
|
98
|
+
+ '',
|
99
|
+
+ );
|
100
|
+
+ return combined;
|
101
|
+
+ }),
|
102
|
+
+ '',
|
103
|
+
+ ),
|
104
|
+
+ }}
|
105
|
+
+ />
|
106
|
+
+ }
|
107
|
+
/>
|
108
|
+
</Grid.Column>
|
109
|
+
</Grid.Row>
|
110
|
+
@@ -306,18 +336,28 @@ const DiffField = ({
|
111
|
+
{view === 'unified' && (
|
112
|
+
<Grid.Row>
|
113
|
+
<Grid.Column width={16} verticalAlign="top">
|
114
|
+
- <span
|
115
|
+
- dangerouslySetInnerHTML={{
|
116
|
+
- __html: join(
|
117
|
+
- map(parts, (part) => {
|
118
|
+
- let combined = (part.value || []).reduce((acc, value) => {
|
119
|
+
- return acc + formatDiffPart(part, value, 'unified');
|
120
|
+
- }, '');
|
121
|
+
- return combined;
|
122
|
+
- }),
|
123
|
+
- '',
|
124
|
+
- ),
|
125
|
+
- }}
|
126
|
+
+ <Widget
|
127
|
+
+ value={two}
|
128
|
+
+ one={one}
|
129
|
+
+ two={two}
|
130
|
+
+ diff={
|
131
|
+
+ <span
|
132
|
+
+ dangerouslySetInnerHTML={{
|
133
|
+
+ __html: join(
|
134
|
+
+ map(parts, (part) => {
|
135
|
+
+ let combined = (part.value || []).reduce(
|
136
|
+
+ (acc, value) => {
|
137
|
+
+ return acc + formatDiffPart(part, value, 'unified');
|
138
|
+
+ },
|
139
|
+
+ '',
|
140
|
+
+ );
|
141
|
+
+ return combined;
|
142
|
+
+ }),
|
143
|
+
+ '',
|
144
|
+
+ ),
|
145
|
+
+ }}
|
146
|
+
+ />
|
147
|
+
+ }
|
148
|
+
/>
|
149
|
+
</Grid.Column>
|
150
|
+
</Grid.Row>
|
@@ -0,0 +1,387 @@
|
|
1
|
+
/**
|
2
|
+
* Diff field component.
|
3
|
+
* @module components/manage/Diff/DiffField
|
4
|
+
*/
|
5
|
+
|
6
|
+
import React from 'react';
|
7
|
+
import { join, map } from 'lodash';
|
8
|
+
import PropTypes from 'prop-types';
|
9
|
+
import { Grid } from 'semantic-ui-react';
|
10
|
+
import ReactDOMServer from 'react-dom/server';
|
11
|
+
import { Provider } from 'react-intl-redux';
|
12
|
+
import { createBrowserHistory } from 'history';
|
13
|
+
import { ConnectedRouter } from 'connected-react-router';
|
14
|
+
import { useSelector } from 'react-redux';
|
15
|
+
import config from '@plone/volto/registry';
|
16
|
+
import { Api } from '@plone/volto/helpers';
|
17
|
+
import configureStore from '@plone/volto/store';
|
18
|
+
import { RenderBlocks } from '@plone/volto/components';
|
19
|
+
import { serializeNodes } from '@plone/volto-slate/editor/render';
|
20
|
+
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
|
21
|
+
|
22
|
+
const isHtmlTag = (str) => {
|
23
|
+
// Match complete HTML tags, including:
|
24
|
+
// 1. Opening tags like <div>, <img src="example" />, <svg>...</svg>
|
25
|
+
// 2. Self-closing tags like <img />, <br />
|
26
|
+
// 3. Closing tags like </div>
|
27
|
+
return /^<([a-zA-Z]+[0-9]*)\b[^>]*>|^<\/([a-zA-Z]+[0-9]*)\b[^>]*>$|^<([a-zA-Z]+[0-9]*)\b[^>]*\/>$/.test(
|
28
|
+
str,
|
29
|
+
);
|
30
|
+
};
|
31
|
+
|
32
|
+
const splitWords = (str) => {
|
33
|
+
if (typeof str !== 'string') return str;
|
34
|
+
if (!str) return [];
|
35
|
+
|
36
|
+
const result = [];
|
37
|
+
let currentWord = '';
|
38
|
+
let insideTag = false;
|
39
|
+
let insideSpecialTag = false;
|
40
|
+
let tagBuffer = '';
|
41
|
+
|
42
|
+
// Special tags that should not be split (e.g., <img />, <svg> ... </svg>)
|
43
|
+
const specialTags = ['img', 'svg'];
|
44
|
+
|
45
|
+
for (let i = 0; i < str.length; i++) {
|
46
|
+
const char = str[i];
|
47
|
+
|
48
|
+
// Start of an HTML tag
|
49
|
+
if (char === '<') {
|
50
|
+
if (currentWord) {
|
51
|
+
result.push(currentWord); // Push text before the tag
|
52
|
+
currentWord = '';
|
53
|
+
}
|
54
|
+
insideTag = true;
|
55
|
+
tagBuffer += char;
|
56
|
+
}
|
57
|
+
// End of an HTML tag
|
58
|
+
else if (char === '>') {
|
59
|
+
tagBuffer += char;
|
60
|
+
insideTag = false;
|
61
|
+
|
62
|
+
// Check if the tagBuffer contains a special tag
|
63
|
+
const tagNameMatch = tagBuffer.match(/^<\/?([a-zA-Z]+[0-9]*)\b/);
|
64
|
+
if (tagNameMatch && specialTags.includes(tagNameMatch[1])) {
|
65
|
+
insideSpecialTag =
|
66
|
+
tagNameMatch[0].startsWith('<') && !tagNameMatch[0].startsWith('</');
|
67
|
+
result.push(tagBuffer); // Push the complete special tag as one unit
|
68
|
+
tagBuffer = '';
|
69
|
+
continue;
|
70
|
+
}
|
71
|
+
|
72
|
+
result.push(tagBuffer); // Push the complete tag
|
73
|
+
tagBuffer = '';
|
74
|
+
}
|
75
|
+
// Inside the tag or special tag
|
76
|
+
else if (insideTag || insideSpecialTag) {
|
77
|
+
tagBuffer += char;
|
78
|
+
}
|
79
|
+
// Space outside of tags - push current word
|
80
|
+
else if (char === ' ' && !insideTag && !insideSpecialTag) {
|
81
|
+
if (currentWord) {
|
82
|
+
result.push(currentWord);
|
83
|
+
currentWord = '';
|
84
|
+
}
|
85
|
+
result.push(' ');
|
86
|
+
} else if (
|
87
|
+
char === ',' &&
|
88
|
+
i < str.length - 1 &&
|
89
|
+
str[i + 1] !== ' ' &&
|
90
|
+
!insideTag &&
|
91
|
+
!insideSpecialTag
|
92
|
+
) {
|
93
|
+
if (currentWord) {
|
94
|
+
result.push(currentWord + char);
|
95
|
+
currentWord = '';
|
96
|
+
}
|
97
|
+
result.push(' ');
|
98
|
+
}
|
99
|
+
// Accumulate characters outside of tags
|
100
|
+
else {
|
101
|
+
currentWord += char;
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
// Push any remaining text
|
106
|
+
if (currentWord) {
|
107
|
+
result.push(currentWord);
|
108
|
+
}
|
109
|
+
if (tagBuffer) {
|
110
|
+
result.push(tagBuffer); // Push remaining tagBuffer
|
111
|
+
}
|
112
|
+
|
113
|
+
return result;
|
114
|
+
};
|
115
|
+
|
116
|
+
const formatDiffPart = (part, value, side) => {
|
117
|
+
if (!isHtmlTag(value)) {
|
118
|
+
if (part.removed && (side === 'left' || side === 'unified')) {
|
119
|
+
return `<span class="deletion">${value}</span>`;
|
120
|
+
} else if (part.removed) return '';
|
121
|
+
else if (part.added && (side === 'right' || side === 'unified')) {
|
122
|
+
return `<span class="addition">${value}</span>`;
|
123
|
+
} else if (part.added) return '';
|
124
|
+
return value;
|
125
|
+
} else {
|
126
|
+
if (side === 'unified' && part.added) return value;
|
127
|
+
else if (side === 'unified' && part.removed) return '';
|
128
|
+
if (part.removed && side === 'left') {
|
129
|
+
return value;
|
130
|
+
} else if (part.removed) return '';
|
131
|
+
else if (part.added && side === 'right') {
|
132
|
+
return value;
|
133
|
+
} else if (part.added) return '';
|
134
|
+
return value;
|
135
|
+
}
|
136
|
+
};
|
137
|
+
|
138
|
+
const getWidgetByBehavior = (behavior) =>
|
139
|
+
config.widgets.views.behavior?.[behavior] || null;
|
140
|
+
|
141
|
+
const getWidgetByFactory = (factory) =>
|
142
|
+
config.widgets.views.factory?.[factory] || null;
|
143
|
+
|
144
|
+
const getDefaultWidget =
|
145
|
+
() =>
|
146
|
+
({ diff }) =>
|
147
|
+
diff;
|
148
|
+
|
149
|
+
/**
|
150
|
+
* Diff field component.
|
151
|
+
* @function DiffField
|
152
|
+
* @param {*} one Field one
|
153
|
+
* @param {*} two Field two
|
154
|
+
* @param {Object} schema Field schema
|
155
|
+
* @returns {string} Markup of the component.
|
156
|
+
*/
|
157
|
+
|
158
|
+
const DiffField = ({
|
159
|
+
one,
|
160
|
+
two,
|
161
|
+
contentOne,
|
162
|
+
contentTwo,
|
163
|
+
view,
|
164
|
+
schema,
|
165
|
+
diffLib,
|
166
|
+
}) => {
|
167
|
+
const language = useSelector((state) => state.intl.locale);
|
168
|
+
const readable_date_format = {
|
169
|
+
dateStyle: 'full',
|
170
|
+
timeStyle: 'short',
|
171
|
+
};
|
172
|
+
const diffWords = (oneStr, twoStr) => {
|
173
|
+
return diffLib.diffArrays(
|
174
|
+
splitWords(String(oneStr)),
|
175
|
+
splitWords(String(twoStr)),
|
176
|
+
);
|
177
|
+
};
|
178
|
+
let parts, oneArray, twoArray;
|
179
|
+
const Widget =
|
180
|
+
getWidgetByBehavior(schema.behavior) ||
|
181
|
+
getWidgetByFactory(schema.factory) ||
|
182
|
+
getDefaultWidget();
|
183
|
+
if (schema.widget) {
|
184
|
+
switch (schema.widget) {
|
185
|
+
case 'richtext':
|
186
|
+
parts = diffWords(one?.data, two?.data);
|
187
|
+
break;
|
188
|
+
case 'datetime':
|
189
|
+
parts = diffWords(
|
190
|
+
new Intl.DateTimeFormat(language, readable_date_format)
|
191
|
+
.format(new Date(one))
|
192
|
+
.replace('\u202F', ' '),
|
193
|
+
new Intl.DateTimeFormat(language, readable_date_format)
|
194
|
+
.format(new Date(two))
|
195
|
+
.replace('\u202F', ' '),
|
196
|
+
);
|
197
|
+
break;
|
198
|
+
case 'json': {
|
199
|
+
const api = new Api();
|
200
|
+
const history = createBrowserHistory();
|
201
|
+
const store = configureStore(window.__data, history, api);
|
202
|
+
parts = diffWords(
|
203
|
+
ReactDOMServer.renderToStaticMarkup(
|
204
|
+
<Provider store={store}>
|
205
|
+
<ConnectedRouter history={history}>
|
206
|
+
<RenderBlocks content={contentOne} />
|
207
|
+
</ConnectedRouter>
|
208
|
+
</Provider>,
|
209
|
+
),
|
210
|
+
ReactDOMServer.renderToStaticMarkup(
|
211
|
+
<Provider store={store}>
|
212
|
+
<ConnectedRouter history={history}>
|
213
|
+
<RenderBlocks content={contentTwo} />
|
214
|
+
</ConnectedRouter>
|
215
|
+
</Provider>,
|
216
|
+
),
|
217
|
+
);
|
218
|
+
break;
|
219
|
+
}
|
220
|
+
case 'slate': {
|
221
|
+
const api = new Api();
|
222
|
+
const history = createBrowserHistory();
|
223
|
+
const store = configureStore(window.__data, history, api);
|
224
|
+
parts = diffWords(
|
225
|
+
ReactDOMServer.renderToStaticMarkup(
|
226
|
+
<Provider store={store}>
|
227
|
+
<ConnectedRouter history={history}>
|
228
|
+
{serializeNodes(one)}
|
229
|
+
</ConnectedRouter>
|
230
|
+
</Provider>,
|
231
|
+
),
|
232
|
+
ReactDOMServer.renderToStaticMarkup(
|
233
|
+
<Provider store={store}>
|
234
|
+
<ConnectedRouter history={history}>
|
235
|
+
{serializeNodes(two)}
|
236
|
+
</ConnectedRouter>
|
237
|
+
</Provider>,
|
238
|
+
),
|
239
|
+
);
|
240
|
+
break;
|
241
|
+
}
|
242
|
+
case 'textarea':
|
243
|
+
default:
|
244
|
+
const Widget = config.widgets?.views?.widget?.[schema.widget];
|
245
|
+
|
246
|
+
if (Widget) {
|
247
|
+
const api = new Api();
|
248
|
+
const history = createBrowserHistory();
|
249
|
+
const store = configureStore(window.__data, history, api);
|
250
|
+
parts = diffWords(
|
251
|
+
ReactDOMServer.renderToStaticMarkup(
|
252
|
+
<Provider store={store}>
|
253
|
+
<ConnectedRouter history={history}>
|
254
|
+
<Widget value={one} />
|
255
|
+
</ConnectedRouter>
|
256
|
+
</Provider>,
|
257
|
+
),
|
258
|
+
ReactDOMServer.renderToStaticMarkup(
|
259
|
+
<Provider store={store}>
|
260
|
+
<ConnectedRouter history={history}>
|
261
|
+
<Widget value={two} />
|
262
|
+
</ConnectedRouter>
|
263
|
+
</Provider>,
|
264
|
+
),
|
265
|
+
);
|
266
|
+
} else parts = diffWords(one, two);
|
267
|
+
|
268
|
+
break;
|
269
|
+
}
|
270
|
+
} else if (schema.type === 'object') {
|
271
|
+
parts = diffWords(one?.filename || one, two?.filename || two);
|
272
|
+
} else if (schema.type === 'array') {
|
273
|
+
oneArray = (one || []).map((i) => i?.title || i);
|
274
|
+
twoArray = (two || []).map((j) => j?.title || j);
|
275
|
+
parts = diffWords(oneArray, twoArray);
|
276
|
+
} else {
|
277
|
+
parts = diffWords(one?.title || one, two?.title || two);
|
278
|
+
}
|
279
|
+
|
280
|
+
return (
|
281
|
+
<Grid data-testid="DiffField">
|
282
|
+
<Grid.Row>
|
283
|
+
<Grid.Column width={12}>{schema.title}</Grid.Column>
|
284
|
+
</Grid.Row>
|
285
|
+
|
286
|
+
{view === 'split' && (
|
287
|
+
<Grid.Row>
|
288
|
+
<Grid.Column width={6} verticalAlign="top">
|
289
|
+
<Widget
|
290
|
+
value={one}
|
291
|
+
diff={
|
292
|
+
<span
|
293
|
+
dangerouslySetInnerHTML={{
|
294
|
+
__html: join(
|
295
|
+
map(parts, (part) => {
|
296
|
+
let combined = (part.value || []).reduce(
|
297
|
+
(acc, value) => {
|
298
|
+
return acc + formatDiffPart(part, value, 'left');
|
299
|
+
},
|
300
|
+
'',
|
301
|
+
);
|
302
|
+
return combined;
|
303
|
+
}),
|
304
|
+
'',
|
305
|
+
),
|
306
|
+
}}
|
307
|
+
/>
|
308
|
+
}
|
309
|
+
/>
|
310
|
+
</Grid.Column>
|
311
|
+
<Grid.Column width={6} verticalAlign="top">
|
312
|
+
<Widget
|
313
|
+
value={two}
|
314
|
+
diff={
|
315
|
+
<span
|
316
|
+
dangerouslySetInnerHTML={{
|
317
|
+
__html: join(
|
318
|
+
map(parts, (part) => {
|
319
|
+
let combined = (part.value || []).reduce(
|
320
|
+
(acc, value) => {
|
321
|
+
return acc + formatDiffPart(part, value, 'right');
|
322
|
+
},
|
323
|
+
'',
|
324
|
+
);
|
325
|
+
return combined;
|
326
|
+
}),
|
327
|
+
'',
|
328
|
+
),
|
329
|
+
}}
|
330
|
+
/>
|
331
|
+
}
|
332
|
+
/>
|
333
|
+
</Grid.Column>
|
334
|
+
</Grid.Row>
|
335
|
+
)}
|
336
|
+
{view === 'unified' && (
|
337
|
+
<Grid.Row>
|
338
|
+
<Grid.Column width={16} verticalAlign="top">
|
339
|
+
<Widget
|
340
|
+
value={two}
|
341
|
+
one={one}
|
342
|
+
two={two}
|
343
|
+
diff={
|
344
|
+
<span
|
345
|
+
dangerouslySetInnerHTML={{
|
346
|
+
__html: join(
|
347
|
+
map(parts, (part) => {
|
348
|
+
let combined = (part.value || []).reduce(
|
349
|
+
(acc, value) => {
|
350
|
+
return acc + formatDiffPart(part, value, 'unified');
|
351
|
+
},
|
352
|
+
'',
|
353
|
+
);
|
354
|
+
return combined;
|
355
|
+
}),
|
356
|
+
'',
|
357
|
+
),
|
358
|
+
}}
|
359
|
+
/>
|
360
|
+
}
|
361
|
+
/>
|
362
|
+
</Grid.Column>
|
363
|
+
</Grid.Row>
|
364
|
+
)}
|
365
|
+
</Grid>
|
366
|
+
);
|
367
|
+
};
|
368
|
+
|
369
|
+
/**
|
370
|
+
* Property types.
|
371
|
+
* @property {Object} propTypes Property types.
|
372
|
+
* @static
|
373
|
+
*/
|
374
|
+
DiffField.propTypes = {
|
375
|
+
one: PropTypes.any.isRequired,
|
376
|
+
two: PropTypes.any.isRequired,
|
377
|
+
contentOne: PropTypes.any,
|
378
|
+
contentTwo: PropTypes.any,
|
379
|
+
view: PropTypes.string.isRequired,
|
380
|
+
schema: PropTypes.shape({
|
381
|
+
widget: PropTypes.string,
|
382
|
+
type: PropTypes.string,
|
383
|
+
title: PropTypes.string,
|
384
|
+
}).isRequired,
|
385
|
+
};
|
386
|
+
|
387
|
+
export default injectLazyLibs('diffLib')(DiffField);
|
@@ -0,0 +1 @@
|
|
1
|
+
Customize DiffField.jsx from @plone/volto 17.21.0. See https://taskman.eionet.europa.eu/issues/281229
|