@eeacms/volto-editing-progress 0.4.0 → 2.0.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 ADDED
@@ -0,0 +1,65 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const projectRootPath = fs.realpathSync(__dirname + '/../../../');
4
+
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
+ }
18
+
19
+ const AddonConfigurationRegistry = require(`${voltoPath}/addon-registry.js`);
20
+ const reg = new AddonConfigurationRegistry(projectRootPath);
21
+
22
+ // Extends ESlint configuration for adding the aliases to `src` directories in Volto addons
23
+ const addonAliases = Object.keys(reg.packages).map((o) => [
24
+ o,
25
+ reg.packages[o].modulePath,
26
+ ]);
27
+
28
+ const addonExtenders = reg.getEslintExtenders().map((m) => require(m));
29
+
30
+ const defaultConfig = {
31
+ extends: `${voltoPath}/.eslintrc`,
32
+ settings: {
33
+ 'import/resolver': {
34
+ alias: {
35
+ map: [
36
+ ['@plone/volto', '@plone/volto/src'],
37
+ ['@plone/volto-slate', '@plone/volto/packages/volto-slate/src'],
38
+ ...addonAliases,
39
+ ['@package', `${__dirname}/src`],
40
+ ['@root', `${__dirname}/src`],
41
+ ['~', `${__dirname}/src`],
42
+ ],
43
+ extensions: ['.js', '.jsx', '.json'],
44
+ },
45
+ 'babel-plugin-root-import': {
46
+ rootPathSuffix: 'src',
47
+ },
48
+ },
49
+ },
50
+ rules: {
51
+ 'react/jsx-no-target-blank': [
52
+ 'error',
53
+ {
54
+ allowReferrer: true,
55
+ },
56
+ ],
57
+ }
58
+ };
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,6 +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
+ ### [2.0.0](https://github.com/eea/volto-editing-progress/compare/1.0.0...2.0.0) - 10 February 2026
8
+
9
+ #### :rocket: New Features
10
+
11
+ - feat: Change in IMS editing to enforce text length limits using progress editing - refs #294806 [dobri1408 - [`062c397`](https://github.com/eea/volto-editing-progress/commit/062c397471f59c165b986e7de31f467a9cdcbf13)]
12
+
13
+ #### :house: Internal changes
14
+
15
+ - chore: i18n [Alin Voinea - [`11c592a`](https://github.com/eea/volto-editing-progress/commit/11c592a7c1d33d5ca3e79516f8113b6e2c525662)]
16
+ - chore: Cleanup double import less file [Alin Voinea - [`d53b1c3`](https://github.com/eea/volto-editing-progress/commit/d53b1c389de962001982bc80d1c4577b8866d51c)]
17
+
18
+ #### :hammer_and_wrench: Others
19
+
20
+ - Autorelease 2.0.0 [Alin Voinea - [`92c1733`](https://github.com/eea/volto-editing-progress/commit/92c17338977f5de4491e1b76699a41de55fbbf18)]
21
+ ## [1.0.0](https://github.com/eea/volto-editing-progress/compare/0.4.0...1.0.0) - 22 April 2024
22
+
23
+ #### :rocket: New Features
24
+
25
+ - feat: Release 1.0.0 - Volto 17 support [alin - [`b8ed6b7`](https://github.com/eea/volto-editing-progress/commit/b8ed6b79fece114d9699f51867121666ec806890)]
26
+ - feat: Volto 17 support - refs #264527 [EEA Jenkins - [`f314298`](https://github.com/eea/volto-editing-progress/commit/f31429892895f2283b522d10bafb121b3a12fd22)]
27
+
7
28
  ### [0.4.0](https://github.com/eea/volto-editing-progress/compare/0.3.0...0.4.0) - 19 February 2024
8
29
 
9
30
  #### :rocket: New Features
@@ -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,18 +11,26 @@ 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',
17
+ '@eeacms/search/(.*)$': '<rootDir>/src/addons/volto-searchlib/searchlib/$1',
18
+ '@eeacms/search': '<rootDir>/src/addons/volto-searchlib/searchlib',
15
19
  '@eeacms/(.*?)/(.*)$': '<rootDir>/node_modules/@eeacms/$1/src/$2',
16
- '@plone/volto-slate':
20
+ '@plone/volto-slate$':
17
21
  '<rootDir>/node_modules/@plone/volto/packages/volto-slate/src',
22
+ '@plone/volto-slate/(.*)$':
23
+ '<rootDir>/node_modules/@plone/volto/packages/volto-slate/src/$1',
18
24
  '~/(.*)$': '<rootDir>/src/$1',
19
25
  'load-volto-addons':
20
26
  '<rootDir>/node_modules/@plone/volto/jest-addons-loader.js',
21
27
  },
28
+ transformIgnorePatterns: [
29
+ '/node_modules/(?!(@plone|@root|@package|@eeacms)/).*/',
30
+ ],
22
31
  transform: {
23
32
  '^.+\\.js(x)?$': 'babel-jest',
33
+ '^.+\\.ts(x)?$': 'babel-jest',
24
34
  '^.+\\.(png)$': 'jest-file',
25
35
  '^.+\\.(jpg)$': 'jest-file',
26
36
  '^.+\\.(svg)$': './node_modules/@plone/volto/jest-svgsystem-transform.js',
@@ -33,4 +43,9 @@ module.exports = {
33
43
  statements: 5,
34
44
  },
35
45
  },
36
- };
46
+ ...(process.env.JEST_USE_SETUP === 'ON' && {
47
+ setupFilesAfterEnv: [
48
+ '<rootDir>/node_modules/@eeacms/volto-editing-progress/jest.setup.js',
49
+ ],
50
+ }),
51
+ }
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
+ });
@@ -11,17 +11,17 @@ msgstr ""
11
11
  "Content-Transfer-Encoding: \n"
12
12
  "Plural-Forms: \n"
13
13
 
14
+ #. Default: "Edit JSON"
14
15
  #: VisualJSONWidget
15
- # defaultMessage: Edit JSON
16
16
  msgid "Edit JSON"
17
17
  msgstr ""
18
18
 
19
+ #. Default: "JSON code"
19
20
  #: schema
20
- # defaultMessage: JSON code
21
21
  msgid "JSON code"
22
22
  msgstr ""
23
23
 
24
+ #. Default: "Please enter valid JSON!"
24
25
  #: TextareaJSONWidget
25
- # defaultMessage: Please enter valid JSON!
26
26
  msgid "Please enter valid JSON!"
27
27
  msgstr ""
@@ -11,17 +11,17 @@ msgstr ""
11
11
  "Content-Transfer-Encoding: \n"
12
12
  "Plural-Forms: \n"
13
13
 
14
+ #. Default: "Edit JSON"
14
15
  #: VisualJSONWidget
15
- # defaultMessage: Edit JSON
16
16
  msgid "Edit JSON"
17
17
  msgstr ""
18
18
 
19
+ #. Default: "JSON code"
19
20
  #: schema
20
- # defaultMessage: JSON code
21
21
  msgid "JSON code"
22
22
  msgstr ""
23
23
 
24
+ #. Default: "Please enter valid JSON!"
24
25
  #: TextareaJSONWidget
25
- # defaultMessage: Please enter valid JSON!
26
26
  msgid "Please enter valid JSON!"
27
27
  msgstr ""
@@ -11,17 +11,17 @@ msgstr ""
11
11
  "Content-Transfer-Encoding: \n"
12
12
  "Plural-Forms: \n"
13
13
 
14
+ #. Default: "Edit JSON"
14
15
  #: VisualJSONWidget
15
- # defaultMessage: Edit JSON
16
16
  msgid "Edit JSON"
17
17
  msgstr ""
18
18
 
19
+ #. Default: "JSON code"
19
20
  #: schema
20
- # defaultMessage: JSON code
21
21
  msgid "JSON code"
22
22
  msgstr ""
23
23
 
24
+ #. Default: "Please enter valid JSON!"
24
25
  #: TextareaJSONWidget
25
- # defaultMessage: Please enter valid JSON!
26
26
  msgid "Please enter valid JSON!"
27
27
  msgstr ""
@@ -11,17 +11,17 @@ msgstr ""
11
11
  "Content-Transfer-Encoding: \n"
12
12
  "Plural-Forms: \n"
13
13
 
14
+ #. Default: "Edit JSON"
14
15
  #: VisualJSONWidget
15
- # defaultMessage: Edit JSON
16
16
  msgid "Edit JSON"
17
17
  msgstr ""
18
18
 
19
+ #. Default: "JSON code"
19
20
  #: schema
20
- # defaultMessage: JSON code
21
21
  msgid "JSON code"
22
22
  msgstr ""
23
23
 
24
+ #. Default: "Please enter valid JSON!"
24
25
  #: TextareaJSONWidget
25
- # defaultMessage: Please enter valid JSON!
26
26
  msgid "Please enter valid JSON!"
27
27
  msgstr ""
package/locales/volto.pot CHANGED
@@ -1,29 +1,29 @@
1
1
  msgid ""
2
2
  msgstr ""
3
3
  "Project-Id-Version: Plone\n"
4
- "POT-Creation-Date: 2023-09-14T13:45:52.728Z\n"
4
+ "POT-Creation-Date: 2026-02-10T19:32:01.026Z\n"
5
5
  "Last-Translator: Plone i18n <plone-i18n@lists.sourceforge.net>\n"
6
6
  "Language-Team: Plone i18n <plone-i18n@lists.sourceforge.net>\n"
7
- "MIME-Version: 1.0\n"
8
7
  "Content-Type: text/plain; charset=utf-8\n"
9
8
  "Content-Transfer-Encoding: 8bit\n"
10
9
  "Plural-Forms: nplurals=1; plural=0;\n"
10
+ "MIME-Version: 1.0\n"
11
11
  "Language-Code: en\n"
12
12
  "Language-Name: English\n"
13
13
  "Preferred-Encodings: utf-8\n"
14
14
  "Domain: volto\n"
15
15
 
16
+ #. Default: "Edit JSON"
16
17
  #: VisualJSONWidget
17
- # defaultMessage: Edit JSON
18
18
  msgid "Edit JSON"
19
19
  msgstr ""
20
20
 
21
+ #. Default: "JSON code"
21
22
  #: schema
22
- # defaultMessage: JSON code
23
23
  msgid "JSON code"
24
24
  msgstr ""
25
25
 
26
+ #. Default: "Please enter valid JSON!"
26
27
  #: TextareaJSONWidget
27
- # defaultMessage: Please enter valid JSON!
28
28
  msgid "Please enter valid JSON!"
29
29
  msgstr ""
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-editing-progress",
3
- "version": "0.4.0",
3
+ "version": "2.0.0",
4
4
  "description": "@eeacms/volto-editing-progress: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -25,6 +25,7 @@
25
25
  "devDependencies": {
26
26
  "@cypress/code-coverage": "^3.9.5",
27
27
  "babel-plugin-transform-class-properties": "^6.24.1",
28
+ "dotenv": "^16.3.2",
28
29
  "husky": "^8.0.3",
29
30
  "lint-staged": "^14.0.1",
30
31
  "md5": "^2.3.0"
@@ -11,7 +11,6 @@ import {
11
11
  Sidebar,
12
12
  } from 'semantic-ui-react';
13
13
  import { flattenToAppURL } from '@plone/volto/helpers';
14
- import './less/editor.less';
15
14
  import _ from 'lodash';
16
15
  import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
17
16
  import PropTypes from 'prop-types';
@@ -194,6 +193,65 @@ const VisualJSONWidget = (props) => {
194
193
  return undefined;
195
194
  };
196
195
 
196
+ // Check if enforceCharLimits already exists for current content type
197
+ const hasEnforceCharLimits = () => {
198
+ if (!currentContentType || !value[currentContentType.id]) return false;
199
+ return value[currentContentType.id].some(
200
+ (rule) => rule.type === 'enforceCharLimits',
201
+ );
202
+ };
203
+
204
+ // Handler to add enforceCharLimits rule
205
+ const handleAddEnforceCharLimits = () => {
206
+ const localCopyOfValue = _.cloneDeep(value);
207
+ if (!localCopyOfValue[currentContentType.id]) {
208
+ localCopyOfValue[currentContentType.id] = [];
209
+ }
210
+
211
+ // Check if already exists
212
+ const exists = localCopyOfValue[currentContentType.id].some(
213
+ (r) => r.type === 'enforceCharLimits',
214
+ );
215
+
216
+ if (!exists) {
217
+ localCopyOfValue[currentContentType.id].push({
218
+ type: 'enforceCharLimits',
219
+ states: ['all'],
220
+ linkLabel: 'Fix {title}',
221
+ });
222
+ onChange(id, localCopyOfValue);
223
+ }
224
+ };
225
+
226
+ // Handler to update enforceCharLimits rule
227
+ const handleUpdateEnforceCharLimits = (key, newValue) => {
228
+ const localCopyOfValue = _.cloneDeep(value);
229
+ const rules = localCopyOfValue[currentContentType.id] || [];
230
+ const ruleIndex = rules.findIndex((r) => r.type === 'enforceCharLimits');
231
+
232
+ if (ruleIndex !== -1) {
233
+ if (key === 'states') {
234
+ rules[ruleIndex].states = newValue.map((s) => s.toLowerCase());
235
+ } else {
236
+ rules[ruleIndex][key] = newValue;
237
+ }
238
+ onChange(id, localCopyOfValue);
239
+ }
240
+ };
241
+
242
+ // Handler to remove enforceCharLimits rule
243
+ const handleRemoveEnforceCharLimits = () => {
244
+ const localCopyOfValue = _.cloneDeep(value);
245
+ const rules = localCopyOfValue[currentContentType.id] || [];
246
+ localCopyOfValue[currentContentType.id] = rules.filter(
247
+ (r) => r.type !== 'enforceCharLimits',
248
+ );
249
+ if (localCopyOfValue[currentContentType.id].length === 0) {
250
+ delete localCopyOfValue[currentContentType.id];
251
+ }
252
+ onChange(id, localCopyOfValue);
253
+ };
254
+
197
255
  return (
198
256
  <>
199
257
  <div>
@@ -217,18 +275,35 @@ const VisualJSONWidget = (props) => {
217
275
  <Dropdown
218
276
  className="ui grey button dropdown-button"
219
277
  text="Add Property"
220
- options={fields
221
- .filter((field) => {
222
- return (
223
- getDropdownValues(field) === undefined &&
224
- !request.data.required.includes(field)
225
- );
226
- })
227
- .map((field) => {
228
- return { key: field, text: field, value: field };
229
- })}
278
+ options={[
279
+ // Existing field options
280
+ ...fields
281
+ .filter((field) => {
282
+ return (
283
+ getDropdownValues(field) === undefined &&
284
+ !request.data.required.includes(field)
285
+ );
286
+ })
287
+ .map((field) => {
288
+ return { key: field, text: field, value: field };
289
+ }),
290
+ // Add enforceCharLimits option if not already added
291
+ ...(!hasEnforceCharLimits()
292
+ ? [
293
+ {
294
+ key: 'enforceCharLimits',
295
+ text: 'Enforce character limits',
296
+ value: 'enforceCharLimits',
297
+ },
298
+ ]
299
+ : []),
300
+ ]}
230
301
  onChange={(e, t) => {
231
- handleOnDropdownChange(e, { value: ['all'] }, t.value);
302
+ if (t.value === 'enforceCharLimits') {
303
+ handleAddEnforceCharLimits();
304
+ } else {
305
+ handleOnDropdownChange(e, { value: ['all'] }, t.value);
306
+ }
232
307
  }}
233
308
  />
234
309
  )}
@@ -250,6 +325,8 @@ const VisualJSONWidget = (props) => {
250
325
  value={value}
251
326
  fields={fields}
252
327
  getDropdownValues={getDropdownValues}
328
+ handleUpdateEnforceCharLimits={handleUpdateEnforceCharLimits}
329
+ handleRemoveEnforceCharLimits={handleRemoveEnforceCharLimits}
253
330
  />
254
331
  </Sidebar.Pusher>
255
332
  </Sidebar.Pushable>