@eeacms/volto-group-block 6.2.0 → 6.2.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/CHANGELOG.md +36 -0
- package/DEVELOP.md +56 -0
- package/README.md +4 -0
- package/docker-compose.yml +28 -0
- package/locales/de/LC_MESSAGES/volto.po +14 -0
- package/locales/it/LC_MESSAGES/volto.po +14 -0
- package/locales/ro/LC_MESSAGES/volto.po +14 -0
- package/locales/volto.pot +16 -0
- package/package.json +1 -1
- package/src/components/manage/Blocks/Group/CounterComponent.jsx +39 -32
- package/src/components/manage/Blocks/Group/CounterComponent.test.jsx +234 -0
- package/src/components/manage/Blocks/Group/Edit.test.jsx +107 -0
- package/src/index.test.js +101 -0
- package/.i18n.babel.config.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ 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
|
+
### [6.2.1](https://github.com/eea/volto-group-block/compare/6.2.0...6.2.1) - 18 August 2023
|
|
8
|
+
|
|
9
|
+
#### :bug: Bug Fixes
|
|
10
|
+
|
|
11
|
+
- fix: ignoreSpaces on char counter - refs #256525 [rexalex - [`8d1ad2c`](https://github.com/eea/volto-group-block/commit/8d1ad2cfdf972b88f02f9efc4b7ef55b1e4b3592)]
|
|
12
|
+
|
|
13
|
+
#### :house: Documentation changes
|
|
14
|
+
|
|
15
|
+
- docs: Cleanup Makefile, update DEVELOP documentation, i18n - refs #254894 [valentinab25 - [`94b58f7`](https://github.com/eea/volto-group-block/commit/94b58f7c0390bfcac24adbfbea61577137c91e2b)]
|
|
16
|
+
|
|
17
|
+
#### :hammer_and_wrench: Others
|
|
18
|
+
|
|
19
|
+
- test: increase test coverage - refs #254313 [ana-oprea - [`5facade`](https://github.com/eea/volto-group-block/commit/5facadec2f866a066ca836f8247a5e58ea44d176)]
|
|
7
20
|
### [6.2.0](https://github.com/eea/volto-group-block/compare/6.1.2...6.2.0) - 20 July 2023
|
|
8
21
|
|
|
9
22
|
#### :nail_care: Enhancements
|
|
@@ -17,6 +30,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
17
30
|
|
|
18
31
|
#### :house: Internal changes
|
|
19
32
|
|
|
33
|
+
- chore: [JENKINS] Deprecate circularity website [valentinab25 - [`ad30e83`](https://github.com/eea/volto-group-block/commit/ad30e832bb869b67dc4e64ed99590b51cb80ab75)]
|
|
20
34
|
|
|
21
35
|
#### :hammer_and_wrench: Others
|
|
22
36
|
|
|
@@ -33,12 +47,19 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
33
47
|
|
|
34
48
|
#### :hammer_and_wrench: Others
|
|
35
49
|
|
|
50
|
+
- Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`37ffae5`](https://github.com/eea/volto-group-block/commit/37ffae512967b36af22cbed208a3ec9e1ddc392b)]
|
|
36
51
|
## [6.0.0](https://github.com/eea/volto-group-block/compare/5.0.1...6.0.0) - 24 March 2023
|
|
37
52
|
|
|
38
53
|
#### :hammer_and_wrench: Others
|
|
39
54
|
|
|
40
55
|
- (feat): Possibility to copy/cut/paste blocks within section group block - refs #157469 [dobri1408 - [`e9fc098`](https://github.com/eea/volto-group-block/commit/e9fc09825ba2ae258feb77864491d97d94c585b4)]
|
|
56
|
+
- Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`db4b09a`](https://github.com/eea/volto-group-block/commit/db4b09a6c14a8b271dec0c766886ffbcc3fe205e)]
|
|
57
|
+
- Add Sonarqube tag using advisory-board-frontend addons list [EEA Jenkins - [`b8c2bf4`](https://github.com/eea/volto-group-block/commit/b8c2bf471868bb0394b2dbbf75ccb7917a9ef0bf)]
|
|
58
|
+
- Add Sonarqube tag using advisory-board-frontend addons list [EEA Jenkins - [`b343119`](https://github.com/eea/volto-group-block/commit/b3431196931fd568476fa8bf6fbc508e086229ae)]
|
|
41
59
|
- test(Jenkins): Run tests and cypress with latest canary @plone/volto [Alin Voinea - [`2f42e7c`](https://github.com/eea/volto-group-block/commit/2f42e7c19a1da5a9c6a883cb4f101e8fa224ff94)]
|
|
60
|
+
- Add Sonarqube tag using cca-frontend addons list [EEA Jenkins - [`73afcc2`](https://github.com/eea/volto-group-block/commit/73afcc2f417797cedaa78cceefb007001d6c2406)]
|
|
61
|
+
- yarn 3 [Alin Voinea - [`3c00ccc`](https://github.com/eea/volto-group-block/commit/3c00ccc7110bbf12a4d268182313418fb46b1a5d)]
|
|
62
|
+
- Add Sonarqube tag using demo-kitkat-frontend addons list [EEA Jenkins - [`9b9662b`](https://github.com/eea/volto-group-block/commit/9b9662bda1da70ba0c3a7b4b05cebf130ed89e9e)]
|
|
42
63
|
### [5.0.1](https://github.com/eea/volto-group-block/compare/5.0.0...5.0.1) - 16 November 2022
|
|
43
64
|
|
|
44
65
|
#### :nail_care: Enhancements
|
|
@@ -55,6 +76,8 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
55
76
|
|
|
56
77
|
- Prepare 5.0.0 release [Miu Razvan - [`88c0ddd`](https://github.com/eea/volto-group-block/commit/88c0ddd569aeda7ee34d1eadea6a087f4e7dc257)]
|
|
57
78
|
- Update dependencies [Alin Voinea - [`c8405af`](https://github.com/eea/volto-group-block/commit/c8405afb830cdf62e7877bf30b619933519e1d71)]
|
|
79
|
+
- Add Sonarqube tag using marine-frontend addons list [EEA Jenkins - [`18e26c6`](https://github.com/eea/volto-group-block/commit/18e26c6939706d572ab8574e9b1826b9abc76314)]
|
|
80
|
+
- Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`8ed6d21`](https://github.com/eea/volto-group-block/commit/8ed6d21d8489911cc4cb471e3f8823c35f4adc50)]
|
|
58
81
|
### [4.3.8](https://github.com/eea/volto-group-block/compare/4.3.7...4.3.8) - 26 August 2022
|
|
59
82
|
|
|
60
83
|
### [4.3.7](https://github.com/eea/volto-group-block/compare/4.3.6...4.3.7) - 22 August 2022
|
|
@@ -67,6 +90,9 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
67
90
|
|
|
68
91
|
#### :hammer_and_wrench: Others
|
|
69
92
|
|
|
93
|
+
- Add Sonarqube tag using circularity-frontend addons list [EEA Jenkins - [`4e73f8b`](https://github.com/eea/volto-group-block/commit/4e73f8be3c73559557efadc410cb56abc055d82d)]
|
|
94
|
+
- Add Sonarqube tag using clms-frontend addons list [EEA Jenkins - [`3040335`](https://github.com/eea/volto-group-block/commit/3040335002c63b50208c95918413bc958150e7a9)]
|
|
95
|
+
- Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`386f730`](https://github.com/eea/volto-group-block/commit/386f730ed65f73fe1468b9b77351c97fb70edcc5)]
|
|
70
96
|
### [4.3.5](https://github.com/eea/volto-group-block/compare/4.3.4...4.3.5) - 4 January 2022
|
|
71
97
|
|
|
72
98
|
### [4.3.4](https://github.com/eea/volto-group-block/compare/4.3.3...4.3.4) - 3 January 2022
|
|
@@ -75,15 +101,23 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
75
101
|
|
|
76
102
|
#### :hammer_and_wrench: Others
|
|
77
103
|
|
|
104
|
+
- Add Sonarqube tag using freshwater-frontend addons list [EEA Jenkins - [`3e62d79`](https://github.com/eea/volto-group-block/commit/3e62d79a7ed37d10d623bc845d43e1144f8080f7)]
|
|
78
105
|
### [4.3.2](https://github.com/eea/volto-group-block/compare/4.3.1...4.3.2) - 10 December 2021
|
|
79
106
|
|
|
80
107
|
#### :hammer_and_wrench: Others
|
|
81
108
|
|
|
82
109
|
- Refs #142010 - Optimize Volto-addons gitflow pipelines [valentinab25 - [`bc36cf5`](https://github.com/eea/volto-group-block/commit/bc36cf58c39e2b43c2fbf5189df6ddefc1260857)]
|
|
110
|
+
- Add Sonarqube tag using industry-frontend addons list [EEA Jenkins - [`8038e78`](https://github.com/eea/volto-group-block/commit/8038e783c1e8ddd71e21f72070fdfa8e7e098993)]
|
|
111
|
+
- Add Sonarqube tag using clms-frontend addons list [EEA Jenkins - [`daccdbc`](https://github.com/eea/volto-group-block/commit/daccdbc733e47be7d6536eb67f8f2eea038dc94b)]
|
|
83
112
|
### [4.3.1](https://github.com/eea/volto-group-block/compare/4.3.0...4.3.1) - 11 October 2021
|
|
84
113
|
|
|
85
114
|
#### :hammer_and_wrench: Others
|
|
86
115
|
|
|
116
|
+
- Add Sonarqube tag using bise-frontend addons list [EEA Jenkins - [`b0092e4`](https://github.com/eea/volto-group-block/commit/b0092e4f78a1a0184e22e32bb9806cd57417dfb2)]
|
|
117
|
+
- Add Sonarqube tag using sustainability-frontend addons list [EEA Jenkins - [`ff8889c`](https://github.com/eea/volto-group-block/commit/ff8889cb7b0761b1df43b201984ce40b14e1561b)]
|
|
118
|
+
- Add Sonarqube tag using climate-energy-frontend addons list [EEA Jenkins - [`0375c28`](https://github.com/eea/volto-group-block/commit/0375c28ed1ffe9186a4790b454795c0ca8039f72)]
|
|
119
|
+
- Add Sonarqube tag using ims-frontend addons list [EEA Jenkins - [`c392190`](https://github.com/eea/volto-group-block/commit/c392190f044f5d9397bd2fb8c3d6a357f84960d0)]
|
|
120
|
+
- Add Sonarqube tag using frontend addons list [EEA Jenkins - [`9694501`](https://github.com/eea/volto-group-block/commit/9694501141e6780eba89464d36406e3c93629fd8)]
|
|
87
121
|
### [4.3.0](https://github.com/eea/volto-group-block/compare/4.2.3...4.3.0) - 24 June 2021
|
|
88
122
|
|
|
89
123
|
#### :hammer_and_wrench: Others
|
|
@@ -199,6 +233,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
199
233
|
- Release 1.0.0 [Alin Voinea - [`b6ef873`](https://github.com/eea/volto-group-block/commit/b6ef873cb6f61e17db66fdd4de1d9d4902a66fc6)]
|
|
200
234
|
- Update package meta info [Alin Voinea - [`143b7d4`](https://github.com/eea/volto-group-block/commit/143b7d44438d7afa5e346a9d21a85352df4e925f)]
|
|
201
235
|
- Add Jenkinkins pipeline [Alin Voinea - [`866a4e1`](https://github.com/eea/volto-group-block/commit/866a4e14ea1eb8f5adb01222e576e5ab6dc73a70)]
|
|
236
|
+
- yarn prettier [Alin Voinea - [`e3fe0a3`](https://github.com/eea/volto-group-block/commit/e3fe0a36b89878769341b45198d6c9e2f2584d15)]
|
|
202
237
|
### [0.1.3](https://github.com/eea/volto-group-block/compare/0.1.2...0.1.3) - 9 November 2020
|
|
203
238
|
|
|
204
239
|
#### :hammer_and_wrench: Others
|
|
@@ -238,4 +273,5 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
238
273
|
- Render meta block [Alin Voinea - [`0d44560`](https://github.com/eea/volto-group-block/commit/0d4456011ca56454068a54c610250b02df4ccb3b)]
|
|
239
274
|
- Implement meta block allowedBlocks settings [Alin Voinea - [`f24feb1`](https://github.com/eea/volto-group-block/commit/f24feb1a1751f04841c21c7cd52a517fb02074ba)]
|
|
240
275
|
- Edit meta block [Alin Voinea - [`236d291`](https://github.com/eea/volto-group-block/commit/236d29156fa835a7aa54eecdb4f120de0d64b271)]
|
|
276
|
+
- yarn bootstrap [Alin Voinea - [`e009dfb`](https://github.com/eea/volto-group-block/commit/e009dfb6b9b74d101a6722f0982a5359fc522b6b)]
|
|
241
277
|
- Initial commit [Alin Voinea - [`6a7b0de`](https://github.com/eea/volto-group-block/commit/6a7b0deb8f873d1462fd6a9c61edfc1562b3aace)]
|
package/DEVELOP.md
CHANGED
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
## Develop
|
|
4
4
|
|
|
5
|
+
1. Make sure you have `docker` and `docker compose` installed and running on your machine:
|
|
6
|
+
|
|
7
|
+
```Bash
|
|
8
|
+
git clone https://github.com/eea/volto-group-block.git
|
|
9
|
+
cd volto-group-block
|
|
10
|
+
git checkout -b bugfix-123456 develop
|
|
11
|
+
make
|
|
12
|
+
make start
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
1. Wait for `Volto started at 0.0.0.0:3000` meesage
|
|
16
|
+
|
|
17
|
+
1. Go to http://localhost:3000
|
|
18
|
+
|
|
19
|
+
1. Happy hacking!
|
|
20
|
+
|
|
21
|
+
```Bash
|
|
22
|
+
cd src/addons/volto-group-block/
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Or add @eeacms/volto-group-block to your Volto project
|
|
26
|
+
|
|
5
27
|
Before starting make sure your development environment is properly set. See [Volto Developer Documentation](https://docs.voltocms.com/getting-started/install/)
|
|
6
28
|
|
|
7
29
|
1. Make sure you have installed `yo`, `@plone/generator-volto` and `mrs-developer`
|
|
@@ -48,3 +70,37 @@ Before starting make sure your development environment is properly set. See [Vol
|
|
|
48
70
|
1. Happy hacking!
|
|
49
71
|
|
|
50
72
|
cd src/addons/volto-group-block/
|
|
73
|
+
|
|
74
|
+
## Cypress
|
|
75
|
+
|
|
76
|
+
To run cypress locally, first make sure you don't have any Volto/Plone running on ports `8080` and `3000`.
|
|
77
|
+
|
|
78
|
+
You don't have to be in a `clean-volto-project`, you can be in any Volto Frontend
|
|
79
|
+
project where you added `volto-group-block` to `mrs.developer.json`
|
|
80
|
+
|
|
81
|
+
Go to:
|
|
82
|
+
|
|
83
|
+
```BASH
|
|
84
|
+
cd src/addons/volto-group-block/
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Start:
|
|
88
|
+
|
|
89
|
+
```Bash
|
|
90
|
+
make
|
|
91
|
+
make start
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
This will build and start with Docker a clean `Plone backend` and `Volto Frontend` with `volto-group-block` block installed.
|
|
95
|
+
|
|
96
|
+
Open Cypress Interface:
|
|
97
|
+
|
|
98
|
+
```Bash
|
|
99
|
+
make cypress-open
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Or run it:
|
|
103
|
+
|
|
104
|
+
```Bash
|
|
105
|
+
make cypress-run
|
|
106
|
+
```
|
package/README.md
CHANGED
|
@@ -51,6 +51,10 @@
|
|
|
51
51
|
|
|
52
52
|
1. Make sure you have a [Plone backend](https://plone.org/download) up-and-running at http://localhost:8080/Plone
|
|
53
53
|
|
|
54
|
+
```Bash
|
|
55
|
+
docker compose up backend
|
|
56
|
+
```
|
|
57
|
+
|
|
54
58
|
1. Start Volto frontend
|
|
55
59
|
|
|
56
60
|
- If you already have a volto project, just update `package.json`:
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
version: "3"
|
|
2
|
+
services:
|
|
3
|
+
backend:
|
|
4
|
+
image: plone/plone-backend:${PLONE_VERSION:-6}
|
|
5
|
+
ports:
|
|
6
|
+
- "8080:8080"
|
|
7
|
+
environment:
|
|
8
|
+
SITE: "Plone"
|
|
9
|
+
|
|
10
|
+
frontend:
|
|
11
|
+
build:
|
|
12
|
+
context: ./
|
|
13
|
+
dockerfile: ./Dockerfile
|
|
14
|
+
args:
|
|
15
|
+
ADDON_NAME: "${ADDON_NAME}"
|
|
16
|
+
ADDON_PATH: "${ADDON_PATH}"
|
|
17
|
+
VOLTO_VERSION: ${VOLTO_VERSION:-16}
|
|
18
|
+
ports:
|
|
19
|
+
- "3000:3000"
|
|
20
|
+
- "3001:3001"
|
|
21
|
+
depends_on:
|
|
22
|
+
- backend
|
|
23
|
+
volumes:
|
|
24
|
+
- ./:/app/src/addons/${ADDON_PATH}
|
|
25
|
+
environment:
|
|
26
|
+
RAZZLE_INTERNAL_API_PATH: "http://backend:8080/Plone"
|
|
27
|
+
RAZZLE_DEV_PROXY_API_PATH: "http://backend:8080/Plone"
|
|
28
|
+
HOST: "0.0.0.0"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
msgid ""
|
|
2
|
+
msgstr ""
|
|
3
|
+
"Project-Id-Version: \n"
|
|
4
|
+
"Report-Msgid-Bugs-To: \n"
|
|
5
|
+
"POT-Creation-Date: \n"
|
|
6
|
+
"PO-Revision-Date: \n"
|
|
7
|
+
"Last-Translator: \n"
|
|
8
|
+
"Language: \n"
|
|
9
|
+
"Language-Team: \n"
|
|
10
|
+
"Content-Type: \n"
|
|
11
|
+
"Content-Transfer-Encoding: \n"
|
|
12
|
+
"Plural-Forms: \n"
|
|
13
|
+
|
|
14
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
msgid ""
|
|
2
|
+
msgstr ""
|
|
3
|
+
"Project-Id-Version: \n"
|
|
4
|
+
"Report-Msgid-Bugs-To: \n"
|
|
5
|
+
"POT-Creation-Date: \n"
|
|
6
|
+
"PO-Revision-Date: \n"
|
|
7
|
+
"Last-Translator: \n"
|
|
8
|
+
"Language: \n"
|
|
9
|
+
"Language-Team: \n"
|
|
10
|
+
"Content-Type: \n"
|
|
11
|
+
"Content-Transfer-Encoding: \n"
|
|
12
|
+
"Plural-Forms: \n"
|
|
13
|
+
|
|
14
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
msgid ""
|
|
2
|
+
msgstr ""
|
|
3
|
+
"Project-Id-Version: \n"
|
|
4
|
+
"Report-Msgid-Bugs-To: \n"
|
|
5
|
+
"POT-Creation-Date: \n"
|
|
6
|
+
"PO-Revision-Date: \n"
|
|
7
|
+
"Last-Translator: \n"
|
|
8
|
+
"Language: \n"
|
|
9
|
+
"Language-Team: \n"
|
|
10
|
+
"Content-Type: \n"
|
|
11
|
+
"Content-Transfer-Encoding: \n"
|
|
12
|
+
"Plural-Forms: \n"
|
|
13
|
+
|
|
14
|
+
|
package/locales/volto.pot
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
msgid ""
|
|
2
|
+
msgstr ""
|
|
3
|
+
"Project-Id-Version: Plone\n"
|
|
4
|
+
"POT-Creation-Date: 2023-06-28T10:48:22.678Z\n"
|
|
5
|
+
"Last-Translator: Plone i18n <plone-i18n@lists.sourceforge.net>\n"
|
|
6
|
+
"Language-Team: Plone i18n <plone-i18n@lists.sourceforge.net>\n"
|
|
7
|
+
"MIME-Version: 1.0\n"
|
|
8
|
+
"Content-Type: text/plain; charset=utf-8\n"
|
|
9
|
+
"Content-Transfer-Encoding: 8bit\n"
|
|
10
|
+
"Plural-Forms: nplurals=1; plural=0;\n"
|
|
11
|
+
"Language-Code: en\n"
|
|
12
|
+
"Language-Name: English\n"
|
|
13
|
+
"Preferred-Encodings: utf-8\n"
|
|
14
|
+
"Domain: volto\n"
|
|
15
|
+
|
|
16
|
+
|
package/package.json
CHANGED
|
@@ -8,46 +8,53 @@ import { serializeNodesToText } from '@plone/volto-slate/editor/render';
|
|
|
8
8
|
import delightedSVG from '@plone/volto/icons/delighted.svg';
|
|
9
9
|
import dissatisfiedSVG from '@plone/volto/icons/dissatisfied.svg';
|
|
10
10
|
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const countCharsWithoutSpaces = (paragraph) => {
|
|
16
|
-
const regex = /[^\s\\]/g;
|
|
11
|
+
const countCharsWithoutSpaces = (paragraph) => {
|
|
12
|
+
const regex = /[^\s\\]/g;
|
|
13
|
+
return (paragraph.match(regex) || []).length;
|
|
14
|
+
};
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
const countCharsWithSpaces = (paragraph) => {
|
|
17
|
+
return paragraph?.length || 0;
|
|
18
|
+
};
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
const countTextInEachBlock = (countTextIn, ignoreSpaces, groupCharCount) => ([
|
|
21
|
+
id,
|
|
22
|
+
blockData,
|
|
23
|
+
]) => {
|
|
24
|
+
const foundText =
|
|
25
|
+
blockData && countTextIn?.includes(blockData?.['@type'])
|
|
26
|
+
? isString(blockData?.plaintext)
|
|
27
|
+
? blockData?.plaintext
|
|
28
|
+
: isArray(blockData?.value) && blockData?.value !== null
|
|
29
|
+
? serializeNodesToText(blockData?.value)
|
|
30
|
+
: ''
|
|
31
|
+
: '';
|
|
24
32
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return groupCharCount;
|
|
30
|
-
}
|
|
31
|
-
if (!blocksObject) return groupCharCount;
|
|
33
|
+
groupCharCount.value += ignoreSpaces
|
|
34
|
+
? countCharsWithoutSpaces(foundText)
|
|
35
|
+
: countCharsWithSpaces(foundText);
|
|
36
|
+
};
|
|
32
37
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
else if (isArray(data?.value) && data?.value !== null)
|
|
38
|
-
foundText = serializeNodesToText(data?.value);
|
|
39
|
-
} else foundText = '';
|
|
38
|
+
const countTextInBlocks = (blocksObject, ignoreSpaces, maxChars) => {
|
|
39
|
+
const { countTextIn } = config.blocks?.blocksConfig?.group;
|
|
40
|
+
// use obj ref to update value - if you send number it will not be updated
|
|
41
|
+
const groupCharCount = { value: 0 };
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
});
|
|
43
|
+
if (!maxChars || !blocksObject) {
|
|
44
|
+
return groupCharCount.value;
|
|
45
|
+
}
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
visitBlocks(
|
|
48
|
+
blocksObject,
|
|
49
|
+
countTextInEachBlock(countTextIn, ignoreSpaces, groupCharCount),
|
|
50
|
+
);
|
|
48
51
|
|
|
49
|
-
|
|
52
|
+
return groupCharCount.value;
|
|
53
|
+
};
|
|
50
54
|
|
|
55
|
+
const CounterComponent = ({ data, setSidebarTab, setSelectedBlock }) => {
|
|
56
|
+
const { maxChars, ignoreSpaces } = data;
|
|
57
|
+
const charCount = countTextInBlocks(data?.data, ignoreSpaces, maxChars);
|
|
51
58
|
const counterClass =
|
|
52
59
|
charCount < Math.ceil(maxChars / 1.05)
|
|
53
60
|
? 'info'
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
import CounterComponent from './CounterComponent';
|
|
4
|
+
import '@testing-library/jest-dom/extend-expect';
|
|
5
|
+
|
|
6
|
+
jest.mock('@plone/volto/registry', () => ({
|
|
7
|
+
blocks: {
|
|
8
|
+
blocksConfig: {
|
|
9
|
+
group: {
|
|
10
|
+
countTextIn: ['text'],
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
jest.mock('@plone/volto-slate/editor/render', () => ({
|
|
17
|
+
serializeNodesToText: jest.fn((nodes) =>
|
|
18
|
+
nodes.map((node) => node.text).join(' '),
|
|
19
|
+
),
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
describe('CounterComponent', () => {
|
|
23
|
+
const setSidebarTab = jest.fn();
|
|
24
|
+
const setSelectedBlock = jest.fn();
|
|
25
|
+
|
|
26
|
+
it('should render info class when character count is less than 95% of maxChars', () => {
|
|
27
|
+
const { container, getByText } = render(
|
|
28
|
+
<CounterComponent
|
|
29
|
+
data={{
|
|
30
|
+
maxChars: 100,
|
|
31
|
+
data: {
|
|
32
|
+
blocks: {
|
|
33
|
+
block1: { '@type': 'text', plaintext: 'test' },
|
|
34
|
+
},
|
|
35
|
+
blocks_layout: {
|
|
36
|
+
items: ['block1'],
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
}}
|
|
40
|
+
setSidebarTab={setSidebarTab}
|
|
41
|
+
setSelectedBlock={setSelectedBlock}
|
|
42
|
+
/>,
|
|
43
|
+
);
|
|
44
|
+
expect(getByText('96 characters remaining out of 100')).toBeInTheDocument();
|
|
45
|
+
expect(container.querySelector('.counter.info')).toBeInTheDocument();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should render warning class when character count is between 95% and 100% of maxChars', () => {
|
|
49
|
+
const { container, getByText } = render(
|
|
50
|
+
<CounterComponent
|
|
51
|
+
data={{
|
|
52
|
+
maxChars: 100,
|
|
53
|
+
data: {
|
|
54
|
+
blocks: {
|
|
55
|
+
block1: { '@type': 'text', plaintext: 'test'.repeat(24) },
|
|
56
|
+
},
|
|
57
|
+
blocks_layout: {
|
|
58
|
+
items: ['block1'],
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
}}
|
|
62
|
+
setSidebarTab={setSidebarTab}
|
|
63
|
+
setSelectedBlock={setSelectedBlock}
|
|
64
|
+
/>,
|
|
65
|
+
);
|
|
66
|
+
expect(getByText('4 characters remaining out of 100')).toBeInTheDocument();
|
|
67
|
+
expect(container.querySelector('.counter.warning')).toBeInTheDocument();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should render warning class when character count is over the maxChars', () => {
|
|
71
|
+
const { container, getByText } = render(
|
|
72
|
+
<CounterComponent
|
|
73
|
+
data={{
|
|
74
|
+
maxChars: 100,
|
|
75
|
+
data: {
|
|
76
|
+
blocks: {
|
|
77
|
+
block1: { '@type': 'text', plaintext: 'test'.repeat(26) },
|
|
78
|
+
},
|
|
79
|
+
blocks_layout: {
|
|
80
|
+
items: ['block1'],
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
}}
|
|
84
|
+
setSidebarTab={setSidebarTab}
|
|
85
|
+
setSelectedBlock={setSelectedBlock}
|
|
86
|
+
/>,
|
|
87
|
+
);
|
|
88
|
+
expect(getByText('4 characters over the limit')).toBeInTheDocument();
|
|
89
|
+
expect(container.querySelector('.counter.danger')).toBeInTheDocument();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should handle click event', () => {
|
|
93
|
+
const { container } = render(
|
|
94
|
+
<CounterComponent
|
|
95
|
+
data={{
|
|
96
|
+
maxChars: 100,
|
|
97
|
+
data: {
|
|
98
|
+
blocks: {
|
|
99
|
+
block1: {
|
|
100
|
+
'@type': 'text',
|
|
101
|
+
plaintext: 'test'.repeat(24),
|
|
102
|
+
ignoreSpaces: true,
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
blocks_layout: {
|
|
106
|
+
items: ['block1'],
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
}}
|
|
110
|
+
setSidebarTab={setSidebarTab}
|
|
111
|
+
setSelectedBlock={setSelectedBlock}
|
|
112
|
+
/>,
|
|
113
|
+
);
|
|
114
|
+
container.querySelector('.counter').click();
|
|
115
|
+
expect(setSidebarTab).toHaveBeenCalledWith(1);
|
|
116
|
+
expect(setSelectedBlock).toHaveBeenCalled();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should handle click event with maxChar undefined', () => {
|
|
120
|
+
const { container } = render(
|
|
121
|
+
<CounterComponent
|
|
122
|
+
data={{
|
|
123
|
+
maxChars: undefined,
|
|
124
|
+
data: undefined,
|
|
125
|
+
}}
|
|
126
|
+
setSidebarTab={setSidebarTab}
|
|
127
|
+
setSelectedBlock={setSelectedBlock}
|
|
128
|
+
/>,
|
|
129
|
+
);
|
|
130
|
+
container.querySelector('.counter').click();
|
|
131
|
+
expect(setSidebarTab).toHaveBeenCalledWith(1);
|
|
132
|
+
expect(setSelectedBlock).toHaveBeenCalled();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('should handle click event with data undefined', () => {
|
|
136
|
+
const { container } = render(
|
|
137
|
+
<CounterComponent
|
|
138
|
+
data={{
|
|
139
|
+
maxChars: 100,
|
|
140
|
+
data: undefined,
|
|
141
|
+
}}
|
|
142
|
+
setSidebarTab={setSidebarTab}
|
|
143
|
+
setSelectedBlock={setSelectedBlock}
|
|
144
|
+
/>,
|
|
145
|
+
);
|
|
146
|
+
container.querySelector('.counter').click();
|
|
147
|
+
expect(setSidebarTab).toHaveBeenCalledWith(1);
|
|
148
|
+
expect(setSelectedBlock).toHaveBeenCalled();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should handle click event with plaintext undefined, but values present', () => {
|
|
152
|
+
const { container } = render(
|
|
153
|
+
<CounterComponent
|
|
154
|
+
data={{
|
|
155
|
+
maxChars: 100,
|
|
156
|
+
data: {
|
|
157
|
+
blocks: {
|
|
158
|
+
block1: {
|
|
159
|
+
'@type': 'text',
|
|
160
|
+
plaintext: undefined,
|
|
161
|
+
value: [
|
|
162
|
+
{ text: 'test' },
|
|
163
|
+
{ children: [{ text: 'more text' }] },
|
|
164
|
+
],
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
blocks_layout: {
|
|
168
|
+
items: ['block1'],
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
}}
|
|
172
|
+
setSidebarTab={setSidebarTab}
|
|
173
|
+
setSelectedBlock={setSelectedBlock}
|
|
174
|
+
/>,
|
|
175
|
+
);
|
|
176
|
+
container.querySelector('.counter').click();
|
|
177
|
+
expect(setSidebarTab).toHaveBeenCalledWith(1);
|
|
178
|
+
expect(setSelectedBlock).toHaveBeenCalled();
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('should handle click event with plaintext undefined and values is not an array and the type is in countTextIn', () => {
|
|
182
|
+
const { container } = render(
|
|
183
|
+
<CounterComponent
|
|
184
|
+
data={{
|
|
185
|
+
maxChars: 100,
|
|
186
|
+
data: {
|
|
187
|
+
blocks: {
|
|
188
|
+
block1: {
|
|
189
|
+
'@type': 'text',
|
|
190
|
+
plaintext: undefined,
|
|
191
|
+
value: {},
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
blocks_layout: {
|
|
195
|
+
items: ['block1'],
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
}}
|
|
199
|
+
setSidebarTab={setSidebarTab}
|
|
200
|
+
setSelectedBlock={setSelectedBlock}
|
|
201
|
+
/>,
|
|
202
|
+
);
|
|
203
|
+
container.querySelector('.counter').click();
|
|
204
|
+
expect(setSidebarTab).toHaveBeenCalledWith(1);
|
|
205
|
+
expect(setSelectedBlock).toHaveBeenCalled();
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('should handle click event with plaintext undefined and values is not an array and the type is not in countTextIn', () => {
|
|
209
|
+
const { container } = render(
|
|
210
|
+
<CounterComponent
|
|
211
|
+
data={{
|
|
212
|
+
maxChars: 100,
|
|
213
|
+
data: {
|
|
214
|
+
blocks: {
|
|
215
|
+
block1: {
|
|
216
|
+
'@type': 'test',
|
|
217
|
+
plaintext: undefined,
|
|
218
|
+
value: {},
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
blocks_layout: {
|
|
222
|
+
items: ['block1'],
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
}}
|
|
226
|
+
setSidebarTab={setSidebarTab}
|
|
227
|
+
setSelectedBlock={setSelectedBlock}
|
|
228
|
+
/>,
|
|
229
|
+
);
|
|
230
|
+
container.querySelector('.counter').click();
|
|
231
|
+
expect(setSidebarTab).toHaveBeenCalledWith(1);
|
|
232
|
+
expect(setSelectedBlock).toHaveBeenCalled();
|
|
233
|
+
});
|
|
234
|
+
});
|
|
@@ -76,4 +76,111 @@ describe('Edit', () => {
|
|
|
76
76
|
);
|
|
77
77
|
fireEvent.keyDown(getByRole('presentation'), { key: 'ArrowUp', code: 38 });
|
|
78
78
|
});
|
|
79
|
+
|
|
80
|
+
it('should call ArrowUp keydown', () => {
|
|
81
|
+
const props = {
|
|
82
|
+
block: 'testBlock',
|
|
83
|
+
data: {
|
|
84
|
+
instructions: 'test',
|
|
85
|
+
data: {
|
|
86
|
+
blocks: {
|
|
87
|
+
block1: {
|
|
88
|
+
type: 'test',
|
|
89
|
+
data: {
|
|
90
|
+
value: 'Test',
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
blocks_layout: {
|
|
95
|
+
items: [undefined],
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
onChangeBlock,
|
|
100
|
+
onChangeField,
|
|
101
|
+
pathname: '/',
|
|
102
|
+
selected: true,
|
|
103
|
+
manage: true,
|
|
104
|
+
};
|
|
105
|
+
const mockOnFocusPreviousBlock = jest.fn();
|
|
106
|
+
const mockOnFocusNextBlock = jest.fn();
|
|
107
|
+
const mockOnAddBlock = jest.fn();
|
|
108
|
+
const mockSidebarTab = jest.fn();
|
|
109
|
+
|
|
110
|
+
const { container } = render(
|
|
111
|
+
<Provider store={store}>
|
|
112
|
+
<Edit
|
|
113
|
+
{...props}
|
|
114
|
+
onFocusPreviousBlock={mockOnFocusPreviousBlock}
|
|
115
|
+
onFocusNextBlock={mockOnFocusNextBlock}
|
|
116
|
+
onAddBlock={mockOnAddBlock}
|
|
117
|
+
blockNode={mockBlockNode}
|
|
118
|
+
setSidebarTab={mockSidebarTab}
|
|
119
|
+
/>
|
|
120
|
+
</Provider>,
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
fireEvent.keyDown(container.querySelector('.section-block'), {
|
|
124
|
+
key: 'ArrowUp',
|
|
125
|
+
code: 38,
|
|
126
|
+
});
|
|
127
|
+
fireEvent.keyDown(container.querySelector('.section-block'), {
|
|
128
|
+
key: 'ArrowDown',
|
|
129
|
+
code: 40,
|
|
130
|
+
});
|
|
131
|
+
fireEvent.keyDown(container.querySelector('.section-block'), {
|
|
132
|
+
key: 'Enter',
|
|
133
|
+
code: 13,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
fireEvent.click(container.querySelector('.blocks-form'), {
|
|
137
|
+
shiftKey: true,
|
|
138
|
+
});
|
|
139
|
+
fireEvent.click(container.querySelector('.section-block legend'));
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should call ArrowUp keydown', () => {
|
|
143
|
+
const props = {
|
|
144
|
+
block: 'testBlock',
|
|
145
|
+
data: {
|
|
146
|
+
instructions: 'test',
|
|
147
|
+
data: {
|
|
148
|
+
blocks: {
|
|
149
|
+
block1: {
|
|
150
|
+
type: 'test',
|
|
151
|
+
data: {
|
|
152
|
+
value: 'Test',
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
blocks_layout: {
|
|
157
|
+
items: [undefined],
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
onChangeBlock,
|
|
162
|
+
onChangeField,
|
|
163
|
+
pathname: '/',
|
|
164
|
+
selected: true,
|
|
165
|
+
manage: true,
|
|
166
|
+
};
|
|
167
|
+
const mockOnFocusPreviousBlock = jest.fn();
|
|
168
|
+
const mockOnFocusNextBlock = jest.fn();
|
|
169
|
+
const mockOnAddBlock = jest.fn();
|
|
170
|
+
const mockSidebarTab = jest.fn();
|
|
171
|
+
const { container } = render(
|
|
172
|
+
<Provider store={store}>
|
|
173
|
+
<Edit
|
|
174
|
+
{...props}
|
|
175
|
+
onFocusPreviousBlock={mockOnFocusPreviousBlock}
|
|
176
|
+
onFocusNextBlock={mockOnFocusNextBlock}
|
|
177
|
+
onAddBlock={mockOnAddBlock}
|
|
178
|
+
setSidebarTab={mockSidebarTab}
|
|
179
|
+
blockNode={mockBlockNode}
|
|
180
|
+
/>
|
|
181
|
+
</Provider>,
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
fireEvent.click(container.querySelector('.section-block legend'));
|
|
185
|
+
});
|
|
79
186
|
});
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import applyConfig from './index';
|
|
2
|
+
|
|
3
|
+
describe('applyConfig', () => {
|
|
4
|
+
it('should add group block configuration', () => {
|
|
5
|
+
const config = {
|
|
6
|
+
blocks: {
|
|
7
|
+
blocksConfig: {
|
|
8
|
+
text: { title: 'Text', restricted: false },
|
|
9
|
+
image: { title: 'Image', restricted: true },
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const newConfig = applyConfig(config);
|
|
15
|
+
|
|
16
|
+
expect(newConfig.blocks.blocksConfig.group).toBeDefined();
|
|
17
|
+
expect(newConfig.blocks.blocksConfig.group.id).toEqual('group');
|
|
18
|
+
expect(newConfig.blocks.blocksConfig.group.title).toEqual(
|
|
19
|
+
'Section (Group)',
|
|
20
|
+
);
|
|
21
|
+
expect(newConfig.blocks.blocksConfig.group.icon).toBeDefined();
|
|
22
|
+
expect(newConfig.blocks.blocksConfig.group.view).toBeDefined();
|
|
23
|
+
expect(newConfig.blocks.blocksConfig.group.edit).toBeDefined();
|
|
24
|
+
expect(newConfig.blocks.blocksConfig.group.schema).toBeDefined();
|
|
25
|
+
expect(newConfig.blocks.blocksConfig.group.restricted).toEqual(false);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should include allowed blocks in schema', () => {
|
|
29
|
+
const config = {
|
|
30
|
+
blocks: {
|
|
31
|
+
blocksConfig: {
|
|
32
|
+
text: { title: 'Text', restricted: false },
|
|
33
|
+
image: { restricted: false },
|
|
34
|
+
image_test: { title: 'Image', restricted: true },
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const newConfig = applyConfig(config);
|
|
40
|
+
|
|
41
|
+
expect(
|
|
42
|
+
newConfig.blocks.blocksConfig.group.schema.properties.allowedBlocks.items
|
|
43
|
+
.choices,
|
|
44
|
+
).toEqual([
|
|
45
|
+
['text', 'Text'],
|
|
46
|
+
['image', 'image'],
|
|
47
|
+
['group', 'Group'],
|
|
48
|
+
]);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should generate tocEntries correctly', () => {
|
|
52
|
+
const config = {
|
|
53
|
+
blocks: {
|
|
54
|
+
blocksConfig: {},
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const block = {
|
|
59
|
+
data: {
|
|
60
|
+
blocks: {
|
|
61
|
+
block1: { value: [{ type: 'h1' }], plaintext: 'Heading 1' },
|
|
62
|
+
block2: { value: [{ type: 'h2' }], plaintext: 'Heading 2' },
|
|
63
|
+
block3: { value: [{ type: 'h3' }], plaintext: 'Heading 3' }, // This should be ignored
|
|
64
|
+
},
|
|
65
|
+
blocks_layout: {
|
|
66
|
+
items: ['block1', 'block2', 'block3'],
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
const tocData = {
|
|
71
|
+
levels: ['h1', 'h2'],
|
|
72
|
+
};
|
|
73
|
+
const newConfig = applyConfig(config);
|
|
74
|
+
const entries = newConfig.blocks.blocksConfig.group.tocEntries(
|
|
75
|
+
block,
|
|
76
|
+
tocData,
|
|
77
|
+
);
|
|
78
|
+
expect(entries).toEqual([
|
|
79
|
+
[1, 'Heading 1', 'block1'],
|
|
80
|
+
[2, 'Heading 2', 'block2'],
|
|
81
|
+
]);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should generate no entries', () => {
|
|
85
|
+
const config = {
|
|
86
|
+
blocks: {
|
|
87
|
+
blocksConfig: {},
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
const block = undefined;
|
|
91
|
+
const tocData = {
|
|
92
|
+
levels: undefined,
|
|
93
|
+
};
|
|
94
|
+
const newConfig = applyConfig(config);
|
|
95
|
+
const entries = newConfig.blocks.blocksConfig.group.tocEntries(
|
|
96
|
+
block,
|
|
97
|
+
tocData,
|
|
98
|
+
);
|
|
99
|
+
expect(entries).toEqual([]);
|
|
100
|
+
});
|
|
101
|
+
});
|
package/.i18n.babel.config.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
module.exports = require('@plone/volto/babel');
|