From d705107d350548c2b67c6ae7acb8360c6cde0f4f Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Tue, 18 Feb 2020 17:39:38 +0800 Subject: [PATCH] implement binary upload --- package-lock.json | 195 +++++++++++++++++++++++++++++++++++ package.json | 3 + src/web/binaryUpload.coffee | 97 +++++++++++++++++ src/web/home.coffee | 22 +++- src/web/pastebin.coffee | 12 +++ src/web/styles/dropzone.scss | 39 +++++++ src/web/styles/home.scss | 13 +++ src/web/styles/index.scss | 1 + 8 files changed, 381 insertions(+), 1 deletion(-) create mode 100644 src/web/binaryUpload.coffee create mode 100644 src/web/styles/dropzone.scss diff --git a/package-lock.json b/package-lock.json index e23bfaa..b81c7c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -925,6 +925,23 @@ "@babel/plugin-transform-react-jsx-source": "^7.8.3" } }, + "@babel/runtime": { + "version": "7.8.4", + "resolved": "https://registry.npm.taobao.org/@babel/runtime/download/@babel/runtime-7.8.4.tgz", + "integrity": "sha1-159aIED3yqJNU+VjqtScvAVYEwg=", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.2" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npm.taobao.org/regenerator-runtime/download/regenerator-runtime-0.13.3.tgz", + "integrity": "sha1-fPanfY9cb2Drc8X8GVWyzrAea/U=", + "dev": true + } + } + }, "@babel/template": { "version": "7.8.3", "resolved": "https://registry.npm.taobao.org/@babel/template/download/@babel/template-7.8.3.tgz", @@ -1376,6 +1393,12 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, + "attr-accept": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/attr-accept/download/attr-accept-2.0.0.tgz", + "integrity": "sha1-hCL+9e5KURwgd5bIiCJ6td4DMG8=", + "dev": true + }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npm.taobao.org/aws-sign2/download/aws-sign2-0.7.0.tgz", @@ -2817,6 +2840,15 @@ "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", "dev": true }, + "file-selector": { + "version": "0.1.12", + "resolved": "https://registry.npm.taobao.org/file-selector/download/file-selector-0.1.12.tgz", + "integrity": "sha1-/nJlR74hmnh6ncxkBXWgSgMrH9A=", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -3707,6 +3739,12 @@ "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", "dev": true }, + "gud": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/gud/download/gud-1.0.0.tgz", + "integrity": "sha1-pIlYGxfmpwvsqavjrlfeekmYUsA=", + "dev": true + }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npm.taobao.org/har-schema/download/har-schema-2.0.0.tgz", @@ -3823,6 +3861,20 @@ "integrity": "sha1-7SGqAB/mJSuxCj121HVzxlOf4Tw=", "dev": true }, + "history": { + "version": "4.10.1", + "resolved": "https://registry.npm.taobao.org/history/download/history-4.10.1.tgz?cache=0&sync_timestamp=1581115672888&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhistory%2Fdownload%2Fhistory-4.10.1.tgz", + "integrity": "sha1-MzcaZeOoOyZ0NOKz87G0xYqtTPM=", + "dev": true, + "requires": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -3834,6 +3886,15 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npm.taobao.org/hoist-non-react-statics/download/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha1-7OCsr3HWLClpwuxZ/v9CpLGoW0U=", + "dev": true, + "requires": { + "react-is": "^16.7.0" + } + }, "homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", @@ -4654,6 +4715,17 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, + "mini-create-react-context": { + "version": "0.3.2", + "resolved": "https://registry.npm.taobao.org/mini-create-react-context/download/mini-create-react-context-0.3.2.tgz", + "integrity": "sha1-efxZjyg91iPajgiLBduM3aslAYk=", + "dev": true, + "requires": { + "@babel/runtime": "^7.4.0", + "gud": "^1.0.0", + "tiny-warning": "^1.0.2" + } + }, "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -5310,6 +5382,23 @@ "integrity": "sha1-1i27VnlAXXLEc37FhgDp3c8G0kw=", "dev": true }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-1.8.0.tgz", + "integrity": "sha1-iHs7qdhDk+h6CgufTLdWGYtTVIo=", + "dev": true, + "requires": { + "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npm.taobao.org/isarray/download/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + } + } + }, "path-type": { "version": "1.1.0", "resolved": "https://registry.npm.taobao.org/path-type/download/path-type-1.1.0.tgz", @@ -5595,6 +5684,15 @@ "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", "dev": true }, + "raf": { + "version": "3.4.1", + "resolved": "https://registry.npm.taobao.org/raf/download/raf-3.4.1.tgz", + "integrity": "sha1-B0LpmkplUvRF1z4+4DKK8P8e3jk=", + "dev": true, + "requires": { + "performance-now": "^2.1.0" + } + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -5659,6 +5757,17 @@ "scheduler": "^0.18.0" } }, + "react-dropzone": { + "version": "10.2.1", + "resolved": "https://registry.npm.taobao.org/react-dropzone/download/react-dropzone-10.2.1.tgz", + "integrity": "sha1-t1IBJMSjtm+W1J94eQJ8ekdeqiA=", + "dev": true, + "requires": { + "attr-accept": "^2.0.0", + "file-selector": "^0.1.12", + "prop-types": "^15.7.2" + } + }, "react-is": { "version": "16.12.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", @@ -5683,6 +5792,68 @@ "warning": "^4.0.3" } }, + "react-motion": { + "version": "0.5.2", + "resolved": "https://registry.npm.taobao.org/react-motion/download/react-motion-0.5.2.tgz", + "integrity": "sha1-DdOmnkETFlZ5J5F8ZiZVG6BgcxY=", + "dev": true, + "requires": { + "performance-now": "^0.2.0", + "prop-types": "^15.5.8", + "raf": "^3.1.0" + }, + "dependencies": { + "performance-now": { + "version": "0.2.0", + "resolved": "https://registry.npm.taobao.org/performance-now/download/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", + "dev": true + } + } + }, + "react-router": { + "version": "5.1.2", + "resolved": "https://registry.npm.taobao.org/react-router/download/react-router-5.1.2.tgz", + "integrity": "sha1-bqUdeJyzamvhul98DUjdnoF9NBg=", + "dev": true, + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "mini-create-react-context": "^0.3.0", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + } + }, + "react-router-dom": { + "version": "5.1.2", + "resolved": "https://registry.npm.taobao.org/react-router-dom/download/react-router-dom-5.1.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-router-dom%2Fdownload%2Freact-router-dom-5.1.2.tgz", + "integrity": "sha1-BnAbg0NS9E03+7YxH4cPhMdrnBg=", + "dev": true, + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.1.2", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + } + }, + "react-router-transition": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/react-router-transition/download/react-router-transition-2.0.0.tgz", + "integrity": "sha1-wApCQPCq1fRBUs8d5JxoK/AOQ6w=", + "dev": true, + "requires": { + "prop-types": "^15.7.2", + "react-motion": "^0.5.2" + } + }, "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npm.taobao.org/read-pkg/download/read-pkg-1.1.0.tgz", @@ -5971,6 +6142,12 @@ "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", "dev": true }, + "resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/resolve-pathname/download/resolve-pathname-3.0.0.tgz", + "integrity": "sha1-mdAiJNPPJjaJvsuzk7xWAxMCXc0=", + "dev": true + }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -6830,6 +7007,18 @@ "setimmediate": "^1.0.4" } }, + "tiny-invariant": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/tiny-invariant/download/tiny-invariant-1.1.0.tgz", + "integrity": "sha1-Y0xfjv3CdxS384bDXmdgmR0jCHU=", + "dev": true + }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npm.taobao.org/tiny-warning/download/tiny-warning-1.0.3.tgz", + "integrity": "sha1-lKMNtFPfTGQ9D9VmBg1gqHXYR1Q=", + "dev": true + }, "to-arraybuffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", @@ -7211,6 +7400,12 @@ "spdx-expression-parse": "^3.0.0" } }, + "value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/value-equal/download/value-equal-1.0.1.tgz", + "integrity": "sha1-Hgt5THNMXAyt4XnEN9NW2TGjTWw=", + "dev": true + }, "verror": { "version": "1.10.0", "resolved": "https://registry.npm.taobao.org/verror/download/verror-1.10.0.tgz", diff --git a/package.json b/package.json index ea3f000..321d8cc 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,10 @@ "raw-loader": "^4.0.0", "react": "^16.12.0", "react-dom": "^16.12.0", + "react-dropzone": "^10.2.1", "react-modal": "^3.11.1", + "react-router-dom": "^5.1.2", + "react-router-transition": "^2.0.0", "sass-loader": "^8.0.2", "style-loader": "^1.1.3", "url-loader": "^3.0.0", diff --git a/src/web/binaryUpload.coffee b/src/web/binaryUpload.coffee new file mode 100644 index 0000000..fa3bee8 --- /dev/null +++ b/src/web/binaryUpload.coffee @@ -0,0 +1,97 @@ +import React from "react" +import { Redirect } from "react-router-dom" +import Dropzone from "react-dropzone" + +class BinaryUpload extends React.Component + constructor: (props) -> + super props + @state = + file: null + uploading: false + progress: 0 + switchToText: false + + onDrop: (files) => + @setState + file: files[0] + + doUpload: => + @setState + uploading: true + progress: 0 + # Due to the lack of progress feature in current Fetch API + # We have to use XHR for now. Dang. + xhr = new XMLHttpRequest() + xhr.upload.addEventListener "progress", (e) => + if e.lengthComputable + @setState + progress: e.loaded / e.total + xhr.addEventListener "readystatechange", => + if xhr.readyState == XMLHttpRequest.DONE + @setState + uploading: false + file: null + @props.openDialog do -> + if xhr.status == 200 + + https://{window.location.hostname}{xhr.responseText} + + else + xhr.responseText + xhr.open 'PUT', '/paste/' + @state.file.name + xhr.send @state.file + + progressText: -> + txt = (@state.progress * 100).toFixed(2) + "%" + if @state.progress < 0.1 + "0" + txt + else + txt + + render: -> + if @state.switchToText + return + +
+ + {({getRootProps, getInputProps}) => +
+
+ +

Drag 'n' drop a file here to upload, or click to select

+
+ +
+ } +
+
+ + +
+
+ +export default BinaryUpload \ No newline at end of file diff --git a/src/web/home.coffee b/src/web/home.coffee index 773acd2..244f4f2 100644 --- a/src/web/home.coffee +++ b/src/web/home.coffee @@ -1,6 +1,9 @@ import React from "react" +import { BrowserRouter as Router, Route, Switch, Redirect } from "react-router-dom" +import { AnimatedSwitch } from 'react-router-transition' import ReactModal from "react-modal" import Pastebin from "./pastebin" +import BinaryUpload from "./binaryUpload" class Home extends React.Component constructor: (props) -> @@ -17,7 +20,24 @@ class Home extends React.Component render: ->
- + + + + } + /> + } + /> + +
{ # Provide modal dialog for all child diff --git a/src/web/pastebin.coffee b/src/web/pastebin.coffee index 65720c3..ebdf4b6 100644 --- a/src/web/pastebin.coffee +++ b/src/web/pastebin.coffee @@ -1,4 +1,5 @@ import React from "react" +import { Redirect } from "react-router-dom" import ContentEditable from "./util/contentEditable" class Pastebin extends React.Component @@ -8,6 +9,7 @@ class Pastebin extends React.Component text: "" pasting: false highlight: true + switchToUpload: false onEditTextUpdate: (ev) => console.log ev.target.value @@ -52,6 +54,9 @@ class Pastebin extends React.Component pasting: false render: -> + if @state.switchToUpload + return +
Highlight: {if @state.highlight then 'ON' else 'OFF'} +