Reputation: 3299
I'm looking to search the editor text for any hashtags, and wrap the hashtag in an anchor tag to make it a link. So this: #whatsup
would be this: <a href='http://help.com'>#whatsup</a>
.
Here's what I have so far, which modifies the text correctly but results in this error. addRange(): The given range isn't in document
And the cursor is removed, disallowing me to type anything else.
I get the same error when using setContents
rather than dangerouslyPasteHTML
Just type any hashtag value such as #foo into the code snippet and look at your console to reproduce the error. Any help much appreciated.
class RichEditor extends React.Component {
constructor (props) {
super(props)
this.state = {
editorHtml: '',
hashTags: []
}
this.modules = {
toolbar: [
[{ header: [1, 2, false] }],
['bold', 'italic', 'underline'],
['image', 'code-block']
]
}
this.editor = null;
this.quillRef = null;
this.handleChange = this.handleChange.bind(this)
}
handleChange (html) {
var blurtHashtags = this.editor.getText().match(/(?:^|\B)#[a-zA-Z][\w]{1,19}\b/g);
if (blurtHashtags) {
var modHtml = html.replace(blurtHashtags[0], "<a href='http://help.com'>" + blurtHashtags[0] + "</a>");
this.editor.clipboard.dangerouslyPasteHTML(modHtml);
} else {
this.setState(prevState => ({
editorHtml: html
}));
}
}
componentDidMount() {
if (typeof this.quillRef.getEditor !== 'function') return;
this.editor = this.quillRef.getEditor();
}
render() {
return (
<div>
<ReactQuill
ref={(el) => { this.quillRef = el; }}
onChange={this.handleChange}
modules={this.modules}
/>
</div>
);
}
}
ReactDOM.render( <
RichEditor / > ,
document.getElementById("quill")
);
<div id="quill"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/prop-types/prop-types.js"></script>
<script src="https://unpkg.com/react-quill@latest/dist/react-quill.js"></script>
<link href="//cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
Upvotes: 3
Views: 2455
Reputation: 15166
It's pretty interesting what is going on in the background. The solution what you find down there uses setTimeout
with 0ms
delay to call dangerouslyPasteHTML
function.
The reason behind why it is working now as expected that is technically not a good practice to modify the content in the handler event of the input field and by adding the delay the event loop will execute the input field modification - dangerouslyPasteHTML
function - after the handler event.
The following code snippet resolves your issue, please take a look:
class RichEditor extends React.Component {
constructor (props) {
super(props)
this.state = {
editorHtml: '',
hashTags: []
}
this.modules = {
toolbar: [
[{ header: [1, 2, false] }],
['bold', 'italic', 'underline'],
['image', 'code-block']
]
}
this.editor = null;
this.quillRef = null;
this.handleChange = this.handleChange.bind(this)
}
handleChange (html) {
const linkStart = `<a href="http://help.com" rel="noopener noreferrer" target="_blank">`;
const linkEnd = `</a>`;
// remove anchor tag around the hashtag value
// in order to identify hashtag properly
let modHtml = html.replace(linkStart, '');
modHtml = modHtml.replace(linkEnd, '');
const blurtHashtags = modHtml.match(/(?:^|\B)#[a-zA-Z][\w]{1,19}\b/g);
if (blurtHashtags) {
// rebuild link with anchor tag
const link = `${linkStart}${blurtHashtags[0]}${linkEnd}`;
modHtml = modHtml.replace(blurtHashtags[0], link);
let editor = this.editor;
setTimeout(() => {
editor.clipboard.dangerouslyPasteHTML(modHtml);
let selection = editor.getSelection();
selection.index = modHtml.length;
editor.setSelection(selection);
}, 0);
} else {
this.setState(prevState => ({
editorHtml: html
}));
}
}
componentDidMount() {
if (typeof this.quillRef.getEditor !== 'function') return;
this.editor = this.quillRef.getEditor();
}
render() {
return (
<div>
<ReactQuill
className="quill-pre"
ref={(el) => { this.quillRef = el; }}
onChange={this.handleChange}
modules={this.modules}
/>
</div>
);
}
}
ReactDOM.render( <
RichEditor / > ,
document.getElementById("quill")
);
.quill-pre p {
white-space: pre;
}
<div id="quill"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/prop-types/prop-types.js"></script>
<script src="https://unpkg.com/react-quill@latest/dist/react-quill.js"></script>
<link href="//cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
Obviously the rich text editor is not perfect at this point but fits for your requirements which was removing the error message what you had earlier. If you try typing the test text value #wassup
then it won't throw any error message.
Additionally I have added white-space: pre;
styling for the p
tag in the component which resolves the white spacing issue after typing any hashtag.
Hope this helps!
Upvotes: 3