@plone/volto 17.0.0-alpha.2 → 17.0.0-alpha.21

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.
Files changed (318) hide show
  1. package/.yarn/install-state.gz +0 -0
  2. package/CHANGELOG.md +549 -15
  3. package/CONTRIBUTING.md +1 -1
  4. package/README.md +11 -14
  5. package/addon-registry.js +34 -0
  6. package/create-theme-addons-loader.js +79 -0
  7. package/cypress/support/commands.js +58 -5
  8. package/cypress/support/e2e.js +1 -2
  9. package/cypress/support/volto-slate.js +4 -5
  10. package/docker-compose.yml +1 -1
  11. package/locales/ca/LC_MESSAGES/volto.po +282 -7
  12. package/locales/ca.json +1 -1
  13. package/locales/de/LC_MESSAGES/volto.po +301 -26
  14. package/locales/de.json +1 -1
  15. package/locales/en/LC_MESSAGES/volto.po +281 -6
  16. package/locales/en.json +1 -1
  17. package/locales/es/LC_MESSAGES/volto.po +291 -16
  18. package/locales/es.json +1 -1
  19. package/locales/eu/LC_MESSAGES/volto.po +282 -7
  20. package/locales/eu.json +1 -1
  21. package/locales/fi/LC_MESSAGES/volto.po +4891 -0
  22. package/locales/fi.json +1 -1
  23. package/locales/fr/LC_MESSAGES/volto.po +282 -7
  24. package/locales/fr.json +1 -1
  25. package/locales/it/LC_MESSAGES/volto.po +284 -9
  26. package/locales/it.json +1 -1
  27. package/locales/ja/LC_MESSAGES/volto.po +282 -7
  28. package/locales/ja.json +1 -1
  29. package/locales/nl/LC_MESSAGES/volto.po +937 -650
  30. package/locales/nl.json +1 -1
  31. package/locales/pt/LC_MESSAGES/volto.po +282 -7
  32. package/locales/pt.json +1 -1
  33. package/locales/pt_BR/LC_MESSAGES/volto.po +291 -16
  34. package/locales/pt_BR.json +1 -1
  35. package/locales/ro/LC_MESSAGES/volto.po +282 -7
  36. package/locales/ro.json +1 -1
  37. package/locales/volto.pot +282 -7
  38. package/locales/zh_CN/LC_MESSAGES/volto.po +282 -7
  39. package/locales/zh_CN.json +1 -1
  40. package/package.json +8 -6
  41. package/packages/volto-slate/build/messages/src/blocks/Table/TableBlockEdit.json +1 -1
  42. package/packages/volto-slate/build/messages/src/blocks/Text/DefaultTextBlockEditor.json +1 -1
  43. package/packages/volto-slate/build/messages/src/blocks/Text/DetachedTextBlockEditor.json +1 -1
  44. package/packages/volto-slate/build/messages/src/blocks/Text/SlashMenu.json +1 -1
  45. package/packages/volto-slate/build/messages/src/editor/plugins/AdvancedLink/index.json +1 -1
  46. package/packages/volto-slate/build/messages/src/editor/plugins/Link/index.json +1 -1
  47. package/packages/volto-slate/build/messages/src/editor/plugins/Table/index.json +1 -1
  48. package/packages/volto-slate/build/messages/src/elementEditor/messages.json +1 -1
  49. package/packages/volto-slate/build/messages/src/widgets/HtmlSlateWidget.json +1 -1
  50. package/packages/volto-slate/build/messages/src/widgets/RichTextWidgetView.json +1 -1
  51. package/packages/volto-slate/package.json +1 -1
  52. package/packages/volto-slate/src/actions/index.js +1 -1
  53. package/packages/volto-slate/src/blocks/Table/TableBlockEdit.jsx +21 -212
  54. package/packages/volto-slate/src/blocks/Table/schema.js +122 -0
  55. package/packages/volto-slate/src/blocks/Text/DefaultTextBlockEditor.jsx +8 -3
  56. package/packages/volto-slate/src/blocks/Text/SlashMenu.jsx +4 -3
  57. package/packages/volto-slate/src/blocks/Text/TextBlockView.jsx +20 -16
  58. package/packages/volto-slate/src/blocks/Text/extensions/withDeserializers.js +3 -1
  59. package/packages/volto-slate/src/blocks/Text/index.js +10 -2
  60. package/packages/volto-slate/src/editor/config.jsx +5 -4
  61. package/packages/volto-slate/src/editor/deserialize.js +0 -1
  62. package/packages/volto-slate/src/editor/index.js +4 -4
  63. package/packages/volto-slate/src/editor/less/slate.less +28 -0
  64. package/packages/volto-slate/src/editor/plugins/StyleMenu/StyleMenu.jsx +14 -4
  65. package/packages/volto-slate/src/editor/plugins/StyleMenu/utils.js +14 -5
  66. package/packages/volto-slate/src/editor/render.jsx +68 -8
  67. package/packages/volto-slate/src/editor/ui/SlateContextToolbar.jsx +2 -2
  68. package/packages/volto-slate/src/editor/ui/index.js +15 -15
  69. package/packages/volto-slate/src/index.js +2 -2
  70. package/packages/volto-slate/src/utils/blocks.js +7 -0
  71. package/packages/volto-slate/src/widgets/RichTextWidget.jsx +15 -8
  72. package/razzle.config.js +28 -0
  73. package/src/actions/index.js +6 -0
  74. package/src/actions/language/language.js +9 -8
  75. package/src/actions/querystringsearch/querystringsearch.js +20 -14
  76. package/src/actions/relations/rebuild.js +25 -0
  77. package/src/actions/relations/relations.js +86 -0
  78. package/src/actions/relations/relations.test.js +15 -0
  79. package/src/components/index.js +3 -0
  80. package/src/components/manage/Add/Add.jsx +2 -2
  81. package/src/components/manage/AnchorPlugin/index.jsx +2 -2
  82. package/src/components/manage/AnchorPlugin/utils/EditorUtils.js +3 -1
  83. package/src/components/manage/BlockChooser/BlockChooser.jsx +14 -5
  84. package/src/components/manage/BlockChooser/BlockChooser.test.jsx +5 -0
  85. package/src/components/manage/Blocks/Block/BlocksForm.jsx +19 -2
  86. package/src/components/manage/Blocks/Block/Edit.jsx +1 -1
  87. package/src/components/manage/Blocks/Block/Style.jsx +2 -2
  88. package/src/components/manage/Blocks/Container/Data.jsx +32 -0
  89. package/src/components/manage/Blocks/Container/Edit.jsx +174 -0
  90. package/src/components/manage/Blocks/Container/EditBlockWrapper.jsx +120 -0
  91. package/src/components/manage/Blocks/Container/NewBlockAddButton.jsx +84 -0
  92. package/src/components/manage/Blocks/Container/SimpleContainerToolbar.jsx +54 -0
  93. package/src/components/manage/Blocks/Grid/Edit.jsx +33 -0
  94. package/src/components/manage/Blocks/Grid/View.jsx +43 -0
  95. package/src/components/manage/Blocks/Grid/adapter.js +14 -0
  96. package/src/components/manage/Blocks/Grid/grid-1.svg +6 -0
  97. package/src/components/manage/Blocks/Grid/grid-2.svg +9 -0
  98. package/src/components/manage/Blocks/Grid/grid-3.svg +10 -0
  99. package/src/components/manage/Blocks/Grid/grid-4.svg +11 -0
  100. package/src/components/manage/Blocks/Grid/schema.js +35 -0
  101. package/src/components/manage/Blocks/Grid/templates.js +47 -0
  102. package/src/components/manage/Blocks/HeroImageLeft/Edit.jsx +6 -1
  103. package/src/components/manage/Blocks/Image/Edit.jsx +51 -12
  104. package/src/components/manage/Blocks/Image/Edit.test.jsx +2 -0
  105. package/src/components/manage/Blocks/Image/ImageSidebar.jsx +66 -16
  106. package/src/components/manage/Blocks/Image/View.jsx +25 -5
  107. package/src/components/manage/Blocks/Image/View.test.jsx +20 -0
  108. package/src/components/manage/Blocks/Image/schema.js +12 -9
  109. package/src/components/manage/Blocks/Image/utils.js +14 -0
  110. package/src/components/manage/Blocks/LeadImage/Edit.jsx +32 -10
  111. package/src/components/manage/Blocks/LeadImage/Edit.test.jsx +11 -1
  112. package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.jsx +28 -9
  113. package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.test.jsx +8 -2
  114. package/src/components/manage/Blocks/LeadImage/View.jsx +50 -38
  115. package/src/components/manage/Blocks/LeadImage/View.test.jsx +11 -1
  116. package/src/components/manage/Blocks/Listing/DefaultTemplate.jsx +18 -3
  117. package/src/components/manage/Blocks/Listing/Edit.jsx +0 -14
  118. package/src/components/manage/Blocks/Listing/ListingBody.jsx +30 -8
  119. package/src/components/manage/Blocks/Listing/ListingBody.test.jsx +20 -0
  120. package/src/components/manage/Blocks/Listing/SummaryTemplate.jsx +1 -1
  121. package/src/components/manage/Blocks/Listing/getAsyncData.js +9 -3
  122. package/src/components/manage/Blocks/Listing/withQuerystringResults.jsx +26 -18
  123. package/src/components/manage/Blocks/Search/SearchBlockEdit.jsx +5 -4
  124. package/src/components/manage/Blocks/Search/SearchBlockView.jsx +2 -1
  125. package/src/components/manage/Blocks/Search/components/DateRangeFacet.jsx +4 -1
  126. package/src/components/manage/Blocks/Search/components/Facets.jsx +64 -4
  127. package/src/components/manage/Blocks/Search/components/SearchInput.jsx +9 -2
  128. package/src/components/manage/Blocks/Search/components/index.js +13 -13
  129. package/src/components/manage/Blocks/Search/hocs/index.js +2 -2
  130. package/src/components/manage/Blocks/Search/hocs/withQueryString.jsx +2 -2
  131. package/src/components/manage/Blocks/Search/hocs/withSearch.jsx +43 -15
  132. package/src/components/manage/Blocks/Search/layout/LeftColumnFacets.jsx +17 -5
  133. package/src/components/manage/Blocks/Search/layout/RightColumnFacets.jsx +17 -5
  134. package/src/components/manage/Blocks/Search/layout/TopSideFacets.jsx +21 -5
  135. package/src/components/manage/Blocks/Search/schema.js +16 -1
  136. package/src/components/manage/Blocks/Teaser/Body.jsx +0 -1
  137. package/src/components/manage/Blocks/Teaser/DefaultBody.jsx +5 -10
  138. package/src/components/manage/Blocks/Teaser/schema.js +5 -0
  139. package/src/components/manage/Blocks/Title/View.jsx +15 -5
  140. package/src/components/manage/Blocks/Title/View.test.jsx +16 -1
  141. package/src/components/manage/Blocks/ToC/Schema.jsx +5 -1
  142. package/src/components/manage/Blocks/ToC/View.jsx +8 -1
  143. package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.jsx +17 -4
  144. package/src/components/manage/Blocks/ToC/variations/HorizontalMenu.jsx +148 -10
  145. package/src/components/manage/Blocks/ToC/variations/index.js +3 -1
  146. package/src/components/manage/Contents/Contents.jsx +47 -32
  147. package/src/components/manage/Contents/ContentsItem.jsx +6 -0
  148. package/src/components/manage/Contents/ContentsUploadModal.jsx +10 -5
  149. package/src/components/manage/Controlpanels/AddonsControlpanel.jsx +3 -3
  150. package/src/components/manage/Controlpanels/Controlpanels.jsx +199 -224
  151. package/src/components/manage/Controlpanels/Controlpanels.test.jsx +46 -7
  152. package/src/components/manage/Controlpanels/Relations/BrokenRelations.jsx +66 -0
  153. package/src/components/manage/Controlpanels/Relations/Relations.jsx +114 -0
  154. package/src/components/manage/Controlpanels/Relations/RelationsListing.jsx +479 -0
  155. package/src/components/manage/Controlpanels/Relations/RelationsMatrix.jsx +531 -0
  156. package/src/components/manage/Controlpanels/Users/UserGroupMembershipControlPanel.jsx +3 -3
  157. package/src/components/manage/Controlpanels/Users/UserGroupMembershipListing.jsx +51 -82
  158. package/src/components/manage/Controlpanels/Users/UserGroupMembershipMatrix.jsx +79 -75
  159. package/src/components/manage/DragDropList/DragDropList.jsx +18 -13
  160. package/src/components/manage/Form/Form.jsx +5 -3
  161. package/src/components/manage/Form/InlineForm.jsx +39 -9
  162. package/src/components/manage/Form/InlineFormState.js +8 -0
  163. package/src/components/manage/History/History.jsx +11 -1
  164. package/src/components/manage/LinksToItem/LinksToItem.jsx +209 -0
  165. package/src/components/manage/LinksToItem/LinksToItem.test.jsx +97 -0
  166. package/src/components/manage/Multilingual/CreateTranslation.jsx +2 -2
  167. package/src/components/manage/Multilingual/TranslationObject.jsx +4 -3
  168. package/src/components/manage/Preferences/ChangePassword.jsx +2 -2
  169. package/src/components/manage/Preferences/PersonalPreferences.jsx +2 -2
  170. package/src/components/manage/Sharing/Sharing.jsx +5 -1
  171. package/src/components/manage/Sidebar/AlignBlock.jsx +1 -1
  172. package/src/components/manage/TemplateChooser/TemplateChooser.jsx +38 -0
  173. package/src/components/manage/TemplateChooser/TemplateChooser.test.jsx +34 -0
  174. package/src/components/manage/TemplateChooser/template.svg +10 -0
  175. package/src/components/manage/Toast/Toast.jsx +2 -2
  176. package/src/components/manage/Toolbar/More.jsx +15 -0
  177. package/src/components/manage/Toolbar/Types.jsx +2 -2
  178. package/src/components/manage/UniversalLink/UniversalLink.jsx +2 -6
  179. package/src/components/manage/UniversalLink/UniversalLink.test.jsx +36 -0
  180. package/src/components/manage/Widgets/ColorPickerWidget.jsx +6 -1
  181. package/src/components/manage/Widgets/DatetimeWidget.jsx +9 -5
  182. package/src/components/manage/Widgets/FileWidget.jsx +2 -1
  183. package/src/components/manage/Widgets/ObjectListWidget.jsx +3 -8
  184. package/src/components/manage/Widgets/RecurrenceWidget/ByDayField.jsx +2 -1
  185. package/src/components/manage/Widgets/RecurrenceWidget/MonthOfTheYearField.jsx +2 -1
  186. package/src/components/manage/Widgets/RecurrenceWidget/Occurences.jsx +2 -1
  187. package/src/components/manage/Widgets/RecurrenceWidget/RecurrenceWidget.jsx +8 -3
  188. package/src/components/manage/Widgets/RecurrenceWidget/WeekdayOfTheMonthField.jsx +2 -1
  189. package/src/components/manage/Widgets/SelectUtils.js +1 -1
  190. package/src/components/manage/Widgets/SelectWidget.jsx +1 -1
  191. package/src/components/theme/Anontools/Anontools.jsx +44 -72
  192. package/src/components/theme/Anontools/Anontools.stories.jsx +16 -6
  193. package/src/components/theme/Anontools/Anontools.test.jsx +16 -2
  194. package/src/components/theme/Breadcrumbs/Breadcrumbs.jsx +52 -99
  195. package/src/components/theme/Breadcrumbs/Breadcrumbs.stories.jsx +14 -13
  196. package/src/components/theme/Comments/CommentEditModal.jsx +63 -115
  197. package/src/components/theme/Component/Component.jsx +1 -1
  198. package/src/components/theme/ContactForm/ContactForm.jsx +108 -192
  199. package/src/components/theme/ContactForm/ContactForm.stories.jsx +1 -1
  200. package/src/components/theme/ContactForm/ContactForm.test.jsx +2 -3
  201. package/src/components/theme/Footer/Footer.jsx +2 -13
  202. package/src/components/theme/Header/Header.jsx +37 -63
  203. package/src/components/theme/Header/Header.test.jsx +18 -0
  204. package/src/components/theme/Icon/Icon.jsx +2 -2
  205. package/src/components/theme/Image/Image.jsx +96 -0
  206. package/src/components/theme/Image/Image.test.jsx +125 -0
  207. package/src/components/theme/LanguageSelector/LanguageSelector.js +8 -3
  208. package/src/components/theme/Login/Login.jsx +1 -0
  209. package/src/components/theme/Logo/Logo.jsx +4 -1
  210. package/src/components/theme/MultilingualRedirector/MultilingualRedirector.jsx +2 -2
  211. package/src/components/theme/Navigation/NavItem.jsx +4 -2
  212. package/src/components/theme/NotFound/NotFound.jsx +55 -41
  213. package/src/components/theme/PasswordReset/PasswordReset.jsx +7 -4
  214. package/src/components/theme/PasswordReset/RequestPasswordReset.jsx +1 -1
  215. package/src/components/theme/PreviewImage/PreviewImage.jsx +25 -14
  216. package/src/components/theme/PreviewImage/PreviewImage.test.js +39 -16
  217. package/src/components/theme/SearchWidget/SearchWidget.jsx +38 -98
  218. package/src/components/theme/Sitemap/Sitemap.jsx +5 -3
  219. package/src/components/theme/View/AlbumView.jsx +20 -16
  220. package/src/components/theme/View/DefaultView.jsx +1 -1
  221. package/src/components/theme/View/EventDatesInfo.jsx +2 -1
  222. package/src/components/theme/View/EventView.jsx +36 -25
  223. package/src/components/theme/View/FileView.jsx +23 -18
  224. package/src/components/theme/View/ImageView.jsx +40 -32
  225. package/src/components/theme/View/ImageView.test.jsx +4 -0
  226. package/src/components/theme/View/LinkView.jsx +53 -78
  227. package/src/components/theme/View/ListingView.jsx +36 -28
  228. package/src/components/theme/View/NewsItemView.jsx +16 -17
  229. package/src/components/theme/View/RenderBlocks.jsx +56 -21
  230. package/src/components/theme/View/RenderEmptyBlock.jsx +5 -0
  231. package/src/components/theme/View/SummaryView.jsx +49 -39
  232. package/src/components/theme/View/TabularView.jsx +59 -53
  233. package/src/components/theme/Widgets/DateWidget.jsx +2 -1
  234. package/src/components/theme/Widgets/DatetimeWidget.jsx +2 -1
  235. package/src/components/theme/Widgets/RelationsWidget.jsx +13 -11
  236. package/src/config/Blocks.jsx +46 -0
  237. package/src/config/Components.jsx +2 -1
  238. package/src/config/ControlPanels.js +2 -0
  239. package/src/config/NonContentRoutes.jsx +1 -0
  240. package/src/config/RichTextEditor/Blocks.jsx +2 -2
  241. package/src/config/RichTextEditor/FromHTML.jsx +2 -2
  242. package/src/config/RichTextEditor/Styles.jsx +1 -1
  243. package/src/config/Widgets.jsx +2 -0
  244. package/src/config/index.js +24 -0
  245. package/src/config/server.js +2 -0
  246. package/src/constants/ActionTypes.js +4 -0
  247. package/src/constants/Indexes.js +3 -1
  248. package/src/constants/Languages.js +8 -4
  249. package/src/express-middleware/devproxy.js +1 -1
  250. package/src/express-middleware/files.js +3 -3
  251. package/src/express-middleware/images.js +4 -4
  252. package/src/express-middleware/ok.js +16 -0
  253. package/src/express-middleware/robotstxt.js +1 -1
  254. package/src/express-middleware/sitemap.js +37 -5
  255. package/src/express-middleware/static.js +3 -3
  256. package/src/helpers/Api/Api.js +1 -1
  257. package/src/helpers/Blocks/Blocks.js +48 -0
  258. package/src/helpers/Blocks/Blocks.test.js +79 -0
  259. package/src/helpers/Extensions/index.js +2 -1
  260. package/src/helpers/Extensions/withBlockSchemaEnhancer.js +15 -11
  261. package/src/helpers/Extensions/withBlockSchemaEnhancer.test.js +145 -0
  262. package/src/helpers/FormValidation/FormValidation.js +40 -2
  263. package/src/helpers/FormValidation/FormValidation.test.js +73 -0
  264. package/src/helpers/Html/Html.jsx +3 -1
  265. package/src/helpers/Html/Html.test.jsx +5 -0
  266. package/src/helpers/MessageLabels/MessageLabels.js +80 -0
  267. package/src/helpers/Robots/Robots.js +24 -6
  268. package/src/helpers/ScrollToTop/ScrollToTop.jsx +5 -3
  269. package/src/helpers/Sitemap/Sitemap.js +44 -2
  270. package/src/helpers/Url/Url.js +49 -7
  271. package/src/helpers/Url/Url.test.js +67 -0
  272. package/src/helpers/Utils/UseDetectClickOutside.stories.jsx +191 -0
  273. package/src/helpers/Utils/Utils.js +63 -13
  274. package/src/helpers/Utils/Utils.test.js +4 -4
  275. package/src/helpers/Utils/usePagination.js +67 -14
  276. package/src/helpers/Utils/usePagination.test.js +115 -0
  277. package/src/helpers/index.js +20 -10
  278. package/src/hooks/client/useClient.js +11 -0
  279. package/src/hooks/clipboard/useClipboard.js +26 -0
  280. package/src/hooks/index.js +2 -0
  281. package/src/icons/grid-block.svg +11 -0
  282. package/src/middleware/Api.test.js +54 -0
  283. package/src/middleware/api.js +24 -6
  284. package/src/middleware/index.js +2 -2
  285. package/src/reducers/actions/actions.js +8 -6
  286. package/src/reducers/actions/actions.test.js +70 -0
  287. package/src/reducers/breadcrumbs/breadcrumbs.js +1 -1
  288. package/src/reducers/index.js +2 -0
  289. package/src/reducers/navigation/navigation.js +1 -1
  290. package/src/reducers/relations/relations.js +173 -0
  291. package/src/reducers/types/types.js +1 -1
  292. package/src/routes.js +14 -0
  293. package/src/server.jsx +28 -23
  294. package/src/start-server.js +2 -2
  295. package/test-setup-config.js +11 -1
  296. package/theme/themes/pastanaga/extras/blocks.less +5 -1
  297. package/theme/themes/pastanaga/extras/contents.less +1 -0
  298. package/theme/themes/pastanaga/extras/grid.less +426 -0
  299. package/theme/themes/pastanaga/extras/main.less +8 -1
  300. package/theme/themes/pastanaga/extras/search.less +6 -0
  301. package/theme/themes/pastanaga/extras/sidebar.less +4 -0
  302. package/theme/themes/pastanaga/extras/toc.less +29 -0
  303. package/theme/themes/pastanaga/extras/userscontrolpanel.less +99 -76
  304. package/.changelog.draft +0 -31
  305. package/.editorconfig +0 -36
  306. package/.storybook/main.js +0 -127
  307. package/.storybook/manager.js +0 -15
  308. package/.storybook/preview.js +0 -21
  309. package/.storybook/static/previewImage.svg +0 -48
  310. package/.yarnrc.yml +0 -5
  311. package/jsdoc.json +0 -16
  312. package/netlify.toml +0 -5
  313. package/pyvenv.cfg +0 -3
  314. package/share/man/man1/ttx.1 +0 -225
  315. package/src/components/manage/Blocks/Teaser/utils.js +0 -44
  316. package/src/components/manage/Blocks/Teaser/utils.test.jsx +0 -229
  317. package/src/components/theme/Header/Header.md +0 -27
  318. package/towncrier.toml +0 -33
@@ -1,9 +1,18 @@
1
- import React from 'react';
1
+ import React, { useState, useMemo } from 'react';
2
+ import { Button, Grid } from 'semantic-ui-react';
2
3
  import { resolveExtension } from '@plone/volto/helpers/Extensions/withBlockExtensions';
3
4
  import config from '@plone/volto/registry';
4
5
  import { hasNonValueOperation, hasDateOperation } from '../utils';
6
+ import { defineMessages, useIntl } from 'react-intl';
5
7
 
6
- const showFacet = (index) => {
8
+ const messages = defineMessages({
9
+ moreFilters: { id: 'More filters', defaultMessage: 'More filters' },
10
+ lessFilters: { id: 'Less filters', defaultMessage: 'Less filters' },
11
+ showFilters: { id: 'Show filters', defaultMessage: 'Show filters' },
12
+ hideFilters: { id: 'Hide filters', defaultMessage: 'Hide filters' },
13
+ });
14
+
15
+ const defaultShowFacet = (index) => {
7
16
  const { values } = index;
8
17
  return index
9
18
  ? hasNonValueOperation(index.operations || []) ||
@@ -14,6 +23,7 @@ const showFacet = (index) => {
14
23
  };
15
24
 
16
25
  const Facets = (props) => {
26
+ const [hidden, setHidden] = useState(true);
17
27
  const {
18
28
  querystring,
19
29
  data = {},
@@ -24,11 +34,29 @@ const Facets = (props) => {
24
34
  } = props;
25
35
  const { search } = config.blocks.blocksConfig;
26
36
 
37
+ const advancedFilters = useMemo(() => {
38
+ let count = 0;
39
+ for (let facetSettings of data.facets || []) {
40
+ if (facetSettings.advanced) {
41
+ count++;
42
+ }
43
+ }
44
+
45
+ if (count === data.facets?.length) {
46
+ return 2;
47
+ }
48
+ if (count) {
49
+ return 1;
50
+ }
51
+ return 0;
52
+ }, [data.facets]);
53
+
27
54
  const FacetWrapper = facetWrapper;
28
55
  const query_to_values = Object.assign(
29
56
  {},
30
57
  ...(data?.query?.query?.map(({ i, v }) => ({ [i]: v })) || []),
31
58
  );
59
+ const intl = useIntl();
32
60
 
33
61
  return (
34
62
  <>
@@ -36,6 +64,7 @@ const Facets = (props) => {
36
64
  ?.filter((facetSettings) => !facetSettings.hidden)
37
65
  .map((facetSettings) => {
38
66
  const field = facetSettings?.field?.value;
67
+ const isAdvanced = facetSettings?.advanced;
39
68
  const index = querystring.indexes[field] || {};
40
69
  const { values = {} } = index;
41
70
 
@@ -58,10 +87,15 @@ const Facets = (props) => {
58
87
 
59
88
  const isMulti = facetSettings.multiple;
60
89
  const selectedValue = facets[facetSettings?.field?.value];
90
+ const visible = (isAdvanced && !hidden) || !isAdvanced;
61
91
 
62
92
  // TODO :handle changing the type of facet (multi/nonmulti)
63
93
 
64
- const { view: FacetWidget, stateToValue } = resolveExtension(
94
+ const {
95
+ view: FacetWidget,
96
+ stateToValue,
97
+ showFacet = defaultShowFacet,
98
+ } = resolveExtension(
65
99
  'type',
66
100
  search.extensions.facetWidgets.types,
67
101
  facetSettings,
@@ -74,7 +108,11 @@ const Facets = (props) => {
74
108
  } = search.extensions.facetWidgets;
75
109
 
76
110
  return FacetWrapper && (isEditMode || showFacet(index)) ? (
77
- <FacetWrapper key={facetSettings['@id']}>
111
+ <FacetWrapper
112
+ key={facetSettings['@id']}
113
+ facetSettings={facetSettings}
114
+ visible={visible}
115
+ >
78
116
  <FacetWidget
79
117
  facet={facetSettings}
80
118
  choices={rewriteOptions(facetSettings?.field?.value, choices)}
@@ -90,6 +128,28 @@ const Facets = (props) => {
90
128
  ''
91
129
  );
92
130
  })}
131
+ {advancedFilters > 0 && (
132
+ <Grid.Column
133
+ mobile={12}
134
+ tablet={12}
135
+ computer={12}
136
+ className="toggle-advanced-facets"
137
+ >
138
+ <Button
139
+ onClick={() => {
140
+ setHidden((prevHidden) => !prevHidden);
141
+ }}
142
+ >
143
+ {hidden
144
+ ? advancedFilters === 2
145
+ ? intl.formatMessage(messages.showFilters)
146
+ : intl.formatMessage(messages.moreFilters)
147
+ : advancedFilters === 2
148
+ ? intl.formatMessage(messages.hideFilters)
149
+ : intl.formatMessage(messages.lessFilters)}
150
+ </Button>
151
+ </Grid.Column>
152
+ )}
93
153
  </>
94
154
  );
95
155
  };
@@ -13,7 +13,14 @@ const messages = defineMessages({
13
13
  });
14
14
 
15
15
  const SearchInput = (props) => {
16
- const { data, searchText, setSearchText, isLive, onTriggerSearch } = props;
16
+ const {
17
+ data,
18
+ searchText,
19
+ setSearchText,
20
+ isLive,
21
+ onTriggerSearch,
22
+ removeSearchQuery,
23
+ } = props;
17
24
  const intl = useIntl();
18
25
 
19
26
  return (
@@ -44,7 +51,7 @@ const SearchInput = (props) => {
44
51
  className="search-input-clear-icon-button"
45
52
  onClick={() => {
46
53
  setSearchText('');
47
- onTriggerSearch('');
54
+ removeSearchQuery();
48
55
  }}
49
56
  >
50
57
  <Icon name={clearSVG} />
@@ -1,13 +1,13 @@
1
- export SearchDetails from './SearchDetails';
2
- export Facets from './Facets';
3
- export SelectFacet from './SelectFacet';
4
- export CheckboxFacet from './CheckboxFacet';
5
- export DateRangeFacet from './DateRangeFacet';
6
- export SearchInput from './SearchInput';
7
- export FilterList from './FilterList';
8
- export SortOn from './SortOn';
9
- export ToggleFacet from './ToggleFacet';
10
- export SelectFacetFilterListEntry from './SelectFacetFilterListEntry';
11
- export ToggleFacetFilterListEntry from './ToggleFacetFilterListEntry';
12
- export DateRangeFacetFilterListEntry from './DateRangeFacetFilterListEntry';
13
- export ViewSwitcher from './ViewSwitcher';
1
+ export { default as SearchDetails } from './SearchDetails';
2
+ export { default as Facets } from './Facets';
3
+ export { default as SelectFacet } from './SelectFacet';
4
+ export { default as CheckboxFacet } from './CheckboxFacet';
5
+ export { default as DateRangeFacet } from './DateRangeFacet';
6
+ export { default as SearchInput } from './SearchInput';
7
+ export { default as FilterList } from './FilterList';
8
+ export { default as SortOn } from './SortOn';
9
+ export { default as ToggleFacet } from './ToggleFacet';
10
+ export { default as SelectFacetFilterListEntry } from './SelectFacetFilterListEntry';
11
+ export { default as ToggleFacetFilterListEntry } from './ToggleFacetFilterListEntry';
12
+ export { default as DateRangeFacetFilterListEntry } from './DateRangeFacetFilterListEntry';
13
+ export { default as ViewSwitcher } from './ViewSwitcher';
@@ -1,2 +1,2 @@
1
- export withQueryString from './withQueryString';
2
- export withSearch from './withSearch';
1
+ export { default as withQueryString } from './withQueryString';
2
+ export { default as withSearch } from './withSearch';
@@ -10,7 +10,7 @@ function getDisplayName(WrappedComponent) {
10
10
  * A HOC that injects querystring metadata information from the backend.
11
11
  *
12
12
  */
13
- export default (WrappedComponent) => {
13
+ export default function withQueryString(WrappedComponent) {
14
14
  function WithQueryString(props) {
15
15
  const dispatch = useDispatch();
16
16
 
@@ -29,4 +29,4 @@ export default (WrappedComponent) => {
29
29
  WrappedComponent,
30
30
  )})`;
31
31
  return WithQueryString;
32
- };
32
+ }
@@ -114,15 +114,19 @@ function normalizeState({
114
114
  block: id,
115
115
  };
116
116
 
117
- // TODO: need to check if SearchableText facet is not already in the query
118
- // Ideally the searchtext functionality should be restructured as being just
119
- // another facet
120
- params.query = params.query.reduce(
121
- // Remove SearchableText from query
122
- (acc, kvp) => (kvp.i === 'SearchableText' ? acc : [...acc, kvp]),
123
- [],
124
- );
117
+ // Note Ideally the searchtext functionality should be restructured as being just
118
+ // another facet. But right now it's the same. This means that if a searchText
119
+ // is provided, it will override the SearchableText facet.
120
+ // If there is no searchText, the SearchableText in the query remains in effect.
121
+ // TODO eventually the searchText should be a distinct facet from SearchableText, and
122
+ // the two conditions could be combined, in comparison to the current state, when
123
+ // one overrides the other.
125
124
  if (searchText) {
125
+ params.query = params.query.reduce(
126
+ // Remove SearchableText from query
127
+ (acc, kvp) => (kvp.i === 'SearchableText' ? acc : [...acc, kvp]),
128
+ [],
129
+ );
126
130
  params.query.push({
127
131
  i: 'SearchableText',
128
132
  o: 'plone.app.querystring.operation.string.contains',
@@ -144,12 +148,16 @@ const getSearchFields = (searchData) => {
144
148
  };
145
149
 
146
150
  /**
147
- * A HOC that will mirror the search block state to a hash location
151
+ * A hook that will mirror the search block state to a hash location
148
152
  */
149
153
  const useHashState = () => {
150
154
  const location = useLocation();
151
155
  const history = useHistory();
152
156
 
157
+ /**
158
+ * Required to maintain parameter compatibility.
159
+ With this we will maintain support for receiving hash (#) and search (?) type parameters.
160
+ */
153
161
  const oldState = React.useMemo(() => {
154
162
  return {
155
163
  ...qs.parse(location.search),
@@ -165,7 +173,7 @@ const useHashState = () => {
165
173
 
166
174
  const setSearchData = React.useCallback(
167
175
  (searchData) => {
168
- const newParams = qs.parse(location.hash);
176
+ const newParams = qs.parse(location.search);
169
177
 
170
178
  let changed = false;
171
179
 
@@ -182,11 +190,11 @@ const useHashState = () => {
182
190
 
183
191
  if (changed) {
184
192
  history.push({
185
- hash: qs.stringify(newParams),
193
+ search: qs.stringify(newParams),
186
194
  });
187
195
  }
188
196
  },
189
- [history, oldState, location.hash],
197
+ [history, oldState, location.search],
190
198
  );
191
199
 
192
200
  return [current, setSearchData];
@@ -278,8 +286,14 @@ const withSearch = (options) => (WrappedComponent) => {
278
286
  const timeoutRef = React.useRef();
279
287
  const facetSettings = data?.facets;
280
288
 
289
+ const deepQuery = JSON.stringify(data.query);
281
290
  const onTriggerSearch = React.useCallback(
282
- (toSearchText, toSearchFacets, toSortOn, toSortOrder) => {
291
+ (
292
+ toSearchText = undefined,
293
+ toSearchFacets = undefined,
294
+ toSortOn = undefined,
295
+ toSortOrder = undefined,
296
+ ) => {
283
297
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
284
298
  timeoutRef.current = setTimeout(
285
299
  () => {
@@ -287,7 +301,7 @@ const withSearch = (options) => (WrappedComponent) => {
287
301
  id,
288
302
  query: data.query || {},
289
303
  facets: toSearchFacets || facets,
290
- searchText: toSearchText,
304
+ searchText: toSearchText ? toSearchText.trim() : '',
291
305
  sortOn: toSortOn || sortOn,
292
306
  sortOrder: toSortOrder || sortOrder,
293
307
  facetSettings,
@@ -301,17 +315,30 @@ const withSearch = (options) => (WrappedComponent) => {
301
315
  toSearchFacets ? inputDelay / 3 : inputDelay,
302
316
  );
303
317
  },
318
+ // eslint-disable-next-line react-hooks/exhaustive-deps
304
319
  [
305
- data.query,
320
+ // Use deep comparison of data.query
321
+ deepQuery,
306
322
  facets,
307
323
  id,
308
324
  setLocationSearchData,
325
+ searchText,
309
326
  sortOn,
310
327
  sortOrder,
311
328
  facetSettings,
312
329
  ],
313
330
  );
314
331
 
332
+ const removeSearchQuery = () => {
333
+ searchData.query = searchData.query.reduce(
334
+ // Remove SearchableText from query
335
+ (acc, kvp) => (kvp.i === 'SearchableText' ? acc : [...acc, kvp]),
336
+ [],
337
+ );
338
+ setSearchData(searchData);
339
+ setLocationSearchData(getSearchFields(searchData));
340
+ };
341
+
315
342
  const querystringResults = useSelector(
316
343
  (state) => state.querystringsearch.subrequests,
317
344
  );
@@ -330,6 +357,7 @@ const withSearch = (options) => (WrappedComponent) => {
330
357
  sortOrder={sortOrder}
331
358
  searchedText={urlSearchText}
332
359
  searchText={searchText}
360
+ removeSearchQuery={removeSearchQuery}
333
361
  setSearchText={setSearchText}
334
362
  onTriggerSearch={onTriggerSearch}
335
363
  totalItems={totalItems}
@@ -11,6 +11,7 @@ import { Grid, Segment } from 'semantic-ui-react';
11
11
  import { Button } from 'semantic-ui-react';
12
12
  import { flushSync } from 'react-dom';
13
13
  import { defineMessages, useIntl } from 'react-intl';
14
+ import cx from 'classnames';
14
15
 
15
16
  const messages = defineMessages({
16
17
  searchButtonText: {
@@ -19,11 +20,22 @@ const messages = defineMessages({
19
20
  },
20
21
  });
21
22
 
22
- const FacetWrapper = ({ children }) => (
23
- <Segment basic className="facet">
24
- {children}
25
- </Segment>
26
- );
23
+ const FacetWrapper = ({ children, facetSettings = {}, visible }) => {
24
+ const { advanced, field = {} } = facetSettings;
25
+
26
+ return (
27
+ <Segment
28
+ basic
29
+ className={cx('facet', {
30
+ [`facet-index-${field.value}`]: !!field.value,
31
+ 'advanced-facet': advanced,
32
+ 'advanced-facet-hidden': !visible,
33
+ })}
34
+ >
35
+ {children}
36
+ </Segment>
37
+ );
38
+ };
27
39
 
28
40
  const LeftColumnFacets = (props) => {
29
41
  const {
@@ -11,6 +11,7 @@ import { Grid, Segment } from 'semantic-ui-react';
11
11
  import { Button } from 'semantic-ui-react';
12
12
  import { flushSync } from 'react-dom';
13
13
  import { defineMessages, useIntl } from 'react-intl';
14
+ import cx from 'classnames';
14
15
 
15
16
  const messages = defineMessages({
16
17
  searchButtonText: {
@@ -19,11 +20,22 @@ const messages = defineMessages({
19
20
  },
20
21
  });
21
22
 
22
- const FacetWrapper = ({ children }) => (
23
- <Segment basic className="facet">
24
- {children}
25
- </Segment>
26
- );
23
+ const FacetWrapper = ({ children, facetSettings = {}, visible }) => {
24
+ const { advanced, field = {} } = facetSettings;
25
+
26
+ return (
27
+ <Segment
28
+ basic
29
+ className={cx('facet', {
30
+ [`facet-index-${field.value}`]: !!field.value,
31
+ 'advanced-facet': advanced,
32
+ 'advanced-facet-hidden': !visible,
33
+ })}
34
+ >
35
+ {children}
36
+ </Segment>
37
+ );
38
+ };
27
39
 
28
40
  const RightColumnFacets = (props) => {
29
41
  const {
@@ -11,6 +11,7 @@ import {
11
11
  SortOn,
12
12
  ViewSwitcher,
13
13
  } from '../components';
14
+ import cx from 'classnames';
14
15
 
15
16
  const messages = defineMessages({
16
17
  searchButtonText: {
@@ -19,11 +20,24 @@ const messages = defineMessages({
19
20
  },
20
21
  });
21
22
 
22
- const FacetWrapper = ({ children }) => (
23
- <Grid.Column mobile={12} tablet={4} computer={3}>
24
- {children}
25
- </Grid.Column>
26
- );
23
+ const FacetWrapper = ({ children, facetSettings = {}, visible }) => {
24
+ const { advanced, field = {} } = facetSettings;
25
+
26
+ return (
27
+ <Grid.Column
28
+ mobile={12}
29
+ tablet={4}
30
+ computer={3}
31
+ className={cx('facet', {
32
+ [`facet-index-${field.value}`]: !!field.value,
33
+ 'advanced-facet': advanced,
34
+ 'advanced-facet-hidden': !visible,
35
+ })}
36
+ >
37
+ {children}
38
+ </Grid.Column>
39
+ );
40
+ };
27
41
 
28
42
  const TopSideFacets = (props) => {
29
43
  const {
@@ -117,6 +131,7 @@ const TopSideFacets = (props) => {
117
131
  <ViewSwitcher {...props} />
118
132
  )}
119
133
  </div>
134
+
120
135
  {data.facets?.length > 0 && (
121
136
  <div className="facets">
122
137
  {data.facetsTitle && <h3>{data.facetsTitle}</h3>}
@@ -136,6 +151,7 @@ const TopSideFacets = (props) => {
136
151
  </Grid>
137
152
  </div>
138
153
  )}
154
+
139
155
  <SearchDetails
140
156
  text={searchedText}
141
157
  total={totalItems}
@@ -88,6 +88,15 @@ const messages = defineMessages({
88
88
  defaultMessage:
89
89
  'Hidden facets will still filter the results if proper parameters are passed in URLs',
90
90
  },
91
+ advancedFacetTitle: {
92
+ id: 'Advanced facet?',
93
+ defaultMessage: 'Advanced facet?',
94
+ },
95
+ advancedFacetDescription: {
96
+ id: 'Advanced facets are initially hidden and displayed on demand',
97
+ defaultMessage:
98
+ 'Advanced facets are initially hidden and displayed on demand',
99
+ },
91
100
  facetWidget: {
92
101
  id: 'Facet widget',
93
102
  defaultMessage: 'Facet widget',
@@ -131,7 +140,7 @@ const FacetSchema = ({ intl }) => ({
131
140
  {
132
141
  id: 'default',
133
142
  title: 'Default',
134
- fields: ['title', 'field', 'type', 'hidden'],
143
+ fields: ['title', 'field', 'type', 'hidden', 'advanced'],
135
144
  },
136
145
  ],
137
146
  properties: {
@@ -170,6 +179,12 @@ const FacetSchema = ({ intl }) => ({
170
179
  default: false,
171
180
  description: intl.formatMessage(messages.hideFacetDescription),
172
181
  },
182
+ advanced: {
183
+ type: 'boolean',
184
+ title: intl.formatMessage(messages.advancedFacetTitle),
185
+ default: false,
186
+ description: intl.formatMessage(messages.advancedFacetDescription),
187
+ },
173
188
  type: {
174
189
  title: intl.formatMessage(messages.facetWidget),
175
190
  choices: config.blocks.blocksConfig.search.extensions.facetWidgets.types.map(
@@ -24,7 +24,6 @@ const TeaserBody = (props) => {
24
24
  TeaserBody.propTypes = {
25
25
  data: PropTypes.objectOf(PropTypes.any).isRequired,
26
26
  isEditMode: PropTypes.bool,
27
- variation: PropTypes.string,
28
27
  };
29
28
 
30
29
  export default TeaserBody;
@@ -3,8 +3,7 @@ import PropTypes from 'prop-types';
3
3
  import { Message } from 'semantic-ui-react';
4
4
  import { defineMessages, useIntl } from 'react-intl';
5
5
  import imageBlockSVG from '@plone/volto/components/manage/Blocks/Image/block-image.svg';
6
- import { flattenToAppURL, isInternalURL } from '@plone/volto/helpers';
7
- import { getTeaserImageURL } from './utils';
6
+ import { isInternalURL } from '@plone/volto/helpers';
8
7
  import { MaybeWrap } from '@plone/volto/components';
9
8
  import { UniversalLink } from '@plone/volto/components';
10
9
  import cx from 'classnames';
@@ -18,20 +17,14 @@ const messages = defineMessages({
18
17
  },
19
18
  });
20
19
 
21
- const DefaultImage = (props) => <img {...props} alt={props.alt || ''} />;
22
-
23
20
  const TeaserDefaultTemplate = (props) => {
24
21
  const { className, data, isEditMode } = props;
25
22
  const intl = useIntl();
26
23
  const href = data.href?.[0];
27
24
  const image = data.preview_image?.[0];
28
- const align = data?.styles?.align;
29
25
 
30
- const hasImageComponent = config.getComponent('Image').component;
31
- const Image = config.getComponent('Image').component || DefaultImage;
26
+ const Image = config.getComponent('Image').component;
32
27
  const { openExternalLinkInNewTab } = config.settings;
33
- const defaultImageSrc =
34
- href && flattenToAppURL(getTeaserImageURL({ href, image, align }));
35
28
 
36
29
  return (
37
30
  <div className={cx('block teaser', className)}>
@@ -60,9 +53,11 @@ const TeaserDefaultTemplate = (props) => {
60
53
  {(href.hasPreviewImage || href.image_field || image) && (
61
54
  <div className="image-wrapper">
62
55
  <Image
63
- src={hasImageComponent ? href : defaultImageSrc}
56
+ item={image || href}
57
+ imageField={image ? image.image_field : href.image_field}
64
58
  alt=""
65
59
  loading="lazy"
60
+ responsive={true}
66
61
  />
67
62
  </div>
68
63
  )}
@@ -101,3 +101,8 @@ export const TeaserSchema = ({ intl }) => {
101
101
 
102
102
  return schema;
103
103
  };
104
+
105
+ export const gridTeaserDisableStylingSchema = ({ schema, formData, intl }) => {
106
+ schema.fieldsets = schema.fieldsets.filter((item) => item.id !== 'styling');
107
+ return schema;
108
+ };
@@ -3,19 +3,29 @@
3
3
  * @module volto-slate/blocks/Title/TitleBlockView
4
4
  */
5
5
 
6
- import React from 'react';
6
+ import React, { useMemo } from 'react';
7
7
  import PropTypes from 'prop-types';
8
+ import Slugger from 'github-slugger';
9
+ import { renderLinkElement } from '@plone/volto-slate/editor/render';
8
10
 
9
11
  /**
10
12
  * View title block component.
11
13
  * @class View
12
14
  * @extends Component
13
15
  */
14
- const TitleBlockView = ({ properties, metadata }) => {
16
+ const TitleBlockView = ({ properties, metadata, id, children }) => {
17
+ let attr = { id };
18
+ const title = (properties || metadata)['title'];
19
+ const slug = Slugger.slug(title);
20
+ attr.id = slug || id;
21
+ const LinkedTitle = useMemo(() => renderLinkElement('h1'), []);
15
22
  return (
16
- <h1 className="documentFirstHeading">
17
- {(metadata || properties)['title'] || ''}
18
- </h1>
23
+ <LinkedTitle
24
+ mode="view"
25
+ children={title ?? children}
26
+ attributes={attr}
27
+ className={'documentFirstHeading'}
28
+ />
19
29
  );
20
30
  };
21
31
 
@@ -1,10 +1,25 @@
1
1
  import React from 'react';
2
2
  import renderer from 'react-test-renderer';
3
+ import configureStore from 'redux-mock-store';
4
+ import { Provider } from 'react-intl-redux';
5
+ import { MemoryRouter } from 'react-router-dom';
3
6
  import View from './View';
4
7
 
8
+ const mockStore = configureStore();
9
+
5
10
  test('renders a view title component', () => {
11
+ const store = mockStore({
12
+ intl: {
13
+ locale: 'en',
14
+ messages: {},
15
+ },
16
+ });
6
17
  const component = renderer.create(
7
- <View properties={{ title: 'My Title' }} />,
18
+ <Provider store={store}>
19
+ <MemoryRouter>
20
+ <View properties={{ title: 'My Title' }} id="a123" />
21
+ </MemoryRouter>
22
+ </Provider>,
8
23
  );
9
24
  const json = component.toJSON();
10
25
  expect(json).toMatchSnapshot();
@@ -10,7 +10,7 @@ const TableOfContentsSchema = ({ data }) => {
10
10
  fields: [
11
11
  'title',
12
12
  'hide_title',
13
- ...(variation === 'default' ? ['ordered'] : []),
13
+ ...(variation === 'default' ? ['ordered'] : ['sticky']),
14
14
  'levels',
15
15
  ],
16
16
  },
@@ -39,6 +39,10 @@ const TableOfContentsSchema = ({ data }) => {
39
39
  title: 'Ordered',
40
40
  type: 'boolean',
41
41
  },
42
+ sticky: {
43
+ title: 'Sticky',
44
+ type: 'boolean',
45
+ },
42
46
  },
43
47
  required: [],
44
48
  };
@@ -56,7 +56,14 @@ const View = (props) => {
56
56
  const items = [];
57
57
  if (!level || !levels.includes(level)) return;
58
58
  tocEntriesLayout.push(id);
59
- tocEntries[id] = { level, title: title || block.plaintext, items, id };
59
+ tocEntries[id] = {
60
+ level,
61
+ title: title || block.plaintext,
62
+ items,
63
+ id,
64
+ override_toc: block.override_toc,
65
+ plaintext: block.plaintext,
66
+ };
60
67
  if (level < rootLevel) {
61
68
  rootLevel = level;
62
69
  }