io-sanita-theme 2.22.1 → 2.23.1
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 +23 -0
- package/package.json +1 -1
- package/src/components/Blocks/Alert/alert.scss +11 -0
- package/src/components/BrandText/BrandText.jsx +11 -1
- package/src/components/Cards/CardFile/CardFile.jsx +11 -10
- package/src/config/components.ts +65 -0
- package/src/config/ioSanitaConfig.js +11 -14
- package/src/config/utilities.ts +18 -0
- package/src/customizations/volto/components/manage/Sidebar/ObjectBrowserBody.jsx +629 -0
- package/src/customizations/volto/components/manage/UniversalLink/UniversalLink.jsx +5 -3
- package/src/customizations/volto/components/theme/Footer/Footer.jsx +1 -1
- package/src/customizations/volto/components/theme/View/FileView.jsx +6 -4
- package/src/helpers/Files/DownloadFileFormat.jsx +3 -5
- package/src/theme/io-sanita/_main.scss +7 -0
- package/src/theme/io-sanita/components/layout/_logo.scss +10 -0
- package/src/theme/io-sanita/subsites/io-sanita-theme/_common.scss +7 -0
- package/src/theme/main.scss +1 -0
- package/tsconfig.json +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.23.1](https://github.com/RedTurtle/io-sanita-theme/compare/2.23.0...2.23.1) (2026-03-20)
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
* alert block height in view mode ([#120](https://github.com/RedTurtle/io-sanita-theme/issues/120)) ([58c969e](https://github.com/RedTurtle/io-sanita-theme/commit/58c969eda0d02e76b6535863eda7230db2808b14))
|
|
8
|
+
* uridecode filename ([#119](https://github.com/RedTurtle/io-sanita-theme/issues/119)) ([eea9e68](https://github.com/RedTurtle/io-sanita-theme/commit/eea9e681fc78a29ee50167191e1f558984da5bda))
|
|
9
|
+
|
|
10
|
+
### Changes
|
|
11
|
+
|
|
12
|
+
* make codebase more flexible for addons ([#116](https://github.com/RedTurtle/io-sanita-theme/issues/116)) ([3e1b034](https://github.com/RedTurtle/io-sanita-theme/commit/3e1b034df7b0556ec6cb94cf7f29b0d92dba9788))
|
|
13
|
+
|
|
14
|
+
## [2.23.0](https://github.com/RedTurtle/io-sanita-theme/compare/2.22.1...2.23.0) (2026-03-19)
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
* title in header could be hidden by settings panel and in that case loggo has width auto ([#117](https://github.com/RedTurtle/io-sanita-theme/issues/117)) ([7a7af44](https://github.com/RedTurtle/io-sanita-theme/commit/7a7af4419b61d359db2d5ff26ea1f004e1991d95))
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* download/file and display-file/file url ([bacf5cf](https://github.com/RedTurtle/io-sanita-theme/commit/bacf5cf1bbc7c90b6ec16d236dea6122fdc9f60c))
|
|
23
|
+
* link color in callout dark ([#118](https://github.com/RedTurtle/io-sanita-theme/issues/118)) ([9bbbf02](https://github.com/RedTurtle/io-sanita-theme/commit/9bbbf0249a158f2dd2b03e05dee15eab0271c0aa))
|
|
24
|
+
* objectbrowser searchableType now consider selectableTypes ([c2976b5](https://github.com/RedTurtle/io-sanita-theme/commit/c2976b5bbc71a41e87f6c13163e5498275109a3d))
|
|
25
|
+
|
|
3
26
|
## [2.22.1](https://github.com/RedTurtle/io-sanita-theme/compare/2.21.10...2.22.1) (2025-11-03)
|
|
4
27
|
|
|
5
28
|
### Features
|
package/package.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import cx from 'classnames';
|
|
3
|
+
import { useSelector } from 'react-redux';
|
|
3
4
|
import { useIntl } from 'react-intl';
|
|
4
5
|
import { SiteProperty } from 'volto-site-settings';
|
|
5
6
|
import { getSiteProperty } from 'io-sanita-theme/helpers';
|
|
6
7
|
|
|
7
8
|
const BrandText = ({ mobile = false, getParent = false }) => {
|
|
9
|
+
const subsite = useSelector((state) => state.subsite?.data);
|
|
8
10
|
const intl = useIntl();
|
|
9
11
|
let title = SiteProperty({
|
|
10
12
|
property: 'site_title',
|
|
@@ -27,8 +29,16 @@ const BrandText = ({ mobile = false, getParent = false }) => {
|
|
|
27
29
|
</React.Fragment>
|
|
28
30
|
));
|
|
29
31
|
|
|
32
|
+
const hide_title = SiteProperty({
|
|
33
|
+
property: 'hide_title',
|
|
34
|
+
defaultValue: false,
|
|
35
|
+
getValue: true,
|
|
36
|
+
getParent: false,
|
|
37
|
+
});
|
|
38
|
+
const visuallyHidden = !subsite && hide_title;
|
|
39
|
+
|
|
30
40
|
return (
|
|
31
|
-
<div className=
|
|
41
|
+
<div className={cx('it-brand-text', { 'visually-hidden': visuallyHidden })}>
|
|
32
42
|
{title && <div className="it-brand-title">{title}</div>}
|
|
33
43
|
{description && (
|
|
34
44
|
<div
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import './cardFile.scss';
|
|
2
|
+
|
|
3
|
+
import { Card, CardBody, CardText, CardTitle } from 'design-react-kit';
|
|
4
|
+
import { defineMessages, useIntl } from 'react-intl';
|
|
5
|
+
|
|
6
|
+
import { FileIcon } from 'io-sanita-theme/helpers';
|
|
7
|
+
import { Icon } from 'io-sanita-theme/components';
|
|
8
|
+
import Module from 'io-sanita-theme/components/Cards/CardFile/Module';
|
|
1
9
|
/*
|
|
2
10
|
Usa la Card File per
|
|
3
11
|
- allegare documenti o
|
|
@@ -21,17 +29,10 @@ In caso di download diretto, è suggerito l’utilizzo dell’icona con il forma
|
|
|
21
29
|
In caso di collegamento a una pagina foglia di tipo documento, è suggerito l’utilizzo di un’icona file generica e non è necessario specificare estensione e peso nel titolo.
|
|
22
30
|
*/
|
|
23
31
|
import React from 'react';
|
|
24
|
-
import
|
|
32
|
+
import UniversalLink from '@plone/volto/components/manage/UniversalLink/UniversalLink';
|
|
25
33
|
import cx from 'classnames';
|
|
26
|
-
import { Card, CardBody, CardTitle, CardText } from 'design-react-kit';
|
|
27
34
|
import { flattenToAppURL } from '@plone/volto/helpers/Url/Url';
|
|
28
|
-
import UniversalLink from '@plone/volto/components/manage/UniversalLink/UniversalLink';
|
|
29
35
|
import { viewDate } from 'io-sanita-theme/helpers';
|
|
30
|
-
import { Icon } from 'io-sanita-theme/components';
|
|
31
|
-
import { FileIcon } from 'io-sanita-theme/helpers';
|
|
32
|
-
import Module from 'io-sanita-theme/components/Cards/CardFile/Module';
|
|
33
|
-
|
|
34
|
-
import './cardFile.scss';
|
|
35
36
|
|
|
36
37
|
const messages = defineMessages({
|
|
37
38
|
attachment: {
|
|
@@ -154,12 +155,12 @@ export const CardFile = ({
|
|
|
154
155
|
<a
|
|
155
156
|
className="card-title-link flex-grow-1 pe-4"
|
|
156
157
|
href={flattenToAppURL(file.download)}
|
|
157
|
-
title={file.filename}
|
|
158
|
+
title={decodeURI(file.filename)}
|
|
158
159
|
target={pdfFile ? '_blank' : '_self'}
|
|
159
160
|
rel={pdfFile ? 'noopener noreferrer' : ''}
|
|
160
161
|
data-element={titleDataElement}
|
|
161
162
|
>
|
|
162
|
-
{file.filename}
|
|
163
|
+
{decodeURI(file.filename)}
|
|
163
164
|
</a>
|
|
164
165
|
)}
|
|
165
166
|
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { ConfigType } from '@plone/registry';
|
|
2
|
+
import { FeedbackForm } from 'volto-feedback-italia';
|
|
3
|
+
import Icon from 'io-sanita-theme/components/Icon/Icon';
|
|
4
|
+
import ImageWithErrors from 'io-sanita-theme/components/ImageWithErrors/ImageWithErrors';
|
|
5
|
+
import Pagination from 'io-sanita-theme/components/Pagination/Pagination';
|
|
6
|
+
import RichTextSection from 'io-sanita-theme/helpers/RichText/RichTextSection';
|
|
7
|
+
import SelectInput from 'io-sanita-theme/components/Widgets/SelectInput/SelectInput';
|
|
8
|
+
import SideMenu from 'io-sanita-theme/components/View/commons/SideMenu/SideMenu';
|
|
9
|
+
import SiteSettingsExtras from 'io-sanita-theme/components/AppExtras/SiteSettingsExtras';
|
|
10
|
+
import SkipToMainContent from 'io-sanita-theme/components/View/commons/SkipToMainContent';
|
|
11
|
+
|
|
12
|
+
export default function applyComponentConfig(config: ConfigType) {
|
|
13
|
+
config.components = {
|
|
14
|
+
...config.components,
|
|
15
|
+
BlockExtraTags: { component: () => null },
|
|
16
|
+
Image: {
|
|
17
|
+
// @ts-expect-error
|
|
18
|
+
component: ImageWithErrors,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
config.registerComponent({
|
|
23
|
+
name: 'FeedbackForm',
|
|
24
|
+
component: FeedbackForm,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
config.registerComponent({
|
|
28
|
+
name: 'Icon',
|
|
29
|
+
component: Icon,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
config.registerComponent({
|
|
33
|
+
name: 'Pagination',
|
|
34
|
+
component: Pagination,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
config.registerComponent({
|
|
38
|
+
name: 'RichTextSection',
|
|
39
|
+
// @ts-expect-error
|
|
40
|
+
component: RichTextSection,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
config.registerComponent({
|
|
44
|
+
name: 'SelectInput',
|
|
45
|
+
component: SelectInput,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
config.registerComponent({
|
|
49
|
+
name: 'SideMenu',
|
|
50
|
+
// @ts-expect-error
|
|
51
|
+
component: SideMenu,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
config.registerComponent({
|
|
55
|
+
name: 'SiteSettingsExtras',
|
|
56
|
+
component: SiteSettingsExtras,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
config.registerComponent({
|
|
60
|
+
name: 'SkipToMainContent',
|
|
61
|
+
component: SkipToMainContent,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return config;
|
|
65
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import loadable from '@loadable/component';
|
|
2
2
|
import { defineMessages } from 'react-intl';
|
|
3
|
-
import ImageWithErrors from 'io-sanita-theme/components/ImageWithErrors/ImageWithErrors';
|
|
4
3
|
|
|
5
4
|
import menuSVG from '@plone/volto/icons/menu.svg';
|
|
6
5
|
import menuAltSVG from '@plone/volto/icons/menu-alt.svg';
|
|
@@ -43,6 +42,7 @@ import TrackFocus from 'io-sanita-theme/components/AppExtras/TrackFocus';
|
|
|
43
42
|
import HandleAnchor from 'io-sanita-theme/components/AppExtras/HandleAnchor';
|
|
44
43
|
import SiteSettingsExtras from 'io-sanita-theme/components/AppExtras/SiteSettingsExtras';
|
|
45
44
|
import GenericAppExtras from 'io-sanita-theme/components/AppExtras/GenericAppExtras';
|
|
45
|
+
import applyComponentConfig from 'io-sanita-theme/config/components';
|
|
46
46
|
import { loadables as IoSanitaLoadables } from 'io-sanita-theme/config/loadables';
|
|
47
47
|
import { registerIOSanitaValidators } from 'io-sanita-theme/config/validators';
|
|
48
48
|
|
|
@@ -58,6 +58,7 @@ import applyIoSanitaViews from 'io-sanita-theme/config/views/views';
|
|
|
58
58
|
import { SideMenu } from 'io-sanita-theme/components/View/commons';
|
|
59
59
|
import AggregationPage from 'io-sanita-theme/components/View/AggregationPage/AggregationPage';
|
|
60
60
|
import { applyFarmacieConfig } from './farmacie';
|
|
61
|
+
import applyUtilitiesConfig from 'io-sanita-theme/config/utilities';
|
|
61
62
|
|
|
62
63
|
import getIoSanitaWidgets from 'io-sanita-theme/config/widgets/widgets';
|
|
63
64
|
import { component } from 'design-react-kit/dist/types/Icon/assets/ItAndroidSquare';
|
|
@@ -321,19 +322,10 @@ export default function applyConfig(config) {
|
|
|
321
322
|
removeListingVariation(config, 'summary'); // removes summary volto template, because is unused
|
|
322
323
|
removeListingVariation(config, 'imageGallery'); // removes imageGallery volto template, because we have our photoGallery template
|
|
323
324
|
|
|
324
|
-
//
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
Image: {
|
|
329
|
-
component: ImageWithErrors,
|
|
330
|
-
},
|
|
331
|
-
};
|
|
332
|
-
|
|
333
|
-
config.registerComponent({
|
|
334
|
-
name: 'SiteSettingsExtras',
|
|
335
|
-
component: SiteSettingsExtras,
|
|
336
|
-
});
|
|
325
|
+
// /******************************************************************************
|
|
326
|
+
// * COMPONENTS
|
|
327
|
+
// ******************************************************************************/
|
|
328
|
+
applyComponentConfig(config);
|
|
337
329
|
|
|
338
330
|
// REDUCERS
|
|
339
331
|
config.addonReducers = {
|
|
@@ -341,6 +333,11 @@ export default function applyConfig(config) {
|
|
|
341
333
|
...reducers,
|
|
342
334
|
};
|
|
343
335
|
|
|
336
|
+
// /******************************************************************************
|
|
337
|
+
// * UTILITIES
|
|
338
|
+
// ******************************************************************************/
|
|
339
|
+
applyUtilitiesConfig(config);
|
|
340
|
+
|
|
344
341
|
// VALIDATORS
|
|
345
342
|
registerIOSanitaValidators(config);
|
|
346
343
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ConfigType } from '@plone/registry';
|
|
2
|
+
import { viewDate } from 'io-sanita-theme/helpers';
|
|
3
|
+
|
|
4
|
+
export default function applyUtilitiesConfig(config: ConfigType) {
|
|
5
|
+
config.registerUtility({
|
|
6
|
+
name: 'viewDate',
|
|
7
|
+
type: 'italia-viewDate',
|
|
8
|
+
method: viewDate,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
return config;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
declare module '@plone/types' {
|
|
15
|
+
interface UtilityTypeMap {
|
|
16
|
+
'italia-viewDate': typeof viewDate;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,629 @@
|
|
|
1
|
+
/* CUSTOMIZATIONS:
|
|
2
|
+
- backport of https://github.com/plone/volto/pull/7915
|
|
3
|
+
*/
|
|
4
|
+
import React, { Component } from 'react';
|
|
5
|
+
import PropTypes from 'prop-types';
|
|
6
|
+
import { compose } from 'redux';
|
|
7
|
+
import { connect } from 'react-redux';
|
|
8
|
+
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
|
|
9
|
+
import { Input, Segment, Breadcrumb } from 'semantic-ui-react';
|
|
10
|
+
|
|
11
|
+
import join from 'lodash/join';
|
|
12
|
+
|
|
13
|
+
// These absolute imports (without using the corresponding centralized index.js) are required
|
|
14
|
+
// to cut circular import problems, this file should never use them. This is because of
|
|
15
|
+
// the very nature of the functionality of the component and its relationship with others
|
|
16
|
+
import { searchContent } from '@plone/volto/actions/search/search';
|
|
17
|
+
import Icon from '@plone/volto/components/theme/Icon/Icon';
|
|
18
|
+
import { flattenToAppURL, isInternalURL } from '@plone/volto/helpers/Url/Url';
|
|
19
|
+
import config from '@plone/volto/registry';
|
|
20
|
+
|
|
21
|
+
import backSVG from '@plone/volto/icons/back.svg';
|
|
22
|
+
import folderSVG from '@plone/volto/icons/folder.svg';
|
|
23
|
+
import clearSVG from '@plone/volto/icons/clear.svg';
|
|
24
|
+
import searchSVG from '@plone/volto/icons/zoom.svg';
|
|
25
|
+
import linkSVG from '@plone/volto/icons/link.svg';
|
|
26
|
+
import homeSVG from '@plone/volto/icons/home.svg';
|
|
27
|
+
import iconsSVG from '@plone/volto/icons/apps.svg';
|
|
28
|
+
import listSVG from '@plone/volto/icons/list-bullet.svg';
|
|
29
|
+
|
|
30
|
+
import ObjectBrowserNav from '@plone/volto/components/manage/Sidebar/ObjectBrowserNav';
|
|
31
|
+
|
|
32
|
+
const messages = defineMessages({
|
|
33
|
+
SearchInputPlaceholder: {
|
|
34
|
+
id: 'Search content',
|
|
35
|
+
defaultMessage: 'Search content',
|
|
36
|
+
},
|
|
37
|
+
SelectedItems: {
|
|
38
|
+
id: 'Selected items',
|
|
39
|
+
defaultMessage: 'Selected items',
|
|
40
|
+
},
|
|
41
|
+
back: {
|
|
42
|
+
id: 'Back',
|
|
43
|
+
defaultMessage: 'Back',
|
|
44
|
+
},
|
|
45
|
+
search: {
|
|
46
|
+
id: 'Search SVG',
|
|
47
|
+
defaultMessage: 'Search SVG',
|
|
48
|
+
},
|
|
49
|
+
iconView: {
|
|
50
|
+
id: 'Icon View',
|
|
51
|
+
defaultMessage: 'Icon View',
|
|
52
|
+
},
|
|
53
|
+
listView: {
|
|
54
|
+
id: 'List View',
|
|
55
|
+
defaultMessage: 'List View',
|
|
56
|
+
},
|
|
57
|
+
home: {
|
|
58
|
+
id: 'Home',
|
|
59
|
+
defaultMessage: 'Home',
|
|
60
|
+
},
|
|
61
|
+
of: { id: 'Selected items - x of y', defaultMessage: 'of' },
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
function getParentURL(url) {
|
|
65
|
+
return flattenToAppURL(`${join(url.split('/').slice(0, -1), '/')}`) || '/';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* ObjectBrowserBody container class.
|
|
70
|
+
* @class ObjectBrowserBody
|
|
71
|
+
* @extends Component
|
|
72
|
+
*/
|
|
73
|
+
class ObjectBrowserBody extends Component {
|
|
74
|
+
/**
|
|
75
|
+
* Property types.
|
|
76
|
+
* @property {Object} propTypes Property types.
|
|
77
|
+
* @static
|
|
78
|
+
*/
|
|
79
|
+
static propTypes = {
|
|
80
|
+
block: PropTypes.string.isRequired,
|
|
81
|
+
mode: PropTypes.string.isRequired,
|
|
82
|
+
data: PropTypes.any.isRequired,
|
|
83
|
+
searchSubrequests: PropTypes.objectOf(PropTypes.any).isRequired,
|
|
84
|
+
searchContent: PropTypes.func.isRequired,
|
|
85
|
+
closeObjectBrowser: PropTypes.func.isRequired,
|
|
86
|
+
onChangeBlock: PropTypes.func.isRequired,
|
|
87
|
+
onSelectItem: PropTypes.func,
|
|
88
|
+
dataName: PropTypes.string,
|
|
89
|
+
maximumSelectionSize: PropTypes.number,
|
|
90
|
+
contextURL: PropTypes.string,
|
|
91
|
+
searchableTypes: PropTypes.arrayOf(PropTypes.string),
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Default properties.
|
|
96
|
+
* @property {Object} defaultProps Default properties.
|
|
97
|
+
* @static
|
|
98
|
+
*/
|
|
99
|
+
static defaultProps = {
|
|
100
|
+
image: '',
|
|
101
|
+
href: '',
|
|
102
|
+
onSelectItem: null,
|
|
103
|
+
dataName: null,
|
|
104
|
+
selectableTypes: [],
|
|
105
|
+
searchableTypes: null,
|
|
106
|
+
maximumSelectionSize: null,
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Constructor
|
|
111
|
+
* @method constructor
|
|
112
|
+
* @param {Object} props Component properties
|
|
113
|
+
* @constructs WysiwygEditor
|
|
114
|
+
*/
|
|
115
|
+
constructor(props) {
|
|
116
|
+
super(props);
|
|
117
|
+
this.state = {
|
|
118
|
+
currentFolder:
|
|
119
|
+
this.props.mode === 'multiple' ? '/' : this.props.contextURL || '/',
|
|
120
|
+
currentImageFolder:
|
|
121
|
+
this.props.mode === 'multiple'
|
|
122
|
+
? '/'
|
|
123
|
+
: this.props.mode === 'image' && this.props.data?.url
|
|
124
|
+
? getParentURL(this.props.data.url)
|
|
125
|
+
: '/',
|
|
126
|
+
currentLinkFolder:
|
|
127
|
+
this.props.mode === 'multiple'
|
|
128
|
+
? '/'
|
|
129
|
+
: this.props.mode === 'link' && this.props.data?.href
|
|
130
|
+
? getParentURL(this.props.data.href)
|
|
131
|
+
: '/',
|
|
132
|
+
parentFolder: '',
|
|
133
|
+
selectedImage:
|
|
134
|
+
this.props.mode === 'multiple'
|
|
135
|
+
? ''
|
|
136
|
+
: this.props.mode === 'image' && this.props.data?.url
|
|
137
|
+
? flattenToAppURL(this.props.data.url)
|
|
138
|
+
: '',
|
|
139
|
+
selectedHref:
|
|
140
|
+
this.props.mode === 'multiple'
|
|
141
|
+
? ''
|
|
142
|
+
: this.props.mode === 'link' && this.props.data?.href
|
|
143
|
+
? flattenToAppURL(this.props.data.href)
|
|
144
|
+
: '',
|
|
145
|
+
showSearchInput: false,
|
|
146
|
+
// In image mode, the searchable types default to the image types which
|
|
147
|
+
// can be overridden with the property if specified.
|
|
148
|
+
// If selectableTypes are passed, the searchableTypes are the selectableTypes
|
|
149
|
+
searchableTypes:
|
|
150
|
+
this.props.mode === 'image'
|
|
151
|
+
? this.props.searchableTypes || config.settings.imageObjects
|
|
152
|
+
: [
|
|
153
|
+
...(this.props.searchableTypes ?? []),
|
|
154
|
+
...(this.props.selectableTypes ?? []),
|
|
155
|
+
],
|
|
156
|
+
view: this.props.mode === 'image' ? 'icons' : 'list',
|
|
157
|
+
};
|
|
158
|
+
this.searchInputRef = React.createRef();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Component did mount
|
|
163
|
+
* @method componentDidMount
|
|
164
|
+
* @returns {undefined}
|
|
165
|
+
*/
|
|
166
|
+
componentDidMount() {
|
|
167
|
+
this.initialSearch(this.props.mode);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
initialSearch = (mode) => {
|
|
171
|
+
const currentSelected =
|
|
172
|
+
mode === 'multiple'
|
|
173
|
+
? ''
|
|
174
|
+
: mode === 'image'
|
|
175
|
+
? this.state.selectedImage
|
|
176
|
+
: this.state.selectedHref;
|
|
177
|
+
if (currentSelected && isInternalURL(currentSelected)) {
|
|
178
|
+
this.props.searchContent(
|
|
179
|
+
getParentURL(currentSelected),
|
|
180
|
+
{
|
|
181
|
+
'path.depth': 1,
|
|
182
|
+
sort_on: 'getObjPositionInParent',
|
|
183
|
+
metadata_fields: '_all',
|
|
184
|
+
b_size: 1000,
|
|
185
|
+
},
|
|
186
|
+
`${this.props.block}-${mode}`,
|
|
187
|
+
);
|
|
188
|
+
} else {
|
|
189
|
+
this.props.searchContent(
|
|
190
|
+
this.state.currentFolder,
|
|
191
|
+
{
|
|
192
|
+
'path.depth': 1,
|
|
193
|
+
sort_on: 'getObjPositionInParent',
|
|
194
|
+
metadata_fields: '_all',
|
|
195
|
+
b_size: 1000,
|
|
196
|
+
},
|
|
197
|
+
`${this.props.block}-${mode}`,
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
navigateTo = (id) => {
|
|
203
|
+
this.props.searchContent(
|
|
204
|
+
id,
|
|
205
|
+
{
|
|
206
|
+
'path.depth': 1,
|
|
207
|
+
sort_on: 'getObjPositionInParent',
|
|
208
|
+
metadata_fields: '_all',
|
|
209
|
+
b_size: 1000,
|
|
210
|
+
},
|
|
211
|
+
`${this.props.block}-${this.props.mode}`,
|
|
212
|
+
);
|
|
213
|
+
const parent = `${join(id.split('/').slice(0, -1), '/')}` || '/';
|
|
214
|
+
this.setState(() => ({
|
|
215
|
+
parentFolder: parent,
|
|
216
|
+
currentFolder: id || '/',
|
|
217
|
+
}));
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
toggleSearchInput = () =>
|
|
221
|
+
this.setState(
|
|
222
|
+
(prevState) => ({
|
|
223
|
+
showSearchInput: !prevState.showSearchInput,
|
|
224
|
+
}),
|
|
225
|
+
() => {
|
|
226
|
+
if (this.searchInputRef?.current) {
|
|
227
|
+
this.searchInputRef.current.focus();
|
|
228
|
+
} else {
|
|
229
|
+
this.props.searchContent(
|
|
230
|
+
this.state.currentFolder,
|
|
231
|
+
{
|
|
232
|
+
'path.depth': 1,
|
|
233
|
+
sort_on: 'getObjPositionInParent',
|
|
234
|
+
metadata_fields: '_all',
|
|
235
|
+
b_size: 1000,
|
|
236
|
+
},
|
|
237
|
+
`${this.props.block}-${this.props.mode}`,
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
toggleView = () =>
|
|
244
|
+
this.setState((prevState) => ({
|
|
245
|
+
view: prevState.view === 'icons' ? 'list' : 'icons',
|
|
246
|
+
}));
|
|
247
|
+
|
|
248
|
+
onSearch = (e) => {
|
|
249
|
+
const text = flattenToAppURL(e.target.value);
|
|
250
|
+
if (text.startsWith('/')) {
|
|
251
|
+
this.setState({ currentFolder: text });
|
|
252
|
+
this.props.searchContent(
|
|
253
|
+
text,
|
|
254
|
+
{
|
|
255
|
+
'path.depth': 1,
|
|
256
|
+
sort_on: 'getObjPositionInParent',
|
|
257
|
+
metadata_fields: '_all',
|
|
258
|
+
portal_type: this.state.searchableTypes,
|
|
259
|
+
},
|
|
260
|
+
`${this.props.block}-${this.props.mode}`,
|
|
261
|
+
);
|
|
262
|
+
} else {
|
|
263
|
+
text.length > 2
|
|
264
|
+
? this.props.searchContent(
|
|
265
|
+
'/',
|
|
266
|
+
{
|
|
267
|
+
SearchableText: `${text}*`,
|
|
268
|
+
metadata_fields: '_all',
|
|
269
|
+
portal_type: this.state.searchableTypes,
|
|
270
|
+
},
|
|
271
|
+
`${this.props.block}-${this.props.mode}`,
|
|
272
|
+
)
|
|
273
|
+
: this.props.searchContent(
|
|
274
|
+
'/',
|
|
275
|
+
{
|
|
276
|
+
'path.depth': 1,
|
|
277
|
+
sort_on: 'getObjPositionInParent',
|
|
278
|
+
metadata_fields: '_all',
|
|
279
|
+
portal_type: this.state.searchableTypes,
|
|
280
|
+
},
|
|
281
|
+
`${this.props.block}-${this.props.mode}`,
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
onSelectItem = (item) => {
|
|
287
|
+
const url = item['@id'];
|
|
288
|
+
const { block, data, mode, dataName, onChangeBlock } = this.props;
|
|
289
|
+
|
|
290
|
+
const updateState = (mode) => {
|
|
291
|
+
switch (mode) {
|
|
292
|
+
case 'image':
|
|
293
|
+
this.setState({
|
|
294
|
+
selectedImage: url,
|
|
295
|
+
currentImageFolder: getParentURL(url),
|
|
296
|
+
});
|
|
297
|
+
break;
|
|
298
|
+
case 'link':
|
|
299
|
+
this.setState({
|
|
300
|
+
selectedHref: url,
|
|
301
|
+
currentLinkFolder: getParentURL(url),
|
|
302
|
+
});
|
|
303
|
+
break;
|
|
304
|
+
default:
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
if (dataName) {
|
|
310
|
+
onChangeBlock(block, {
|
|
311
|
+
...data,
|
|
312
|
+
[dataName]: url,
|
|
313
|
+
});
|
|
314
|
+
} else if (this.props.onSelectItem) {
|
|
315
|
+
this.props.onSelectItem(url, item);
|
|
316
|
+
} else if (mode === 'image') {
|
|
317
|
+
onChangeBlock(block, {
|
|
318
|
+
...data,
|
|
319
|
+
url: flattenToAppURL(item.getURL),
|
|
320
|
+
alt: '',
|
|
321
|
+
});
|
|
322
|
+
} else if (mode === 'link') {
|
|
323
|
+
onChangeBlock(block, {
|
|
324
|
+
...data,
|
|
325
|
+
href: flattenToAppURL(url),
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
updateState(mode);
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
onChangeBlockData = (key, value) => {
|
|
332
|
+
this.props.onChangeBlock(this.props.block, {
|
|
333
|
+
...this.props.data,
|
|
334
|
+
[key]: value,
|
|
335
|
+
});
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
isSelectable = (item) => {
|
|
339
|
+
const { maximumSelectionSize, data, mode, selectableTypes } = this.props;
|
|
340
|
+
if (
|
|
341
|
+
maximumSelectionSize &&
|
|
342
|
+
data &&
|
|
343
|
+
mode === 'multiple' &&
|
|
344
|
+
maximumSelectionSize <= data.length
|
|
345
|
+
)
|
|
346
|
+
// The item should actually be selectable, but only for removing it from already selected items list.
|
|
347
|
+
// handleClickOnItem will handle the deselection logic.
|
|
348
|
+
// The item is not selectable if we reached/exceeded maximumSelectionSize and is not already selected.
|
|
349
|
+
return data.some(
|
|
350
|
+
(d) => flattenToAppURL(d['@id']) === flattenToAppURL(item['@id']),
|
|
351
|
+
);
|
|
352
|
+
return selectableTypes.length > 0
|
|
353
|
+
? selectableTypes.indexOf(item['@type']) >= 0
|
|
354
|
+
: true;
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
handleClickOnItem = (item) => {
|
|
358
|
+
if (this.props.mode === 'image') {
|
|
359
|
+
if (item.is_folderish) {
|
|
360
|
+
this.navigateTo(item['@id']);
|
|
361
|
+
}
|
|
362
|
+
if (config.settings.imageObjects.includes(item['@type'])) {
|
|
363
|
+
this.onSelectItem(item);
|
|
364
|
+
}
|
|
365
|
+
} else {
|
|
366
|
+
if (this.isSelectable(item)) {
|
|
367
|
+
if (
|
|
368
|
+
!this.props.maximumSelectionSize ||
|
|
369
|
+
this.props.mode === 'multiple' ||
|
|
370
|
+
!this.props.data ||
|
|
371
|
+
this.props.data.length <= this.props.maximumSelectionSize
|
|
372
|
+
) {
|
|
373
|
+
let isDeselecting;
|
|
374
|
+
if (this.props.mode === 'multiple' && Array.isArray(this.props.data))
|
|
375
|
+
isDeselecting = this.props.data.some(
|
|
376
|
+
(d) => flattenToAppURL(d['@id']) === flattenToAppURL(item['@id']),
|
|
377
|
+
);
|
|
378
|
+
this.onSelectItem(item);
|
|
379
|
+
let length = this.props.data ? this.props.data.length : 0;
|
|
380
|
+
let stopSelecting = this.props.mode !== 'multiple';
|
|
381
|
+
if (isDeselecting && !stopSelecting)
|
|
382
|
+
stopSelecting =
|
|
383
|
+
this.props.maximumSelectionSize > 0 &&
|
|
384
|
+
length - 1 >= this.props.maximumSelectionSize;
|
|
385
|
+
else
|
|
386
|
+
stopSelecting =
|
|
387
|
+
this.props.maximumSelectionSize > 0 &&
|
|
388
|
+
length + 1 >= this.props.maximumSelectionSize;
|
|
389
|
+
if (stopSelecting) {
|
|
390
|
+
this.props.closeObjectBrowser();
|
|
391
|
+
}
|
|
392
|
+
} else {
|
|
393
|
+
this.props.closeObjectBrowser();
|
|
394
|
+
}
|
|
395
|
+
} else {
|
|
396
|
+
this.navigateTo(item['@id']);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
handleDoubleClickOnItem = (item) => {
|
|
402
|
+
if (this.props.mode === 'image') {
|
|
403
|
+
if (item.is_folderish) {
|
|
404
|
+
this.navigateTo(item['@id']);
|
|
405
|
+
}
|
|
406
|
+
if (config.settings.imageObjects.includes(item['@type'])) {
|
|
407
|
+
this.onSelectItem(item);
|
|
408
|
+
this.props.closeObjectBrowser();
|
|
409
|
+
}
|
|
410
|
+
} else {
|
|
411
|
+
if (this.isSelectable(item)) {
|
|
412
|
+
if (this.props.data.length < this.props.maximumSelectionSize) {
|
|
413
|
+
this.onSelectItem(item);
|
|
414
|
+
}
|
|
415
|
+
this.props.closeObjectBrowser();
|
|
416
|
+
} else {
|
|
417
|
+
this.navigateTo(item['@id']);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Render method.
|
|
424
|
+
* @method render
|
|
425
|
+
* @returns {string} Markup for the component.
|
|
426
|
+
*/
|
|
427
|
+
render() {
|
|
428
|
+
return (
|
|
429
|
+
<Segment.Group raised className="object-browser">
|
|
430
|
+
<header className="header pulled">
|
|
431
|
+
<div className="vertical divider" />
|
|
432
|
+
{this.state.showSearchInput ? (
|
|
433
|
+
<Input
|
|
434
|
+
className="search"
|
|
435
|
+
ref={this.searchInputRef}
|
|
436
|
+
onChange={this.onSearch}
|
|
437
|
+
placeholder={this.props.intl.formatMessage(
|
|
438
|
+
messages.SearchInputPlaceholder,
|
|
439
|
+
)}
|
|
440
|
+
/>
|
|
441
|
+
) : (
|
|
442
|
+
<>
|
|
443
|
+
{this.state.currentFolder === '/' ? (
|
|
444
|
+
<>
|
|
445
|
+
{this.props.mode === 'image' ? (
|
|
446
|
+
<Icon name={folderSVG} size="24px" />
|
|
447
|
+
) : (
|
|
448
|
+
<Icon name={linkSVG} size="24px" />
|
|
449
|
+
)}
|
|
450
|
+
</>
|
|
451
|
+
) : (
|
|
452
|
+
<button
|
|
453
|
+
aria-label={this.props.intl.formatMessage(messages.back)}
|
|
454
|
+
onClick={() => this.navigateTo(this.state.parentFolder)}
|
|
455
|
+
>
|
|
456
|
+
<Icon name={backSVG} size="24px" />
|
|
457
|
+
</button>
|
|
458
|
+
)}
|
|
459
|
+
{this.props.mode === 'image' ? (
|
|
460
|
+
<h2>
|
|
461
|
+
<FormattedMessage
|
|
462
|
+
id="Choose Image"
|
|
463
|
+
defaultMessage="Choose Image"
|
|
464
|
+
/>
|
|
465
|
+
</h2>
|
|
466
|
+
) : (
|
|
467
|
+
<h2>
|
|
468
|
+
<FormattedMessage
|
|
469
|
+
id="Choose Target"
|
|
470
|
+
defaultMessage="Choose Target"
|
|
471
|
+
/>
|
|
472
|
+
</h2>
|
|
473
|
+
)}
|
|
474
|
+
</>
|
|
475
|
+
)}
|
|
476
|
+
|
|
477
|
+
<button
|
|
478
|
+
aria-label={this.props.intl.formatMessage(messages.search)}
|
|
479
|
+
onClick={this.toggleSearchInput}
|
|
480
|
+
>
|
|
481
|
+
<Icon name={searchSVG} size="24px" />
|
|
482
|
+
</button>
|
|
483
|
+
<button className="clearSVG" onClick={this.props.closeObjectBrowser}>
|
|
484
|
+
<Icon name={clearSVG} size="24px" />
|
|
485
|
+
</button>
|
|
486
|
+
</header>
|
|
487
|
+
<Segment secondary className="breadcrumbs" vertical>
|
|
488
|
+
{this.props.mode === 'image' && (
|
|
489
|
+
<button
|
|
490
|
+
onClick={this.toggleView}
|
|
491
|
+
className="mode-switch"
|
|
492
|
+
aria-label={this.props.intl.formatMessage(
|
|
493
|
+
this.state.view === 'list'
|
|
494
|
+
? messages.iconView
|
|
495
|
+
: messages.listView,
|
|
496
|
+
)}
|
|
497
|
+
>
|
|
498
|
+
<Icon
|
|
499
|
+
name={this.state.view === 'list' ? iconsSVG : listSVG}
|
|
500
|
+
size="24px"
|
|
501
|
+
className="mode-switch"
|
|
502
|
+
title={this.props.intl.formatMessage(
|
|
503
|
+
this.state.view === 'list'
|
|
504
|
+
? messages.iconView
|
|
505
|
+
: messages.listView,
|
|
506
|
+
)}
|
|
507
|
+
/>
|
|
508
|
+
</button>
|
|
509
|
+
)}
|
|
510
|
+
{!this.state.showSearchInput ? (
|
|
511
|
+
<Breadcrumb>
|
|
512
|
+
{this.state.currentFolder !== '/' ? (
|
|
513
|
+
this.state.currentFolder
|
|
514
|
+
.split('/')
|
|
515
|
+
.map((item, index, items) => {
|
|
516
|
+
return (
|
|
517
|
+
<React.Fragment key={`divider-${item}-${index}`}>
|
|
518
|
+
{index === 0 ? (
|
|
519
|
+
<Breadcrumb.Section
|
|
520
|
+
onClick={() => this.navigateTo('/')}
|
|
521
|
+
role="button"
|
|
522
|
+
aria-label={this.props.intl.formatMessage(
|
|
523
|
+
messages.home,
|
|
524
|
+
)}
|
|
525
|
+
>
|
|
526
|
+
<Icon
|
|
527
|
+
className="home-icon"
|
|
528
|
+
name={homeSVG}
|
|
529
|
+
size="18px"
|
|
530
|
+
title={this.props.intl.formatMessage(
|
|
531
|
+
messages.home,
|
|
532
|
+
)}
|
|
533
|
+
/>
|
|
534
|
+
</Breadcrumb.Section>
|
|
535
|
+
) : (
|
|
536
|
+
<>
|
|
537
|
+
<Breadcrumb.Divider key={`divider-${item.url}`} />
|
|
538
|
+
<Breadcrumb.Section
|
|
539
|
+
role="button"
|
|
540
|
+
onClick={() =>
|
|
541
|
+
this.navigateTo(
|
|
542
|
+
items.slice(0, index + 1).join('/'),
|
|
543
|
+
)
|
|
544
|
+
}
|
|
545
|
+
>
|
|
546
|
+
{item}
|
|
547
|
+
</Breadcrumb.Section>
|
|
548
|
+
</>
|
|
549
|
+
)}
|
|
550
|
+
</React.Fragment>
|
|
551
|
+
);
|
|
552
|
+
})
|
|
553
|
+
) : (
|
|
554
|
+
<Breadcrumb.Section
|
|
555
|
+
onClick={() => this.navigateTo('/')}
|
|
556
|
+
aria-label={this.props.intl.formatMessage(messages.home)}
|
|
557
|
+
>
|
|
558
|
+
<Icon
|
|
559
|
+
className="home-icon"
|
|
560
|
+
name={homeSVG}
|
|
561
|
+
role="button"
|
|
562
|
+
size="18px"
|
|
563
|
+
title={this.props.intl.formatMessage(messages.home)}
|
|
564
|
+
/>
|
|
565
|
+
</Breadcrumb.Section>
|
|
566
|
+
)}
|
|
567
|
+
</Breadcrumb>
|
|
568
|
+
) : (
|
|
569
|
+
<div className="searchResults">
|
|
570
|
+
<FormattedMessage
|
|
571
|
+
id="Search results"
|
|
572
|
+
defaultMessage="Search results"
|
|
573
|
+
/>
|
|
574
|
+
</div>
|
|
575
|
+
)}
|
|
576
|
+
</Segment>
|
|
577
|
+
{this.props.mode === 'multiple' && (
|
|
578
|
+
<Segment className="infos">
|
|
579
|
+
{this.props.intl.formatMessage(messages.SelectedItems)}:{' '}
|
|
580
|
+
{this.props.data?.length}
|
|
581
|
+
{this.props.maximumSelectionSize > 0 && (
|
|
582
|
+
<>
|
|
583
|
+
{' '}
|
|
584
|
+
{this.props.intl.formatMessage(messages.of)}{' '}
|
|
585
|
+
{this.props.maximumSelectionSize}
|
|
586
|
+
</>
|
|
587
|
+
)}
|
|
588
|
+
</Segment>
|
|
589
|
+
)}
|
|
590
|
+
<ObjectBrowserNav
|
|
591
|
+
currentSearchResults={
|
|
592
|
+
this.props.searchSubrequests[
|
|
593
|
+
`${this.props.block}-${this.props.mode}`
|
|
594
|
+
]
|
|
595
|
+
}
|
|
596
|
+
selected={
|
|
597
|
+
this.props.mode === 'multiple'
|
|
598
|
+
? this.props.data
|
|
599
|
+
: [
|
|
600
|
+
{
|
|
601
|
+
'@id':
|
|
602
|
+
this.props.mode === 'image'
|
|
603
|
+
? this.state.selectedImage
|
|
604
|
+
: this.state.selectedHref,
|
|
605
|
+
},
|
|
606
|
+
]
|
|
607
|
+
}
|
|
608
|
+
handleClickOnItem={this.handleClickOnItem}
|
|
609
|
+
handleDoubleClickOnItem={this.handleDoubleClickOnItem}
|
|
610
|
+
mode={this.props.mode}
|
|
611
|
+
view={this.state.view}
|
|
612
|
+
navigateTo={this.navigateTo}
|
|
613
|
+
isSelectable={this.isSelectable}
|
|
614
|
+
/>
|
|
615
|
+
</Segment.Group>
|
|
616
|
+
);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
export default compose(
|
|
621
|
+
injectIntl,
|
|
622
|
+
connect(
|
|
623
|
+
(state) => ({
|
|
624
|
+
searchSubrequests: state.search.subrequests,
|
|
625
|
+
lang: state.intl.locale,
|
|
626
|
+
}),
|
|
627
|
+
{ searchContent },
|
|
628
|
+
),
|
|
629
|
+
)(ObjectBrowserBody);
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* CUSTOMIZATIONS:
|
|
6
6
|
* - aggiunto icona per link esterni
|
|
7
7
|
* - aggiunto title informativo per link esterni
|
|
8
|
-
* - aggiunta condizione per non avere un duplicato di @@download/file
|
|
8
|
+
* - aggiunta condizione per non avere un duplicato di @@download/file e @@display-file/file, perchè su io-sanità arriva dal BE anche per gli anonimi
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import React from 'react';
|
|
@@ -64,7 +64,8 @@ const UniversalLink = ({
|
|
|
64
64
|
if (
|
|
65
65
|
!token &&
|
|
66
66
|
config.settings.downloadableObjects.includes(item['@type']) &&
|
|
67
|
-
url.indexOf('@@download') < 0 //aggiunta condizione per non avere un duplicato di @@download/file, perchè su io-sanità arriva dal BE anche per gli anonimi
|
|
67
|
+
url.indexOf('@@download') < 0 && //aggiunta condizione per non avere un duplicato di @@download/file, perchè su io-sanità arriva dal BE anche per gli anonimi
|
|
68
|
+
url.indexOf('@@display-file') < 0 //aggiunta condizione per non avere sia @@download/file che @@display-file/file, perchè su io-sanità arriva dal BE anche per gli anonimi
|
|
68
69
|
) {
|
|
69
70
|
url = `${url}/@@download/file`;
|
|
70
71
|
}
|
|
@@ -72,7 +73,8 @@ const UniversalLink = ({
|
|
|
72
73
|
if (
|
|
73
74
|
!token &&
|
|
74
75
|
config.settings.viewableInBrowserObjects.includes(item['@type']) &&
|
|
75
|
-
url.indexOf('@@display-file') < 0 //aggiunta condizione per non avere un duplicato di @@display-file/file, perchè su io-sanità arriva dal BE anche per gli anonimi
|
|
76
|
+
url.indexOf('@@display-file') < 0 && //aggiunta condizione per non avere un duplicato di @@display-file/file, perchè su io-sanità arriva dal BE anche per gli anonimi
|
|
77
|
+
url.indexOf('@@download') < 0 //aggiunta condizione per non avere sia @@download/file che @@display-file/file, perchè su io-sanità arriva dal BE anche per gli anonimi
|
|
76
78
|
) {
|
|
77
79
|
url = `${url}/@@display-file/file`;
|
|
78
80
|
}
|
|
@@ -32,7 +32,7 @@ const Footer = ({ intl }) => {
|
|
|
32
32
|
contentType = null;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
const
|
|
35
|
+
const noFeedbackFormFor =
|
|
36
36
|
config.settings.siteProperties.noFeedbackFormFor || [];
|
|
37
37
|
const showFeedbackForm = config.settings.siteProperties
|
|
38
38
|
?.enableNoFeedbackFormFor
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
* File view component.
|
|
3
3
|
* @module components/theme/View/FileView
|
|
4
4
|
* - changed card layout
|
|
5
|
+
* - decodeURI filename
|
|
5
6
|
*/
|
|
6
7
|
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
import { Container, Row, Col } from 'design-react-kit';
|
|
8
|
+
import { Col, Container, Row } from 'design-react-kit';
|
|
9
|
+
|
|
10
10
|
import { DownloadFileFormat } from 'io-sanita-theme/helpers';
|
|
11
|
+
import PropTypes from 'prop-types';
|
|
12
|
+
import React from 'react';
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* File view component class.
|
|
@@ -35,7 +37,7 @@ const FileView = ({ content }) => (
|
|
|
35
37
|
<Col className="card-wrapper card-teaser-wrapper">
|
|
36
38
|
<div className="genericcard card card-teaser shadow p-4 mt-3 rounded">
|
|
37
39
|
<div className="card-body">
|
|
38
|
-
<h2 className="card-title h5">{content.file.filename}</h2>
|
|
40
|
+
<h2 className="card-title h5">{decodeURI(content.file.filename)}</h2>
|
|
39
41
|
<DownloadFileFormat file={content.file} iconSize="2x" />
|
|
40
42
|
</div>
|
|
41
43
|
</div>
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FileIcon } from 'io-sanita-theme/helpers';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
|
|
3
|
+
import React from 'react';
|
|
4
4
|
import { flattenToAppURL } from '@plone/volto/helpers/Url/Url';
|
|
5
5
|
|
|
6
|
-
import { FileIcon } from 'io-sanita-theme/helpers';
|
|
7
|
-
|
|
8
6
|
const DownloadFileFormat = ({
|
|
9
7
|
file,
|
|
10
8
|
formatsize = '2x',
|
|
@@ -16,7 +14,7 @@ const DownloadFileFormat = ({
|
|
|
16
14
|
return file ? (
|
|
17
15
|
<a
|
|
18
16
|
href={flattenToAppURL(file.download)}
|
|
19
|
-
title={file.filename}
|
|
17
|
+
title={decodeURI(file.filename)}
|
|
20
18
|
className={className}
|
|
21
19
|
target={pdfFile ? '_blank' : '_self'}
|
|
22
20
|
rel={pdfFile ? 'noopener noreferrer' : ''}
|
package/src/theme/main.scss
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
@import './io-sanita/addons/volto-data-grid-widget';
|
|
19
19
|
@import './io-sanita/addons/volto-form-block';
|
|
20
20
|
@import './io-sanita/components/layout/navbar';
|
|
21
|
+
@import './io-sanita/components/layout/logo';
|
|
21
22
|
@import './io-sanita/components/layout/mobileMenu';
|
|
22
23
|
@import './io-sanita/components/layout/tertiaryMenu';
|
|
23
24
|
@import './io-sanita/components/layout/footer';
|