application/components/common/rich-editor2/plugins/anchor.js
import React from "react";
import Dialog from "material-ui/Dialog";
import TextField from "material-ui/TextField";
import CheckBox from "material-ui/Checkbox";
import FlatButton from "material-ui/FlatButton";
import RaisedButton from "material-ui/RaisedButton";
import ToolbarButton from "../common/toolbar-button";
export const SERIALIZER_RULES = [
{
deserialize(el, next) {
if (el.tagName.toLowerCase() == "a") {
const href = el.getAttribute("href");
const target = el.getAttribute("target")
? el.getAttribute("target")
: "";
return {
object: "inline",
type: "anchor",
nodes: next(el.childNodes),
data: {
href: href,
target: target,
},
};
}
},
serialize(obj, children) {
if (obj.object == "inline" && obj.type == "anchor") {
return (
<a
href={obj.data.get("href")}
target={obj.data.get("target")}
>
{children}
</a>
);
}
},
},
];
class AnchorButton extends ToolbarButton {
handleOnClick(e) {
return anchorClickHandler.call(this.props.editor, e);
}
getLabel() {
return <i className="fa fa-link"></i>;
}
}
class AnchorNode extends React.Component {
constructor(props) {
super(props);
this.parentEditor = this.props.editor;
}
render() {
const { data } = this.props.node;
const handleClick = (e) => {
e.preventDefault();
// open the modal and store the anchor data
this.props.editor.setState({
myAnchorModalOpen: true,
myAnchorData: data,
});
};
return (
<a
{...this.props.attributes}
href={data.get("href")}
target={data.get("target")}
onClick={handleClick}
>
{this.props.children}
</a>
);
}
}
function anchorClickHandler(e, defaultUrl = "") {
const { editor } = this;
const { editorContent } = this.state;
const hasLinks = this.hasInline("anchor");
if (hasLinks) {
// user highlighted a link and clicked the button, so remove the link
editor.unwrapInline("anchor");
} else if (editorContent.selection.isExpanded) {
// open the modal
editor.setState({ myAnchorModalOpen: true });
return;
}
}
class AnchorModal extends React.Component {
constructor(props) {
super(props);
this.state = {
url: "",
newWindow: false,
};
}
closeModal() {
this.props.editor.setState({
myAnchorModalOpen: false,
myAnchorData: null,
});
this.setState({
url: "",
newWindow: false,
});
}
handleCancel(e) {
this.closeModal.call(this);
}
componentWillReceiveProps(newProps) {
if (newProps.editor && newProps.editor.state.myAnchorData) {
this.setState({
url: newProps.editor.state.myAnchorData.get("href"),
newWindow:
newProps.editor.state.myAnchorData.get("target") == "_blank"
? true
: false,
});
}
}
handleSave(e) {
let useUrl = this.state.url;
if (useUrl.substring(useUrl.length - 1, useUrl.length) === "\\") {
useUrl = useUrl.substring(0, useUrl.length - 1);
}
// remove any existing links, expand the selection then replace the URL
// if it's set
this.props.editor
.focus()
.moveAnchorToStartOfInline()
.moveFocusToEndOfInline()
.unwrapInline("anchor")
.wrapInline({
type: "anchor",
data: {
href: useUrl,
target: this.state.newWindow ? "_blank" : "",
},
});
this.props.editor.moveToEnd();
setTimeout(() => {
this.closeModal.call(this);
}, 250);
}
updateUrl(e) {
this.setState({
url: e.target.value,
});
}
updateTarget(e, checked) {
this.setState({
newWindow: checked,
});
}
handleKeyPress(e) {
if (e.key == "Enter") {
this.handleSave.call(this, e);
}
}
render() {
const buttons = [
<FlatButton
label="Cancel"
onClick={this.handleCancel.bind(this)}
/>,
<RaisedButton
label="Save"
onClick={this.handleSave.bind(this)}
primary={true}
/>,
];
return (
<Dialog
modal={true}
actions={buttons}
title="Edit Link"
open={this.props.editor.state.myAnchorModalOpen ? true : false}
>
<TextField
floatingLabelText="URL"
value={this.state.url}
onChange={this.updateUrl.bind(this)}
onKeyPress={this.handleKeyPress.bind(this)}
fullWidth={true}
/>
<CheckBox
label="Open in new window"
labelPosition="right"
checked={this.state.newWindow}
onCheck={this.updateTarget.bind(this)}
/>
</Dialog>
);
}
}
function AnchorPlugin(options) {
return {
renderEditor(props, editor, next) {
const children = next();
return (
<React.Fragment>
{children}
<AnchorModal editor={editor} />
</React.Fragment>
);
},
renderNode(props, editor, next) {
const { attributes, children } = props;
switch (props.node.type) {
case "anchor":
return <AnchorNode {...props} editor={editor} />;
default:
return next();
}
},
};
}
export { AnchorPlugin, AnchorButton, anchorClickHandler };