diff --git a/spec/highlight-support.spec.js b/spec/highlight-support.spec.js index bcc410e0..b8587757 100644 --- a/spec/highlight-support.spec.js +++ b/spec/highlight-support.spec.js @@ -327,6 +327,38 @@ ke The
World Go Round`) expect(this.getHtml()).to.equal(expectedHtml) }) + it('limits start and end values to text range', function () { + setupHighlightEnv(this, 'ab') + this.highlightRange('ab', 'myId', -1, 100) + const expectedHtml = this.formatHtml( + `ab` + ) + + expect(this.getHtml()).to.equal(expectedHtml) + }) + + it('always selects the first character if values are too small', function () { + setupHighlightEnv(this, 'ab') + const highlightText = undefined // Avoid validation + this.highlightRange(highlightText, 'myId', 0, 0) + const expectedHtml = this.formatHtml( + `ab` + ) + + expect(this.getHtml()).to.equal(expectedHtml) + }) + + it('always selects the last character if values are too large', function () { + setupHighlightEnv(this, 'ab') + const highlightText = undefined // Avoid validation + this.highlightRange(highlightText, 'myId', 2, 5) + const expectedHtml = this.formatHtml( + `ab` + ) + + expect(this.getHtml()).to.equal(expectedHtml) + }) + it('handles a
tag without whitespaces', function () { setupHighlightEnv(this, 'a
b') this.highlightRange('b', 'myId', 1, 2) @@ -482,7 +514,7 @@ ke The
World Go Round`) it('extracts a readable text', function () { setupHighlightEnv(this, '๐Ÿ˜ Make The \r\n ๐ŸŒ Go \n๐Ÿ”„') - this.highlightRange('๐Ÿ˜ Makeย The ๐ŸŒ Go ๐Ÿ”„', 'myId', 0, 23) + this.highlightRange('๐Ÿ˜ Makeย The \n ๐ŸŒ Go \n๐Ÿ”„', 'myId', 0, 23) const expectedRanges = { myId: { text: '๐Ÿ˜ Makeย The \n ๐ŸŒ Go \n๐Ÿ”„', @@ -499,7 +531,7 @@ ke The
World Go Round`) setupHighlightEnv(this, '๐Ÿ˜ Make The \r\n ๐ŸŒ Go \n๐Ÿ”„') let called = 0 const dispatcher = {notify: () => called++} - this.highlightRange('๐Ÿ˜ Makeย The ๐ŸŒ Go ๐Ÿ”„', 'myId', 0, 20, dispatcher) + this.highlightRange('๐Ÿ˜ Makeย The \n ๐ŸŒ Go \n๐Ÿ”„', 'myId', 0, 23, dispatcher) expect(called).to.equal(1) }) @@ -508,7 +540,7 @@ ke The
World Go Round`) setupHighlightEnv(this, '๐Ÿ˜ Make The \r\n ๐ŸŒ Go \n๐Ÿ”„') let called = 0 const dispatcher = {notify: () => called++} - this.highlightRange('๐Ÿ˜ Makeย The ๐ŸŒ Go ๐Ÿ”„', 'myId', 0, 20) + this.highlightRange('๐Ÿ˜ Makeย The \n ๐ŸŒ Go \n๐Ÿ”„', 'myId', 0, 23) this.removeHighlight('first', dispatcher) expect(called).to.equal(1) diff --git a/spec/selection.spec.js b/spec/selection.spec.js index ccdc0fb9..4e2bd180 100644 --- a/spec/selection.spec.js +++ b/spec/selection.spec.js @@ -142,6 +142,17 @@ describe('Selection', function () { }) }) + describe('getTextRange()', function () { + + it('handles a zero width non-break space', function () { + const oneWord = createElement('
\uFEFFfoobar\uFEFF
') + const range = createRange() + range.selectNodeContents(oneWord) + const selection = new Selection(oneWord, range) + expect(selection.getTextRange()).to.deep.equal({start: 0, end: 6, text: 'foobar'}) + }) + }) + describe('custom:', function () { beforeEach(function () { diff --git a/src/highlight-support.js b/src/highlight-support.js index 87dd1ce9..85957e5c 100644 --- a/src/highlight-support.js +++ b/src/highlight-support.js @@ -45,8 +45,18 @@ const highlightSupport = { this.win ) - const actualStartIndex = startIndex - const actualEndIndex = endIndex + // Do not let highlight exceed text range + const actualStartIndex = Math.min(Math.max(startIndex, 0), blockText.length - 1) + const actualEndIndex = Math.min(Math.max(endIndex, 1), blockText.length) + + // If text is provided then validate that it matches + if (text) { + const tempElement = document.createElement('div') + tempElement.innerHTML = text + if (tempElement.textContent !== blockText.slice(actualStartIndex, actualEndIndex)) { + return -1 + } + } highlightText.highlightMatches(editableHost, [{ startIndex: actualStartIndex, @@ -107,7 +117,7 @@ const highlightSupport = { if (position) res[highlightId] = position } - return res + return Object.keys(res).length > 0 ? res : undefined }, extractMarkerNodePosition (editableHost, markers) { diff --git a/src/util/dom.js b/src/util/dom.js index 2dc067ab..a1b91e46 100644 --- a/src/util/dom.js +++ b/src/util/dom.js @@ -182,7 +182,10 @@ export const toCharacterRange = (range, container) => { startRange.setStart(container, 0) startRange.setEnd(range.startContainer, range.startOffset) - const rangeText = range.toString() + // Remove zero width space to make selection more accurate, + // because it will be removed on component blur via extractContent. + const zeroWidthNonBreakingSpace = /\uFEFF/g + const rangeText = range.toString().replace(zeroWidthNonBreakingSpace, '') const start = startRange.toString().length const end = start + rangeText.length