mirror of
https://github.com/Redocly/redoc.git
synced 2025-07-29 17:40:05 +03:00
feat(): Fix navigation with # in markdown
This commit is contained in:
parent
99aec2fffd
commit
63731f9dd7
|
@ -73,7 +73,7 @@ export class AppStore {
|
|||
MenuStore.updateOnHistory(this.history.currentId, this.scroll);
|
||||
|
||||
this.spec = new SpecStore(spec, specUrl, this.options);
|
||||
this.menu = new MenuStore(this.spec, this.scroll, this.history);
|
||||
this.menu = new MenuStore(this.spec, this.scroll, this.history, this.options);
|
||||
|
||||
if (!this.options.disableSearch) {
|
||||
this.search = new SearchStore();
|
||||
|
|
|
@ -18,10 +18,16 @@ export class HistoryService {
|
|||
get currentId(): string {
|
||||
if (IS_BROWSER) {
|
||||
if (this.shouldQueryParamNavigationBeUsed()) {
|
||||
// When the window.location.hash is not empty this means that we have clicked on
|
||||
// router that's for example stored in the description via markdown
|
||||
if (window.location.hash == '') {
|
||||
return this.getQueryParams(window.location.search);
|
||||
} else {
|
||||
return decodeURIComponent(window.location.hash.substring(1));
|
||||
}
|
||||
} else {
|
||||
return decodeURIComponent(window.location.hash.substring(1));
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
@ -30,7 +36,11 @@ export class HistoryService {
|
|||
if (!id) {
|
||||
return '';
|
||||
}
|
||||
return this.getHrefSplitCharacter() + id;
|
||||
if (this.shouldQueryParamNavigationBeUsed()) {
|
||||
return this.getFullUrl(id);
|
||||
} else {
|
||||
return '#' + id;
|
||||
}
|
||||
}
|
||||
|
||||
subscribe(cb): () => void {
|
||||
|
@ -61,23 +71,33 @@ export class HistoryService {
|
|||
return;
|
||||
}
|
||||
|
||||
if (id == null || id === this.currentId) {
|
||||
// If there currentId and the ID are equal but there is still
|
||||
// a hash left when using query param navigation
|
||||
// that means that the URL hasn't been overridden
|
||||
if (
|
||||
id == null ||
|
||||
(id === this.currentId && this.checkIfThereIsHashLeftWhenQueryParamNavigationShouldBeUsed())
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (rewriteHistory) {
|
||||
if (this.shouldQueryParamNavigationBeUsed()) {
|
||||
window.history.replaceState(null, '', this.getFullUrl(id));
|
||||
} else {
|
||||
window.history.replaceState(
|
||||
null,
|
||||
'',
|
||||
window.location.href.split(this.getHrefSplitCharacter())[0] + this.linkForId(id),
|
||||
window.location.href.split('#')[0] + this.linkForId(id),
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
window.history.pushState(
|
||||
null,
|
||||
'',
|
||||
window.location.href.split(this.getHrefSplitCharacter())[0] + this.linkForId(id),
|
||||
);
|
||||
if (this.shouldQueryParamNavigationBeUsed()) {
|
||||
window.history.pushState(null, '', this.getFullUrl(id));
|
||||
} else {
|
||||
window.history.pushState(null, '', window.location.href.split('#')[0] + this.linkForId(id));
|
||||
}
|
||||
this.emit();
|
||||
}
|
||||
|
||||
|
@ -93,7 +113,19 @@ export class HistoryService {
|
|||
return '';
|
||||
}
|
||||
|
||||
private getHrefSplitCharacter(): string {
|
||||
return this.shouldQueryParamNavigationBeUsed() ? '?redoc=' : '#';
|
||||
private getFullUrl(id: string): string {
|
||||
const url = this.getUrl();
|
||||
// Override the hash, so it's removed when using query param navigation
|
||||
url.hash = '';
|
||||
url.searchParams.set('redoc', id);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
private getUrl(): URL {
|
||||
return new URL(window.location.href);
|
||||
}
|
||||
|
||||
private checkIfThereIsHashLeftWhenQueryParamNavigationShouldBeUsed(): boolean {
|
||||
return !(this.shouldQueryParamNavigationBeUsed() && window.location.hash != '');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import { GROUP_DEPTH } from './MenuBuilder';
|
|||
import type { SpecStore } from './models';
|
||||
import type { ScrollService } from './ScrollService';
|
||||
import type { IMenuItem } from './types';
|
||||
import { RedocNormalizedOptions } from './RedocNormalizedOptions';
|
||||
|
||||
/** Generic interface for MenuItems */
|
||||
|
||||
|
@ -42,6 +43,7 @@ export class MenuStore {
|
|||
|
||||
items: IMenuItem[];
|
||||
flatItems: IMenuItem[];
|
||||
private options: RedocNormalizedOptions;
|
||||
|
||||
/**
|
||||
* cached flattened menu items to support absolute indexing
|
||||
|
@ -53,11 +55,19 @@ export class MenuStore {
|
|||
*
|
||||
* @param spec [SpecStore](#SpecStore) which contains page content structure
|
||||
* @param scroll scroll service instance used by this menu
|
||||
* @param history the history service
|
||||
* @param options the RedocNormalizedOptions that can be used to retrieve the config options
|
||||
*/
|
||||
constructor(spec: SpecStore, public scroll: ScrollService, public history: HistoryService) {
|
||||
constructor(
|
||||
spec: SpecStore,
|
||||
public scroll: ScrollService,
|
||||
public history: HistoryService,
|
||||
options: RedocNormalizedOptions,
|
||||
) {
|
||||
makeObservable(this);
|
||||
|
||||
this.items = spec.contentItems;
|
||||
this.options = options;
|
||||
|
||||
this.flatItems = flattenByProp(this.items || [], 'items');
|
||||
this.flatItems.forEach((item, idx) => (item.absoluteIdx = idx));
|
||||
|
@ -126,16 +136,28 @@ export class MenuStore {
|
|||
item = this.flatItems.find(i => i.id === id);
|
||||
|
||||
if (item) {
|
||||
this.activateAndScroll(item, false);
|
||||
this.activateAndScrollWithNavigationStrategy(item);
|
||||
} else {
|
||||
if (id.startsWith(SECURITY_SCHEMES_SECTION_PREFIX)) {
|
||||
item = this.flatItems.find(i => SECURITY_SCHEMES_SECTION_PREFIX.startsWith(i.id));
|
||||
this.activateAndScroll(item, false);
|
||||
this.activateAndScrollWithNavigationStrategy(item);
|
||||
}
|
||||
this.scroll.scrollIntoViewBySelector(`[${SECTION_ATTR}="${escapeHTMLAttrChars(id)}"]`);
|
||||
}
|
||||
};
|
||||
|
||||
private activateAndScrollWithNavigationStrategy(item: IMenuItem | undefined): void {
|
||||
if (this.shouldQueryParamNavigationBeUsed()) {
|
||||
this.activateAndScroll(item, true, true);
|
||||
} else {
|
||||
this.activateAndScroll(item, false);
|
||||
}
|
||||
}
|
||||
|
||||
private shouldQueryParamNavigationBeUsed(): boolean {
|
||||
return this.options?.userQueryParamToNavigate;
|
||||
}
|
||||
|
||||
/**
|
||||
* get section/operation DOM Node related to the item or null if it doesn't exist
|
||||
* @param idx item absolute index
|
||||
|
@ -237,6 +259,7 @@ export class MenuStore {
|
|||
) {
|
||||
// item here can be a copy from search results so find corresponding item from menu
|
||||
const menuItem = (item && this.getItemById(item.id)) || item;
|
||||
console.log('activateAndScroll', menuItem?.id, updateLocation, rewriteHistory);
|
||||
this.activate(menuItem, updateLocation, rewriteHistory);
|
||||
this.scrollToActive();
|
||||
if (!menuItem || !menuItem.items.length) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user