pastebin: rewrite using React Hooks

This commit is contained in:
Peter Cai 2020-02-20 09:20:58 +08:00
parent 597c6c9359
commit cf57e3de42
No known key found for this signature in database
GPG Key ID: 71F5FB4E4F3FD54F
2 changed files with 89 additions and 82 deletions

View File

@ -1,6 +1,15 @@
import React, { useState } from "react"
import ReactModal from "react-modal"
# Simple abstraction for a toggling state
export useToggle = (defVal) ->
[state, setState] = useState defVal
toggle = ->
setState (prev) -> not prev
[state, toggle]
# A hook to support opening dialogs from the code
# returns [openDialog, renderDialog]
# renderDialog should always be called somewhere
@ -31,3 +40,39 @@ export useDialog = ->
</ReactModal>
[openDialog, renderDialog]
# Handles shared file-uploading logic between text / binary pasting
export usePaste = (openDialog, transformUrl, callback) ->
[pasting, setPasting] = useState false
[progress, setProgress] = useState 0
doPaste = (name, mime, content) ->
# Unfortunately we have to all resort to using XHR here
setProgress 0
setPasting true
# Build the XHR
xhr = new XMLHttpRequest()
xhr.upload.addEventListener "progress", (e) ->
if e.lengthComputable
setProgress e.loaded / e.total
xhr.addEventListener "readystatechange", ->
if xhr.readyState == XMLHttpRequest.DONE
setPasting false
openDialog do ->
if xhr.status == 200
url = xhr.responseText
url = transformUrl url if transformUrl
<a href={url} target="_blank">
https://{window.location.hostname}{url}
</a>
else
xhr.responseText
callback xhr.status, xhr.responseText if callback
# Handle uploading
xhr.open 'PUT', "/paste/" + name
xhr.setRequestHeader "content-type", mime
xhr.send content
[doPaste, pasting, progress]

View File

@ -1,90 +1,52 @@
import React from "react"
import React, { useState } from "react"
import * as hooks from "./hooks"
import HelpButton from "./helpButton"
import LinkButton from "./util/linkButton"
import ContentEditable from "./util/contentEditable"
class Pastebin extends React.Component
constructor: (props) ->
super props
@state =
text: ""
pasting: false
highlight: false # Make this false by default to avoid blocking
export default Pastebin = ->
[openDialog, renderDialog] = hooks.useDialog()
[highlight, toggleHighlight] = hooks.useToggle false
[text, setText] = useState ""
[doPaste, pasting, _] = hooks.usePaste openDialog, null, (status) ->
setText "" if status == 200
onEditTextUpdate: (ev) =>
console.log ev.target.value
@setState
text: ev.target.value
onEditTextUpdate = (ev) ->
setText ev.target.value
toggleHighlight: (ev) =>
@setState (state, props) =>
{ highlight: not state.highlight }
paste = ->
doPaste "web_paste.txt", "text/plain", text
paste: =>
return if @state.text.trim() == ""
# Set the state first to disable the button
@setState
pasting: true
# For things pasted through the web interface,
# we always assume the name is `web_paste.txt`,
# and the content type is always `text/plain`.
resp = await fetch "/paste/web_paste.txt",
method: 'PUT'
headers:
'content-type': 'text/plain'
body: @state.text
console.log resp
txt = await resp.text()
console.log txt
# Dialog opening is provided by parent
@props.openDialog do ->
if resp.ok
<a href={txt} target="_blank">
https://{window.location.hostname}{txt}
</a>
else
txt
@setState
text: ""
# Reset the button
@setState
pasting: false
render: ->
<div className="content-pastebin">
<ContentEditable
className="content-pastebin-edit"
onUpdate={@onEditTextUpdate}
value={@state.text}
highlightCode={@state.highlight}
plainText
/>
<div className="content-buttons">
<HelpButton openDialog={@props.openDialog} />
<button
className="button-blue"
onClick={@toggleHighlight}
>
Highlight: {if @state.highlight then 'ON' else 'OFF'}
</button>
<LinkButton
className="button-blue"
disabled={@state.pasting}
to="/paste/binary"
>
File Upload
</LinkButton>
<button
className="button-blue"
disabled={@state.pasting or @state.text.trim() is ""}
onClick={@paste}
>
Paste
</button>
</div>
<div className="content-pastebin">
{renderDialog()}
<ContentEditable
className="content-pastebin-edit"
onUpdate={onEditTextUpdate}
value={text}
highlightCode={highlight}
plainText
/>
<div className="content-buttons">
<HelpButton openDialog={openDialog} />
<button
className="button-blue"
onClick={toggleHighlight}
>
Highlight: {if highlight then 'ON' else 'OFF'}
</button>
<LinkButton
className="button-blue"
disabled={pasting}
to="/paste/binary"
>
File Upload
</LinkButton>
<button
className="button-blue"
disabled={pasting or text.trim() is ""}
onClick={paste}
>
Paste
</button>
</div>
export default Pastebin
</div>