From 2795518340b6c424dd96e14e61a47588609474de Mon Sep 17 00:00:00 2001 From: Giancarlo Klemm Camilo Date: Thu, 12 Apr 2018 18:18:49 -0700 Subject: [PATCH] enhance: scrollable + downloadable `HighlightCode` (#4397) * Auto hidding content that is longer than 600 characters long. * Added basic downloading Slightly broken * Better downloading now downloads file on button click * Fix the angry linter * Fix dist * Removed collapsing, added scrolling. * Code clean up. * CSS fix. * prevent HighlightCode from scrolling entire document * center "Download" text in button * `this.downloadJSON` -> `this.downloadText` we're always saving as `.txt`, so JSON is a misnomer * hide Download button behind option `downloadable` prop * `file-saver` -> `js-file-download` --- package.json | 1 + src/core/components/highlight-code.jsx | 44 ++++++++++++++++++++++++-- src/core/components/response-body.jsx | 8 ++--- src/style/_layout.scss | 26 +++++++++++++++ 4 files changed, 72 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index a0ce4a62..5d77ce43 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "getbase": "^2.8.2", "ieee754": "^1.1.8", "immutable": "^3.x.x", + "js-file-download": "^0.4.1", "js-yaml": "^3.5.5", "lodash": "4.17.5", "matcher": "^0.1.2", diff --git a/src/core/components/highlight-code.jsx b/src/core/components/highlight-code.jsx index e0c3c461..22ed061e 100644 --- a/src/core/components/highlight-code.jsx +++ b/src/core/components/highlight-code.jsx @@ -1,11 +1,13 @@ import React, { Component } from "react" import PropTypes from "prop-types" import { highlight } from "core/utils" +import saveAs from "js-file-download" export default class HighlightCode extends Component { static propTypes = { value: PropTypes.string.isRequired, - className: PropTypes.string + className: PropTypes.string, + downloadable: PropTypes.bool } componentDidMount() { @@ -20,10 +22,46 @@ export default class HighlightCode extends Component { this.el = c } + downloadText = () => { + saveAs(this.props.value, "response.txt") + } + + preventYScrollingBeyondElement = (e) => { + const target = e.target + + var deltaY = e.nativeEvent.deltaY + var contentHeight = target.scrollHeight + var visibleHeight = target.offsetHeight + var scrollTop = target.scrollTop + + const scrollOffset = visibleHeight + scrollTop + + const isScrollingPastTop = scrollTop === 0 && deltaY < 0 + const isScrollingPastBottom = scrollOffset >= contentHeight && deltaY > 0 + + if (isScrollingPastTop || isScrollingPastBottom) { + e.preventDefault() + } + } + render () { - let { value, className } = this.props + let { value, className, downloadable } = this.props className = className || "" - return
{ value }
+ return ( +
+ { !downloadable ? null : +
+ Download +
+ } +
+          {value}
+        
+
+ ) } } diff --git a/src/core/components/response-body.jsx b/src/core/components/response-body.jsx index 640e0007..75b0f12f 100644 --- a/src/core/components/response-body.jsx +++ b/src/core/components/response-body.jsx @@ -66,7 +66,7 @@ export default class ResponseBody extends React.Component { body = "can't parse JSON. Raw result:\n\n" + content } - bodyEl = + bodyEl = // XML } else if (/xml/i.test(contentType)) { @@ -74,11 +74,11 @@ export default class ResponseBody extends React.Component { textNodesOnSameLine: true, indentor: " " }) - bodyEl = + bodyEl = // HTML or Plain Text } else if (lowerCase(contentType) === "text/html" || /text\/plain/.test(contentType)) { - bodyEl = + bodyEl = // Image } else if (/^image\//i.test(contentType)) { @@ -92,7 +92,7 @@ export default class ResponseBody extends React.Component { } else if (/^audio\//i.test(contentType)) { bodyEl =
} else if (typeof content === "string") { - bodyEl = + bodyEl = } else if ( content.size > 0 ) { // We don't know the contentType, but there was some content returned bodyEl =
Unknown response type
diff --git a/src/style/_layout.scss b/src/style/_layout.scss index 4a117e5a..23b8214e 100644 --- a/src/style/_layout.scss +++ b/src/style/_layout.scss @@ -626,6 +626,32 @@ } } +.highlight-code { + position: relative; + + > .microlight { + overflow-y: auto; + max-height: 400px; + } +} + +.download-contents { + position: absolute; + bottom: 10px; + right: 10px; + cursor: pointer; + background: #7d8293; + text-align: center; + padding: 5px; + border-radius: 4px; + font-family: 'Titillium Web', sans-serif; + font-weight: 600; + color: white; + font-size: 14px; + height: 30px; + width: 75px; +} + .scheme-container { margin: 0 0 20px 0;