pastebin: rewrite using React Hooks
This commit is contained in:
parent
597c6c9359
commit
cf57e3de42
|
@ -1,6 +1,15 @@
|
||||||
import React, { useState } from "react"
|
import React, { useState } from "react"
|
||||||
import ReactModal from "react-modal"
|
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
|
# A hook to support opening dialogs from the code
|
||||||
# returns [openDialog, renderDialog]
|
# returns [openDialog, renderDialog]
|
||||||
# renderDialog should always be called somewhere
|
# renderDialog should always be called somewhere
|
||||||
|
@ -31,3 +40,39 @@ export useDialog = ->
|
||||||
</ReactModal>
|
</ReactModal>
|
||||||
|
|
||||||
[openDialog, renderDialog]
|
[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]
|
|
@ -1,90 +1,52 @@
|
||||||
import React from "react"
|
import React, { useState } from "react"
|
||||||
|
import * as hooks from "./hooks"
|
||||||
import HelpButton from "./helpButton"
|
import HelpButton from "./helpButton"
|
||||||
import LinkButton from "./util/linkButton"
|
import LinkButton from "./util/linkButton"
|
||||||
import ContentEditable from "./util/contentEditable"
|
import ContentEditable from "./util/contentEditable"
|
||||||
|
|
||||||
class Pastebin extends React.Component
|
export default Pastebin = ->
|
||||||
constructor: (props) ->
|
[openDialog, renderDialog] = hooks.useDialog()
|
||||||
super props
|
[highlight, toggleHighlight] = hooks.useToggle false
|
||||||
@state =
|
[text, setText] = useState ""
|
||||||
text: ""
|
[doPaste, pasting, _] = hooks.usePaste openDialog, null, (status) ->
|
||||||
pasting: false
|
setText "" if status == 200
|
||||||
highlight: false # Make this false by default to avoid blocking
|
|
||||||
|
|
||||||
onEditTextUpdate: (ev) =>
|
onEditTextUpdate = (ev) ->
|
||||||
console.log ev.target.value
|
setText ev.target.value
|
||||||
@setState
|
|
||||||
text: ev.target.value
|
|
||||||
|
|
||||||
toggleHighlight: (ev) =>
|
paste = ->
|
||||||
@setState (state, props) =>
|
doPaste "web_paste.txt", "text/plain", text
|
||||||
{ highlight: not state.highlight }
|
|
||||||
|
|
||||||
paste: =>
|
<div className="content-pastebin">
|
||||||
return if @state.text.trim() == ""
|
{renderDialog()}
|
||||||
# Set the state first to disable the button
|
<ContentEditable
|
||||||
@setState
|
className="content-pastebin-edit"
|
||||||
pasting: true
|
onUpdate={onEditTextUpdate}
|
||||||
# For things pasted through the web interface,
|
value={text}
|
||||||
# we always assume the name is `web_paste.txt`,
|
highlightCode={highlight}
|
||||||
# and the content type is always `text/plain`.
|
plainText
|
||||||
resp = await fetch "/paste/web_paste.txt",
|
/>
|
||||||
method: 'PUT'
|
<div className="content-buttons">
|
||||||
headers:
|
<HelpButton openDialog={openDialog} />
|
||||||
'content-type': 'text/plain'
|
<button
|
||||||
body: @state.text
|
className="button-blue"
|
||||||
console.log resp
|
onClick={toggleHighlight}
|
||||||
txt = await resp.text()
|
>
|
||||||
console.log txt
|
Highlight: {if highlight then 'ON' else 'OFF'}
|
||||||
|
</button>
|
||||||
# Dialog opening is provided by parent
|
<LinkButton
|
||||||
@props.openDialog do ->
|
className="button-blue"
|
||||||
if resp.ok
|
disabled={pasting}
|
||||||
<a href={txt} target="_blank">
|
to="/paste/binary"
|
||||||
https://{window.location.hostname}{txt}
|
>
|
||||||
</a>
|
File Upload
|
||||||
else
|
</LinkButton>
|
||||||
txt
|
<button
|
||||||
|
className="button-blue"
|
||||||
@setState
|
disabled={pasting or text.trim() is ""}
|
||||||
text: ""
|
onClick={paste}
|
||||||
|
>
|
||||||
# Reset the button
|
Paste
|
||||||
@setState
|
</button>
|
||||||
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>
|
</div>
|
||||||
|
</div>
|
||||||
export default Pastebin
|
|
Loading…
Reference in New Issue