design-comuni-plone-theme 10.6.1 → 10.6.2

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
@@ -1,5 +1,18 @@
1
1
 
2
2
 
3
+ ## [10.6.2](https://github.com/redturtle/design-comuni-plone-theme/compare/v10.6.1...v10.6.2) (2023-12-14)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * custom inline styles rendering in wysiwygwidget ([17e1d10](https://github.com/redturtle/design-comuni-plone-theme/commit/17e1d10a2de1c8ba4d12a7364bc8858761b4b92e))
9
+
10
+
11
+ ### Documentation
12
+
13
+ * aggiornamento lista dei comuni in publiccode.yml ([#158](https://github.com/redturtle/design-comuni-plone-theme/issues/158)) ([2abad9a](https://github.com/redturtle/design-comuni-plone-theme/commit/2abad9aecaa288ca87670183df13212bdb47fa66))
14
+ * updated publiccode and release log ([38d8d00](https://github.com/redturtle/design-comuni-plone-theme/commit/38d8d00daf1b3c822d11a701ecc3a83657c865cb))
15
+
3
16
  ## [10.6.1](https://github.com/RedTurtle/design-comuni-plone-theme/compare/v10.6.0...v10.6.1) (2023-12-13)
4
17
 
5
18
 
package/RELEASE.md CHANGED
@@ -41,11 +41,17 @@
41
41
  - ...
42
42
  -->
43
43
 
44
+ ## Versione 10.6.2 (14/12/2023)
45
+
46
+ ### Fix
47
+
48
+ - Ora si vedono correttamente gli stili di allineamento del testo in alcuni editor di testo, ad esempio header e footer dei sottositi.
49
+
44
50
  ## Versione 10.6.1 (13/12/2023)
45
51
 
46
52
  ### Novità
47
53
 
48
- - I seguenti campi sono ora riordinabili liberamente: "Timeline tempi e scadenze" per il tipo di contenuto *Servizio* e "Valore punto di contatto" del tipo di contenuto *Punto di contatto*.
54
+ - I seguenti campi sono ora riordinabili liberamente: "Timeline tempi e scadenze" per il tipo di contenuto _Servizio_ e "Valore punto di contatto" del tipo di contenuto _Punto di contatto_.
49
55
 
50
56
  ### Fix
51
57
 
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "design-comuni-plone-theme",
3
3
  "description": "Volto Theme for Italia design guidelines",
4
4
  "license": "GPL-v3",
5
- "version": "10.6.1",
5
+ "version": "10.6.2",
6
6
  "main": "src/index.js",
7
7
  "keywords": [
8
8
  "volto-addon",
package/publiccode.yml CHANGED
@@ -227,9 +227,9 @@ maintenance:
227
227
  name: io-Comune - Il sito AgID per Comuni ed Enti Pubblici
228
228
  platforms:
229
229
  - web
230
- releaseDate: '2023-12-13'
230
+ releaseDate: '2023-12-14'
231
231
  softwareType: standalone/web
232
- softwareVersion: 10.6.1
232
+ softwareVersion: 10.6.2
233
233
  url: 'https://github.com/italia/design-comuni-plone-theme'
234
234
  usedBy:
235
235
  - ASP Comuni Modenesi Area Nord
@@ -243,6 +243,7 @@ usedBy:
243
243
  - Biblioteche Pianura Est
244
244
  - Camera di Commercio dell'Umbria
245
245
  - Camera di Commercio di Reggio Emilia
246
+ - Comune della Spezia
246
247
  - Comune di Bibbiano
247
248
  - Comune di Camposanto
248
249
  - Comune di Cantagallo
@@ -266,6 +267,7 @@ usedBy:
266
267
  - Comune di San Possidonio
267
268
  - Comune di San Prospero
268
269
  - Comune di Santilario d'Enza
270
+ - Comune di Toscolano Maderno
269
271
  - Comune di Vaiano
270
272
  - Comune di Vernio
271
273
  - Comando Generale della Guardia di Finanza
@@ -136,33 +136,50 @@ const ItaliaFromHTMLCustomBlockFn = (element) => {
136
136
  ret = {
137
137
  type: 'buttons',
138
138
  };
139
- } else if (element.className === 'draftjs-text-larger') {
139
+ } else if (element.className === 'text-center') {
140
140
  ret = {
141
- type: 'TEXT_LARGER',
141
+ type: 'align-center',
142
+ };
143
+ } else if (element.className === 'text-end') {
144
+ ret = {
145
+ type: 'align-right',
146
+ };
147
+ } else if (element.className === 'text-justify') {
148
+ ret = {
149
+ type: 'align-justify',
142
150
  };
143
151
  }
144
152
  }
145
153
  return ret;
146
154
  };
147
155
 
156
+ const ItaliaFromHTMLCustomInlineFn = (element, { Style }) => {
157
+ if (element.tagName === 'SPAN') {
158
+ if (element.className === 'draftjs-text-larger') {
159
+ return Style('TEXT_LARGER');
160
+ }
161
+ }
162
+ };
163
+
148
164
  export default function applyConfig(config) {
149
165
  config.settings.richtextEditorSettings = (props) => {
150
166
  const { plugins /*, inlineToolbarButtons*/ } = Plugins(props); // volto plugins
151
- const { extendedBlockRenderMap, blockStyleFn, listBlockTypes } =
152
- Blocks(props);
167
+ const { extendedBlockRenderMap, blockStyleFn, listBlockTypes } = Blocks(
168
+ props,
169
+ );
153
170
 
154
171
  const { immutableLib } = props;
155
172
  const { Map } = immutableLib;
156
173
 
157
174
  const blockRenderMap = Map({
158
175
  'align-center': {
159
- element: 'p',
176
+ element: (props) => <p {...props} style={{ textAlign: 'center' }} />,
160
177
  },
161
178
  'align-right': {
162
- element: 'p',
179
+ element: (props) => <p {...props} style={{ textAlign: 'right' }} />,
163
180
  },
164
181
  'align-justify': {
165
- element: 'p',
182
+ element: (props) => <p {...props} style={{ textAlign: 'justify' }} />,
166
183
  },
167
184
  'callout-bg': {
168
185
  element: 'p',
@@ -179,9 +196,6 @@ export default function applyConfig(config) {
179
196
  r = r.length > 0 ? ' ' : r;
180
197
 
181
198
  const styles = {
182
- 'align-center': 'text-center',
183
- 'align-right': 'text-end',
184
- 'align-justify': 'text-justify',
185
199
  callout: 'callout',
186
200
  'callout-bg': 'callout-bg',
187
201
  buttons: 'draftjs-buttons',
@@ -203,9 +217,12 @@ export default function applyConfig(config) {
203
217
  ...plugins,
204
218
  ...ItaliaRichTextEditorPlugins(props),
205
219
  ],
206
- richTextEditorInlineToolbarButtons:
207
- ItaliaRichTextEditorInlineToolbarButtons(props, plugins), //[inlineToolbarButtons,...ItaliaRichTextEditorInlineToolbarButtons(props)]
208
- FromHTMLCustomBlockFn: ItaliaFromHTMLCustomBlockFn, //FromHTMLCustomBlockFn
220
+ richTextEditorInlineToolbarButtons: ItaliaRichTextEditorInlineToolbarButtons(
221
+ props,
222
+ plugins,
223
+ ), //[inlineToolbarButtons,...ItaliaRichTextEditorInlineToolbarButtons(props)]
224
+ FromHTMLCustomBlockFn: ItaliaFromHTMLCustomBlockFn,
225
+ FromHTMLCustomInlineFn: ItaliaFromHTMLCustomInlineFn,
209
226
  customStyleMap: {
210
227
  TEXT_LARGER: { fontSize: '1.75rem' },
211
228
  },
@@ -0,0 +1,362 @@
1
+ /**
2
+ * Customizations
3
+ * - add customInlineFn to stateFromHTML call (line 179)
4
+ */
5
+ /**
6
+ * WysiwygWidget container.
7
+ * @module components/manage/WysiwygWidget/WysiwygWidget
8
+ */
9
+
10
+ import React, { Component } from 'react';
11
+ import ReactDOMServer from 'react-dom/server';
12
+ import PropTypes from 'prop-types';
13
+ import { connect, Provider } from 'react-redux';
14
+ import { compose } from 'redux';
15
+ import redraft from 'redraft';
16
+ import { Form, Label, TextArea } from 'semantic-ui-react';
17
+ import { map } from 'lodash';
18
+ import { defineMessages, injectIntl } from 'react-intl';
19
+ import configureStore from 'redux-mock-store';
20
+ import { MemoryRouter } from 'react-router-dom';
21
+ import config from '@plone/volto/registry';
22
+
23
+ import { FormFieldWrapper } from '@plone/volto/components';
24
+
25
+ import loadable from '@loadable/component';
26
+ import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
27
+
28
+ const Editor = loadable(() => import('draft-js-plugins-editor'));
29
+
30
+ const messages = defineMessages({
31
+ default: {
32
+ id: 'Default',
33
+ defaultMessage: 'Default',
34
+ },
35
+ idTitle: {
36
+ id: 'Short Name',
37
+ defaultMessage: 'Short Name',
38
+ },
39
+ idDescription: {
40
+ id: 'Used for programmatic access to the fieldset.',
41
+ defaultMessage: 'Used for programmatic access to the fieldset.',
42
+ },
43
+ title: {
44
+ id: 'Title',
45
+ defaultMessage: 'Title',
46
+ },
47
+ description: {
48
+ id: 'Description',
49
+ defaultMessage: 'Description',
50
+ },
51
+ required: {
52
+ id: 'Required',
53
+ defaultMessage: 'Required',
54
+ },
55
+ delete: {
56
+ id: 'Delete',
57
+ defaultMessage: 'Delete',
58
+ },
59
+ });
60
+
61
+ /**
62
+ * WysiwygWidget HTML richtext editing widget
63
+ *
64
+ * To use it, in schema properties, declare a field like:
65
+ *
66
+ * ```jsx
67
+ * {
68
+ * title: "Rich text",
69
+ * widget: 'richtext',
70
+ * }
71
+ * ```
72
+ *
73
+ */
74
+ class WysiwygWidgetComponent extends Component {
75
+ /**
76
+ * Property types.
77
+ * @property {Object} propTypes Property types.
78
+ * @static
79
+ */
80
+ static propTypes = {
81
+ /**
82
+ * Id of the field
83
+ */
84
+ id: PropTypes.string.isRequired,
85
+ /**
86
+ * Title of the field
87
+ */
88
+ title: PropTypes.string.isRequired,
89
+ /**
90
+ * Description of the field
91
+ */
92
+ description: PropTypes.string,
93
+ /**
94
+ * True if field is required
95
+ */
96
+ required: PropTypes.bool,
97
+ /**
98
+ * Value of the field
99
+ */
100
+ value: PropTypes.shape({
101
+ /**
102
+ * Content type of the value
103
+ */
104
+ 'content-type': PropTypes.string,
105
+ /**
106
+ * Data of the value
107
+ */
108
+ data: PropTypes.string,
109
+ /**
110
+ * Encoding of the value
111
+ */
112
+ encoding: PropTypes.string,
113
+ }),
114
+ /**
115
+ * Placeholder for the editor
116
+ */
117
+ placeholder: PropTypes.string,
118
+ /**
119
+ * List of error messages
120
+ */
121
+ error: PropTypes.arrayOf(PropTypes.string),
122
+ /**
123
+ * On change handler
124
+ */
125
+ onChange: PropTypes.func,
126
+ /**
127
+ * On delete handler
128
+ */
129
+ onDelete: PropTypes.func,
130
+ /**
131
+ * On edit handler
132
+ */
133
+ onEdit: PropTypes.func,
134
+ /**
135
+ * Wrapped form component
136
+ */
137
+ wrapped: PropTypes.bool,
138
+ };
139
+
140
+ /**
141
+ * Default properties
142
+ * @property {Object} defaultProps Default properties.
143
+ * @static
144
+ */
145
+ static defaultProps = {
146
+ description: null,
147
+ required: false,
148
+ value: {
149
+ 'content-type': 'text/html',
150
+ data: '',
151
+ encoding: 'utf8',
152
+ },
153
+ error: [],
154
+ onEdit: null,
155
+ onDelete: null,
156
+ onChange: null,
157
+ };
158
+
159
+ /**
160
+ * Constructor
161
+ * @method constructor
162
+ * @param {Object} props Component properties
163
+ * @constructs WysiwygWidget
164
+ */
165
+ constructor(props) {
166
+ super(props);
167
+
168
+ const { stateFromHTML } = props.draftJsImportHtml;
169
+ const { EditorState } = props.draftJs;
170
+ const createInlineToolbarPlugin = props.draftJsInlineToolbarPlugin.default;
171
+
172
+ this.draftConfig = config.settings.richtextEditorSettings(props);
173
+
174
+ if (!__SERVER__) {
175
+ let editorState;
176
+ if (props.value && props.value.data) {
177
+ const contentState = stateFromHTML(props.value.data, {
178
+ customBlockFn: this.draftConfig.FromHTMLCustomBlockFn,
179
+ customInlineFn: this.draftConfig.FromHTMLCustomInlineFn,
180
+ });
181
+ editorState = EditorState.createWithContent(contentState);
182
+ } else {
183
+ editorState = EditorState.createEmpty();
184
+ }
185
+
186
+ const inlineToolbarPlugin = createInlineToolbarPlugin({
187
+ structure: this.draftConfig.richTextEditorInlineToolbarButtons,
188
+ });
189
+
190
+ this.state = { editorState, inlineToolbarPlugin };
191
+ }
192
+
193
+ this.schema = {
194
+ fieldsets: [
195
+ {
196
+ id: 'default',
197
+ title: props.intl.formatMessage(messages.default),
198
+ fields: ['title', 'id', 'description', 'required'],
199
+ },
200
+ ],
201
+ properties: {
202
+ id: {
203
+ type: 'string',
204
+ title: props.intl.formatMessage(messages.idTitle),
205
+ description: props.intl.formatMessage(messages.idDescription),
206
+ },
207
+ title: {
208
+ type: 'string',
209
+ title: props.intl.formatMessage(messages.title),
210
+ },
211
+ description: {
212
+ type: 'string',
213
+ widget: 'textarea',
214
+ title: props.intl.formatMessage(messages.description),
215
+ },
216
+ required: {
217
+ type: 'boolean',
218
+ title: props.intl.formatMessage(messages.required),
219
+ },
220
+ },
221
+ required: ['id', 'title'],
222
+ };
223
+
224
+ this.onChange = this.onChange.bind(this);
225
+ }
226
+
227
+ /**
228
+ * Change handler
229
+ * @method onChange
230
+ * @param {object} editorState Editor state.
231
+ * @returns {undefined}
232
+ */
233
+ onChange(editorState) {
234
+ const { convertToRaw } = this.props.draftJs;
235
+ this.setState({ editorState });
236
+ const mockStore = configureStore();
237
+
238
+ this.props.onChange(this.props.id, {
239
+ 'content-type': this.props.value
240
+ ? this.props.value['content-type']
241
+ : 'text/html',
242
+ encoding: this.props.value ? this.props.value.encoding : 'utf8',
243
+ data: ReactDOMServer.renderToStaticMarkup(
244
+ <Provider
245
+ store={mockStore({
246
+ userSession: {
247
+ token: this.props.token,
248
+ },
249
+ })}
250
+ >
251
+ <MemoryRouter>
252
+ {redraft(
253
+ convertToRaw(editorState.getCurrentContent()),
254
+ config.settings.richtextViewSettings.ToHTMLRenderers,
255
+ config.settings.richtextViewSettings.ToHTMLOptions,
256
+ )}
257
+ </MemoryRouter>
258
+ </Provider>,
259
+ ),
260
+ });
261
+ }
262
+
263
+ /**
264
+ * Render method.
265
+ * @method render
266
+ * @returns {string} Markup for the component.
267
+ */
268
+ render() {
269
+ const {
270
+ id,
271
+ title,
272
+ description,
273
+ required,
274
+ value,
275
+ error,
276
+ fieldSet,
277
+ } = this.props;
278
+
279
+ if (__SERVER__) {
280
+ return (
281
+ <Form.Field
282
+ inline
283
+ required={required}
284
+ error={error.length > 0}
285
+ className={description ? 'help' : ''}
286
+ id={`${fieldSet || 'field'}-${id}`}
287
+ >
288
+ <div className="wrapper">
289
+ <label htmlFor={`field-${id}`}>{title}</label>
290
+ <TextArea id={id} name={id} value={value ? value.data : ''} />
291
+ {description && <p className="help">{description}</p>}
292
+ {map(error, (message) => (
293
+ <Label key={message} basic color="red" pointing>
294
+ {message}
295
+ </Label>
296
+ ))}
297
+ </div>
298
+ </Form.Field>
299
+ );
300
+ }
301
+ const { InlineToolbar } = this.state.inlineToolbarPlugin;
302
+
303
+ return (
304
+ <FormFieldWrapper {...this.props} className="wysiwyg">
305
+ <div style={{ boxSizing: 'initial' }}>
306
+ {this.props.onChange ? (
307
+ <>
308
+ <Editor
309
+ id={`field-${id}`}
310
+ readOnly={this.props.isDisabled}
311
+ onChange={this.onChange}
312
+ editorState={this.state.editorState}
313
+ plugins={[
314
+ this.state.inlineToolbarPlugin,
315
+ ...this.draftConfig.richTextEditorPlugins,
316
+ ]}
317
+ placeholder={this.props.placeholder}
318
+ blockRenderMap={this.draftConfig.extendedBlockRenderMap}
319
+ blockStyleFn={this.draftConfig.blockStyleFn}
320
+ customStyleMap={this.draftConfig.customStyleMap}
321
+ />
322
+ {this.props.onChange && <InlineToolbar />}
323
+ </>
324
+ ) : (
325
+ <div className="DraftEditor-root" />
326
+ )}
327
+ </div>
328
+ </FormFieldWrapper>
329
+ );
330
+ }
331
+ }
332
+
333
+ export const WysiwygWidget = compose(
334
+ injectIntl,
335
+ injectLazyLibs([
336
+ 'draftJs',
337
+ 'draftJsBlockBreakoutPlugin',
338
+ 'draftJsCreateBlockStyleButton',
339
+ 'draftJsCreateInlineStyleButton',
340
+ 'draftJsFilters',
341
+ 'draftJsImportHtml',
342
+ 'draftJsInlineToolbarPlugin',
343
+ 'draftJsLibIsSoftNewlineEvent',
344
+ 'immutableLib',
345
+ ]),
346
+ connect(
347
+ (state, props) => ({
348
+ token: state.userSession.token,
349
+ }),
350
+ {},
351
+ ),
352
+ )(WysiwygWidgetComponent);
353
+
354
+ const Preloader = (props) => {
355
+ const [loaded, setLoaded] = React.useState(false);
356
+ React.useEffect(() => {
357
+ Editor.load().then(() => setLoaded(true));
358
+ }, []);
359
+ return loaded ? <WysiwygWidget {...props} /> : null;
360
+ };
361
+
362
+ export default Preloader;