@salesforcedevs/docs-components 0.57.1-flex-ref1 → 0.60.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +12 -0
- package/package.json +2 -2
- package/src/modules/doc/amfReference/amfReference.html +5 -13
- package/src/modules/doc/amfReference/amfReference.ts +303 -799
- package/src/modules/doc/amfReference/route-meta.ts +22 -0
- package/src/modules/doc/amfReference/types.ts +3 -43
- package/src/modules/doc/breadcrumbItem/breadcrumbItem.css +2 -1
- package/src/modules/doc/breadcrumbs/breadcrumbs.css +2 -0
- package/src/modules/doc/breadcrumbs/breadcrumbs.html +1 -1
- package/src/modules/doc/breadcrumbs/breadcrumbs.ts +31 -6
- package/src/modules/doc/contentLayout/contentLayout.css +1 -5
- package/src/modules/doc/contentLayout/contentLayout.html +2 -9
- package/src/modules/doc/contentLayout/contentLayout.ts +29 -74
- package/src/modules/doc/xmlContent/types.ts +3 -0
- package/src/modules/doc/xmlContent/utils.ts +14 -11
- package/src/modules/doc/xmlContent/xmlContent.css +5 -0
- package/src/modules/doc/xmlContent/xmlContent.html +5 -0
- package/src/modules/doc/xmlContent/xmlContent.ts +64 -15
- package/src/modules/doc/amfReference/constants.ts +0 -76
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents the URL reference meta on Reference page.
|
|
3
|
+
* Contains information on selected Reference ID, Topic ID, and Topic Type
|
|
4
|
+
* separated by ":"
|
|
5
|
+
*/
|
|
6
|
+
export class RouteMeta {
|
|
7
|
+
meta: string;
|
|
8
|
+
referenceId = "";
|
|
9
|
+
topicId = "";
|
|
10
|
+
type = "";
|
|
11
|
+
|
|
12
|
+
constructor(meta: string) {
|
|
13
|
+
this.meta = meta;
|
|
14
|
+
|
|
15
|
+
if (meta && meta.includes(":")) {
|
|
16
|
+
const [referenceId, type, topicId] = meta.split(":");
|
|
17
|
+
this.referenceId = referenceId;
|
|
18
|
+
this.topicId = topicId || type;
|
|
19
|
+
this.type = type;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -2,7 +2,6 @@ import { Json } from "typings/custom";
|
|
|
2
2
|
|
|
3
3
|
export interface AmfTopicType {
|
|
4
4
|
referenceId: string;
|
|
5
|
-
parentReferencePath: string;
|
|
6
5
|
amfId: string;
|
|
7
6
|
elementId: string;
|
|
8
7
|
type: string;
|
|
@@ -11,7 +10,6 @@ export interface AmfTopicType {
|
|
|
11
10
|
export interface AmfMetadataTopic extends AmfTopicType {
|
|
12
11
|
meta: string;
|
|
13
12
|
identifier: string;
|
|
14
|
-
navTitle?: string;
|
|
15
13
|
}
|
|
16
14
|
|
|
17
15
|
export interface AmfMetaTopicType extends AmfTopicType {
|
|
@@ -55,37 +53,11 @@ export type DocPhaseEntry = {
|
|
|
55
53
|
body: string;
|
|
56
54
|
};
|
|
57
55
|
|
|
58
|
-
export
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Represents parsed topic for the sidebar.
|
|
62
|
-
*/
|
|
63
|
-
export interface ParsedMarkdownTopic {
|
|
64
|
-
label: string;
|
|
65
|
-
name: string;
|
|
66
|
-
children: ParsedMarkdownTopic[];
|
|
67
|
-
link?: {
|
|
68
|
-
href: string;
|
|
69
|
-
target?: string;
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export interface AmfConfig {
|
|
56
|
+
export interface AmfConfig extends AmfModelRecord {
|
|
74
57
|
id: string;
|
|
58
|
+
amf: string;
|
|
75
59
|
version?: string;
|
|
76
60
|
docPhase?: DocPhaseEntry;
|
|
77
|
-
title: string;
|
|
78
|
-
href: string;
|
|
79
|
-
referenceType: ReferenceType;
|
|
80
|
-
|
|
81
|
-
// determines if a reference config is the current active and selected one.
|
|
82
|
-
isSelected: boolean;
|
|
83
|
-
|
|
84
|
-
// required for spec based references
|
|
85
|
-
amf?: string;
|
|
86
|
-
|
|
87
|
-
// required for markdown based references
|
|
88
|
-
topic?: ParsedMarkdownTopic;
|
|
89
61
|
}
|
|
90
62
|
|
|
91
63
|
export interface ParsedTopicModel {
|
|
@@ -112,22 +84,10 @@ export interface ReferenceVersion {
|
|
|
112
84
|
label: string;
|
|
113
85
|
deprecated?: boolean;
|
|
114
86
|
selected?: boolean;
|
|
115
|
-
link: {
|
|
116
|
-
href: string;
|
|
117
|
-
};
|
|
118
87
|
}
|
|
119
88
|
|
|
120
89
|
export interface ReferenceSetConfig {
|
|
121
|
-
refId?: string;
|
|
122
90
|
versionToRefMap?: Map<string, Array<AmfConfig>>;
|
|
123
91
|
refList: Array<AmfConfig>;
|
|
124
|
-
versions
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
export interface RouteMeta {
|
|
128
|
-
meta: string;
|
|
129
|
-
referenceId: string;
|
|
130
|
-
topicId: string;
|
|
131
|
-
//type is only for spec based references
|
|
132
|
-
type?: string;
|
|
92
|
+
versions?: Array<ReferenceVersion>;
|
|
133
93
|
}
|
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
:host {
|
|
5
5
|
display: flex;
|
|
6
6
|
align-items: center;
|
|
7
|
+
justify-content: center;
|
|
7
8
|
width: fit-content;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
:host(.breadcrumb_long) {
|
|
11
12
|
/* ensure 30 character min-width */
|
|
12
|
-
min-width:
|
|
13
|
+
min-width: 200px;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
:host(.breadcrumb_back-arrow) {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
analytics-event={analyticsEventName}
|
|
37
37
|
analytics-base-payload={analyticsBasePayload}
|
|
38
38
|
href={breadcrumb.href}
|
|
39
|
-
key={breadcrumb.
|
|
39
|
+
key={breadcrumb.id}
|
|
40
40
|
label={breadcrumb.label}
|
|
41
41
|
></doc-breadcrumb-item>
|
|
42
42
|
<span class="breadcrumb-item_slash" key={breadcrumb.label}>
|
|
@@ -8,10 +8,12 @@ type BreadcrumbConfig = {
|
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
const GAP = 8;
|
|
11
|
+
|
|
12
|
+
// Unit in pixels based on Salesforce Sans font-family.
|
|
11
13
|
const CONSTANTS = {
|
|
12
|
-
pixelPerCharacter: 7.
|
|
13
|
-
pixelPerCrumbSpace: GAP * 2 +
|
|
14
|
-
minWidthPerCrumb:
|
|
14
|
+
pixelPerCharacter: 7.7,
|
|
15
|
+
pixelPerCrumbSpace: GAP * 2 + 8.6,
|
|
16
|
+
minWidthPerCrumb: 200,
|
|
15
17
|
dropdownWidth: 32
|
|
16
18
|
};
|
|
17
19
|
|
|
@@ -29,15 +31,26 @@ export default class Breadcrumbs extends LightningElement {
|
|
|
29
31
|
get breadcrumbs(): Breadcrumb[] {
|
|
30
32
|
return this._breadcrumbs;
|
|
31
33
|
}
|
|
34
|
+
|
|
32
35
|
set breadcrumbs(value) {
|
|
33
|
-
this.
|
|
36
|
+
this.normalizeAndAssignBreadcrumbs(value);
|
|
34
37
|
this.calculateBreadcrumbsConfigs();
|
|
35
38
|
if (this.observer) {
|
|
36
39
|
this.updateDropdownOptionAmount();
|
|
37
40
|
}
|
|
38
41
|
}
|
|
39
42
|
|
|
43
|
+
@api
|
|
44
|
+
get pixelPerCharacter(): number {
|
|
45
|
+
return this._pixelPerCharacter;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
set pixelPerCharacter(value: number | string) {
|
|
49
|
+
this._pixelPerCharacter = +value;
|
|
50
|
+
}
|
|
51
|
+
|
|
40
52
|
private _breadcrumbs: Breadcrumb[] = [];
|
|
53
|
+
private _pixelPerCharacter = CONSTANTS.pixelPerCharacter;
|
|
41
54
|
private navWidth = 0;
|
|
42
55
|
private observer: ResizeObserver | null = null;
|
|
43
56
|
private breadcrumbConfigs: BreadcrumbConfig[] = [];
|
|
@@ -72,7 +85,7 @@ export default class Breadcrumbs extends LightningElement {
|
|
|
72
85
|
private get dropdownOptions(): OptionWithLink[] {
|
|
73
86
|
return this.breadcrumbs!.slice(1, this.dropdownOptionAmount! + 1).map(
|
|
74
87
|
(link) => ({
|
|
75
|
-
id: link.
|
|
88
|
+
id: link.id!,
|
|
76
89
|
label: link.label,
|
|
77
90
|
link: { href: link.href! }
|
|
78
91
|
})
|
|
@@ -118,6 +131,17 @@ export default class Breadcrumbs extends LightningElement {
|
|
|
118
131
|
this.observer?.disconnect();
|
|
119
132
|
}
|
|
120
133
|
|
|
134
|
+
private normalizeAndAssignBreadcrumbs(breadcrumbs?: Breadcrumb[] | string) {
|
|
135
|
+
if (!breadcrumbs) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
this._breadcrumbs = toJson(breadcrumbs).map((crumb: Breadcrumb) => ({
|
|
140
|
+
...crumb,
|
|
141
|
+
id: crumb.id || crumb.href
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
144
|
+
|
|
121
145
|
private updateDropdownOptionAmount(): void {
|
|
122
146
|
this.dropdownOptionAmount = this.breadcrumbConfigs.find(
|
|
123
147
|
({ minWidth }) => minWidth <= this.navWidth
|
|
@@ -150,7 +174,8 @@ export default class Breadcrumbs extends LightningElement {
|
|
|
150
174
|
(previousValue, element) =>
|
|
151
175
|
previousValue +
|
|
152
176
|
Math.min(
|
|
153
|
-
element.label.length *
|
|
177
|
+
element.label.length *
|
|
178
|
+
(this.pixelPerCharacter || CONSTANTS.pixelPerCharacter),
|
|
154
179
|
CONSTANTS.minWidthPerCrumb
|
|
155
180
|
),
|
|
156
181
|
(breadcrumbs.length - 1) * CONSTANTS.pixelPerCrumbSpace + offset
|
|
@@ -56,7 +56,7 @@ dx-toc {
|
|
|
56
56
|
max-width: 275px;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
doc-breadcrumbs {
|
|
60
60
|
display: block;
|
|
61
61
|
margin-bottom: var(--dx-g-spacing-2xl);
|
|
62
62
|
}
|
|
@@ -68,10 +68,6 @@ dx-breadcrumbs {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
@media screen and (max-width: 800px) {
|
|
71
|
-
dx-breadcrumbs {
|
|
72
|
-
display: none;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
71
|
.content-body {
|
|
76
72
|
margin-top: var(--dx-c-content-vertical-spacing);
|
|
77
73
|
}
|
|
@@ -28,17 +28,10 @@
|
|
|
28
28
|
<slot name="doc-phase"></slot>
|
|
29
29
|
<div class="content-body-container">
|
|
30
30
|
<div class="content-body">
|
|
31
|
-
<
|
|
31
|
+
<doc-breadcrumbs
|
|
32
32
|
if:true={breadcrumbs}
|
|
33
33
|
breadcrumbs={breadcrumbs}
|
|
34
|
-
|
|
35
|
-
hide-current-location
|
|
36
|
-
></dx-breadcrumbs>
|
|
37
|
-
<dx-breadcrumbs
|
|
38
|
-
if:false={breadcrumbs}
|
|
39
|
-
pathname={pathname}
|
|
40
|
-
hide-current-location
|
|
41
|
-
></dx-breadcrumbs>
|
|
34
|
+
></doc-breadcrumbs>
|
|
42
35
|
<slot onslotchange={onSlotChange}></slot>
|
|
43
36
|
</div>
|
|
44
37
|
<div class="right-nav-bar is-sticky">
|
|
@@ -20,7 +20,6 @@ const HIGHLIGHTABLE_SELECTOR = [
|
|
|
20
20
|
"th",
|
|
21
21
|
"td"
|
|
22
22
|
].join(",");
|
|
23
|
-
const OBSERVER_ATTACH_WAIT_TIME = 500;
|
|
24
23
|
|
|
25
24
|
export default class ContentLayout extends LightningElement {
|
|
26
25
|
@api sidebarValue: string;
|
|
@@ -96,8 +95,6 @@ export default class ContentLayout extends LightningElement {
|
|
|
96
95
|
target: window
|
|
97
96
|
});
|
|
98
97
|
private tocValue?: string = undefined;
|
|
99
|
-
private observerTimerId = null;
|
|
100
|
-
private didScrollToSelectedHash = false;
|
|
101
98
|
|
|
102
99
|
get showToc(): boolean {
|
|
103
100
|
return this.tocOptions && this.tocOptions.length > 0;
|
|
@@ -122,18 +119,6 @@ export default class ContentLayout extends LightningElement {
|
|
|
122
119
|
}
|
|
123
120
|
}
|
|
124
121
|
|
|
125
|
-
renderedCallback(): void {
|
|
126
|
-
/**
|
|
127
|
-
* Note: We are adding timeout because chrome is optimizing and not triggering recent renderedCallback though elements reference is changed
|
|
128
|
-
* Also we are considering recent renderedCallback
|
|
129
|
-
*/
|
|
130
|
-
this.clearRenderObserverTimer();
|
|
131
|
-
this.observerTimerId = setTimeout(
|
|
132
|
-
this.attachInteractionObserver,
|
|
133
|
-
OBSERVER_ATTACH_WAIT_TIME
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
122
|
disconnectedCallback(): void {
|
|
138
123
|
this.disconnectObserver();
|
|
139
124
|
window.removeEventListener(
|
|
@@ -141,25 +126,19 @@ export default class ContentLayout extends LightningElement {
|
|
|
141
126
|
this.updateHighlighted
|
|
142
127
|
);
|
|
143
128
|
this.searchSyncer.dispose();
|
|
144
|
-
this.clearRenderObserverTimer();
|
|
145
129
|
}
|
|
146
130
|
|
|
147
|
-
clearRenderObserverTimer = () => {
|
|
148
|
-
if (this.observerTimerId) {
|
|
149
|
-
clearTimeout(this.observerTimerId);
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
|
|
153
131
|
updateHighlighted = (event: Event): void =>
|
|
154
132
|
highlightTerms(
|
|
155
133
|
this.querySelectorAll(HIGHLIGHTABLE_SELECTOR),
|
|
156
134
|
(event as CustomEvent<string>).detail
|
|
157
135
|
);
|
|
158
136
|
|
|
159
|
-
|
|
137
|
+
onSlotChange(event: Event): void {
|
|
160
138
|
if (!this.enableSlotChange) {
|
|
161
139
|
return;
|
|
162
140
|
}
|
|
141
|
+
|
|
163
142
|
this.disconnectObserver();
|
|
164
143
|
this.observer = new IntersectionObserver((entries) => {
|
|
165
144
|
entries.forEach(
|
|
@@ -171,54 +150,30 @@ export default class ContentLayout extends LightningElement {
|
|
|
171
150
|
this.calculateActualSection();
|
|
172
151
|
});
|
|
173
152
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
153
|
+
const anchoredTags = (event.target as HTMLSlotElement)
|
|
154
|
+
.assignedElements()
|
|
155
|
+
.filter(({ tagName }) => tagName === TOC_HEADER_TAG)
|
|
156
|
+
.map((tag) => {
|
|
157
|
+
tag.id = tag.hash;
|
|
158
|
+
return tag;
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
this._tocOptions = anchoredTags.map((tag) => ({
|
|
162
|
+
anchor: `#${tag.hash}`,
|
|
163
|
+
id: tag.id,
|
|
164
|
+
label: tag.title
|
|
165
|
+
}));
|
|
166
|
+
|
|
167
|
+
this.scrollToHash(anchoredTags);
|
|
168
|
+
|
|
169
|
+
anchoredTags.forEach((section) => {
|
|
170
|
+
const id = section.getAttribute("id");
|
|
179
171
|
this.anchoredElements[id] = {
|
|
180
172
|
id,
|
|
181
173
|
intersect: false
|
|
182
174
|
};
|
|
183
|
-
this.observer.observe(
|
|
184
|
-
}
|
|
185
|
-
if (!this.didScrollToSelectedHash) {
|
|
186
|
-
this.didScrollToSelectedHash = true;
|
|
187
|
-
this.scrollToHash(headingElements);
|
|
188
|
-
}
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
onSlotChange(event: Event): void {
|
|
192
|
-
const slotElements = (
|
|
193
|
-
event.target as HTMLSlotElement
|
|
194
|
-
).assignedElements();
|
|
195
|
-
|
|
196
|
-
if (slotElements.length) {
|
|
197
|
-
const slotContentElement = slotElements[0];
|
|
198
|
-
const headingElements =
|
|
199
|
-
slotContentElement.ownerDocument?.getElementsByTagName(
|
|
200
|
-
TOC_HEADER_TAG
|
|
201
|
-
);
|
|
202
|
-
for (const headingElement of headingElements) {
|
|
203
|
-
// Sometimes elements hash is not being set when slot content is wrapped with div
|
|
204
|
-
headingElement.hash =
|
|
205
|
-
headingElement.attributes.hash?.nodeValue;
|
|
206
|
-
}
|
|
207
|
-
const tocOptions = [];
|
|
208
|
-
for (const headingElement of headingElements) {
|
|
209
|
-
headingElement.id = headingElement.hash;
|
|
210
|
-
|
|
211
|
-
// Update tocOptions from anchorTags
|
|
212
|
-
const tocItem = {
|
|
213
|
-
anchor: `#${headingElement.hash}`,
|
|
214
|
-
id: headingElement.id,
|
|
215
|
-
label: headingElement.title
|
|
216
|
-
};
|
|
217
|
-
tocOptions.push(tocItem);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
this._tocOptions = tocOptions;
|
|
221
|
-
}
|
|
175
|
+
this.observer.observe(section);
|
|
176
|
+
});
|
|
222
177
|
}
|
|
223
178
|
|
|
224
179
|
private disconnectObserver(): void {
|
|
@@ -228,16 +183,16 @@ export default class ContentLayout extends LightningElement {
|
|
|
228
183
|
}
|
|
229
184
|
}
|
|
230
185
|
|
|
231
|
-
|
|
232
|
-
private scrollToHash(headingElements: NodeListOf<Element>): void {
|
|
186
|
+
private scrollToHash(anchoredTags: Array<Element>): void {
|
|
233
187
|
let { hash } = window.location;
|
|
188
|
+
|
|
234
189
|
if (hash) {
|
|
235
190
|
hash = hash.substr(1);
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
191
|
+
const toScrollElement = anchoredTags.find(
|
|
192
|
+
(element) => element.getAttribute("id") === hash
|
|
193
|
+
);
|
|
194
|
+
if (toScrollElement) {
|
|
195
|
+
toScrollElement.scrollIntoView({ behavior: "auto" });
|
|
241
196
|
}
|
|
242
197
|
}
|
|
243
198
|
}
|
|
@@ -24,6 +24,7 @@ export type TreeNode = {
|
|
|
24
24
|
name: string;
|
|
25
25
|
children?: Array<TreeNode>;
|
|
26
26
|
isExpanded?: boolean;
|
|
27
|
+
parent?: TreeNode;
|
|
27
28
|
};
|
|
28
29
|
|
|
29
30
|
type DropdownOption = {
|
|
@@ -109,3 +110,5 @@ export type ContentApiOptions = {
|
|
|
109
110
|
version: string;
|
|
110
111
|
language: string;
|
|
111
112
|
};
|
|
113
|
+
|
|
114
|
+
export type TocMap = { [key: string]: TreeNode };
|
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
DocumentData,
|
|
9
9
|
DocLanguage,
|
|
10
10
|
DocVersion,
|
|
11
|
-
TreeNode
|
|
11
|
+
TreeNode,
|
|
12
|
+
TocMap
|
|
12
13
|
} from "./types";
|
|
13
14
|
import { Language } from "typings/custom";
|
|
14
15
|
import { getLanguageDisplayTextById } from "dxUtils/language";
|
|
@@ -100,26 +101,26 @@ export class FetchContent {
|
|
|
100
101
|
|
|
101
102
|
private normalizeNavItem(
|
|
102
103
|
navItem: ApiNavItem,
|
|
103
|
-
tocMap:
|
|
104
|
+
tocMap: TocMap,
|
|
105
|
+
parentNavItem?: TreeNode
|
|
104
106
|
): TreeNode {
|
|
105
107
|
const name = this.calculateNavItemName(navItem, tocMap);
|
|
106
108
|
const node: TreeNode = {
|
|
107
109
|
label: navItem.text,
|
|
108
|
-
name
|
|
110
|
+
name,
|
|
111
|
+
parent: parentNavItem
|
|
109
112
|
};
|
|
113
|
+
|
|
110
114
|
if (name) {
|
|
111
115
|
tocMap[name] = node;
|
|
112
116
|
}
|
|
113
117
|
node.children = navItem.children?.map((child) =>
|
|
114
|
-
this.normalizeNavItem(child, tocMap)
|
|
118
|
+
this.normalizeNavItem(child, tocMap, node)
|
|
115
119
|
);
|
|
116
120
|
return node;
|
|
117
121
|
}
|
|
118
122
|
|
|
119
|
-
private calculateNavItemName(
|
|
120
|
-
navItem: ApiNavItem,
|
|
121
|
-
tocMap: { [key: string]: TreeNode }
|
|
122
|
-
): string {
|
|
123
|
+
private calculateNavItemName(navItem: ApiNavItem, tocMap: TocMap): string {
|
|
123
124
|
let href = navItem.a_attr?.href || "";
|
|
124
125
|
if (href.includes("#")) {
|
|
125
126
|
const [pathUrl] = href.split("#");
|
|
@@ -144,11 +145,13 @@ export class FetchContent {
|
|
|
144
145
|
}
|
|
145
146
|
|
|
146
147
|
private normalizeLanguage(language: ApiDocLanguage): DocLanguage {
|
|
147
|
-
|
|
148
148
|
return (
|
|
149
149
|
language && {
|
|
150
|
-
label:
|
|
151
|
-
|
|
150
|
+
label:
|
|
151
|
+
getLanguageDisplayTextById(
|
|
152
|
+
this.languages,
|
|
153
|
+
language.locale
|
|
154
|
+
) || language.label,
|
|
152
155
|
id: language.locale,
|
|
153
156
|
code: language.code,
|
|
154
157
|
url: language.url
|
|
@@ -25,6 +25,11 @@
|
|
|
25
25
|
</dx-button>
|
|
26
26
|
</dx-dropdown>
|
|
27
27
|
</div>
|
|
28
|
+
<doc-breadcrumbs
|
|
29
|
+
if:true={breadcrumbs}
|
|
30
|
+
breadcrumbs={breadcrumbs}
|
|
31
|
+
pixel-per-character={breadcrumbPixelPerCharacter}
|
|
32
|
+
></doc-breadcrumbs>
|
|
28
33
|
<doc-content
|
|
29
34
|
docs-data={docContent}
|
|
30
35
|
page-reference={pageReference}
|
|
@@ -8,15 +8,26 @@ import {
|
|
|
8
8
|
TreeNode,
|
|
9
9
|
Header,
|
|
10
10
|
HistoryState,
|
|
11
|
-
PageReference
|
|
11
|
+
PageReference,
|
|
12
|
+
TocMap
|
|
12
13
|
} from "./types";
|
|
13
14
|
import { SearchSyncer } from "docUtils/SearchSyncer";
|
|
14
15
|
import { LightningElementWithState } from "docBaseElements/lightningElementWithState";
|
|
15
|
-
import { Language } from "typings/custom";
|
|
16
|
+
import { Breadcrumb, Language } from "typings/custom";
|
|
16
17
|
|
|
17
18
|
// TODO: Imitating from actual implementation as doc-content use it like this. We should refactor it later.
|
|
18
19
|
const handleContentError = (error): void => console.log(error);
|
|
19
20
|
|
|
21
|
+
const FIRST_CRUMB = {
|
|
22
|
+
href: "/docs",
|
|
23
|
+
label: "Documentation"
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const PIXEL_PER_CHARACTER_MAP: { [key: string]: number } = {
|
|
27
|
+
default: 7.7,
|
|
28
|
+
"ja-jp": 12.5
|
|
29
|
+
};
|
|
30
|
+
|
|
20
31
|
export default class DocXmlContent extends LightningElementWithState<{
|
|
21
32
|
isFetchingDocument: boolean;
|
|
22
33
|
isFetchingContent: boolean;
|
|
@@ -53,7 +64,7 @@ export default class DocXmlContent extends LightningElementWithState<{
|
|
|
53
64
|
private language: DocLanguage = null;
|
|
54
65
|
private loaded = false;
|
|
55
66
|
private pdfUrl = "";
|
|
56
|
-
private tocMap =
|
|
67
|
+
private tocMap: TocMap = {};
|
|
57
68
|
private sidebarContent: Array<TreeNode> = null;
|
|
58
69
|
private version: DocVersion = null;
|
|
59
70
|
private docTitle = "";
|
|
@@ -102,6 +113,7 @@ export default class DocXmlContent extends LightningElementWithState<{
|
|
|
102
113
|
private _allLanguages: Array<Language> = [];
|
|
103
114
|
|
|
104
115
|
@track private pageReference: PageReference = {};
|
|
116
|
+
@track breadcrumbs: Array<Breadcrumb> = [];
|
|
105
117
|
|
|
106
118
|
constructor() {
|
|
107
119
|
super();
|
|
@@ -267,6 +279,13 @@ export default class DocXmlContent extends LightningElementWithState<{
|
|
|
267
279
|
}));
|
|
268
280
|
}
|
|
269
281
|
|
|
282
|
+
private get breadcrumbPixelPerCharacter() {
|
|
283
|
+
return (
|
|
284
|
+
PIXEL_PER_CHARACTER_MAP[this.language.id] ||
|
|
285
|
+
PIXEL_PER_CHARACTER_MAP.default
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
|
|
270
289
|
private handlePopState = (): void =>
|
|
271
290
|
this.updatePageReference(this.getReferenceFromUrl());
|
|
272
291
|
|
|
@@ -280,15 +299,15 @@ export default class DocXmlContent extends LightningElementWithState<{
|
|
|
280
299
|
|
|
281
300
|
if (name) {
|
|
282
301
|
const hashIndex = name.indexOf("#");
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
this.pageReference
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
302
|
+
const hash = hashIndex > -1 ? name.slice(hashIndex) : "";
|
|
303
|
+
|
|
304
|
+
const contentDocumentId =
|
|
305
|
+
hashIndex > -1 ? name.slice(0, hashIndex) : name;
|
|
306
|
+
this.updatePageReference({
|
|
307
|
+
...this.pageReference,
|
|
308
|
+
contentDocumentId,
|
|
309
|
+
hash
|
|
310
|
+
});
|
|
292
311
|
this.updateUrl();
|
|
293
312
|
}
|
|
294
313
|
}
|
|
@@ -321,15 +340,17 @@ export default class DocXmlContent extends LightningElementWithState<{
|
|
|
321
340
|
return;
|
|
322
341
|
}
|
|
323
342
|
|
|
324
|
-
const isSameDocId = this.pageReference.docId
|
|
343
|
+
const isSameDocId = this.pageReference.docId === newPageReference.docId;
|
|
325
344
|
this.pageReference = newPageReference;
|
|
326
345
|
|
|
327
|
-
if (isSameDocId) {
|
|
346
|
+
if (!isSameDocId) {
|
|
328
347
|
this.fetchDocument();
|
|
329
348
|
return;
|
|
330
349
|
}
|
|
331
350
|
|
|
332
|
-
this.fetchContent()
|
|
351
|
+
this.fetchContent()
|
|
352
|
+
.then(() => this.buildBreadcrumbs())
|
|
353
|
+
.catch(handleContentError);
|
|
333
354
|
}
|
|
334
355
|
|
|
335
356
|
getReferenceFromUrl(): PageReference {
|
|
@@ -386,6 +407,8 @@ export default class DocXmlContent extends LightningElementWithState<{
|
|
|
386
407
|
|
|
387
408
|
this.updateHeader();
|
|
388
409
|
|
|
410
|
+
this.buildBreadcrumbs();
|
|
411
|
+
|
|
389
412
|
if (this.pageReference.deliverable !== data.deliverable) {
|
|
390
413
|
this.pageReference.deliverable = data.deliverable;
|
|
391
414
|
this.updateUrl(HistoryState.REPLACE_STATE);
|
|
@@ -558,6 +581,32 @@ export default class DocXmlContent extends LightningElementWithState<{
|
|
|
558
581
|
);
|
|
559
582
|
}
|
|
560
583
|
|
|
584
|
+
private buildBreadcrumbs(): void {
|
|
585
|
+
const { contentDocumentId } = this.pageReference;
|
|
586
|
+
if (!contentDocumentId) {
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
const currentNode = this.tocMap[contentDocumentId];
|
|
591
|
+
this.breadcrumbs = this.nodeToBreadcrumb(currentNode);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
private nodeToBreadcrumb(node?: TreeNode): Breadcrumb[] {
|
|
595
|
+
if (!node) {
|
|
596
|
+
return [FIRST_CRUMB];
|
|
597
|
+
}
|
|
598
|
+
return [
|
|
599
|
+
...this.nodeToBreadcrumb(node.parent),
|
|
600
|
+
{
|
|
601
|
+
href: this.pageReferenceToString({
|
|
602
|
+
...this.pageReference,
|
|
603
|
+
contentDocumentId: node.name
|
|
604
|
+
}),
|
|
605
|
+
label: node.label
|
|
606
|
+
}
|
|
607
|
+
];
|
|
608
|
+
}
|
|
609
|
+
|
|
561
610
|
addMetatags(): void {
|
|
562
611
|
const div = document.createElement("div");
|
|
563
612
|
div.innerHTML = this.docContent;
|