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`
This commit is contained in:
committed by
kyle
parent
2bf2167a18
commit
2795518340
@@ -52,6 +52,7 @@
|
|||||||
"getbase": "^2.8.2",
|
"getbase": "^2.8.2",
|
||||||
"ieee754": "^1.1.8",
|
"ieee754": "^1.1.8",
|
||||||
"immutable": "^3.x.x",
|
"immutable": "^3.x.x",
|
||||||
|
"js-file-download": "^0.4.1",
|
||||||
"js-yaml": "^3.5.5",
|
"js-yaml": "^3.5.5",
|
||||||
"lodash": "4.17.5",
|
"lodash": "4.17.5",
|
||||||
"matcher": "^0.1.2",
|
"matcher": "^0.1.2",
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import React, { Component } from "react"
|
import React, { Component } from "react"
|
||||||
import PropTypes from "prop-types"
|
import PropTypes from "prop-types"
|
||||||
import { highlight } from "core/utils"
|
import { highlight } from "core/utils"
|
||||||
|
import saveAs from "js-file-download"
|
||||||
|
|
||||||
export default class HighlightCode extends Component {
|
export default class HighlightCode extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
value: PropTypes.string.isRequired,
|
value: PropTypes.string.isRequired,
|
||||||
className: PropTypes.string
|
className: PropTypes.string,
|
||||||
|
downloadable: PropTypes.bool
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@@ -20,10 +22,46 @@ export default class HighlightCode extends Component {
|
|||||||
this.el = c
|
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 () {
|
render () {
|
||||||
let { value, className } = this.props
|
let { value, className, downloadable } = this.props
|
||||||
className = className || ""
|
className = className || ""
|
||||||
|
|
||||||
return <pre ref={this.initializeComponent} className={className + " microlight"}>{ value }</pre>
|
return (
|
||||||
|
<div className="highlight-code">
|
||||||
|
{ !downloadable ? null :
|
||||||
|
<div className="download-contents" onClick={this.downloadText}>
|
||||||
|
Download
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<pre
|
||||||
|
ref={this.initializeComponent}
|
||||||
|
onWheel={this.preventYScrollingBeyondElement}
|
||||||
|
className={className + " microlight"}>
|
||||||
|
{value}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export default class ResponseBody extends React.Component {
|
|||||||
body = "can't parse JSON. Raw result:\n\n" + content
|
body = "can't parse JSON. Raw result:\n\n" + content
|
||||||
}
|
}
|
||||||
|
|
||||||
bodyEl = <HighlightCode value={ body } />
|
bodyEl = <HighlightCode downloadable value={ body } />
|
||||||
|
|
||||||
// XML
|
// XML
|
||||||
} else if (/xml/i.test(contentType)) {
|
} else if (/xml/i.test(contentType)) {
|
||||||
@@ -74,11 +74,11 @@ export default class ResponseBody extends React.Component {
|
|||||||
textNodesOnSameLine: true,
|
textNodesOnSameLine: true,
|
||||||
indentor: " "
|
indentor: " "
|
||||||
})
|
})
|
||||||
bodyEl = <HighlightCode value={ body } />
|
bodyEl = <HighlightCode downloadable value={ body } />
|
||||||
|
|
||||||
// HTML or Plain Text
|
// HTML or Plain Text
|
||||||
} else if (lowerCase(contentType) === "text/html" || /text\/plain/.test(contentType)) {
|
} else if (lowerCase(contentType) === "text/html" || /text\/plain/.test(contentType)) {
|
||||||
bodyEl = <HighlightCode value={ content } />
|
bodyEl = <HighlightCode downloadable value={ content } />
|
||||||
|
|
||||||
// Image
|
// Image
|
||||||
} else if (/^image\//i.test(contentType)) {
|
} else if (/^image\//i.test(contentType)) {
|
||||||
@@ -92,7 +92,7 @@ export default class ResponseBody extends React.Component {
|
|||||||
} else if (/^audio\//i.test(contentType)) {
|
} else if (/^audio\//i.test(contentType)) {
|
||||||
bodyEl = <pre><audio controls><source src={ url } type={ contentType } /></audio></pre>
|
bodyEl = <pre><audio controls><source src={ url } type={ contentType } /></audio></pre>
|
||||||
} else if (typeof content === "string") {
|
} else if (typeof content === "string") {
|
||||||
bodyEl = <HighlightCode value={ content } />
|
bodyEl = <HighlightCode downloadable value={ content } />
|
||||||
} else if ( content.size > 0 ) {
|
} else if ( content.size > 0 ) {
|
||||||
// We don't know the contentType, but there was some content returned
|
// We don't know the contentType, but there was some content returned
|
||||||
bodyEl = <div>Unknown response type</div>
|
bodyEl = <div>Unknown response type</div>
|
||||||
|
|||||||
@@ -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
|
.scheme-container
|
||||||
{
|
{
|
||||||
margin: 0 0 20px 0;
|
margin: 0 0 20px 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user