Skip to content

Commit ffd7908

Browse files
committed
feat: add editable.highlight() method
1 parent 6b6ef61 commit ffd7908

File tree

4 files changed

+78
-17
lines changed

4 files changed

+78
-17
lines changed

src/core.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import * as content from './content'
99
import * as clipboard from './clipboard'
1010
import Dispatcher from './dispatcher'
1111
import Cursor from './cursor'
12+
import highlightSupport from './highlight-support'
1213
import Highlighting from './highlighting'
1314
import createDefaultEvents from './create-default-events'
1415
import browser from 'bowser'
@@ -35,6 +36,7 @@ import browser from 'bowser'
3536
*/
3637

3738
const Editable = module.exports = class Editable {
39+
3840
constructor (instanceConfig) {
3941
const defaultInstanceConfig = {
4042
window: window,
@@ -330,6 +332,26 @@ const Editable = module.exports = class Editable {
330332
}
331333
}
332334

335+
// Highlight text within an editable.
336+
//
337+
// The first occurrence of the provided 'text' will be highlighted.
338+
//
339+
// The markup used for the highlighting will be removed from
340+
// the final content.
341+
//
342+
// @param editableHost {DomNode}
343+
// @param text {String}
344+
// @param highlightId {String} Optional
345+
// Added to the highlight markups in the property `data-word-id`
346+
// @param remove {Boolean} Optional
347+
highlight ({editableHost, text, highlightId, remove}) {
348+
if (!remove) {
349+
highlightSupport.highlightText(editableHost, text, highlightId)
350+
} else {
351+
highlightSupport.removeHighlight(editableHost, highlightId)
352+
}
353+
}
354+
333355
/**
334356
* Subscribe a callback function to a custom event fired by the API.
335357
*

src/highlight-support.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import $ from 'jquery'
2+
3+
import * as content from './content'
4+
import highlightText from './highlight-text'
5+
import TextHighlighting from './plugins/highlighting/text-highlighting'
6+
7+
const highlightSupport = {
8+
9+
highlightText (editableHost, text, highlightId) {
10+
let blockText = highlightText.extractText(editableHost)
11+
12+
const marker = '<span class="highlight-comment"></span>'
13+
const markerNode = highlightSupport.createMarkerNode(marker, this.win)
14+
15+
const textSearch = new TextHighlighting(markerNode, 'text')
16+
const matches = textSearch.findMatches(blockText, [text])
17+
18+
if (matches && matches.length) {
19+
if (highlightId) matches[0].id = highlightId
20+
highlightText.highlightMatches(editableHost, matches)
21+
}
22+
},
23+
24+
removeHighlight (editableHost, highlightId) {
25+
$(editableHost).find(`[data-word-id="${highlightId}"]`)
26+
.each((index, elem) => {
27+
content.unwrap(elem)
28+
})
29+
},
30+
31+
createMarkerNode (markerMarkup, win) {
32+
let marker = $(markerMarkup)[0]
33+
34+
if (win) {
35+
marker = content.adoptElement(marker, win.document)
36+
}
37+
38+
marker.setAttribute('data-editable', 'ui-unwrap')
39+
marker.setAttribute('data-highlight', 'highlight')
40+
return marker
41+
}
42+
43+
}
44+
45+
export default highlightSupport

src/highlight-text.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export default {
5151
let isFirstPortion = isLastPortion = false
5252
if (totalOffset <= currentMatch.startIndex) {
5353
isFirstPortion = true
54-
var wordId = currentMatch.startIndex
54+
var wordId = currentMatch.id || currentMatch.startIndex
5555
}
5656
if (nodeEndOffset >= currentMatch.endIndex) {
5757
var isLastPortion = true

src/highlighting.js

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ import SpellcheckService from './plugins/highlighting/spellcheck-service'
77
import WhitespaceHighlighting from './plugins/highlighting/whitespace-highlighting'
88
import WordHighlighting from './plugins/highlighting/text-highlighting'
99
import MatchCollection from './plugins/highlighting/match-collection'
10+
import highlightSupport from './highlight-support'
1011

1112
export default class Highlighting {
13+
1214
constructor (editable, configuration, spellcheckConfig) {
1315
this.editable = editable
1416
this.win = editable.win
@@ -37,12 +39,14 @@ export default class Highlighting {
3739
this.config = $.extend(true, defaultConfig, configuration)
3840

3941
let spellcheckService = this.config.spellcheck.spellcheckService
40-
let spellcheckMarker = this.createMarkerNode(this.config.spellcheck.marker)
41-
let whitespaceMarker = this.createMarkerNode(this.config.whitespace.marker)
42+
const spellcheckMarker = this.config.spellcheck.marker
43+
const whitespaceMarker = this.config.whitespace.marker
44+
const spellcheckMarkerNode = highlightSupport.createMarkerNode(spellcheckMarker, this.win)
45+
const whitespaceMarkerNode = highlightSupport.createMarkerNode(whitespaceMarker, this.win)
4246

4347
this.spellcheckService = new SpellcheckService(spellcheckService)
44-
this.spellcheck = new WordHighlighting(spellcheckMarker)
45-
this.whitespace = new WhitespaceHighlighting(whitespaceMarker)
48+
this.spellcheck = new WordHighlighting(spellcheckMarkerNode)
49+
this.whitespace = new WhitespaceHighlighting(whitespaceMarkerNode)
4650

4751
this.setupListeners()
4852
}
@@ -89,18 +93,6 @@ export default class Highlighting {
8993
}
9094
}
9195

92-
// Marker
93-
// ------
94-
95-
createMarkerNode (markerMarkup) {
96-
let marker = $(markerMarkup)[0]
97-
marker = content.adoptElement(marker, this.win.document)
98-
99-
marker.setAttribute('data-editable', 'ui-unwrap')
100-
marker.setAttribute('data-highlight', 'highlight')
101-
return marker
102-
}
103-
10496
// Manage Highlights
10597
// -----------------
10698

@@ -144,6 +136,8 @@ export default class Highlighting {
144136

145137
}
146138

139+
// Calls highlightMatches internally but ensures
140+
// that the selection stays the same
147141
safeHighlightMatches (editableHost, matches) {
148142
const selection = this.editable.getSelection(editableHost)
149143
if (selection) {

0 commit comments

Comments
 (0)