Fix issue with navigation when operationId contains backslash

This commit is contained in:
Oleksandr Strakhov 2021-03-07 19:25:59 +02:00
parent 4846259de3
commit 44cc1194e2
4 changed files with 22 additions and 6 deletions

9
package-lock.json generated
View File

@ -1869,6 +1869,12 @@
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ=="
}, },
"@types/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/cssesc/-/cssesc-3.0.0.tgz",
"integrity": "sha512-4mBnOrTpVKn+tYzlnMO7cwDkDa6wlQ2bBXW+79/6ahMd36GF216kxWYxgz+S4d5Ev1ByFbnQbPGxV4P5BSL8MA==",
"dev": true
},
"@types/dompurify": { "@types/dompurify": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-2.0.2.tgz", "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-2.0.2.tgz",
@ -5212,8 +5218,7 @@
"cssesc": { "cssesc": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="
"dev": true
}, },
"cssom": { "cssom": {
"version": "0.4.4", "version": "0.4.4",

View File

@ -60,6 +60,7 @@
"@cypress/webpack-preprocessor": "^5.4.2", "@cypress/webpack-preprocessor": "^5.4.2",
"@hot-loader/react-dom": "^16.12.0", "@hot-loader/react-dom": "^16.12.0",
"@types/chai": "^4.2.12", "@types/chai": "^4.2.12",
"@types/cssesc": "^3.0.0",
"@types/dompurify": "^2.0.2", "@types/dompurify": "^2.0.2",
"@types/enzyme": "^3.10.5", "@types/enzyme": "^3.10.5",
"@types/enzyme-to-json": "^1.5.3", "@types/enzyme-to-json": "^1.5.3",
@ -137,6 +138,7 @@
"@redocly/react-dropdown-aria": "^2.0.11", "@redocly/react-dropdown-aria": "^2.0.11",
"@types/node": "^13.11.1", "@types/node": "^13.11.1",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"cssesc": "^3.0.0",
"decko": "^1.2.0", "decko": "^1.2.0",
"dompurify": "^2.0.12", "dompurify": "^2.0.12",
"eventemitter3": "^4.0.4", "eventemitter3": "^4.0.4",

View File

@ -1,5 +1,5 @@
import { action, observable, makeObservable } from 'mobx'; import { action, observable, makeObservable } from 'mobx';
import { querySelector } from '../utils/dom'; import { escapeSelectorValue, querySelector } from '../utils/dom';
import { SpecStore } from './models'; import { SpecStore } from './models';
import { history as historyInst, HistoryService } from './HistoryService'; import { history as historyInst, HistoryService } from './HistoryService';
@ -162,7 +162,7 @@ export class MenuStore {
*/ */
getElementAt(idx: number): Element | null { getElementAt(idx: number): Element | null {
const item = this.flatItems[idx]; const item = this.flatItems[idx];
return (item && querySelector(`[${SECTION_ATTR}="${item.id}"]`)) || null; return (item && querySelector(`[${SECTION_ATTR}="${escapeSelectorValue(item.id)}"]`)) || null;
} }
/** /**
@ -174,7 +174,7 @@ export class MenuStore {
if (item && item.type === 'group') { if (item && item.type === 'group') {
item = item.items[0]; item = item.items[0];
} }
return (item && querySelector(`[${SECTION_ATTR}="${item.id}"]`)) || null; return (item && querySelector(`[${SECTION_ATTR}="${escapeSelectorValue(item.id)}"]`)) || null;
} }
/** /**
@ -222,7 +222,7 @@ export class MenuStore {
this.activeItemIdx = item.absoluteIdx!; this.activeItemIdx = item.absoluteIdx!;
if (updateLocation) { if (updateLocation) {
this.history.replace(item.id, rewriteHistory); this.history.replace(encodeURI(item.id), rewriteHistory);
} }
item.activate(); item.activate();

View File

@ -1,3 +1,5 @@
import * as cssesc from 'cssesc';
export const IS_BROWSER = typeof window !== 'undefined' && 'HTMLElement' in window; export const IS_BROWSER = typeof window !== 'undefined' && 'HTMLElement' in window;
export function querySelector(selector: string): Element | null { export function querySelector(selector: string): Element | null {
@ -7,6 +9,13 @@ export function querySelector(selector: string): Element | null {
return null; return null;
} }
export function escapeSelectorValue(
value: string,
options: Readonly<Partial<cssesc.Options>> = { quotes: 'double' },
): string {
return cssesc(value, options);
}
/** /**
* Drop everything inside <...> (i.e., tags/elements), and keep the text. * Drop everything inside <...> (i.e., tags/elements), and keep the text.
* Unlike browser innerText, this removes newlines; it also doesn't handle * Unlike browser innerText, this removes newlines; it also doesn't handle