)}
>
diff --git a/src/components/ItaliaTheme/manage/Widgets/CanaleDigitaleWidget.jsx b/src/components/ItaliaTheme/manage/Widgets/CanaleDigitaleWidget.jsx
index ec1c84a20..d08a2fba4 100644
--- a/src/components/ItaliaTheme/manage/Widgets/CanaleDigitaleWidget.jsx
+++ b/src/components/ItaliaTheme/manage/Widgets/CanaleDigitaleWidget.jsx
@@ -3,6 +3,7 @@ import { Form } from 'semantic-ui-react';
import config from '@plone/volto/registry';
import cx from 'classnames';
import { defineMessages, injectIntl } from 'react-intl';
+import { UniversalLink } from '@plone/volto/components';
const messages = defineMessages({
canale_digitale_widget_title: {
@@ -33,14 +34,9 @@ const CanaleDigitaleWidget = (props) => {
Sezione obbligatoria ai fini della validazione AGID secondo i seguenti{' '}
-
+
termini
-
+
. Per confermare la presenza in pagina della relativa sezione devono
essere presenti:
diff --git a/src/config/RichTextEditor/Plugins/AnchorPlugin/components/Link/index.jsx b/src/config/RichTextEditor/Plugins/AnchorPlugin/components/Link/index.jsx
index 21f908ab6..7f25620e3 100644
--- a/src/config/RichTextEditor/Plugins/AnchorPlugin/components/Link/index.jsx
+++ b/src/config/RichTextEditor/Plugins/AnchorPlugin/components/Link/index.jsx
@@ -2,6 +2,7 @@
* Questo รจ il link quando viene mostrato dentro l'editor nelle viste di edit
* Customizzato
* - aggiunto data-element
+ * - aggiunto icona link esterno
*/
import React from 'react';
import PropTypes from 'prop-types';
@@ -19,7 +20,6 @@ const Link = ({ children, className, entityKey, getEditorState, target }) => {
const entity = getEditorState().getCurrentContent().getEntity(entityKey);
const entityData = entity ? entity.get('data') : undefined;
const href = (entityData && entityData.url) || undefined;
-
return (
{
data-element={entityData.dataElement || entityData['data-element']}
>
{children}
+ {!isInternalURL(href) && }
);
};
diff --git a/src/config/italiaConfig.js b/src/config/italiaConfig.js
index af841d8d5..274d4d613 100644
--- a/src/config/italiaConfig.js
+++ b/src/config/italiaConfig.js
@@ -236,6 +236,7 @@ export default function applyConfig(voltoConfig) {
enableVoltoFormBlockCaptcha: true,
splitMegamenuColumns: true, //se impostato a false, non spezza le colonne con intestazioni nel megamenu
footerNavigationDepth: 2, //valori possibili: [1,2]. Se impostato ad 1 non verranno mostrati nel footer i link agli elementi contenuti nelle sezioni di primo livello.
+ markSpecialLinks: true, // se impostato a false, non marca con icona i link esterni
},
apiExpanders: [
...config.settings.apiExpanders,
diff --git a/src/customizations/volto/components/manage/UniversalLink/UniversalLink.jsx b/src/customizations/volto/components/manage/UniversalLink/UniversalLink.jsx
new file mode 100644
index 000000000..a24fa605a
--- /dev/null
+++ b/src/customizations/volto/components/manage/UniversalLink/UniversalLink.jsx
@@ -0,0 +1,170 @@
+/*
+ * UniversalLink
+ * @module components/UniversalLink
+ *
+ * CUSTOMIZATIONS:
+ * - aggiunto icona per link esterni
+ */
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import { HashLink as Link } from 'react-router-hash-link';
+import { useSelector } from 'react-redux';
+import {
+ flattenToAppURL,
+ isInternalURL,
+ URLUtils,
+} from '@plone/volto/helpers/Url/Url';
+import { matchPath } from 'react-router';
+import { Icon } from 'design-comuni-plone-theme/components/ItaliaTheme';
+
+import config from '@plone/volto/registry';
+
+const UniversalLink = ({
+ href,
+ item = null,
+ openLinkInNewTab,
+ download = false,
+ children,
+ className = null,
+ title = null,
+ ...props
+}) => {
+ const token = useSelector((state) => state.userSession?.token);
+
+ let url = href;
+ if (!href && item) {
+ if (!item['@id']) {
+ // eslint-disable-next-line no-console
+ console.error(
+ 'Invalid item passed to UniversalLink',
+ item,
+ props,
+ children,
+ );
+ url = '#';
+ } else {
+ //case: generic item
+ url = flattenToAppURL(item['@id']);
+
+ //case: item like a Link
+ let remoteUrl = item.remoteUrl || item.getRemoteUrl;
+ if (!token && remoteUrl) {
+ url = remoteUrl;
+ }
+
+ //case: item of type 'File'
+ if (
+ !token &&
+ config.settings.downloadableObjects.includes(item['@type'])
+ ) {
+ url = `${url}/@@download/file`;
+ }
+
+ if (
+ !token &&
+ config.settings.viewableInBrowserObjects.includes(item['@type'])
+ ) {
+ url = `${url}/@@display-file/file`;
+ }
+ }
+ }
+
+ const isBlacklisted =
+ (config.settings.externalRoutes ?? []).find((route) =>
+ matchPath(flattenToAppURL(url), route.match),
+ )?.length > 0;
+ const isExternal = !isInternalURL(url) || isBlacklisted;
+ const isDownload = (!isExternal && url.includes('@@download')) || download;
+ const isDisplayFile =
+ (!isExternal && url.includes('@@display-file')) || false;
+
+ const checkedURL = URLUtils.checkAndNormalizeUrl(url);
+
+ url = checkedURL.url;
+ let tag = (
+
+ {children}
+
+ );
+
+ if (isExternal) {
+ tag = (
+
+ {children}
+ {config.settings.siteProperties.markSpecialLinks && (
+
+ )}
+
+ );
+ } else if (isDownload) {
+ tag = (
+
+ {children}
+
+ );
+ } else if (isDisplayFile) {
+ tag = (
+
+ {children}
+
+ );
+ }
+ return tag;
+};
+
+UniversalLink.propTypes = {
+ href: PropTypes.string,
+ openLinkInNewTab: PropTypes.bool,
+ download: PropTypes.bool,
+ className: PropTypes.string,
+ title: PropTypes.string,
+ item: PropTypes.shape({
+ '@id': PropTypes.string.isRequired,
+ remoteUrl: PropTypes.string, //of plone @type 'Link'
+ }),
+ children: PropTypes.oneOfType([
+ PropTypes.arrayOf(PropTypes.node),
+ PropTypes.node,
+ ]),
+};
+
+export default UniversalLink;
diff --git a/src/theme/ItaliaTheme/Blocks/_ctaBlock.scss b/src/theme/ItaliaTheme/Blocks/_ctaBlock.scss
index 105aab21c..816df337c 100644
--- a/src/theme/ItaliaTheme/Blocks/_ctaBlock.scss
+++ b/src/theme/ItaliaTheme/Blocks/_ctaBlock.scss
@@ -41,6 +41,12 @@
&:focus {
background: $secondary-text;
color: $secondary;
+ .external-link {
+ fill: #004080 !important;
+ }
+ }
+ .external-link {
+ fill: $external-link-fill-buttons !important;
}
}
diff --git a/src/theme/ItaliaTheme/_common.scss b/src/theme/ItaliaTheme/_common.scss
index 8e4d5f3d2..3719404d9 100644
--- a/src/theme/ItaliaTheme/_common.scss
+++ b/src/theme/ItaliaTheme/_common.scss
@@ -43,4 +43,21 @@
}
}
}
+ .btn-primary,
+ .btn-secondary,
+ .btn-tertiary,
+ .draftjs-buttons {
+ .external-link {
+ fill: $external-link-fill-buttons !important;
+ }
+ }
+ .external-link {
+ fill: $link-color !important;
+ &:hover {
+ fill: #004080 !important;
+ }
+ }
+ .it-footer-small-prints-list .external-link {
+ fill: $external-link-fill-subfooter !important;
+ }
}
diff --git a/src/theme/_site-variables.scss b/src/theme/_site-variables.scss
index a3aed43c9..41be84e38 100644
--- a/src/theme/_site-variables.scss
+++ b/src/theme/_site-variables.scss
@@ -45,6 +45,8 @@ $primary-a0: hsl($primary-h, 62%, 97%) !default;
$argument-icon-color: $tertiary !default;
$argument-icon-bg: #f5f6f7 !default;
+$external-link-fill-buttons: $tertiary-text !default;
+$external-link-fill-subfooter: $tertiary-text !default;
// $dvt-header-center-max-height: 166px;
// $header-center-max-height-mob: 80px;