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 ( +
+
+ + + + + + + +
+ +
+ ); + } +} + +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'} + + +
+

Detailed Link

+
+ +
+ +
+
+ + {/* */} + +
+
+
+ ); + } +} + +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; }