@salesforcedevs/docs-components 1.17.13-table-2 → 1.18.0-search-alpha
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/lwc.config.json +0 -1
- package/package.json +1 -1
- package/src/modules/doc/amfReference/amfReference.html +1 -6
- package/src/modules/doc/amfReference/amfReference.ts +10 -37
- package/src/modules/doc/contentLayout/contentLayout.html +16 -38
- package/src/modules/doc/contentLayout/contentLayout.ts +17 -48
- package/src/modules/doc/lwcContentLayout/lwcContentLayout.html +15 -38
- package/src/modules/doc/lwcContentLayout/lwcContentLayout.ts +103 -15
- package/src/modules/doc/specificationContent/specificationContent.html +2 -6
- package/src/modules/doc/xmlContent/xmlContent.html +0 -6
- package/src/modules/doc/xmlContent/xmlContent.ts +5 -44
- package/src/modules/doc/table/table.css +0 -267
- package/src/modules/doc/table/table.html +0 -46
- package/src/modules/doc/table/table.ts +0 -175
package/lwc.config.json
CHANGED
package/package.json
CHANGED
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<doc-content-layout
|
|
3
3
|
lwc:if={isVersionFetched}
|
|
4
|
-
use-old-sidebar={useOldSidebar}
|
|
5
4
|
class="content-type content-type-reference"
|
|
6
|
-
coveo-organization-id={coveoOrganizationId}
|
|
7
|
-
coveo-public-access-token={coveoPublicAccessToken}
|
|
8
|
-
coveo-analytics-token={coveoAnalyticsToken}
|
|
9
|
-
coveo-search-hub={coveoSearchHub}
|
|
10
|
-
coveo-advanced-query-config={coveoAdvancedQueryConfig}
|
|
11
5
|
breadcrumbs={breadcrumbs}
|
|
12
6
|
sidebar-header={sidebarHeader}
|
|
13
7
|
sidebar-value={selectedSidebarValue}
|
|
@@ -20,6 +14,7 @@
|
|
|
20
14
|
languages={languages}
|
|
21
15
|
language={language}
|
|
22
16
|
show-footer={enableFooter}
|
|
17
|
+
empty-state-message={emptyStateMessage}
|
|
23
18
|
>
|
|
24
19
|
<doc-phase
|
|
25
20
|
slot="doc-phase"
|
|
@@ -3,7 +3,7 @@ import { noCase } from "no-case";
|
|
|
3
3
|
import { sentenceCase } from "sentence-case";
|
|
4
4
|
import qs from "query-string";
|
|
5
5
|
import { AmfModelParser } from "doc/amfModelParser";
|
|
6
|
-
import { normalizeBoolean
|
|
6
|
+
import { normalizeBoolean } from "dxUtils/normalizers";
|
|
7
7
|
import type { OptionWithLink } from "typings/custom";
|
|
8
8
|
import type {
|
|
9
9
|
AmfConfig,
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
} from "./constants";
|
|
29
29
|
import { restoreScroll } from "dx/scrollManager";
|
|
30
30
|
import { DocPhaseInfo } from "typings/custom";
|
|
31
|
-
import {
|
|
31
|
+
import { oldVersionDocInfo } from "docUtils/utils";
|
|
32
32
|
|
|
33
33
|
type NavigationItem = {
|
|
34
34
|
label: string;
|
|
@@ -41,11 +41,6 @@ type NavigationItem = {
|
|
|
41
41
|
export default class AmfReference extends LightningElement {
|
|
42
42
|
@api breadcrumbs: string | null = null;
|
|
43
43
|
@api sidebarHeader!: string;
|
|
44
|
-
@api coveoOrganizationId!: string;
|
|
45
|
-
@api coveoPublicAccessToken!: string;
|
|
46
|
-
@api coveoAnalyticsToken!: string;
|
|
47
|
-
@api coveoSearchHub!: string;
|
|
48
|
-
@api useOldSidebar: boolean = false;
|
|
49
44
|
@api tocTitle?: string;
|
|
50
45
|
@api tocOptions?: string;
|
|
51
46
|
@api languages!: OptionWithLink[];
|
|
@@ -54,7 +49,6 @@ export default class AmfReference extends LightningElement {
|
|
|
54
49
|
@track navigation = [] as NavigationItem[];
|
|
55
50
|
@track versions: Array<ReferenceVersion> = [];
|
|
56
51
|
@track showVersionBanner = false;
|
|
57
|
-
@track _coveoAdvancedQueryConfig!: { [key: string]: any };
|
|
58
52
|
|
|
59
53
|
// Update this to update what component gets rendered in the content block
|
|
60
54
|
@track
|
|
@@ -160,35 +154,18 @@ export default class AmfReference extends LightningElement {
|
|
|
160
154
|
this._expandChildren = normalizeBoolean(value);
|
|
161
155
|
}
|
|
162
156
|
|
|
163
|
-
/*
|
|
164
|
-
* The get coveoAdvancedQueryConfig() method returns this._coveoAdvancedQueryConfig,
|
|
165
|
-
* but before returning it, it checks if there are multiple versions (this.versions.length > 1)
|
|
166
|
-
* and if a version is selected (this.selectedVersion). If both conditions are met,
|
|
167
|
-
* it updates the version property of this._coveoAdvancedQueryConfig with the selected version.
|
|
168
|
-
*/
|
|
169
|
-
@api
|
|
170
|
-
get coveoAdvancedQueryConfig(): { [key: string]: any } {
|
|
171
|
-
const coveoConfig = this._coveoAdvancedQueryConfig;
|
|
172
|
-
if (this.versions.length > 1 && this.selectedVersion) {
|
|
173
|
-
const currentGAVersionRef = this.versions[0];
|
|
174
|
-
if (this.selectedVersion.id !== currentGAVersionRef.id) {
|
|
175
|
-
// Currently Coveo only supports query without "v"
|
|
176
|
-
const version = this.selectedVersion.id.replace("v", "");
|
|
177
|
-
coveoConfig.version = version;
|
|
178
|
-
this._coveoAdvancedQueryConfig = coveoConfig;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
return this._coveoAdvancedQueryConfig;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
set coveoAdvancedQueryConfig(config) {
|
|
185
|
-
this._coveoAdvancedQueryConfig = toJson(config);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
157
|
private get enableFooter(): boolean {
|
|
189
158
|
return !this.hideFooter;
|
|
190
159
|
}
|
|
191
160
|
|
|
161
|
+
private get emptyStateMessage(): string {
|
|
162
|
+
return JSON.stringify([
|
|
163
|
+
"Select a relevant API specification",
|
|
164
|
+
"Please consider misspellings",
|
|
165
|
+
"Try different search keywords"
|
|
166
|
+
]);
|
|
167
|
+
}
|
|
168
|
+
|
|
192
169
|
// model
|
|
193
170
|
protected _amfConfigList: AmfConfig[] = [];
|
|
194
171
|
protected _amfConfigMap: Map<string, AmfConfig> = new Map();
|
|
@@ -1436,10 +1413,6 @@ export default class AmfReference extends LightningElement {
|
|
|
1436
1413
|
metaVal
|
|
1437
1414
|
);
|
|
1438
1415
|
|
|
1439
|
-
logCoveoPageView(
|
|
1440
|
-
this.coveoOrganizationId,
|
|
1441
|
-
this.coveoAnalyticsToken
|
|
1442
|
-
);
|
|
1443
1416
|
this.updateUrlWithSelected(parentReferencePath, metaVal);
|
|
1444
1417
|
this.updateTags(metadata.navTitle);
|
|
1445
1418
|
} else {
|
|
@@ -1,43 +1,21 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="content">
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
</template>
|
|
20
|
-
<template lwc:else>
|
|
21
|
-
<dx-sidebar
|
|
22
|
-
class="is-sticky left-nav-bar"
|
|
23
|
-
trees={sidebarContent}
|
|
24
|
-
value={sidebarValue}
|
|
25
|
-
header={sidebarHeader}
|
|
26
|
-
coveo-organization-id={coveoOrganizationId}
|
|
27
|
-
coveo-public-access-token={coveoPublicAccessToken}
|
|
28
|
-
coveo-search-hub={coveoSearchHub}
|
|
29
|
-
coveo-advanced-query-config={coveoAdvancedQueryConfig}
|
|
30
|
-
ontogglesidebar={onToggleSidebar}
|
|
31
|
-
languages={languages}
|
|
32
|
-
language={language}
|
|
33
|
-
bail-href={bailHref}
|
|
34
|
-
bail-label={bailLabel}
|
|
35
|
-
dev-center={devCenter}
|
|
36
|
-
brand={brand}
|
|
37
|
-
>
|
|
38
|
-
<slot name="sidebar-header" slot="version-picker"></slot>
|
|
39
|
-
</dx-sidebar>
|
|
40
|
-
</template>
|
|
3
|
+
<dx-sidebar-old
|
|
4
|
+
class="is-sticky left-nav-bar"
|
|
5
|
+
trees={sidebarContent}
|
|
6
|
+
value={sidebarValue}
|
|
7
|
+
header={sidebarHeader}
|
|
8
|
+
ontogglesidebar={onToggleSidebar}
|
|
9
|
+
languages={languages}
|
|
10
|
+
language={language}
|
|
11
|
+
bail-href={bailHref}
|
|
12
|
+
bail-label={bailLabel}
|
|
13
|
+
dev-center={devCenter}
|
|
14
|
+
brand={brand}
|
|
15
|
+
empty-state-message={emptyStateMessage}
|
|
16
|
+
>
|
|
17
|
+
<slot name="sidebar-header" slot="version-picker"></slot>
|
|
18
|
+
</dx-sidebar-old>
|
|
41
19
|
<div class="content-body-doc-phase-container">
|
|
42
20
|
<slot name="doc-phase"></slot>
|
|
43
21
|
<slot name="version-banner"></slot>
|
|
@@ -32,11 +32,6 @@ export default class ContentLayout extends LightningElement {
|
|
|
32
32
|
@api sidebarHeader!: string;
|
|
33
33
|
@api tocTitle!: string;
|
|
34
34
|
@api enableSlotChange = false;
|
|
35
|
-
@api coveoOrganizationId!: string;
|
|
36
|
-
@api coveoPublicAccessToken!: string;
|
|
37
|
-
@api coveoAnalyticsToken!: string;
|
|
38
|
-
@api coveoSearchHub!: string;
|
|
39
|
-
@api coveoAdvancedQueryConfig!: string;
|
|
40
35
|
@api useOldSidebar?: boolean = false;
|
|
41
36
|
@api languages!: OptionWithLink[];
|
|
42
37
|
@api language!: string;
|
|
@@ -44,6 +39,7 @@ export default class ContentLayout extends LightningElement {
|
|
|
44
39
|
@api bailLabel!: string;
|
|
45
40
|
@api devCenter: any;
|
|
46
41
|
@api brand: any;
|
|
42
|
+
@api emptyStateMessage?: string;
|
|
47
43
|
|
|
48
44
|
// This is needed for now to prevent failing snapshot tests due to links in the footer
|
|
49
45
|
@api showFooter = false;
|
|
@@ -210,10 +206,7 @@ export default class ContentLayout extends LightningElement {
|
|
|
210
206
|
We have to account for the global nav changing height due to animations.
|
|
211
207
|
*/
|
|
212
208
|
adjustNavPosition = () => {
|
|
213
|
-
const
|
|
214
|
-
? "dx-sidebar-old"
|
|
215
|
-
: "dx-sidebar";
|
|
216
|
-
const sidebarEl = this.template.querySelector(sidebarType);
|
|
209
|
+
const sidebarEl = this.template.querySelector("dx-sidebar-old");
|
|
217
210
|
const globalNavEl = document.querySelector(
|
|
218
211
|
"hgf-c360nav"
|
|
219
212
|
) as HTMLElement;
|
|
@@ -248,65 +241,41 @@ export default class ContentLayout extends LightningElement {
|
|
|
248
241
|
const docHeaderHeight = docHeaderEl.getBoundingClientRect().height;
|
|
249
242
|
const totalHeaderHeight = globalNavHeight + docHeaderHeight;
|
|
250
243
|
|
|
251
|
-
// Collect any banners rendered via the doc-phase and version-banner slots
|
|
252
|
-
const versionBannerSlot = this.template.querySelector(
|
|
253
|
-
"[name=version-banner]"
|
|
254
|
-
) as any;
|
|
255
|
-
const docPhaseSlot = this.template.querySelector(
|
|
256
|
-
"[name=doc-phase]"
|
|
257
|
-
) as any;
|
|
258
|
-
const versionBannerEls = (
|
|
259
|
-
versionBannerSlot
|
|
260
|
-
? (versionBannerSlot.assignedElements() as HTMLElement[])
|
|
261
|
-
: []
|
|
262
|
-
) as HTMLElement[];
|
|
263
|
-
const docPhaseEls = (
|
|
264
|
-
docPhaseSlot
|
|
265
|
-
? (docPhaseSlot.assignedElements() as HTMLElement[])
|
|
266
|
-
: []
|
|
267
|
-
) as HTMLElement[];
|
|
268
|
-
const bannersTotalHeight = [
|
|
269
|
-
...versionBannerEls,
|
|
270
|
-
...docPhaseEls
|
|
271
|
-
].reduce(
|
|
272
|
-
(sum, el) => sum + (el?.getBoundingClientRect()?.height || 0),
|
|
273
|
-
0
|
|
274
|
-
);
|
|
275
|
-
|
|
276
244
|
// Selecting the doc section heading and RNB here.
|
|
277
245
|
const docHeadingEls = Array.from(
|
|
278
246
|
document.querySelectorAll("doc-heading")
|
|
279
247
|
);
|
|
280
248
|
const rightNavBarEl = this.template.querySelector(".right-nav-bar");
|
|
281
249
|
|
|
282
|
-
|
|
250
|
+
sidebarEl.style.setProperty(
|
|
283
251
|
"--dx-c-content-sidebar-sticky-top",
|
|
284
|
-
`${
|
|
252
|
+
`${globalNavHeight + docHeaderHeight}px`
|
|
285
253
|
);
|
|
286
254
|
|
|
287
255
|
docHeaderEl.style.setProperty(
|
|
288
256
|
"--dx-g-global-header-height",
|
|
289
257
|
`${globalNavHeight}px`
|
|
290
258
|
);
|
|
291
|
-
// Expose heights as CSS variables for sticky offsets used by page content
|
|
292
|
-
const rootStyle = document.documentElement.style;
|
|
293
|
-
rootStyle.setProperty(
|
|
294
|
-
"--dx-g-doc-header-banner-height",
|
|
295
|
-
`${docHeaderHeight + bannersTotalHeight}px`
|
|
296
|
-
);
|
|
297
259
|
|
|
298
260
|
// Adjusting the doc section heading on scroll.
|
|
299
261
|
docHeadingEls.forEach((docHeadingEl) => {
|
|
300
|
-
(docHeadingEl as any).style.scrollMarginTop =
|
|
301
|
-
|
|
302
|
-
|
|
262
|
+
(docHeadingEl as any).style.scrollMarginTop = docPhaseEl
|
|
263
|
+
? `${
|
|
264
|
+
totalHeaderHeight +
|
|
265
|
+
docPhaseEl.getBoundingClientRect().height +
|
|
266
|
+
40
|
|
267
|
+
}px`
|
|
268
|
+
: `${totalHeaderHeight + 40}px`;
|
|
303
269
|
});
|
|
304
270
|
|
|
305
271
|
// Adjusting the right nav bar on scroll.
|
|
306
272
|
if (rightNavBarEl) {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
273
|
+
rightNavBarEl.style.top = docPhaseEl
|
|
274
|
+
? `${
|
|
275
|
+
totalHeaderHeight +
|
|
276
|
+
docPhaseEl.getBoundingClientRect().height
|
|
277
|
+
}px`
|
|
278
|
+
: `${totalHeaderHeight}px`;
|
|
310
279
|
}
|
|
311
280
|
|
|
312
281
|
// If doc phase element exists, we need to account for its sticky position. Mobile should include the sidebar height (since it becomes sticky aswell).
|
|
@@ -1,43 +1,20 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="content">
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
>
|
|
17
|
-
|
|
18
|
-
</dx-sidebar-old>
|
|
19
|
-
</template>
|
|
20
|
-
<template lwc:else>
|
|
21
|
-
<dx-sidebar
|
|
22
|
-
class="is-sticky left-nav-bar"
|
|
23
|
-
trees={sidebarContent}
|
|
24
|
-
value={sidebarValue}
|
|
25
|
-
header={sidebarHeader}
|
|
26
|
-
coveo-organization-id={coveoOrganizationId}
|
|
27
|
-
coveo-public-access-token={coveoPublicAccessToken}
|
|
28
|
-
coveo-search-hub={coveoSearchHub}
|
|
29
|
-
coveo-advanced-query-config={coveoAdvancedQueryConfig}
|
|
30
|
-
ontogglesidebar={onToggleSidebar}
|
|
31
|
-
languages={languages}
|
|
32
|
-
language={language}
|
|
33
|
-
bail-href={bailHref}
|
|
34
|
-
bail-label={bailLabel}
|
|
35
|
-
dev-center={devCenter}
|
|
36
|
-
brand={brand}
|
|
37
|
-
>
|
|
38
|
-
<slot name="sidebar-header" slot="version-picker"></slot>
|
|
39
|
-
</dx-sidebar>
|
|
40
|
-
</template>
|
|
3
|
+
<dx-sidebar-old
|
|
4
|
+
class="is-sticky left-nav-bar"
|
|
5
|
+
trees={sidebarContent}
|
|
6
|
+
value={sidebarValue}
|
|
7
|
+
header={sidebarHeader}
|
|
8
|
+
ontogglesidebar={onToggleSidebar}
|
|
9
|
+
languages={languages}
|
|
10
|
+
language={language}
|
|
11
|
+
bail-href={bailHref}
|
|
12
|
+
bail-label={bailLabel}
|
|
13
|
+
dev-center={devCenter}
|
|
14
|
+
brand={brand}
|
|
15
|
+
>
|
|
16
|
+
<slot name="sidebar-header" slot="version-picker"></slot>
|
|
17
|
+
</dx-sidebar-old>
|
|
41
18
|
<div class="content-body-doc-phase-container">
|
|
42
19
|
<slot name="doc-phase"></slot>
|
|
43
20
|
<slot name="version-banner"></slot>
|
|
@@ -2,44 +2,111 @@ import ContentLayout from "doc/contentLayout";
|
|
|
2
2
|
|
|
3
3
|
const TOC_HEADER_TAG = "doc-heading";
|
|
4
4
|
const RNB_BY_TAB = "docs-tab";
|
|
5
|
-
const
|
|
5
|
+
const SPECIFICATION_TAG = "doc-specification-content";
|
|
6
6
|
export const OBSERVER_ATTACH_WAIT_TIME = 500;
|
|
7
7
|
|
|
8
8
|
export default class LwcContentLayout extends ContentLayout {
|
|
9
9
|
private rnbByTab: boolean = false;
|
|
10
10
|
|
|
11
|
+
// DOM element caches to avoid repeated queries
|
|
12
|
+
private tabPanelListCache: any = null;
|
|
13
|
+
private hasSpecContentCache: boolean | null = null;
|
|
14
|
+
private allTabsCache: any[] | null = null;
|
|
15
|
+
private mainSlotCache: any = null;
|
|
16
|
+
|
|
11
17
|
private setRNBByTab() {
|
|
12
|
-
const tabPanelListItem
|
|
13
|
-
this.rnbByTab = tabPanelListItem?.id === RNB_BY_TAB
|
|
18
|
+
const tabPanelListItem = this.getTabPanelList();
|
|
19
|
+
this.rnbByTab = tabPanelListItem?.id === RNB_BY_TAB;
|
|
14
20
|
}
|
|
15
21
|
|
|
16
22
|
get showTabBasedRNB() {
|
|
17
23
|
return this.rnbByTab;
|
|
18
24
|
}
|
|
19
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Check if the main slot contains doc-specification-content
|
|
28
|
+
* Uses caching to avoid repeated DOM queries
|
|
29
|
+
*/
|
|
30
|
+
private hasSpecificationContent(): boolean {
|
|
31
|
+
if (this.hasSpecContentCache !== null) {
|
|
32
|
+
return this.hasSpecContentCache;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const mainSlot = this.getMainSlot();
|
|
36
|
+
if (mainSlot) {
|
|
37
|
+
const assignedElements = (mainSlot as any).assignedElements();
|
|
38
|
+
|
|
39
|
+
for (const element of assignedElements) {
|
|
40
|
+
if (
|
|
41
|
+
element.tagName === SPECIFICATION_TAG ||
|
|
42
|
+
element.querySelector(SPECIFICATION_TAG) ||
|
|
43
|
+
element.shadowRoot?.querySelector(SPECIFICATION_TAG)
|
|
44
|
+
) {
|
|
45
|
+
return (this.hasSpecContentCache = true);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return (this.hasSpecContentCache = false);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Clear all caches when content changes
|
|
54
|
+
*/
|
|
55
|
+
private clearAllCaches(): void {
|
|
56
|
+
this.hasSpecContentCache = null;
|
|
57
|
+
this.tabPanelListCache = null;
|
|
58
|
+
this.allTabsCache = null;
|
|
59
|
+
this.mainSlotCache = null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get the main slot element with caching
|
|
64
|
+
*/
|
|
65
|
+
private getMainSlot(): any {
|
|
66
|
+
if (!this.mainSlotCache) {
|
|
67
|
+
this.mainSlotCache =
|
|
68
|
+
this.template.querySelector("slot:not([name])");
|
|
69
|
+
}
|
|
70
|
+
return this.mainSlotCache;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Get tab panel list with caching
|
|
75
|
+
*/
|
|
76
|
+
private getTabPanelList(): any {
|
|
77
|
+
if (!this.tabPanelListCache) {
|
|
78
|
+
// eslint-disable-next-line @lwc/lwc/no-document-query
|
|
79
|
+
this.tabPanelListCache =
|
|
80
|
+
document.querySelector("dx-tab-panel-list");
|
|
81
|
+
}
|
|
82
|
+
return this.tabPanelListCache;
|
|
83
|
+
}
|
|
84
|
+
|
|
20
85
|
onRNBClick = (event: CustomEvent) => {
|
|
21
86
|
event.stopPropagation();
|
|
22
|
-
|
|
23
|
-
if (currentTab === SPECIFICATION_TAB_TITLE) {
|
|
87
|
+
if (this.hasSpecificationContent()) {
|
|
24
88
|
this.didScrollToSelectedHash = false;
|
|
25
89
|
}
|
|
26
90
|
};
|
|
27
91
|
|
|
28
92
|
onTabChanged = () => {
|
|
29
93
|
this.updateRNB();
|
|
30
|
-
};
|
|
31
94
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
95
|
+
const { hash } = window.location;
|
|
96
|
+
if (this.hasSpecificationContent() && hash) {
|
|
97
|
+
this.didScrollToSelectedHash = false;
|
|
98
|
+
|
|
99
|
+
requestAnimationFrame(() => this.updateHeadingForRNB());
|
|
100
|
+
}
|
|
101
|
+
};
|
|
36
102
|
|
|
37
103
|
protected getHeadingElements() {
|
|
38
104
|
let headingElements = super.getHeadingElements();
|
|
39
105
|
if (this.showTabBasedRNB) {
|
|
40
|
-
const tabPanelListItem
|
|
106
|
+
const tabPanelListItem = this.getTabPanelList();
|
|
41
107
|
const tabPanels =
|
|
42
108
|
tabPanelListItem?.querySelectorAll("dx-tab-panel");
|
|
109
|
+
|
|
43
110
|
for (const tabPanelItem of tabPanels) {
|
|
44
111
|
if (tabPanelItem.active) {
|
|
45
112
|
// This is needed for Specification tab content
|
|
@@ -65,6 +132,7 @@ export default class LwcContentLayout extends ContentLayout {
|
|
|
65
132
|
private updateURL() {
|
|
66
133
|
const tabs = this.getAllTabs();
|
|
67
134
|
const selectedTabId = this.getSelectedTabId();
|
|
135
|
+
|
|
68
136
|
tabs.forEach((tab: any) => {
|
|
69
137
|
if (tab.getAttribute("aria-selected") === "true") {
|
|
70
138
|
const tabID = tab.getAttribute("aria-label");
|
|
@@ -101,22 +169,38 @@ export default class LwcContentLayout extends ContentLayout {
|
|
|
101
169
|
const selectedTabId = this.getSelectedTabId();
|
|
102
170
|
if (selectedTabId) {
|
|
103
171
|
this.selectTabById(selectedTabId);
|
|
172
|
+
|
|
173
|
+
// If there's a hash and we have specification content,
|
|
174
|
+
// we need to wait for the content to load before scrolling
|
|
175
|
+
const { hash } = window.location;
|
|
176
|
+
if (this.hasSpecificationContent() && hash) {
|
|
177
|
+
// Reset the scroll flag to allow scrolling once content is loaded
|
|
178
|
+
this.didScrollToSelectedHash = false;
|
|
179
|
+
}
|
|
104
180
|
}
|
|
105
181
|
});
|
|
106
182
|
}
|
|
107
183
|
|
|
108
184
|
private getAllTabs(): any[] {
|
|
109
|
-
|
|
185
|
+
// Return cached result if available
|
|
186
|
+
if (this.allTabsCache) {
|
|
187
|
+
return this.allTabsCache;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const tabPanelListItem = this.getTabPanelList();
|
|
110
191
|
if (tabPanelListItem?.shadowRoot) {
|
|
111
|
-
|
|
192
|
+
this.allTabsCache = Array.from(
|
|
112
193
|
tabPanelListItem.shadowRoot.querySelectorAll(
|
|
113
194
|
"dx-tab-panel-item"
|
|
114
195
|
)
|
|
115
196
|
).map((tabPanelItem: any) =>
|
|
116
197
|
tabPanelItem.shadowRoot.querySelector("button")
|
|
117
198
|
);
|
|
199
|
+
} else {
|
|
200
|
+
this.allTabsCache = [];
|
|
118
201
|
}
|
|
119
|
-
|
|
202
|
+
|
|
203
|
+
return this.allTabsCache;
|
|
120
204
|
}
|
|
121
205
|
|
|
122
206
|
private selectTabById(tabId: string) {
|
|
@@ -158,8 +242,12 @@ export default class LwcContentLayout extends ContentLayout {
|
|
|
158
242
|
}
|
|
159
243
|
}
|
|
160
244
|
|
|
245
|
+
onSlotChange(): void {
|
|
246
|
+
this.clearAllCaches();
|
|
247
|
+
super.onSlotChange();
|
|
248
|
+
}
|
|
249
|
+
|
|
161
250
|
updateHeadingForRNB(): void {
|
|
162
|
-
// We only need to update URL in case of /docs and ignore if tabs are used anywhere else in DSC
|
|
163
251
|
if (this.showTabBasedRNB) {
|
|
164
252
|
this.updateURL();
|
|
165
253
|
}
|
|
@@ -73,9 +73,7 @@
|
|
|
73
73
|
<template lwc:if={method.firstArgument}>
|
|
74
74
|
<tr key={method.name}>
|
|
75
75
|
<td rowspan={method.arguments.length}>
|
|
76
|
-
<span class="code">
|
|
77
|
-
{method.nameInKebabCase}
|
|
78
|
-
</span>
|
|
76
|
+
<span class="code">{method.name}</span>
|
|
79
77
|
</td>
|
|
80
78
|
<td rowspan={method.arguments.length}>
|
|
81
79
|
{method.description}
|
|
@@ -100,9 +98,7 @@
|
|
|
100
98
|
<template lwc:else>
|
|
101
99
|
<tr key={method.name}>
|
|
102
100
|
<td>
|
|
103
|
-
<span class="code">
|
|
104
|
-
{method.nameInKebabCase}
|
|
105
|
-
</span>
|
|
101
|
+
<span class="code">{method.name}</span>
|
|
106
102
|
</td>
|
|
107
103
|
<td>{method.description}</td>
|
|
108
104
|
<td colspan="3"></td>
|
|
@@ -2,16 +2,10 @@
|
|
|
2
2
|
<doc-content-layout
|
|
3
3
|
lwc:if={displayContent}
|
|
4
4
|
lwc:ref="docContentLayout"
|
|
5
|
-
coveo-organization-id={coveoOrganizationId}
|
|
6
|
-
coveo-public-access-token={coveoPublicAccessToken}
|
|
7
|
-
coveo-analytics-token={coveoAnalyticsToken}
|
|
8
|
-
coveo-search-hub={coveoSearchHub}
|
|
9
|
-
coveo-advanced-query-config={coveoAdvancedQueryConfig}
|
|
10
5
|
sidebar-header={docTitle}
|
|
11
6
|
sidebar-content={sidebarContent}
|
|
12
7
|
sidebar-value={sidebarValue}
|
|
13
8
|
onselect={handleSelect}
|
|
14
|
-
use-old-sidebar={useOldSidebar}
|
|
15
9
|
onlangchange={handleLanguageChange}
|
|
16
10
|
languages={sidebarFooterContent.languages}
|
|
17
11
|
language={sidebarFooterContent.language}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
/* eslint-disable @lwc/lwc/no-document-query */
|
|
2
2
|
import { api, track } from "lwc";
|
|
3
|
-
import { normalizeBoolean } from "dxUtils/normalizers";
|
|
4
3
|
import { FetchContent } from "./utils";
|
|
5
4
|
import {
|
|
6
|
-
CoveoAdvancedQueryXMLConfig,
|
|
7
5
|
DocLanguage,
|
|
8
6
|
DocVersion,
|
|
9
7
|
TreeNode,
|
|
@@ -16,7 +14,7 @@ import {
|
|
|
16
14
|
} from "./types";
|
|
17
15
|
import { SearchSyncer } from "docUtils/searchSyncer";
|
|
18
16
|
import { LightningElementWithState } from "dxBaseElements/lightningElementWithState";
|
|
19
|
-
import {
|
|
17
|
+
import { oldVersionDocInfo } from "docUtils/utils";
|
|
20
18
|
import { Breadcrumb, DocPhaseInfo, Language } from "typings/custom";
|
|
21
19
|
import { track as trackGTM } from "dxUtils/analytics";
|
|
22
20
|
import DOMPurify from "dompurify";
|
|
@@ -42,10 +40,6 @@ export default class DocXmlContent extends LightningElementWithState<{
|
|
|
42
40
|
internalLinkClicked: boolean;
|
|
43
41
|
}> {
|
|
44
42
|
@api apiDomain = "https://developer.salesforce.com";
|
|
45
|
-
@api coveoOrganizationId!: string;
|
|
46
|
-
@api coveoPublicAccessToken!: string;
|
|
47
|
-
@api coveoAnalyticsToken!: string;
|
|
48
|
-
@api coveoSearchHub!: string;
|
|
49
43
|
@api hideFooter = false;
|
|
50
44
|
|
|
51
45
|
@api
|
|
@@ -59,15 +53,6 @@ export default class DocXmlContent extends LightningElementWithState<{
|
|
|
59
53
|
}
|
|
60
54
|
}
|
|
61
55
|
|
|
62
|
-
@api
|
|
63
|
-
get enableCoveo() {
|
|
64
|
-
return this._enableCoveo;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
set enableCoveo(value) {
|
|
68
|
-
this._enableCoveo = normalizeBoolean(value);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
56
|
private availableLanguages: Array<DocLanguage> = [];
|
|
72
57
|
@track private availableVersions: Array<DocVersion> = [];
|
|
73
58
|
private contentProvider?: FetchContent;
|
|
@@ -83,7 +68,6 @@ export default class DocXmlContent extends LightningElementWithState<{
|
|
|
83
68
|
private docTitle = "";
|
|
84
69
|
private _pathName = "";
|
|
85
70
|
private listenerAttached = false;
|
|
86
|
-
private _enableCoveo?: boolean = false;
|
|
87
71
|
private sidebarFooterContent: SiderbarFooter = { ...defaultSidebarFooter };
|
|
88
72
|
private latestVersion = false;
|
|
89
73
|
private previewVersion = false;
|
|
@@ -260,35 +244,13 @@ export default class DocXmlContent extends LightningElementWithState<{
|
|
|
260
244
|
// Coveo is enabled and the version is greater than 51 (within the latest 3 versions)
|
|
261
245
|
// TODO: we need a better fix for version number check
|
|
262
246
|
return !(
|
|
263
|
-
this.
|
|
264
|
-
this.
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
(this.version?.releaseVersion &&
|
|
268
|
-
parseInt(
|
|
269
|
-
this.version.releaseVersion.replace("v", ""),
|
|
270
|
-
10
|
|
271
|
-
) >= 53))
|
|
247
|
+
!this.version?.releaseVersion ||
|
|
248
|
+
(this.version?.releaseVersion &&
|
|
249
|
+
parseInt(this.version.releaseVersion.replace("v", ""), 10) >=
|
|
250
|
+
53)
|
|
272
251
|
);
|
|
273
252
|
}
|
|
274
253
|
|
|
275
|
-
private get coveoAdvancedQueryConfig(): CoveoAdvancedQueryXMLConfig {
|
|
276
|
-
const config: {
|
|
277
|
-
locale?: string;
|
|
278
|
-
topicid?: string;
|
|
279
|
-
version?: string;
|
|
280
|
-
} = {
|
|
281
|
-
locale: this.languageId,
|
|
282
|
-
topicid: this.deliverable
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
if (this.releaseVersionId && this.releaseVersionId !== "noversion") {
|
|
286
|
-
config.version = this.releaseVersionId;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
return config;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
254
|
private get pageHeader(): Header {
|
|
293
255
|
if (!this._pageHeader) {
|
|
294
256
|
this._pageHeader = document.querySelector("doc-header")!;
|
|
@@ -589,7 +551,6 @@ export default class DocXmlContent extends LightningElementWithState<{
|
|
|
589
551
|
}
|
|
590
552
|
|
|
591
553
|
updateUrl(method = HistoryState.PUSH_STATE): void {
|
|
592
|
-
logCoveoPageView(this.coveoOrganizationId, this.coveoAnalyticsToken);
|
|
593
554
|
window.history[method](
|
|
594
555
|
{},
|
|
595
556
|
"docs",
|
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
/* stylelint-disable selector-class-pattern */
|
|
2
|
-
|
|
3
|
-
/* Table wrapper for overflow handling */
|
|
4
|
-
.doc-table-wrapper {
|
|
5
|
-
margin: 16px 0;
|
|
6
|
-
|
|
7
|
-
/* Ensure sticky positioning context */
|
|
8
|
-
position: relative;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/* Only add horizontal scroll when sticky headers are disabled */
|
|
12
|
-
.doc-table-wrapper:not(.doc-table-wrapper--sticky-headers) {
|
|
13
|
-
overflow-x: auto;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/* When sticky headers are enabled, remove overflow to allow sticky positioning */
|
|
17
|
-
.doc-table-wrapper--sticky-headers {
|
|
18
|
-
overflow-x: visible;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/* GitHub markdown table styles - exact replication */
|
|
22
|
-
.doc-table {
|
|
23
|
-
border-spacing: 0;
|
|
24
|
-
border-collapse: collapse;
|
|
25
|
-
display: table;
|
|
26
|
-
width: max-content;
|
|
27
|
-
max-width: 100%;
|
|
28
|
-
overflow: auto;
|
|
29
|
-
font-size: 14px;
|
|
30
|
-
line-height: 1.45;
|
|
31
|
-
color: #1f2328;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/* Table caption - GitHub style */
|
|
35
|
-
.doc-table__caption {
|
|
36
|
-
caption-side: top;
|
|
37
|
-
padding: 8px 0;
|
|
38
|
-
font-weight: 600;
|
|
39
|
-
color: #656d76;
|
|
40
|
-
text-align: left;
|
|
41
|
-
font-size: 14px;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/* Header and cell base styles */
|
|
45
|
-
.doc-table__header-cell,
|
|
46
|
-
.doc-table__cell {
|
|
47
|
-
padding: 6px 13px;
|
|
48
|
-
border: 1px solid #d1d9e0;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/* Header specific styles */
|
|
52
|
-
.doc-table__header-cell {
|
|
53
|
-
font-weight: 600;
|
|
54
|
-
background-color: #f6f8fa;
|
|
55
|
-
text-align: left;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/* Body cell styles */
|
|
59
|
-
.doc-table__cell {
|
|
60
|
-
background-color: #fff;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/* Row hover effect - subtle like GitHub */
|
|
64
|
-
.doc-table__row:hover .doc-table__cell {
|
|
65
|
-
background-color: #f6f8fa;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/* Sticky headers */
|
|
69
|
-
.doc-table--sticky-headers .doc-table__header-cell {
|
|
70
|
-
position: sticky;
|
|
71
|
-
top: calc(
|
|
72
|
-
var(--dx-g-global-header-height) +
|
|
73
|
-
var(--dx-g-doc-header-banner-height, 0px)
|
|
74
|
-
);
|
|
75
|
-
z-index: 10;
|
|
76
|
-
|
|
77
|
-
/* Ensure background is maintained when sticky */
|
|
78
|
-
background-color: #f6f8fa;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/* Bordered table variant - enhanced GitHub style */
|
|
82
|
-
.doc-table--bordered {
|
|
83
|
-
border: 1px solid #d1d9e0;
|
|
84
|
-
border-radius: 6px;
|
|
85
|
-
overflow: hidden;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
.doc-table--bordered .doc-table__header-cell:first-child,
|
|
89
|
-
.doc-table--bordered .doc-table__cell:first-child {
|
|
90
|
-
border-left: none;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.doc-table--bordered .doc-table__header-cell:last-child,
|
|
94
|
-
.doc-table--bordered .doc-table__cell:last-child {
|
|
95
|
-
border-right: none;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/* Striped table variant - GitHub style alternating rows */
|
|
99
|
-
.doc-table--striped .doc-table__row:nth-child(even) .doc-table__cell {
|
|
100
|
-
background-color: #f6f8fa;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
.doc-table--striped .doc-table__row:nth-child(even):hover .doc-table__cell {
|
|
104
|
-
background-color: #eaeef2;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/* Links within table cells - GitHub style */
|
|
108
|
-
.doc-table__cell a {
|
|
109
|
-
color: #0969da;
|
|
110
|
-
text-decoration: none;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
.doc-table__cell a:hover {
|
|
114
|
-
text-decoration: underline;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
.doc-table__cell a:visited {
|
|
118
|
-
color: #8250df;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/* Code within table cells - GitHub style */
|
|
122
|
-
.doc-table__cell code {
|
|
123
|
-
padding: 0.2em 0.4em;
|
|
124
|
-
margin: 0;
|
|
125
|
-
font-size: 85%;
|
|
126
|
-
white-space: break-spaces;
|
|
127
|
-
background-color: rgb(175 184 193 / 20%);
|
|
128
|
-
border-radius: 6px;
|
|
129
|
-
font-family: ui-monospace, SFMono-Regular, "SF Mono", Consolas,
|
|
130
|
-
"Liberation Mono", Menlo, monospace;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/* Strong/bold text in cells */
|
|
134
|
-
.doc-table__cell strong,
|
|
135
|
-
.doc-table__cell b {
|
|
136
|
-
font-weight: 600;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/* Emphasis/italic text in cells */
|
|
140
|
-
.doc-table__cell em,
|
|
141
|
-
.doc-table__cell i {
|
|
142
|
-
font-style: italic;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/* Empty state - GitHub inspired */
|
|
146
|
-
.doc-table__empty {
|
|
147
|
-
padding: 32px;
|
|
148
|
-
text-align: center;
|
|
149
|
-
border: 1px solid #d1d9e0;
|
|
150
|
-
border-radius: 6px;
|
|
151
|
-
background-color: #f6f8fa;
|
|
152
|
-
margin: 16px 0;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
.doc-table__empty-message {
|
|
156
|
-
color: #656d76;
|
|
157
|
-
font-style: italic;
|
|
158
|
-
margin: 0;
|
|
159
|
-
font-size: 14px;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/* Responsive design - GitHub mobile behavior */
|
|
163
|
-
@media (max-width: 768px) {
|
|
164
|
-
.doc-table-wrapper {
|
|
165
|
-
margin-left: -16px;
|
|
166
|
-
margin-right: -16px;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
.doc-table {
|
|
170
|
-
font-size: 12px;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
.doc-table__header-cell,
|
|
174
|
-
.doc-table__cell {
|
|
175
|
-
padding: 4px 8px;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/* Adjust sticky header position for mobile */
|
|
179
|
-
.doc-table--sticky-headers .doc-table__header-cell {
|
|
180
|
-
top: calc(
|
|
181
|
-
var(--dx-g-global-header-height) +
|
|
182
|
-
var(--dx-g-doc-header-banner-height, 0px)
|
|
183
|
-
);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/* Dark mode support (GitHub style) */
|
|
188
|
-
@media (prefers-color-scheme: dark) {
|
|
189
|
-
.doc-table {
|
|
190
|
-
color: #f0f6fc;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
.doc-table__header-cell,
|
|
194
|
-
.doc-table__cell {
|
|
195
|
-
border-color: #30363d;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
.doc-table__header-cell {
|
|
199
|
-
background-color: #161b22;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/* Ensure sticky headers maintain background in dark mode */
|
|
203
|
-
.doc-table--sticky-headers .doc-table__header-cell {
|
|
204
|
-
background-color: #161b22;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
.doc-table__cell {
|
|
208
|
-
background-color: #0d1117;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
.doc-table__row:hover .doc-table__cell {
|
|
212
|
-
background-color: #161b22;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
.doc-table--striped .doc-table__row:nth-child(even) .doc-table__cell {
|
|
216
|
-
background-color: #161b22;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
.doc-table--striped .doc-table__row:nth-child(even):hover .doc-table__cell {
|
|
220
|
-
background-color: #21262d;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
.doc-table__caption {
|
|
224
|
-
color: #8b949e;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
.doc-table__empty {
|
|
228
|
-
background-color: #161b22;
|
|
229
|
-
border-color: #30363d;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
.doc-table__empty-message {
|
|
233
|
-
color: #8b949e;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
.doc-table__cell a {
|
|
237
|
-
color: #58a6ff;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
.doc-table__cell a:visited {
|
|
241
|
-
color: #bc8cff;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
.doc-table__cell code {
|
|
245
|
-
background-color: rgb(110 118 129 / 40%);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/* High contrast mode support */
|
|
250
|
-
@media (prefers-contrast: high) {
|
|
251
|
-
.doc-table__header-cell,
|
|
252
|
-
.doc-table__cell {
|
|
253
|
-
border: 1px solid;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
.doc-table__row:hover .doc-table__cell {
|
|
257
|
-
background-color: highlight;
|
|
258
|
-
color: highlighttext;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/* Reduced motion support */
|
|
263
|
-
@media (prefers-reduced-motion: reduce) {
|
|
264
|
-
.doc-table__row:hover .doc-table__cell {
|
|
265
|
-
transition: none;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class={wrapperClasses} if:true={hasData}>
|
|
3
|
-
<table class={tableClasses}>
|
|
4
|
-
<!-- Caption -->
|
|
5
|
-
<caption if:true={caption} class="doc-table__caption">
|
|
6
|
-
{caption}
|
|
7
|
-
</caption>
|
|
8
|
-
<!-- Table Header -->
|
|
9
|
-
<thead class="doc-table__head">
|
|
10
|
-
<tr class="doc-table__header-row">
|
|
11
|
-
<th
|
|
12
|
-
for:each={columns}
|
|
13
|
-
for:item="column"
|
|
14
|
-
key={column.key}
|
|
15
|
-
class="doc-table__header-cell"
|
|
16
|
-
scope="col"
|
|
17
|
-
>
|
|
18
|
-
{column.label}
|
|
19
|
-
</th>
|
|
20
|
-
</tr>
|
|
21
|
-
</thead>
|
|
22
|
-
<!-- Table Body -->
|
|
23
|
-
<tbody class="doc-table__body">
|
|
24
|
-
<tr
|
|
25
|
-
for:each={processedRows}
|
|
26
|
-
for:item="row"
|
|
27
|
-
key={row.id}
|
|
28
|
-
class="doc-table__row"
|
|
29
|
-
>
|
|
30
|
-
<td
|
|
31
|
-
for:each={row.cells}
|
|
32
|
-
for:item="cell"
|
|
33
|
-
key={cell.key}
|
|
34
|
-
class="doc-table__cell"
|
|
35
|
-
>
|
|
36
|
-
{cell.value}
|
|
37
|
-
</td>
|
|
38
|
-
</tr>
|
|
39
|
-
</tbody>
|
|
40
|
-
</table>
|
|
41
|
-
</div>
|
|
42
|
-
<!-- Empty state -->
|
|
43
|
-
<div class="doc-table__empty" if:false={hasData}>
|
|
44
|
-
<p class="doc-table__empty-message">No data available</p>
|
|
45
|
-
</div>
|
|
46
|
-
</template>
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import { LightningElement, api } from "lwc";
|
|
2
|
-
|
|
3
|
-
interface TableColumn {
|
|
4
|
-
key: string;
|
|
5
|
-
label: string;
|
|
6
|
-
type?: "text" | "link" | "html";
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
interface TableRow {
|
|
10
|
-
[key: string]: any;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
interface TableData {
|
|
14
|
-
columns: TableColumn[];
|
|
15
|
-
rows: TableRow[];
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export default class Table extends LightningElement {
|
|
19
|
-
@api caption: string = "";
|
|
20
|
-
|
|
21
|
-
private _striped: boolean = false;
|
|
22
|
-
private _bordered: boolean = false;
|
|
23
|
-
private _stickyHeaders: boolean = false;
|
|
24
|
-
|
|
25
|
-
@api
|
|
26
|
-
get striped(): boolean {
|
|
27
|
-
return this._striped;
|
|
28
|
-
}
|
|
29
|
-
set striped(value: boolean | string) {
|
|
30
|
-
this._striped = this.toBooleanValue(value);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
@api
|
|
34
|
-
get bordered(): boolean {
|
|
35
|
-
return this._bordered;
|
|
36
|
-
}
|
|
37
|
-
set bordered(value: boolean | string) {
|
|
38
|
-
this._bordered = this.toBooleanValue(value);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
@api
|
|
42
|
-
get stickyHeaders(): boolean {
|
|
43
|
-
return this._stickyHeaders;
|
|
44
|
-
}
|
|
45
|
-
set stickyHeaders(value: boolean | string) {
|
|
46
|
-
this._stickyHeaders = this.toBooleanValue(value);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
private _tableData: TableData = { columns: [], rows: [] };
|
|
50
|
-
|
|
51
|
-
@api
|
|
52
|
-
get tableData(): string | TableData {
|
|
53
|
-
return this._tableData;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
set tableData(value: string | TableData) {
|
|
57
|
-
if (typeof value === "string") {
|
|
58
|
-
// Handle the case where object is stringified as "[object Object]"
|
|
59
|
-
if (value === "[object Object]") {
|
|
60
|
-
console.error(
|
|
61
|
-
"Invalid JSON provided to table component: Object was not properly serialized. Use property binding (.table-data) instead of attribute binding (table-data) for objects."
|
|
62
|
-
);
|
|
63
|
-
this._tableData = { columns: [], rows: [] };
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
try {
|
|
68
|
-
this._tableData = JSON.parse(value);
|
|
69
|
-
} catch (error) {
|
|
70
|
-
console.error(
|
|
71
|
-
"Invalid JSON provided to table component:",
|
|
72
|
-
error
|
|
73
|
-
);
|
|
74
|
-
this._tableData = { columns: [], rows: [] };
|
|
75
|
-
}
|
|
76
|
-
} else if (value) {
|
|
77
|
-
this._tableData = value as TableData;
|
|
78
|
-
} else {
|
|
79
|
-
this._tableData = { columns: [], rows: [] };
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
get columns(): TableColumn[] {
|
|
84
|
-
return this._tableData?.columns || [];
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
get rows(): TableRow[] {
|
|
88
|
-
return this._tableData?.rows || [];
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
get hasData(): boolean {
|
|
92
|
-
return this.columns.length > 0 && this.rows.length > 0;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
get wrapperClasses(): string {
|
|
96
|
-
const classes = ["doc-table-wrapper"];
|
|
97
|
-
|
|
98
|
-
if (this.stickyHeaders) {
|
|
99
|
-
classes.push("doc-table-wrapper--sticky-headers");
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return classes.join(" ");
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
get tableClasses(): string {
|
|
106
|
-
const classes = ["doc-table"];
|
|
107
|
-
|
|
108
|
-
if (this.striped) {
|
|
109
|
-
classes.push("doc-table--striped");
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (this.bordered) {
|
|
113
|
-
classes.push("doc-table--bordered");
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (this.stickyHeaders) {
|
|
117
|
-
classes.push("doc-table--sticky-headers");
|
|
118
|
-
}
|
|
119
|
-
return classes.join(" ");
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
get processedRows(): Array<{
|
|
123
|
-
id: string;
|
|
124
|
-
cells: Array<{ key: string; value: any; type: string }>;
|
|
125
|
-
}> {
|
|
126
|
-
return this.rows.map((row, index) => ({
|
|
127
|
-
id: `row-${index}`,
|
|
128
|
-
cells: this.columns.map((column) => ({
|
|
129
|
-
key: column.key,
|
|
130
|
-
value: row[column.key] || "",
|
|
131
|
-
type: column.type || "text"
|
|
132
|
-
}))
|
|
133
|
-
}));
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
private renderCellContent(value: any, type: string): string {
|
|
137
|
-
if (value === null || value === undefined) {
|
|
138
|
-
return "";
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
switch (type) {
|
|
142
|
-
case "html":
|
|
143
|
-
return value.toString();
|
|
144
|
-
case "link":
|
|
145
|
-
if (typeof value === "object" && value.url && value.text) {
|
|
146
|
-
return `<a href="${value.url}" target="_blank" rel="noopener noreferrer">${value.text}</a>`;
|
|
147
|
-
}
|
|
148
|
-
return value.toString();
|
|
149
|
-
case "text":
|
|
150
|
-
default:
|
|
151
|
-
return value.toString();
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Method to handle cell content rendering in the template
|
|
156
|
-
getCellContent(value: any, type: string): string {
|
|
157
|
-
return this.renderCellContent(value, type);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Method to check if cell content should be rendered as HTML
|
|
161
|
-
isHtmlCell(type: string): boolean {
|
|
162
|
-
return type === "html" || type === "link";
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Helper method to convert string/boolean values to boolean
|
|
166
|
-
private toBooleanValue(value: boolean | string): boolean {
|
|
167
|
-
if (typeof value === "boolean") {
|
|
168
|
-
return value;
|
|
169
|
-
}
|
|
170
|
-
if (typeof value === "string") {
|
|
171
|
-
return value.toLowerCase() === "true";
|
|
172
|
-
}
|
|
173
|
-
return false;
|
|
174
|
-
}
|
|
175
|
-
}
|