From ae2bdda62920a355fc0b71827d500979a420a47f Mon Sep 17 00:00:00 2001 From: AJvanLoon Date: Sun, 3 Jun 2018 11:21:45 +0200 Subject: [PATCH 01/21] is -> in --- website/src/docs/uppy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/docs/uppy.md b/website/src/docs/uppy.md index 69a947306..2a67828f9 100644 --- a/website/src/docs/uppy.md +++ b/website/src/docs/uppy.md @@ -365,7 +365,7 @@ Update the state for a single file. This is mostly useful for plugins that may w ### `uppy.setMeta(data)` -Alters global `meta` object is state, the one that can be set in Uppy options and gets merged with all newly added files. Calling `setMeta` will also merge newly added meta data with previously selected files. +Alters global `meta` object in state, the one that can be set in Uppy options and gets merged with all newly added files. Calling `setMeta` will also merge newly added meta data with previously selected files. ```js uppy.setMeta({ resize: 1500, token: 'ab5kjfg' }) From 723c88def763ba01cf0495ea908b614de36397be Mon Sep 17 00:00:00 2001 From: AJvanLoon Date: Sun, 3 Jun 2018 13:47:29 +0200 Subject: [PATCH 02/21] Some docs polish @arturi --- website/src/docs/server.md | 94 +++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/website/src/docs/server.md b/website/src/docs/server.md index 02de80367..1cda7c98b 100644 --- a/website/src/docs/server.md +++ b/website/src/docs/server.md @@ -5,23 +5,23 @@ permalink: docs/server/ order: 2 --- -Drag and Drop, Webcam, basic file manipulation (adding metadata, for example) and uploading via tus resumable uploads or XHR/Multipart are all possible using just the uppy client module. +Drag and drop, webcam, basic file manipulation (adding metadata, for example) and uploading via tus-resumable uploads or XHR/Multipart are all possible using just the Uppy client module. -However, if you add [Uppy Server](https://github.com/transloadit/uppy-server) to the mix, your users will be able to select files from remote sources, such as Instagram, Google Drive and Dropbox, bypassing the client (so a 5 GB video isn’t eating into your users’ data plans), and then uploaded to the final destination. Files are removed from Uppy Server after an upload is complete, or after a reasonable timeout. Access tokens also don’t stick around for long, for security. +However, if you add [Uppy Server](https://github.com/transloadit/uppy-server) to the mix, your users will be able to select files from remote sources, such as Instagram, Google Drive and Dropbox, bypassing the client (so a 5 GB video isn’t eating into your users’ data plans), and then uploaded to the final destination. Files are removed from Uppy Server after an upload is complete, or after a reasonable timeout. Access tokens also don’t stick around for long, for security reasons. Uppy Server handles the server-to-server communication between your server and file storage providers such as Google Drive, Dropbox, Instagram, etc. -## Supported Providers +## Supported providers -As of now Uppy Server is integrated to work with: +As of now, Uppy Server is integrated to work with: - Google Drive - Dropbox - Instagram -- Remote Urls +- Remote URLs - Amazon S3 -## Install +## Installation ```bash npm install uppy-server @@ -29,11 +29,11 @@ npm install uppy-server ## Usage -Uppy Server may either be used as a pluggable express app, which you plug to your already existing server, or it may simply be run as a standalone server: +Uppy Server may either be used as a pluggable express app, which you plug into your already existing server, or it may simply be run as a standalone server: -### Plug to already existing server +### Plugging into an already existing server -To plug Uppy Server to an existing server, simply call on its `.app` method, passing in an [options](#Options) object as parameter. +To plug Uppy Server into an existing server, simply call on its `.app` method, passing in an [options](#Options) object as a parameter. ```javascript @@ -66,7 +66,7 @@ app.use(uppy.app(options)) ``` See [Options](#Options) for valid configuration options. -To enable Uppy Socket for realtime upload progress, you can call the `socket` method like so: +To enable Uppy Socket for realtime upload progress, you can call the `socket` method, like so: ```javascript ... @@ -75,9 +75,9 @@ var server = app.listen(PORT) uppy.socket(server, options) ``` -This takes your `server` instance and your Uppy [options](#Options) as parameters. +This takes your `server` instance and your Uppy [Options](#Options) as parameters. -### Run as standalone server +### Running as a standalone server > Please ensure that the required environment variables are set before running/using Uppy Server as a standalone server. See [Configure Standalone](#Configure-Standalone) for the variables required. @@ -101,7 +101,7 @@ If you cloned the repo from GitHub and want to run it as a standalone server, yo npm start ``` -You can also pass in the path to your json config file like so: +You can also pass in the path to your JSON config file, like so: ```bash uppy-server --config /path/to/uppyconf.json @@ -113,11 +113,11 @@ or npm start -- --config /path/to/uppyconf.json ``` -Please see [options](#Options) for possible options. +Please see [Options](#Options) for possible options. -#### Configure Standalone +#### Configuring a standalone server -To run Uppy Server as a standalone server, you are required to set your Uppy [options](#Options) via environment variables: +To run Uppy Server as a standalone server, you are required to set your Uppy [Options](#Options) via environment variables: ```bash ####### Mandatory variables ########### @@ -131,24 +131,24 @@ export UPPYSERVER_DATADIR="PATH/TO/DOWNLOAD/DIRECTORY" ###### Optional variables ########## -# corresponds to the server.protocol option. defaults to http +# corresponds to the server.protocol option, defaults to http export UPPYSERVER_PROTOCOL="YOUR SERVER PROTOCOL" -# the port to start the server on. defaults to 3020 +# the port on which to start the server, defaults to 3020 export UPPYSERVER_PORT="YOUR SERVER PORT" -# corresponds to the server.port option. defaults to '' +# corresponds to the server.port option, defaults to '' export UPPYSERVER_PATH="/SERVER/PATH/TO/WHERE/UPPY-SERVER/LIVES" # use this in place of UPPYSERVER_PATH if the server path should not be -# handled by the express.js app but maybe by an external server configuration +# handled by the express.js app, but maybe by an external server configuration # instead (e.g Nginx). export UPPYSERVER_IMPLICIT_PATH="/SERVER/PATH/TO/WHERE/UPPY/SERVER/LIVES" -# comma separated client hosts to whitlelist by the server +# comma-separated client hosts to whitlelist by the server # if not specified, the server would allow any host export UPPY_ENDPOINTS="localhost:3452,uppy.io" # corresponds to the redisUrl option -# This also enables redis session storage if set +# this also enables Redis session storage if set export UPPYSERVER_REDIS_URL="REDIS URL" # to enable Dropbox @@ -163,7 +163,7 @@ export UPPYSERVER_GOOGLE_SECRET="YOUR GOOGLE SECRET" export UPPYSERVER_INSTAGRAM_KEY="YOUR INSTAGRAM KEY" export UPPYSERVER_INSTAGRAM_SECRET="YOUR INSTAGRAM SECRET" -# to enable s3 +# to enable S3 export UPPYSERVER_AWS_KEY="YOUR AWS KEY" export UPPYSERVER_AWS_SECRET="YOUR AWS SECRET" export UPPYSERVER_AWS_BUCKET="YOUR AWS S3 BUCKET" @@ -177,7 +177,7 @@ export UPPYSERVER_DOMAINS="sub1.domain.com,sub2.domain.com,sub3.domain.com" # corresponds to the sendSelfEndpoint option export UPPYSERVER_SELF_ENDPOINT="THIS SHOULD BE SAME AS YOUR DOMAIN + PATH" -# comma separated urls +# comma-separated URLs # corresponds to the uploadUrls option export UPPYSERVER_UPLOAD_URLS="http://master.tus.io/files/,https://master.tus.io/files/" ``` @@ -221,37 +221,37 @@ See [env.example.sh](https://github.com/transloadit/uppy-server/blob/master/env. } ``` -1. **filePath(required)** - Full path to the directory where provider files would temporarily be downloaded to. +1. **filePath(required)** - Full path to the directory to which provider files would be downloaded temporarily. -2. **redisUrl(optional)** - URL to running redis server. If this is set, the state of uploads would be stored temporarily. This helps for resumed uploads after a browser crash from the client. The stored upload would be sent back to the client on reconnection. +2. **redisUrl(optional)** - URL to running Redis server. If this is set, the state of uploads would be stored temporarily. This helps for resumed uploads after a browser crash from the client. The stored upload would be sent back to the client on reconnection. -3. **providerOptions(optional)** - An object containing credentials (`key` and `secret`) for each provider you would like to enable. Please see [here for the list of supported providers](#Supported-Providers). +3. **providerOptions(optional)** - An object containing credentials (`key` and `secret`) for each provider you would like to enable. Please see [the list of supported providers](#Supported-Providers). -4. **server(optional)** - An object with details mainly used to carry out oauth authentication from any of the enabled providers above. Though it is optional, it is required if you would be enabling any of the supported providers. The following are the server options you may set: +4. **server(optional)** - An object with details, mainly used to carry out oauth authentication from any of the enabled providers above. Though it is optional, it is required if you would be enabling any of the supported providers. The following are the server options you may set: - protocol - `http | https` - host(required) - your server host (e.g localhost:3020, mydomain.com) - - path - the server path to where the uppy app is sitting (e.g if uppy server is at `mydomain.com/uppy`, then the path would be `/uppy`). - - oauthDomain - if you have multiple instances of uppy server with different (and maybe dynamic) subdomains, you can set a master domain (e.g `sub1.mydomain.com`) to handle your oauth authentication for you. This would then redirect to the slave subdomain with the required credentials on completion. - - validHosts - if you are setting a master `oauthDomain`, you need to set a list of valid hosts, so the master oauth handler can validate the host of the uppy instance requesting the authentication. This is basically a list of valid domains running your uppy server instances. The list may also contain regex patterns. e.g `['sub2.mydomain.com', 'sub3.mydomain.com', '(\\w+).mydomain.com']` + - path - the server path to where the Uppy app is sitting (e.g if Uppy Server is at `mydomain.com/uppy`, then the path would be `/uppy`). + - oauthDomain - if you have multiple instances of Uppy Server with different (and perhaps dynamic) subdomains, you can set a master domain (e.g `sub1.mydomain.com`) to handle your oauth authentication for you. This would then redirect to the slave subdomain with the required credentials on completion. + - validHosts - if you are setting a master `oauthDomain`, you need to set a list of valid hosts, so the master oauth handler can validate the host of the Uppy instance requesting the authentication. This is basically a list of valid domains running your Uppy Server instances. The list may also contain regex patterns. e.g `['sub2.mydomain.com', 'sub3.mydomain.com', '(\\w+).mydomain.com']` 5. **sendSelfEndpoint(optional)** - This is basically the same as the `server.host + server.path` attributes. The major reason for this attribute is that, when set, it adds the value as the `i-am` header of every request response. 6. **customProviders(optional)** - This option enables you to add custom providers along with the already supported providers. See [Adding Custom Providers](#Adding-Custom-Providers) for more information. -7. **uploadUrls(optional)** - An array of urls (full paths). If specified, Uppy Server will only accept uploads to these urls (useful when you want to make sure an Uppy Server instance is only allowed to upload to your servers, for example). +7. **uploadUrls(optional)** - An array of URLs (full paths). If specified, Uppy Server will only accept uploads to these URLs (useful when you want to make sure an Uppy Server instance is only allowed to upload to your servers, for example). 8. **secret(required)** - A secret string which Uppy Server uses to generate authorization tokens. 9. **debug(optional)** - A boolean flag to tell Uppy Server whether or not to log useful debug information while running. -### S3 Options +### S3 options The S3 uploader has some options in addition to the ones necessary for authentication. #### `s3.getKey(req, filename)` -Get the key name for a file. The key is the file path that the file will be uploaded to in your bucket. This option should be a function receiving two arguments: `req`, the HTTP request, and the original `filename` of the uploaded file. It should return a string `key`. The `req` parameter can be used to upload to a user-specific folder in your bucket, for example: +Get the key name for a file. The key is the file path to which the file will be uploaded in your bucket. This option should be a function receiving two arguments: `req`, the HTTP request, and the original `filename` of the uploaded file. It should return a string `key`. The `req` parameter can be used to upload to a user-specific folder in your bucket, for example: ```js app.use(authenticationMiddleware) @@ -265,13 +265,13 @@ app.use(uppy.app({ The default value simply returns `filename`, so all files will be uploaded to the root of the bucket as their original file name. -### Run in Kubernetes +### Running in Kubernetes We have [a detailed guide on running Uppy Server in Kubernetes](https://github.com/transloadit/uppy-server/blob/master/KUBERNETES.md) for you, that’s how we currently run our example server at http://server.uppy.io. -### Adding Custom Providers +### Adding custom providers -As of now, Uppy Server supports **Google Drive**, **Dropbox**, **Instagram**, and **Url** (remote urls) out of the box, but you may also choose to add your custom providers. You can do this by passing the `customProviders` option when calling the uppy `app` method. The custom provider is expected to support Oauth 1 or 2 for authentication/authorization. +As of now, Uppy Server supports **Google Drive**, **Dropbox**, **Instagram**, and **URL** (remote urls) out of the box, but you may also choose to add your own custom providers. You can do this by passing the `customProviders` option when calling the Uppy `app` method. The custom provider is expected to support Oauth 1 or 2 for authentication/authorization. ```javascript let options = { @@ -293,26 +293,26 @@ let options = { uppy.app(options) ``` -The `customProviders` option should be an object containing each custom provider. Each custom provider would in turn be an object with two keys, `config` and `module`. The `config` option would contain Oauth API settings, while the `module` would point to the provider module. +The `customProviders` option should be an object containing each custom provider. Each custom provider would, in turn, be an object with two keys, `config` and `module`. The `config` option would contain Oauth API settings, while the `module` would point to the provider module. To work well with Uppy Server, the **Module** must be a class with the following methods. -1. `list (options, done)` - lists json data of user files (e.g list of all the files in a particular directory). +1. `list (options, done)` - lists JSON data of user files (e.g. list of all the files in a particular directory). - `options` - is an object containing the following attributes - - token - authorization token(retrieved from oauth process) to send along with your request - - directory - the `id/name` of the directory whose data is to be retrieved. This may be ignored if it doesn't apply to your provider - - query - expressjs query params object received by the server(just in case there's some data you need in there). - - `done (err, response, body)` - the callback that should be called when the request to your provider is done. As the signature indicates the following data should be passed along to the callback `err`, `response`, and `body`. + - token - authorization token (retrieved from oauth process) to send along with your request + - directory - the `id/name` of the directory from which data is to be retrieved. This may be ignored if it doesn't apply to your provider + - query - expressjs query params object received by the server (just in case there is some data you need in there). + - `done (err, response, body)` - the callback that should be called when the request to your provider is made. As the signature indicates, the following data should be passed along to the callback `err`, `response`, and `body`. 2. `download (options, onData, onResponse)` - downloads a particular file from the provider. - - `options` - is an object containing the following attributes - - token - authorization token(retrieved from oauth process) to send along with your request. - - id - id of the file being downloaded. + - `options` - is an object containing the following attributes: + - token - authorization token (retrieved from oauth process) to send along with your request. + - id - ID of the file being downloaded. - `onData (chunk)` - a callback that should be called with each data chunk received on download. This is useful if the size of the downloaded file can be pre-determined. This would allow for pipelined upload of the file (to the desired destination), while the download is still going on. - `onResponse (response)` - if the size of the downloaded file can not be pre-determined by Uppy Server, then this callback should be called in place of the `onData` callback. This callback would be called after the download is done, and would take the downloaded data (response) as the argument. ## Development -1\. To setup Uppy Server for local development, please clone the repo and install like so: +1\. To set up Uppy Server for local development, please clone the repo and install, like so: ```bash git clone https://github.com/transloadit/uppy-server && cd uppy-server && npm install From cb0d1744a7e1a2eed6f65c2fc522fe042a27c5fd Mon Sep 17 00:00:00 2001 From: AJvanLoon Date: Sun, 3 Jun 2018 14:45:00 +0200 Subject: [PATCH 03/21] Some docs polish @arturi --- website/src/docs/stores.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/src/docs/stores.md b/website/src/docs/stores.md index a04921123..196e8ac8f 100644 --- a/website/src/docs/stores.md +++ b/website/src/docs/stores.md @@ -5,7 +5,7 @@ title: "Custom Stores" permalink: docs/stores/ --- -> This section is about storing internal application state, if you work with React/Redux, for example. If none of this rings a bell, you can safely skip this section. +> This section concerns storing the internal application state, if you work with React/Redux, for example. If none of this rings a bell, you can safely skip this section. By default, Uppy stores its internal state in an object. @@ -16,11 +16,11 @@ Uppy comes with two state management solutions (stores): - `DefaultStore`, a simple object-based store. - `ReduxStore`, a store that uses a key in a Redux store. -There are also some third party stores: +There are also some third-party stores: - [uppy-store-ngrx](https://github.com/rimlin/uppy-store-ngrx/), keeping Uppy state in a key in an [Ngrx](https://github.com/ngrx/platform) store for use with Angular. -## Using Stores +## Using stores To use a store, pass an instance to the [`store` option](/docs/uppy#store-defaultstore) in the Uppy constructor: From c6c4503e6fef177f8e98568e81a6092bc2fa373d Mon Sep 17 00:00:00 2001 From: AJvanLoon Date: Sun, 3 Jun 2018 14:54:33 +0200 Subject: [PATCH 04/21] Some docs polish @arturi --- website/src/docs/contributing.md | 37 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/website/src/docs/contributing.md b/website/src/docs/contributing.md index de00951d8..04723815d 100644 --- a/website/src/docs/contributing.md +++ b/website/src/docs/contributing.md @@ -4,7 +4,7 @@ type: docs order: 4 --- -## Uppy Development +## Uppy development Fork the repository into your own account first. See the [GitHub Help](https://help.github.com/articles/fork-a-repo/) article for instructions. @@ -16,7 +16,7 @@ cd uppy npm install ``` -Our website’s examples section is also our playground, please read [Local Previews](#Local-Previews) section to get up and running. +Our website’s examples section is also our playground, please read the [Local Previews](#Local-Previews) section to get up and running. ## Tests @@ -24,7 +24,7 @@ Unit tests are using Jest and can be run with: `npm run test:unit` -For acceptance (or end to end) tests, we use [Webdriverio](http://webdriver.io). For it to run locally, you need to install selenium standalone server, just follow [the guide](http://webdriver.io/guide.html) to do so. You can also install Selenium Standalone server from NPM: +For acceptance (or end-to-end) tests, we use [Webdriverio](http://webdriver.io). For it to run locally, you need to install a Selenium standalone server. Just follow [the guide](http://webdriver.io/guide.html) to do so. You can also install a Selenium standalone server from NPM: ```bash npm install selenium-standalone -g @@ -35,30 +35,31 @@ And then launch it: `selenium-standalone start` -After you’ve installed and launched the selenium standalone server, run: +After you have installed and launched the selenium standalone server, run: `npm run test:acceptance:local` These tests are also run automatically on Travis builds with [SauceLabs](https://saucelabs.com/) cloud service using different OSes. -## Website Development +## Website development -We keep the [uppy.io](http://uppy.io) website in `./website` so it’s easy to keep docs & code in sync as we’re still iterating at high velocity. +We keep the [uppy.io](http://uppy.io) website in `./website`, so it’s easy to keep docs and code in sync as we are still iterating at high velocity. The site is built with [Hexo](http://hexo.io/), and Travis automatically deploys this onto GitHub Pages (it overwrites the `gh-pages` branch with Hexo's build at every change to `master`). The content is written in Markdown and located in `./website/src`. Feel free to fork & hack! -Even though bundled in this repo, the website is regarded as a separate project. So it has its own `package.json` and we aim to keep the surface where the two projects interface as small as possible. `./website/update.js` is called during website builds to inject the Uppy knowledge into the site. +Even though bundled in this repo, the website is regarded as a separate project. As such, it has its own `package.json` and we aim to keep the surface where the two projects interface as small as possible. `./website/update.js` is called during website builds to inject the Uppy knowledge into the site. -### Local Previews +### Local previews -It's recommended to exclude `./website/public/` from your editor if you want efficient searches. +It is recommended to exclude `./website/public/` from your editor if you want efficient searches. To install the required node modules, type: + ```bash npm install && cd website && npm install && cd .. ``` -For local previews on http://127.0.0.1:4000 type: +For local previews on http://127.0.0.1:4000, type: ```bash npm start @@ -66,7 +67,7 @@ npm start This will watch the website, as well as Uppy, as the examples, and rebuild everything and refresh your browser as files change. -Then, to work on e.g. the XHRUpload example, you'd edit the following files: +Then, to work on, for instance, the XHRUpload example, you would edit the following files: ```bash atom src/core/Core.js \ @@ -75,13 +76,13 @@ atom src/core/Core.js \ website/src/examples/xhrupload/app.es6 ``` -And open in your webbrowser. +And open in your web browser. -## CSS Guidelines +## CSS guidelines -The CSS standards followed in this project closely resemble those from [Medium's CSS Guidelines](https://gist.github.com/fat/a47b882eb5f84293c4ed). If it's not mentioned here, follow their guidelines. +The CSS standards followed in this project closely resemble those from [Medium's CSS Guidelines](https://gist.github.com/fat/a47b882eb5f84293c4ed). If something is not mentioned here, follow their guidelines. -### Naming Conventions +### Naming conventions This project uses naming conventions adopted from the SUIT CSS framework. [Read about them here](https://github.com/suitcss/suit/blob/master/doc/naming-conventions.md). @@ -118,7 +119,7 @@ Syntax: [-][-descendentName][--modifierName] ### SASS -This project uses SASS, with some limitations on nesting. One-level deep nesting is allowed, but nesting may not extend a selector by using the `&` operator. For example: +This project uses SASS, with some limitations on nesting. One-level-deep nesting is allowed, but nesting may not extend a selector by using the `&` operator. For example: ```sass /* BAD */ @@ -138,11 +139,11 @@ This project uses SASS, with some limitations on nesting. One-level deep nestin } ``` -### Mobile-first Responsive Approach +### Mobile-first responsive approach Style to the mobile breakpoint with your selectors, then use `min-width` media queries to add any styles to the tablet or desktop breakpoints. -### Selector, Rule Ordering +### Selector, rule ordering - All selectors are sorted alphabetically and by type. - HTML elements go above classes and IDs in a file. From 70e25163b2ffcf3fdd7588d8189759d8cadb9e6d Mon Sep 17 00:00:00 2001 From: AJvanLoon Date: Sun, 3 Jun 2018 15:14:55 +0200 Subject: [PATCH 05/21] Some docs polish @arturi --- website/src/docs/plugins.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/website/src/docs/plugins.md b/website/src/docs/plugins.md index dc4ab54e3..007b91e4e 100644 --- a/website/src/docs/plugins.md +++ b/website/src/docs/plugins.md @@ -8,8 +8,8 @@ order: 10 Plugins are what makes Uppy useful: they help select, manipulate and upload files. - **Acquirers (various ways of picking files):** - - [Dashboard](/docs/dashboard) — full featured sleek UI with file previews, metadata editing, upload/pause/resume/cancel buttons and more. Includes `StatusBar` and `Informer` plugins by default - - [DragDrop](/docs/dragdrop) — plain and simple drag and drop area + - [Dashboard](/docs/dashboard) — full-featured sleek UI with file previews, metadata editing, upload/pause/resume/cancel buttons and more. Includes `StatusBar` and `Informer` plugins by default + - [DragDrop](/docs/dragdrop) — plain and simple drag-and-drop area - [FileInput](/docs/fileinput) — even more plain and simple, just a button - [Webcam](/docs/webcam) — upload selfies or audio / video recordings - [Provider Plugins](/docs/providers) (remote sources that work through [Uppy Server](/docs/uppy-server/)) @@ -27,13 +27,13 @@ Plugins are what makes Uppy useful: they help select, manipulate and upload file - [Informer](/docs/informer) — show notifications - **Helpers:** - [GoldenRetriever](/docs/golden-retriever) — restore files and continue uploading after a page refresh or a browser crash - - [Form](/docs/form) — collect metadata from `
` right before Uppy upload, then optionally append results back to the form + - [Form](/docs/form) — collect metadata from `` right before the Uppy upload, then optionally append results back to the form - **Encoding Services:** - [Transloadit](/docs/transloadit) — manipulate and transcode uploaded files using the [transloadit.com](https://transloadit.com) service -## Common Options +## Common options -Each plugin can have any number of options (please see specific plugin for details), but these are shared between some: +Each plugin can have any number of options (please see specific plugins for details), but these are shared between some: ### `id` @@ -64,11 +64,11 @@ uppy.use(Dashboard, { uppy.use(GoogleDrive, {target: Dashboard}) ``` -In the example above the `Dashboard` gets rendered into an element with ID `uppy`, while `GoogleDrive` is rendered into the `Dashboard` itself. +In the example above, the `Dashboard` gets rendered into an element with ID `uppy`, while `GoogleDrive` is rendered into the `Dashboard` itself. ### `locale: {}` -Same as with Uppy.Core’s setting from above, this allows you to override plugin’s locale string, so that instead of `Select files` in English, your users will see `Выберите файлы` in Russian. Example: +Same as with Uppy.Core’s setting above, this allows you to override plugin’s locale string, so that instead of `Select files` in English, your users will see `Выберите файлы` in Russian. Example: ```js .use(FileInput, { From 4a6b50d578d1af929c00972004c0e9769bac9d2e Mon Sep 17 00:00:00 2001 From: AJvanLoon Date: Sun, 3 Jun 2018 15:37:52 +0200 Subject: [PATCH 06/21] Some docs polish @arturi --- website/src/docs/writing-plugins.md | 31 ++++++++++++++--------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/website/src/docs/writing-plugins.md b/website/src/docs/writing-plugins.md index 274814348..787028b62 100644 --- a/website/src/docs/writing-plugins.md +++ b/website/src/docs/writing-plugins.md @@ -5,16 +5,15 @@ permalink: docs/writing-plugins/ order: 11 --- -There are a few useful Uppy plugins out there, but there might come a time when you’ll want to build your own. -Plugins can hook into the upload process or render a custom UI, typically to: +There are already a few useful Uppy plugins out there, but there might come a time when you will want to build your own. Plugins can hook into the upload process or render a custom UI, typically to: - - Render some custom UI element, e.g. [StatusBar](/docs/statusbar) or [Dashboard](/docs/dashboard). - - Do the actual uploading, e.g. [XHRUpload](/docs/xhrupload) or [Tus](/docs/tus). - - Interact with a third party service to process uploads correctly, e.g. [Transloadit](/docs/transloadit) or [AwsS3](/docs/aws-s3). + - Render some custom UI element, e.g., [StatusBar](/docs/statusbar) or [Dashboard](/docs/dashboard). + - Do the actual uploading, e.g., [XHRUpload](/docs/xhrupload) or [Tus](/docs/tus). + - Interact with a third-party service to process uploads correctly, e.g., [Transloadit](/docs/transloadit) or [AwsS3](/docs/aws-s3). ## Creating A Plugin -Plugins are classes that extend from Uppy's `Plugin` class. Each plugin has an `id` and a `type`. `id`s are used to uniquely identify plugins. A `type` can be anything—some plugins use `type`s to determine whether to do something to some other plugin. For example, when targeting plugins at the builtin `Dashboard` plugin, the Dashboard uses the `type` to figure out where to mount different UI elements. `'acquirer'` type plugins are mounted into the tab bar, while `'progressindicator'` type plugins are mounted into the progress bar area. +Plugins are classes that extend from Uppy's `Plugin` class. Each plugin has an `id` and a `type`. `id`s are used to uniquely identify plugins. A `type` can be anything—some plugins use `type`s to determine whether to do something to some other plugin. For example, when targeting plugins at the built-in `Dashboard` plugin, the Dashboard uses the `type` to figure out where to mount different UI elements. `'acquirer'`-type plugins are mounted into the tab bar, while `'progressindicator'`-type plugins are mounted into the progress bar area. The plugin constructor receives the Uppy instance in the first parameter, and any options passed to `uppy.use()` in the second parameter. @@ -59,17 +58,17 @@ uninstall () { ### `update(state)` -Called on each state update. It's rare that you'd need to use this, it's mostly handy if you want to build a UI plugin using something other than preact. +Called on each state update. You will rarely need to use this, it is mostly handy if you want to build a UI plugin using something other than Preact. ## Upload Hooks -When creating an upload, Uppy runs files through an upload pipeline. The pipeline consists of three parts, each of which can be hooked into: Preprocessing, Uploading, and Postprocessing. Preprocessors can be used to configure uploader plugins, encrypt files, resize images, etc., before uploading them. Uploaders do the actual uploading work, such as creating an XMLHttpRequest object and sending the file. Postprocessors do work after files have been uploaded completely. This could be anything from waiting for a file to propagate across a CDN, to sending another request to relate some metadata to the file. +When creating an upload, Uppy runs files through an upload pipeline. The pipeline consists of three parts, each of which can be hooked into: Preprocessing, Uploading, and Postprocessing. Preprocessors can be used to configure uploader plugins, encrypt files, resize images, etc., before uploading them. Uploaders do the actual uploading work, such as creating an XMLHttpRequest object and sending the file. Postprocessors do their work after files have been uploaded completely. This could be anything from waiting for a file to propagate across a CDN, to sending another request to relate some metadata to the file. Each hook is a function that receives an array containing the file IDs that are being uploaded, and returns a Promise to signal completion. Hooks are added and removed through `Uppy` methods: `addPreProcessor`, `addUploader`, `addPostProcessor`, and their `remove*` counterparts. Normally, hooks should be added during the plugin's `install()` method, and removed during the `uninstall()` method. Additionally, upload hooks can fire events to signal progress. -When adding hooks, make sure to bind the hook `fn` beforehand! Otherwise it will be impossible to remove. For example: +When adding hooks, make sure to bind the hook `fn` beforehand! Otherwise, it will be impossible to remove. For example: ```js class MyPlugin extends Plugin { @@ -102,7 +101,7 @@ Add a preprocessing function. `fn` gets called with a list of file IDs before an Add an uploader function. `fn` gets called with a list of file IDs when an upload should start. Uploader functions should do the actual uploading work, such as creating and sending an XMLHttpRequest or calling into some upload service's SDK. `fn` should return a Promise that resolves once all files have been uploaded. -You may choose to still resolve the Promise if some file uploads fail. This way any postprocessing will still run on the files that were uploaded successfully, while uploads that failed will be retried when `uppy.retryAll` is called. +You may choose to still resolve the Promise if some file uploads fail. This way, any postprocessing will still run on the files that were uploaded successfully, while uploads that failed will be retried when `uppy.retryAll` is called. ### `addPostProcessor(fn)` @@ -110,13 +109,13 @@ Add a postprocessing function. `fn` is called with a list of file IDs when an up ### `removePreProcessor/removeUploader/removePostProcessor(fn)` -Remove a processor or uploader function that was added previously. Normally this should be done in the `uninstall()` method. +Remove a processor or uploader function that was added previously. Normally, this should be done in the `uninstall()` method. -## Progress Events +## Progress events Progress events can be fired for individual files to show feedback to the user. For upload progress events, only emitting how many bytes are expected and how many have been uploaded is enough. Uppy will handle calculating progress percentages, upload speed, etc. -Preprocessing and postprocessing progress events are plugin-dependent and can refer to anything, so Uppy doesn't try to be smart about them. There are two types of processing progress events: determinate and indeterminate. Some processing does not have meaningful progress beyond "not done" and "done". For example, sending a request to initialize a server-side resource that will be uploaded to. In those situations, indeterminate progress is suitable. Other processing does have meaningful progress. For example, encrypting a large file. In those situations, determinate progress is suitable. +Preprocessing and postprocessing progress events are plugin-dependent and can refer to anything, so Uppy doesn't try to be smart about them. There are two types of processing progress events: determinate and indeterminate. Some processing does not have meaningful progress beyond "not done" and "done". For example, sending a request to initialize a server-side resource that will serve as the upload destination. In those situations, indeterminate progress is suitable. Other processing does have meaningful progress. For example, encrypting a large file. In those situations, determinate progress is suitable. ### `preprocess-progress(fileID, progress)` @@ -163,14 +162,14 @@ This method can be overridden to support for different render engines. ### `render()` -Render this plugin's UI. Uppy uses [preact](https://preactjs.com) as its view engine, so `render()` should return a preact element. +Render this plugin's UI. Uppy uses [Preact](https://preactjs.com) as its view engine, so `render()` should return a Preact element. `render` is automatically called by Uppy on each state change. -Note that we are looking into ways to make Uppy render engine agnostic, so that plugins can choose their own favourite library—whether it's preact, choo, jQuery, or anything else. This means that the `render()` API may change in the future, but we'll detail exactly what you need to do on the [blog](https://uppy.io/blog) if and when that happens. +Note that we are looking into ways to make Uppy's render engine agnostic, so that plugins can choose their own favourite library—whether it's Preact, Choo, jQuery, or anything else. This means that the `render()` API may change in the future, but we will detail exactly what you need to do on the [blog](https://uppy.io/blog) if and when that happens. ### JSX -Since Uppy uses Preact and not React, the default Babel configuration for JSX elements does not work. You have to import the preact `h` function and tell Babel to use it by adding a `/** @jsx h */` comment at the top of the file. +Since Uppy uses Preact and not React, the default Babel configuration for JSX elements does not work. You have to import the Preact `h` function and tell Babel to use it by adding a `/** @jsx h */` comment at the top of the file. See the Preact [Getting Started Guide](https://preactjs.com/guide/getting-started) for more on Babel and JSX. From a75aa30663771e3043655ac7de1bdd886cc92789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Mon, 4 Jun 2018 10:35:37 +0200 Subject: [PATCH 07/21] Fix plugin IDs in Dashboard.uninstall(), closes #881 --- src/plugins/Dashboard/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/Dashboard/index.js b/src/plugins/Dashboard/index.js index 9434edabb..b959dce69 100644 --- a/src/plugins/Dashboard/index.js +++ b/src/plugins/Dashboard/index.js @@ -593,19 +593,19 @@ module.exports = class Dashboard extends Plugin { uninstall () { if (!this.opts.disableInformer) { - const informer = this.uppy.getPlugin('Informer') + const informer = this.uppy.getPlugin(`${this.id}:Informer`) // Checking if this plugin exists, in case it was removed by uppy-core // before the Dashboard was. if (informer) this.uppy.removePlugin(informer) } if (!this.opts.disableStatusBar) { - const statusBar = this.uppy.getPlugin('StatusBar') + const statusBar = this.uppy.getPlugin(`${this.id}:StatusBar`) if (statusBar) this.uppy.removePlugin(statusBar) } if (!this.opts.disableThumbnailGenerator) { - const thumbnail = this.uppy.getPlugin('ThumbnailGenerator') + const thumbnail = this.uppy.getPlugin(`${this.id}:ThumbnailGenerator`) if (thumbnail) this.uppy.removePlugin(thumbnail) } From 4a15e4c30bfd8f816e27fabb3faf641ce986398e Mon Sep 17 00:00:00 2001 From: Kevin van Zonneveld Date: Mon, 4 Jun 2018 10:46:04 +0200 Subject: [PATCH 08/21] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e71c530d..d7f4ab9ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,9 @@ PRs are welcome! Please do open an issue to discuss first if it's a big feature, What we need to do to release Uppy 1.0 - [ ] website: big release blog post +- [ ] chore: hunt down all `@TODO`s and either fix, or remove, or move to github issues/changelog backlog +- [ ] chore: remove dead code/commented blocks +- [ ] chore: rewrite all code based on prettier+standardjs.com - [ ] ~refactoring: Make `uppy-server` module live in main Uppy repo in `./server` as a second stage todo (after Lerna is done and we're happy) (@ife) - [ ] QA: manually test in multiple browsers and mobile devices again (SauceLabs can do Android/iOS too) (@nqst) - [ ] QA: add one integration test that uses a Webpack and React/Redux environment (e.g. via `create-react-app`) (@goto-bus-stop) From 3c9cf4b16a1a0f30c62c730f4c8f5a4e45e62dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Mon, 4 Jun 2018 11:32:56 +0200 Subject: [PATCH 09/21] Fix invisible identifiers in class declarations. --- website/themes/uppy/source/css/_syntax.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/themes/uppy/source/css/_syntax.scss b/website/themes/uppy/source/css/_syntax.scss index d7fe4a7ae..054c4181b 100644 --- a/website/themes/uppy/source/css/_syntax.scss +++ b/website/themes/uppy/source/css/_syntax.scss @@ -37,7 +37,7 @@ pre { } .class .title { - color: white; + color: #2973b7; } .symbol, From 9eaaf7e4c6afeb812f84762a8221d61af99252f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Mon, 4 Jun 2018 13:04:59 +0200 Subject: [PATCH 10/21] Switch to prismjs for highlighting. --- website/_config.yml | 9 +- website/package-lock.json | 59 +++++++++++ website/package.json | 2 + website/scripts/highlight.js | 68 +++++++++++++ website/themes/uppy/source/css/_syntax.scss | 107 +++----------------- 5 files changed, 148 insertions(+), 97 deletions(-) create mode 100644 website/scripts/highlight.js diff --git a/website/_config.yml b/website/_config.yml index c476665a8..63c0c4ae6 100644 --- a/website/_config.yml +++ b/website/_config.yml @@ -51,9 +51,7 @@ filename_case: 0 render_drafts: false post_asset_folder: false highlight: - enable: true - line_number: false - tab_replace: + enable: false # Category & Tag default_category: uncategorized @@ -114,6 +112,11 @@ marked: # modifyAnchors: 1 autolink: true +prism_plugin: + mode: 'preprocess' + theme: 'tomorrow' + line_number: false + feed: type: atom path: atom.xml diff --git a/website/package-lock.json b/website/package-lock.json index cfeb4bc2a..c237ae196 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -2860,6 +2860,17 @@ "restore-cursor": "^1.0.1" } }, + "clipboard": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-1.7.1.tgz", + "integrity": "sha1-Ng1taUbpmnof7zleQrqStem1oWs=", + "optional": true, + "requires": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, "cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", @@ -3508,6 +3519,12 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", + "optional": true + }, "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -5737,6 +5754,15 @@ } } }, + "good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", + "optional": true, + "requires": { + "delegate": "^3.1.2" + } + }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", @@ -5878,6 +5904,11 @@ "sntp": "1.x.x" } }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" + }, "header-case": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz", @@ -7951,6 +7982,14 @@ "which": "^1.3.0" } }, + "node-prismjs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/node-prismjs/-/node-prismjs-0.1.1.tgz", + "integrity": "sha512-7TrcjtiF9XFemrdZ9sMliEkOx4IzRWspZGu938YF+9crjfxwaLhlbRpY9ulvxfVJr6ZrEuZ/HvN/uz5LJvSafQ==", + "requires": { + "prismjs": "~1.6.0" + } + }, "node-sass": { "version": "4.9.0", "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.0.tgz", @@ -9708,6 +9747,14 @@ "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=" }, + "prismjs": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.6.0.tgz", + "integrity": "sha1-EY2V+3pm26InLjQ7NF9SNmWds2U=", + "requires": { + "clipboard": "^1.5.5" + } + }, "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", @@ -10419,6 +10466,12 @@ } } }, + "select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=", + "optional": true + }, "semver": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", @@ -11232,6 +11285,12 @@ "process": "~0.11.0" } }, + "tiny-emitter": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.0.2.tgz", + "integrity": "sha512-2NM0auVBGft5tee/OxP4PI3d8WItkDM+fPnaRAVo6xTDI2knbz9eC5ArWGqtGlYqiH3RU5yMpdyTTO7MguC4ow==", + "optional": true + }, "tiny-lr": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-0.2.1.tgz", diff --git a/website/package.json b/website/package.json index f32e0377e..6021fb4f3 100644 --- a/website/package.json +++ b/website/package.json @@ -8,6 +8,7 @@ "dependencies": { "autoprefixer": "^7.2.6", "cssnano": "^3.10.0", + "he": "^1.1.1", "hexo": "^3.7.1", "hexo-browsersync": "^0.3.0", "hexo-deployer-git": "^0.3.1", @@ -26,6 +27,7 @@ "hexo-util": "^0.6.3", "js-yaml": "^3.11.0", "mkdirp": "0.5.1", + "node-prismjs": "^0.1.1", "postcss-inline-svg": "^3.1.1" }, "devDependencies": { diff --git a/website/scripts/highlight.js b/website/scripts/highlight.js new file mode 100644 index 000000000..e51f0901b --- /dev/null +++ b/website/scripts/highlight.js @@ -0,0 +1,68 @@ +/* global hexo */ +const Prism = require('node-prismjs') +const { decode } = require('he') +const { promisify } = require('util') +const readFile = promisify(require('fs').readFile) +const path = require('path') + +const regex = /
([\s\S]*?)<\/code><\/pre>/igm
+const captionRegex = /

(?![\s\S]*<\/p>/igm + +/** + * Code transform for prism plugin. + * @param {Object} data + * @return {Object} + */ +function prismify (data) { + // Patch for caption support + if (captionRegex.test(data.content)) { + // Attempt to parse the code + data.content = data.content.replace(captionRegex, (origin, lang, caption, code) => { + if (!lang || !caption || !code) return origin + return `

${caption}
${code}
` + }) + } + + function replace (lang, code) { + const startTag = `
`
+    const endTag = `
` + code = decode(code) + let parsedCode = '' + if (Prism.languages[lang]) { + parsedCode = Prism.highlight(code, Prism.languages[lang]) + } else { + parsedCode = code + } + + return startTag + parsedCode + endTag + } + + data.content = data.content.replace(regex, (origin, lang, code) => replace(lang, code)) + + return data +} + +function code (args, content) { + let lang = '' + if (args[0].startsWith('lang:')) { + lang = args.shift().replace(/^lang:/, '') + } + + return `
${content}
` +} + +function includeCode (args) { + let lang = '' + if (args[0].startsWith('lang:')) { + lang = args.shift().replace(/^lang:/, '') + } + + const file = path.join(hexo.source_dir, hexo.config.code_dir, args.join(' ')) + return readFile(file, 'utf8') + .then((code) => code.trim()) + .then((code) => `
${code}
`) +} + +hexo.extend.filter.register('after_post_render', prismify) +hexo.extend.tag.register('codeblock', code, true) +hexo.extend.tag.register('include_code', includeCode, { async: true }) diff --git a/website/themes/uppy/source/css/_syntax.scss b/website/themes/uppy/source/css/_syntax.scss index 054c4181b..48deb1c0f 100644 --- a/website/themes/uppy/source/css/_syntax.scss +++ b/website/themes/uppy/source/css/_syntax.scss @@ -4,101 +4,20 @@ pre { color: #525252; + // background-color: #f8f8f8 !important; + // font-size: .8em !important; + // .token.function, .token.punctuation { color: inherit; } - .function .keyword, - .constant { - color: #0092db; - } + // Generic + .token.comment { color: #b3b3b3; } - .line { - min-height: 1em; - } - - .keyword, - .attribute { - color: #e96900; - } - - .number, - .literal { - color: #AE81FF; - } - - .tag, - .tag .title, - .change, - .winutils, - .flow, - .lisp .title, - .clojure .built_in, - .nginx .title, - .tex .special { - color: #2973b7; - } - - .class .title { - color: #2973b7; - } - - .symbol, - .symbol .string, - .value, - .regexp { - color: $color-green; - } - - .title { - color: #A6E22E; - } - - .tag .value, - .string, - .subst, - .haskell .type, - .preprocessor, - .ruby .class .parent, - .built_in, - .sql .aggregate, - .django .template_tag, - .django .variable, - .smalltalk .class, - .javadoc, - .django .filter .argument, - .smalltalk .localvars, - .smalltalk .array, - .attr_selector, - .pseudo, - .addition, - .stream, - .envvar, - .apache .tag, - .apache .cbracket, - .tex .command, - .prompt { - color: $color-green; - } - - .comment, - .java .annotation, - .python .decorator, - .template_comment, - .pi, - .doctype, - .deletion, - .shebang, - .apache .sqbracket, - .tex .formula { - color: #b3b3b3; - } - - .coffeescript .javascript, - .javascript .xml, - .tex .formula, - .xml .javascript, - .xml .vbscript, - .xml .css, - .xml .cdata { - opacity: 0.5 - } + // JS + .token.keyword { color: #e96900; } + .token.number, .token.boolean { color: #AE81FF; } + .token.class-name { color: #2973b7; } + .token.string { color: $color-green; } + // HTML + .token.tag { color: #2973b7; } + .token.attr-value { color: $color-green; } } From 2425d339c60ba4b421df6d9c794c1475d1ddbcc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Mon, 4 Jun 2018 13:41:29 +0200 Subject: [PATCH 11/21] robustify --- website/_config.yml | 1 + website/scripts/highlight.js | 64 +++++++++++++++--------------------- 2 files changed, 28 insertions(+), 37 deletions(-) diff --git a/website/_config.yml b/website/_config.yml index 63c0c4ae6..cd41eccd0 100644 --- a/website/_config.yml +++ b/website/_config.yml @@ -52,6 +52,7 @@ render_drafts: false post_asset_folder: false highlight: enable: false + line_number: false # Category & Tag default_category: uncategorized diff --git a/website/scripts/highlight.js b/website/scripts/highlight.js index e51f0901b..c7839e1d7 100644 --- a/website/scripts/highlight.js +++ b/website/scripts/highlight.js @@ -1,43 +1,28 @@ /* global hexo */ const Prism = require('node-prismjs') -const { decode } = require('he') +const entities = require('he') const { promisify } = require('util') const readFile = promisify(require('fs').readFile) const path = require('path') -const regex = /
([\s\S]*?)<\/code><\/pre>/igm
-const captionRegex = /

(?![\s\S]*<\/p>/igm +const unhighlightedCodeRx = /

([\s\S]*?)<\/code><\/pre>/igm
+
+function highlight (lang, code) {
+  const startTag = `
`
+  const endTag = `
` + let parsedCode = '' + if (Prism.languages[lang]) { + parsedCode = Prism.highlight(code, Prism.languages[lang]) + } else { + parsedCode = code + } + + return startTag + parsedCode + endTag +} -/** - * Code transform for prism plugin. - * @param {Object} data - * @return {Object} - */ function prismify (data) { - // Patch for caption support - if (captionRegex.test(data.content)) { - // Attempt to parse the code - data.content = data.content.replace(captionRegex, (origin, lang, caption, code) => { - if (!lang || !caption || !code) return origin - return `
${caption}
${code}
` - }) - } - - function replace (lang, code) { - const startTag = `
`
-    const endTag = `
` - code = decode(code) - let parsedCode = '' - if (Prism.languages[lang]) { - parsedCode = Prism.highlight(code, Prism.languages[lang]) - } else { - parsedCode = code - } - - return startTag + parsedCode + endTag - } - - data.content = data.content.replace(regex, (origin, lang, code) => replace(lang, code)) + data.content = data.content.replace(unhighlightedCodeRx, + (_, lang, code) => highlight(lang, entities.decode(code))) return data } @@ -48,7 +33,7 @@ function code (args, content) { lang = args.shift().replace(/^lang:/, '') } - return `
${content}
` + return highlight(lang, content) } function includeCode (args) { @@ -58,11 +43,16 @@ function includeCode (args) { } const file = path.join(hexo.source_dir, hexo.config.code_dir, args.join(' ')) - return readFile(file, 'utf8') - .then((code) => code.trim()) - .then((code) => `
${code}
`) + return readFile(file, 'utf8').then((code) => highlight(lang, code.trim())) } -hexo.extend.filter.register('after_post_render', prismify) +// Highlight as many things as we possibly can +hexo.extend.tag.register('code', code, true) hexo.extend.tag.register('codeblock', code, true) hexo.extend.tag.register('include_code', includeCode, { async: true }) +hexo.extend.tag.register('include-code', includeCode, { async: true }) + +// Hexo includes its own code block handling by default which may +// cause the above to miss some things, so do another pass when the page +// is done rendering to pick up any code blocks we may have missed. +hexo.extend.filter.register('after_post_render', prismify) From 5c7a23cc656556be087b81baad50b91863ac32be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Mon, 4 Jun 2018 13:42:12 +0200 Subject: [PATCH 12/21] Include custom hexo scripts in lint. --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 9d875ebfd..ea2cae7ed 100644 --- a/package.json +++ b/package.json @@ -134,8 +134,8 @@ "build:lib": "babel --version && babel src --source-maps -d lib", "build": "npm-run-all --parallel build:js build:css --serial build:gzip size", "clean": "rm -rf lib && rm -rf dist", - "lint:fix": "eslint src test website/build-examples.js website/update.js website/themes/uppy/source/js/common.js --fix", - "lint": "eslint src test website/build-examples.js website/update.js website/themes/uppy/source/js/common.js", + "lint:fix": "eslint src test website/scripts website/build-examples.js website/update.js website/themes/uppy/source/js/common.js --fix", + "lint": "eslint src test website/scripts website/build-examples.js website/update.js website/themes/uppy/source/js/common.js", "lint-staged": "lint-staged", "release:major": "env SEMANTIC=major npm run release", "release:minor": "env SEMANTIC=minor npm run release", From 5c32a26c64815ddf8202a5655d9cb5a0b1d7ec41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Mon, 4 Jun 2018 13:51:12 +0200 Subject: [PATCH 13/21] Use prismjs directly. --- website/package-lock.json | 22 +++++++--------------- website/package.json | 4 ++-- website/scripts/highlight.js | 2 +- 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/website/package-lock.json b/website/package-lock.json index c237ae196..e318132a8 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -2861,9 +2861,9 @@ } }, "clipboard": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-1.7.1.tgz", - "integrity": "sha1-Ng1taUbpmnof7zleQrqStem1oWs=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.1.tgz", + "integrity": "sha512-7yhQBmtN+uYZmfRjjVjKa0dZdWuabzpSKGtyQZN+9C8xlC788SSJjOHWh7tzurfwTqTD5UDYAhIv5fRJg3sHjQ==", "optional": true, "requires": { "good-listener": "^1.2.2", @@ -7982,14 +7982,6 @@ "which": "^1.3.0" } }, - "node-prismjs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/node-prismjs/-/node-prismjs-0.1.1.tgz", - "integrity": "sha512-7TrcjtiF9XFemrdZ9sMliEkOx4IzRWspZGu938YF+9crjfxwaLhlbRpY9ulvxfVJr6ZrEuZ/HvN/uz5LJvSafQ==", - "requires": { - "prismjs": "~1.6.0" - } - }, "node-sass": { "version": "4.9.0", "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.0.tgz", @@ -9748,11 +9740,11 @@ "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=" }, "prismjs": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.6.0.tgz", - "integrity": "sha1-EY2V+3pm26InLjQ7NF9SNmWds2U=", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.14.0.tgz", + "integrity": "sha512-sa2s4m60bXs+kU3jcuUwx3ZCrUH7o0kuqnOOINbODqlRrDB7KY8SRx+xR/D7nHLlgfDdG7zXbRO8wJ+su5Ls0A==", "requires": { - "clipboard": "^1.5.5" + "clipboard": "^2.0.0" } }, "private": { diff --git a/website/package.json b/website/package.json index 6021fb4f3..e9245eddf 100644 --- a/website/package.json +++ b/website/package.json @@ -27,8 +27,8 @@ "hexo-util": "^0.6.3", "js-yaml": "^3.11.0", "mkdirp": "0.5.1", - "node-prismjs": "^0.1.1", - "postcss-inline-svg": "^3.1.1" + "postcss-inline-svg": "^3.1.1", + "prismjs": "^1.14.0" }, "devDependencies": { "aliasify": "^2.1.0", diff --git a/website/scripts/highlight.js b/website/scripts/highlight.js index c7839e1d7..bde2bc694 100644 --- a/website/scripts/highlight.js +++ b/website/scripts/highlight.js @@ -1,5 +1,5 @@ /* global hexo */ -const Prism = require('node-prismjs') +const Prism = require('prismjs') const entities = require('he') const { promisify } = require('util') const readFile = promisify(require('fs').readFile) From 5b0b496207f89660112bbef08f9f25e4da34cc40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Mon, 4 Jun 2018 13:52:48 +0200 Subject: [PATCH 14/21] Remove hexo-prism-plugin config. --- website/_config.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/website/_config.yml b/website/_config.yml index cd41eccd0..7ccf27d1f 100644 --- a/website/_config.yml +++ b/website/_config.yml @@ -113,11 +113,6 @@ marked: # modifyAnchors: 1 autolink: true -prism_plugin: - mode: 'preprocess' - theme: 'tomorrow' - line_number: false - feed: type: atom path: atom.xml From 71128bef071f29240093245c70b37329204b48ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Mon, 4 Jun 2018 14:06:08 +0200 Subject: [PATCH 15/21] Regenerate frontpage code sample. --- .../{api-usage-example.ejs => api-usage-example.js} | 2 +- website/src/frontpage-code-sample.ejs | 2 +- .../uppy/layout/partials/frontpage-code-sample.html | 13 +++++++++++-- 3 files changed, 13 insertions(+), 4 deletions(-) rename website/src/{api-usage-example.ejs => api-usage-example.js} (99%) diff --git a/website/src/api-usage-example.ejs b/website/src/api-usage-example.js similarity index 99% rename from website/src/api-usage-example.ejs rename to website/src/api-usage-example.js index 562b54a16..8a2a1ef7d 100644 --- a/website/src/api-usage-example.ejs +++ b/website/src/api-usage-example.js @@ -1,7 +1,7 @@ import Uppy from 'uppy/lib/core' import Dashboard from 'uppy/lib/plugins/Dashboard' import Tus from 'uppy/lib/plugins/Tus' -  + Uppy({ autoProceed: false }) .use(Dashboard, { trigger: '#select-files' }) .use(Tus, { endpoint: 'https://master.tus.io/files/' }) diff --git a/website/src/frontpage-code-sample.ejs b/website/src/frontpage-code-sample.ejs index 4b4be5e30..ffb600527 100644 --- a/website/src/frontpage-code-sample.ejs +++ b/website/src/frontpage-code-sample.ejs @@ -9,4 +9,4 @@ save it as a layout partial $ npm install uppy {% endcodeblock %} -{% include_code lang:js ../api-usage-example.ejs %} +{% include_code lang:js ../api-usage-example.js %} diff --git a/website/themes/uppy/layout/partials/frontpage-code-sample.html b/website/themes/uppy/layout/partials/frontpage-code-sample.html index 4ffe3f7de..b7925e1a9 100644 --- a/website/themes/uppy/layout/partials/frontpage-code-sample.html +++ b/website/themes/uppy/layout/partials/frontpage-code-sample.html @@ -2,6 +2,15 @@ You can `npm run web:update:frontpage:code:sample` to render this code snippet and save it as a layout partial --> -
$ npm install uppy
+
$ npm install uppy
-
api-usage-example.ejsview raw
import Uppy from 'uppy/lib/core'
import Dashboard from 'uppy/lib/plugins/Dashboard'
import Tus from 'uppy/lib/plugins/Tus'
 
Uppy({ autoProceed: false })
.use(Dashboard, { trigger: '#select-files' })
.use(Tus, { endpoint: 'https://master.tus.io/files/' })
.run()
.on('complete', (result) => {
console.log('Upload result:', result)
})
+
import Uppy from 'uppy/lib/core'
+import Dashboard from 'uppy/lib/plugins/Dashboard'
+import Tus from 'uppy/lib/plugins/Tus'
+ 
+Uppy({ autoProceed: false })
+  .use(Dashboard, { trigger: '#select-files' })
+  .use(Tus, { endpoint: 'https://master.tus.io/files/' })
+  .on('complete', (result) => {
+    console.log('Upload result:', result)
+  })
From 8aaebafc2d9156735547fe1a3ecd876ae4cb1a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Mon, 4 Jun 2018 14:45:11 +0200 Subject: [PATCH 16/21] Tolerate trailing slashes in `host` options. As seen in #879, having a trailing slash in a `host` option breaks providers: ```js // does not work: does requests like https://server.uppy.io//drive/list uppy.use(GoogleDrive, { host: 'https://server.uppy.io/' }) ``` This patch strips the trailing slash if it exists so we can always safely append `/drive/list` and get a well formed URL back. --- src/server/RequestClient.js | 7 ++++++- src/server/RequestClient.test.js | 12 ++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 src/server/RequestClient.test.js diff --git a/src/server/RequestClient.js b/src/server/RequestClient.js index 013a3de0e..95788b7b2 100644 --- a/src/server/RequestClient.js +++ b/src/server/RequestClient.js @@ -2,6 +2,11 @@ require('whatwg-fetch') +// Remove the trailing slash so we can always safely append /xyz. +function stripSlash (url) { + return url.replace(/\/$/, '') +} + module.exports = class RequestClient { constructor (uppy, opts) { this.uppy = uppy @@ -12,7 +17,7 @@ module.exports = class RequestClient { get hostname () { const { uppyServer } = this.uppy.getState() const host = this.opts.host - return uppyServer && uppyServer[host] ? uppyServer[host] : host + return stripSlash(uppyServer && uppyServer[host] ? uppyServer[host] : host) } get defaultHeaders () { diff --git a/src/server/RequestClient.test.js b/src/server/RequestClient.test.js new file mode 100644 index 000000000..6c07151fd --- /dev/null +++ b/src/server/RequestClient.test.js @@ -0,0 +1,12 @@ +const RequestClient = require('./RequestClient') + +describe('RequestClient', () => { + it('has a hostname without trailing slash', () => { + const mockCore = { getState: () => ({}) } + const a = new RequestClient(mockCore, { host: 'http://server.uppy.io' }) + const b = new RequestClient(mockCore, { host: 'http://server.uppy.io/' }) + + expect(a.hostname).toBe('http://server.uppy.io') + expect(b.hostname).toBe('http://server.uppy.io') + }) +}) From 33b1b02631f8963d602971d8293c19d89518890e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Mon, 4 Jun 2018 15:06:16 +0200 Subject: [PATCH 17/21] Fix language string in i18n example. --- website/src/examples/i18n/app.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/src/examples/i18n/app.html b/website/src/examples/i18n/app.html index a8602d6ef..52194a807 100644 --- a/website/src/examples/i18n/app.html +++ b/website/src/examples/i18n/app.html @@ -1,10 +1,10 @@ -
-