@eeacms/volto-eea-website-theme 1.34.0 → 2.0.1
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/.eslintrc.js +7 -2
- package/CHANGELOG.md +53 -1
- package/docker-compose.yml +1 -1
- package/jest-addon.config.js +3 -0
- package/package.json +2 -1
- package/src/components/manage/Blocks/LayoutSettings/index.js +3 -1
- package/src/components/manage/Blocks/Title/index.js +3 -1
- package/src/components/manage/Blocks/Title/schema.js +3 -1
- package/src/components/theme/Banner/View.jsx +12 -5
- package/src/components/theme/DraftBackground/DraftBackground.jsx +30 -21
- package/src/components/theme/DraftBackground/DraftBackground.test.jsx +85 -0
- package/src/config.js +2 -0
- package/src/customizations/@plone/volto-slate/blocks/Text/TextBlockView.jsx +32 -0
- package/src/customizations/@plone/volto-slate/editor/render.jsx +75 -0
- package/src/customizations/@plone/volto-slate/elementEditor/utils.js +76 -75
- package/src/customizations/volto/components/manage/Blocks/Grid/Edit.jsx +70 -0
- package/src/customizations/volto/components/manage/Blocks/Grid/View.jsx +61 -0
- package/src/customizations/volto/components/manage/Blocks/Grid/readme.md +1 -0
- package/src/customizations/volto/components/manage/Blocks/Image/Edit.jsx +82 -23
- package/src/customizations/volto/components/manage/Blocks/Image/Edit.test.jsx +10 -3
- package/src/customizations/volto/components/manage/Blocks/Image/View.jsx +110 -111
- package/src/customizations/volto/components/manage/Blocks/Image/schema.js +17 -2
- package/src/customizations/volto/components/manage/Blocks/LeadImage/Edit.jsx +35 -14
- package/src/customizations/volto/components/manage/Blocks/LeadImage/View.jsx +65 -79
- package/src/customizations/volto/components/manage/Display/Display.jsx +306 -0
- package/src/customizations/volto/components/manage/Display/Readme.md +1 -0
- package/src/customizations/volto/components/manage/Sidebar/SidebarPopup copy.jsx +82 -0
- package/src/customizations/volto/components/manage/Toolbar/More.jsx +541 -0
- package/src/customizations/volto/components/manage/UniversalLink/UniversalLink.jsx +3 -1
- package/src/customizations/volto/components/manage/Widgets/ObjectBrowserWidget.jsx +24 -14
- package/src/customizations/volto/components/manage/Widgets/README.md +1 -0
- package/src/customizations/volto/components/manage/Workflow/README.txt +1 -0
- package/src/customizations/volto/components/manage/Workflow/Workflow.jsx +324 -0
- package/src/customizations/volto/components/manage/Workflow/Workflow.test.jsx +81 -0
- package/src/customizations/volto/components/theme/Comments/Comments.jsx +1 -2
- package/src/customizations/volto/components/theme/ContactForm/ContactForm.jsx +1 -1
- package/src/customizations/volto/components/theme/EventDetails/EventDetails.jsx +1 -0
- package/src/index.js +21 -16
- package/src/middleware/ok.js +4 -2
- package/src/middleware/voltoCustom.js +4 -2
- package/src/slate.js +10 -8
- package/src/customizations/@plone/volto-slate/editor/plugins/StyleMenu/README.txt +0 -1
- package/src/customizations/@plone/volto-slate/editor/plugins/StyleMenu/StyleMenu.jsx +0 -157
- package/src/customizations/@plone/volto-slate/editor/plugins/StyleMenu/utils.js +0 -168
- package/src/customizations/volto/components/manage/Add/Add.jsx +0 -498
- package/src/customizations/volto/components/manage/Add/readme.md +0 -1
- package/src/customizations/volto/components/manage/Contents/ContentsPropertiesModal.jsx +0 -232
- package/src/customizations/volto/components/manage/Form/Form.jsx +0 -810
- package/src/customizations/volto/components/manage/Form/Form.test.jsx +0 -1124
- package/src/customizations/volto/components/manage/Form/ModalForm.jsx +0 -326
- package/src/customizations/volto/components/manage/Sharing/Sharing.jsx +0 -528
- package/src/customizations/volto/components/manage/Sharing/Sharing.test.jsx +0 -72
- package/src/customizations/volto/components/manage/Widgets/ObjectBrowserWidget.test.jsx +0 -193
- package/src/customizations/volto/components/theme/AppExtras/AppExtras.jsx +0 -27
package/.eslintrc.js
CHANGED
package/CHANGELOG.md
CHANGED
@@ -4,7 +4,59 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
4
4
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
6
6
|
|
7
|
-
### [
|
7
|
+
### [2.0.1](https://github.com/eea/volto-eea-website-theme/compare/2.0.0...2.0.1) - 14 May 2024
|
8
|
+
|
9
|
+
#### :nail_care: Enhancements
|
10
|
+
|
11
|
+
- change(draft-image): check if parent has effective date in future for draft image showing [David Ichim - [`608cbb0`](https://github.com/eea/volto-eea-website-theme/commit/608cbb0d06d014c3dc8ba99e2b79cf9103291d68)]
|
12
|
+
|
13
|
+
#### :hammer_and_wrench: Others
|
14
|
+
|
15
|
+
- modified param of dateIsInFuture to signal it's a string and not a date [David Ichim - [`e3243a0`](https://github.com/eea/volto-eea-website-theme/commit/e3243a075969a379462ba0b7889fe0d8b52af62a)]
|
16
|
+
## [2.0.0](https://github.com/eea/volto-eea-website-theme/compare/1.34.0...2.0.0) - 13 May 2024
|
17
|
+
|
18
|
+
#### :rocket: New Features
|
19
|
+
|
20
|
+
- feat: Volto 17 support - refs #259049 [Teodor Voicu - [`79ce620`](https://github.com/eea/volto-eea-website-theme/commit/79ce6202469523c21462a86cb72b93016b10a2b6)]
|
21
|
+
|
22
|
+
#### :bug: Bug Fixes
|
23
|
+
|
24
|
+
- fix(draft_image): added fixes from 1.x.x branch [David Ichim - [`b62de0a`](https://github.com/eea/volto-eea-website-theme/commit/b62de0a8fd9c953210f4b371b5117d70f9e04040)]
|
25
|
+
|
26
|
+
#### :nail_care: Enhancements
|
27
|
+
|
28
|
+
- change(draft_image): added comments to DraftBackground code [David Ichim - [`0cb4304`](https://github.com/eea/volto-eea-website-theme/commit/0cb430424281f0d0a78e2f9b1326b6bc4128a6f3)]
|
29
|
+
- refactor: Disable data figure and plotly chart - refs #269278 [dobri1408 - [`d8fd0da`](https://github.com/eea/volto-eea-website-theme/commit/d8fd0dab10aceebf57cff5c1e777b795117b5a04)]
|
30
|
+
- change(draft-image): to remove image when published date is set to the future [David Ichim - [`9b9e023`](https://github.com/eea/volto-eea-website-theme/commit/9b9e0232fe6cd624c19dc87bc8152477f1ee83fd)]
|
31
|
+
- refactor: Move all customizations from volto-eea-website-policy [alin - [`07650fe`](https://github.com/eea/volto-eea-website-theme/commit/07650fe1c55571ec628dbe2cf8394709f0c7ae2d)]
|
32
|
+
|
33
|
+
#### :house: Internal changes
|
34
|
+
|
35
|
+
- style: Automated code fix [eea-jenkins - [`e671c83`](https://github.com/eea/volto-eea-website-theme/commit/e671c834773f9091e1dafb8ec7a1cbea88e53ee2)]
|
36
|
+
- style: Automated code fix [eea-jenkins - [`5156bb5`](https://github.com/eea/volto-eea-website-theme/commit/5156bb54b48f9731278ea860847a019fff10a84f)]
|
37
|
+
|
38
|
+
#### :hammer_and_wrench: Others
|
39
|
+
|
40
|
+
- Bump package version to 2.0.0 to signal major release due to Volto 17 jump [David Ichim - [`ffe3049`](https://github.com/eea/volto-eea-website-theme/commit/ffe3049b3b656093a44f05044dbe7cd63bac495f)]
|
41
|
+
### [1.34.0](https://github.com/eea/volto-eea-website-theme/compare/1.33.2...1.34.0) - 9 May 2024
|
42
|
+
|
43
|
+
#### :bug: Bug Fixes
|
44
|
+
|
45
|
+
- fix: Make sure effectiveDate is not null/undefined [alin - [`43400bc`](https://github.com/eea/volto-eea-website-theme/commit/43400bcce422049d9d38f17c7cc29e88062da902)]
|
46
|
+
- fix: DraftBackground for effectiveDate in the future [alin - [`da7fa80`](https://github.com/eea/volto-eea-website-theme/commit/da7fa806e5d6edbb7b016f0356d5a886b75ba892)]
|
47
|
+
|
48
|
+
#### :nail_care: Enhancements
|
49
|
+
|
50
|
+
- refactor: Disable data figure and plotly chart - refs #269278 [dobri1408 - [`002ef00`](https://github.com/eea/volto-eea-website-theme/commit/002ef003ad872ea8dd5c74acf74a85ca1fd1992b)]
|
51
|
+
- change(draft-image): show draft image for items with publishing date in the future [David Ichim - [`59a3873`](https://github.com/eea/volto-eea-website-theme/commit/59a387364f40d8d66a747921ccff946e7f8814e1)]
|
52
|
+
|
53
|
+
#### :hammer_and_wrench: Others
|
54
|
+
|
55
|
+
- Release 1.34.0 [alin - [`92cc065`](https://github.com/eea/volto-eea-website-theme/commit/92cc065730f44412a04b2df7159c540d858f4607)]
|
56
|
+
- Revert "Release 1.40.0" [alin - [`c1a4f30`](https://github.com/eea/volto-eea-website-theme/commit/c1a4f3042a91ebb4a1d674914d3bccf68954c94f)]
|
57
|
+
- Revert "fix: DraftBackground for effectiveDate in the future" [alin - [`ed2ca9b`](https://github.com/eea/volto-eea-website-theme/commit/ed2ca9b5881c6991d82bb2a8d3f0fe8e29f1a6d7)]
|
58
|
+
- Release 1.40.0 [alin - [`210f833`](https://github.com/eea/volto-eea-website-theme/commit/210f83384b6401f7c9a0e08070d69dd1fed690b1)]
|
59
|
+
### [1.33.2](https://github.com/eea/volto-eea-website-theme/compare/1.33.1...1.33.2) - 16 April 2024
|
8
60
|
|
9
61
|
#### :bug: Bug Fixes
|
10
62
|
|
package/docker-compose.yml
CHANGED
package/jest-addon.config.js
CHANGED
@@ -14,6 +14,8 @@ module.exports = {
|
|
14
14
|
'@package/(.*)$': '<rootDir>/node_modules/@plone/volto/src/$1',
|
15
15
|
'@root/(.*)$': '<rootDir>/node_modules/@plone/volto/src/$1',
|
16
16
|
'@plone/volto-quanta/(.*)$': '<rootDir>/src/addons/volto-quanta/src/$1',
|
17
|
+
'@eeacms/search/(.*)$': '<rootDir>/src/addons/volto-searchlib/searchlib/$1',
|
18
|
+
'@eeacms/search': '<rootDir>/src/addons/volto-searchlib/searchlib',
|
17
19
|
'@eeacms/(.*?)/(.*)$': '<rootDir>/node_modules/@eeacms/$1/src/$2',
|
18
20
|
'@plone/volto-slate$':
|
19
21
|
'<rootDir>/node_modules/@plone/volto/packages/volto-slate/src',
|
@@ -28,6 +30,7 @@ module.exports = {
|
|
28
30
|
],
|
29
31
|
transform: {
|
30
32
|
'^.+\\.js(x)?$': 'babel-jest',
|
33
|
+
'^.+\\.ts(x)?$': 'babel-jest',
|
31
34
|
'^.+\\.(png)$': 'jest-file',
|
32
35
|
'^.+\\.(jpg)$': 'jest-file',
|
33
36
|
'^.+\\.(svg)$': './node_modules/@plone/volto/jest-svgsystem-transform.js',
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@eeacms/volto-eea-website-theme",
|
3
|
-
"version": "
|
3
|
+
"version": "2.0.1",
|
4
4
|
"description": "@eeacms/volto-eea-website-theme: Volto add-on",
|
5
5
|
"main": "src/index.js",
|
6
6
|
"author": "European Environment Agency: IDM2 A-Team",
|
@@ -34,6 +34,7 @@
|
|
34
34
|
"babel-plugin-transform-class-properties": "^6.24.1",
|
35
35
|
"dotenv": "^16.3.2",
|
36
36
|
"husky": "^8.0.3",
|
37
|
+
"jsonwebtoken": "9.0.0",
|
37
38
|
"lint-staged": "^14.0.1",
|
38
39
|
"md5": "^2.3.0",
|
39
40
|
"postcss-less": "6.0.0"
|
@@ -3,7 +3,7 @@ import LayoutSettingsView from './LayoutSettingsView';
|
|
3
3
|
import LayoutSettingsEdit from './LayoutSettingsEdit';
|
4
4
|
import BlockSettingsSchema from '@plone/volto/components/manage/Blocks/Block/Schema';
|
5
5
|
|
6
|
-
|
6
|
+
const applyConfig = (config) => {
|
7
7
|
config.blocks.blocksConfig.layoutSettings = {
|
8
8
|
id: 'layoutSettings',
|
9
9
|
title: 'Layout settings',
|
@@ -19,3 +19,5 @@ export default (config) => {
|
|
19
19
|
|
20
20
|
return config;
|
21
21
|
};
|
22
|
+
|
23
|
+
export default applyConfig;
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import Edit from './Edit';
|
2
2
|
import View from './View';
|
3
3
|
|
4
|
-
|
4
|
+
const applyConfig = (config) => {
|
5
5
|
config.blocks.blocksConfig.title = {
|
6
6
|
...config.blocks.blocksConfig.title,
|
7
7
|
edit: Edit,
|
@@ -12,3 +12,5 @@ export default (config) => {
|
|
12
12
|
|
13
13
|
return config;
|
14
14
|
};
|
15
|
+
|
16
|
+
export default applyConfig;
|
@@ -89,6 +89,9 @@ const View = (props) => {
|
|
89
89
|
const copyrightPrefix =
|
90
90
|
config.blocks.blocksConfig.title.copyrightPrefix || '';
|
91
91
|
|
92
|
+
const contentTypesWithoutHeaderImage =
|
93
|
+
config.settings?.eea?.contentTypesWithoutHeaderImage || [];
|
94
|
+
|
92
95
|
// Set dates
|
93
96
|
const getDate = useCallback(
|
94
97
|
(hidden, key) => {
|
@@ -96,10 +99,10 @@ const View = (props) => {
|
|
96
99
|
},
|
97
100
|
[metadata],
|
98
101
|
);
|
99
|
-
const creationDate = useMemo(
|
100
|
-
getDate,
|
101
|
-
hideCreationDate,
|
102
|
-
|
102
|
+
const creationDate = useMemo(
|
103
|
+
() => getDate(hideCreationDate, 'created'),
|
104
|
+
[getDate, hideCreationDate],
|
105
|
+
);
|
103
106
|
const publishingDate = useMemo(
|
104
107
|
() => getDate(hidePublishingDate, 'effective'),
|
105
108
|
[getDate, hidePublishingDate],
|
@@ -110,7 +113,11 @@ const View = (props) => {
|
|
110
113
|
);
|
111
114
|
|
112
115
|
// Set image source
|
113
|
-
const image =
|
116
|
+
const image = contentTypesWithoutHeaderImage.includes(
|
117
|
+
props.properties['@type'],
|
118
|
+
)
|
119
|
+
? false
|
120
|
+
: getImageSource(metadata['image']);
|
114
121
|
// Get type
|
115
122
|
const type = metadata.type_title || friendlyId(metadata['@type']);
|
116
123
|
|
@@ -1,10 +1,8 @@
|
|
1
|
-
import
|
1
|
+
import { BodyClass, flattenToAppURL } from '@plone/volto/helpers';
|
2
2
|
import { connect } from 'react-redux';
|
3
|
-
import './draft.css';
|
4
|
-
import { BodyClass } from '@plone/volto/helpers';
|
5
3
|
import { withRouter } from 'react-router-dom';
|
6
4
|
import { compose } from 'redux';
|
7
|
-
import
|
5
|
+
import './draft.css';
|
8
6
|
|
9
7
|
/**
|
10
8
|
* Removes any trailing slashes from the given string.
|
@@ -16,6 +14,18 @@ const removeTrailingSlash = (str) => {
|
|
16
14
|
return str.replace(/\/+$/, '');
|
17
15
|
};
|
18
16
|
|
17
|
+
/**
|
18
|
+
* Checks if a given date is in the future.
|
19
|
+
*
|
20
|
+
* @param {string} date - The date to check.
|
21
|
+
* @returns {boolean} `true` if the date is in the future, `false` otherwise.
|
22
|
+
*/
|
23
|
+
const dateIsInFuture = (date) => {
|
24
|
+
return (
|
25
|
+
date && date !== 'None' && new Date(date).getTime() > new Date().getTime()
|
26
|
+
);
|
27
|
+
};
|
28
|
+
|
19
29
|
/**
|
20
30
|
* Checks if the current content is published.
|
21
31
|
*
|
@@ -38,36 +48,35 @@ export const checkIfPublished = (props) => {
|
|
38
48
|
// set draft image if effective date is set and is in the future
|
39
49
|
// regardless of review_state
|
40
50
|
const effectiveDate = props?.content?.effective;
|
41
|
-
if (
|
42
|
-
effectiveDate &&
|
43
|
-
effectiveDate !== 'None' &&
|
44
|
-
new Date(effectiveDate).getTime() > new Date().getTime()
|
45
|
-
) {
|
51
|
+
if (dateIsInFuture(effectiveDate)) {
|
46
52
|
return false;
|
47
53
|
}
|
48
54
|
|
55
|
+
const reviewState = props?.review_state;
|
56
|
+
|
49
57
|
//case 1 : review_state published
|
50
|
-
if (
|
58
|
+
if (reviewState === 'published') return true;
|
51
59
|
|
52
60
|
//case 2: review_state null, but parent is published eg:Image in published folder
|
53
|
-
if
|
54
|
-
|
55
|
-
|
56
|
-
|
61
|
+
// is marked as published, or not published if the effective date of parent
|
62
|
+
// is in the future
|
63
|
+
const parent = props?.content?.parent;
|
64
|
+
const parentReviewState = parent?.review_state;
|
65
|
+
if (!reviewState && parentReviewState === 'published') {
|
66
|
+
if (dateIsInFuture(parent?.effective)) {
|
67
|
+
return false;
|
68
|
+
}
|
57
69
|
return true;
|
70
|
+
}
|
58
71
|
|
59
72
|
//case 3: review_state null, but there is no parent eg: PloneSite
|
60
|
-
if (
|
61
|
-
!props?.review_state &&
|
62
|
-
Object.keys(props?.content?.parent || {}).length === 0
|
63
|
-
)
|
64
|
-
return true;
|
73
|
+
if (!reviewState && Object.keys(parent || {}).length === 0) return true;
|
65
74
|
|
66
75
|
//case 4: review_state null, and review state of parent is null, eg: Image in PloneSite
|
67
|
-
if (!
|
68
|
-
return true;
|
76
|
+
if (!reviewState && !parentReviewState) return true;
|
69
77
|
return false;
|
70
78
|
};
|
79
|
+
|
71
80
|
const DraftBackground = (props) => {
|
72
81
|
let draftClass = 'wf-state-is-draft';
|
73
82
|
if (checkIfPublished(props)) {
|
@@ -0,0 +1,85 @@
|
|
1
|
+
import { checkIfPublished } from './DraftBackground';
|
2
|
+
describe('checkIfPublished', () => {
|
3
|
+
it('should return true if contentId does not match pathname', () => {
|
4
|
+
const props = {
|
5
|
+
contentId: '/page1',
|
6
|
+
pathname: '/page2',
|
7
|
+
};
|
8
|
+
|
9
|
+
expect(checkIfPublished(props)).toBe(true);
|
10
|
+
});
|
11
|
+
|
12
|
+
it('should return false if effective date is in the future', () => {
|
13
|
+
const futureDate = new Date();
|
14
|
+
futureDate.setDate(futureDate.getDate() + 10);
|
15
|
+
const props = {
|
16
|
+
contentId: '/page1',
|
17
|
+
pathname: '/page1',
|
18
|
+
content: {
|
19
|
+
effective: futureDate.toISOString(),
|
20
|
+
},
|
21
|
+
};
|
22
|
+
expect(checkIfPublished(props)).toBe(false);
|
23
|
+
});
|
24
|
+
|
25
|
+
it('should return true if review_state is published', () => {
|
26
|
+
const props = {
|
27
|
+
contentId: '/page1',
|
28
|
+
pathname: '/page1',
|
29
|
+
review_state: 'published',
|
30
|
+
};
|
31
|
+
expect(checkIfPublished(props)).toBe(true);
|
32
|
+
});
|
33
|
+
|
34
|
+
it('should return true if review_state is null and parent is published', () => {
|
35
|
+
const props = {
|
36
|
+
contentId: '/page1',
|
37
|
+
pathname: '/page1',
|
38
|
+
review_state: null,
|
39
|
+
content: {
|
40
|
+
parent: {
|
41
|
+
review_state: 'published',
|
42
|
+
},
|
43
|
+
},
|
44
|
+
};
|
45
|
+
expect(checkIfPublished(props)).toBe(true);
|
46
|
+
});
|
47
|
+
|
48
|
+
it('should return true if review_state is null and parent is empty', () => {
|
49
|
+
const props = {
|
50
|
+
contentId: '/page1',
|
51
|
+
pathname: '/page1',
|
52
|
+
review_state: null,
|
53
|
+
content: {
|
54
|
+
parent: {},
|
55
|
+
},
|
56
|
+
};
|
57
|
+
expect(checkIfPublished(props)).toBe(true);
|
58
|
+
});
|
59
|
+
|
60
|
+
it('should return true if review_state is null and parent review_state is null', () => {
|
61
|
+
const props = {
|
62
|
+
contentId: '/page1',
|
63
|
+
pathname: '/page1',
|
64
|
+
review_state: null,
|
65
|
+
content: {
|
66
|
+
parent: {
|
67
|
+
review_state: null,
|
68
|
+
},
|
69
|
+
},
|
70
|
+
};
|
71
|
+
expect(checkIfPublished(props)).toBe(true);
|
72
|
+
});
|
73
|
+
|
74
|
+
it('should return false if review_state is not published and effective date is not in the future', () => {
|
75
|
+
const props = {
|
76
|
+
contentId: '/page1',
|
77
|
+
pathname: '/page1',
|
78
|
+
review_state: 'private',
|
79
|
+
content: {
|
80
|
+
effective: '2023-01-01T00:00:00Z',
|
81
|
+
},
|
82
|
+
};
|
83
|
+
expect(checkIfPublished(props)).toBe(false);
|
84
|
+
});
|
85
|
+
});
|
package/src/config.js
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
import {
|
2
|
+
serializeNodes,
|
3
|
+
serializeNodesToText,
|
4
|
+
} from '@plone/volto-slate/editor/render';
|
5
|
+
import config from '@plone/volto/registry';
|
6
|
+
import { isEqual } from 'lodash';
|
7
|
+
import Slugger from 'github-slugger';
|
8
|
+
import { normalizeString } from '@plone/volto/helpers';
|
9
|
+
|
10
|
+
const TextBlockView = (props) => {
|
11
|
+
const { id, data, styling = {} } = props;
|
12
|
+
const { value, override_toc } = data;
|
13
|
+
const metadata = props.metadata || props.properties;
|
14
|
+
const { topLevelTargetElements } = config.settings.slate;
|
15
|
+
|
16
|
+
const getAttributes = (node, path) => {
|
17
|
+
const res = { ...styling };
|
18
|
+
if (node.type && isEqual(path, [0])) {
|
19
|
+
if (topLevelTargetElements.includes(node.type) || override_toc) {
|
20
|
+
const text = serializeNodesToText([node] || []);
|
21
|
+
const slug = Slugger.slug(normalizeString(text));
|
22
|
+
res.id = slug || id;
|
23
|
+
res['data-block'] = id;
|
24
|
+
}
|
25
|
+
}
|
26
|
+
return res;
|
27
|
+
};
|
28
|
+
|
29
|
+
return serializeNodes(value, getAttributes, { metadata: metadata });
|
30
|
+
};
|
31
|
+
|
32
|
+
export default TextBlockView;
|
@@ -1,9 +1,19 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import { renderToStaticMarkup } from 'react-dom/server';
|
3
|
+
import { useLocation } from 'react-router-dom';
|
4
|
+
import { toast } from 'react-toastify';
|
5
|
+
import { useIntl } from 'react-intl';
|
6
|
+
import { useSelector } from 'react-redux';
|
3
7
|
import { Node, Text } from 'slate';
|
4
8
|
import cx from 'classnames';
|
5
9
|
import { isEmpty, isEqual, omit } from 'lodash';
|
10
|
+
import { UniversalLink, Toast } from '@plone/volto/components';
|
11
|
+
import { messages, addAppURL } from '@plone/volto/helpers';
|
12
|
+
import useClipboard from '@plone/volto/hooks/clipboard/useClipboard';
|
6
13
|
import config from '@plone/volto/registry';
|
14
|
+
import linkSVG from '@plone/volto/icons/link.svg';
|
15
|
+
|
16
|
+
import '@plone/volto-slate/editor/less/slate.less';
|
7
17
|
|
8
18
|
const OMITTED = ['editor', 'path'];
|
9
19
|
|
@@ -177,3 +187,68 @@ export const serializeNodesToText = (nodes) => {
|
|
177
187
|
|
178
188
|
export const serializeNodesToHtml = (nodes) =>
|
179
189
|
renderToStaticMarkup(serializeNodes(nodes));
|
190
|
+
|
191
|
+
export const renderLinkElement = (tagName) => {
|
192
|
+
function LinkElement({
|
193
|
+
attributes,
|
194
|
+
children,
|
195
|
+
mode = 'edit',
|
196
|
+
className = null,
|
197
|
+
}) {
|
198
|
+
const { slate = {} } = config.settings;
|
199
|
+
const Tag = tagName;
|
200
|
+
const slug = attributes.id || '';
|
201
|
+
const location = useLocation();
|
202
|
+
const token = useSelector((state) => state.userSession.token);
|
203
|
+
const appPathname = addAppURL(location.pathname);
|
204
|
+
// eslint-disable-next-line no-unused-vars
|
205
|
+
const [copied, copy, setCopied] = useClipboard(
|
206
|
+
appPathname.concat(`#${slug}`),
|
207
|
+
);
|
208
|
+
const intl = useIntl();
|
209
|
+
return !token || slate.useLinkedHeadings === false ? (
|
210
|
+
<Tag {...attributes} className={className} tabIndex={0}>
|
211
|
+
{children}
|
212
|
+
</Tag>
|
213
|
+
) : (
|
214
|
+
<Tag {...attributes} className={className} tabIndex={0}>
|
215
|
+
{children}
|
216
|
+
{mode === 'view' && slug && (
|
217
|
+
<UniversalLink
|
218
|
+
className="anchor"
|
219
|
+
aria-hidden="true"
|
220
|
+
tabIndex={-1}
|
221
|
+
href={`#${slug}`}
|
222
|
+
>
|
223
|
+
<style>
|
224
|
+
{/* Prettify the unstyled flash of the link icon on development */}
|
225
|
+
{`
|
226
|
+
a.anchor svg {
|
227
|
+
height: var(--anchor-svg-height, 24px);
|
228
|
+
}
|
229
|
+
`}
|
230
|
+
</style>
|
231
|
+
<svg
|
232
|
+
{...linkSVG.attributes}
|
233
|
+
dangerouslySetInnerHTML={{ __html: linkSVG.content }}
|
234
|
+
height={null}
|
235
|
+
onClick={() => {
|
236
|
+
copy();
|
237
|
+
|
238
|
+
toast.info(
|
239
|
+
<Toast
|
240
|
+
info
|
241
|
+
title={intl.formatMessage(messages.success)}
|
242
|
+
content={intl.formatMessage(messages.urlClipboardCopy)}
|
243
|
+
/>,
|
244
|
+
);
|
245
|
+
}}
|
246
|
+
></svg>
|
247
|
+
</UniversalLink>
|
248
|
+
)}
|
249
|
+
</Tag>
|
250
|
+
);
|
251
|
+
}
|
252
|
+
LinkElement.displayName = `${tagName}LinkElement`;
|
253
|
+
return LinkElement;
|
254
|
+
};
|
@@ -158,88 +158,89 @@ export const _isActiveElement = (elementType) => (editor) => {
|
|
158
158
|
* @param {string|Object[]} elementType - this can be a string or an array of strings
|
159
159
|
* @returns {Object|null} - found node
|
160
160
|
*/
|
161
|
-
export const _getActiveElement =
|
162
|
-
|
163
|
-
direction = 'any'
|
164
|
-
|
165
|
-
|
166
|
-
let found = [];
|
167
|
-
|
168
|
-
try {
|
169
|
-
found = Array.from(
|
170
|
-
Editor.nodes(editor, {
|
171
|
-
match: (n) =>
|
172
|
-
Array.isArray(elementType)
|
173
|
-
? elementType.includes(n.type)
|
174
|
-
: n.type === elementType,
|
175
|
-
at: selection,
|
176
|
-
}),
|
177
|
-
);
|
178
|
-
} catch (e) {
|
179
|
-
return null;
|
180
|
-
}
|
181
|
-
|
182
|
-
if (found.length) return found[0];
|
183
|
-
|
184
|
-
if (!selection) return null;
|
161
|
+
export const _getActiveElement =
|
162
|
+
(elementType) =>
|
163
|
+
(editor, direction = 'any') => {
|
164
|
+
const selection = editor.selection || editor.getSavedSelection();
|
165
|
+
let found = [];
|
185
166
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
167
|
+
try {
|
168
|
+
found = Array.from(
|
169
|
+
Editor.nodes(editor, {
|
170
|
+
match: (n) =>
|
171
|
+
Array.isArray(elementType)
|
172
|
+
? elementType.includes(n.type)
|
173
|
+
: n.type === elementType,
|
174
|
+
at: selection,
|
175
|
+
}),
|
176
|
+
);
|
177
|
+
} catch (e) {
|
178
|
+
return null;
|
179
|
+
}
|
190
180
|
|
191
|
-
if (
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
) {
|
207
|
-
|
181
|
+
if (found.length) return found[0];
|
182
|
+
|
183
|
+
if (!selection) return null;
|
184
|
+
|
185
|
+
if (direction === 'any' || direction === 'backward') {
|
186
|
+
const { path } = selection.anchor;
|
187
|
+
const isAtStart =
|
188
|
+
selection.anchor.offset === 0 && selection.focus.offset === 0;
|
189
|
+
|
190
|
+
if (isAtStart) {
|
191
|
+
let found;
|
192
|
+
try {
|
193
|
+
found = Editor.previous(editor, {
|
194
|
+
at: path,
|
195
|
+
});
|
196
|
+
} catch (ex) {
|
197
|
+
// eslint-disable-next-line no-console
|
198
|
+
console.warn('Unable to find previous node', editor, path);
|
199
|
+
return;
|
200
|
+
}
|
201
|
+
if (found && found[0] && found[0].type === elementType) {
|
202
|
+
if (
|
203
|
+
(Array.isArray(elementType) &&
|
204
|
+
elementType.includes(found[0].type)) ||
|
205
|
+
found[0].type === elementType
|
206
|
+
) {
|
207
|
+
return found;
|
208
|
+
}
|
209
|
+
} else {
|
210
|
+
return null;
|
208
211
|
}
|
209
|
-
} else {
|
210
|
-
return null;
|
211
212
|
}
|
212
213
|
}
|
213
|
-
}
|
214
|
-
|
215
|
-
if (direction === 'any' || direction === 'forward') {
|
216
|
-
const { path } = selection.anchor;
|
217
|
-
const isAtStart =
|
218
|
-
selection.anchor.offset === 0 && selection.focus.offset === 0;
|
219
214
|
|
220
|
-
if (
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
215
|
+
if (direction === 'any' || direction === 'forward') {
|
216
|
+
const { path } = selection.anchor;
|
217
|
+
const isAtStart =
|
218
|
+
selection.anchor.offset === 0 && selection.focus.offset === 0;
|
219
|
+
|
220
|
+
if (isAtStart) {
|
221
|
+
let found;
|
222
|
+
try {
|
223
|
+
found = Editor.next(editor, {
|
224
|
+
at: path,
|
225
|
+
});
|
226
|
+
} catch (e) {
|
227
|
+
// eslint-disable-next-line
|
228
|
+
console.warn('Unable to find next node', editor, path);
|
229
|
+
return;
|
230
|
+
}
|
231
|
+
if (found && found[0] && found[0].type === elementType) {
|
232
|
+
if (
|
233
|
+
(Array.isArray(elementType) &&
|
234
|
+
elementType.includes(found[0].type)) ||
|
235
|
+
found[0].type === elementType
|
236
|
+
) {
|
237
|
+
return found;
|
238
|
+
}
|
239
|
+
} else {
|
240
|
+
return null;
|
237
241
|
}
|
238
|
-
} else {
|
239
|
-
return null;
|
240
242
|
}
|
241
243
|
}
|
242
|
-
}
|
243
244
|
|
244
|
-
|
245
|
-
};
|
245
|
+
return null;
|
246
|
+
};
|