@progress/kendo-pdfviewer-common 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +7 -0
- package/NOTICE.txt +614 -0
- package/README.md +9 -0
- package/dist/es/main.js +3 -0
- package/dist/es/scroller.js +229 -0
- package/dist/es/search.js +256 -0
- package/dist/es/utils.js +315 -0
- package/dist/npm/main.d.ts +5 -0
- package/dist/npm/main.js +6 -0
- package/dist/npm/scroller.d.ts +32 -0
- package/dist/npm/scroller.js +232 -0
- package/dist/npm/search.d.ts +37 -0
- package/dist/npm/search.js +259 -0
- package/dist/npm/utils.d.ts +96 -0
- package/dist/npm/utils.js +317 -0
- package/package.json +98 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import Draggable from '@progress/kendo-draggable';
|
|
2
|
+
const throttle = function (func, wait, options = {}) {
|
|
3
|
+
let timeout, context, args, result;
|
|
4
|
+
let previous = 0;
|
|
5
|
+
const later = function () {
|
|
6
|
+
previous = options.leading === false ? 0 : new Date().getTime();
|
|
7
|
+
timeout = undefined;
|
|
8
|
+
result = func.apply(context, args);
|
|
9
|
+
if (!timeout) {
|
|
10
|
+
context = args = null;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
const throttled = function () {
|
|
14
|
+
const now = new Date().getTime();
|
|
15
|
+
if (!previous && options.leading === false) {
|
|
16
|
+
previous = now;
|
|
17
|
+
}
|
|
18
|
+
const remaining = wait - (now - previous);
|
|
19
|
+
context = undefined; // this
|
|
20
|
+
args = arguments;
|
|
21
|
+
if (remaining <= 0 || remaining > wait) {
|
|
22
|
+
if (timeout) {
|
|
23
|
+
clearTimeout(timeout);
|
|
24
|
+
timeout = undefined;
|
|
25
|
+
}
|
|
26
|
+
previous = now;
|
|
27
|
+
result = func.apply(context, args);
|
|
28
|
+
if (!timeout) {
|
|
29
|
+
context = args = null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else if (!timeout && options.trailing !== false) {
|
|
33
|
+
timeout = window.setTimeout(later, remaining);
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
return throttled;
|
|
38
|
+
};
|
|
39
|
+
const preventDefault = (e) => {
|
|
40
|
+
if (e.preventDefault) {
|
|
41
|
+
e.preventDefault();
|
|
42
|
+
}
|
|
43
|
+
if (e.originalEvent) {
|
|
44
|
+
e.originalEvent.preventDefault();
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const matchesElementSelector = (element, selector) => {
|
|
48
|
+
if (!element || !selector) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return element.closest(selector);
|
|
52
|
+
};
|
|
53
|
+
const FRAMES_PER_SECOND = 1000 / 60;
|
|
54
|
+
const SCROLL = 'scroll';
|
|
55
|
+
/**
|
|
56
|
+
* @hidden
|
|
57
|
+
*/
|
|
58
|
+
export class Scroller {
|
|
59
|
+
constructor(element, options) {
|
|
60
|
+
this.options = {
|
|
61
|
+
events: {
|
|
62
|
+
[SCROLL]: () => undefined
|
|
63
|
+
},
|
|
64
|
+
filter: '',
|
|
65
|
+
// throttle the scroll events to get a more similar experience
|
|
66
|
+
// to the scrolling behavior in Adobe Acrobat Reader
|
|
67
|
+
// as well as allow a way to improve the scrolling performance for large files
|
|
68
|
+
panScrollThrottleDelay: FRAMES_PER_SECOND,
|
|
69
|
+
// the drag directions are actually reversed, e.g.
|
|
70
|
+
// dragging to the right actually moves the document to the left
|
|
71
|
+
scrollDirectionModifier: -1,
|
|
72
|
+
scrollThrottleDelay: FRAMES_PER_SECOND
|
|
73
|
+
};
|
|
74
|
+
this.onElementScroll = () => {
|
|
75
|
+
const element = this.element;
|
|
76
|
+
if (this.state.trackNextElementScroll) {
|
|
77
|
+
this.scrollTo(element.scrollLeft, element.scrollTop);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
// reset the state, so that consecutive scroll events can be handled
|
|
81
|
+
this.state.trackNextElementScroll = true;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
this.onDragStart = (e) => {
|
|
85
|
+
this.state.dragStarted = false;
|
|
86
|
+
if (!this.shouldTrackPanEvents()) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const target = e.target || (e.originalEvent || {}).target;
|
|
90
|
+
if (this.options.filter &&
|
|
91
|
+
!matchesElementSelector(target, this.options.filter)) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
preventDefault(e);
|
|
95
|
+
this.setState({
|
|
96
|
+
dragStarted: true,
|
|
97
|
+
location: {
|
|
98
|
+
pageX: e.pageX,
|
|
99
|
+
pageY: e.pageY
|
|
100
|
+
},
|
|
101
|
+
locationDelta: {
|
|
102
|
+
x: 0,
|
|
103
|
+
y: 0
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
this.onDrag = (e) => {
|
|
108
|
+
if (!this.shouldTrackPanEvents() || !this.state.dragStarted) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
this.calculateEventLocationDelta(e);
|
|
112
|
+
this.setState({
|
|
113
|
+
location: {
|
|
114
|
+
pageX: e.pageX,
|
|
115
|
+
pageY: e.pageY
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
const directionModifier = this.options.scrollDirectionModifier;
|
|
119
|
+
const scrollLeft = this.element.scrollLeft +
|
|
120
|
+
directionModifier * this.state.locationDelta.x;
|
|
121
|
+
const scrollTop = this.element.scrollTop +
|
|
122
|
+
directionModifier * this.state.locationDelta.y;
|
|
123
|
+
this.scrollTo(scrollLeft, scrollTop);
|
|
124
|
+
};
|
|
125
|
+
this.onDragEnd = () => {
|
|
126
|
+
if (!this.shouldTrackPanEvents()) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
this.element = element;
|
|
131
|
+
this.options = Object.assign({}, this.options, options);
|
|
132
|
+
this.resetState();
|
|
133
|
+
this.bindEvents();
|
|
134
|
+
}
|
|
135
|
+
destroy() {
|
|
136
|
+
this.unbindEvents();
|
|
137
|
+
}
|
|
138
|
+
initDraggable() {
|
|
139
|
+
this.destroyDraggable();
|
|
140
|
+
if (this.options.panScrollThrottleDelay > 0) {
|
|
141
|
+
this.throttledOnDrag = throttle(this.onDrag, this.options.panScrollThrottleDelay);
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
this.throttledOnDrag = this.onDrag;
|
|
145
|
+
}
|
|
146
|
+
this.draggable = new Draggable({
|
|
147
|
+
mouseOnly: false,
|
|
148
|
+
press: this.onDragStart,
|
|
149
|
+
drag: this.throttledOnDrag,
|
|
150
|
+
release: this.onDragEnd
|
|
151
|
+
});
|
|
152
|
+
this.draggable.bindTo(this.element);
|
|
153
|
+
}
|
|
154
|
+
destroyDraggable() {
|
|
155
|
+
if (this.draggable && this.draggable.destroy) {
|
|
156
|
+
this.draggable.destroy();
|
|
157
|
+
if (this.throttledOnDrag && this.throttledOnDrag.cancel) {
|
|
158
|
+
this.throttledOnDrag.cancel();
|
|
159
|
+
this.throttledOnDrag = null;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
bindEvents() {
|
|
164
|
+
this.bindDraggableEvents();
|
|
165
|
+
this.bindElementScroll();
|
|
166
|
+
}
|
|
167
|
+
bindDraggableEvents() {
|
|
168
|
+
this.initDraggable();
|
|
169
|
+
}
|
|
170
|
+
bindElementScroll() {
|
|
171
|
+
if (this.options.scrollThrottleDelay > 0) {
|
|
172
|
+
this.throttledOnElementScroll = throttle(this.onElementScroll, this.options.scrollThrottleDelay);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
this.throttledOnElementScroll = this.onElementScroll;
|
|
176
|
+
}
|
|
177
|
+
this.element.addEventListener(SCROLL, this.throttledOnElementScroll);
|
|
178
|
+
}
|
|
179
|
+
unbindEvents() {
|
|
180
|
+
this.unbindElementScroll();
|
|
181
|
+
this.unbindDraggableEvents();
|
|
182
|
+
}
|
|
183
|
+
unbindDraggableEvents() {
|
|
184
|
+
this.destroyDraggable();
|
|
185
|
+
}
|
|
186
|
+
unbindElementScroll() {
|
|
187
|
+
if (this.throttledOnElementScroll &&
|
|
188
|
+
this.throttledOnElementScroll.cancel) {
|
|
189
|
+
this.throttledOnElementScroll.cancel();
|
|
190
|
+
this.throttledOnElementScroll = null;
|
|
191
|
+
}
|
|
192
|
+
this.element.removeEventListener(SCROLL, this.throttledOnElementScroll);
|
|
193
|
+
}
|
|
194
|
+
setState(newState) {
|
|
195
|
+
this.state = Object.assign({}, this.state || {}, newState);
|
|
196
|
+
}
|
|
197
|
+
resetState() {
|
|
198
|
+
this.setState({
|
|
199
|
+
trackPanEvents: false,
|
|
200
|
+
trackNextElementScroll: false,
|
|
201
|
+
location: { pageX: 0, pageY: 0 },
|
|
202
|
+
locationDelta: { x: 0, y: 0 }
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
enablePanEventsTracking() {
|
|
206
|
+
this.state.trackPanEvents = true;
|
|
207
|
+
this.bindDraggableEvents();
|
|
208
|
+
}
|
|
209
|
+
disablePanEventsTracking() {
|
|
210
|
+
this.unbindDraggableEvents();
|
|
211
|
+
this.state.trackPanEvents = false;
|
|
212
|
+
}
|
|
213
|
+
shouldTrackPanEvents() {
|
|
214
|
+
return this.state.trackPanEvents;
|
|
215
|
+
}
|
|
216
|
+
calculateEventLocationDelta(e) {
|
|
217
|
+
this.state.locationDelta = {
|
|
218
|
+
x: e.pageX - this.state.location.pageX,
|
|
219
|
+
y: e.pageY - this.state.location.pageY
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
scrollTo(x, y, options = { trackScrollEvent: true }) {
|
|
223
|
+
if (!options.trackScrollEvent) {
|
|
224
|
+
this.state.trackNextElementScroll = false;
|
|
225
|
+
}
|
|
226
|
+
this.element.scrollLeft = x;
|
|
227
|
+
this.element.scrollTop = y;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
const unwrapElement = (element) => {
|
|
2
|
+
const parentElement = element.parentElement;
|
|
3
|
+
if (!element || !parentElement) {
|
|
4
|
+
return;
|
|
5
|
+
}
|
|
6
|
+
parentElement.replaceWith(...Array.from(parentElement.childNodes));
|
|
7
|
+
};
|
|
8
|
+
const unwrapElements = (elements) => {
|
|
9
|
+
if (!elements || !elements.length || elements.length <= 0) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
for (let i = 0; i < elements.length; i++) {
|
|
13
|
+
unwrapElement(elements[i]);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
const wrapElement = (element, wrapper) => {
|
|
17
|
+
if (element.parentNode) {
|
|
18
|
+
element.parentNode.insertBefore(wrapper, element);
|
|
19
|
+
wrapper.appendChild(element);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const wrapInnerElement = (element, wrapper) => {
|
|
23
|
+
if (!element || !element.parentNode || !wrapper) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
element.appendChild(wrapper);
|
|
27
|
+
while (element.firstChild && element.firstChild !== wrapper) {
|
|
28
|
+
wrapper.appendChild(element.firstChild);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const addClass = (className, element) => {
|
|
32
|
+
element.classList.add(className);
|
|
33
|
+
};
|
|
34
|
+
const removeClass = (className, element) => {
|
|
35
|
+
element.classList.remove(className);
|
|
36
|
+
};
|
|
37
|
+
const toClassSelector = (className) => `.${className}`;
|
|
38
|
+
const CHAR_INDEX_DATA_ATTR = 'data-char-index';
|
|
39
|
+
const MATCH_INDEX_DATA_ATTR = 'data-match-index';
|
|
40
|
+
/**
|
|
41
|
+
* @hidden
|
|
42
|
+
*/
|
|
43
|
+
export class SearchService {
|
|
44
|
+
constructor(options) {
|
|
45
|
+
this.options = {
|
|
46
|
+
highlightClass: 'k-search-highlight',
|
|
47
|
+
highlightMarkClass: 'k-search-highlight-mark',
|
|
48
|
+
charClass: 'k-text-char',
|
|
49
|
+
textContainers: []
|
|
50
|
+
};
|
|
51
|
+
this.extendOptions(options);
|
|
52
|
+
this.resetState();
|
|
53
|
+
}
|
|
54
|
+
destroy() {
|
|
55
|
+
this.clearSearch();
|
|
56
|
+
}
|
|
57
|
+
extendOptions(options) {
|
|
58
|
+
this.options = Object.assign({}, this.options, options);
|
|
59
|
+
}
|
|
60
|
+
setState(newState) {
|
|
61
|
+
this.state = Object.assign({}, this.state || {}, newState);
|
|
62
|
+
}
|
|
63
|
+
resetState() {
|
|
64
|
+
this.setState({
|
|
65
|
+
text: '',
|
|
66
|
+
textNodes: [],
|
|
67
|
+
charIndex: 0,
|
|
68
|
+
activeMatchIndex: 0,
|
|
69
|
+
matches: []
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
search({ text, matchCase }) {
|
|
73
|
+
let searchRegex = new RegExp(text, matchCase ? 'g' : 'ig');
|
|
74
|
+
let match;
|
|
75
|
+
if (this.shouldTransformText()) {
|
|
76
|
+
this.transformTextForSearch();
|
|
77
|
+
}
|
|
78
|
+
this.state.matches = [];
|
|
79
|
+
this.state.activeMatchIndex = 0;
|
|
80
|
+
this.removeIndicators();
|
|
81
|
+
if (text === '') {
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
match = searchRegex.exec(this.state.text);
|
|
85
|
+
while (match) {
|
|
86
|
+
this.state.matches.push({
|
|
87
|
+
startOffset: match.index,
|
|
88
|
+
endOffset: match.index + match[0].length
|
|
89
|
+
});
|
|
90
|
+
match = searchRegex.exec(this.state.text);
|
|
91
|
+
}
|
|
92
|
+
this.highlightAllMatches();
|
|
93
|
+
this.addActiveMatchMark();
|
|
94
|
+
return this.state.matches;
|
|
95
|
+
}
|
|
96
|
+
clearSearch() {
|
|
97
|
+
this.removeIndicators();
|
|
98
|
+
this.restoreOriginalText();
|
|
99
|
+
}
|
|
100
|
+
restoreOriginalText() {
|
|
101
|
+
this.forEachTextContainer((textContainer) => {
|
|
102
|
+
const nodes = Array.from(textContainer.querySelectorAll('span:not(.' + this.options.charClass + ')'));
|
|
103
|
+
nodes.forEach((node) => {
|
|
104
|
+
node.innerHTML = node.textContent;
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
shouldTransformText() {
|
|
109
|
+
return !this.state.text;
|
|
110
|
+
}
|
|
111
|
+
transformTextForSearch() {
|
|
112
|
+
this.state.textNodes = [];
|
|
113
|
+
this.state.charIndex = 0;
|
|
114
|
+
this.state.text = '';
|
|
115
|
+
this.forEachTextContainer((textContainer) => {
|
|
116
|
+
this.extractTextNodes(textContainer);
|
|
117
|
+
});
|
|
118
|
+
this.transformTextNodesForSearch(this.state.textNodes);
|
|
119
|
+
}
|
|
120
|
+
extractTextNodes(node) {
|
|
121
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
122
|
+
this.state.textNodes.push(node);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
for (let i = 0; i < node.childNodes.length; i++) {
|
|
126
|
+
this.extractTextNodes(node.childNodes[i]);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
transformTextNodesForSearch(textNodes) {
|
|
131
|
+
for (let i = 0; i < textNodes.length; i++) {
|
|
132
|
+
this.transformTextNodeForSearch(textNodes[i]);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
transformTextNodeForSearch(node) {
|
|
136
|
+
const text = node.textContent;
|
|
137
|
+
if (text.length <= 0) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
this.state.text = this.state.text + text;
|
|
141
|
+
const span = document.createElement('span');
|
|
142
|
+
wrapElement(node, span);
|
|
143
|
+
const splittedHtml = this.splitTextByChars(text);
|
|
144
|
+
span.innerHTML = splittedHtml;
|
|
145
|
+
unwrapElement(span.childNodes[0]);
|
|
146
|
+
}
|
|
147
|
+
splitTextByChars(text) {
|
|
148
|
+
let splittedTextHtml = '';
|
|
149
|
+
for (let i = 0; i < text.length; i++) {
|
|
150
|
+
splittedTextHtml += `<span class='${this.options.charClass}' ${CHAR_INDEX_DATA_ATTR}=${this.state.charIndex}>${text[i]}</span>`;
|
|
151
|
+
this.state.charIndex++;
|
|
152
|
+
}
|
|
153
|
+
return splittedTextHtml;
|
|
154
|
+
}
|
|
155
|
+
forEachTextContainer(callback) {
|
|
156
|
+
for (let i = 0; i < this.options.textContainers.length; i++) {
|
|
157
|
+
const textContainer = this.options.textContainers[i];
|
|
158
|
+
callback(textContainer, i);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
highlightAllMatches() {
|
|
162
|
+
this.state.matches.forEach((match, matchIndex) => {
|
|
163
|
+
this.addMatchHighlight(match.startOffset, match.endOffset, matchIndex);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
addMatchHighlight(matchStartOffset, matchEndOffset, matchIndex) {
|
|
167
|
+
for (let i = matchStartOffset; i < matchEndOffset; i++) {
|
|
168
|
+
this.forEachTextContainer((textContainer) => {
|
|
169
|
+
const highlights = Array.from(textContainer.querySelectorAll(toClassSelector(`${this.options.charClass}[${CHAR_INDEX_DATA_ATTR}='${i}']`)));
|
|
170
|
+
highlights.forEach((highlight) => {
|
|
171
|
+
addClass(this.options.highlightClass, highlight);
|
|
172
|
+
highlight.setAttribute(MATCH_INDEX_DATA_ATTR, matchIndex);
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
removeMatchHighlights() {
|
|
178
|
+
this.forEachTextContainer((textContainer) => {
|
|
179
|
+
const highlights = Array.from(textContainer.querySelectorAll(toClassSelector(this.options.highlightClass)));
|
|
180
|
+
highlights.forEach((highlight) => {
|
|
181
|
+
removeClass(this.options.highlightClass, highlight);
|
|
182
|
+
highlight.removeAttribute(MATCH_INDEX_DATA_ATTR);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
addActiveMatchMark() {
|
|
187
|
+
if (!this.state.activeMatchIndex && this.state.activeMatchIndex !== 0) {
|
|
188
|
+
this.state.activeMatchIndex = 0;
|
|
189
|
+
}
|
|
190
|
+
else if (this.state.activeMatchIndex > this.state.matches.length) {
|
|
191
|
+
this.state.activeMatchIndex = this.state.matches.length;
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
this.removeActiveMatchMark();
|
|
195
|
+
}
|
|
196
|
+
const mark = document.createElement('span');
|
|
197
|
+
mark.classList.add(this.options.highlightMarkClass);
|
|
198
|
+
this.forEachTextContainer((textContainer) => {
|
|
199
|
+
const matches = Array.from(textContainer.querySelectorAll(toClassSelector(this.options.charClass +
|
|
200
|
+
'[' +
|
|
201
|
+
MATCH_INDEX_DATA_ATTR +
|
|
202
|
+
"='" +
|
|
203
|
+
this.state.activeMatchIndex +
|
|
204
|
+
"']")));
|
|
205
|
+
matches.forEach((match) => {
|
|
206
|
+
wrapInnerElement(match, mark.cloneNode(true));
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
removeActiveMatchMark() {
|
|
211
|
+
this.forEachTextContainer((textContainer) => {
|
|
212
|
+
const marks = Array.from(textContainer.querySelectorAll(toClassSelector(this.options.highlightMarkClass)));
|
|
213
|
+
const childNodes = marks.flatMap((x) => Array.from(x.childNodes));
|
|
214
|
+
unwrapElements(childNodes);
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
removeIndicators() {
|
|
218
|
+
this.removeActiveMatchMark();
|
|
219
|
+
this.removeMatchHighlights();
|
|
220
|
+
}
|
|
221
|
+
markNextMatch() {
|
|
222
|
+
this.markNextMatchIndex();
|
|
223
|
+
this.addActiveMatchMark();
|
|
224
|
+
}
|
|
225
|
+
markPreviousMatch() {
|
|
226
|
+
this.markPreviousMatchIndex();
|
|
227
|
+
this.addActiveMatchMark();
|
|
228
|
+
}
|
|
229
|
+
markNextMatchIndex() {
|
|
230
|
+
this.moveActiveMatchIndex(1);
|
|
231
|
+
}
|
|
232
|
+
markPreviousMatchIndex() {
|
|
233
|
+
this.moveActiveMatchIndex(-1);
|
|
234
|
+
}
|
|
235
|
+
moveActiveMatchIndex(delta) {
|
|
236
|
+
this.state.activeMatchIndex += delta;
|
|
237
|
+
if (this.state.activeMatchIndex < 0) {
|
|
238
|
+
this.state.activeMatchIndex = Math.max(this.state.matches.length - 1, 0);
|
|
239
|
+
}
|
|
240
|
+
else if (this.state.activeMatchIndex >
|
|
241
|
+
this.state.matches.length - 1) {
|
|
242
|
+
this.state.activeMatchIndex = 0;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
getActiveMatchElement() {
|
|
246
|
+
let markedMatch;
|
|
247
|
+
this.forEachTextContainer((textContainer) => {
|
|
248
|
+
const mark = textContainer.querySelector(toClassSelector(this.options.highlightMarkClass));
|
|
249
|
+
if (mark) {
|
|
250
|
+
markedMatch = mark;
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
return markedMatch;
|
|
255
|
+
}
|
|
256
|
+
}
|