@eeacms/volto-group-block 6.1.1 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,11 +4,26 @@ 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.1.1](https://github.com/eea/volto-group-block/compare/6.1.0...6.1.1) - 22 May 2023
7
+ ### [6.2.0](https://github.com/eea/volto-group-block/compare/6.1.2...6.2.0) - 20 July 2023
8
+
9
+ #### :nail_care: Enhancements
10
+
11
+ - refactor: char-count component refs #253801 [Nilesh - [`1a54719`](https://github.com/eea/volto-group-block/commit/1a54719af523663314190741417bb06142967f68)]
12
+
13
+ #### :hammer_and_wrench: Others
8
14
 
9
- #### :rocket: New Features
15
+ - Release 6.2.0 [Alin Voinea - [`e4e254d`](https://github.com/eea/volto-group-block/commit/e4e254da4c109ee1c8c8a9ce42821eeabfae06ef)]
16
+ ### [6.1.2](https://github.com/eea/volto-group-block/compare/6.1.1...6.1.2) - 12 June 2023
10
17
 
11
- - feat: add support for toc [Miu Razvan - [`0c4568b`](https://github.com/eea/volto-group-block/commit/0c4568b816dcfa55820f45f796f115fcf2306dfa)]
18
+ #### :house: Internal changes
19
+
20
+
21
+ #### :hammer_and_wrench: Others
22
+
23
+ - test: jest should look for addons in node_modules Refs #253277 [valentinab25 - [`4352c3a`](https://github.com/eea/volto-group-block/commit/4352c3afb80d6f1cbfca06b27abd11e156f1c216)]
24
+ - test: Add unit tests for View, Edit, EditBlockWrapper - refs #253277 [ana-oprea - [`2f7e7ac`](https://github.com/eea/volto-group-block/commit/2f7e7ac2c9cf7654f5a0b6b123e7589364ba13c2)]
25
+ - test: Fix test config, coverage Refs #253277 [valentinab25 - [`fa46d74`](https://github.com/eea/volto-group-block/commit/fa46d741f4ac393eb7123b09a38b774192550f95)]
26
+ ### [6.1.1](https://github.com/eea/volto-group-block/compare/6.1.0...6.1.1) - 22 May 2023
12
27
 
13
28
  ### [6.1.0](https://github.com/eea/volto-group-block/compare/6.0.0...6.1.0) - 4 April 2023
14
29
 
@@ -18,19 +33,12 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
18
33
 
19
34
  #### :hammer_and_wrench: Others
20
35
 
21
- - Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`37ffae5`](https://github.com/eea/volto-group-block/commit/37ffae512967b36af22cbed208a3ec9e1ddc392b)]
22
36
  ## [6.0.0](https://github.com/eea/volto-group-block/compare/5.0.1...6.0.0) - 24 March 2023
23
37
 
24
38
  #### :hammer_and_wrench: Others
25
39
 
26
40
  - (feat): Possibility to copy/cut/paste blocks within section group block - refs #157469 [dobri1408 - [`e9fc098`](https://github.com/eea/volto-group-block/commit/e9fc09825ba2ae258feb77864491d97d94c585b4)]
27
- - Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`db4b09a`](https://github.com/eea/volto-group-block/commit/db4b09a6c14a8b271dec0c766886ffbcc3fe205e)]
28
- - Add Sonarqube tag using advisory-board-frontend addons list [EEA Jenkins - [`b8c2bf4`](https://github.com/eea/volto-group-block/commit/b8c2bf471868bb0394b2dbbf75ccb7917a9ef0bf)]
29
- - Add Sonarqube tag using advisory-board-frontend addons list [EEA Jenkins - [`b343119`](https://github.com/eea/volto-group-block/commit/b3431196931fd568476fa8bf6fbc508e086229ae)]
30
41
  - test(Jenkins): Run tests and cypress with latest canary @plone/volto [Alin Voinea - [`2f42e7c`](https://github.com/eea/volto-group-block/commit/2f42e7c19a1da5a9c6a883cb4f101e8fa224ff94)]
31
- - Add Sonarqube tag using cca-frontend addons list [EEA Jenkins - [`73afcc2`](https://github.com/eea/volto-group-block/commit/73afcc2f417797cedaa78cceefb007001d6c2406)]
32
- - yarn 3 [Alin Voinea - [`3c00ccc`](https://github.com/eea/volto-group-block/commit/3c00ccc7110bbf12a4d268182313418fb46b1a5d)]
33
- - Add Sonarqube tag using demo-kitkat-frontend addons list [EEA Jenkins - [`9b9662b`](https://github.com/eea/volto-group-block/commit/9b9662bda1da70ba0c3a7b4b05cebf130ed89e9e)]
34
42
  ### [5.0.1](https://github.com/eea/volto-group-block/compare/5.0.0...5.0.1) - 16 November 2022
35
43
 
36
44
  #### :nail_care: Enhancements
@@ -47,8 +55,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
47
55
 
48
56
  - Prepare 5.0.0 release [Miu Razvan - [`88c0ddd`](https://github.com/eea/volto-group-block/commit/88c0ddd569aeda7ee34d1eadea6a087f4e7dc257)]
49
57
  - Update dependencies [Alin Voinea - [`c8405af`](https://github.com/eea/volto-group-block/commit/c8405afb830cdf62e7877bf30b619933519e1d71)]
50
- - Add Sonarqube tag using marine-frontend addons list [EEA Jenkins - [`18e26c6`](https://github.com/eea/volto-group-block/commit/18e26c6939706d572ab8574e9b1826b9abc76314)]
51
- - Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`8ed6d21`](https://github.com/eea/volto-group-block/commit/8ed6d21d8489911cc4cb471e3f8823c35f4adc50)]
52
58
  ### [4.3.8](https://github.com/eea/volto-group-block/compare/4.3.7...4.3.8) - 26 August 2022
53
59
 
54
60
  ### [4.3.7](https://github.com/eea/volto-group-block/compare/4.3.6...4.3.7) - 22 August 2022
@@ -61,9 +67,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
61
67
 
62
68
  #### :hammer_and_wrench: Others
63
69
 
64
- - Add Sonarqube tag using circularity-frontend addons list [EEA Jenkins - [`4e73f8b`](https://github.com/eea/volto-group-block/commit/4e73f8be3c73559557efadc410cb56abc055d82d)]
65
- - Add Sonarqube tag using clms-frontend addons list [EEA Jenkins - [`3040335`](https://github.com/eea/volto-group-block/commit/3040335002c63b50208c95918413bc958150e7a9)]
66
- - Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`386f730`](https://github.com/eea/volto-group-block/commit/386f730ed65f73fe1468b9b77351c97fb70edcc5)]
67
70
  ### [4.3.5](https://github.com/eea/volto-group-block/compare/4.3.4...4.3.5) - 4 January 2022
68
71
 
69
72
  ### [4.3.4](https://github.com/eea/volto-group-block/compare/4.3.3...4.3.4) - 3 January 2022
@@ -72,23 +75,15 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
72
75
 
73
76
  #### :hammer_and_wrench: Others
74
77
 
75
- - Add Sonarqube tag using freshwater-frontend addons list [EEA Jenkins - [`3e62d79`](https://github.com/eea/volto-group-block/commit/3e62d79a7ed37d10d623bc845d43e1144f8080f7)]
76
78
  ### [4.3.2](https://github.com/eea/volto-group-block/compare/4.3.1...4.3.2) - 10 December 2021
77
79
 
78
80
  #### :hammer_and_wrench: Others
79
81
 
80
82
  - Refs #142010 - Optimize Volto-addons gitflow pipelines [valentinab25 - [`bc36cf5`](https://github.com/eea/volto-group-block/commit/bc36cf58c39e2b43c2fbf5189df6ddefc1260857)]
81
- - Add Sonarqube tag using industry-frontend addons list [EEA Jenkins - [`8038e78`](https://github.com/eea/volto-group-block/commit/8038e783c1e8ddd71e21f72070fdfa8e7e098993)]
82
- - Add Sonarqube tag using clms-frontend addons list [EEA Jenkins - [`daccdbc`](https://github.com/eea/volto-group-block/commit/daccdbc733e47be7d6536eb67f8f2eea038dc94b)]
83
83
  ### [4.3.1](https://github.com/eea/volto-group-block/compare/4.3.0...4.3.1) - 11 October 2021
84
84
 
85
85
  #### :hammer_and_wrench: Others
86
86
 
87
- - Add Sonarqube tag using bise-frontend addons list [EEA Jenkins - [`b0092e4`](https://github.com/eea/volto-group-block/commit/b0092e4f78a1a0184e22e32bb9806cd57417dfb2)]
88
- - Add Sonarqube tag using sustainability-frontend addons list [EEA Jenkins - [`ff8889c`](https://github.com/eea/volto-group-block/commit/ff8889cb7b0761b1df43b201984ce40b14e1561b)]
89
- - Add Sonarqube tag using climate-energy-frontend addons list [EEA Jenkins - [`0375c28`](https://github.com/eea/volto-group-block/commit/0375c28ed1ffe9186a4790b454795c0ca8039f72)]
90
- - Add Sonarqube tag using ims-frontend addons list [EEA Jenkins - [`c392190`](https://github.com/eea/volto-group-block/commit/c392190f044f5d9397bd2fb8c3d6a357f84960d0)]
91
- - Add Sonarqube tag using frontend addons list [EEA Jenkins - [`9694501`](https://github.com/eea/volto-group-block/commit/9694501141e6780eba89464d36406e3c93629fd8)]
92
87
  ### [4.3.0](https://github.com/eea/volto-group-block/compare/4.2.3...4.3.0) - 24 June 2021
93
88
 
94
89
  #### :hammer_and_wrench: Others
@@ -204,7 +199,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
204
199
  - Release 1.0.0 [Alin Voinea - [`b6ef873`](https://github.com/eea/volto-group-block/commit/b6ef873cb6f61e17db66fdd4de1d9d4902a66fc6)]
205
200
  - Update package meta info [Alin Voinea - [`143b7d4`](https://github.com/eea/volto-group-block/commit/143b7d44438d7afa5e346a9d21a85352df4e925f)]
206
201
  - Add Jenkinkins pipeline [Alin Voinea - [`866a4e1`](https://github.com/eea/volto-group-block/commit/866a4e14ea1eb8f5adb01222e576e5ab6dc73a70)]
207
- - yarn prettier [Alin Voinea - [`e3fe0a3`](https://github.com/eea/volto-group-block/commit/e3fe0a36b89878769341b45198d6c9e2f2584d15)]
208
202
  ### [0.1.3](https://github.com/eea/volto-group-block/compare/0.1.2...0.1.3) - 9 November 2020
209
203
 
210
204
  #### :hammer_and_wrench: Others
@@ -244,5 +238,4 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
244
238
  - Render meta block [Alin Voinea - [`0d44560`](https://github.com/eea/volto-group-block/commit/0d4456011ca56454068a54c610250b02df4ccb3b)]
245
239
  - Implement meta block allowedBlocks settings [Alin Voinea - [`f24feb1`](https://github.com/eea/volto-group-block/commit/f24feb1a1751f04841c21c7cd52a517fb02074ba)]
246
240
  - Edit meta block [Alin Voinea - [`236d291`](https://github.com/eea/volto-group-block/commit/236d29156fa835a7aa54eecdb4f120de0d64b271)]
247
- - yarn bootstrap [Alin Voinea - [`e009dfb`](https://github.com/eea/volto-group-block/commit/e009dfb6b9b74d101a6722f0982a5359fc522b6b)]
248
241
  - Initial commit [Alin Voinea - [`6a7b0de`](https://github.com/eea/volto-group-block/commit/6a7b0deb8f873d1462fd6a9c61edfc1562b3aace)]
@@ -5,19 +5,19 @@ module.exports = {
5
5
  '!src/**/*.d.ts',
6
6
  ],
7
7
  moduleNameMapper: {
8
+ '\\.(css|less|scss|sass)$': 'identity-obj-proxy',
8
9
  '@plone/volto/cypress': '<rootDir>/node_modules/@plone/volto/cypress',
9
10
  '@plone/volto/babel': '<rootDir>/node_modules/@plone/volto/babel',
10
11
  '@plone/volto/(.*)$': '<rootDir>/node_modules/@plone/volto/src/$1',
11
12
  '@package/(.*)$': '<rootDir>/src/$1',
12
13
  '@root/(.*)$': '<rootDir>/src/$1',
13
14
  '@plone/volto-quanta/(.*)$': '<rootDir>/src/addons/volto-quanta/src/$1',
14
- '@eeacms/(.*?)/(.*)$': '<rootDir>/src/addons/$1/src/$2',
15
+ '@eeacms/(.*?)/(.*)$': '<rootDir>/node_modules/@eeacms/$1/src/$2',
15
16
  '@plone/volto-slate':
16
17
  '<rootDir>/node_modules/@plone/volto/packages/volto-slate/src',
17
18
  '~/(.*)$': '<rootDir>/src/$1',
18
19
  'load-volto-addons':
19
20
  '<rootDir>/node_modules/@plone/volto/jest-addons-loader.js',
20
- '\\.(css|less|scss|sass)$': 'identity-obj-proxy',
21
21
  },
22
22
  transform: {
23
23
  '^.+\\.js(x)?$': 'babel-jest',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-group-block",
3
- "version": "6.1.1",
3
+ "version": "6.2.0",
4
4
  "description": "volto-group-block: Volto block to be used to group other blocks",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -0,0 +1,84 @@
1
+ import cx from 'classnames';
2
+ import isString from 'lodash/isString';
3
+ import isArray from 'lodash/isArray';
4
+ import { Icon } from '@plone/volto/components';
5
+ import config from '@plone/volto/registry';
6
+ import { visitBlocks } from '@plone/volto/helpers/Blocks/Blocks';
7
+ import { serializeNodesToText } from '@plone/volto-slate/editor/render';
8
+ import delightedSVG from '@plone/volto/icons/delighted.svg';
9
+ import dissatisfiedSVG from '@plone/volto/icons/dissatisfied.svg';
10
+
11
+ const CounterComponent = ({ data, setSidebarTab, setSelectedBlock }) => {
12
+ const { maxChars } = data;
13
+ let charCount = 0;
14
+
15
+ const countCharsWithoutSpaces = (paragraph) => {
16
+ const regex = /[^\s\\]/g;
17
+
18
+ return (paragraph.match(regex) || []).length;
19
+ };
20
+
21
+ const countCharsWithSpaces = (paragraph) => {
22
+ return paragraph?.length || 0;
23
+ };
24
+
25
+ const countTextInBlocks = (blocksObject) => {
26
+ const { countTextIn } = config.blocks?.blocksConfig?.group;
27
+ let groupCharCount = 0;
28
+ if (!maxChars) {
29
+ return groupCharCount;
30
+ }
31
+ if (!blocksObject) return groupCharCount;
32
+
33
+ visitBlocks(blocksObject, ([id, data]) => {
34
+ let foundText;
35
+ if (data && countTextIn?.includes(data?.['@type'])) {
36
+ if (isString(data?.plaintext)) foundText = data?.plaintext;
37
+ else if (isArray(data?.value) && data?.value !== null)
38
+ foundText = serializeNodesToText(data?.value);
39
+ } else foundText = '';
40
+
41
+ groupCharCount += data?.ignoreSpaces
42
+ ? countCharsWithoutSpaces(foundText)
43
+ : countCharsWithSpaces(foundText);
44
+ });
45
+
46
+ return groupCharCount;
47
+ };
48
+
49
+ charCount = countTextInBlocks(data?.data);
50
+
51
+ const counterClass =
52
+ charCount < Math.ceil(maxChars / 1.05)
53
+ ? 'info'
54
+ : charCount < maxChars
55
+ ? 'warning'
56
+ : 'danger';
57
+
58
+ return (
59
+ <p
60
+ className={cx('counter', counterClass)}
61
+ onClick={() => {
62
+ setSelectedBlock();
63
+ setSidebarTab(1);
64
+ }}
65
+ aria-hidden="true"
66
+ >
67
+ {maxChars - charCount < 0 ? (
68
+ <>
69
+ <span>{`${charCount - maxChars} characters over the limit`}</span>
70
+ <Icon name={dissatisfiedSVG} size="24px" />
71
+ </>
72
+ ) : (
73
+ <>
74
+ <span>{`${
75
+ maxChars - charCount
76
+ } characters remaining out of ${maxChars}`}</span>
77
+ <Icon name={delightedSVG} size="24px" />
78
+ </>
79
+ )}
80
+ </p>
81
+ );
82
+ };
83
+
84
+ export default CounterComponent;
@@ -1,4 +1,4 @@
1
- import React, { useState } from 'react';
1
+ import React, { useState, useCallback } from 'react';
2
2
  import { isEmpty, without } from 'lodash';
3
3
  import config from '@plone/volto/registry';
4
4
  import {
@@ -12,14 +12,12 @@ import {
12
12
  emptyBlocksForm,
13
13
  getBlocksLayoutFieldname,
14
14
  } from '@plone/volto/helpers';
15
- import delightedSVG from '@plone/volto/icons/delighted.svg';
16
- import dissatisfiedSVG from '@plone/volto/icons/dissatisfied.svg';
17
15
  import PropTypes from 'prop-types';
18
16
  import { Button, Segment } from 'semantic-ui-react';
19
17
  import EditBlockWrapper from './EditBlockWrapper';
20
18
  import EditSchema from './EditSchema';
19
+ import CounterComponent from './CounterComponent';
21
20
  import helpSVG from '@plone/volto/icons/help.svg';
22
- import cx from 'classnames';
23
21
  import './editor.less';
24
22
 
25
23
  const Edit = (props) => {
@@ -43,8 +41,6 @@ const Edit = (props) => {
43
41
  );
44
42
 
45
43
  const blockState = {};
46
- let charCount = 0;
47
-
48
44
  const handleKeyDown = (
49
45
  e,
50
46
  index,
@@ -71,47 +67,48 @@ const Edit = (props) => {
71
67
  }
72
68
  };
73
69
 
74
- const onSelectBlock = (id, isMultipleSelection, event, activeBlock) => {
75
- let newMultiSelected = [];
76
- let selected = id;
70
+ const onSelectBlock = useCallback(
71
+ (id, isMultipleSelection, event, activeBlock) => {
72
+ let newMultiSelected = [];
73
+ let selected = id;
77
74
 
78
- if (isMultipleSelection) {
79
- selected = null;
80
- const blocksLayoutFieldname = getBlocksLayoutFieldname(data?.data);
81
- const blocks_layout = data?.data[blocksLayoutFieldname].items;
82
- if (event.shiftKey) {
83
- const anchor =
84
- multiSelected.length > 0
85
- ? blocks_layout.indexOf(multiSelected[0])
86
- : blocks_layout.indexOf(activeBlock);
87
- const focus = blocks_layout.indexOf(id);
88
- if (anchor === focus) {
89
- newMultiSelected = [id];
90
- } else if (focus > anchor) {
91
- newMultiSelected = [...blocks_layout.slice(anchor, focus + 1)];
92
- } else {
93
- newMultiSelected = [...blocks_layout.slice(focus, anchor + 1)];
75
+ if (isMultipleSelection) {
76
+ selected = null;
77
+ const blocksLayoutFieldname = getBlocksLayoutFieldname(data?.data);
78
+ const blocks_layout = data?.data[blocksLayoutFieldname].items;
79
+ if (event.shiftKey) {
80
+ const anchor =
81
+ multiSelected.length > 0
82
+ ? blocks_layout.indexOf(multiSelected[0])
83
+ : blocks_layout.indexOf(activeBlock);
84
+ const focus = blocks_layout.indexOf(id);
85
+ if (anchor === focus) {
86
+ newMultiSelected = [id];
87
+ } else if (focus > anchor) {
88
+ newMultiSelected = [...blocks_layout.slice(anchor, focus + 1)];
89
+ } else {
90
+ newMultiSelected = [...blocks_layout.slice(focus, anchor + 1)];
91
+ }
94
92
  }
95
- }
96
- if ((event.ctrlKey || event.metaKey) && !event.shiftKey) {
97
- if (multiSelected.includes(id)) {
98
- selected = null;
99
- newMultiSelected = without(multiSelected, id);
100
- } else {
101
- newMultiSelected = [...(multiSelected || []), id];
93
+ if ((event.ctrlKey || event.metaKey) && !event.shiftKey) {
94
+ if (multiSelected.includes(id)) {
95
+ selected = null;
96
+ newMultiSelected = without(multiSelected, id);
97
+ } else {
98
+ newMultiSelected = [...(multiSelected || []), id];
99
+ }
102
100
  }
103
101
  }
104
- }
105
102
 
106
- setSelectedBlock(selected);
107
- setMultiSelected(newMultiSelected);
108
- };
103
+ setSelectedBlock(selected);
104
+ setMultiSelected(newMultiSelected);
105
+ },
106
+ [data.data, multiSelected],
107
+ );
109
108
 
110
109
  const changeBlockData = (newBlockData) => {
111
110
  let pastedBlocks = newBlockData.blocks_layout.items.filter((blockID) => {
112
- if (data?.data?.blocks_layout.items.find((x) => x === blockID))
113
- return false;
114
- return true;
111
+ return !data?.data?.blocks_layout.items.find((x) => x === blockID);
115
112
  });
116
113
  const selectedIndex =
117
114
  data.data.blocks_layout.items.indexOf(selectedBlock) + 1;
@@ -144,101 +141,6 @@ const Edit = (props) => {
144
141
  }
145
142
  }, [onChangeBlock, properties, selectedBlock, block, data, data_blocks]);
146
143
 
147
- /**
148
- * Count the number of characters that are anything except using Regex
149
- * @param {string} paragraph
150
- * @returns
151
- */
152
- const countCharsWithoutSpaces = (paragraph) => {
153
- const regex = /[^\s\\]/g;
154
-
155
- return (paragraph.match(regex) || []).length;
156
- };
157
-
158
- /**
159
- * Count the number of characters
160
- * @param {string} paragraph
161
- * @returns
162
- */
163
- const countCharsWithSpaces = (paragraph) => {
164
- return paragraph?.length || 0;
165
- };
166
-
167
- /**
168
- * Recursively look for any block that contains text or plaintext
169
- * @param {Object} blocksObject
170
- * @returns
171
- */
172
- const countTextInBlocks = (blocksObject) => {
173
- let groupCharCount = 0;
174
- if (!props.data.maxChars) {
175
- return groupCharCount;
176
- }
177
-
178
- Object.keys(blocksObject).forEach((blockId) => {
179
- const foundText = blocksObject[blockId]?.plaintext
180
- ? blocksObject[blockId]?.plaintext
181
- : blocksObject[blockId]?.text?.blocks[0]?.text
182
- ? blocksObject[blockId].text.blocks[0].text
183
- : blocksObject[blockId]?.data?.blocks
184
- ? countTextInBlocks(blocksObject[blockId]?.data?.blocks)
185
- : blocksObject[blockId]?.blocks
186
- ? countTextInBlocks(blocksObject[blockId]?.blocks)
187
- : '';
188
- const resultText =
189
- typeof foundText === 'string' || foundText instanceof String
190
- ? foundText
191
- : '';
192
-
193
- groupCharCount += props.data.ignoreSpaces
194
- ? countCharsWithoutSpaces(resultText)
195
- : countCharsWithSpaces(resultText);
196
- });
197
-
198
- return groupCharCount;
199
- };
200
-
201
- const showCharCounter = () => {
202
- if (data_blocks) {
203
- charCount = countTextInBlocks(data_blocks);
204
- }
205
- };
206
- showCharCounter();
207
-
208
- const counterClass =
209
- charCount < Math.ceil(props.data.maxChars / 1.05)
210
- ? 'info'
211
- : charCount < props.data.maxChars
212
- ? 'warning'
213
- : 'danger';
214
-
215
- const counterComponent = props.data.maxChars ? (
216
- <p
217
- className={cx('counter', counterClass)}
218
- onClick={() => {
219
- setSelectedBlock();
220
- props.setSidebarTab(1);
221
- }}
222
- aria-hidden="true"
223
- >
224
- {props.data.maxChars - charCount < 0 ? (
225
- <>
226
- <span>{`${
227
- charCount - props.data.maxChars
228
- } characters over the limit`}</span>
229
- <Icon name={dissatisfiedSVG} size="24px" />
230
- </>
231
- ) : (
232
- <>
233
- <span>{`${
234
- props.data.maxChars - charCount
235
- } characters remaining out of ${props.data.maxChars}`}</span>
236
- <Icon name={delightedSVG} size="24px" />
237
- </>
238
- )}
239
- </p>
240
- ) : null;
241
-
242
144
  // Get editing instructions from block settings or props
243
145
  let instructions = data?.instructions?.data || data?.instructions;
244
146
  if (!instructions || instructions === '<p><br/></p>') {
@@ -355,7 +257,9 @@ const Edit = (props) => {
355
257
  )}
356
258
  </BlocksForm>
357
259
 
358
- {counterComponent}
260
+ {props.data.maxChars && (
261
+ <CounterComponent {...props} setSelectedBlock={setSelectedBlock} />
262
+ )}
359
263
  <SidebarPortal selected={selected && !selectedBlock}>
360
264
  {instructions && (
361
265
  <Segment attached>
@@ -0,0 +1,79 @@
1
+ import React from 'react';
2
+ import Edit from './Edit';
3
+ import configureStore from 'redux-mock-store';
4
+ import { Provider } from 'react-intl-redux';
5
+ import thunk from 'redux-thunk';
6
+ import renderer from 'react-test-renderer';
7
+ import { render, fireEvent } from '@testing-library/react';
8
+ import '@testing-library/jest-dom/extend-expect';
9
+
10
+ const mockStore = configureStore([thunk]);
11
+ const store = mockStore({
12
+ intl: {
13
+ locale: 'en',
14
+ messages: {},
15
+ },
16
+ });
17
+
18
+ describe('Edit', () => {
19
+ const onChangeBlock = jest.fn();
20
+ const onChangeField = jest.fn();
21
+ const mockBlockNode = { current: {} };
22
+ const props = {
23
+ block: 'testBlock',
24
+ data: {
25
+ data: {
26
+ blocks: {
27
+ block1: {
28
+ type: 'test',
29
+ data: {
30
+ value: 'Test',
31
+ },
32
+ },
33
+ },
34
+ blocks_layout: {
35
+ items: ['block1'],
36
+ },
37
+ },
38
+ },
39
+ onChangeBlock,
40
+ onChangeField,
41
+ pathname: '/',
42
+ selected: true,
43
+ manage: true,
44
+ };
45
+
46
+ it('should render without crashing', () => {
47
+ const component = renderer.create(
48
+ <Provider store={store}>
49
+ <Edit {...props} />
50
+ </Provider>,
51
+ );
52
+
53
+ const json = component.toJSON();
54
+ expect(json).toMatchSnapshot();
55
+ });
56
+
57
+ it('renders without crashing', () => {
58
+ const { getByRole } = render(
59
+ <Provider store={store}>
60
+ <Edit {...props} />
61
+ </Provider>,
62
+ );
63
+ expect(getByRole('presentation')).toBeInTheDocument();
64
+ });
65
+
66
+ it('should call ArrowUp keydown', () => {
67
+ const mockOnFocusPreviousBlock = jest.fn();
68
+ const { getByRole } = render(
69
+ <Provider store={store}>
70
+ <Edit
71
+ {...props}
72
+ onFocusPreviousBlock={mockOnFocusPreviousBlock}
73
+ blockNode={mockBlockNode}
74
+ />
75
+ </Provider>,
76
+ );
77
+ fireEvent.keyDown(getByRole('presentation'), { key: 'ArrowUp', code: 38 });
78
+ });
79
+ });
@@ -0,0 +1,58 @@
1
+ import React from 'react';
2
+ import { fireEvent, render } from '@testing-library/react';
3
+ import { Provider } from 'react-intl-redux';
4
+ import EditBlockWrapper from './EditBlockWrapper';
5
+ import configureStore from 'redux-mock-store';
6
+ import '@testing-library/jest-dom/extend-expect';
7
+
8
+ const mockDragInfo = {
9
+ innerRef: {
10
+ current: {
11
+ childMethod: jest.fn(),
12
+ },
13
+ },
14
+ draggableProps: {},
15
+ dragHandleProps: {},
16
+ };
17
+
18
+ const mockStore = configureStore();
19
+ const store = mockStore({
20
+ intl: {
21
+ locale: 'en',
22
+ messages: {},
23
+ },
24
+ });
25
+
26
+ describe('EditBlockWrapper', () => {
27
+ const mockBlockProps = {
28
+ allowedBlocks: [],
29
+ block: 'mockBlock',
30
+ data: {},
31
+ onSelectBlock: jest.fn(),
32
+ onDeleteBlock: jest.fn(),
33
+ onMutateBlock: jest.fn(),
34
+ onInsertBlock: jest.fn(),
35
+ selected: true,
36
+ };
37
+
38
+ it('renders children', () => {
39
+ const { getByText } = render(
40
+ <Provider store={store}>
41
+ <EditBlockWrapper blockProps={mockBlockProps} draginfo={mockDragInfo}>
42
+ <div>Test child</div>
43
+ </EditBlockWrapper>
44
+ </Provider>,
45
+ );
46
+ expect(getByText('Test child')).toBeInTheDocument();
47
+ });
48
+
49
+ it('calls onDeleteBlock when delete button is clicked', () => {
50
+ const { getByTitle } = render(
51
+ <Provider store={store}>
52
+ <EditBlockWrapper blockProps={mockBlockProps} draginfo={mockDragInfo} />
53
+ </Provider>,
54
+ );
55
+ fireEvent.click(getByTitle('Remove block'));
56
+ expect(mockBlockProps.onDeleteBlock).toHaveBeenCalledWith('mockBlock');
57
+ });
58
+ });
@@ -0,0 +1,68 @@
1
+ import React from 'react';
2
+ import View from './View';
3
+ import renderer from 'react-test-renderer';
4
+ import { render } from '@testing-library/react';
5
+ import { RenderBlocks } from '@plone/volto/components';
6
+ import '@testing-library/jest-dom/extend-expect';
7
+
8
+ jest.mock('@plone/volto/components', () => ({
9
+ RenderBlocks: jest.fn(() => <div>RenderBlocks</div>),
10
+ }));
11
+
12
+ describe('View', () => {
13
+ it('should render without crashing', () => {
14
+ const props = {
15
+ data: {},
16
+ metadata: {},
17
+ properties: {},
18
+ };
19
+ const component = renderer.create(<View {...props} />);
20
+
21
+ const json = component.toJSON();
22
+ expect(json).toMatchSnapshot();
23
+ });
24
+
25
+ it('renders with default tag and without crashing', () => {
26
+ const props = {
27
+ data: {},
28
+ metadata: {},
29
+ properties: {},
30
+ };
31
+ const { container } = render(<View {...props} />);
32
+ expect(container.querySelector('div')).toBeInTheDocument();
33
+ });
34
+
35
+ it('renders with a custom tag and custom id', () => {
36
+ const props = {
37
+ data: {
38
+ as: 'section',
39
+ title: 'Test Title',
40
+ data: { key: 'value' },
41
+ },
42
+ properties: {},
43
+ };
44
+ const { container } = render(<View {...props} />);
45
+ expect(container.querySelector('section')).toBeInTheDocument();
46
+ expect(container.querySelector('#test-title')).toBeInTheDocument();
47
+ });
48
+
49
+ it('renders RenderBlocks with correct props', () => {
50
+ const props = {
51
+ data: {
52
+ as: 'section',
53
+ title: 'Test Title',
54
+ data: { key: 'value' },
55
+ },
56
+ metadata: { meta: 'data' },
57
+ properties: { prop: 'erty' },
58
+ };
59
+ render(<View {...props} />);
60
+ expect(RenderBlocks).toHaveBeenCalledWith(
61
+ expect.objectContaining({
62
+ metadata: props.metadata,
63
+ content: props.data.data,
64
+ }),
65
+ {},
66
+ );
67
+ });
68
+ });
package/src/index.js CHANGED
@@ -59,6 +59,7 @@ const applyConfig = (config) => {
59
59
  });
60
60
  return entries;
61
61
  },
62
+ countTextIn: ['slate', 'description'], //id of the block whose text should be counted
62
63
  };
63
64
 
64
65
  return config;