'react-quill How to properly add attribute to a specific html tag
Here is what I want to achieve. My user is typing a text in a react-quill component and each time the user type a hashtag like "#S1 " (the space is important, it allow to detect when the user has finished to type his tag) I want to replace the tag #S1 by a specific text containing some value.
I don't use delta, but HTML string for the value of the reat-quill component. So far I have succeed to replace the hastag by the proper value I need, and add a color to the span inserted. What I want to also add is a title attribute that will allow to show the corresponding tag name (i.e. #S1) and an id that will uniquely identify the content of the tag. But when I tried to add these attribute in my span, it's systematically strip.
I understood that I have to create my own parchment, but I' didn't succeed to get it work. Here is my code.
const modules = {
toolbar: [
[{header: [1, 2, false]}],
['bold', 'italic', 'underline', 'strike', 'blockquote'],
[{'script': 'sub'}, {'script': 'super'}],
[{'list': 'ordered'}, {'list': 'bullet'}, {'indent': '-1'}, {'indent': '+1'}],
['link', 'image'],
['clean'],
[{color: []}, {background: []}],
],
};
const formats = [
'header',
'bold', 'italic', 'underline', 'strike', 'blockquote',
'script', 'sub', 'super',
'list', 'bullet', 'indent',
'link', 'image',
'color', 'background',
];
/**
* Inline Em Tag from Quill Docs:
* https://quilljs.com/guides/cloning-medium-with-parchment/
*/
let Inline = ReactQuill.Quill.import('blots/inline');
class EmphBlot extends Inline {
static create(value) {
console.log(value);
let node = super.create();
node.setAttribute('style', 'color: rgb(230, 0, 0)');
node.setAttribute('title', value.title);
return node;
}
static value(node) {
return {
title: node.getAttribute('title'),
style: node.getAttribute('style')
};
}
}
EmphBlot.blotName = 'tag';
EmphBlot.tagName = 'span';
ReactQuill.Quill.register('formats/em', EmphBlot);
class Editor extends React.Component {
constructor (props) {
super(props)
this.state = { editorHtml: '<p>Start here by typing a hashtag</p>' }
this.quillRef = null;
this.reactQuillRef = null;
this.handleChange = this.handleChange.bind(this)
this.handleClickEmbed = this.handleClickEmbed.bind(this)
this.handleClickFormat = this.handleClickFormat.bind(this)
this.registerFormats = this.registerFormats.bind(this)
}
componentDidMount () {
this.registerFormats()
this.setState({
editorHtml: '' // trigger update
})
}
componentDidUpdate () {
this.registerFormats()
}
registerFormats () {
// Ensure React-Quill references is available:
if (typeof this.reactQuillRef.getEditor !== 'function') return;
// Skip if Quill reference is defined:
if (this.quillRef != null) return;
console.log('Registering formats...', this.reactQuillRef)
const quillRef = this.reactQuillRef.getEditor() // could still be null
if (quillRef != null) {
this.quillRef = quillRef;
// console.log(Quill.imports)
}
}
handleClickFormat () {
var range = this.quillRef.getSelection();
if (range) {
this.quillRef.format('em', true);
}
}
handleClickEmbed () {
var range = this.quillRef.getSelection();
if (range) {
this.quillRef.insertEmbed(range.index,"hr","null")
}
}
checkForTag(content, indexPosition){
let tag = /#(\w+)\s/;
let find = content.match(tag);
let indexAfterInsertion = indexPosition;
let updated = false;
let comment;
if (find !== null) {
indexAfterInsertion = indexPosition - find[0].length;
let replace = "My new data (1, 5, 3)"
indexAfterInsertion += replace.length + 1;
updated = true;
if (replace !== '#' + find[1]) {
let toReplacer = '<span style="color:red" title="tag-' + find[1].toUpperCase() + '">' + replace + '</span> ';
// console.log(toReplacer);
comment = content.replace(/#(\w+)\s/, toReplacer);
} else {
comment = content.replace(/#(\w+)\s/, find[1] + " ");
}
}
// console.log(comment);
return {content: comment, updated, indexAfterInsertion}
}
handleChange (content, delta, source, editor) {
let editorHtml = content
let newHtml = this.checkForTag(content);
if(newHtml.updated === true){
console.log(newHtml);
editorHtml = newHtml.content
}
console.log(editorHtml)
this.setState({editorHtml});
}
render () {
return (
<div>
<p>Enter a text containing #S1 (or any other tag, the space must be placed after the tag). It sould be replaced by an other data, but missing the attribute title.</p>
<ReactQuill
ref={(el) => { this.reactQuillRef = el }}
value={this.state.editorHtml}
onChange={this.handleChange.bind(this)}
modules={modules}
formats={formats}
/>
</div>
)
}
}
Editor.propTypes = {
placeholder: React.PropTypes.string,
}
ReactDOM.render(
<div>
<Editor/>
</div>,
document.querySelector('.app')
)
Here is a codepen showing how it work so far https://codepen.io/FLCcrakers/pen/JZVeZE?editors=0111
I surely miss something, but don't understand what.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|