@salesforcedevs/dx-components 0.25.1 → 0.25.2-alpha.30
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/package.json +2 -3
- package/src/.DS_Store +0 -0
- package/src/modules/.DS_Store +0 -0
- package/src/modules/dx/.DS_Store +0 -0
- package/src/modules/dx/groupText/groupText.stories.ts +1 -1
- package/src/modules/dx/sidebar/sidebar.stories.ts +4 -1
- package/src/modules/dx/sidebarOld/sidebarOld.ts +22 -7
- package/src/modules/dx/sidebarSearch/__tests__/sidebarSearch.test.ts +1 -61
- package/src/modules/dx/sidebarSearch/sidebarSearch.ts +39 -20
- package/src/modules/dx/toc/__tests__/mockProps.ts +6 -0
- package/src/modules/dx/toc/toc.css +1 -0
- package/src/modules/utils/highlight/__tests__/highlight.test.ts +45 -43
- package/src/modules/utils/highlight/highlight.ts +27 -14
- package/src/modules/utils-internal/regexps/regexps.ts +9 -2
- package/LICENSE +0 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforcedevs/dx-components",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.2-alpha.30",
|
|
4
4
|
"description": "DX Lightning web components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"engines": {
|
|
@@ -28,6 +28,5 @@
|
|
|
28
28
|
"@types/classnames": "^2.2.10",
|
|
29
29
|
"@types/debounce": "^1.2.0",
|
|
30
30
|
"@types/lodash.get": "^4.4.6"
|
|
31
|
-
}
|
|
32
|
-
"gitHead": "19fa005af70d80558071eaacf3b0366d99004754"
|
|
31
|
+
}
|
|
33
32
|
}
|
package/src/.DS_Store
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { html } from "lit-html";
|
|
2
2
|
import mockProps from "./__tests__/mockProps";
|
|
3
3
|
import featureListMockProps from "../featuresList/__tests__/mockProps";
|
|
4
|
-
import { renderStyle } from "../../utils/storybook/storybook";
|
|
4
|
+
import { renderStyle } from "../../utils-internal/storybook/storybook";
|
|
5
5
|
|
|
6
6
|
export default {
|
|
7
7
|
title: "dx/dx-group-text",
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { html } from "lit-html";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
coveoXMLDocsConfig,
|
|
4
|
+
coveoSFDocsConfig
|
|
5
|
+
} from "../../utils-internal/coveo/coveo";
|
|
3
6
|
import { SAMPLE_TREES, SAMPLE_TREES_WITH_METHODS } from "./__tests__/mockProps";
|
|
4
7
|
|
|
5
8
|
export default {
|
|
@@ -78,10 +78,18 @@ export default class Sidebar extends LightningElement {
|
|
|
78
78
|
this.expanded = !this.matchMedia.matches;
|
|
79
79
|
this.onMediaChange(this.matchMedia);
|
|
80
80
|
this.matchMedia.addEventListener("change", this.onMediaChange);
|
|
81
|
+
window.addEventListener(
|
|
82
|
+
"referencecontentloaded",
|
|
83
|
+
this.dispatchHighlightedTermChange
|
|
84
|
+
);
|
|
81
85
|
}
|
|
82
86
|
|
|
83
87
|
disconnectedCallback() {
|
|
84
88
|
this.matchMedia.removeEventListener("change", this.onMediaChange);
|
|
89
|
+
window.removeEventListener(
|
|
90
|
+
"referencecontentloaded",
|
|
91
|
+
this.dispatchHighlightedTermChange
|
|
92
|
+
);
|
|
85
93
|
}
|
|
86
94
|
|
|
87
95
|
private onMediaChange = (event: MediaQueryListEvent | MediaQueryList) =>
|
|
@@ -120,16 +128,23 @@ export default class Sidebar extends LightningElement {
|
|
|
120
128
|
window.clearTimeout(this._searchTimeout);
|
|
121
129
|
this._searchTimeout = window.setTimeout(() => {
|
|
122
130
|
this.assignFilteredTrees();
|
|
123
|
-
this.
|
|
124
|
-
new CustomEvent("highlightedtermchange", {
|
|
125
|
-
detail: this.searchText,
|
|
126
|
-
composed: true,
|
|
127
|
-
bubbles: true
|
|
128
|
-
})
|
|
129
|
-
);
|
|
131
|
+
this.dispatchHighlightedTermChange();
|
|
130
132
|
}, WAIT_TIME);
|
|
131
133
|
}
|
|
132
134
|
|
|
135
|
+
private dispatchHighlightedTermChange = () => {
|
|
136
|
+
this.dispatchEvent(
|
|
137
|
+
new CustomEvent("highlightedtermchange", {
|
|
138
|
+
detail: {
|
|
139
|
+
query: this.searchText,
|
|
140
|
+
termsToHighlight: [this.searchText]
|
|
141
|
+
},
|
|
142
|
+
composed: true,
|
|
143
|
+
bubbles: true
|
|
144
|
+
})
|
|
145
|
+
);
|
|
146
|
+
};
|
|
147
|
+
|
|
133
148
|
private assignFilteredTrees() {
|
|
134
149
|
this.filteredTrees = this._trees
|
|
135
150
|
.map((singleTree) => {
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import { createElement } from "lwc";
|
|
2
1
|
import SidebarSearch from "dx/sidebarSearch";
|
|
3
|
-
import {
|
|
4
|
-
createRenderComponent,
|
|
5
|
-
renderLightningElement
|
|
6
|
-
} from "utils-internal/tests";
|
|
2
|
+
import { createRenderComponent } from "utils-internal/tests";
|
|
7
3
|
import { coveoXMLDocsConfig } from "utils-internal/coveo";
|
|
8
4
|
import { mockQueryParameter, unmockQueryParameter } from "utils-internal/jest";
|
|
9
5
|
import { SESSION_KEY } from "dx/sidebarSearch";
|
|
@@ -72,62 +68,6 @@ describe(TAG, () => {
|
|
|
72
68
|
return expect(element).toBeAccessible();
|
|
73
69
|
});
|
|
74
70
|
|
|
75
|
-
describe("highlighting", () => {
|
|
76
|
-
afterEach(unmockQueryParameter);
|
|
77
|
-
|
|
78
|
-
it("triggers on initial render when a search value exists", () => {
|
|
79
|
-
mockQueryParameter(QUERY);
|
|
80
|
-
const element = createElement(TAG, { is: SidebarSearch });
|
|
81
|
-
const dispatchEventSpy = jest.spyOn(element, "dispatchEvent");
|
|
82
|
-
renderLightningElement(element, PROPS);
|
|
83
|
-
expect(dispatchEventSpy).toHaveBeenCalledWith(
|
|
84
|
-
expect.objectContaining({
|
|
85
|
-
type: "highlightedtermchange",
|
|
86
|
-
detail: QUERY
|
|
87
|
-
})
|
|
88
|
-
);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it("does not trigger on initial render when a search value does not exist", () => {
|
|
92
|
-
const element = createElement(TAG, { is: SidebarSearch });
|
|
93
|
-
const dispatchEventSpy = jest.spyOn(element, "dispatchEvent");
|
|
94
|
-
renderLightningElement(element, PROPS);
|
|
95
|
-
expect(dispatchEventSpy).not.toHaveBeenCalledWith(
|
|
96
|
-
expect.objectContaining({ type: "highlightedtermchange" })
|
|
97
|
-
);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it("triggers on input change with non-empty value", () => {
|
|
101
|
-
const element = render(PROPS);
|
|
102
|
-
const dxInput = element.shadowRoot.querySelector("dx-input");
|
|
103
|
-
const dispatchEventSpy = jest.spyOn(element, "dispatchEvent");
|
|
104
|
-
|
|
105
|
-
dxInput.dispatchEvent(new CustomEvent("change", { detail: QUERY }));
|
|
106
|
-
|
|
107
|
-
expect(dispatchEventSpy).toHaveBeenCalledWith(
|
|
108
|
-
expect.objectContaining({
|
|
109
|
-
type: "highlightedtermchange",
|
|
110
|
-
detail: QUERY
|
|
111
|
-
})
|
|
112
|
-
);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it("triggers on input change with empty value", () => {
|
|
116
|
-
const element = render(PROPS);
|
|
117
|
-
const dxInput = element.shadowRoot.querySelector("dx-input");
|
|
118
|
-
const dispatchEventSpy = jest.spyOn(element, "dispatchEvent");
|
|
119
|
-
|
|
120
|
-
dxInput.dispatchEvent(new CustomEvent("change", { detail: "" }));
|
|
121
|
-
|
|
122
|
-
expect(dispatchEventSpy).toHaveBeenCalledWith(
|
|
123
|
-
expect.objectContaining({
|
|
124
|
-
type: "highlightedtermchange",
|
|
125
|
-
detail: ""
|
|
126
|
-
})
|
|
127
|
-
);
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
71
|
it("correctly consumes a valid session storage object", () => {
|
|
132
72
|
mockQueryParameter(mockPreloadedState.state.query.q);
|
|
133
73
|
|
|
@@ -94,6 +94,30 @@ export default class SidebarSearch extends LightningElement {
|
|
|
94
94
|
private fetchingMoreResults: boolean = false;
|
|
95
95
|
private didRender = false;
|
|
96
96
|
|
|
97
|
+
private get termsToHighlight(): string[] | null {
|
|
98
|
+
const { termsToHighlight, phrasesToHighlight } =
|
|
99
|
+
this.engine?.state?.search?.response;
|
|
100
|
+
if (!termsToHighlight || !phrasesToHighlight) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const flattenTerms = (terms: Object): string[] =>
|
|
105
|
+
Object.entries(terms).reduce((acc, [key, value]) => {
|
|
106
|
+
if (Array.isArray(value)) {
|
|
107
|
+
return [...acc, key, ...value];
|
|
108
|
+
}
|
|
109
|
+
const values = flattenTerms(value);
|
|
110
|
+
return [...acc, key, ...values];
|
|
111
|
+
}, []);
|
|
112
|
+
|
|
113
|
+
const terms = flattenTerms({
|
|
114
|
+
...termsToHighlight,
|
|
115
|
+
...phrasesToHighlight
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
return Array.from(new Set([this.value, ...terms].flat(2))) as string[];
|
|
119
|
+
}
|
|
120
|
+
|
|
97
121
|
private get hasCorrectCoveoConfig(): boolean {
|
|
98
122
|
const coveoConfigurations = [
|
|
99
123
|
this.coveoOrganizationId,
|
|
@@ -147,12 +171,6 @@ export default class SidebarSearch extends LightningElement {
|
|
|
147
171
|
);
|
|
148
172
|
}
|
|
149
173
|
|
|
150
|
-
// If this is the first render and there is a search value, trigger
|
|
151
|
-
// term highlighting
|
|
152
|
-
if (!this.didRender && this.value) {
|
|
153
|
-
this.dispatchHighlightedTermChange();
|
|
154
|
-
}
|
|
155
|
-
|
|
156
174
|
this.didRender = true;
|
|
157
175
|
}
|
|
158
176
|
|
|
@@ -227,10 +245,6 @@ export default class SidebarSearch extends LightningElement {
|
|
|
227
245
|
this.onResultListChange
|
|
228
246
|
);
|
|
229
247
|
|
|
230
|
-
if (this.value) {
|
|
231
|
-
this.dispatchHighlightedTermChange();
|
|
232
|
-
}
|
|
233
|
-
|
|
234
248
|
if (!this.preloadedState) {
|
|
235
249
|
if (this.value) {
|
|
236
250
|
this.submitSearch();
|
|
@@ -333,6 +347,7 @@ export default class SidebarSearch extends LightningElement {
|
|
|
333
347
|
|
|
334
348
|
private dispatchOnChangeEvent(results: Result[]) {
|
|
335
349
|
this.updateSessionStorage();
|
|
350
|
+
this.dispatchHighlightedTermChange();
|
|
336
351
|
this.dispatchEvent(
|
|
337
352
|
new CustomEvent("change", {
|
|
338
353
|
detail: {
|
|
@@ -347,15 +362,20 @@ export default class SidebarSearch extends LightningElement {
|
|
|
347
362
|
this.dispatchEvent(new CustomEvent("loading", { detail: loading }));
|
|
348
363
|
}
|
|
349
364
|
|
|
350
|
-
private dispatchHighlightedTermChange() {
|
|
351
|
-
this.
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
365
|
+
private dispatchHighlightedTermChange = () => {
|
|
366
|
+
if (this.termsToHighlight) {
|
|
367
|
+
this.dispatchEvent(
|
|
368
|
+
new CustomEvent("highlightedtermchange", {
|
|
369
|
+
detail: {
|
|
370
|
+
query: this.value,
|
|
371
|
+
termsToHighlight: this.termsToHighlight
|
|
372
|
+
},
|
|
373
|
+
composed: true,
|
|
374
|
+
bubbles: true
|
|
375
|
+
})
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
};
|
|
359
379
|
|
|
360
380
|
private updateRecentSearches = () =>
|
|
361
381
|
(this.recentSearches = UserRecentSearches.get().map((item: string) => ({
|
|
@@ -410,7 +430,6 @@ export default class SidebarSearch extends LightningElement {
|
|
|
410
430
|
this.value = e.detail;
|
|
411
431
|
|
|
412
432
|
this.handleValueChange(false);
|
|
413
|
-
this.dispatchHighlightedTermChange();
|
|
414
433
|
}
|
|
415
434
|
|
|
416
435
|
private onInputFocus() {
|
|
@@ -17,6 +17,12 @@ export default {
|
|
|
17
17
|
"Why build on Quip? This is an extra long blurb to test the toc wrapping ability",
|
|
18
18
|
id: "quip",
|
|
19
19
|
anchor: "#test3"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
label:
|
|
23
|
+
"SomeLongExampleWordWithoutAnyBreaks and Then a Word",
|
|
24
|
+
id: "long-word",
|
|
25
|
+
anchor: "#test4"
|
|
20
26
|
}
|
|
21
27
|
]
|
|
22
28
|
};
|
|
@@ -10,99 +10,101 @@ describe("highlight utility", () => {
|
|
|
10
10
|
|
|
11
11
|
it("highlights text that matches search criteria", () => {
|
|
12
12
|
container.innerHTML = mockContent;
|
|
13
|
-
highlightTerms(
|
|
14
|
-
|
|
15
|
-
"apex"
|
|
16
|
-
);
|
|
13
|
+
highlightTerms(container.querySelectorAll(allowedTags.join(",")), {
|
|
14
|
+
query: "apex",
|
|
15
|
+
termsToHighlight: ["apex"]
|
|
16
|
+
});
|
|
17
17
|
expect(container.querySelectorAll("mark")).toHaveLength(14);
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
it("doesn't highlight elements that contains dx/docs components", () => {
|
|
21
|
-
const
|
|
21
|
+
const query = "customreport";
|
|
22
22
|
const codeBlock = createElement("dx-code-block", { is: CodeBlock });
|
|
23
23
|
Object.assign(codeBlock, {
|
|
24
|
-
codeBlock:
|
|
24
|
+
codeBlock: query,
|
|
25
25
|
language: "text"
|
|
26
26
|
});
|
|
27
27
|
container.appendChild(document.createElement("p"));
|
|
28
28
|
container.firstElementChild?.appendChild(codeBlock);
|
|
29
|
-
highlightTerms(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
);
|
|
29
|
+
highlightTerms(container.querySelectorAll(allowedTags.join(",")), {
|
|
30
|
+
query,
|
|
31
|
+
termsToHighlight: [query]
|
|
32
|
+
});
|
|
33
33
|
expect(container.querySelectorAll("mark")).toHaveLength(0);
|
|
34
|
-
expect(codeBlock.shadowRoot.innerHTML).toMatch(
|
|
34
|
+
expect(codeBlock.shadowRoot.innerHTML).toMatch(query); // sanity check
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
it("doesn't highlight terms separated by html tags", () => {
|
|
38
|
+
const query = "loadDatawithin";
|
|
38
39
|
container.innerHTML = "<p>loadData<span>within</span></p>";
|
|
39
|
-
highlightTerms(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
);
|
|
40
|
+
highlightTerms(container.querySelectorAll(allowedTags.join(",")), {
|
|
41
|
+
query,
|
|
42
|
+
termsToHighlight: [query]
|
|
43
|
+
});
|
|
43
44
|
expect(container.querySelectorAll("mark")).toHaveLength(0);
|
|
44
45
|
});
|
|
45
46
|
|
|
46
47
|
it("escapes regex especial characters", () => {
|
|
48
|
+
const query = "apex.+";
|
|
47
49
|
container.innerHTML = mockContent;
|
|
48
|
-
highlightTerms(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
);
|
|
50
|
+
highlightTerms(container.querySelectorAll(allowedTags.join(",")), {
|
|
51
|
+
query,
|
|
52
|
+
termsToHighlight: [query]
|
|
53
|
+
});
|
|
52
54
|
expect(container.querySelectorAll("mark")).toHaveLength(0);
|
|
53
55
|
});
|
|
54
56
|
|
|
55
57
|
it("cleans previous search result before searching for a new term", () => {
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
+
const firstQuery = "apex";
|
|
59
|
+
const secondQuery = "salesforce";
|
|
58
60
|
|
|
59
61
|
container.innerHTML = mockContent;
|
|
60
62
|
|
|
61
|
-
highlightTerms(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
);
|
|
63
|
+
highlightTerms(container.querySelectorAll(allowedTags.join(",")), {
|
|
64
|
+
query: firstQuery,
|
|
65
|
+
termsToHighlight: [firstQuery]
|
|
66
|
+
});
|
|
65
67
|
const firstMarks = container.querySelectorAll("mark");
|
|
66
68
|
expect(firstMarks).toHaveLength(14);
|
|
67
69
|
firstMarks.forEach(({ textContent }) =>
|
|
68
|
-
expect(textContent?.toLowerCase()).toBe(
|
|
70
|
+
expect(textContent?.toLowerCase()).toBe(firstQuery)
|
|
69
71
|
);
|
|
70
72
|
|
|
71
|
-
highlightTerms(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
);
|
|
73
|
+
highlightTerms(container.querySelectorAll(allowedTags.join(",")), {
|
|
74
|
+
query: secondQuery,
|
|
75
|
+
termsToHighlight: [secondQuery]
|
|
76
|
+
});
|
|
75
77
|
const secondMarks = container.querySelectorAll("mark");
|
|
76
78
|
expect(secondMarks).toHaveLength(4);
|
|
77
79
|
secondMarks.forEach(({ textContent }) =>
|
|
78
|
-
expect(textContent?.toLowerCase()).toBe(
|
|
80
|
+
expect(textContent?.toLowerCase()).toBe(secondQuery)
|
|
79
81
|
);
|
|
80
82
|
});
|
|
81
83
|
|
|
82
84
|
it("cleans all marks if the search term is empty string", () => {
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
+
const firstQuery = "apex";
|
|
86
|
+
const secondQuery = "";
|
|
85
87
|
|
|
86
88
|
container.innerHTML = mockContent;
|
|
87
89
|
|
|
88
|
-
highlightTerms(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
);
|
|
90
|
+
highlightTerms(container.querySelectorAll(allowedTags.join(",")), {
|
|
91
|
+
query: firstQuery,
|
|
92
|
+
termsToHighlight: [firstQuery]
|
|
93
|
+
});
|
|
92
94
|
const firstMarks = container.querySelectorAll("mark");
|
|
93
95
|
expect(firstMarks).toHaveLength(14);
|
|
94
96
|
firstMarks.forEach(({ textContent }) =>
|
|
95
|
-
expect(textContent?.toLowerCase()).toBe(
|
|
97
|
+
expect(textContent?.toLowerCase()).toBe(firstQuery)
|
|
96
98
|
);
|
|
97
99
|
|
|
98
|
-
highlightTerms(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
);
|
|
100
|
+
highlightTerms(container.querySelectorAll(allowedTags.join(",")), {
|
|
101
|
+
query: secondQuery,
|
|
102
|
+
termsToHighlight: [secondQuery]
|
|
103
|
+
});
|
|
102
104
|
const secondMarks = container.querySelectorAll("mark");
|
|
103
105
|
expect(secondMarks).toHaveLength(0);
|
|
104
106
|
secondMarks.forEach(({ textContent }) =>
|
|
105
|
-
expect(textContent?.toLowerCase()).toBe(
|
|
107
|
+
expect(textContent?.toLowerCase()).toBe(secondQuery)
|
|
106
108
|
);
|
|
107
109
|
});
|
|
108
110
|
});
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { createSearchRegExp } from "utils-internal/regexps";
|
|
2
2
|
|
|
3
|
-
const MARK_TAGS = /<\/?mark
|
|
3
|
+
const MARK_TAGS = /<\/?mark[^>]*>/gi;
|
|
4
|
+
|
|
5
|
+
// mark tags dif color on ref page
|
|
4
6
|
|
|
5
7
|
export const highlightTerms = (
|
|
6
8
|
// eslint-disable-next-line no-undef
|
|
7
|
-
elements: NodeListOf<
|
|
8
|
-
|
|
9
|
+
elements: NodeListOf<HTMLElement>,
|
|
10
|
+
{ query, termsToHighlight }: { query: string; termsToHighlight: string[] }
|
|
9
11
|
): void => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
const searchExp = createSearchRegExp(termsToHighlight);
|
|
13
|
+
let scrolled = false;
|
|
12
14
|
elements.forEach((element) => {
|
|
13
15
|
if (
|
|
14
16
|
element?.innerHTML.includes("<dx-") ||
|
|
@@ -17,16 +19,27 @@ export const highlightTerms = (
|
|
|
17
19
|
return;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
try {
|
|
23
|
+
if (element.innerHTML.match(MARK_TAGS)) {
|
|
24
|
+
// Remove previously added mark tags
|
|
25
|
+
element.innerHTML = element.innerHTML.replace(MARK_TAGS, "");
|
|
26
|
+
}
|
|
27
|
+
if (element.innerHTML.match(searchExp) && query) {
|
|
28
|
+
element.innerHTML = element.innerHTML.replace(
|
|
29
|
+
searchExp,
|
|
30
|
+
'<mark style="background-color:var(--dx-g-yellow-vibrant-90)">$&</mark>'
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
} catch (e) {
|
|
34
|
+
console.error(
|
|
35
|
+
`${element} could not be parsed by the highlight utility: ${e}`
|
|
36
|
+
);
|
|
28
37
|
}
|
|
29
38
|
|
|
30
|
-
|
|
39
|
+
const mark = element.querySelector("mark");
|
|
40
|
+
if (mark && !scrolled) {
|
|
41
|
+
scrolled = true;
|
|
42
|
+
mark.scrollIntoView({ block: "nearest" });
|
|
43
|
+
}
|
|
31
44
|
});
|
|
32
45
|
};
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
const escapeRegExp = (text: string) =>
|
|
2
2
|
text.replace(/[-[\]{}()*+?.,\\^$|]/g, "\\$&");
|
|
3
3
|
|
|
4
|
-
export const createSearchRegExp = (
|
|
5
|
-
|
|
4
|
+
export const createSearchRegExp = (searchTerms: string[]): RegExp => {
|
|
5
|
+
const escaped = searchTerms.map((term) => escapeRegExp(term.trim()));
|
|
6
|
+
return new RegExp(
|
|
7
|
+
`(?:\\b|[^A-Za-z0-9]\\K)(?:${escaped.join(
|
|
8
|
+
"|"
|
|
9
|
+
)})(?![^<>]*>)(?=\\b|[^A-Za-z0-9])`,
|
|
10
|
+
"gi"
|
|
11
|
+
);
|
|
12
|
+
};
|
package/LICENSE
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
Copyright (c) 2020, Salesforce.com, Inc.
|
|
2
|
-
All rights reserved.
|
|
3
|
-
|
|
4
|
-
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
5
|
-
|
|
6
|
-
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
7
|
-
|
|
8
|
-
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
9
|
-
|
|
10
|
-
* Neither the name of Salesforce.com nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
11
|
-
|
|
12
|
-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|