volto-dropdownmenu 2.2.8 → 2.4.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/.release-it.json +1 -1
- package/CHANGELOG.md +27 -0
- package/README.md +13 -0
- package/babel.config.js +17 -1
- package/locales/de/LC_MESSAGES/volto.po +32 -12
- package/locales/en/LC_MESSAGES/volto.po +32 -12
- package/locales/es/LC_MESSAGES/volto.po +32 -12
- package/locales/eu/LC_MESSAGES/volto.po +32 -12
- package/locales/fr/LC_MESSAGES/volto.po +32 -12
- package/locales/it/LC_MESSAGES/volto.po +32 -12
- package/locales/ja/LC_MESSAGES/volto.po +32 -12
- package/locales/nl/LC_MESSAGES/volto.po +32 -12
- package/locales/pt/LC_MESSAGES/volto.po +32 -12
- package/locales/pt_BR/LC_MESSAGES/volto.po +32 -12
- package/locales/ro/LC_MESSAGES/volto.po +32 -12
- package/locales/volto.pot +17 -27
- package/package.json +5 -4
- package/src/components/DropdownMenu.jsx +13 -3
- package/src/customizations/components/theme/Navigation/Navigation.jsx +5 -0
- package/src/index.js +6 -0
- package/src/widget/MenuConfigurationForm.jsx +23 -3
- package/src/i18n.js +0 -183
|
@@ -32,7 +32,7 @@ const DropdownMenu = ({ menu, open = false, closeMenu }) => {
|
|
|
32
32
|
const location = useLocation();
|
|
33
33
|
const blocksFieldname = getBlocksFieldname(menu);
|
|
34
34
|
const blocksLayoutFieldname = getBlocksLayoutFieldname(menu);
|
|
35
|
-
|
|
35
|
+
const { clickableNavigationRoots = true } = menu;
|
|
36
36
|
const navItemWidth = menu.navigationRoot?.length > 1 ? 3 : 4;
|
|
37
37
|
const blocksWidth =
|
|
38
38
|
menu.navigationRoot?.length === 1
|
|
@@ -40,6 +40,13 @@ const DropdownMenu = ({ menu, open = false, closeMenu }) => {
|
|
|
40
40
|
: menu.navigationRoot?.length > 2 || menu.navigationRoot?.length === 0
|
|
41
41
|
? 12
|
|
42
42
|
: 6;
|
|
43
|
+
let hasBlocks = hasBlocksData(menu);
|
|
44
|
+
if (menu?.blocks && Object.keys(menu.blocks).length === 1) {
|
|
45
|
+
let b = menu.blocks[Object.keys(menu.blocks)[0]];
|
|
46
|
+
if (b['@type'] === 'text' && (!b.text || b.text?.length === 0)) {
|
|
47
|
+
hasBlocks = false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
43
50
|
|
|
44
51
|
return (
|
|
45
52
|
<div
|
|
@@ -69,7 +76,10 @@ const DropdownMenu = ({ menu, open = false, closeMenu }) => {
|
|
|
69
76
|
<h2>
|
|
70
77
|
<ConditionalLink
|
|
71
78
|
to={flattenToAppURL(navRoot['@id'])}
|
|
72
|
-
condition={
|
|
79
|
+
condition={
|
|
80
|
+
menu.navigationRoot?.length > 1 &&
|
|
81
|
+
clickableNavigationRoots
|
|
82
|
+
}
|
|
73
83
|
>
|
|
74
84
|
<span>{navRoot.title}</span>
|
|
75
85
|
</ConditionalLink>
|
|
@@ -87,7 +97,7 @@ const DropdownMenu = ({ menu, open = false, closeMenu }) => {
|
|
|
87
97
|
)}
|
|
88
98
|
</Grid.Column>
|
|
89
99
|
))}
|
|
90
|
-
{
|
|
100
|
+
{hasBlocks && (
|
|
91
101
|
<Grid.Column
|
|
92
102
|
width={blocksWidth}
|
|
93
103
|
className="dropdownmenu-blocks-column"
|
|
@@ -50,6 +50,11 @@ const Navigation = ({ pathname, type }) => {
|
|
|
50
50
|
dispatch(getDropdownMenuNavitems());
|
|
51
51
|
}, [dispatch, token]);
|
|
52
52
|
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
setMobileMenuOpen(false);
|
|
55
|
+
setOpenDropodownIndex(-1);
|
|
56
|
+
}, [pathname]);
|
|
57
|
+
|
|
53
58
|
const getAnchorTarget = (nodeElement) => {
|
|
54
59
|
if (nodeElement.nodeName === 'A') {
|
|
55
60
|
return nodeElement;
|
package/src/index.js
CHANGED
|
@@ -40,5 +40,11 @@ export default (config) => {
|
|
|
40
40
|
|
|
41
41
|
config.settings.controlPanelsIcons['dropdown-menu-settings'] = menuSVG;
|
|
42
42
|
|
|
43
|
+
config.settings['volto-dropdownmenu'] = {
|
|
44
|
+
options: {
|
|
45
|
+
clickableNavigationRoots: false, //if true, a checkbox option in dropdown menu appears
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
43
49
|
return config;
|
|
44
50
|
};
|
|
@@ -76,6 +76,10 @@ const messages = defineMessages({
|
|
|
76
76
|
id: 'dropdownmenu-deletemenuitem-button',
|
|
77
77
|
defaultMessage: 'Delete menu item',
|
|
78
78
|
},
|
|
79
|
+
clickableNavigationRoots: {
|
|
80
|
+
id: 'dropdownmenu-clickableNavigationRoots',
|
|
81
|
+
defaultMessage: 'Clickable navigation roots',
|
|
82
|
+
},
|
|
79
83
|
});
|
|
80
84
|
|
|
81
85
|
const MenuConfigurationForm = ({ id, menuItem, onChange, deleteMenuItem }) => {
|
|
@@ -117,11 +121,12 @@ const MenuConfigurationForm = ({ id, menuItem, onChange, deleteMenuItem }) => {
|
|
|
117
121
|
return () => {
|
|
118
122
|
document
|
|
119
123
|
.querySelector('form.ui.form')
|
|
120
|
-
|
|
124
|
+
?.removeEventListener('click', preventClick);
|
|
121
125
|
document.querySelectorAll('form.ui.form input').forEach((item) => {
|
|
122
|
-
item
|
|
126
|
+
item?.removeEventListener('keypress', preventEnter);
|
|
123
127
|
});
|
|
124
128
|
};
|
|
129
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
125
130
|
}, []);
|
|
126
131
|
|
|
127
132
|
const onChangeFormData = (id, value) => {
|
|
@@ -201,6 +206,22 @@ const MenuConfigurationForm = ({ id, menuItem, onChange, deleteMenuItem }) => {
|
|
|
201
206
|
}
|
|
202
207
|
/>
|
|
203
208
|
</div>
|
|
209
|
+
|
|
210
|
+
{config.settings?.['volto-dropdownmenu']?.options
|
|
211
|
+
?.clickableNavigationRoots && (
|
|
212
|
+
<div className="menu-item-field-clickableNavigationRoots">
|
|
213
|
+
<CheckboxWidget
|
|
214
|
+
id={`${id}-clickableNavigationRoots`}
|
|
215
|
+
title={intl.formatMessage(messages.clickableNavigationRoots)}
|
|
216
|
+
description=""
|
|
217
|
+
defaultValue={true}
|
|
218
|
+
value={!!menuItem.clickableNavigationRoots}
|
|
219
|
+
onChange={(id, value) =>
|
|
220
|
+
onChangeFormData('clickableNavigationRoots', value)
|
|
221
|
+
}
|
|
222
|
+
/>
|
|
223
|
+
</div>
|
|
224
|
+
)}
|
|
204
225
|
<div className="menu-item-field-showMoreLink">
|
|
205
226
|
<ObjectBrowserWidget
|
|
206
227
|
id={`${id}-showMoreLink`}
|
|
@@ -233,7 +254,6 @@ const MenuConfigurationForm = ({ id, menuItem, onChange, deleteMenuItem }) => {
|
|
|
233
254
|
}
|
|
234
255
|
/>
|
|
235
256
|
</div>
|
|
236
|
-
|
|
237
257
|
<UIForm.Field inline className="help wide" id="menu-blocks">
|
|
238
258
|
<Grid>
|
|
239
259
|
<Grid.Row stretched>
|
package/src/i18n.js
DELETED
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
/* eslint no-console: 0 */
|
|
2
|
-
/**
|
|
3
|
-
* i18n script.
|
|
4
|
-
* @module scripts/i18n
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const { find, keys, map, concat, reduce } = require('lodash');
|
|
8
|
-
const glob = require('glob').sync;
|
|
9
|
-
const fs = require('fs');
|
|
10
|
-
const Pofile = require('pofile');
|
|
11
|
-
const babel = require('@babel/core');
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Extract messages into separate JSON files
|
|
15
|
-
* @function extractMessages
|
|
16
|
-
* @return {undefined}
|
|
17
|
-
*/
|
|
18
|
-
function extractMessages() {
|
|
19
|
-
map(glob('src/**/*.js?(x)'), (filename) => {
|
|
20
|
-
babel.transformFileSync(filename, {}, (err) => {
|
|
21
|
-
if (err) {
|
|
22
|
-
console.log(err);
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Get messages from separate JSON files
|
|
30
|
-
* @function getMessages
|
|
31
|
-
* @return {Object} Object with messages
|
|
32
|
-
*/
|
|
33
|
-
function getMessages() {
|
|
34
|
-
return reduce(
|
|
35
|
-
concat(
|
|
36
|
-
{},
|
|
37
|
-
...map(
|
|
38
|
-
// We ignore the existing customized shadowed components ones, since most
|
|
39
|
-
// probably we won't be overriding them
|
|
40
|
-
// If so, we should do it in the config object or somewhere else
|
|
41
|
-
glob(
|
|
42
|
-
'build/messages/src/**/*.json',
|
|
43
|
-
// , {
|
|
44
|
-
// ignore: 'build/messages/src/customizations/**',
|
|
45
|
-
// }
|
|
46
|
-
),
|
|
47
|
-
(filename) =>
|
|
48
|
-
map(JSON.parse(fs.readFileSync(filename, 'utf8')), (message) => ({
|
|
49
|
-
...message,
|
|
50
|
-
filename: filename.match(/build\/messages\/src\/(.*).json$/)[1],
|
|
51
|
-
})),
|
|
52
|
-
),
|
|
53
|
-
),
|
|
54
|
-
(current, value) => {
|
|
55
|
-
let result = current;
|
|
56
|
-
if (current.id) {
|
|
57
|
-
result = {
|
|
58
|
-
[current.id]: {
|
|
59
|
-
defaultMessage: current.defaultMessage,
|
|
60
|
-
filenames: [current.filename],
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (result[value.id]) {
|
|
66
|
-
result[value.id].filenames.push(value.filename);
|
|
67
|
-
} else {
|
|
68
|
-
result[value.id] = {
|
|
69
|
-
defaultMessage: value.defaultMessage,
|
|
70
|
-
filenames: [value.filename],
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
return result;
|
|
74
|
-
},
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Convert messages to pot format
|
|
80
|
-
* @function messagesToPot
|
|
81
|
-
* @param {Object} messages Messages
|
|
82
|
-
* @return {string} Formatted pot string
|
|
83
|
-
*/
|
|
84
|
-
function messagesToPot(messages) {
|
|
85
|
-
return map(keys(messages).sort(), (key) =>
|
|
86
|
-
[
|
|
87
|
-
...map(messages[key].filenames, (filename) => `#: ${filename}`),
|
|
88
|
-
`# defaultMessage: ${messages[key].defaultMessage}`,
|
|
89
|
-
`msgid "${key}"`,
|
|
90
|
-
'msgstr ""',
|
|
91
|
-
].join('\n'),
|
|
92
|
-
).join('\n\n');
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Pot header
|
|
97
|
-
* @function potHeader
|
|
98
|
-
* @return {string} Formatted pot header
|
|
99
|
-
*/
|
|
100
|
-
function potHeader() {
|
|
101
|
-
return `msgid ""
|
|
102
|
-
msgstr ""
|
|
103
|
-
"Project-Id-Version: Plone\\n"
|
|
104
|
-
"POT-Creation-Date: ${new Date().toISOString()}\\n"
|
|
105
|
-
"Last-Translator: Plone i18n <plone-i18n@lists.sourceforge.net>\\n"
|
|
106
|
-
"Language-Team: Plone i18n <plone-i18n@lists.sourceforge.net>\\n"
|
|
107
|
-
"MIME-Version: 1.0\\n"
|
|
108
|
-
"Content-Type: text/plain; charset=utf-8\\n"
|
|
109
|
-
"Content-Transfer-Encoding: 8bit\\n"
|
|
110
|
-
"Plural-Forms: nplurals=1; plural=0;\\n"
|
|
111
|
-
"Language-Code: en\\n"
|
|
112
|
-
"Language-Name: English\\n"
|
|
113
|
-
"Preferred-Encodings: utf-8\\n"
|
|
114
|
-
"Domain: volto\\n"
|
|
115
|
-
|
|
116
|
-
`;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Format header
|
|
121
|
-
* @function formatHeader
|
|
122
|
-
* @param {Array} comments Array of comments
|
|
123
|
-
* @param {Object} headers Object of header items
|
|
124
|
-
* @return {string} Formatted header
|
|
125
|
-
*/
|
|
126
|
-
function formatHeader(comments, headers) {
|
|
127
|
-
return [
|
|
128
|
-
...map(comments, (comment) => `# ${comment}`),
|
|
129
|
-
'msgid ""',
|
|
130
|
-
'msgstr ""',
|
|
131
|
-
...map(keys(headers), (key) => `"${key}: ${headers[key]}\\n"`),
|
|
132
|
-
'',
|
|
133
|
-
].join('\n');
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Sync po by the pot file
|
|
138
|
-
* @function syncPoByPot
|
|
139
|
-
* @return {undefined}
|
|
140
|
-
*/
|
|
141
|
-
function syncPoByPot() {
|
|
142
|
-
const pot = Pofile.parse(fs.readFileSync('locales/volto.pot', 'utf8'));
|
|
143
|
-
|
|
144
|
-
map(glob('locales/**/*.po'), (filename) => {
|
|
145
|
-
const po = Pofile.parse(fs.readFileSync(filename, 'utf8'));
|
|
146
|
-
|
|
147
|
-
fs.writeFileSync(
|
|
148
|
-
filename,
|
|
149
|
-
`${formatHeader(po.comments, po.headers)}
|
|
150
|
-
${map(pot.items, (item) => {
|
|
151
|
-
const poItem = find(po.items, { msgid: item.msgid });
|
|
152
|
-
return [
|
|
153
|
-
`${map(item.references, (ref) => `#: ${ref}`).join('\n')}`,
|
|
154
|
-
`msgid "${item.msgid}"`,
|
|
155
|
-
`msgstr "${poItem ? poItem.msgstr : ''}"`,
|
|
156
|
-
].join('\n');
|
|
157
|
-
}).join('\n\n')}\n`,
|
|
158
|
-
);
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Main tasks
|
|
163
|
-
console.log('Extracting messages from source files...');
|
|
164
|
-
extractMessages();
|
|
165
|
-
console.log('Synchronizing messages to pot file...');
|
|
166
|
-
// We only write the pot file if it's really different
|
|
167
|
-
const newPot = `${potHeader()}${messagesToPot(getMessages())}\n`.replace(
|
|
168
|
-
/"POT-Creation-Date:(.*)\\n"/,
|
|
169
|
-
'',
|
|
170
|
-
);
|
|
171
|
-
const oldPot = fs
|
|
172
|
-
.readFileSync('locales/volto.pot', 'utf8')
|
|
173
|
-
.replace(/"POT-Creation-Date:(.*)\\n"/, '');
|
|
174
|
-
|
|
175
|
-
if (newPot !== oldPot) {
|
|
176
|
-
fs.writeFileSync(
|
|
177
|
-
'locales/volto.pot',
|
|
178
|
-
`${potHeader()}${messagesToPot(getMessages())}\n`,
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
console.log('Synchronizing messages to po files...');
|
|
182
|
-
syncPoByPot();
|
|
183
|
-
console.log('done!');
|