@eeacms/volto-eea-website-theme 1.27.2 → 1.28.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/.eslintrc.js +26 -17
- package/CHANGELOG.md +12 -17
- package/README.md +2 -0
- package/jest-addon.config.js +20 -11
- package/jest.setup.js +65 -0
- package/package.json +3 -2
- package/src/customizations/@plone/volto-slate/editor/SlateEditor.jsx +404 -0
- package/src/index.js +15 -0
package/.eslintrc.js
CHANGED
@@ -1,40 +1,43 @@
|
|
1
1
|
const fs = require('fs');
|
2
2
|
const path = require('path');
|
3
|
-
|
4
|
-
const projectRootPath = fs.existsSync('./project')
|
5
|
-
? fs.realpathSync('./project')
|
6
|
-
: fs.realpathSync(__dirname + '/../../../');
|
7
|
-
const packageJson = require(path.join(projectRootPath, 'package.json'));
|
8
|
-
const jsConfig = require(path.join(projectRootPath, 'jsconfig.json')).compilerOptions;
|
9
|
-
|
10
|
-
const pathsConfig = jsConfig.paths;
|
3
|
+
const projectRootPath = fs.realpathSync(__dirname + '/../../../');
|
11
4
|
|
12
5
|
let voltoPath = path.join(projectRootPath, 'node_modules/@plone/volto');
|
6
|
+
let configFile;
|
7
|
+
if (fs.existsSync(`${projectRootPath}/tsconfig.json`))
|
8
|
+
configFile = `${projectRootPath}/tsconfig.json`;
|
9
|
+
else if (fs.existsSync(`${projectRootPath}/jsconfig.json`))
|
10
|
+
configFile = `${projectRootPath}/jsconfig.json`;
|
11
|
+
|
12
|
+
if (configFile) {
|
13
|
+
const jsConfig = require(configFile).compilerOptions;
|
14
|
+
const pathsConfig = jsConfig.paths;
|
15
|
+
if (pathsConfig['@plone/volto'])
|
16
|
+
voltoPath = `./${jsConfig.baseUrl}/${pathsConfig['@plone/volto'][0]}`;
|
17
|
+
}
|
13
18
|
|
14
|
-
Object.keys(pathsConfig).forEach(pkg => {
|
15
|
-
if (pkg === '@plone/volto') {
|
16
|
-
voltoPath = `./${jsConfig.baseUrl}/${pathsConfig[pkg][0]}`;
|
17
|
-
}
|
18
|
-
});
|
19
19
|
const AddonConfigurationRegistry = require(`${voltoPath}/addon-registry.js`);
|
20
20
|
const reg = new AddonConfigurationRegistry(projectRootPath);
|
21
21
|
|
22
22
|
// Extends ESlint configuration for adding the aliases to `src` directories in Volto addons
|
23
|
-
const addonAliases = Object.keys(reg.packages).map(o => [
|
23
|
+
const addonAliases = Object.keys(reg.packages).map((o) => [
|
24
24
|
o,
|
25
25
|
reg.packages[o].modulePath,
|
26
26
|
]);
|
27
27
|
|
28
|
+
const addonExtenders = reg.getEslintExtenders().map((m) => require(m));
|
28
29
|
|
29
|
-
|
30
|
-
extends: `${
|
30
|
+
const defaultConfig = {
|
31
|
+
extends: `${voltoPath}/.eslintrc`,
|
31
32
|
settings: {
|
32
33
|
'import/resolver': {
|
33
34
|
alias: {
|
34
35
|
map: [
|
35
36
|
['@plone/volto', '@plone/volto/src'],
|
37
|
+
['@plone/volto-slate', '@plone/volto/packages/volto-slate/src'],
|
36
38
|
...addonAliases,
|
37
39
|
['@package', `${__dirname}/src`],
|
40
|
+
['@root', `${__dirname}/src`],
|
38
41
|
['~', `${__dirname}/src`],
|
39
42
|
],
|
40
43
|
extensions: ['.js', '.jsx', '.json'],
|
@@ -51,6 +54,12 @@ module.exports = {
|
|
51
54
|
allowReferrer: true,
|
52
55
|
},
|
53
56
|
],
|
54
|
-
}
|
57
|
+
},
|
55
58
|
};
|
56
59
|
|
60
|
+
const config = addonExtenders.reduce(
|
61
|
+
(acc, extender) => extender.modify(acc),
|
62
|
+
defaultConfig,
|
63
|
+
);
|
64
|
+
|
65
|
+
module.exports = config;
|
package/CHANGELOG.md
CHANGED
@@ -4,16 +4,27 @@ 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
|
-
### [1.
|
7
|
+
### [1.28.0](https://github.com/eea/volto-eea-website-theme/compare/1.27.2...1.28.0) - 16 February 2024
|
8
8
|
|
9
9
|
#### :bug: Bug Fixes
|
10
10
|
|
11
|
+
- fix(toc): make toc work, refs #265201 [Razvan - [`507adc2`](https://github.com/eea/volto-eea-website-theme/commit/507adc29f0a2e144933b06dfcf0856f1ac7efc98)]
|
12
|
+
- fix: volto slate when used in metadata block with SlateJSONField - refs #264239 [Miu Razvan - [`51682c4`](https://github.com/eea/volto-eea-website-theme/commit/51682c42001f6aa3433feff62c5f8536283de990)]
|
11
13
|
- fix(lint): service so that it work with editor and command line tool [David Ichim - [`ad43bc2`](https://github.com/eea/volto-eea-website-theme/commit/ad43bc2f9bfc3e272d30b35db9d4b160a8edcbec)]
|
12
14
|
|
15
|
+
#### :house: Internal changes
|
16
|
+
|
17
|
+
- chore: package.json [Alin Voinea - [`08beb70`](https://github.com/eea/volto-eea-website-theme/commit/08beb706d9021a89c80acc5aa7c94350195f7de7)]
|
18
|
+
|
13
19
|
#### :hammer_and_wrench: Others
|
14
20
|
|
21
|
+
- bump version [Razvan - [`721e939`](https://github.com/eea/volto-eea-website-theme/commit/721e939d12e324b459ebfa78a2e656ee7142a3d6)]
|
22
|
+
- merge master into this branch [Razvan - [`586c8f9`](https://github.com/eea/volto-eea-website-theme/commit/586c8f910bac55a043bd8dda60e9444bd2ae1663)]
|
23
|
+
- test: Update jest,Jenkinsfile,lint to volto-addons-template PR30 [valentinab25 - [`c4dbd28`](https://github.com/eea/volto-eea-website-theme/commit/c4dbd289358205bc2d849aab7edb11ccf3b89cee)]
|
15
24
|
- fix tests [Razvan - [`042330b`](https://github.com/eea/volto-eea-website-theme/commit/042330bc97d32ffe7ba769b4f2453f71cffed706)]
|
16
25
|
- remove RemoveSchema logic [Razvan - [`08d10f8`](https://github.com/eea/volto-eea-website-theme/commit/08d10f8bf6f75478260e4e4c66d7316ba87b907a)]
|
26
|
+
### [1.27.2](https://github.com/eea/volto-eea-website-theme/compare/1.27.1...1.27.2) - 24 January 2024
|
27
|
+
|
17
28
|
### [1.27.1](https://github.com/eea/volto-eea-website-theme/compare/1.27.0...1.27.1) - 18 January 2024
|
18
29
|
|
19
30
|
#### :bug: Bug Fixes
|
@@ -103,11 +114,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
103
114
|
- test: Add real image to cypress test [Alin Voinea - [`4ff591a`](https://github.com/eea/volto-eea-website-theme/commit/4ff591ae3318c9588b4e2114582c0fa6cfdf31ae)]
|
104
115
|
- test: Add cypress tests for Image block styling position and align [Alin Voinea - [`7341ef7`](https://github.com/eea/volto-eea-website-theme/commit/7341ef7b92714fc0cc3ab0c31c39033e7b3e19e7)]
|
105
116
|
- Revert "change(tests): commented out rss test since title block config is missing" [Alin Voinea - [`fb61191`](https://github.com/eea/volto-eea-website-theme/commit/fb611918d6ca380b89b594f283dcf9f685a4b294)]
|
106
|
-
- test: [JENKINS] Use java17 for sonarqube scanner [valentinab25 - [`6a3be30`](https://github.com/eea/volto-eea-website-theme/commit/6a3be3092589411af7808a235f76de5222fd3868)]
|
107
|
-
- test: [JENKINS] Run cypress in started frontend container [valentinab25 - [`c3978f2`](https://github.com/eea/volto-eea-website-theme/commit/c3978f23375ef066e9fd6f6c2e34ba6c1c058f69)]
|
108
|
-
- test: [JENKINS] Add cpu limit on cypress docker [valentinab25 - [`f672779`](https://github.com/eea/volto-eea-website-theme/commit/f672779e845bec9240ccc901e9f53ec80c5a1819)]
|
109
|
-
- test: [JENKINS] Increase shm-size to cypress docker [valentinab25 - [`ae5d8e3`](https://github.com/eea/volto-eea-website-theme/commit/ae5d8e3f4e04dc2808d47ce2ee886e1b23b528da)]
|
110
|
-
- test: [JENKINS] Improve cypress time [valentinab25 - [`170ff0c`](https://github.com/eea/volto-eea-website-theme/commit/170ff0c8e3b30e69479bdf1117e811fea94f1027)]
|
111
117
|
### [1.23.0](https://github.com/eea/volto-eea-website-theme/compare/1.22.1...1.23.0) - 2 November 2023
|
112
118
|
|
113
119
|
#### :rocket: New Features
|
@@ -120,7 +126,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
120
126
|
|
121
127
|
#### :house: Internal changes
|
122
128
|
|
123
|
-
- chore: [JENKINS] Refactor automated testing [valentinab25 - [`f28fce3`](https://github.com/eea/volto-eea-website-theme/commit/f28fce3d1eb815f95fb9aa40de42b10b7e8e30c5)]
|
124
129
|
- chore: husky, lint-staged use fixed versions [valentinab25 - [`6d15088`](https://github.com/eea/volto-eea-website-theme/commit/6d150886c5aeb2ca0b569270486e60f7cc274e2c)]
|
125
130
|
- chore:volto 16 in tests, update docs, fix stylelint overrides [valentinab25 - [`20c0323`](https://github.com/eea/volto-eea-website-theme/commit/20c032380b33c0077c869a05136f93e2fb68e5d4)]
|
126
131
|
|
@@ -306,7 +311,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
306
311
|
|
307
312
|
#### :house: Internal changes
|
308
313
|
|
309
|
-
- chore: [JENKINS] Deprecate circularity website [valentinab25 - [`370dcbf`](https://github.com/eea/volto-eea-website-theme/commit/370dcbfbf1a8135ce7b1b3b271b004552a631837)]
|
310
314
|
|
311
315
|
#### :hammer_and_wrench: Others
|
312
316
|
|
@@ -462,7 +466,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
462
466
|
|
463
467
|
#### :hammer_and_wrench: Others
|
464
468
|
|
465
|
-
- Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`6c5e2f8`](https://github.com/eea/volto-eea-website-theme/commit/6c5e2f80456e2061d9e9c15fd0a0b91b9ac70568)]
|
466
469
|
### [1.9.1](https://github.com/eea/volto-eea-website-theme/compare/1.9.0...1.9.1) - 28 February 2023
|
467
470
|
|
468
471
|
#### :bug: Bug Fixes
|
@@ -609,7 +612,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
609
612
|
|
610
613
|
- For some reasons types is a string [Alin Voinea - [`3769a09`](https://github.com/eea/volto-eea-website-theme/commit/3769a0981181d5b633f3498daebbe96be8b4b833)]
|
611
614
|
- Fix(redirect): o.filter - refs #157627 [Alin Voinea - [`deb23da`](https://github.com/eea/volto-eea-website-theme/commit/deb23da846444cc96539697fd798429ae0abe89e)]
|
612
|
-
- Add Sonarqube tag using advisory-board-frontend addons list [EEA Jenkins - [`f1fffc5`](https://github.com/eea/volto-eea-website-theme/commit/f1fffc5db96725440863d545580b4e76cce4b796)]
|
613
615
|
### [1.5.0](https://github.com/eea/volto-eea-website-theme/compare/1.4.2...1.5.0) - 9 January 2023
|
614
616
|
|
615
617
|
#### :hammer_and_wrench: Others
|
@@ -643,7 +645,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
643
645
|
|
644
646
|
- Release 1.4.0 [Alin Voinea - [`bd42a0d`](https://github.com/eea/volto-eea-website-theme/commit/bd42a0d26e928cac5d99933194755da3db06b341)]
|
645
647
|
- bump version to use as volto-eea-design-system [David Ichim - [`f4be047`](https://github.com/eea/volto-eea-website-theme/commit/f4be047328b46399b03b612d378b18aaf82e7dc1)]
|
646
|
-
- Add Sonarqube tag using advisory-board-frontend addons list [EEA Jenkins - [`9b7cfef`](https://github.com/eea/volto-eea-website-theme/commit/9b7cfefb4d34fc1c948015e491feb370f9795bd8)]
|
647
648
|
- test(Jenkins): Run tests and cypress with latest canary @plone/volto [Alin Voinea - [`df252a9`](https://github.com/eea/volto-eea-website-theme/commit/df252a9bfed0bb86cadf53c59dd1603b1e2cd822)]
|
648
649
|
### [1.3.2](https://github.com/eea/volto-eea-website-theme/compare/1.3.1...1.3.2) - 16 December 2022
|
649
650
|
|
@@ -653,7 +654,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
653
654
|
|
654
655
|
#### :hammer_and_wrench: Others
|
655
656
|
|
656
|
-
- Add Sonarqube tag using cca-frontend addons list [EEA Jenkins - [`a43c658`](https://github.com/eea/volto-eea-website-theme/commit/a43c658a7920c8df95e763b9a637f38ce77eba2c)]
|
657
657
|
- Better razzle.config [Tiberiu Ichim - [`81dbf48`](https://github.com/eea/volto-eea-website-theme/commit/81dbf48815fb27facb4f82c9b764540fdf188b2e)]
|
658
658
|
- Better razzle.config [Tiberiu Ichim - [`7bc9da2`](https://github.com/eea/volto-eea-website-theme/commit/7bc9da2cd837ab62a95cd29979cdd9b0055b7d67)]
|
659
659
|
### [1.3.1](https://github.com/eea/volto-eea-website-theme/compare/1.3.0...1.3.1) - 28 November 2022
|
@@ -664,7 +664,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
664
664
|
|
665
665
|
#### :hammer_and_wrench: Others
|
666
666
|
|
667
|
-
- yarn 3 [Alin Voinea - [`ea7a709`](https://github.com/eea/volto-eea-website-theme/commit/ea7a7094945312776e9b6f44e371178603e92139)]
|
668
667
|
### [1.3.0](https://github.com/eea/volto-eea-website-theme/compare/1.2.0...1.3.0) - 22 November 2022
|
669
668
|
|
670
669
|
#### :rocket: New Features
|
@@ -705,7 +704,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
705
704
|
- Add subsite class to body [Tiberiu Ichim - [`74d700f`](https://github.com/eea/volto-eea-website-theme/commit/74d700fbfd6249a8604762a7e4e49cce857db0f3)]
|
706
705
|
- Add subsite info to header [Tiberiu Ichim - [`47daf8b`](https://github.com/eea/volto-eea-website-theme/commit/47daf8bb6374a1222040626b19d4154df7ba1b83)]
|
707
706
|
- fix eslint [Miu Razvan - [`eb8d0a7`](https://github.com/eea/volto-eea-website-theme/commit/eb8d0a790bc70c0aae256c6ff35f63c4885f338e)]
|
708
|
-
- Add Sonarqube tag using circularity-frontend addons list [EEA Jenkins - [`cc578a4`](https://github.com/eea/volto-eea-website-theme/commit/cc578a413b205a8e61e091fab3a88f94cedefc89)]
|
709
707
|
### [1.1.0](https://github.com/eea/volto-eea-website-theme/compare/1.0.0...1.1.0) - 28 October 2022
|
710
708
|
|
711
709
|
#### :nail_care: Enhancements
|
@@ -753,7 +751,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
753
751
|
|
754
752
|
#### :hammer_and_wrench: Others
|
755
753
|
|
756
|
-
- Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`33b56ac`](https://github.com/eea/volto-eea-website-theme/commit/33b56acb13fbaf0c5b79e8fc6e13c4b699c79c90)]
|
757
754
|
### [0.7.3](https://github.com/eea/volto-eea-website-theme/compare/0.7.2...0.7.3) - 22 September 2022
|
758
755
|
|
759
756
|
#### :hammer_and_wrench: Others
|
@@ -1021,7 +1018,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
1021
1018
|
- Header refactor, add custom logo #5 [ichim-david - [`4950235`](https://github.com/eea/volto-eea-website-theme/commit/49502358105437cfeac3b144e6d301cb59aa2346)]
|
1022
1019
|
- Update footer.config with new publication card component [ichim-david - [`2e38e9a`](https://github.com/eea/volto-eea-website-theme/commit/2e38e9a417f835009d60c80d4eb4b30229f55e45)]
|
1023
1020
|
- feature(breadcrumbs): implement eea-design-system breadcrumb as Volto component #32 #7 [ichim-david - [`181af41`](https://github.com/eea/volto-eea-website-theme/commit/181af4125ce2b9ddac56dab4723cb11c26633221)]
|
1024
|
-
- Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`da8ceb6`](https://github.com/eea/volto-eea-website-theme/commit/da8ceb68ea68bfbc9504e48ccd4d68277f11ab9a)]
|
1025
1021
|
- use breadcrumbs from eea-design-system [nileshgulia1 - [`db2f9e9`](https://github.com/eea/volto-eea-website-theme/commit/db2f9e9a4327420a3cce9a9903cd88549b129eab)]
|
1026
1022
|
- Update theme.config [ichim-david - [`8eca4f4`](https://github.com/eea/volto-eea-website-theme/commit/8eca4f40397a4aeca6d39029c92db78968d37064)]
|
1027
1023
|
- Added keyContent component to theme.config [ichim-david - [`d86f202`](https://github.com/eea/volto-eea-website-theme/commit/d86f202d0274d839487a88b51cae9a0e899beb23)]
|
@@ -1063,5 +1059,4 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
1063
1059
|
|
1064
1060
|
#### :hammer_and_wrench: Others
|
1065
1061
|
|
1066
|
-
- yarn bootstrap [Alin Voinea - [`6995e9e`](https://github.com/eea/volto-eea-website-theme/commit/6995e9e091f21fdbbdffa8a44fc0e2c626f6d46a)]
|
1067
1062
|
- Initial commit [Alin Voinea - [`6a9c03a`](https://github.com/eea/volto-eea-website-theme/commit/6a9c03a7cebe71ca87e82cf58c42904063e9d8d3)]
|
package/README.md
CHANGED
@@ -27,6 +27,8 @@ See [Storybook](https://eea.github.io/eea-storybook/).
|
|
27
27
|
|
28
28
|
## Volto customizations
|
29
29
|
|
30
|
+
- `volto-slate/editor/SlateEditor` -> [ref](https://taskman.eionet.europa.eu/issues/264239#note-11) When two slates looks at the same prop changing one slate and updating the other should be handled properly. This change makes replacing the old value of slate work in sync with the other slates that watches the same prop.
|
31
|
+
|
30
32
|
- `volto/components/manage/Sidebar/SidebarPopup` -> https://github.com/plone/volto/pull/5520
|
31
33
|
|
32
34
|
## Getting started
|
package/jest-addon.config.js
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require('dotenv').config({ path: __dirname + '/.env' })
|
2
|
+
|
1
3
|
module.exports = {
|
2
4
|
testMatch: ['**/src/addons/**/?(*.)+(spec|test).[jt]s?(x)'],
|
3
5
|
collectCoverageFrom: [
|
@@ -9,31 +11,38 @@ module.exports = {
|
|
9
11
|
'@plone/volto/cypress': '<rootDir>/node_modules/@plone/volto/cypress',
|
10
12
|
'@plone/volto/babel': '<rootDir>/node_modules/@plone/volto/babel',
|
11
13
|
'@plone/volto/(.*)$': '<rootDir>/node_modules/@plone/volto/src/$1',
|
12
|
-
'@package/(.*)$': '<rootDir>/src/$1',
|
13
|
-
'@root/(.*)$': '<rootDir>/src/$1',
|
14
|
+
'@package/(.*)$': '<rootDir>/node_modules/@plone/volto/src/$1',
|
15
|
+
'@root/(.*)$': '<rootDir>/node_modules/@plone/volto/src/$1',
|
14
16
|
'@plone/volto-quanta/(.*)$': '<rootDir>/src/addons/volto-quanta/src/$1',
|
15
17
|
'@eeacms/(.*?)/(.*)$': '<rootDir>/node_modules/@eeacms/$1/src/$2',
|
16
|
-
'@plone/volto-slate':
|
18
|
+
'@plone/volto-slate$':
|
17
19
|
'<rootDir>/node_modules/@plone/volto/packages/volto-slate/src',
|
20
|
+
'@plone/volto-slate/(.*)$':
|
21
|
+
'<rootDir>/node_modules/@plone/volto/packages/volto-slate/src/$1',
|
18
22
|
'~/(.*)$': '<rootDir>/src/$1',
|
19
23
|
'load-volto-addons':
|
20
24
|
'<rootDir>/node_modules/@plone/volto/jest-addons-loader.js',
|
21
25
|
},
|
26
|
+
transformIgnorePatterns: [
|
27
|
+
'/node_modules/(?!(@plone|@root|@package|@eeacms)/).*/',
|
28
|
+
],
|
22
29
|
transform: {
|
23
30
|
'^.+\\.js(x)?$': 'babel-jest',
|
24
31
|
'^.+\\.(png)$': 'jest-file',
|
25
32
|
'^.+\\.(jpg)$': 'jest-file',
|
26
33
|
'^.+\\.(svg)$': './node_modules/@plone/volto/jest-svgsystem-transform.js',
|
27
34
|
},
|
28
|
-
transformIgnorePatterns: [
|
29
|
-
'node_modules/(?!@eeacms)/volto-eea-design-system/ui',
|
30
|
-
],
|
31
35
|
coverageThreshold: {
|
32
36
|
global: {
|
33
|
-
branches:
|
34
|
-
functions:
|
35
|
-
lines:
|
36
|
-
statements:
|
37
|
+
branches: 5,
|
38
|
+
functions: 5,
|
39
|
+
lines: 5,
|
40
|
+
statements: 5,
|
37
41
|
},
|
38
42
|
},
|
39
|
-
|
43
|
+
...(process.env.JEST_USE_SETUP === 'ON' && {
|
44
|
+
setupFilesAfterEnv: [
|
45
|
+
'<rootDir>/node_modules/@eeacms/volto-eea-website-theme/jest.setup.js',
|
46
|
+
],
|
47
|
+
}),
|
48
|
+
}
|
package/jest.setup.js
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
import { jest } from '@jest/globals';
|
2
|
+
import configureStore from 'redux-mock-store';
|
3
|
+
import thunk from 'redux-thunk';
|
4
|
+
import { blocksConfig } from '@plone/volto/config/Blocks';
|
5
|
+
import installSlate from '@plone/volto-slate/index';
|
6
|
+
|
7
|
+
var mockSemanticComponents = jest.requireActual('semantic-ui-react');
|
8
|
+
var mockComponents = jest.requireActual('@plone/volto/components');
|
9
|
+
var config = jest.requireActual('@plone/volto/registry').default;
|
10
|
+
|
11
|
+
config.blocks.blocksConfig = {
|
12
|
+
...blocksConfig,
|
13
|
+
...config.blocks.blocksConfig,
|
14
|
+
};
|
15
|
+
|
16
|
+
jest.doMock('semantic-ui-react', () => ({
|
17
|
+
__esModule: true,
|
18
|
+
...mockSemanticComponents,
|
19
|
+
Popup: ({ content, trigger }) => {
|
20
|
+
return (
|
21
|
+
<div className="popup">
|
22
|
+
<div className="trigger">{trigger}</div>
|
23
|
+
<div className="content">{content}</div>
|
24
|
+
</div>
|
25
|
+
);
|
26
|
+
},
|
27
|
+
}));
|
28
|
+
|
29
|
+
jest.doMock('@plone/volto/components', () => {
|
30
|
+
return {
|
31
|
+
__esModule: true,
|
32
|
+
...mockComponents,
|
33
|
+
SidebarPortal: ({ children }) => <div id="sidebar">{children}</div>,
|
34
|
+
};
|
35
|
+
});
|
36
|
+
|
37
|
+
jest.doMock('@plone/volto/registry', () =>
|
38
|
+
[installSlate].reduce((acc, apply) => apply(acc), config),
|
39
|
+
);
|
40
|
+
|
41
|
+
const mockStore = configureStore([thunk]);
|
42
|
+
|
43
|
+
global.fetch = jest.fn(() =>
|
44
|
+
Promise.resolve({
|
45
|
+
json: () => Promise.resolve({}),
|
46
|
+
}),
|
47
|
+
);
|
48
|
+
|
49
|
+
global.store = mockStore({
|
50
|
+
intl: {
|
51
|
+
locale: 'en',
|
52
|
+
messages: {},
|
53
|
+
formatMessage: jest.fn(),
|
54
|
+
},
|
55
|
+
content: {
|
56
|
+
create: {},
|
57
|
+
subrequests: [],
|
58
|
+
},
|
59
|
+
connected_data_parameters: {},
|
60
|
+
screen: {
|
61
|
+
page: {
|
62
|
+
width: 768,
|
63
|
+
},
|
64
|
+
},
|
65
|
+
});
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@eeacms/volto-eea-website-theme",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.28.0",
|
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",
|
@@ -32,6 +32,7 @@
|
|
32
32
|
"@cypress/code-coverage": "^3.10.0",
|
33
33
|
"@plone/scripts": "*",
|
34
34
|
"babel-plugin-transform-class-properties": "^6.24.1",
|
35
|
+
"dotenv": "^16.3.2",
|
35
36
|
"husky": "^8.0.3",
|
36
37
|
"lint-staged": "^14.0.1",
|
37
38
|
"md5": "^2.3.0",
|
@@ -78,4 +79,4 @@
|
|
78
79
|
"cypress:open": "make cypress-open",
|
79
80
|
"prepare": "husky install"
|
80
81
|
}
|
81
|
-
}
|
82
|
+
}
|
@@ -0,0 +1,404 @@
|
|
1
|
+
import ReactDOM from 'react-dom';
|
2
|
+
import cx from 'classnames';
|
3
|
+
import { isEqual, cloneDeep } from 'lodash';
|
4
|
+
import { Transforms, Editor, Point } from 'slate'; // , Transforms
|
5
|
+
import { Slate, Editable, ReactEditor } from 'slate-react';
|
6
|
+
import React, { Component } from 'react'; // , useState
|
7
|
+
import { v4 as uuid } from 'uuid';
|
8
|
+
|
9
|
+
import config from '@plone/volto/registry';
|
10
|
+
|
11
|
+
import { Element, Leaf } from './render';
|
12
|
+
|
13
|
+
import withTestingFeatures from '@plone/volto-slate/editor/extensions/withTestingFeatures';
|
14
|
+
import {
|
15
|
+
makeEditor,
|
16
|
+
toggleInlineFormat,
|
17
|
+
toggleMark,
|
18
|
+
parseDefaultSelection,
|
19
|
+
} from '@plone/volto-slate/utils';
|
20
|
+
import { InlineToolbar } from '@plone/volto-slate/editor/ui';
|
21
|
+
import EditorContext from '@plone/volto-slate/editor/EditorContext';
|
22
|
+
|
23
|
+
import isHotkey from 'is-hotkey';
|
24
|
+
|
25
|
+
import '@plone/volto-slate/editor/less/editor.less';
|
26
|
+
|
27
|
+
import Toolbar from '@plone/volto-slate/editor/ui/Toolbar';
|
28
|
+
|
29
|
+
const handleHotKeys = (editor, event, config) => {
|
30
|
+
let wasHotkey = false;
|
31
|
+
|
32
|
+
for (const hk of Object.entries(config.hotkeys)) {
|
33
|
+
const [shortcut, { format, type }] = hk;
|
34
|
+
if (isHotkey(shortcut, event)) {
|
35
|
+
event.preventDefault();
|
36
|
+
|
37
|
+
if (type === 'inline') {
|
38
|
+
toggleInlineFormat(editor, format);
|
39
|
+
} else {
|
40
|
+
// type === 'mark'
|
41
|
+
toggleMark(editor, format);
|
42
|
+
}
|
43
|
+
|
44
|
+
wasHotkey = true;
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
return wasHotkey;
|
49
|
+
};
|
50
|
+
|
51
|
+
function resetNodes(editor, options = {}) {
|
52
|
+
const children = [...editor.children];
|
53
|
+
|
54
|
+
children.forEach((node) =>
|
55
|
+
editor.apply({ type: 'remove_node', path: [0], node }),
|
56
|
+
);
|
57
|
+
|
58
|
+
if (options.nodes) {
|
59
|
+
options.nodes.forEach((node, i) =>
|
60
|
+
editor.apply({ type: 'insert_node', path: [i], node: node }),
|
61
|
+
);
|
62
|
+
}
|
63
|
+
|
64
|
+
const point =
|
65
|
+
options.at && Point.isPoint(options.at)
|
66
|
+
? options.at
|
67
|
+
: Editor.end(editor, []);
|
68
|
+
|
69
|
+
if (point) {
|
70
|
+
Transforms.select(editor, point);
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
// TODO: implement onFocus
|
75
|
+
class SlateEditor extends Component {
|
76
|
+
constructor(props) {
|
77
|
+
super(props);
|
78
|
+
|
79
|
+
this.createEditor = this.createEditor.bind(this);
|
80
|
+
this.multiDecorator = this.multiDecorator.bind(this);
|
81
|
+
this.handleChange = this.handleChange.bind(this);
|
82
|
+
this.getSavedSelection = this.getSavedSelection.bind(this);
|
83
|
+
this.setSavedSelection = this.setSavedSelection.bind(this);
|
84
|
+
|
85
|
+
this.savedSelection = null;
|
86
|
+
|
87
|
+
const uid = uuid(); // used to namespace the editor's plugins
|
88
|
+
|
89
|
+
this.slateSettings = props.slateSettings || config.settings.slate;
|
90
|
+
|
91
|
+
this.initialValue = cloneDeep(
|
92
|
+
this.props.value || this.slateSettings.defaultValue(),
|
93
|
+
);
|
94
|
+
|
95
|
+
this.state = {
|
96
|
+
editor: this.createEditor(uid),
|
97
|
+
showExpandedToolbar: config.settings.slate.showExpandedToolbar,
|
98
|
+
internalValue: this.initialValue,
|
99
|
+
uid,
|
100
|
+
};
|
101
|
+
|
102
|
+
this.editor = null;
|
103
|
+
this.selectionTimeout = null;
|
104
|
+
}
|
105
|
+
|
106
|
+
getSavedSelection() {
|
107
|
+
return this.savedSelection;
|
108
|
+
}
|
109
|
+
setSavedSelection(selection) {
|
110
|
+
this.savedSelection = selection;
|
111
|
+
}
|
112
|
+
|
113
|
+
createEditor(uid) {
|
114
|
+
// extensions are "editor plugins" or "editor wrappers". It's a similar
|
115
|
+
// similar to OOP inheritance, where a callable creates a new copy of the
|
116
|
+
// editor, while replacing or adding new capabilities to that editor.
|
117
|
+
// Extensions are purely JS, no React components.
|
118
|
+
const editor = makeEditor({ extensions: this.props.extensions });
|
119
|
+
|
120
|
+
// When the editor loses focus it no longer has a valid selections. This
|
121
|
+
// makes it impossible to have complex types of interactions (like filling
|
122
|
+
// in another text box, operating a select menu, etc). For this reason we
|
123
|
+
// save the active selection
|
124
|
+
|
125
|
+
editor.getSavedSelection = this.getSavedSelection;
|
126
|
+
editor.setSavedSelection = this.setSavedSelection;
|
127
|
+
editor.uid = uid || this.state.uid;
|
128
|
+
|
129
|
+
return editor;
|
130
|
+
}
|
131
|
+
|
132
|
+
handleChange(value) {
|
133
|
+
ReactDOM.unstable_batchedUpdates(() => {
|
134
|
+
const newValue = cloneDeep(value);
|
135
|
+
this.setState({ internalValue: newValue });
|
136
|
+
if (this.props.onChange && !isEqual(newValue, this.props.value)) {
|
137
|
+
this.props.onChange(newValue, this.editor);
|
138
|
+
}
|
139
|
+
});
|
140
|
+
}
|
141
|
+
|
142
|
+
multiDecorator([node, path]) {
|
143
|
+
// Decorations (such as higlighting node types, selection, etc).
|
144
|
+
const { runtimeDecorators = [] } = this.slateSettings;
|
145
|
+
return runtimeDecorators.reduce(
|
146
|
+
(acc, deco) => deco(this.state.editor, [node, path], acc),
|
147
|
+
[],
|
148
|
+
);
|
149
|
+
}
|
150
|
+
|
151
|
+
componentDidMount() {
|
152
|
+
// watch the dom change
|
153
|
+
|
154
|
+
if (this.props.selected) {
|
155
|
+
let focused = true;
|
156
|
+
try {
|
157
|
+
focused = ReactEditor.isFocused(this.state.editor);
|
158
|
+
} catch {}
|
159
|
+
if (!focused) {
|
160
|
+
setTimeout(() => {
|
161
|
+
try {
|
162
|
+
ReactEditor.focus(this.state.editor);
|
163
|
+
} catch {}
|
164
|
+
}, 100); // flush
|
165
|
+
}
|
166
|
+
|
167
|
+
this.state.editor.normalize({ force: true });
|
168
|
+
}
|
169
|
+
}
|
170
|
+
|
171
|
+
componentWillUnmount() {
|
172
|
+
this.isUnmounted = true;
|
173
|
+
}
|
174
|
+
|
175
|
+
componentDidUpdate(prevProps) {
|
176
|
+
if (!isEqual(prevProps.extensions, this.props.extensions)) {
|
177
|
+
this.setState({ editor: this.createEditor() });
|
178
|
+
return;
|
179
|
+
}
|
180
|
+
|
181
|
+
if (
|
182
|
+
this.props.value &&
|
183
|
+
!isEqual(this.props.value, this.state.internalValue)
|
184
|
+
) {
|
185
|
+
const newValue = cloneDeep(this.props.value);
|
186
|
+
const { editor } = this.state;
|
187
|
+
|
188
|
+
resetNodes(editor, { nodes: newValue });
|
189
|
+
|
190
|
+
this.setState({
|
191
|
+
internalValue: newValue,
|
192
|
+
});
|
193
|
+
|
194
|
+
if (this.props.defaultSelection) {
|
195
|
+
const selection = parseDefaultSelection(
|
196
|
+
editor,
|
197
|
+
this.props.defaultSelection,
|
198
|
+
);
|
199
|
+
|
200
|
+
ReactEditor.focus(editor);
|
201
|
+
Transforms.select(editor, selection);
|
202
|
+
} else {
|
203
|
+
Transforms.select(editor, Editor.end(editor, []));
|
204
|
+
}
|
205
|
+
return;
|
206
|
+
}
|
207
|
+
|
208
|
+
const { editor } = this.state;
|
209
|
+
|
210
|
+
if (!prevProps.selected && this.props.selected) {
|
211
|
+
// if the SlateEditor becomes selected from unselected
|
212
|
+
|
213
|
+
if (window.getSelection().type === 'None') {
|
214
|
+
// TODO: why is this condition checked?
|
215
|
+
Transforms.select(
|
216
|
+
this.state.editor,
|
217
|
+
Editor.range(this.state.editor, Editor.start(this.state.editor, [])),
|
218
|
+
);
|
219
|
+
}
|
220
|
+
|
221
|
+
ReactEditor.focus(this.state.editor);
|
222
|
+
}
|
223
|
+
|
224
|
+
if (this.props.selected && this.props.onUpdate) {
|
225
|
+
this.props.onUpdate(editor);
|
226
|
+
}
|
227
|
+
}
|
228
|
+
|
229
|
+
shouldComponentUpdate(nextProps, nextState) {
|
230
|
+
const { selected = true, value, readOnly } = nextProps;
|
231
|
+
const res =
|
232
|
+
selected ||
|
233
|
+
this.props.selected !== selected ||
|
234
|
+
this.props.readOnly !== readOnly ||
|
235
|
+
!isEqual(value, this.props.value);
|
236
|
+
return res;
|
237
|
+
}
|
238
|
+
|
239
|
+
render() {
|
240
|
+
const {
|
241
|
+
selected,
|
242
|
+
placeholder,
|
243
|
+
onKeyDown,
|
244
|
+
testingEditorRef,
|
245
|
+
readOnly,
|
246
|
+
className,
|
247
|
+
renderExtensions = [],
|
248
|
+
editableProps = {},
|
249
|
+
} = this.props;
|
250
|
+
const slateSettings = this.slateSettings;
|
251
|
+
|
252
|
+
// renderExtensions is needed because the editor is memoized, so if these
|
253
|
+
// extensions need an updated state (for example to insert updated
|
254
|
+
// blockProps) then we need to always wrap the editor with them
|
255
|
+
const editor = renderExtensions.reduce(
|
256
|
+
(acc, apply) => apply(acc),
|
257
|
+
this.state.editor,
|
258
|
+
);
|
259
|
+
|
260
|
+
// Reset selection if field is reset
|
261
|
+
if (
|
262
|
+
editor.selection &&
|
263
|
+
this.props.value?.length === 1 &&
|
264
|
+
this.props.value[0].children.length === 1 &&
|
265
|
+
this.props.value[0].children[0].text === ''
|
266
|
+
) {
|
267
|
+
Transforms.select(editor, {
|
268
|
+
anchor: { path: [0, 0], offset: 0 },
|
269
|
+
focus: { path: [0, 0], offset: 0 },
|
270
|
+
});
|
271
|
+
}
|
272
|
+
this.editor = editor;
|
273
|
+
|
274
|
+
if (testingEditorRef) {
|
275
|
+
testingEditorRef.current = editor;
|
276
|
+
}
|
277
|
+
|
278
|
+
// debug-values are `data-` HTML attributes in withTestingFeatures HOC
|
279
|
+
|
280
|
+
return (
|
281
|
+
<div
|
282
|
+
{...this.props['debug-values']}
|
283
|
+
className={cx('slate-editor', {
|
284
|
+
'show-toolbar': this.state.showExpandedToolbar,
|
285
|
+
selected,
|
286
|
+
})}
|
287
|
+
tabIndex={-1}
|
288
|
+
>
|
289
|
+
<EditorContext.Provider value={editor}>
|
290
|
+
<Slate
|
291
|
+
editor={editor}
|
292
|
+
initialValue={this.initialValue}
|
293
|
+
onChange={this.handleChange}
|
294
|
+
>
|
295
|
+
{selected ? (
|
296
|
+
<>
|
297
|
+
<InlineToolbar
|
298
|
+
editor={editor}
|
299
|
+
className={className}
|
300
|
+
slateSettings={this.props.slateSettings}
|
301
|
+
/>
|
302
|
+
{Object.keys(slateSettings.elementToolbarButtons).map(
|
303
|
+
(t, i) => {
|
304
|
+
return (
|
305
|
+
<Toolbar elementType={t} key={i}>
|
306
|
+
{slateSettings.elementToolbarButtons[t].map(
|
307
|
+
(Btn, b) => {
|
308
|
+
return <Btn editor={editor} key={b} />;
|
309
|
+
},
|
310
|
+
)}
|
311
|
+
</Toolbar>
|
312
|
+
);
|
313
|
+
},
|
314
|
+
)}
|
315
|
+
</>
|
316
|
+
) : (
|
317
|
+
''
|
318
|
+
)}
|
319
|
+
<Editable
|
320
|
+
tabIndex={this.props.tabIndex || 0}
|
321
|
+
readOnly={readOnly}
|
322
|
+
placeholder={placeholder}
|
323
|
+
renderElement={(props) => <Element {...props} />}
|
324
|
+
renderLeaf={(props) => <Leaf {...props} />}
|
325
|
+
decorate={this.multiDecorator}
|
326
|
+
spellCheck={false}
|
327
|
+
scrollSelectionIntoView={
|
328
|
+
slateSettings.scrollIntoView ? undefined : () => null
|
329
|
+
}
|
330
|
+
onBlur={() => {
|
331
|
+
this.props.onBlur && this.props.onBlur();
|
332
|
+
return null;
|
333
|
+
}}
|
334
|
+
onClick={this.props.onClick}
|
335
|
+
onSelect={(e) => {
|
336
|
+
if (!selected && this.props.onFocus) {
|
337
|
+
// we can't overwrite the onFocus of Editable, as the onFocus
|
338
|
+
// in Slate has too much builtin behaviour that's not
|
339
|
+
// accessible otherwise. Instead we try to detect such an
|
340
|
+
// event based on observing selected state
|
341
|
+
if (!editor.selection) {
|
342
|
+
setTimeout(() => {
|
343
|
+
this.props.onFocus();
|
344
|
+
}, 100); // TODO: why 100 is chosen here?
|
345
|
+
}
|
346
|
+
}
|
347
|
+
|
348
|
+
if (this.selectionTimeout) clearTimeout(this.selectionTimeout);
|
349
|
+
this.selectionTimeout = setTimeout(() => {
|
350
|
+
if (
|
351
|
+
editor.selection &&
|
352
|
+
!isEqual(editor.selection, this.savedSelection) &&
|
353
|
+
!this.isUnmounted
|
354
|
+
) {
|
355
|
+
this.setState((state) => ({ update: !this.state.update }));
|
356
|
+
this.setSavedSelection(
|
357
|
+
JSON.parse(JSON.stringify(editor.selection)),
|
358
|
+
);
|
359
|
+
}
|
360
|
+
}, 200);
|
361
|
+
}}
|
362
|
+
onKeyDown={(event) => {
|
363
|
+
const handled = handleHotKeys(editor, event, slateSettings);
|
364
|
+
if (handled) return;
|
365
|
+
onKeyDown && onKeyDown({ editor, event });
|
366
|
+
}}
|
367
|
+
{...editableProps}
|
368
|
+
/>
|
369
|
+
{selected &&
|
370
|
+
slateSettings.persistentHelpers.map((Helper, i) => {
|
371
|
+
return <Helper key={i} editor={editor} />;
|
372
|
+
})}
|
373
|
+
{this.props.debug ? (
|
374
|
+
<ul>
|
375
|
+
<li>{selected ? 'selected' : 'no-selected'}</li>
|
376
|
+
<li>
|
377
|
+
{ReactEditor.isFocused(editor) ? 'focused' : 'unfocused'}
|
378
|
+
</li>
|
379
|
+
<li>
|
380
|
+
savedSelection: {JSON.stringify(editor.getSavedSelection())}
|
381
|
+
</li>
|
382
|
+
<li>live selection: {JSON.stringify(editor.selection)}</li>
|
383
|
+
<li>children: {JSON.stringify(editor.children)}</li>
|
384
|
+
</ul>
|
385
|
+
) : (
|
386
|
+
''
|
387
|
+
)}
|
388
|
+
{this.props.children}
|
389
|
+
</Slate>
|
390
|
+
</EditorContext.Provider>
|
391
|
+
</div>
|
392
|
+
);
|
393
|
+
}
|
394
|
+
}
|
395
|
+
|
396
|
+
SlateEditor.defaultProps = {
|
397
|
+
extensions: [],
|
398
|
+
className: '',
|
399
|
+
};
|
400
|
+
|
401
|
+
// May be needed to wrap in React.memo(), it used to be wrapped in connect()
|
402
|
+
export default __CLIENT__ && window?.Cypress
|
403
|
+
? withTestingFeatures(SlateEditor)
|
404
|
+
: SlateEditor;
|
package/src/index.js
CHANGED
@@ -8,6 +8,7 @@ import { TokenWidget } from '@eeacms/volto-eea-website-theme/components/theme/Wi
|
|
8
8
|
import { TopicsWidget } from '@eeacms/volto-eea-website-theme/components/theme/Widgets/TopicsWidget';
|
9
9
|
import { Icon } from '@plone/volto/components';
|
10
10
|
import { getBlocks } from '@plone/volto/helpers';
|
11
|
+
import { serializeNodesToText } from '@plone/volto-slate/editor/render';
|
11
12
|
import Tag from '@eeacms/volto-eea-design-system/ui/Tag/Tag';
|
12
13
|
|
13
14
|
import {
|
@@ -224,6 +225,20 @@ const applyConfig = (config) => {
|
|
224
225
|
...config.views.errorViews,
|
225
226
|
'404': NotFound,
|
226
227
|
};
|
228
|
+
// Apply slate text block customization
|
229
|
+
if (config.blocks.blocksConfig.slate) {
|
230
|
+
config.blocks.blocksConfig.slate.tocEntry = (block = {}) => {
|
231
|
+
const { value, override_toc, entry_text, level } = block;
|
232
|
+
const plaintext =
|
233
|
+
serializeNodesToText(block.value || []) || block.plaintext;
|
234
|
+
const type = value?.[0]?.type;
|
235
|
+
return override_toc && level
|
236
|
+
? [parseInt(level.slice(1)), entry_text]
|
237
|
+
: config.settings.slate.topLevelTargetElements.includes(type)
|
238
|
+
? [parseInt(type.slice(1)), plaintext]
|
239
|
+
: null;
|
240
|
+
};
|
241
|
+
}
|
227
242
|
// Apply accordion block customization
|
228
243
|
if (config.blocks.blocksConfig.accordion) {
|
229
244
|
config.blocks.blocksConfig.accordion.titleIcons = {
|