implement browser code viewer
This commit is contained in:
parent
10ef547da7
commit
348ea6c49c
|
@ -2384,6 +2384,12 @@
|
|||
"minimalistic-assert": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"detect-browser": {
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npm.taobao.org/detect-browser/download/detect-browser-4.8.0.tgz",
|
||||
"integrity": "sha1-HXO9iMF76GaQGVDOCqrh7QYJAsY=",
|
||||
"dev": true
|
||||
},
|
||||
"detect-file": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
"coffee-loader": "^0.9.0",
|
||||
"coffeescript": "^2.5.1",
|
||||
"css-loader": "^3.4.2",
|
||||
"detect-browser": "^4.8.0",
|
||||
"fast-xml-parser": "^3.16.0",
|
||||
"highlight.js": "^9.18.1",
|
||||
"html-webpack-inline-source-plugin": "0.0.10",
|
||||
|
|
|
@ -21,15 +21,18 @@ buildInvalidResponse = (msg) ->
|
|||
new Response msg,
|
||||
status: 400
|
||||
|
||||
buildFrontendResponse = ->
|
||||
new Response indexHtml,
|
||||
status: 200
|
||||
headers:
|
||||
'content-type': 'text/html'
|
||||
|
||||
handleRequest = (event) ->
|
||||
# Handle request for static home page first
|
||||
if event.request.method == "GET"
|
||||
parsedURL = new URL event.request.url
|
||||
if parsedURL.pathname in FRONTEND_PATHS
|
||||
return new Response indexHtml,
|
||||
status: 200
|
||||
headers:
|
||||
'content-type': 'text/html'
|
||||
return buildFrontendResponse _
|
||||
|
||||
# Validate file name first, since this is shared logic
|
||||
file = util.getFileName event.request.url
|
||||
|
@ -99,6 +102,14 @@ handleGET = (req, file) ->
|
|||
return new Response "Something went wrong",
|
||||
status: resp.status
|
||||
|
||||
# If the content is text, and the user is using a browser
|
||||
# show frontend code viewer
|
||||
if not req.url.endsWith 'original'
|
||||
isText = util.isText resp.headers.get 'content-type'
|
||||
isBrowser = util.isBrowser req
|
||||
if isText and isBrowser
|
||||
return buildFrontendResponse _
|
||||
|
||||
# Build response headers
|
||||
headers =
|
||||
'content-length': resp.headers.get 'content-length'
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { detect as detectBrowser } from 'detect-browser'
|
||||
|
||||
# Maimum upload size (in bytes)
|
||||
MAX_UPLOAD_SIZE = 10 * 1024 * 1024 # 10 MB
|
||||
|
||||
|
@ -34,18 +36,28 @@ idToPath = (id) ->
|
|||
|
||||
# Determine if we show something inline or not
|
||||
shouldShowInline = (mime) ->
|
||||
mime.startsWith('text/') or
|
||||
isText(mime) or
|
||||
mime.startsWith('image/') or
|
||||
mime.startsWith('audio/') or
|
||||
mime.startsWith('video/') or
|
||||
mime.startsWith('video/')
|
||||
|
||||
isText = (mime) ->
|
||||
mime.startsWith('text/') or
|
||||
mime == 'application/json' or
|
||||
mime == 'application/javascript'
|
||||
|
||||
# Determine if we consider the user a browser or not
|
||||
isBrowser = (req) ->
|
||||
b = detectBrowser req.headers.get 'user-agent'
|
||||
(not b) or (b.name != 'searchbot')
|
||||
|
||||
export {
|
||||
getFileName,
|
||||
validateLength,
|
||||
MAX_UPLOAD_SIZE,
|
||||
randomID,
|
||||
idToPath,
|
||||
shouldShowInline
|
||||
shouldShowInline,
|
||||
isBrowser,
|
||||
isText
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
import React from "react"
|
||||
import { Redirect } from "react-router-dom"
|
||||
import hljs from "highlight.js"
|
||||
|
||||
MAX_HIGHLIGHT_LENGTH = 10 * 1024 # 10 KiB
|
||||
|
||||
class CodeViewer extends React.Component
|
||||
constructor: (props) ->
|
||||
super props
|
||||
@state =
|
||||
code: "Loading..."
|
||||
switchToHome: false
|
||||
highlight: true
|
||||
|
||||
componentDidMount: ->
|
||||
resp = await fetch "/paste/#{@props.match.params.id}?original"
|
||||
resp = await resp.text()
|
||||
if resp.length < MAX_HIGHLIGHT_LENGTH
|
||||
resp = hljs.highlightAuto(resp).value
|
||||
else
|
||||
@setState
|
||||
highlight: false
|
||||
|
||||
@setState
|
||||
code: resp
|
||||
|
||||
render: ->
|
||||
if @state.switchToHome
|
||||
return <Redirect push to="/paste/text" />
|
||||
|
||||
<div className="content-pastebin">
|
||||
<div
|
||||
className="content-code-viewer"
|
||||
>
|
||||
{
|
||||
if @state.highlight
|
||||
<pre
|
||||
dangerouslySetInnerHTML={{__html: @state.code}}
|
||||
/>
|
||||
else
|
||||
<pre>{@state.code}</pre>
|
||||
}
|
||||
</div>
|
||||
<div className="content-buttons">
|
||||
<button
|
||||
className="button-blue"
|
||||
onClick={(ev) => @setState { switchToHome: true }}
|
||||
>
|
||||
New Paste
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
export default CodeViewer
|
|
@ -4,6 +4,7 @@ import { AnimatedSwitch } from 'react-router-transition'
|
|||
import ReactModal from "react-modal"
|
||||
import Pastebin from "./pastebin"
|
||||
import BinaryUpload from "./binaryUpload"
|
||||
import CodeViewer from "./codeViewer"
|
||||
|
||||
class Home extends React.Component
|
||||
constructor: (props) ->
|
||||
|
@ -36,6 +37,10 @@ class Home extends React.Component
|
|||
exact path="/paste/binary"
|
||||
component={() => <BinaryUpload openDialog={@openDialog}/>}
|
||||
/>
|
||||
<Route
|
||||
path="/paste/:id"
|
||||
component={CodeViewer}
|
||||
/>
|
||||
</AnimatedSwitch>
|
||||
</Router>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
// Some blend of both editable and pastebin style
|
||||
.content-code-viewer {
|
||||
display: block;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
text-align: left;
|
||||
box-sizing: border-box;
|
||||
font-family: monospace;
|
||||
padding: 10px;
|
||||
outline: none;
|
||||
border: 1px solid $editable-color;
|
||||
border-radius: $editable-radius;
|
||||
|
||||
pre {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
@import './pastebin.scss';
|
||||
@import './buttons.scss';
|
||||
@import './dropzone.scss';
|
||||
@import './codeViewer.scss';
|
||||
|
||||
body, html {
|
||||
margin: 0px;
|
||||
|
|
Loading…
Reference in New Issue