diff --git a/package.json b/package.json index 709752ff..8d85d26f 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "dependencies": { "base64-js": "^1.2.0", "brace": "0.7.0", + "css.escape": "1.5.1", "deep-extend": "0.4.1", "expect": "1.20.2", "getbase": "^2.8.2", diff --git a/src/core/components/operations.jsx b/src/core/components/operations.jsx index 2aec664a..e0bf0645 100644 --- a/src/core/components/operations.jsx +++ b/src/core/components/operations.jsx @@ -1,7 +1,7 @@ import React from "react" import PropTypes from "prop-types" import { helpers } from "swagger-client" - +import { createDeepLinkPath } from "core/utils" const { opId } = helpers export default class Operations extends React.Component { @@ -69,7 +69,7 @@ export default class Operations extends React.Component { let tagExternalDocsDescription = tagObj.getIn(["tagDetails", "externalDocs", "description"]) let tagExternalDocsUrl = tagObj.getIn(["tagDetails", "externalDocs", "url"]) - let isShownKey = ["operations-tag", tag] + let isShownKey = ["operations-tag", createDeepLinkPath(tag)] let showTag = layoutSelectors.isShown(isShownKey, docExpansion === "full" || docExpansion === "list") return ( @@ -124,7 +124,7 @@ export default class Operations extends React.Component { const operationId = op.getIn(["operation", "operationId"]) || op.getIn(["operation", "__originalOperationId"]) || opId(op.get("operation"), path, method) || op.get("id") - const isShownKey = ["operations", tag, operationId] + const isShownKey = ["operations", createDeepLinkPath(tag), createDeepLinkPath(operationId)] const allowTryItOut = specSelectors.allowTryItOutFor(op.get("path"), op.get("method")) const response = specSelectors.responseFor(op.get("path"), op.get("method")) diff --git a/src/core/plugins/deep-linking/layout-wrap-actions.js b/src/core/plugins/deep-linking/layout-wrap-actions.js index 72d98948..f1e67d12 100644 --- a/src/core/plugins/deep-linking/layout-wrap-actions.js +++ b/src/core/plugins/deep-linking/layout-wrap-actions.js @@ -1,4 +1,5 @@ import { setHash } from "./helpers" +import { createDeepLinkPath } from "core/utils" export const show = (ori, { getConfigs }) => (...args) => { ori(...args) @@ -19,12 +20,12 @@ export const show = (ori, { getConfigs }) => (...args) => { if(type === "operations") { let [, tag, operationId] = thing - setHash(`/${tag}/${operationId}`) + setHash(`/${createDeepLinkPath(tag)}/${createDeepLinkPath(operationId)}`) } if(type === "operations-tag") { let [, tag] = thing - setHash(`/${tag}`) + setHash(`/${createDeepLinkPath(tag)}`) } } diff --git a/src/core/plugins/deep-linking/spec-wrap-actions.js b/src/core/plugins/deep-linking/spec-wrap-actions.js index bb13a6ff..ebeebe5c 100644 --- a/src/core/plugins/deep-linking/spec-wrap-actions.js +++ b/src/core/plugins/deep-linking/spec-wrap-actions.js @@ -1,4 +1,5 @@ import scrollTo from "scroll-to-element" +import { escapeDeepLinkPath } from "core/utils" const SCROLL_OFFSET = -5 let hasHashBeenParsed = false @@ -34,14 +35,14 @@ export const updateResolved = (ori, { layoutActions, getConfigs }) => (...args) layoutActions.show(["operations-tag", tag], true) layoutActions.show(["operations", tag, operationId], true) - scrollTo(`#operations-${tag}-${operationId}`, { + scrollTo(`#operations-${escapeDeepLinkPath(tag)}-${escapeDeepLinkPath(operationId)}`, { offset: SCROLL_OFFSET }) } else if(tag) { // Pre-expand and scroll to the tag layoutActions.show(["operations-tag", tag], true) - scrollTo(`#operations-tag-${tag}`, { + scrollTo(`#operations-tag-${escapeDeepLinkPath(tag)}`, { offset: SCROLL_OFFSET }) } diff --git a/src/core/utils.js b/src/core/utils.js index 743c4749..4a2845b7 100644 --- a/src/core/utils.js +++ b/src/core/utils.js @@ -8,6 +8,7 @@ import some from "lodash/some" import eq from "lodash/eq" import { memoizedSampleFromSchema, memoizedCreateXMLExample } from "core/plugins/samples/fn" import win from "./window" +import cssEscape from "css.escape" const DEFAULT_REPONSE_KEY = "default" @@ -650,3 +651,6 @@ export const shallowEqualKeys = (a,b, keys) => { return eq(a[key], b[key]) }) } + +export const createDeepLinkPath = (str) => str ? str.replace(/\s/g, "_") : "" +export const escapeDeepLinkPath = (str) => cssEscape( createDeepLinkPath(str) ) \ No newline at end of file