diff --git a/package.json b/package.json index 77f14ab7..3d6350b3 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "base64-js": "^1.2.0", "brace": "0.7.0", "classnames": "^2.2.5", + "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 4a0ea3ac..82bf62a3 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 { @@ -71,7 +71,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 ( @@ -126,7 +126,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 99cb9525..fbfd3155 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" @@ -673,3 +674,6 @@ export function getAcceptControllingResponse(responses) { return suitable2xxResponse || suitableDefaultResponse } + +export const createDeepLinkPath = (str) => str ? str.replace(/\s/g, "_") : "" +export const escapeDeepLinkPath = (str) => cssEscape( createDeepLinkPath(str) )