Inline formats such as bold, italic, bold-italic, code does not work well with inline-embeds.
wooolfgang opened this issue · 0 comments
wooolfgang commented
For my particular use-case, using quill-markdown-shortcuts with quill-mentions causes a bug. The bug will also happen if you have custom inline-embeds, or default ones such as images, etc.
Steps to reproduce:
- Open code-sandbox -- the editor here uses quill-markdown-shortcuts and quill-mentions
- Create a mention blot (use @{USER_HERE}) and then after the blot and within the current line, use markdown shortcuts such as bold ({WORD}), italics ({WORD}), etc.
- As you can see, there's an issue with the deleting/replacing of the text with the correct format.
The issue is caused by this line in particular
const startIndex = lineStart + match.index
if (text.match(/^([*_ \n]+)$/g)) return
setTimeout(() => {
this.quill.deleteText(startIndex, annotatedText.length)
this.quill.insertText(startIndex, matchedText, {bold: true, italic: true})
this.quill.format('bold', false)
}, 0)
The calculations for startIndex is not correct when there are inline-embed blots before the matchedText and within the current line. Inline-embeds will only have length === 1, causing an issue with the markdown-shortcut plugin once the editor has non-text contents.
I have a solution that fixes this issue, but I'm not sure if this is best one. I would like to know anyone's thoughts, or if they came up with more elegant solutions. Thanks!
getStartIndex (annotatedText) {
const wholeText = this.quill.getText()
const embedsCountBeforeText = this.getInlineEmbedsBeforeText(annotatedText)
const startIndex = wholeText.indexOf(annotatedText) + embedsCountBeforeText
return startIndex
}
/**
* @description -- This counts the number of inline embeds (image|imageLoading|mention)
* before a matched text within the current line
* @param {String} annotatedText
* @returns {Number}
*/
getInlineEmbedsBeforeText (annotatedText) {
const contents = this.quill.getContents()
let count = 0
let startCount = false
let matchedIndex = 0
if (contents.ops.length <= 1) {
return count
}
for (let i = contents.ops.length - 1; i >= 0; i--) {
const content = contents.ops[i]
// If the annotatedText matches within the text, start the count
if (typeof content.insert === 'string' && content.insert.includes(annotatedText)) {
startCount = true
matchedIndex = i
}
// If an inline embed is matched before the annotatedText and within the current line, increment
if (startCount &&
(content.insert.mention || content.insert.image || content.insert.imageLoading)) {
count += 1
}
// If the content is not within the current line, end the count
if (
startCount &&
typeof content.insert === 'string' &&
content.insert.includes('↵') &&
matchedIndex !== i
) {
startCount = false
break
}
}
return count
}