diff --git a/src/components/manage/Blocks/FolderContentsBlock/AddLinkForm.jsx b/src/components/manage/Blocks/FolderContentsBlock/AddLinkForm.jsx
new file mode 100644
index 0000000..a753e7d
--- /dev/null
+++ b/src/components/manage/Blocks/FolderContentsBlock/AddLinkForm.jsx
@@ -0,0 +1,201 @@
+/**
+ * Add link form.
+ * @module components/manage/AnchorPlugin/components/LinkButton/AddLinkForm
+ */
+
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { compose } from 'redux';
+import unionClassNames from 'union-class-names';
+import { connect } from 'react-redux';
+import { map } from 'lodash';
+import { doesNodeContainClick } from 'semantic-ui-react/dist/commonjs/lib';
+import { defineMessages, injectIntl } from 'react-intl';
+
+import { resetSearchContent, searchContent } from '@plone/volto/actions';
+import URLUtils from '@plone/volto/components/manage/AnchorPlugin/utils/URLUtils';
+
+const messages = defineMessages({
+ placeholder: {
+ id: 'Enter URL or title',
+ defaultMessage: 'Enter URL or title',
+ },
+});
+
+class AddLinkForm extends Component {
+ static propTypes = {
+ onOverrideContent: PropTypes.func.isRequired,
+ resetSearchContent: PropTypes.func.isRequired,
+ searchContent: PropTypes.func.isRequired,
+ search: PropTypes.arrayOf(
+ PropTypes.shape({
+ '@id': PropTypes.string,
+ '@type': PropTypes.string,
+ title: PropTypes.string,
+ description: PropTypes.string,
+ }),
+ ),
+ };
+
+ static defaultProps = {
+ placeholder: 'Enter URL or search for content',
+ search: [],
+ };
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ value: '',
+ isInvalid: false,
+ };
+ this.onRef = this.onRef.bind(this);
+ this.onChange = this.onChange.bind(this);
+ this.onKeyDown = this.onKeyDown.bind(this);
+ this.onSubmit = this.onSubmit.bind(this);
+ }
+
+ componentDidMount() {
+ this.input.focus();
+ this.props.resetSearchContent();
+ document.addEventListener('mousedown', this.handleClickOutside, false);
+ }
+
+ componentWillUnmount() {
+ document.removeEventListener('mousedown', this.handleClickOutside, false);
+ }
+
+ handleClickOutside = e => {
+ if (
+ this.linkFormContainer.current &&
+ doesNodeContainClick(this.linkFormContainer.current, e)
+ )
+ return;
+ this.onClose();
+ };
+
+ onClose() {
+ return true;
+ }
+
+ onRef(node) {
+ this.input = node;
+ }
+
+ linkFormContainer = React.createRef();
+
+ onChange({ target: { value } }) {
+ const nextState = { value };
+ if (this.state.isInvalid && URLUtils.isUrl(URLUtils.normalizeUrl(value))) {
+ nextState.isInvalid = false;
+ }
+ this.setState(nextState);
+ if (value && value !== '') {
+ this.props.searchContent('', {
+ Title: `*${value}*`,
+ });
+ } else {
+ this.props.resetSearchContent();
+ }
+ }
+
+ onSelectItem = (e, item) => {
+ e.preventDefault();
+ const itemToSave = {
+ key: item['@id'],
+ text: item.title,
+ value: item['@id'],
+ description: item.description,
+ external: true,
+ };
+ this.setState({
+ value: itemToSave,
+ isInvalid: false,
+ });
+ this.props.onAddLink(itemToSave)
+ this.props.resetSearchContent();
+ this.input.blur();
+ this.onClose();
+ };
+
+ onKeyDown(e) {
+ if (e.key === 'Enter') {
+ e.preventDefault();
+ this.onSubmit();
+ } else if (e.key === 'Escape') {
+ e.preventDefault();
+ this.onClose();
+ }
+ }
+
+ onSubmit() {
+ let { value: url } = this.state;
+ if (!URLUtils.isMail(URLUtils.normaliseMail(url))) {
+ url = URLUtils.normalizeUrl(url);
+ if (!URLUtils.isUrl(url)) {
+ this.setState({ isInvalid: true });
+ return;
+ }
+ } else {
+ url = URLUtils.normaliseMail(url);
+ }
+ this.input.blur();
+ this.onClose();
+ }
+
+ render() {
+ const { value, isInvalid } = this.state;
+ console.log('link value', this.props);
+ return (
+
+
+
+ {map(this.props.search, item => (
+ -
+
+
+ ))}
+
+
+ );
+ }
+}
+
+export default compose(
+ injectIntl,
+ connect(
+ state => ({
+ search: state.search.items,
+ }),
+ { resetSearchContent, searchContent },
+ ),
+)(AddLinkForm);
diff --git a/src/components/manage/Blocks/FolderContentsBlock/Edit.jsx b/src/components/manage/Blocks/FolderContentsBlock/Edit.jsx
new file mode 100644
index 0000000..5ed2bb7
--- /dev/null
+++ b/src/components/manage/Blocks/FolderContentsBlock/Edit.jsx
@@ -0,0 +1,117 @@
+/**
+ * Edit map block.
+ * @module components/manage/Blocks/Maps/Edit
+ */
+
+import React, { Component } from 'react';
+import PropTypes, { array } from 'prop-types';
+import { Link } from 'react-router-dom';
+import { Icon, SidebarPortal, TextWidget } from '@plone/volto/components';
+import { Dropdown, Segment, Checkbox, Input, Button } from 'semantic-ui-react';
+import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+import { Card } from 'semantic-ui-react';
+import { settings } from '~/config';
+import AddLinkForm from './AddLinkForm';
+
+function removeDuplicates(myArr, prop) {
+ return myArr.filter((obj, pos, arr) => {
+ return arr.map(mapObj => mapObj[prop]).indexOf(obj[prop]) === pos;
+ });
+}
+
+class Edit extends Component {
+ /**
+ * Property types.
+ * @property {Object} propTypes Property types.
+ * @static
+ */
+ static propTypes = {
+ selected: PropTypes.bool.isRequired,
+ block: PropTypes.string.isRequired,
+ index: PropTypes.number.isRequired,
+ data: PropTypes.objectOf(PropTypes.any).isRequired,
+ pathname: PropTypes.string.isRequired,
+ onChangeBlock: PropTypes.func.isRequired,
+ onSelectBlock: PropTypes.func.isRequired,
+ onDeleteBlock: PropTypes.func.isRequired,
+ onFocusPreviousBlock: PropTypes.func.isRequired,
+ onFocusNextBlock: PropTypes.func.isRequired,
+ };
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ link: this.props.data.link
+ };
+ }
+ getPath(url) {
+ if (!url) return '';
+ return url
+ .replace(settings.apiPath, '')
+ .replace(settings.internalApiPath, '');
+ }
+
+
+ componentDidUpdate(prevProps, prevState) {
+ if (JSON.stringify(prevState) !== JSON.stringify(this.state)) {
+ this.onChangeData();
+ }
+ }
+
+ onChangeData() {
+ this.props.onChangeBlock(this.props.block, {
+ ...this.props.data,
+ link: this.state.link,
+ });
+ }
+
+
+ onAddLink = link => {
+ this.setState({
+ link
+ });
+ };
+
+ render() {
+ console.log('link instate', this.state.link)
+ return (
+
+ {this.state.link && (
+
e.preventDefault} to={this.getPath(this.state.link.value)}>
+
+ {this.state.link.text}
+
+
+ {this.state.link.description &&
{this.state.link.description}
}
+
+
+
+ ) || 'Select a page from sidebar'}
+
+
+
+
+
+
+
+ {/* */}
+
+
+
+
+ );
+ }
+}
+
+export default injectIntl(Edit);
diff --git a/src/components/manage/Blocks/FolderContentsBlock/View.jsx b/src/components/manage/Blocks/FolderContentsBlock/View.jsx
new file mode 100644
index 0000000..785ec6f
--- /dev/null
+++ b/src/components/manage/Blocks/FolderContentsBlock/View.jsx
@@ -0,0 +1,67 @@
+/**
+ * Edit map block.
+ * @module components/manage/Blocks/Maps/Edit
+ */
+
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { Link } from 'react-router-dom';
+import { injectIntl } from 'react-intl';
+import { settings } from '~/config';
+import { BodyClass } from '@plone/volto/helpers';
+
+import { Button } from 'semantic-ui-react';
+// import AddLinkForm from './AddLinkForm';
+
+function removeDuplicates(myArr, prop) {
+ return myArr.filter((obj, pos, arr) => {
+ return arr.map(mapObj => mapObj[prop]).indexOf(obj[prop]) === pos;
+ });
+}
+
+class View extends Component {
+ /**
+ * Property types.
+ * @property {Object} propTypes Property types.
+ * @static
+ */
+ static propTypes = {
+ data: PropTypes.objectOf(PropTypes.any).isRequired,
+ // pathname: PropTypes.string.isRequired,
+ };
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ link: this.props.data.link
+ };
+ }
+ getPath(url) {
+ if (!url) return '';
+ return url
+ .replace(settings.apiPath, '')
+ .replace(settings.internalApiPath, '');
+ }
+
+
+ render() {
+ return (
+
+ {this.state.link && (
+
e.preventDefault} to={this.getPath(this.state.link.value)}>
+
+ {this.state.link.text}
+
+
+
+ {this.state.link.description &&
{this.state.link.description}
}
+
+
+
+ ) || 'Select a page from sidebar'}
+
+ );
+ }
+}
+
+export default injectIntl(View);
diff --git a/src/localconfig.js b/src/localconfig.js
index ca0c86c..4f7ecfb 100644
--- a/src/localconfig.js
+++ b/src/localconfig.js
@@ -6,6 +6,9 @@ import TabsChildView from '~/components/theme/View/TabsChildView';
import DetailedLinkView from '~/components/manage/Blocks/DetailedLink/View';
import DetailedLinkEdit from '~/components/manage/Blocks/DetailedLink/Edit';
+import FolderContentsBlockView from '~/components/manage/Blocks/FolderContentsBlock/View';
+import FolderContentsBlockEdit from '~/components/manage/Blocks/FolderContentsBlock/Edit';
+
const applyConfig = config => {
console.log('config', config)
config.views = {
@@ -31,6 +34,15 @@ console.log('config', config)
icon: config.blocks.blocksConfig.text.icon,
};
+
+ config.blocks.blocksConfig.folder_contents = {
+ id: 'folder_contents',
+ group: 'custom_addons',
+ title: 'Folder Contents',
+ view: FolderContentsBlockView,
+ edit: FolderContentsBlockEdit,
+ icon: config.blocks.blocksConfig.text.icon,
+ };
return config;
}