react-draft-wysiwyg
Version:
A wysiwyg on top of DraftJS.
266 lines (248 loc) • 7.97 kB
JavaScript
/* @flow */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { stopPropagation } from '../../../utils/common';
import { getFirstIcon } from '../../../utils/toolbar';
import Option from '../../../components/Option';
import { Dropdown, DropdownOption } from '../../../components/Dropdown';
import './styles.css';
class LayoutComponent extends Component {
static propTypes = {
expanded: PropTypes.bool,
doExpand: PropTypes.func,
doCollapse: PropTypes.func,
onExpandEvent: PropTypes.func,
config: PropTypes.object,
onChange: PropTypes.func,
currentState: PropTypes.object,
translations: PropTypes.object,
};
state: Object = {
showModal: false,
linkTarget: '',
linkTitle: '',
linkTargetOption: this.props.config.defaultTargetOption,
};
componentWillReceiveProps(props) {
if (this.props.expanded && !props.expanded) {
this.setState({
showModal: false,
linkTarget: '',
linkTitle: '',
linkTargetOption: this.props.config.defaultTargetOption,
});
}
}
removeLink: Function = (): void => {
const { onChange } = this.props;
onChange('unlink');
};
addLink: Function = (): void => {
const { onChange } = this.props;
const { linkTitle, linkTarget, linkTargetOption } = this.state;
onChange('link', linkTitle, linkTarget, linkTargetOption);
};
updateValue: Function = (event: Object): void => {
this.setState({
[`${event.target.name}`]: event.target.value,
});
};
updateTargetOption: Function = (event: Object): void => {
this.setState({
linkTargetOption: event.target.checked ? '_blank' : '_self',
});
};
hideModal: Function = (): void => {
this.setState({
showModal: false,
});
};
signalExpandShowModal = () => {
const { onExpandEvent, currentState: { link, selectionText } } = this.props;
const { linkTargetOption } = this.state;
onExpandEvent();
this.setState({
showModal: true,
linkTarget: (link && link.target) || '',
linkTargetOption: (link && link.targetOption) || linkTargetOption,
linkTitle: (link && link.title) || selectionText,
});
}
forceExpandAndShowModal: Function = (): void => {
const { doExpand, currentState: { link, selectionText } } = this.props;
const { linkTargetOption } = this.state;
doExpand();
this.setState({
showModal: true,
linkTarget: link && link.target,
linkTargetOption: (link && link.targetOption) || linkTargetOption,
linkTitle: (link && link.title) || selectionText,
});
}
renderAddLinkModal() {
const { config: { popupClassName }, doCollapse, translations } = this.props;
const { linkTitle, linkTarget, linkTargetOption } = this.state;
return (
<div
className={classNames('rdw-link-modal', popupClassName)}
onClick={stopPropagation}
>
<label className="rdw-link-modal-label" htmlFor="linkTitle">
{translations['components.controls.link.linkTitle']}
</label>
<input
id="linkTitle"
className="rdw-link-modal-input"
onChange={this.updateValue}
onBlur={this.updateValue}
name="linkTitle"
value={linkTitle}
/>
<label className="rdw-link-modal-label" htmlFor="linkTarget">
{translations['components.controls.link.linkTarget']}
</label>
<input
id="linkTarget"
className="rdw-link-modal-input"
onChange={this.updateValue}
onBlur={this.updateValue}
name="linkTarget"
value={linkTarget}
/>
<label className="rdw-link-modal-target-option" htmlFor="openLinkInNewWindow">
<input
id="openLinkInNewWindow"
type="checkbox"
defaultChecked={linkTargetOption === '_blank'}
value="_blank"
onChange={this.updateTargetOption}
/>
<span>{translations['components.controls.link.linkTargetOption']}</span>
</label>
<span className="rdw-link-modal-buttonsection">
<button
className="rdw-link-modal-btn"
onClick={this.addLink}
disabled={!linkTarget || !linkTitle}
>
{translations['generic.add']}
</button>
<button
className="rdw-link-modal-btn"
onClick={doCollapse}
>
{translations['generic.cancel']}
</button>
</span>
</div>
);
}
renderInFlatList(): Object {
const {
config: { options, link, unlink, className },
currentState,
expanded,
translations,
} = this.props;
const { showModal } = this.state;
return (
<div className={classNames('rdw-link-wrapper', className)} aria-label="rdw-link-control">
{options.indexOf('link') >= 0 && <Option
value="unordered-list-item"
className={classNames(link.className)}
onClick={this.signalExpandShowModal}
aria-haspopup="true"
aria-expanded={showModal}
title={link.title || translations['components.controls.link.link']}
>
<img
src={link.icon}
alt=""
/>
</Option>}
{options.indexOf('unlink') >= 0 && <Option
disabled={!currentState.link}
value="ordered-list-item"
className={classNames(unlink.className)}
onClick={this.removeLink}
title={unlink.title || translations['components.controls.link.unlink']}
>
<img
src={unlink.icon}
alt=""
/>
</Option>}
{expanded && showModal ? this.renderAddLinkModal() : undefined}
</div>
);
}
renderInDropDown(): Object {
const {
expanded,
onExpandEvent,
doCollapse,
doExpand,
onChange,
config,
currentState,
translations,
} = this.props;
const { options, link, unlink, className, dropdownClassName, title } = config;
const { showModal } = this.state;
return (
<div
className="rdw-link-wrapper"
aria-haspopup="true"
aria-label="rdw-link-control"
aria-expanded={expanded}
title={title}
>
<Dropdown
className={classNames('rdw-link-dropdown', className)}
optionWrapperClassName={classNames(dropdownClassName)}
onChange={onChange}
expanded={expanded && !showModal}
doExpand={doExpand}
doCollapse={doCollapse}
onExpandEvent={onExpandEvent}
>
<img
src={getFirstIcon(config)}
alt=""
/>
{options.indexOf('link') >= 0 && <DropdownOption
onClick={this.forceExpandAndShowModal}
className={classNames('rdw-link-dropdownoption', link.className)}
title={link.title || translations['components.controls.link.link']}
>
<img
src={link.icon}
alt=""
/>
</DropdownOption>}
{options.indexOf('unlink') >= 0 && <DropdownOption
onClick={this.removeLink}
disabled={!currentState.link}
className={classNames('rdw-link-dropdownoption', unlink.className)}
title={unlink.title || translations['components.controls.link.unlink']}
>
<img
src={unlink.icon}
alt=""
/>
</DropdownOption>}
</Dropdown>
{expanded && showModal ? this.renderAddLinkModal() : undefined}
</div>
);
}
render(): Object {
const { config: { inDropdown } } = this.props;
if (inDropdown) {
return this.renderInDropDown();
}
return this.renderInFlatList();
}
}
export default LayoutComponent;