@salesforcedevs/dx-components 0.10.1-alpha.142 → 0.10.1-alpha.146
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 +1 -1
- package/src/modules/dx/codeBlock/codeBlock.ts +27 -27
- package/src/modules/dx/sidebar/__tests__/sidebar.test.ts +99 -175
- package/src/modules/dx/sidebar/sidebar.ts +2 -1
- package/src/modules/dx/sidebarSearch/sidebarSearch.ts +34 -30
- package/src/modules/dx/treeTile/__tests__/treeTile.test.ts +26 -37
- package/src/modules/utils/coveo/coveo.ts +1 -1
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { LightningElement, api, track } from "lwc";
|
|
1
|
+
import { LightningElement, api, wire, track } from "lwc";
|
|
2
2
|
import { CodeBlockTheme, CodeBlockLanguage } from "typings/custom";
|
|
3
3
|
import cx from "classnames";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
import Prism from "utils/prismjs";
|
|
5
|
+
import {
|
|
6
|
+
getLocalStorageData,
|
|
7
|
+
setLocalStorageData
|
|
8
|
+
} from "@sfdocs-internal/wires";
|
|
9
9
|
import { track as gtmTrack } from "dx/instrumentation";
|
|
10
10
|
|
|
11
11
|
// Used por remove enclosing <pre> tag's (if occurs)
|
|
@@ -13,8 +13,8 @@ const preTagRegexp: RegExp = /^<pre.*?>(.*)<\/pre>$/is;
|
|
|
13
13
|
|
|
14
14
|
const LIGHT = "light";
|
|
15
15
|
const DARK = "dark";
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
const themes: CodeBlockTheme[] = [LIGHT, DARK];
|
|
17
|
+
const LOCAL_STORAGE_KEY = "dx-codeblock-theme";
|
|
18
18
|
|
|
19
19
|
export default class CodeBlock extends LightningElement {
|
|
20
20
|
@api defaultTheme: CodeBlockTheme = LIGHT;
|
|
@@ -56,9 +56,10 @@ export default class CodeBlock extends LightningElement {
|
|
|
56
56
|
set codeBlock(value: string) {
|
|
57
57
|
this._codeBlockRendered = false;
|
|
58
58
|
let match;
|
|
59
|
-
this._codeBlock = (
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
this._codeBlock = (
|
|
60
|
+
(match = preTagRegexp.exec(value.trim())) === null
|
|
61
|
+
? value.trim()
|
|
62
|
+
: match[1]
|
|
62
63
|
).trim();
|
|
63
64
|
}
|
|
64
65
|
|
|
@@ -68,17 +69,17 @@ export default class CodeBlock extends LightningElement {
|
|
|
68
69
|
|
|
69
70
|
@track private theme: CodeBlockTheme | null = null;
|
|
70
71
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
72
|
+
@wire(getLocalStorageData, { key: "dx-codeblock-theme" })
|
|
73
|
+
updateThemeForCodeblock(value: any) {
|
|
74
|
+
if (themes.includes(value)) {
|
|
75
|
+
this.theme = value;
|
|
76
|
+
} else {
|
|
77
|
+
setLocalStorageData(
|
|
78
|
+
LOCAL_STORAGE_KEY,
|
|
79
|
+
this.theme || this.defaultTheme
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
82
83
|
|
|
83
84
|
get updateThemeBtnText(): string {
|
|
84
85
|
return `Switch to ${this.theme === DARK ? "Light" : "Dark"} mode`;
|
|
@@ -133,7 +134,7 @@ export default class CodeBlock extends LightningElement {
|
|
|
133
134
|
// eslint-disable-next-line
|
|
134
135
|
codeBlockEl.innerHTML = "";
|
|
135
136
|
codeBlockEl.appendChild(codeEl);
|
|
136
|
-
|
|
137
|
+
Prism.highlightAllUnder(codeBlockEl);
|
|
137
138
|
});
|
|
138
139
|
|
|
139
140
|
if (divEl) {
|
|
@@ -173,9 +174,8 @@ export default class CodeBlock extends LightningElement {
|
|
|
173
174
|
});
|
|
174
175
|
|
|
175
176
|
try {
|
|
176
|
-
const snippetContainer: HTMLElement | null =
|
|
177
|
-
".code-block-content"
|
|
178
|
-
);
|
|
177
|
+
const snippetContainer: HTMLElement | null =
|
|
178
|
+
this.template.querySelector(".code-block-content");
|
|
179
179
|
if (snippetContainer && snippetContainer.textContent) {
|
|
180
180
|
await navigator.clipboard.writeText(
|
|
181
181
|
snippetContainer.textContent
|
|
@@ -192,7 +192,7 @@ export default class CodeBlock extends LightningElement {
|
|
|
192
192
|
|
|
193
193
|
updateTheme(event: any) {
|
|
194
194
|
this.theme = this.theme === DARK ? LIGHT : DARK;
|
|
195
|
-
|
|
195
|
+
setLocalStorageData(LOCAL_STORAGE_KEY, this.theme);
|
|
196
196
|
|
|
197
197
|
gtmTrack(event.target, "custEv_codeBlock", {
|
|
198
198
|
codeBlockAction: this.theme === DARK ? "darkmode" : "lightmode"
|
|
@@ -5,6 +5,7 @@ import Sidebar from "dx/sidebar";
|
|
|
5
5
|
import Tree from "dx/tree";
|
|
6
6
|
import { createMediaMock } from "utils/jest";
|
|
7
7
|
import { createRenderComponent } from "utils/tests";
|
|
8
|
+
import { coveoXMLDocsConfig } from "utils/coveo";
|
|
8
9
|
import { SAMPLE_TREES } from "./mockProps";
|
|
9
10
|
|
|
10
11
|
jest.mock("dx/instrumentation");
|
|
@@ -28,38 +29,31 @@ describe(TAG, () => {
|
|
|
28
29
|
const expectedTitle = "Super cool title";
|
|
29
30
|
const component = renderComponent({
|
|
30
31
|
header: expectedTitle,
|
|
31
|
-
trees: SAMPLE_TREES
|
|
32
|
+
trees: SAMPLE_TREES,
|
|
33
|
+
...coveoXMLDocsConfig
|
|
32
34
|
});
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const container: HTMLElement = component.shadowRoot.querySelector(
|
|
37
|
-
".container"
|
|
38
|
-
);
|
|
36
|
+
const container: HTMLElement =
|
|
37
|
+
component.shadowRoot.querySelector(".container");
|
|
39
38
|
expect(container).not.toBeNull();
|
|
40
39
|
expect(container.classList).not.toContain(COLLAPSED_CLASS);
|
|
41
40
|
|
|
42
|
-
const headerTitle: HTMLElement =
|
|
43
|
-
".header h2"
|
|
44
|
-
);
|
|
41
|
+
const headerTitle: HTMLElement =
|
|
42
|
+
component.shadowRoot.querySelector(".header h2");
|
|
45
43
|
expect(headerTitle).not.toBeNull();
|
|
46
44
|
expect(headerTitle.textContent).toBe(expectedTitle);
|
|
47
45
|
|
|
48
|
-
const collapseButton: Button =
|
|
49
|
-
"dx-button"
|
|
50
|
-
);
|
|
46
|
+
const collapseButton: Button =
|
|
47
|
+
component.shadowRoot.querySelector("dx-button");
|
|
51
48
|
expect(collapseButton).not.toBeNull();
|
|
52
49
|
expect(collapseButton.iconSymbol).toBe("close_panel");
|
|
53
50
|
|
|
54
|
-
const
|
|
55
|
-
"dx-
|
|
56
|
-
);
|
|
57
|
-
expect(searchBox).not.toBeNull();
|
|
58
|
-
expect(searchBox.value).toBe("");
|
|
51
|
+
const search: Input =
|
|
52
|
+
component.shadowRoot.querySelector("dx-sidebar-search");
|
|
53
|
+
expect(search).not.toBeNull();
|
|
59
54
|
|
|
60
|
-
const trees: Array<Tree> =
|
|
61
|
-
"dx-tree"
|
|
62
|
-
);
|
|
55
|
+
const trees: Array<Tree> =
|
|
56
|
+
component.shadowRoot.querySelectorAll("dx-tree");
|
|
63
57
|
expect(trees).toHaveLength(SAMPLE_TREES.length);
|
|
64
58
|
trees.forEach((tree, index) =>
|
|
65
59
|
expect(tree.treeRoot).toHaveProperty(
|
|
@@ -89,38 +83,31 @@ describe(TAG, () => {
|
|
|
89
83
|
const expectedTitle = "Other super cool title";
|
|
90
84
|
const component = renderComponent({
|
|
91
85
|
header: expectedTitle,
|
|
92
|
-
trees: JSON.stringify(SAMPLE_TREES)
|
|
86
|
+
trees: JSON.stringify(SAMPLE_TREES),
|
|
87
|
+
...coveoXMLDocsConfig
|
|
93
88
|
});
|
|
94
89
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const container: HTMLElement = component.shadowRoot.querySelector(
|
|
98
|
-
".container"
|
|
99
|
-
);
|
|
90
|
+
const container: HTMLElement =
|
|
91
|
+
component.shadowRoot.querySelector(".container");
|
|
100
92
|
expect(container).not.toBeNull();
|
|
101
93
|
expect(container.classList).not.toContain(COLLAPSED_CLASS);
|
|
102
94
|
|
|
103
|
-
const headerTitle: HTMLElement =
|
|
104
|
-
".header h2"
|
|
105
|
-
);
|
|
95
|
+
const headerTitle: HTMLElement =
|
|
96
|
+
component.shadowRoot.querySelector(".header h2");
|
|
106
97
|
expect(headerTitle).not.toBeNull();
|
|
107
98
|
expect(headerTitle.textContent).toBe(expectedTitle);
|
|
108
99
|
|
|
109
|
-
const collapseButton: Button =
|
|
110
|
-
"dx-button"
|
|
111
|
-
);
|
|
100
|
+
const collapseButton: Button =
|
|
101
|
+
component.shadowRoot.querySelector("dx-button");
|
|
112
102
|
expect(collapseButton).not.toBeNull();
|
|
113
103
|
expect(collapseButton.iconSymbol).toBe("close_panel");
|
|
114
104
|
|
|
115
|
-
const
|
|
116
|
-
"dx-
|
|
117
|
-
);
|
|
118
|
-
expect(searchBox).not.toBeNull();
|
|
119
|
-
expect(searchBox.value).toBe("");
|
|
105
|
+
const search: Input =
|
|
106
|
+
component.shadowRoot.querySelector("dx-sidebar-search");
|
|
107
|
+
expect(search).not.toBeNull();
|
|
120
108
|
|
|
121
|
-
const trees: Array<Tree> =
|
|
122
|
-
"dx-tree"
|
|
123
|
-
);
|
|
109
|
+
const trees: Array<Tree> =
|
|
110
|
+
component.shadowRoot.querySelectorAll("dx-tree");
|
|
124
111
|
expect(trees).toHaveLength(SAMPLE_TREES.length);
|
|
125
112
|
trees.forEach((tree, index) =>
|
|
126
113
|
expect(tree.treeRoot).toHaveProperty(
|
|
@@ -138,12 +125,12 @@ describe(TAG, () => {
|
|
|
138
125
|
const component = renderComponent({
|
|
139
126
|
header: "Non visible title",
|
|
140
127
|
trees: SAMPLE_TREES,
|
|
141
|
-
value: testValue
|
|
128
|
+
value: testValue,
|
|
129
|
+
...coveoXMLDocsConfig
|
|
142
130
|
});
|
|
143
131
|
|
|
144
|
-
const trees: Array<Tree> =
|
|
145
|
-
"dx-tree"
|
|
146
|
-
);
|
|
132
|
+
const trees: Array<Tree> =
|
|
133
|
+
component.shadowRoot.querySelectorAll("dx-tree");
|
|
147
134
|
|
|
148
135
|
expect(trees).toHaveLength(SAMPLE_TREES.length);
|
|
149
136
|
trees.forEach((tree) => expect(tree.value).toBe(testValue));
|
|
@@ -156,15 +143,14 @@ describe(TAG, () => {
|
|
|
156
143
|
it("should expand/collapse sidebar when toggle button is clicked", () => {
|
|
157
144
|
const component = renderComponent({
|
|
158
145
|
header: "Cool Title",
|
|
159
|
-
trees: SAMPLE_TREES
|
|
146
|
+
trees: SAMPLE_TREES,
|
|
147
|
+
...coveoXMLDocsConfig
|
|
160
148
|
});
|
|
161
149
|
|
|
162
|
-
const container: HTMLElement =
|
|
163
|
-
".container"
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
"dx-button"
|
|
167
|
-
);
|
|
150
|
+
const container: HTMLElement =
|
|
151
|
+
component.shadowRoot.querySelector(".container");
|
|
152
|
+
const toggleButton: HTMLElement =
|
|
153
|
+
component.shadowRoot.querySelector("dx-button");
|
|
168
154
|
toggleButton.click();
|
|
169
155
|
|
|
170
156
|
expect(track).toBeCalledTimes(1);
|
|
@@ -177,26 +163,10 @@ describe(TAG, () => {
|
|
|
177
163
|
.then(() => {
|
|
178
164
|
expect(container.classList).toContain(COLLAPSED_CLASS);
|
|
179
165
|
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
);
|
|
183
|
-
expect(headerTitle).toBeNull();
|
|
184
|
-
|
|
185
|
-
const expandButton: Button = component.shadowRoot.querySelector(
|
|
186
|
-
"dx-button"
|
|
187
|
-
);
|
|
166
|
+
const expandButton: Button =
|
|
167
|
+
component.shadowRoot.querySelector("dx-button");
|
|
188
168
|
expect(expandButton).not.toBeNull();
|
|
189
169
|
|
|
190
|
-
const searchBox: Input = component.shadowRoot.querySelector(
|
|
191
|
-
"dx-input"
|
|
192
|
-
);
|
|
193
|
-
expect(searchBox).toBeNull();
|
|
194
|
-
|
|
195
|
-
const trees: Tree = component.shadowRoot.querySelector(
|
|
196
|
-
"dx-tree"
|
|
197
|
-
);
|
|
198
|
-
expect(trees).toBeNull();
|
|
199
|
-
|
|
200
170
|
toggleButton.click();
|
|
201
171
|
|
|
202
172
|
expect(track).toBeCalledTimes(2);
|
|
@@ -214,21 +184,6 @@ describe(TAG, () => {
|
|
|
214
184
|
COLLAPSED_CLASS
|
|
215
185
|
);
|
|
216
186
|
|
|
217
|
-
const headerTitle: HTMLElement = component.shadowRoot.querySelector(
|
|
218
|
-
".header h2"
|
|
219
|
-
);
|
|
220
|
-
expect(headerTitle).not.toBeNull();
|
|
221
|
-
|
|
222
|
-
const searchBox: Input = component.shadowRoot.querySelector(
|
|
223
|
-
"dx-input"
|
|
224
|
-
);
|
|
225
|
-
expect(searchBox).not.toBeNull();
|
|
226
|
-
|
|
227
|
-
const trees: Tree = component.shadowRoot.querySelector(
|
|
228
|
-
"dx-tree"
|
|
229
|
-
);
|
|
230
|
-
expect(trees).not.toBeNull();
|
|
231
|
-
|
|
232
187
|
return expect(component).toBeAccessible();
|
|
233
188
|
});
|
|
234
189
|
});
|
|
@@ -236,15 +191,14 @@ describe(TAG, () => {
|
|
|
236
191
|
it("should make hover effect on toggle button hover", () => {
|
|
237
192
|
const component = renderComponent({
|
|
238
193
|
header: "Cool Title",
|
|
239
|
-
trees: SAMPLE_TREES
|
|
194
|
+
trees: SAMPLE_TREES,
|
|
195
|
+
...coveoXMLDocsConfig
|
|
240
196
|
});
|
|
241
197
|
|
|
242
|
-
const container: HTMLElement =
|
|
243
|
-
".container"
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
"dx-button"
|
|
247
|
-
);
|
|
198
|
+
const container: HTMLElement =
|
|
199
|
+
component.shadowRoot.querySelector(".container");
|
|
200
|
+
const toggleButton: Button =
|
|
201
|
+
component.shadowRoot.querySelector("dx-button");
|
|
248
202
|
|
|
249
203
|
expect(container.classList).not.toContain(
|
|
250
204
|
"container-border-active"
|
|
@@ -283,42 +237,14 @@ describe(TAG, () => {
|
|
|
283
237
|
|
|
284
238
|
describe("render", () => {
|
|
285
239
|
it("should render as collapsed", () => {
|
|
286
|
-
const expectedTitle = SAMPLE_TREES[0].label;
|
|
287
240
|
const component = renderComponent({
|
|
288
|
-
trees: SAMPLE_TREES
|
|
241
|
+
trees: SAMPLE_TREES,
|
|
242
|
+
...coveoXMLDocsConfig
|
|
289
243
|
});
|
|
290
244
|
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
);
|
|
294
|
-
expect(headerTitle).not.toBeNull();
|
|
295
|
-
expect(headerTitle.textContent).toBe(expectedTitle);
|
|
296
|
-
|
|
297
|
-
const headerIcon = component.shadowRoot.querySelector(
|
|
298
|
-
".header .header-toggle-icon dx-icon"
|
|
299
|
-
);
|
|
300
|
-
expect(headerIcon).not.toBeNull();
|
|
301
|
-
|
|
302
|
-
const searchBox: Input = component.shadowRoot.querySelector(
|
|
303
|
-
"dx-input"
|
|
304
|
-
);
|
|
305
|
-
expect(searchBox).toBeNull();
|
|
306
|
-
|
|
307
|
-
const trees: Tree = component.shadowRoot.querySelector(
|
|
308
|
-
"dx-tree"
|
|
309
|
-
);
|
|
310
|
-
expect(trees).toBeNull();
|
|
311
|
-
|
|
312
|
-
// Desktop specific elements should not render
|
|
313
|
-
const headerTitleDesktop = component.shadowRoot.querySelector(
|
|
314
|
-
".header h2.header-title"
|
|
315
|
-
);
|
|
316
|
-
expect(headerTitleDesktop).toBeNull();
|
|
317
|
-
|
|
318
|
-
const toggleButtonDesktop = component.shadowRoot.querySelector(
|
|
319
|
-
"dx-button.header-toggle-button"
|
|
320
|
-
);
|
|
321
|
-
expect(toggleButtonDesktop).toBeNull();
|
|
245
|
+
const container: HTMLElement =
|
|
246
|
+
component.shadowRoot.querySelector(".container");
|
|
247
|
+
expect(container.classList).toContain(COLLAPSED_CLASS);
|
|
322
248
|
|
|
323
249
|
expect(window.matchMedia).toBeCalledTimes(1);
|
|
324
250
|
expect(window.matchMedia).toBeCalledWith(EXPECTED_QUERY);
|
|
@@ -329,17 +255,18 @@ describe(TAG, () => {
|
|
|
329
255
|
it("should ignore null values for trees api", () => {
|
|
330
256
|
const component = renderComponent({
|
|
331
257
|
header: "Cool Title",
|
|
332
|
-
trees: null
|
|
258
|
+
trees: null,
|
|
259
|
+
...coveoXMLDocsConfig
|
|
333
260
|
});
|
|
334
261
|
|
|
335
|
-
const tree: Tree =
|
|
336
|
-
"dx-tree"
|
|
337
|
-
);
|
|
262
|
+
const tree: Tree =
|
|
263
|
+
component.shadowRoot.querySelector("dx-tree");
|
|
338
264
|
expect(tree).toBeNull();
|
|
339
265
|
|
|
340
|
-
const headerTitle: HTMLElement =
|
|
341
|
-
|
|
342
|
-
|
|
266
|
+
const headerTitle: HTMLElement =
|
|
267
|
+
component.shadowRoot.querySelector(
|
|
268
|
+
".header span.header-title"
|
|
269
|
+
);
|
|
343
270
|
expect(headerTitle).not.toBeNull();
|
|
344
271
|
expect(headerTitle.textContent).toBe("");
|
|
345
272
|
});
|
|
@@ -349,15 +276,14 @@ describe(TAG, () => {
|
|
|
349
276
|
it("should expand/collapse sidebar when mobile toggle is clicked", () => {
|
|
350
277
|
const expectedTitle = SAMPLE_TREES[0].label;
|
|
351
278
|
const component = renderComponent({
|
|
352
|
-
trees: SAMPLE_TREES
|
|
279
|
+
trees: SAMPLE_TREES,
|
|
280
|
+
...coveoXMLDocsConfig
|
|
353
281
|
});
|
|
354
282
|
|
|
355
|
-
const container: HTMLElement =
|
|
356
|
-
".container"
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
"div.header"
|
|
360
|
-
);
|
|
283
|
+
const container: HTMLElement =
|
|
284
|
+
component.shadowRoot.querySelector(".container");
|
|
285
|
+
const toggleDiv: HTMLElement =
|
|
286
|
+
component.shadowRoot.querySelector("div.header");
|
|
361
287
|
toggleDiv.click();
|
|
362
288
|
|
|
363
289
|
expect(track).toBeCalledTimes(1);
|
|
@@ -371,9 +297,10 @@ describe(TAG, () => {
|
|
|
371
297
|
expect(container.classList).not.toContain(
|
|
372
298
|
COLLAPSED_CLASS
|
|
373
299
|
);
|
|
374
|
-
const headerTitle: HTMLElement =
|
|
375
|
-
|
|
376
|
-
|
|
300
|
+
const headerTitle: HTMLElement =
|
|
301
|
+
component.shadowRoot.querySelector(
|
|
302
|
+
".header span.header-title"
|
|
303
|
+
);
|
|
377
304
|
expect(headerTitle).not.toBeNull();
|
|
378
305
|
expect(headerTitle.textContent).toBe(expectedTitle);
|
|
379
306
|
|
|
@@ -382,15 +309,14 @@ describe(TAG, () => {
|
|
|
382
309
|
);
|
|
383
310
|
expect(headerIcon).not.toBeNull();
|
|
384
311
|
|
|
385
|
-
const
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
expect(
|
|
312
|
+
const search: HTMLElement =
|
|
313
|
+
component.shadowRoot.querySelector(
|
|
314
|
+
"dx-sidebar-search"
|
|
315
|
+
);
|
|
316
|
+
expect(search).not.toBeNull();
|
|
390
317
|
|
|
391
|
-
const trees: Array<Tree> =
|
|
392
|
-
"dx-tree"
|
|
393
|
-
);
|
|
318
|
+
const trees: Array<Tree> =
|
|
319
|
+
component.shadowRoot.querySelectorAll("dx-tree");
|
|
394
320
|
expect(trees).toHaveLength(SAMPLE_TREES.length);
|
|
395
321
|
trees.forEach((tree, index) =>
|
|
396
322
|
expect(tree.treeRoot).toHaveProperty(
|
|
@@ -400,14 +326,16 @@ describe(TAG, () => {
|
|
|
400
326
|
);
|
|
401
327
|
|
|
402
328
|
// Desktop specific elements should not render
|
|
403
|
-
const headerTitleDesktop =
|
|
404
|
-
|
|
405
|
-
|
|
329
|
+
const headerTitleDesktop =
|
|
330
|
+
component.shadowRoot.querySelector(
|
|
331
|
+
".header h2.header-title"
|
|
332
|
+
);
|
|
406
333
|
expect(headerTitleDesktop).toBeNull();
|
|
407
334
|
|
|
408
|
-
const toggleButtonDesktop =
|
|
409
|
-
|
|
410
|
-
|
|
335
|
+
const toggleButtonDesktop =
|
|
336
|
+
component.shadowRoot.querySelector(
|
|
337
|
+
"dx-button.header-toggle-button"
|
|
338
|
+
);
|
|
411
339
|
expect(toggleButtonDesktop).toBeNull();
|
|
412
340
|
|
|
413
341
|
toggleDiv.click();
|
|
@@ -433,12 +361,12 @@ describe(TAG, () => {
|
|
|
433
361
|
const defaultTitle = SAMPLE_TREES[0].label;
|
|
434
362
|
const itemToSelect = SAMPLE_TREES[0].children![2];
|
|
435
363
|
const component = renderComponent({
|
|
436
|
-
trees: SAMPLE_TREES
|
|
364
|
+
trees: SAMPLE_TREES,
|
|
365
|
+
...coveoXMLDocsConfig
|
|
437
366
|
});
|
|
438
367
|
|
|
439
|
-
const toggleDiv: HTMLElement =
|
|
440
|
-
"div.header"
|
|
441
|
-
);
|
|
368
|
+
const toggleDiv: HTMLElement =
|
|
369
|
+
component.shadowRoot.querySelector("div.header");
|
|
442
370
|
const headerTitle: HTMLElement = toggleDiv.querySelector(
|
|
443
371
|
".header span.header-title"
|
|
444
372
|
)!;
|
|
@@ -450,9 +378,8 @@ describe(TAG, () => {
|
|
|
450
378
|
expect(headerTitle).not.toBeNull();
|
|
451
379
|
expect(headerTitle.textContent).toBe(defaultTitle);
|
|
452
380
|
|
|
453
|
-
const tree: Tree =
|
|
454
|
-
"dx-tree"
|
|
455
|
-
);
|
|
381
|
+
const tree: Tree =
|
|
382
|
+
component.shadowRoot.querySelector("dx-tree");
|
|
456
383
|
tree.dispatchEvent(
|
|
457
384
|
new CustomEvent("select", {
|
|
458
385
|
detail: { name: itemToSelect.name }
|
|
@@ -475,12 +402,12 @@ describe(TAG, () => {
|
|
|
475
402
|
const [expectedTree] = SAMPLE_TREES;
|
|
476
403
|
const component = renderComponent({
|
|
477
404
|
header: "Cool Title",
|
|
478
|
-
trees: expectedTree
|
|
405
|
+
trees: expectedTree,
|
|
406
|
+
...coveoXMLDocsConfig
|
|
479
407
|
});
|
|
480
408
|
|
|
481
|
-
const trees: Array<Tree> =
|
|
482
|
-
"dx-tree"
|
|
483
|
-
);
|
|
409
|
+
const trees: Array<Tree> =
|
|
410
|
+
component.shadowRoot.querySelectorAll("dx-tree");
|
|
484
411
|
expect(trees).toHaveLength(1);
|
|
485
412
|
|
|
486
413
|
const [singleTree] = trees;
|
|
@@ -498,14 +425,14 @@ describe(TAG, () => {
|
|
|
498
425
|
|
|
499
426
|
const component = renderComponent({
|
|
500
427
|
header: "Cool Title",
|
|
501
|
-
trees: SAMPLE_TREES
|
|
428
|
+
trees: SAMPLE_TREES,
|
|
429
|
+
...coveoXMLDocsConfig
|
|
502
430
|
});
|
|
503
431
|
|
|
504
432
|
component.addEventListener("select", mockSelect);
|
|
505
433
|
|
|
506
|
-
const tree: Tree =
|
|
507
|
-
"dx-tree"
|
|
508
|
-
);
|
|
434
|
+
const tree: Tree =
|
|
435
|
+
component.shadowRoot.querySelector("dx-tree");
|
|
509
436
|
expect(tree).not.toBeNull();
|
|
510
437
|
expect(tree.value).toBeUndefined();
|
|
511
438
|
|
|
@@ -520,11 +447,8 @@ describe(TAG, () => {
|
|
|
520
447
|
return Promise.resolve().then(() => {
|
|
521
448
|
expect(tree.value).toBe(expectedName);
|
|
522
449
|
expect(mockSelect).toBeCalledTimes(1);
|
|
523
|
-
const {
|
|
524
|
-
|
|
525
|
-
composed,
|
|
526
|
-
bubbles
|
|
527
|
-
} = mockSelect.mock.calls[0][0];
|
|
450
|
+
const { detail, composed, bubbles } =
|
|
451
|
+
mockSelect.mock.calls[0][0];
|
|
528
452
|
expect(detail).toEqual({
|
|
529
453
|
name: expectedName
|
|
530
454
|
});
|
|
@@ -48,7 +48,7 @@ export default class Sidebar extends LightningElement {
|
|
|
48
48
|
setInputValue(searchTerm: string) {
|
|
49
49
|
this.template
|
|
50
50
|
.querySelector("dx-sidebar-search")
|
|
51
|
-
|
|
51
|
+
?.setInputValue(searchTerm);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
private expanded: boolean = true;
|
|
@@ -189,6 +189,7 @@ export default class Sidebar extends LightningElement {
|
|
|
189
189
|
private onSearchChange(e: CustomEvent) {
|
|
190
190
|
this.requestedFetchMoreResults = false;
|
|
191
191
|
this.searchResults = e.detail.results;
|
|
192
|
+
console.log(this.searchResults);
|
|
192
193
|
this.searchValue = e.detail.value;
|
|
193
194
|
}
|
|
194
195
|
|
|
@@ -36,7 +36,7 @@ export default class SidebarSearch extends LightningElement {
|
|
|
36
36
|
get coveoAdvancedQueryConfig(): { [key: string]: any } {
|
|
37
37
|
return this._coveoAdvancedQueryConfig;
|
|
38
38
|
}
|
|
39
|
-
set coveoAdvancedQueryConfig(value
|
|
39
|
+
set coveoAdvancedQueryConfig(value) {
|
|
40
40
|
const jsonValue = toJson(value);
|
|
41
41
|
const hasChanged =
|
|
42
42
|
this._coveoAdvancedQueryConfig &&
|
|
@@ -50,7 +50,7 @@ export default class SidebarSearch extends LightningElement {
|
|
|
50
50
|
// set adnvanced filters needs access to the latest coveoAdvancedQueryConfig
|
|
51
51
|
this.dispatchOnLoading(true);
|
|
52
52
|
this.setAdvancedFilters(this.engine);
|
|
53
|
-
this.submitSearch();
|
|
53
|
+
this.submitSearch(true);
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -65,6 +65,7 @@ export default class SidebarSearch extends LightningElement {
|
|
|
65
65
|
@api
|
|
66
66
|
setInputValue(searchTerm: string) {
|
|
67
67
|
this.value = searchTerm || "";
|
|
68
|
+
this.handleValueChange(true);
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
private _coveoAdvancedQueryConfig!: { [key: string]: any };
|
|
@@ -154,10 +155,6 @@ export default class SidebarSearch extends LightningElement {
|
|
|
154
155
|
);
|
|
155
156
|
const hasSameQuery = json?.state?.query?.q === this.value;
|
|
156
157
|
if (hasSameConfig && hasSameQuery) {
|
|
157
|
-
console.log(
|
|
158
|
-
"valid session storage found for value =",
|
|
159
|
-
this.value
|
|
160
|
-
);
|
|
161
158
|
this.preloadedState = json?.state;
|
|
162
159
|
} else {
|
|
163
160
|
window.sessionStorage.removeItem(SESSION_KEY);
|
|
@@ -231,16 +228,10 @@ export default class SidebarSearch extends LightningElement {
|
|
|
231
228
|
|
|
232
229
|
if ((!firstSearchExecuted && !isLoading) || !this.value) {
|
|
233
230
|
// coveo search is firing off some unwanted payloads on startup
|
|
234
|
-
console.log(
|
|
235
|
-
"returning in results list change",
|
|
236
|
-
this.value,
|
|
237
|
-
!firstSearchExecuted && !isLoading
|
|
238
|
-
);
|
|
239
231
|
return;
|
|
240
232
|
}
|
|
241
233
|
|
|
242
234
|
if (!isLoading) {
|
|
243
|
-
console.log("dispatching on change event");
|
|
244
235
|
this.dispatchOnChangeEvent(results);
|
|
245
236
|
}
|
|
246
237
|
|
|
@@ -254,7 +245,6 @@ export default class SidebarSearch extends LightningElement {
|
|
|
254
245
|
};
|
|
255
246
|
|
|
256
247
|
private setAdvancedFilters(engine: SearchEngine) {
|
|
257
|
-
console.log("setting advanced filters");
|
|
258
248
|
const aq = Object.entries(this.coveoAdvancedQueryConfig).reduce(
|
|
259
249
|
(result, [key, value]) =>
|
|
260
250
|
`${result}(@${key}=="${normalizeCoveoAdvancedQueryValue(
|
|
@@ -281,9 +271,14 @@ export default class SidebarSearch extends LightningElement {
|
|
|
281
271
|
titleHighlights,
|
|
282
272
|
uniqueId
|
|
283
273
|
}: Result) => {
|
|
274
|
+
// discussion about this normalization here: https://salesforce-internal.slack.com/archives/C020S6784JX/p1639506238376600
|
|
275
|
+
const extension =
|
|
276
|
+
this.coveoAdvancedQueryConfig.path_segment_4 === "references"
|
|
277
|
+
? ""
|
|
278
|
+
: ".html";
|
|
284
279
|
const pathname = sfhtml_url__c
|
|
285
280
|
? `/docs/${sfhtml_url__c}`
|
|
286
|
-
: `${new URL(clickUri).pathname}
|
|
281
|
+
: `${new URL(clickUri).pathname}${extension}`;
|
|
287
282
|
const href = `${pathname}?q=${this.value}`;
|
|
288
283
|
|
|
289
284
|
return {
|
|
@@ -298,7 +293,6 @@ export default class SidebarSearch extends LightningElement {
|
|
|
298
293
|
};
|
|
299
294
|
|
|
300
295
|
private updateSessionStorage() {
|
|
301
|
-
console.log("updating session storage");
|
|
302
296
|
window.sessionStorage.setItem(
|
|
303
297
|
SESSION_KEY,
|
|
304
298
|
JSON.stringify({
|
|
@@ -321,7 +315,6 @@ export default class SidebarSearch extends LightningElement {
|
|
|
321
315
|
}
|
|
322
316
|
|
|
323
317
|
private dispatchOnLoading(loading: boolean) {
|
|
324
|
-
console.log("dispatching onloading", loading);
|
|
325
318
|
this.dispatchEvent(new CustomEvent("loading", { detail: loading }));
|
|
326
319
|
}
|
|
327
320
|
|
|
@@ -353,11 +346,17 @@ export default class SidebarSearch extends LightningElement {
|
|
|
353
346
|
);
|
|
354
347
|
}
|
|
355
348
|
|
|
356
|
-
private submitSearch = debounce(() => {
|
|
349
|
+
private submitSearch = debounce((isSyncingSearchValue = false) => {
|
|
357
350
|
if (this.searchBox) {
|
|
358
351
|
UserRecentSearches.add(this.value);
|
|
359
352
|
this.updateRecentSearches();
|
|
360
353
|
|
|
354
|
+
// When `isSyncingSearchValue` is true, we are submitting in a case
|
|
355
|
+
// where the search box is already synced correctly.
|
|
356
|
+
if (!isSyncingSearchValue) {
|
|
357
|
+
this.dispatchSidebarSearchChange(this.value);
|
|
358
|
+
}
|
|
359
|
+
|
|
361
360
|
this.searchBox.updateText(this.value || "");
|
|
362
361
|
this.searchBox.submit();
|
|
363
362
|
}
|
|
@@ -366,7 +365,7 @@ export default class SidebarSearch extends LightningElement {
|
|
|
366
365
|
private onClickRecentSearch(e: CustomEvent) {
|
|
367
366
|
this.value = e.detail;
|
|
368
367
|
this.dispatchSidebarSearchChange(this.value);
|
|
369
|
-
this.submitSearch();
|
|
368
|
+
this.submitSearch(true);
|
|
370
369
|
}
|
|
371
370
|
|
|
372
371
|
private onDropdownRequestClose(e: CustomEvent) {
|
|
@@ -383,27 +382,32 @@ export default class SidebarSearch extends LightningElement {
|
|
|
383
382
|
private onInputChange(e: CustomEvent) {
|
|
384
383
|
this.value = e.detail;
|
|
385
384
|
|
|
385
|
+
this.handleValueChange(false);
|
|
386
|
+
this.dispatchHighlightedTermChange();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
private onInputFocus() {
|
|
390
|
+
this.dropdownRequestedOpen = true;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
private onInputClear() {
|
|
394
|
+
this.dropdownRequestedOpen = false;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
private handleValueChange(isSyncingSearchValue = false) {
|
|
386
398
|
if (this.value) {
|
|
387
399
|
this.dispatchOnLoading(true);
|
|
388
400
|
if (this.searchBox) {
|
|
389
|
-
this.submitSearch();
|
|
401
|
+
this.submitSearch(isSyncingSearchValue);
|
|
390
402
|
}
|
|
391
403
|
} else {
|
|
392
404
|
// coveo's reaction to an empty value triggers a return of results
|
|
393
405
|
// bootlegging our own ux here`
|
|
394
406
|
this.dispatchOnLoading(false);
|
|
395
407
|
this.dispatchOnChangeEvent([]);
|
|
408
|
+
// Empty search values are not submitted for search, so we need to manually
|
|
409
|
+
// trigger a search change on our own here
|
|
410
|
+
this.dispatchSidebarSearchChange(this.value);
|
|
396
411
|
}
|
|
397
|
-
|
|
398
|
-
this.dispatchHighlightedTermChange();
|
|
399
|
-
this.dispatchSidebarSearchChange(this.value);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
private onInputFocus() {
|
|
403
|
-
this.dropdownRequestedOpen = true;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
private onInputClear() {
|
|
407
|
-
this.dropdownRequestedOpen = false;
|
|
408
412
|
}
|
|
409
413
|
}
|
|
@@ -24,23 +24,20 @@ describe(TAG, () => {
|
|
|
24
24
|
describe("render", () => {
|
|
25
25
|
it("should render as a leaf tile", () => {
|
|
26
26
|
const component = render({ treeNode: SINGLE_NODE, href: "/test" });
|
|
27
|
-
const tileAnchor: HTMLElement =
|
|
28
|
-
"a.tile"
|
|
29
|
-
);
|
|
27
|
+
const tileAnchor: HTMLElement =
|
|
28
|
+
component.shadowRoot.querySelector("a.tile");
|
|
30
29
|
|
|
31
30
|
expect(tileAnchor.getAttribute("href")).toBe("/test");
|
|
32
|
-
expect(tileAnchor.classList).toHaveLength(
|
|
31
|
+
expect(tileAnchor.classList).toHaveLength(2);
|
|
33
32
|
expect(tileAnchor).not.toBeNull();
|
|
34
33
|
assertLevelAndLabel(tileAnchor);
|
|
35
34
|
|
|
36
|
-
const arrowIcon: Icon =
|
|
37
|
-
"dx-icon"
|
|
38
|
-
);
|
|
35
|
+
const arrowIcon: Icon =
|
|
36
|
+
component.shadowRoot.querySelector("dx-icon");
|
|
39
37
|
expect(arrowIcon).toBeNull();
|
|
40
38
|
|
|
41
|
-
const typeBadge =
|
|
42
|
-
"dx-type-badge"
|
|
43
|
-
);
|
|
39
|
+
const typeBadge =
|
|
40
|
+
component.shadowRoot.querySelector("dx-type-badge");
|
|
44
41
|
expect(typeBadge).toBeNull();
|
|
45
42
|
|
|
46
43
|
return expect(component).toBeAccessible();
|
|
@@ -52,23 +49,20 @@ describe(TAG, () => {
|
|
|
52
49
|
isRoot: true,
|
|
53
50
|
hasChildren: true
|
|
54
51
|
});
|
|
55
|
-
const tileAnchor: HTMLElement =
|
|
56
|
-
"a.tile.tile-root"
|
|
57
|
-
);
|
|
52
|
+
const tileAnchor: HTMLElement =
|
|
53
|
+
component.shadowRoot.querySelector("a.tile.tile-root");
|
|
58
54
|
expect(tileAnchor).not.toBeNull();
|
|
59
|
-
expect(tileAnchor.classList).toHaveLength(
|
|
55
|
+
expect(tileAnchor.classList).toHaveLength(3);
|
|
60
56
|
assertLevelAndLabel(tileAnchor);
|
|
61
57
|
|
|
62
|
-
const arrowIcon: Icon =
|
|
63
|
-
"dx-icon"
|
|
64
|
-
)!;
|
|
58
|
+
const arrowIcon: Icon =
|
|
59
|
+
component.shadowRoot.querySelector("dx-icon")!;
|
|
65
60
|
expect(arrowIcon).not.toBeNull();
|
|
66
61
|
expect(arrowIcon.getAttribute("aria-expanded")).toBe("false");
|
|
67
62
|
expect(arrowIcon.size).toBe("small");
|
|
68
63
|
|
|
69
|
-
const typeBadge =
|
|
70
|
-
"dx-type-badge"
|
|
71
|
-
);
|
|
64
|
+
const typeBadge =
|
|
65
|
+
component.shadowRoot.querySelector("dx-type-badge");
|
|
72
66
|
expect(typeBadge).toBeNull();
|
|
73
67
|
|
|
74
68
|
return expect(component).toBeAccessible();
|
|
@@ -85,19 +79,17 @@ describe(TAG, () => {
|
|
|
85
79
|
);
|
|
86
80
|
|
|
87
81
|
expect(tileAnchor).not.toBeNull();
|
|
88
|
-
expect(tileAnchor.classList).toHaveLength(
|
|
82
|
+
expect(tileAnchor.classList).toHaveLength(3);
|
|
89
83
|
assertLevelAndLabel(tileAnchor);
|
|
90
84
|
|
|
91
|
-
const arrowIcon: Icon =
|
|
92
|
-
"dx-icon"
|
|
93
|
-
);
|
|
85
|
+
const arrowIcon: Icon =
|
|
86
|
+
component.shadowRoot.querySelector("dx-icon");
|
|
94
87
|
expect(arrowIcon).not.toBeNull();
|
|
95
88
|
expect(arrowIcon.getAttribute("aria-expanded")).toBe("true");
|
|
96
89
|
expect(arrowIcon.size).toBe("xsmall");
|
|
97
90
|
|
|
98
|
-
const typeBadge =
|
|
99
|
-
"dx-type-badge"
|
|
100
|
-
);
|
|
91
|
+
const typeBadge =
|
|
92
|
+
component.shadowRoot.querySelector("dx-type-badge");
|
|
101
93
|
expect(typeBadge).toBeNull();
|
|
102
94
|
|
|
103
95
|
return expect(component).toBeAccessible();
|
|
@@ -112,16 +104,15 @@ describe(TAG, () => {
|
|
|
112
104
|
"a.tile.sidebar-item-selected"
|
|
113
105
|
);
|
|
114
106
|
expect(tileAnchor).not.toBeNull();
|
|
115
|
-
expect(tileAnchor.classList).toHaveLength(
|
|
107
|
+
expect(tileAnchor.classList).toHaveLength(3);
|
|
116
108
|
|
|
117
109
|
return expect(component).toBeAccessible();
|
|
118
110
|
});
|
|
119
111
|
|
|
120
112
|
it("should render a leaf tile with a valid brand method", () => {
|
|
121
113
|
const component = render({ treeNode: SINGLE_NODE_WITH_METHOD });
|
|
122
|
-
const typeBadge =
|
|
123
|
-
"dx-type-badge"
|
|
124
|
-
);
|
|
114
|
+
const typeBadge =
|
|
115
|
+
component.shadowRoot.querySelector("dx-type-badge");
|
|
125
116
|
|
|
126
117
|
expect(typeBadge).not.toBeNull();
|
|
127
118
|
expect(typeBadge.classList).toHaveLength(3);
|
|
@@ -140,9 +131,8 @@ describe(TAG, () => {
|
|
|
140
131
|
const component = render({
|
|
141
132
|
treeNode: { ...SINGLE_NODE_WITH_METHOD, method }
|
|
142
133
|
});
|
|
143
|
-
const typeBadge =
|
|
144
|
-
"dx-type-badge"
|
|
145
|
-
);
|
|
134
|
+
const typeBadge =
|
|
135
|
+
component.shadowRoot.querySelector("dx-type-badge");
|
|
146
136
|
|
|
147
137
|
expect(typeBadge).not.toBeNull();
|
|
148
138
|
expect(typeBadge.classList).toHaveLength(3);
|
|
@@ -163,9 +153,8 @@ describe(TAG, () => {
|
|
|
163
153
|
isExpanded: true
|
|
164
154
|
});
|
|
165
155
|
|
|
166
|
-
const arrowIcon: HTMLElement =
|
|
167
|
-
"dx-icon"
|
|
168
|
-
);
|
|
156
|
+
const arrowIcon: HTMLElement =
|
|
157
|
+
component.shadowRoot.querySelector("dx-icon");
|
|
169
158
|
|
|
170
159
|
const mockIconClick = jest.fn();
|
|
171
160
|
component.addEventListener("iconclick", mockIconClick);
|
|
@@ -43,7 +43,7 @@ export const coveoXMLDocsConfig = {
|
|
|
43
43
|
coveoSearchHub: "Developer_Docs_SS",
|
|
44
44
|
coveoAdvancedQueryConfig: JSON.stringify({
|
|
45
45
|
objecttype: "HTDeveloperDocumentsC",
|
|
46
|
-
|
|
46
|
+
sflocale__c: "en_US",
|
|
47
47
|
sfrelease__c: "232.0",
|
|
48
48
|
sfdelivarable__c: "apexcode"
|
|
49
49
|
})
|