@salesforcedevs/docs-components 0.17.0 → 0.17.12-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 +18 -3
- package/package.json +18 -7
- package/src/modules/README.md +41 -0
- package/src/modules/doc/amfModelParser/amfModelParser.ts +674 -0
- package/src/modules/doc/amfReference/amfReference.css +25 -0
- package/src/modules/doc/amfReference/amfReference.html +55 -0
- package/src/modules/doc/amfReference/amfReference.ts +1467 -0
- package/src/modules/doc/amfReference/constants.ts +76 -0
- package/src/modules/doc/amfReference/types.ts +125 -0
- package/src/modules/doc/amfTopic/amfTopic.css +21 -0
- package/src/modules/doc/amfTopic/amfTopic.html +3 -0
- package/src/modules/doc/amfTopic/amfTopic.ts +111 -0
- package/src/modules/doc/amfTopic/types.ts +56 -0
- package/src/modules/doc/amfTopic/utils.ts +136 -0
- package/src/modules/doc/breadcrumbItem/breadcrumbItem.css +51 -0
- package/src/modules/doc/breadcrumbItem/breadcrumbItem.html +5 -0
- package/src/modules/doc/breadcrumbItem/breadcrumbItem.ts +71 -0
- package/src/modules/doc/breadcrumbs/breadcrumbs.css +27 -0
- package/src/modules/doc/breadcrumbs/breadcrumbs.html +58 -0
- package/src/modules/doc/breadcrumbs/breadcrumbs.ts +183 -0
- package/src/modules/doc/componentPlayground/componentPlayground.css +22 -0
- package/src/modules/doc/componentPlayground/componentPlayground.html +20 -0
- package/src/modules/doc/componentPlayground/componentPlayground.ts +42 -0
- package/src/modules/doc/content/content.css +89 -70
- package/src/modules/doc/content/content.html +1 -0
- package/src/modules/doc/content/content.ts +188 -195
- package/src/modules/doc/contentCallout/contentCallout.css +17 -23
- package/src/modules/doc/contentCallout/contentCallout.html +13 -4
- package/src/modules/doc/contentCallout/contentCallout.ts +16 -3
- package/src/modules/doc/contentLayout/contentLayout.css +1 -0
- package/src/modules/doc/contentLayout/contentLayout.html +46 -0
- package/src/modules/doc/contentLayout/contentLayout.ts +524 -0
- package/src/modules/doc/doDont/doDont.css +47 -0
- package/src/modules/doc/doDont/doDont.html +27 -0
- package/src/modules/doc/doDont/doDont.ts +17 -0
- package/src/modules/doc/header/header.css +70 -37
- package/src/modules/doc/header/header.html +41 -138
- package/src/modules/doc/header/header.ts +56 -78
- package/src/modules/doc/heading/heading.css +33 -0
- package/src/modules/doc/heading/heading.html +14 -0
- package/src/modules/doc/heading/heading.ts +67 -0
- package/src/modules/doc/headingAnchor/headingAnchor.css +3 -3
- package/src/modules/doc/headingAnchor/headingAnchor.ts +2 -2
- package/src/modules/doc/headingContent/headingContent.css +53 -0
- package/src/modules/doc/headingContent/headingContent.html +13 -0
- package/src/modules/doc/headingContent/headingContent.ts +30 -0
- package/src/modules/doc/lwcContentLayout/lwcContentLayout.css +1 -0
- package/src/modules/doc/lwcContentLayout/lwcContentLayout.html +45 -0
- package/src/modules/doc/lwcContentLayout/lwcContentLayout.ts +256 -0
- package/src/modules/doc/overview/overview.css +40 -0
- package/src/modules/doc/overview/overview.html +34 -0
- package/src/modules/doc/overview/overview.ts +12 -0
- package/src/modules/doc/phase/phase.css +70 -0
- package/src/modules/doc/phase/phase.html +38 -0
- package/src/modules/doc/phase/phase.ts +93 -0
- package/src/modules/doc/specificationContent/specificationContent.css +36 -0
- package/src/modules/doc/specificationContent/specificationContent.html +167 -0
- package/src/modules/doc/specificationContent/specificationContent.ts +127 -0
- package/src/modules/doc/sprigSurvey/sprigSurvey.html +20 -0
- package/src/modules/doc/sprigSurvey/sprigSurvey.scoped.css +16 -0
- package/src/modules/doc/sprigSurvey/sprigSurvey.ts +16 -0
- package/src/modules/doc/toc/toc.ts +1 -1
- package/src/modules/doc/versionPicker/versionPicker.css +64 -0
- package/src/modules/doc/versionPicker/versionPicker.html +38 -0
- package/src/modules/doc/versionPicker/versionPicker.ts +65 -0
- package/src/modules/doc/xmlContent/types.ts +120 -0
- package/src/modules/doc/xmlContent/utils.ts +163 -0
- package/src/modules/doc/xmlContent/xmlContent.css +54 -0
- package/src/modules/doc/xmlContent/xmlContent.html +54 -0
- package/src/modules/doc/xmlContent/xmlContent.ts +763 -0
- package/src/modules/docHelpers/amfStyle/amfStyle.css +355 -0
- package/src/modules/docHelpers/contentLayoutStyle/contentLayoutStyle.css +131 -0
- package/src/modules/docHelpers/imgStyle/imgStyle.css +59 -0
- package/src/modules/docHelpers/status/status.css +22 -0
- package/src/modules/docUtils/searchSyncer/searchSyncer.ts +86 -0
- package/src/modules/docUtils/utils/__mocks__/coveo.analytics.ts +16 -0
- package/src/modules/docUtils/utils/coveo.analytics.d.ts +10 -0
- package/src/modules/docUtils/utils/utils.ts +32 -0
- package/LICENSE +0 -12
- package/src/modules/doc/content/__tests__/content.test.ts +0 -312
- package/src/modules/doc/content/__tests__/mockDocContent.ts +0 -348
- package/src/modules/doc/content/__tests__/mockPageReference.ts +0 -8
- package/src/modules/doc/content/__tests__/mockSidebar.ts +0 -81
- package/src/modules/doc/content/content.stories.ts +0 -148
- package/src/modules/doc/contentCallout/__tests__/contentCallout.test.ts +0 -80
- package/src/modules/doc/contentCallout/__tests__/mockProps.ts +0 -14
- package/src/modules/doc/contentCallout/contentCallout.stories.ts +0 -29
- package/src/modules/doc/contentMedia/__tests__/contentMedia.test.ts +0 -97
- package/src/modules/doc/contentMedia/contentMedia.stories.ts +0 -113
- package/src/modules/doc/header/__tests__/coveoConfig.ts +0 -12
- package/src/modules/doc/header/__tests__/header.test.ts +0 -445
- package/src/modules/doc/header/__tests__/mockNavDevelopers.ts +0 -427
- package/src/modules/doc/header/__tests__/mockNavs.ts +0 -115
- package/src/modules/doc/header/__tests__/mockProps.ts +0 -152
- package/src/modules/doc/header/header.stories.ts +0 -190
- package/src/modules/doc/headingAnchor/__tests__/headingAnchor.test.ts +0 -111
- package/src/modules/doc/headingAnchor/headingAnchor.stories.ts +0 -33
- package/src/modules/doc/nav/__tests__/mockAvailableLanguages.ts +0 -8
- package/src/modules/doc/nav/__tests__/mockAvailableVersions.ts +0 -122
- package/src/modules/doc/nav/__tests__/mockPageReference.ts +0 -8
- package/src/modules/doc/nav/__tests__/mockPdfUrl.ts +0 -1
- package/src/modules/doc/nav/__tests__/mockSelectedLanguage.ts +0 -8
- package/src/modules/doc/nav/__tests__/mockSelectedVersion.ts +0 -8
- package/src/modules/doc/nav/__tests__/mockToc.ts +0 -146
- package/src/modules/doc/nav/__tests__/nav.test.ts +0 -58
- package/src/modules/doc/toc/__tests__/mockPageReference.ts +0 -8
- package/src/modules/doc/toc/__tests__/mockToc.ts +0 -146
- package/src/modules/doc/toc/__tests__/toc.test.ts +0 -29
- package/src/modules/doc/toolbar/__tests__/mockAvailableLanguages.ts +0 -8
- package/src/modules/doc/toolbar/__tests__/mockAvailableVersions.ts +0 -122
- package/src/modules/doc/toolbar/__tests__/mockPdfUrl.ts +0 -1
- package/src/modules/doc/toolbar/__tests__/mockSelectedLanguage.ts +0 -8
- package/src/modules/doc/toolbar/__tests__/mockSelectedVersion.ts +0 -8
- package/src/modules/doc/toolbar/__tests__/toolbar.test.ts +0 -44
|
@@ -0,0 +1,1467 @@
|
|
|
1
|
+
import { LightningElement, api, track } from "lwc";
|
|
2
|
+
import { noCase } from "no-case";
|
|
3
|
+
import { sentenceCase } from "sentence-case";
|
|
4
|
+
import qs from "query-string";
|
|
5
|
+
import { AmfModelParser } from "doc/amfModelParser";
|
|
6
|
+
import { normalizeBoolean } from "dxUtils/normalizers";
|
|
7
|
+
import type { OptionWithLink } from "typings/custom";
|
|
8
|
+
import type {
|
|
9
|
+
AmfConfig,
|
|
10
|
+
AmfMetadataTopic,
|
|
11
|
+
AmfModel,
|
|
12
|
+
AmfModelRecord,
|
|
13
|
+
NavItem,
|
|
14
|
+
ParsedTopicModel,
|
|
15
|
+
TopicModel,
|
|
16
|
+
ReferenceVersion,
|
|
17
|
+
ReferenceSetConfig,
|
|
18
|
+
AmfMetaTopicType,
|
|
19
|
+
RouteMeta,
|
|
20
|
+
ParsedMarkdownTopic
|
|
21
|
+
} from "./types";
|
|
22
|
+
|
|
23
|
+
import {
|
|
24
|
+
NAVIGATION_ITEMS,
|
|
25
|
+
URL_CONFIG,
|
|
26
|
+
REFERENCE_TYPES,
|
|
27
|
+
oldReferenceIdNewReferenceIdMap
|
|
28
|
+
} from "./constants";
|
|
29
|
+
import { restoreScroll } from "dx/scrollManager";
|
|
30
|
+
import { DocPhaseInfo } from "typings/custom";
|
|
31
|
+
import { oldVersionDocInfo } from "docUtils/utils";
|
|
32
|
+
|
|
33
|
+
type NavigationItem = {
|
|
34
|
+
label: string;
|
|
35
|
+
name: string;
|
|
36
|
+
isExpanded: boolean;
|
|
37
|
+
children: ParsedMarkdownTopic[];
|
|
38
|
+
isChildrenLoading: boolean;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export default class AmfReference extends LightningElement {
|
|
42
|
+
@api breadcrumbs: string | null = null;
|
|
43
|
+
@api sidebarHeader!: string;
|
|
44
|
+
@api tocTitle?: string;
|
|
45
|
+
@api tocOptions?: string;
|
|
46
|
+
@api languages!: OptionWithLink[];
|
|
47
|
+
@api language!: string;
|
|
48
|
+
@api hideFooter = false;
|
|
49
|
+
@track navigation = [] as NavigationItem[];
|
|
50
|
+
@track versions: Array<ReferenceVersion> = [];
|
|
51
|
+
@track showVersionBanner = false;
|
|
52
|
+
|
|
53
|
+
// Update this to update what component gets rendered in the content block
|
|
54
|
+
@track
|
|
55
|
+
protected topicModel!: TopicModel;
|
|
56
|
+
|
|
57
|
+
get isVersionEnabled(): boolean {
|
|
58
|
+
return !!this._referenceSetConfig?.versions?.length;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Gives if the currently selected reference is spec based or not
|
|
63
|
+
*/
|
|
64
|
+
get showSpecBasedReference(): boolean {
|
|
65
|
+
return this.isSpecBasedReference(this._currentReferenceId);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@api
|
|
69
|
+
get referenceSetConfig(): ReferenceSetConfig {
|
|
70
|
+
return this._referenceSetConfig;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
set referenceSetConfig(value: ReferenceSetConfig) {
|
|
74
|
+
// No change, do nothing.
|
|
75
|
+
if (value === this._referenceSetConfig) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
const refConfig =
|
|
81
|
+
typeof value === "string" ? JSON.parse(value) : value;
|
|
82
|
+
if (!(<ReferenceSetConfig>refConfig).versions) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
this._referenceSetConfig = refConfig;
|
|
86
|
+
} catch (e) {
|
|
87
|
+
this._referenceSetConfig = {
|
|
88
|
+
refList: [],
|
|
89
|
+
versions: []
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
this._amfConfigList = this._referenceSetConfig.refList || [];
|
|
94
|
+
|
|
95
|
+
this._amfConfigList.forEach((amfConfig) => {
|
|
96
|
+
this._amfConfigMap.set(amfConfig.id, amfConfig);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
if (this._amfConfigList.length > 0) {
|
|
100
|
+
this._currentReferenceId =
|
|
101
|
+
this._referenceSetConfig.refId || this._amfConfigList[0].id;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (this.isVersionEnabled) {
|
|
105
|
+
const selectedVersion = this.getSelectedVersion();
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* If current selected is markdown based reference,
|
|
109
|
+
* We will assign versions once the selected item url is updated
|
|
110
|
+
*/
|
|
111
|
+
if (this.isSpecBasedReference(this._currentReferenceId)) {
|
|
112
|
+
this.versions = this.getVersions();
|
|
113
|
+
}
|
|
114
|
+
this.selectedVersion = selectedVersion;
|
|
115
|
+
if (this.isSpecBasedReference(this._currentReferenceId)) {
|
|
116
|
+
this.isVersionFetched = true;
|
|
117
|
+
if (this.oldVersionInfo) {
|
|
118
|
+
this.showVersionBanner = true;
|
|
119
|
+
} else {
|
|
120
|
+
this.latestVersion = true;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
this.isVersionFetched = true;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// This is to check if the url is hash based and redirect if needed
|
|
128
|
+
const redirectUrl = this.getHashBasedRedirectUrl();
|
|
129
|
+
if (redirectUrl) {
|
|
130
|
+
window.location.href = redirectUrl;
|
|
131
|
+
} else {
|
|
132
|
+
this.updateAmfConfigInView();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
@api
|
|
137
|
+
get docPhaseInfo(): string | null {
|
|
138
|
+
return this.selectedReferenceDocPhase || null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
set docPhaseInfo(value: string) {
|
|
142
|
+
if (value) {
|
|
143
|
+
this.isParentLevelDocPhaseEnabled = true;
|
|
144
|
+
this.selectedReferenceDocPhase = value;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
@api
|
|
149
|
+
get expandChildren() {
|
|
150
|
+
return this._expandChildren;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
set expandChildren(value) {
|
|
154
|
+
this._expandChildren = normalizeBoolean(value);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private get enableFooter(): boolean {
|
|
158
|
+
return !this.hideFooter;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
private get emptyStateMessage(): string {
|
|
162
|
+
return JSON.stringify([
|
|
163
|
+
"Please consider misspellings",
|
|
164
|
+
"Try different search keywords",
|
|
165
|
+
"Select a relevant API specification"
|
|
166
|
+
]);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// model
|
|
170
|
+
protected _amfConfigList: AmfConfig[] = [];
|
|
171
|
+
protected _amfConfigMap: Map<string, AmfConfig> = new Map();
|
|
172
|
+
protected _referenceSetConfig!: ReferenceSetConfig;
|
|
173
|
+
protected _currentReferenceId = "";
|
|
174
|
+
|
|
175
|
+
protected parentReferenceUrls = [] as string[];
|
|
176
|
+
protected amfMap: Record<string, AmfModelRecord> = {};
|
|
177
|
+
protected amfFetchPromiseMap = {} as any;
|
|
178
|
+
protected metadata: { [key: string]: AmfMetadataTopic } = {};
|
|
179
|
+
protected selectedTopic?: AmfMetaTopicType = undefined;
|
|
180
|
+
protected selectedSidebarValue: string | undefined = undefined;
|
|
181
|
+
|
|
182
|
+
protected selectedVersion: ReferenceVersion | null = null;
|
|
183
|
+
|
|
184
|
+
private hasRendered = false;
|
|
185
|
+
|
|
186
|
+
private isParentLevelDocPhaseEnabled = false;
|
|
187
|
+
private selectedReferenceDocPhase?: string | null = null;
|
|
188
|
+
private _expandChildren?: boolean = false;
|
|
189
|
+
private isVersionFetched = false;
|
|
190
|
+
private latestVersion = false;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Key for storing the currently selected reference url. This will be used to save the
|
|
194
|
+
* previously selected reference url and restoring it when changing between reference versions.
|
|
195
|
+
*/
|
|
196
|
+
private readonly docsReferenceUrlSessionKey: string = "docsReferenceUrl";
|
|
197
|
+
|
|
198
|
+
_boundOnApiNavigationChanged;
|
|
199
|
+
_boundUpdateSelectedItemFromUrlQuery;
|
|
200
|
+
|
|
201
|
+
constructor() {
|
|
202
|
+
super();
|
|
203
|
+
|
|
204
|
+
this._boundOnApiNavigationChanged =
|
|
205
|
+
this.onApiNavigationChanged.bind(this);
|
|
206
|
+
this._boundUpdateSelectedItemFromUrlQuery =
|
|
207
|
+
this.updateSelectedItemFromUrlQuery.bind(this);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
connectedCallback(): void {
|
|
211
|
+
this.addEventListener(
|
|
212
|
+
"api-navigation-selection-changed",
|
|
213
|
+
this._boundOnApiNavigationChanged
|
|
214
|
+
);
|
|
215
|
+
window.addEventListener(
|
|
216
|
+
"popstate",
|
|
217
|
+
this._boundUpdateSelectedItemFromUrlQuery
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
disconnectedCallback(): void {
|
|
222
|
+
this.removeEventListener(
|
|
223
|
+
"api-navigation-selection-changed",
|
|
224
|
+
this._boundOnApiNavigationChanged
|
|
225
|
+
);
|
|
226
|
+
window.removeEventListener(
|
|
227
|
+
"popstate",
|
|
228
|
+
this._boundUpdateSelectedItemFromUrlQuery
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
renderedCallback(): void {
|
|
233
|
+
if (!this.hasRendered) {
|
|
234
|
+
this.hasRendered = true;
|
|
235
|
+
if (this._amfConfigList && this._amfConfigList.length) {
|
|
236
|
+
// If amfConfig has a value and length, it is assumed that fetch
|
|
237
|
+
// has already been called and promises stored.
|
|
238
|
+
this.updateView();
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Check if the URL hash to see whether this is one we want to redirect
|
|
245
|
+
* See GUS W-10718771 for references where we want hash-based redirects
|
|
246
|
+
* Return if we needs to redirect url to updated url
|
|
247
|
+
*/
|
|
248
|
+
private getHashBasedRedirectUrl(): string | undefined {
|
|
249
|
+
const { hash } = window.location;
|
|
250
|
+
let hashBasedRedirectUrl = "";
|
|
251
|
+
if (hash) {
|
|
252
|
+
const strippedHash = hash.startsWith("#") ? hash.slice(1) : hash;
|
|
253
|
+
const strippedHashItems = strippedHash
|
|
254
|
+
? strippedHash.split(":")
|
|
255
|
+
: [];
|
|
256
|
+
if (strippedHashItems.length) {
|
|
257
|
+
const referenceId = strippedHashItems[0];
|
|
258
|
+
const meta = strippedHashItems[1];
|
|
259
|
+
const encodedMeta = this.getUrlEncoded(meta);
|
|
260
|
+
const updatedReferenceId =
|
|
261
|
+
oldReferenceIdNewReferenceIdMap[referenceId];
|
|
262
|
+
const newReferenceId = updatedReferenceId || referenceId;
|
|
263
|
+
const referenceItemConfig =
|
|
264
|
+
this.getAmfConfigWithId(newReferenceId);
|
|
265
|
+
if (referenceItemConfig) {
|
|
266
|
+
hashBasedRedirectUrl = `${referenceItemConfig.href}?meta=${encodedMeta}`;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return hashBasedRedirectUrl;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* @param referenceId
|
|
275
|
+
* @returns AMFConfig with given reference Id
|
|
276
|
+
*/
|
|
277
|
+
private getAmfConfigWithId(referenceId: string): AmfConfig | undefined {
|
|
278
|
+
return this._amfConfigMap.get(referenceId);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* @param referenceId
|
|
283
|
+
* @returns if the reference is spec based one or not with given referenceId.
|
|
284
|
+
*/
|
|
285
|
+
private isSpecBasedReference(referenceId: string): boolean {
|
|
286
|
+
const selectedReference = this.getAmfConfigWithId(referenceId);
|
|
287
|
+
return selectedReference
|
|
288
|
+
? selectedReference.referenceType !== REFERENCE_TYPES.markdown
|
|
289
|
+
: false;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/*
|
|
293
|
+
* Refactor below method when sidebar allows sending extraData along with the name for each item.
|
|
294
|
+
* See if we can refactor the below method using regex.
|
|
295
|
+
*/
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* @param url
|
|
299
|
+
* @returns reference Id from url path / selected sidebar item.
|
|
300
|
+
*/
|
|
301
|
+
private getReferenceIdFromUrl(url: string): string {
|
|
302
|
+
let referenceId = "";
|
|
303
|
+
const urlItems = url.split("/references/");
|
|
304
|
+
if (urlItems.length > 1) {
|
|
305
|
+
const rightSidePart = urlItems[1];
|
|
306
|
+
|
|
307
|
+
//This covers urls like "/project-name/references/reference-id/..."
|
|
308
|
+
const slashSeparatorItems = rightSidePart.split("/");
|
|
309
|
+
|
|
310
|
+
//This covers urls like "/project-name/references/reference-id?meta=Summary"
|
|
311
|
+
const querySeparatorItems = slashSeparatorItems[0].split("?");
|
|
312
|
+
|
|
313
|
+
referenceId = querySeparatorItems[0];
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return referenceId;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
private get oldVersionInfo(): DocPhaseInfo | null {
|
|
320
|
+
let info = null;
|
|
321
|
+
if (this.versions.length > 1 && this.selectedVersion) {
|
|
322
|
+
const currentGAVersionRef = this.versions[0];
|
|
323
|
+
if (this.selectedVersion.id !== currentGAVersionRef.id) {
|
|
324
|
+
info = oldVersionDocInfo(currentGAVersionRef.link.href);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return info;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* @returns versions to be shown in the dropdown
|
|
332
|
+
* For markdown based specs, Adds selected markdown topic url to same references
|
|
333
|
+
*/
|
|
334
|
+
private getVersions(): Array<ReferenceVersion> {
|
|
335
|
+
const allVersions = this._referenceSetConfig.versions;
|
|
336
|
+
if (!this.isSpecBasedReference(this._currentReferenceId)) {
|
|
337
|
+
const currentRefMeta = this.getMarkdownReferenceMeta(
|
|
338
|
+
window.location.href
|
|
339
|
+
);
|
|
340
|
+
if (currentRefMeta) {
|
|
341
|
+
for (let i = 0; i < allVersions.length; i++) {
|
|
342
|
+
const versionItem = allVersions[i];
|
|
343
|
+
const referenceLink = versionItem.link.href;
|
|
344
|
+
const referenceId =
|
|
345
|
+
this.getReferenceIdFromUrl(referenceLink);
|
|
346
|
+
if (this._currentReferenceId === referenceId) {
|
|
347
|
+
// This is to navigate to respective topic in the changed version
|
|
348
|
+
versionItem.link.href = `${referenceLink}/${currentRefMeta}`;
|
|
349
|
+
allVersions[i] = versionItem;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return allVersions;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Returns the selected version or the first available version.
|
|
359
|
+
*/
|
|
360
|
+
private getSelectedVersion(): ReferenceVersion | null {
|
|
361
|
+
const versions = this._referenceSetConfig?.versions || [];
|
|
362
|
+
const selectedVersion = versions.find(
|
|
363
|
+
(v: ReferenceVersion) => v.selected
|
|
364
|
+
);
|
|
365
|
+
// return a selected version if there is one, else return the first one.
|
|
366
|
+
return selectedVersion || (versions.length && versions[0]) || null;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
private updateAmfConfigInView(): void {
|
|
370
|
+
if (this._amfConfigList && this._amfConfigList.length) {
|
|
371
|
+
// fetch AMF Json as soon as config is set
|
|
372
|
+
this.populateReferenceItems();
|
|
373
|
+
// update() must be called after renderedCallback.
|
|
374
|
+
if (this.hasRendered) {
|
|
375
|
+
this.updateView();
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
private async fetchAmf(
|
|
381
|
+
amfConfig: AmfConfig
|
|
382
|
+
): Promise<AmfModel | AmfModel[]> {
|
|
383
|
+
const { amf } = amfConfig;
|
|
384
|
+
const response = await fetch(amf!, {
|
|
385
|
+
headers: {
|
|
386
|
+
"Cache-Control": `max-age=86400`
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
const json = await response.json();
|
|
390
|
+
return json;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Returns whether current location is project root path like ../example-project/references
|
|
395
|
+
*/
|
|
396
|
+
private isProjectRootPath(): boolean {
|
|
397
|
+
return this.getReferenceIdFromUrl(window.location.href) === "";
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Returns whether given url is parent reference path like ../example-project/references/reference-id
|
|
402
|
+
*/
|
|
403
|
+
private isParentReferencePath(urlPath?: string | null): boolean {
|
|
404
|
+
if (!urlPath) {
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
const parentReferenceIndex = this.parentReferenceUrls.findIndex(
|
|
408
|
+
(referenceUrl: string) => {
|
|
409
|
+
return urlPath.endsWith(referenceUrl);
|
|
410
|
+
}
|
|
411
|
+
);
|
|
412
|
+
return parentReferenceIndex !== -1;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Expands the children of Markdown-based References.
|
|
417
|
+
*/
|
|
418
|
+
private expandChildrenForMarkdownReferences(
|
|
419
|
+
children: ParsedMarkdownTopic[]
|
|
420
|
+
): void {
|
|
421
|
+
if (!children) {
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
for (const childNode of children) {
|
|
425
|
+
childNode.isExpanded = true;
|
|
426
|
+
this.expandChildrenForMarkdownReferences(childNode.children);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Populates reference Items from amfConfigList and assigns it to navigation for sidebar
|
|
432
|
+
*/
|
|
433
|
+
private populateReferenceItems(): void {
|
|
434
|
+
const navAmfOrder = [] as NavigationItem[];
|
|
435
|
+
for (const [index, amfConfig] of this._amfConfigList.entries()) {
|
|
436
|
+
let navItemChildren = [] as ParsedMarkdownTopic[];
|
|
437
|
+
let isChildrenLoading = false;
|
|
438
|
+
if (amfConfig.referenceType !== REFERENCE_TYPES.markdown) {
|
|
439
|
+
if (amfConfig.isSelected) {
|
|
440
|
+
const amfPromise = this.fetchAmf(amfConfig).then(
|
|
441
|
+
(amfJson) => {
|
|
442
|
+
this.updateModel(amfConfig.id, amfJson);
|
|
443
|
+
this.assignNavigationItemsFromAmf(amfConfig, index);
|
|
444
|
+
}
|
|
445
|
+
);
|
|
446
|
+
this.amfFetchPromiseMap[amfConfig.id] = amfPromise;
|
|
447
|
+
}
|
|
448
|
+
isChildrenLoading = true;
|
|
449
|
+
} else {
|
|
450
|
+
const isExpandChildrenEnabled = this.isExpandChildrenEnabled(
|
|
451
|
+
amfConfig.id
|
|
452
|
+
);
|
|
453
|
+
// check whether we should expand all the child nodes, this is required for Coveo to crawl.
|
|
454
|
+
if (isExpandChildrenEnabled) {
|
|
455
|
+
this.expandChildrenForMarkdownReferences(
|
|
456
|
+
amfConfig.topic!.children
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
navItemChildren = amfConfig.topic!.children;
|
|
460
|
+
}
|
|
461
|
+
// store nav items for each spec in order
|
|
462
|
+
navAmfOrder[index] = {
|
|
463
|
+
label: amfConfig.title,
|
|
464
|
+
name: amfConfig.href,
|
|
465
|
+
isExpanded:
|
|
466
|
+
amfConfig.isSelected ||
|
|
467
|
+
this.isExpandChildrenEnabled(amfConfig.id),
|
|
468
|
+
children: navItemChildren,
|
|
469
|
+
isChildrenLoading
|
|
470
|
+
};
|
|
471
|
+
this.parentReferenceUrls.push(amfConfig.href);
|
|
472
|
+
}
|
|
473
|
+
this.navigation = navAmfOrder;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Returns a boolean indicating whether the children should be expanded or not.
|
|
478
|
+
*/
|
|
479
|
+
private isExpandChildrenEnabled(referenceId: string): boolean {
|
|
480
|
+
return (
|
|
481
|
+
!!this.expandChildren && this._currentReferenceId === referenceId
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Stores fetched AMF JSON value.
|
|
487
|
+
* Creates and stores a new AmfModelParser instance for the AMF spec.
|
|
488
|
+
* @param {*} referenceId
|
|
489
|
+
* @param {*} amf
|
|
490
|
+
*/
|
|
491
|
+
private updateModel(referenceId: string, amf: AmfModel | AmfModel[]): void {
|
|
492
|
+
const parser = new AmfModelParser(amf);
|
|
493
|
+
this.amfMap[referenceId] = {
|
|
494
|
+
model: amf,
|
|
495
|
+
parser: parser,
|
|
496
|
+
parsedModel: parser.parsedModel
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Convert any case to a readable Title
|
|
502
|
+
* ex: snake_case => Snake case
|
|
503
|
+
* ex: camelCase => Camel case
|
|
504
|
+
* ex: PascalCase => Pascal case
|
|
505
|
+
* @param label
|
|
506
|
+
* @returns string
|
|
507
|
+
*/
|
|
508
|
+
private getTitleForLabel(label: string): string {
|
|
509
|
+
return sentenceCase(noCase(label));
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Transforms a list of model data for endpoints into corresponding
|
|
514
|
+
* navigation list items that are compatible with dx-sidebar.
|
|
515
|
+
* Compatible with transforming AMF data parsed from both RAML and OAS spec.
|
|
516
|
+
* Transforms a flat list of endpoints into a nested list based on indentation level
|
|
517
|
+
* for RAML spec.
|
|
518
|
+
* @param {Array<Object>} items An array of endpoints.
|
|
519
|
+
* @returns {array<Object>} List of navigation items
|
|
520
|
+
*/
|
|
521
|
+
private assignEndpointNavItems(
|
|
522
|
+
parentReferencePath: string,
|
|
523
|
+
referenceId: string,
|
|
524
|
+
items: ParsedTopicModel[]
|
|
525
|
+
): NavItem[] {
|
|
526
|
+
const methodList = [] as NavItem[];
|
|
527
|
+
|
|
528
|
+
items.forEach((item) => {
|
|
529
|
+
item.methods?.forEach((method) => {
|
|
530
|
+
const title =
|
|
531
|
+
this.getTitleForLabel(method.label!) || method.method;
|
|
532
|
+
const meta = this.addToMetadata(
|
|
533
|
+
parentReferencePath,
|
|
534
|
+
referenceId,
|
|
535
|
+
"method",
|
|
536
|
+
method,
|
|
537
|
+
title
|
|
538
|
+
);
|
|
539
|
+
methodList.push(
|
|
540
|
+
Object.assign(method, {
|
|
541
|
+
name: this.getReferencePathWithMeta(
|
|
542
|
+
parentReferencePath,
|
|
543
|
+
meta
|
|
544
|
+
),
|
|
545
|
+
label: title
|
|
546
|
+
})
|
|
547
|
+
);
|
|
548
|
+
});
|
|
549
|
+
});
|
|
550
|
+
return methodList;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Gives URL path for reference items, Which can be used to push to the history
|
|
555
|
+
*/
|
|
556
|
+
private getReferencePathWithMeta(
|
|
557
|
+
parentReferencePath: string,
|
|
558
|
+
meta: string
|
|
559
|
+
): string {
|
|
560
|
+
// update the encoded url meta param
|
|
561
|
+
const encodedMeta = meta ? this.getUrlEncoded(meta) : "";
|
|
562
|
+
return encodedMeta ? `${parentReferencePath}?meta=${encodedMeta}` : "";
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* Assigns Navigation Items to dx-sidebar from the parsed AMF model.
|
|
567
|
+
* Adds each nav item to the Metadata by type.
|
|
568
|
+
* The 'summary' nav item has no children.
|
|
569
|
+
* The 'endpoint' nav item may have nested children.
|
|
570
|
+
*/
|
|
571
|
+
private assignNavigationItemsFromAmf(
|
|
572
|
+
amfConfig: AmfConfig,
|
|
573
|
+
amfIdx: number
|
|
574
|
+
): void {
|
|
575
|
+
const referenceId = amfConfig.id;
|
|
576
|
+
const parentReferencePath = amfConfig.href;
|
|
577
|
+
const model = this.amfMap[referenceId].parser.parsedModel;
|
|
578
|
+
|
|
579
|
+
const children: any[] = [];
|
|
580
|
+
const expandChildren = this.isExpandChildrenEnabled(referenceId);
|
|
581
|
+
|
|
582
|
+
NAVIGATION_ITEMS.forEach(
|
|
583
|
+
({ label, name, childrenPropertyName, type }) => {
|
|
584
|
+
const indexedName = `${name}-${amfIdx}`;
|
|
585
|
+
switch (type) {
|
|
586
|
+
case "summary": {
|
|
587
|
+
const summary = model[type];
|
|
588
|
+
const meta = this.addToMetadata(
|
|
589
|
+
parentReferencePath,
|
|
590
|
+
referenceId,
|
|
591
|
+
type,
|
|
592
|
+
summary,
|
|
593
|
+
label
|
|
594
|
+
);
|
|
595
|
+
children.push({
|
|
596
|
+
label,
|
|
597
|
+
name: this.getReferencePathWithMeta(
|
|
598
|
+
parentReferencePath,
|
|
599
|
+
meta
|
|
600
|
+
)
|
|
601
|
+
});
|
|
602
|
+
break;
|
|
603
|
+
}
|
|
604
|
+
case "endpoint":
|
|
605
|
+
if (
|
|
606
|
+
model[childrenPropertyName!] &&
|
|
607
|
+
model[childrenPropertyName!].length
|
|
608
|
+
) {
|
|
609
|
+
const amfTopicId = this.getFormattedIdentifier(
|
|
610
|
+
referenceId,
|
|
611
|
+
indexedName
|
|
612
|
+
);
|
|
613
|
+
const childTopics = this.assignEndpointNavItems(
|
|
614
|
+
parentReferencePath,
|
|
615
|
+
referenceId,
|
|
616
|
+
model[childrenPropertyName!]
|
|
617
|
+
);
|
|
618
|
+
children.push({
|
|
619
|
+
label,
|
|
620
|
+
name: this.getReferencePathWithMeta(
|
|
621
|
+
parentReferencePath,
|
|
622
|
+
this.metadata[amfTopicId]?.meta
|
|
623
|
+
),
|
|
624
|
+
isExpanded: expandChildren,
|
|
625
|
+
children: childTopics
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
break;
|
|
629
|
+
case "security":
|
|
630
|
+
case "type":
|
|
631
|
+
if (model[childrenPropertyName!]?.length) {
|
|
632
|
+
// Sorting the types alphabetically
|
|
633
|
+
model[childrenPropertyName!].sort(
|
|
634
|
+
(typeA: any, typeB: any) => {
|
|
635
|
+
const typeALbl = typeA.label.toLowerCase();
|
|
636
|
+
const typeBLbl = typeB.label.toLowerCase();
|
|
637
|
+
return typeALbl < typeBLbl
|
|
638
|
+
? -1
|
|
639
|
+
: typeALbl > typeBLbl
|
|
640
|
+
? 1
|
|
641
|
+
: 0;
|
|
642
|
+
}
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
// eslint-disable-next-line no-fallthrough
|
|
646
|
+
default:
|
|
647
|
+
if (
|
|
648
|
+
model[childrenPropertyName!] &&
|
|
649
|
+
model[childrenPropertyName!].length
|
|
650
|
+
) {
|
|
651
|
+
const amfTopicId = this.getFormattedIdentifier(
|
|
652
|
+
referenceId,
|
|
653
|
+
indexedName
|
|
654
|
+
);
|
|
655
|
+
children.push({
|
|
656
|
+
label,
|
|
657
|
+
name: this.getReferencePathWithMeta(
|
|
658
|
+
parentReferencePath,
|
|
659
|
+
this.metadata[amfTopicId]?.meta
|
|
660
|
+
),
|
|
661
|
+
isExpanded: expandChildren,
|
|
662
|
+
children: model[childrenPropertyName!].map(
|
|
663
|
+
(topic: any) => {
|
|
664
|
+
const meta = this.addToMetadata(
|
|
665
|
+
parentReferencePath,
|
|
666
|
+
referenceId,
|
|
667
|
+
type,
|
|
668
|
+
topic,
|
|
669
|
+
topic.label
|
|
670
|
+
);
|
|
671
|
+
return {
|
|
672
|
+
label: topic.label,
|
|
673
|
+
name: this.getReferencePathWithMeta(
|
|
674
|
+
parentReferencePath,
|
|
675
|
+
meta
|
|
676
|
+
)
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
)
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
);
|
|
685
|
+
|
|
686
|
+
this.navigation[amfIdx] = {
|
|
687
|
+
...this.navigation[amfIdx],
|
|
688
|
+
children,
|
|
689
|
+
isChildrenLoading: false
|
|
690
|
+
};
|
|
691
|
+
this.navigation = [...this.navigation];
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
protected addToMetadata(
|
|
695
|
+
parentReferencePath: string,
|
|
696
|
+
referenceId: string,
|
|
697
|
+
type: string,
|
|
698
|
+
topic: { id: string; domId: string },
|
|
699
|
+
navTitle: string
|
|
700
|
+
): string {
|
|
701
|
+
const config = URL_CONFIG[type as keyof typeof URL_CONFIG];
|
|
702
|
+
const urlIdentifer = config.urlIdentifer;
|
|
703
|
+
let prefix = null;
|
|
704
|
+
if ("prefix" in config) {
|
|
705
|
+
prefix = config.prefix;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// encodeURI to avoid special characters in the URL meta.
|
|
709
|
+
const identifier =
|
|
710
|
+
urlIdentifer in topic &&
|
|
711
|
+
this.encodeIdentifier(topic[urlIdentifer as keyof typeof topic]);
|
|
712
|
+
let meta;
|
|
713
|
+
// Assuming that there will be an identifier always
|
|
714
|
+
if (identifier) {
|
|
715
|
+
meta = prefix ? `${prefix}${identifier}` : `${identifier}`;
|
|
716
|
+
this.metadata[meta] = {
|
|
717
|
+
parentReferencePath,
|
|
718
|
+
meta,
|
|
719
|
+
referenceId,
|
|
720
|
+
amfId: topic.id,
|
|
721
|
+
elementId: topic.domId,
|
|
722
|
+
identifier,
|
|
723
|
+
type,
|
|
724
|
+
navTitle
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
return meta!;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* Returns metadata given route meta
|
|
732
|
+
*/
|
|
733
|
+
protected getMetadataByUrlQuery(routeMeta: RouteMeta): AmfMetadataTopic {
|
|
734
|
+
return Object.values(this.metadata).find(
|
|
735
|
+
(metadata: AmfMetadataTopic) => {
|
|
736
|
+
return routeMeta.meta === metadata.meta;
|
|
737
|
+
}
|
|
738
|
+
)!;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* Returns metadata given reference ID and topic amf ID
|
|
743
|
+
*/
|
|
744
|
+
protected getMetadataByAmfId(
|
|
745
|
+
referenceId: string,
|
|
746
|
+
amfId: string
|
|
747
|
+
): AmfMetadataTopic {
|
|
748
|
+
// Lets make a map based on the hash values so we don't need to loop like this.
|
|
749
|
+
return Object.values(this.metadata).find(
|
|
750
|
+
(metadata: AmfMetadataTopic) =>
|
|
751
|
+
referenceId === metadata.referenceId && amfId === metadata.amfId
|
|
752
|
+
)!;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* Returns metadata given reference ID and topic identifier
|
|
757
|
+
*/
|
|
758
|
+
protected getMetadataByIdentifier(
|
|
759
|
+
referenceId: string,
|
|
760
|
+
identifier: string
|
|
761
|
+
): AmfMetadataTopic {
|
|
762
|
+
// Lets make a map based on the hash values so we don't need to loop like this.
|
|
763
|
+
return Object.values(this.metadata).find(
|
|
764
|
+
(metadata: AmfMetadataTopic) =>
|
|
765
|
+
referenceId === metadata.referenceId &&
|
|
766
|
+
identifier === metadata.identifier
|
|
767
|
+
)!;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
/**
|
|
771
|
+
* Returns metadata given reference ID and topic type
|
|
772
|
+
*/
|
|
773
|
+
protected getMetadataByType(
|
|
774
|
+
referenceId: string,
|
|
775
|
+
type: string
|
|
776
|
+
): AmfMetadataTopic {
|
|
777
|
+
// Lets make a map based on the hash values so we don't need to loop like this.
|
|
778
|
+
return Object.values(this.metadata).find(
|
|
779
|
+
(metadata: AmfMetadataTopic) =>
|
|
780
|
+
referenceId === metadata.referenceId && type === metadata.type
|
|
781
|
+
)!;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
/**
|
|
785
|
+
* Parses URL query params without decoding of params
|
|
786
|
+
*/
|
|
787
|
+
private parseParams(params: string): qs.ParsedQuery<string> {
|
|
788
|
+
if (!params) {
|
|
789
|
+
return {};
|
|
790
|
+
}
|
|
791
|
+
return qs.parse(params, {
|
|
792
|
+
decode: false
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/**
|
|
797
|
+
* Normalizes topic identifier by replacing spaces with '+'
|
|
798
|
+
* and running encodeURI() on it
|
|
799
|
+
* @param identifier raw identifier for a topic as parsed from the spec file
|
|
800
|
+
* @returns normalized and encoded identifier
|
|
801
|
+
*/
|
|
802
|
+
protected encodeIdentifier(identifier: string): string {
|
|
803
|
+
let result = identifier.trim();
|
|
804
|
+
result = result.replace(new RegExp(/\s+/, "g"), "+");
|
|
805
|
+
return encodeURI(result);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
/**
|
|
809
|
+
* Constructs a Reference Topic ID
|
|
810
|
+
*/
|
|
811
|
+
protected getFormattedIdentifier(referenceId: string, id: string): string {
|
|
812
|
+
return `${referenceId}:${id}`;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
protected updateUrlWithSelected(
|
|
816
|
+
parentReferencePath: string,
|
|
817
|
+
meta?: string
|
|
818
|
+
): void {
|
|
819
|
+
if (meta) {
|
|
820
|
+
// update the encoded url meta param
|
|
821
|
+
const encodedMeta = this.getUrlEncoded(meta);
|
|
822
|
+
|
|
823
|
+
window.history.pushState(
|
|
824
|
+
{},
|
|
825
|
+
"",
|
|
826
|
+
`${parentReferencePath}?meta=${encodedMeta}`
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* Does a replace on the URL meta, so it does not create a history entry.
|
|
833
|
+
*/
|
|
834
|
+
protected replaceUrlWithSelected(
|
|
835
|
+
parentReferencePath: string,
|
|
836
|
+
meta?: string
|
|
837
|
+
): void {
|
|
838
|
+
if (meta) {
|
|
839
|
+
// update the encoded url meta param
|
|
840
|
+
const encodedMeta = this.getUrlEncoded(meta);
|
|
841
|
+
|
|
842
|
+
window.history.replaceState(
|
|
843
|
+
window.history.state,
|
|
844
|
+
"",
|
|
845
|
+
`${parentReferencePath}?meta=${encodedMeta}`
|
|
846
|
+
);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
/**
|
|
851
|
+
* This method gets called when the user navigates back and forth using browser arrows
|
|
852
|
+
* Updates content depending on the type of reference - spec based or markdown
|
|
853
|
+
*/
|
|
854
|
+
protected updateSelectedItemFromUrlQuery(): void {
|
|
855
|
+
const specBasedReference = this.isSpecBasedReference(
|
|
856
|
+
this._currentReferenceId
|
|
857
|
+
);
|
|
858
|
+
if (specBasedReference) {
|
|
859
|
+
const currentMeta: RouteMeta | undefined =
|
|
860
|
+
this.getReferenceMetaInfo(window.location.href);
|
|
861
|
+
const metadata =
|
|
862
|
+
currentMeta && this.getMetadataByUrlQuery(currentMeta);
|
|
863
|
+
if (metadata) {
|
|
864
|
+
const {
|
|
865
|
+
parentReferencePath,
|
|
866
|
+
referenceId,
|
|
867
|
+
amfId,
|
|
868
|
+
type,
|
|
869
|
+
elementId
|
|
870
|
+
}: AmfMetadataTopic = metadata;
|
|
871
|
+
this.loadSpecReferenceContent(
|
|
872
|
+
parentReferencePath,
|
|
873
|
+
referenceId,
|
|
874
|
+
amfId,
|
|
875
|
+
type,
|
|
876
|
+
elementId,
|
|
877
|
+
currentMeta.meta
|
|
878
|
+
);
|
|
879
|
+
}
|
|
880
|
+
} else {
|
|
881
|
+
this.loadMarkdownBasedReference();
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
restoreScroll(); // don't try this at home kids
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
/**
|
|
888
|
+
* The API Navigation event will always intend to navigate within the current reference
|
|
889
|
+
* @param event
|
|
890
|
+
*/
|
|
891
|
+
protected onApiNavigationChanged(): void {
|
|
892
|
+
const specBasedReference = this.isSpecBasedReference(
|
|
893
|
+
this._currentReferenceId
|
|
894
|
+
);
|
|
895
|
+
if (specBasedReference) {
|
|
896
|
+
const { meta } = this.selectedTopic!;
|
|
897
|
+
const metadata = this.metadata[meta];
|
|
898
|
+
if (metadata) {
|
|
899
|
+
const {
|
|
900
|
+
parentReferencePath,
|
|
901
|
+
referenceId,
|
|
902
|
+
amfId,
|
|
903
|
+
type,
|
|
904
|
+
elementId
|
|
905
|
+
}: AmfMetadataTopic = metadata;
|
|
906
|
+
this.loadSpecReferenceContent(
|
|
907
|
+
parentReferencePath,
|
|
908
|
+
referenceId,
|
|
909
|
+
amfId,
|
|
910
|
+
type,
|
|
911
|
+
elementId,
|
|
912
|
+
metadata.meta
|
|
913
|
+
);
|
|
914
|
+
}
|
|
915
|
+
} else {
|
|
916
|
+
this.loadMarkdownBasedReference();
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
/**
|
|
921
|
+
* Updates the currently selected amf and topic
|
|
922
|
+
*/
|
|
923
|
+
protected loadSpecReferenceContent(
|
|
924
|
+
parentReferencePath: string,
|
|
925
|
+
referenceId: string,
|
|
926
|
+
amfId: string,
|
|
927
|
+
type: string,
|
|
928
|
+
elementId: string,
|
|
929
|
+
meta: string
|
|
930
|
+
): void {
|
|
931
|
+
this.selectedTopic = {
|
|
932
|
+
referenceId,
|
|
933
|
+
parentReferencePath,
|
|
934
|
+
amfId,
|
|
935
|
+
elementId,
|
|
936
|
+
type,
|
|
937
|
+
meta
|
|
938
|
+
};
|
|
939
|
+
this.selectedSidebarValue = this.getReferencePathWithMeta(
|
|
940
|
+
parentReferencePath,
|
|
941
|
+
meta
|
|
942
|
+
);
|
|
943
|
+
|
|
944
|
+
this.handleSelectedItem();
|
|
945
|
+
|
|
946
|
+
this.updateDocPhase();
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
/**
|
|
950
|
+
* Updates doc phase of selected reference
|
|
951
|
+
*/
|
|
952
|
+
updateDocPhase(): void {
|
|
953
|
+
/* If parent level doc phase is enabled, Individual reference level doc phase should not be considered */
|
|
954
|
+
|
|
955
|
+
if (!this.isParentLevelDocPhaseEnabled) {
|
|
956
|
+
const selectedReference = this._amfConfigList.find(
|
|
957
|
+
(referenceItem: AmfConfig) => {
|
|
958
|
+
return referenceItem.id === this._currentReferenceId;
|
|
959
|
+
}
|
|
960
|
+
);
|
|
961
|
+
if (selectedReference) {
|
|
962
|
+
this.selectedReferenceDocPhase = JSON.stringify(
|
|
963
|
+
selectedReference.docPhase
|
|
964
|
+
);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
/**
|
|
970
|
+
* Returns the decoded meta query param from given Url as it is being used internally.
|
|
971
|
+
*/
|
|
972
|
+
getMetaFromUrl(referenceUrl: string): string {
|
|
973
|
+
const indexOfQueryParam = referenceUrl.indexOf("?");
|
|
974
|
+
const urlPath = referenceUrl.substring(
|
|
975
|
+
indexOfQueryParam >= 0 ? indexOfQueryParam : referenceUrl.length
|
|
976
|
+
);
|
|
977
|
+
const meta = this.parseParams(urlPath).meta as string;
|
|
978
|
+
// Always get the meta query param encoded and decode it and store it for internal use
|
|
979
|
+
// This has 2 advantages,
|
|
980
|
+
// 1. Supports backward compatible meta query param, so there is no need for redirects.
|
|
981
|
+
// 2. Supports Prerender and Coveo for their crawling.
|
|
982
|
+
const encodedMeta = meta && this.getUrlEncoded(meta);
|
|
983
|
+
const decodedMeta = encodedMeta && decodeURIComponent(encodedMeta);
|
|
984
|
+
return decodedMeta || "";
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
/**
|
|
988
|
+
*
|
|
989
|
+
* @returns meta for given markdown based referenceUrl
|
|
990
|
+
* Consider last topic url in ../references/reference-name/example.html
|
|
991
|
+
*/
|
|
992
|
+
getMarkdownReferenceMeta(referenceUrl: string): string {
|
|
993
|
+
let meta = "";
|
|
994
|
+
if (referenceUrl) {
|
|
995
|
+
const slashSeparatorItems = referenceUrl.split("/");
|
|
996
|
+
const lastItem =
|
|
997
|
+
slashSeparatorItems[slashSeparatorItems.length - 1];
|
|
998
|
+
if (lastItem.endsWith(".html")) {
|
|
999
|
+
meta = lastItem;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
return meta;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
/**
|
|
1006
|
+
* Gets the encoded url.
|
|
1007
|
+
* This method will return the encoded url for 2 cases,
|
|
1008
|
+
* 1. If the url is encoded already
|
|
1009
|
+
* 2. If the url is decoded
|
|
1010
|
+
*/
|
|
1011
|
+
getUrlEncoded(url: string): string {
|
|
1012
|
+
// if url matches, then return the encoded url.
|
|
1013
|
+
if (decodeURIComponent(url) === url) {
|
|
1014
|
+
return encodeURIComponent(url);
|
|
1015
|
+
}
|
|
1016
|
+
// return the encoded url.
|
|
1017
|
+
return this.getUrlEncoded(decodeURIComponent(url));
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
/**
|
|
1021
|
+
*
|
|
1022
|
+
* @returns RouteMeta object for given referenceUrl
|
|
1023
|
+
* referenceId - gets referenceId from url
|
|
1024
|
+
* For spec based references gets meta parm from url and then topicId & type from meta
|
|
1025
|
+
* For markdown based references gets topicId as last html path in the name, meta & type will be empty
|
|
1026
|
+
*/
|
|
1027
|
+
getReferenceMetaInfo(referenceUrl: string | null): RouteMeta | undefined {
|
|
1028
|
+
let metaReferenceInfo;
|
|
1029
|
+
if (referenceUrl) {
|
|
1030
|
+
const referenceId = this.getReferenceIdFromUrl(referenceUrl);
|
|
1031
|
+
let meta = "";
|
|
1032
|
+
let topicId = "";
|
|
1033
|
+
let type = "";
|
|
1034
|
+
if (this.isSpecBasedReference(referenceId)) {
|
|
1035
|
+
meta = this.getMetaFromUrl(referenceUrl);
|
|
1036
|
+
if (meta) {
|
|
1037
|
+
if (meta.includes(":")) {
|
|
1038
|
+
const metaInfo = meta.split(":");
|
|
1039
|
+
type = metaInfo[0];
|
|
1040
|
+
topicId = metaInfo[1] || type;
|
|
1041
|
+
} else {
|
|
1042
|
+
topicId = meta;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
} else {
|
|
1046
|
+
topicId = this.getMarkdownReferenceMeta(referenceUrl);
|
|
1047
|
+
}
|
|
1048
|
+
metaReferenceInfo = {
|
|
1049
|
+
referenceId,
|
|
1050
|
+
meta,
|
|
1051
|
+
topicId,
|
|
1052
|
+
type
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
return metaReferenceInfo;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
/**
|
|
1059
|
+
* Finds and returns referenceUrl and topicTitle if given topic url matches
|
|
1060
|
+
*/
|
|
1061
|
+
getReferenceDetailsInGivenTopics(
|
|
1062
|
+
topics: ParsedMarkdownTopic[],
|
|
1063
|
+
topicMeta: string
|
|
1064
|
+
): { referenceUrl: string; topicTitle: string } {
|
|
1065
|
+
let referenceUrl = "";
|
|
1066
|
+
let topicTitle = "";
|
|
1067
|
+
for (let i = 0; i < topics.length; i++) {
|
|
1068
|
+
const topic = topics[i];
|
|
1069
|
+
const meta = this.getMarkdownReferenceMeta(topic.link!.href);
|
|
1070
|
+
const childTopics = topic.children;
|
|
1071
|
+
if (meta === topicMeta) {
|
|
1072
|
+
referenceUrl = topic.link!.href;
|
|
1073
|
+
topicTitle = topic.label;
|
|
1074
|
+
} else if (childTopics && childTopics.length) {
|
|
1075
|
+
const referenceDetails = this.getReferenceDetailsInGivenTopics(
|
|
1076
|
+
childTopics,
|
|
1077
|
+
topicMeta
|
|
1078
|
+
);
|
|
1079
|
+
referenceUrl = referenceDetails.referenceUrl;
|
|
1080
|
+
topicTitle = referenceDetails.topicTitle;
|
|
1081
|
+
}
|
|
1082
|
+
if (referenceUrl && topicTitle) {
|
|
1083
|
+
break;
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
return {
|
|
1087
|
+
referenceUrl,
|
|
1088
|
+
topicTitle
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
/**
|
|
1093
|
+
* Gives referenceUrl and topicTitle for given markdown topic url
|
|
1094
|
+
*/
|
|
1095
|
+
getRefDetailsForGivenTopicMeta(
|
|
1096
|
+
referenceId: string,
|
|
1097
|
+
topicMeta: string
|
|
1098
|
+
): { referenceUrl: string; topicTitle: string } | undefined {
|
|
1099
|
+
const amfConfig = this.getAmfConfigWithId(referenceId);
|
|
1100
|
+
let referenceDetails;
|
|
1101
|
+
if (amfConfig) {
|
|
1102
|
+
const topics = amfConfig.topic?.children || [];
|
|
1103
|
+
referenceDetails = this.getReferenceDetailsInGivenTopics(
|
|
1104
|
+
topics,
|
|
1105
|
+
topicMeta
|
|
1106
|
+
);
|
|
1107
|
+
}
|
|
1108
|
+
return referenceDetails;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
/**
|
|
1112
|
+
* Updates the DOM on the first load
|
|
1113
|
+
*/
|
|
1114
|
+
updateView(): void {
|
|
1115
|
+
const previousRefUrlInSession = window.sessionStorage.getItem(
|
|
1116
|
+
this.docsReferenceUrlSessionKey
|
|
1117
|
+
);
|
|
1118
|
+
window.sessionStorage.removeItem(this.docsReferenceUrlSessionKey);
|
|
1119
|
+
let previousRefInfo = this.getReferenceMetaInfo(
|
|
1120
|
+
previousRefUrlInSession
|
|
1121
|
+
);
|
|
1122
|
+
|
|
1123
|
+
// For spec based reference, We should consider urlData to show same topic when user reloads after navigating to specific topic
|
|
1124
|
+
if (!previousRefInfo) {
|
|
1125
|
+
const currentUrl = window.location.href;
|
|
1126
|
+
const urlReferenceId = this.getReferenceIdFromUrl(currentUrl);
|
|
1127
|
+
if (urlReferenceId && this.isSpecBasedReference(urlReferenceId)) {
|
|
1128
|
+
if (
|
|
1129
|
+
!this.isProjectRootPath() &&
|
|
1130
|
+
!this.isParentReferencePath(currentUrl)
|
|
1131
|
+
) {
|
|
1132
|
+
previousRefInfo = this.getReferenceMetaInfo(currentUrl);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
let referenceId: string;
|
|
1138
|
+
let topicId = "";
|
|
1139
|
+
|
|
1140
|
+
if (
|
|
1141
|
+
previousRefInfo &&
|
|
1142
|
+
this._amfConfigMap.has(previousRefInfo.referenceId)
|
|
1143
|
+
) {
|
|
1144
|
+
referenceId = previousRefInfo.referenceId;
|
|
1145
|
+
topicId = previousRefInfo.topicId;
|
|
1146
|
+
} else {
|
|
1147
|
+
referenceId = this._currentReferenceId;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
const specBasedReference = this.isSpecBasedReference(referenceId);
|
|
1151
|
+
if (specBasedReference) {
|
|
1152
|
+
// Wait till the AMF is loaded.
|
|
1153
|
+
this.amfFetchPromiseMap[referenceId].then(() => {
|
|
1154
|
+
let selectedItemMetaData = this.getMetadataByIdentifier(
|
|
1155
|
+
referenceId,
|
|
1156
|
+
topicId
|
|
1157
|
+
);
|
|
1158
|
+
if (!selectedItemMetaData) {
|
|
1159
|
+
// Doesn't exist, let's use the summary.
|
|
1160
|
+
selectedItemMetaData = this.getMetadataByType(
|
|
1161
|
+
referenceId,
|
|
1162
|
+
"summary"
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
if (selectedItemMetaData) {
|
|
1167
|
+
this.loadSpecReferenceContent(
|
|
1168
|
+
selectedItemMetaData.parentReferencePath,
|
|
1169
|
+
selectedItemMetaData.referenceId,
|
|
1170
|
+
selectedItemMetaData.amfId,
|
|
1171
|
+
selectedItemMetaData.type,
|
|
1172
|
+
"",
|
|
1173
|
+
selectedItemMetaData.meta
|
|
1174
|
+
);
|
|
1175
|
+
|
|
1176
|
+
this.updateUrlWithSelected(
|
|
1177
|
+
selectedItemMetaData.parentReferencePath,
|
|
1178
|
+
selectedItemMetaData.meta
|
|
1179
|
+
);
|
|
1180
|
+
this.updateTags(selectedItemMetaData.navTitle);
|
|
1181
|
+
}
|
|
1182
|
+
});
|
|
1183
|
+
} else {
|
|
1184
|
+
let invalidTopicReferenceUrl: string | null = "";
|
|
1185
|
+
if (topicId) {
|
|
1186
|
+
const referenceDetails = this.getRefDetailsForGivenTopicMeta(
|
|
1187
|
+
referenceId,
|
|
1188
|
+
topicId
|
|
1189
|
+
);
|
|
1190
|
+
const selectedItemUrl = referenceDetails?.referenceUrl;
|
|
1191
|
+
if (!selectedItemUrl) {
|
|
1192
|
+
invalidTopicReferenceUrl = previousRefUrlInSession;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
this.loadMarkdownBasedReference(invalidTopicReferenceUrl);
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
/**
|
|
1200
|
+
* Navigates to reference of the given URL
|
|
1201
|
+
* @param url
|
|
1202
|
+
*/
|
|
1203
|
+
private loadNewReferenceItem(url: string): void {
|
|
1204
|
+
const referenceId = this.getReferenceIdFromUrl(url);
|
|
1205
|
+
const referenceItem = this.getAmfConfigWithId(referenceId);
|
|
1206
|
+
if (referenceItem) {
|
|
1207
|
+
window.location.href = referenceItem.href;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
/**
|
|
1212
|
+
* @param referenceUrl to which user wants to navigate
|
|
1213
|
+
* Redirect to first sub item if it's root level item, otherwise content will be loaded
|
|
1214
|
+
* Push the history as a first child item
|
|
1215
|
+
* set selected sidebar value as a pathname
|
|
1216
|
+
*/
|
|
1217
|
+
|
|
1218
|
+
private loadMarkdownBasedReference(referenceUrl?: string | null): void {
|
|
1219
|
+
// MILES TODO: figure out if we ever need to log a coveo page view in here
|
|
1220
|
+
// this would be the case if at some point we 'load' a new 'markdown based reference'
|
|
1221
|
+
// without actually triggering a page load
|
|
1222
|
+
let referenceId = "";
|
|
1223
|
+
const currentUrl = window.location.href;
|
|
1224
|
+
if (this.isProjectRootPath()) {
|
|
1225
|
+
/**
|
|
1226
|
+
* CASE1: This case is to consider when the user navigates to references by clicking a project card
|
|
1227
|
+
* Ex: /docs/example-project/references should navigate to the first topic in the first reference
|
|
1228
|
+
*/
|
|
1229
|
+
referenceId = this._currentReferenceId;
|
|
1230
|
+
} else if (this.isParentReferencePath(referenceUrl)) {
|
|
1231
|
+
/**
|
|
1232
|
+
* CASE2: This case is to navigate to respective reference when the user clicked on root item
|
|
1233
|
+
* Ex: .../references/markdown-ref should navigate to first topic.
|
|
1234
|
+
*/
|
|
1235
|
+
referenceId = this.getReferenceIdFromUrl(referenceUrl!);
|
|
1236
|
+
} else if (this.isParentReferencePath(currentUrl)) {
|
|
1237
|
+
/**
|
|
1238
|
+
* CASE3: This case is to navigate to respective reference when the user entered url with reference id
|
|
1239
|
+
* Ex: .../references/markdown-ref should navigate to first topic.
|
|
1240
|
+
*/
|
|
1241
|
+
referenceId = this.getReferenceIdFromUrl(currentUrl);
|
|
1242
|
+
} else if (referenceUrl) {
|
|
1243
|
+
/**
|
|
1244
|
+
* CASE4: This case is to navigate to first item when we don't have topic in the selected version
|
|
1245
|
+
* Ex: .../references/markdown-ref/not-existed-topic-url should navigate to first topic.
|
|
1246
|
+
*/
|
|
1247
|
+
const referenceMeta = this.getMarkdownReferenceMeta(referenceUrl);
|
|
1248
|
+
const selectedItemRefId = this.getReferenceIdFromUrl(referenceUrl);
|
|
1249
|
+
const referenceDetails = this.getRefDetailsForGivenTopicMeta(
|
|
1250
|
+
selectedItemRefId,
|
|
1251
|
+
referenceMeta
|
|
1252
|
+
);
|
|
1253
|
+
const selectedItemUrl = referenceDetails?.referenceUrl;
|
|
1254
|
+
if (!selectedItemUrl) {
|
|
1255
|
+
referenceId = this.getReferenceIdFromUrl(referenceUrl);
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
let isRedirecting = false;
|
|
1260
|
+
if (referenceId) {
|
|
1261
|
+
const amfConfig = this.getAmfConfigWithId(referenceId);
|
|
1262
|
+
let redirectReferenceUrl = "";
|
|
1263
|
+
if (amfConfig) {
|
|
1264
|
+
const childrenItems = amfConfig.topic!.children;
|
|
1265
|
+
if (childrenItems.length > 0) {
|
|
1266
|
+
redirectReferenceUrl = childrenItems[0].link!.href;
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
if (redirectReferenceUrl) {
|
|
1270
|
+
if (this.isParentReferencePath(referenceUrl)) {
|
|
1271
|
+
// This is for CASE2 mentioned above, Where we need to navigate user to respective href
|
|
1272
|
+
isRedirecting = true;
|
|
1273
|
+
window.location.href = redirectReferenceUrl;
|
|
1274
|
+
} else {
|
|
1275
|
+
// This is for CASE 1,3 and 4 mentioned above, Where we need to update the browser history
|
|
1276
|
+
window.history.replaceState(
|
|
1277
|
+
window.history.state,
|
|
1278
|
+
"",
|
|
1279
|
+
redirectReferenceUrl
|
|
1280
|
+
);
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
if (!isRedirecting) {
|
|
1285
|
+
const currentReferenceUrl = window.location.href;
|
|
1286
|
+
const referenceMeta =
|
|
1287
|
+
this.getMarkdownReferenceMeta(currentReferenceUrl);
|
|
1288
|
+
const selectedItemRefId =
|
|
1289
|
+
this.getReferenceIdFromUrl(currentReferenceUrl);
|
|
1290
|
+
const referenceDetails = this.getRefDetailsForGivenTopicMeta(
|
|
1291
|
+
selectedItemRefId,
|
|
1292
|
+
referenceMeta
|
|
1293
|
+
);
|
|
1294
|
+
if (referenceDetails) {
|
|
1295
|
+
this.updateTags(referenceDetails.topicTitle);
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
this.versions = this.getVersions();
|
|
1299
|
+
if (this.oldVersionInfo) {
|
|
1300
|
+
this.showVersionBanner = true;
|
|
1301
|
+
} else {
|
|
1302
|
+
this.latestVersion = true;
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
this.isVersionFetched = true;
|
|
1306
|
+
this.updateDocPhase();
|
|
1307
|
+
this.selectedSidebarValue = window.location.pathname;
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
/**
|
|
1312
|
+
* Currently, used to handle the version change and store the current reference Url.
|
|
1313
|
+
*/
|
|
1314
|
+
handleVersionChange(): void {
|
|
1315
|
+
const currentUrl = window.location.href;
|
|
1316
|
+
window.sessionStorage.setItem(
|
|
1317
|
+
this.docsReferenceUrlSessionKey,
|
|
1318
|
+
currentUrl
|
|
1319
|
+
);
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
handleDismissVersionBanner() {
|
|
1323
|
+
this.showVersionBanner = false;
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
private updateTags(navTitle = ""): void {
|
|
1327
|
+
if (!navTitle) {
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
// this is required to update the nav title meta tag.
|
|
1332
|
+
// eslint-disable-next-line @lwc/lwc/no-document-query
|
|
1333
|
+
const metaNavTitle = document.querySelector('meta[name="nav-title"]');
|
|
1334
|
+
// eslint-disable-next-line @lwc/lwc/no-document-query
|
|
1335
|
+
const titleTag = document.querySelector("title");
|
|
1336
|
+
const TITLE_SEPARATOR = " | ";
|
|
1337
|
+
|
|
1338
|
+
if (metaNavTitle) {
|
|
1339
|
+
metaNavTitle.setAttribute("content", navTitle);
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
/**
|
|
1343
|
+
* Right now, the title tag only changes when you pick a Ref spec,
|
|
1344
|
+
* not every time you choose a subsection of the Ref spec.
|
|
1345
|
+
* This update aims to refresh the title tag with each selection.
|
|
1346
|
+
* If a Ref spec is chosen, we add the value of the <selected topic> to the title.
|
|
1347
|
+
* If a subsection is selected, we update the first part of the current
|
|
1348
|
+
* title with the new <selected topic>.
|
|
1349
|
+
* Example: Following is a sample project structure.
|
|
1350
|
+
* - Project Name
|
|
1351
|
+
* - Ref Spec1
|
|
1352
|
+
* - Summary
|
|
1353
|
+
* - Endpoints
|
|
1354
|
+
* - E1
|
|
1355
|
+
* - E2
|
|
1356
|
+
* - Ref Spec2
|
|
1357
|
+
* - Summary
|
|
1358
|
+
* - Endpoints
|
|
1359
|
+
* - E1 (Selected)
|
|
1360
|
+
* - E2
|
|
1361
|
+
* Previous Title: Ref Spec2 | Project Name | Salesforce Developer
|
|
1362
|
+
* New Title: E1 | Ref Spec2 | Project Name | Salesforce Developer
|
|
1363
|
+
*
|
|
1364
|
+
*/
|
|
1365
|
+
if (titleTag) {
|
|
1366
|
+
let titleTagValue = titleTag.textContent;
|
|
1367
|
+
const titleTagSectionValues: string[] =
|
|
1368
|
+
titleTagValue?.split(TITLE_SEPARATOR);
|
|
1369
|
+
if (titleTagSectionValues) {
|
|
1370
|
+
if (titleTagSectionValues.length <= 3) {
|
|
1371
|
+
titleTagValue = navTitle + TITLE_SEPARATOR + titleTagValue;
|
|
1372
|
+
} else {
|
|
1373
|
+
titleTagSectionValues[0] = navTitle;
|
|
1374
|
+
titleTagValue = titleTagSectionValues.join(TITLE_SEPARATOR);
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
titleTag.textContent = titleTagValue;
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
onNavSelect(event: CustomEvent): void {
|
|
1382
|
+
const name = event.detail.name;
|
|
1383
|
+
if (name) {
|
|
1384
|
+
const urlReferenceId = this.getReferenceIdFromUrl(name);
|
|
1385
|
+
const specBasedReference =
|
|
1386
|
+
this.isSpecBasedReference(urlReferenceId);
|
|
1387
|
+
if (specBasedReference) {
|
|
1388
|
+
const metaVal = this.getMetaFromUrl(name);
|
|
1389
|
+
const currentSelectedMeta = this.selectedTopic
|
|
1390
|
+
? this.selectedTopic.meta
|
|
1391
|
+
: "";
|
|
1392
|
+
|
|
1393
|
+
if (metaVal && metaVal === currentSelectedMeta) {
|
|
1394
|
+
// selecting the same nav item, skip update
|
|
1395
|
+
return;
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
const metadata = this.metadata[metaVal];
|
|
1399
|
+
if (metadata) {
|
|
1400
|
+
const {
|
|
1401
|
+
parentReferencePath,
|
|
1402
|
+
referenceId,
|
|
1403
|
+
amfId,
|
|
1404
|
+
type,
|
|
1405
|
+
elementId
|
|
1406
|
+
} = metadata;
|
|
1407
|
+
this.loadSpecReferenceContent(
|
|
1408
|
+
parentReferencePath,
|
|
1409
|
+
referenceId,
|
|
1410
|
+
amfId,
|
|
1411
|
+
type,
|
|
1412
|
+
elementId,
|
|
1413
|
+
metaVal
|
|
1414
|
+
);
|
|
1415
|
+
|
|
1416
|
+
this.updateUrlWithSelected(parentReferencePath, metaVal);
|
|
1417
|
+
this.updateTags(metadata.navTitle);
|
|
1418
|
+
} else {
|
|
1419
|
+
if (this.isParentReferencePath(name)) {
|
|
1420
|
+
this.loadNewReferenceItem(name);
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
} else {
|
|
1424
|
+
this.loadMarkdownBasedReference(name);
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
onExpandCollapse(event: CustomEvent): void {
|
|
1430
|
+
const { name, isSelectAction, isExpanded } = event.detail;
|
|
1431
|
+
if (!isSelectAction && isExpanded) {
|
|
1432
|
+
const referenceId = this.getReferenceIdFromUrl(name);
|
|
1433
|
+
const currentUrl = window.location.href;
|
|
1434
|
+
const currentReferenceId = this.getReferenceIdFromUrl(currentUrl);
|
|
1435
|
+
//No need to do anything if user is expanding currently selected reference
|
|
1436
|
+
if (referenceId !== currentReferenceId) {
|
|
1437
|
+
const isSpecBasedReference =
|
|
1438
|
+
this.isSpecBasedReference(referenceId);
|
|
1439
|
+
if (isSpecBasedReference) {
|
|
1440
|
+
// Perform functionality same as item selection
|
|
1441
|
+
this.onNavSelect(event);
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
handleSelectedItem(): void {
|
|
1448
|
+
// update topic view
|
|
1449
|
+
const { referenceId, amfId, type } = this.selectedTopic!;
|
|
1450
|
+
|
|
1451
|
+
// Adding stringify inside try/catch
|
|
1452
|
+
let amfModelString = "";
|
|
1453
|
+
try {
|
|
1454
|
+
amfModelString = JSON.stringify(this.amfMap[referenceId].model);
|
|
1455
|
+
} catch (error) {
|
|
1456
|
+
console.error(`Error stringifying amf model: ${error}`);
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
// This updates the component in the content section.
|
|
1460
|
+
this.topicModel = {
|
|
1461
|
+
type,
|
|
1462
|
+
amf: amfModelString,
|
|
1463
|
+
parser: this.amfMap[referenceId].parser,
|
|
1464
|
+
id: amfId
|
|
1465
|
+
};
|
|
1466
|
+
}
|
|
1467
|
+
}
|