implement browser code viewer

This commit is contained in:
Peter Cai 2020-02-18 20:27:24 +08:00
parent 10ef547da7
commit 348ea6c49c
No known key found for this signature in database
GPG Key ID: 71F5FB4E4F3FD54F
8 changed files with 114 additions and 7 deletions

6
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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'

View File

@ -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
}

54
src/web/codeViewer.coffee Normal file
View File

@ -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

View File

@ -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>

View File

@ -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;
}
}

View File

@ -7,6 +7,7 @@
@import './pastebin.scss';
@import './buttons.scss';
@import './dropzone.scss';
@import './codeViewer.scss';
body, html {
margin: 0px;