Procházet zdrojové kódy

Update website API docs and readme

Artur Paikin před 8 roky
rodič
revize
f45c3157c2

+ 5 - 6
README.md

@@ -35,8 +35,8 @@ Check out [uppy.io](http://uppy.io/) for docs, API, examples and stats.
 ### Installing from NPM
 
 It’s easy to start using Uppy, we recommend installing from npm:
-```
-npm install uppy --save
+``` bash
+$ npm install uppy --save
 ```
 
 and then use a bundler like Browserify or Webpack:
@@ -57,7 +57,7 @@ or
 ``` javascript
 // ES5
 // warning: bundling with `require` will currently include the whole Uppy package, with all plugins.
-// If you want to pick and choose, use `import`)
+// If you want to pick and choose, use `import`
 var Uppy = require('uppy')
 
 var uppy = new Uppy.Core({wait: false})
@@ -69,7 +69,7 @@ var files = uppy
 
 Add CSS [uppy.min.css](https://unpkg.com/uppy/dist/uppy.min.css), either to `head` of your HTML or include in JS, if your bundler of choice supports it — transforms and plugins are available for Browserify and Webpack.
 
-Give it a spin on RequireBin: http://requirebin.com/?gist=54e076cccc929cc567cb0aba38815105
+Give Uppy a spin [on RequireBin](http://requirebin.com/?gist=54e076cccc929cc567cb0aba38815105).
 
 ### Installing from CDN
 
@@ -92,7 +92,7 @@ But if you like, you can also use a pre-built bundle, for example from [unpkg CD
 <script>
   var uppy = new Uppy.Core({locales: Uppy.locales.ru_RU, debug: true})
   uppy.use(Uppy.DragDrop, {target: '.UppyDragDrop'})
-  uppy.use(Uppy.Tus10, {endpoint: 'http://master.tus.io:3020/files/'})
+  uppy.use(Uppy.Tus10, {endpoint: '//tusd.tus.io/files/'})
   uppy.run()
 </script>
 ```
@@ -130,7 +130,6 @@ uppy.on('core:success', (fileCount) => {
 })
 ```
 
-
 ## Browser Support
 
 <a href="https://saucelabs.com/u/transloadit-uppy">

+ 3 - 3
src/scss/_dashboard.scss

@@ -326,8 +326,8 @@
 
 .UppyDashboard-dropFilesTitle {
   text-align: center;
-  font-size: 19px;
-  line-height: 1.4;
+  font-size: 18px;
+  line-height: 1.45;
   font-weight: normal;
   color: $color-asphalt-gray;
   margin: 0;
@@ -335,7 +335,7 @@
 
   .UppyDashboard-bgIcon .UppyIcon {
     width: 100%;
-    margin-bottom: 25px;
+    margin-bottom: 35px;
     fill: $color-asphalt-gray;
   }
 

+ 12 - 0
website/src/api-usage-example.ejs

@@ -0,0 +1,12 @@
+import { Core, DragDrop, ProgressBar, Tus10 } from 'uppy'
+
+const uppy = new Core({wait: false})
+uppy
+  .use(DragDrop, {target: '#drop-target'})
+  .use(ProgressBar, {target: 'body'})
+  .use(Tus10, {endpoint: '//tusd.tus.io/files'})
+  .run()
+
+uppy.on('core:success', (fileCount) => {
+  console.log(`Upload complete. We uploaded ${fileCount} files!`)
+})

+ 124 - 51
website/src/api/architecture.md

@@ -2,75 +2,148 @@
 type: api
 order: 0
 title: "Architecture"
-permalink: api/
+permalink: api/architecture
 ---
 
-*Work in progress, API not stable. Last update: 2015-12-03*
+Uppy has a lean [Core](https://github.com/transloadit/uppy/blob/master/src/core/Core.js) module and [Plugins](https://github.com/transloadit/uppy/tree/master/src/plugins) (see simple [Input](https://github.com/transloadit/uppy/blob/master/src/plugins/Formtag.js) as an example) that extend its functionality. Here’s how it’s currently used:
 
-### The Gist
+{% include_code lang:js ../api-usage-example.ejs %}
 
-``` javascript
-import Uppy from './src/core';
-import { DragDrop, Tus10 } from './src/plugins';
-
-const uppy = new Uppy({wait: false});
-const files = uppy
-  .use(DragDrop, {selector: '#upload-target'})
-  .use(Tus10, {endpoint: 'http://master.tus.io:8080'})
-  .run();
-```
+## Core
+
+Core module orchestrates everything in Uppy. Plugins are added to it via `.use(Plugin, opts)` API, like `.use(DragDrop, {target: 'body'})`. Core instantiates plugins with `new Plugin(this, opts)`, passing options to them, then places them in `plugins` object, nested by type: `uploader`, `progressindicator`, `acquirer`, etc.
+
+Core then iterates over `plugins` object and calls `install` on each plugin. In its `install`
+method a plugin can extend global state with its state, set event listeners to react to events happening in Uppy (upload progress, file has been removed), or do anything else needed on init.
+
+Each time `state` is updated with `setState(stateAddition)`, Core runs `updateAll()` that re-renders all of the plugins (components) that have been mounted in the dom somewhere, using the new state.
+
+Core is very lean (at least should be), and acts as a glue that ties together all the plugins, shared data and functionality together. It keeps `state` with `files`, `capabilities`, plus exposes a few methods that are called by plugins to update state — adding files, adding preview Thumbnails to images, updating progress for each file and total progress, etc.
+
+*Comment: There is a discussion that these methods could in theory all live in Utils or be standalone modules used by plugins and the user directly, see https://github.com/transloadit/uppy/issues/116#issuecomment-247695921.*
+
+### getState()
+
+Returns current state.
+
+### setState({itemToUpdate: data})
+
+Updates state with new state (Object.assign({}, this.state, newState)) and then runs `updateAll()`.
+
+### updateAll()
+
+Iterates over all `plugins` and runs `update()` on each of them.
+
+### updateMeta(data, fileID)
+
+Given `{ size: 1200 }` adds that metadata to a file.
+
+### addFile(file)
+
+Adds a new file to `state`. This method is used by `acquirer` plugins like Drag & Drop, Webcam and Google Drive,
+or can be called by the user on uppy instance directly: `uppy.addFile(myFile)`.
+
+Normalizes that file too: tries to figure out file type by extension if mime is missing, use noname if name is missing, sets progress: 0  and so on.
+
+### removeFile(fileID)
+
+Removes file from `state.files`.
+
+### addThumbnail(fileID)
+
+Reads image from file’s data object in base64 and resizes that, using canvas. Then `state` is updated with a file that has thumbnail in it. Thumbnails are used for file previews by plugins like Dashboard.
+
+### state.capabilities
+
+Core (or plugins) check and set capabilities, like: `resumable: true` (this is set by Tus Plugin), `touch: false`, `dragdrop: true`, that could possibly be used by all plugins.
+
+### log(msg)
 
-### Core
+Logs stuff to console only if user specified `debug: true`, silent in production.
 
-1. Core class `Uppy` accepts object `options` (with general options), and exposes methods `.use` for adding plugins and `.set` for setting options.
-2. We create a new instance of `Uppy` and call `.use` on it, passing the plugins and their options.
-3. Then `run` is called to get things going.
-4. Plugins have types: `presetter`, `orchestrator`, `progressindicator`, `acquirer`, `uploader`, and `presenter` (more could be added in the future). When `use` is called, each plugin’s `run` method is added to an array of corresponding types, `methods`.
-5. Ok, now the tricky part. Core’s method `run` iterates over plugin types in a waterfall manner — each `runTypes`  runs its `method`s in parallel and returns an array of results (files) to the next plugin type in the waterfall. This way we first get all the of files from `DragDrop`, `Dropbox`, `Instagram` and other inputs — then parse them somehow — and then upload:
+### core.on('event', action), core.emit('event')
 
-![waterfall of parallels](/images/uppy-core-plugins-architecture.jpg)
+An event emitter embedded into Core that is passed to Plugins, and can be used directly on the instance. Used by Plugins for communicating with other Plugins and Core.
 
-### Plugins
+For example:
 
-1. Plugins are registered like this:
-```javascript
-uppy
-  .use(DragDrop, {selector: '#upload-target'})
-  .use(Tus10, {endpoint: 'http://master.tus.io:8080'})
+- Core listens for `core:upload-progress` event and calculates speed & ETA for all files currently in progress. *Uploader plugins could just call core.updateProgress().*
+- Core checks if browser in offline or online and emits `core:is-offline` or `core:is-online` that other plugins can listen to.
+- Any plugin can emit `informer` event that `Informer` plugin can use to display info bubbles. Currently only used in the Dashboard plugin. Example: `core.emitter.emit('informer', 'Connected!', 'success', 3000)`. *(Should this be a Core method instead of Plugin? Could be replaced by core.inform(info) method that will just update state with info)*
+- Uploader plugins listen to `core:upload` event (can be emitted after a file has been added or when upload button has been pressed), get files via `core.getState().files`, filter those that are not marked as complete and upload them, emitting progress events.
+
+*See discussion about Core and Event Emitter: https://github.com/transloadit/uppy/issues/116#issuecomment-247695921*
+
+## Plugins
+
+Plugins extend the functionality of Core (which itself is very much barebones, does almost nothing). Plugins actually do the work — select files, modify and upload them, and show the UI.
+
+Plugins that have some UI can be mounted anywhere in the dom. With current design you can have a Drag & Drop area in `#dragdrop` and Progressbar in `body`. Plugins can also be mounted into other plugins that support that, like Dashboard.
+
+Each plugin extends `Plugin` class with default methods that can be overridden:
+
+### update()
+
+Gets called when state changes and `updateAll()` is called from Core. Checks if a DOM element (tree) has been created with a reference for it stored in plugin’s `this.el`. If so, creates a new element (tree) `const newEl = this.render(currentState)` for current plugin and then calls `yo.update(this.el, newEl)` to effectively update the existing element to match the new one (morphdom is behind that).
+
+All together now:
+
+``` javascript
+const newEl = this.render(currentState)
+yo.update(this.el, newEl)
 ```
 
-Internally, plugins extend from a [`Plugin`](https://github.com/transloadit/uppy/blob/master/src/plugins/Plugin.js) class, see that for details.
+### mount(target, plugin)
 
+Called by the plugin itself, if it is a UI plugin that needs to do something in DOM. A `target` is passed as an argument. There are two possible scenarios for mounting:
 
-2. Settings and handlers are chainable, set like this:
-```javascript
-uppy
-  .set({ wait: true })
-  .use(Modal, {target: 'div#mycontainer', some: 'config'})
-  .use(DragDrop, {target: Modal})
-  .use(Instagram, {target: Modal, some: 'config'})
-  .on('progress', handleProgress)
-  .on('error', handleError);
+1\. If `typeof target === 'string'`, then the element (tree) is rendered and gets mounted to the DOM:
+
+``` javascript
+this.el = plugin.render(this.core.state)
+document.querySelector(target).appendChild(this.el)
 ```
 
-3. In `Uppy` everything is a plugin: a `Modal` dialog, `Drag & Drop`, `Instagram`. We borrow general approach from the new Babel and PostCSS — each chunk of functionality exists as separate plugin — easier to pick and choose exactly what you need to get a lightweight solution for production, while also easier to develop and avoid merge conflicts.
+2\. If `typeof target === 'object'`, then that plugin is found in `plugins` object of Core and `addTarget()` is called on that plugin.
 
-4. There will be a simplified preset that strings together many Plugins using sane defaults.
-```javascript
-uppy
-  .use(Basic, {target: 'div#mycontainer', endpoint: 'http://master.tus.io:8080'})
-  .run();
+``` javascript
+const targetPlugin = this.core.getPlugin(targetPluginName)
+const selectorTarget = targetPlugin.addTarget(plugin)
 ```
 
-5. Users will be able to roll out themes and style settings via plain CSS .
+### focus()
+
+Called when plugin is in focus, like when that plugin’s tab is selected in the Dashboard.
+
+### install()
+
+Called by Core when it instantiates new plugins. In `install`
+a plugin can extend global state with its own state (like `{ modal: { isHidden: true } }`), or do anything needed on initialization, including `mount()`.
+
+### Plugins are currently of the following types:
+
+### acquirer
+
+- **DragDrop** — simple DragDrop, once file is dropped on a target, it gets added to state.files. “click here to select” too
+- **GoogleDrive** — GoogleDrive UI, uses uppy-server component. Files are downloaded from Google Drive to uppy-server, without having to go through the client, saving bandwidth and space
+- **Formtag** — simple input[type=file] element
+- **Webcam** — allows to take pictures with your webcam, works in most browsers, except Safari. Flash (ugh) is used for fallback
+
+### orchestrator
+
+*Should probably be called UI*
+
+- **Dashboard** — the full-featured interface for interacting with Uppy. Supports drag & dropping files, provides UI for Google Drive, Webcam and any other plugin, shows selected files, shows progress on them.
+
+### progressindicator
+
+- **ProgressBar** — tiny progressbar that can be mounted anywhere.
+
+### uploader
 
-6. Would be cool if you could use whatever drag & drop library you wanted (DropZone) with our wrapper.
+- **Tus10** — tus resumable file uploads, see http://tus.io
+- **Multipart** — regular form/multipart/xhr uploads
 
-### References & Inspiration
+### modifier
 
-1. [PostCSS](https://github.com/postcss/postcss/blob/master/lib/postcss.es6#L19)
-2. [Markdown-It](https://github.com/markdown-it/markdown-it/blob/master/lib/index.js#L459)
-3. [Babel](babeljs.io)
-4. [Lodash](https://lodash.com/)
-5. [Vue.js](http://vuejs.org/guide/plugins.html#Using_a_Plugin)
-6. [The tus js client](https://github.com/tus/tus-js-client)
+- **Metadata** — allows adding custom metadata fields, data from each field is then added to a file

+ 75 - 0
website/src/api/index.md

@@ -0,0 +1,75 @@
+---
+type: api
+order: 0
+title: "API"
+permalink: api/
+---
+
+*Work in progress, API not stable. Last update: 2016-10-21*
+
+## The Gist
+
+{% include_code lang:js ../api-usage-example.ejs %}
+
+## Methods
+
+### `uppy.use(plugin)`
+
+``` javascript
+uppy.use(DragDrop)
+```
+
+### `uppy.run()`
+
+Initializes everything after setup.
+
+### uppy.on('event', action)
+
+Subscribe to an event.
+
+## Events
+
+Uppy exposes events that you can subscribe to in your app:
+
+### core:upload-progress
+
+Fired each time file upload progress is available, `data` object looks like this:
+
+```javascript
+data = {
+  id: myimg12321323,
+  bytesUploaded: 2323254,
+  bytesTotal
+}
+```
+
+```javascript
+uppy.on('core:upload-progress', (data) => {
+  console.log(data.id, data.bytesUploaded, data.bytesTotal)
+})
+```
+
+### `core:upload-success`
+
+Fired when single upload is complete.
+
+``` javascript
+uppy.on('core:upload-success', (fileId, url) => {
+  console.log(url)
+  var img = new Image()
+  img.width = 300
+  img.alt = fileId
+  img.src = url
+  document.body.appendChild(img)
+})
+```
+
+### `core:success`
+
+Fired when all uploads are complete.
+
+``` javascript
+uppy.on('core:success', (fileCount) => {
+  console.log(fileCount)
+})
+```

+ 69 - 8
website/src/guide/getting-started.md

@@ -5,19 +5,80 @@ order: 0
 permalink: guide/
 ---
 
-> **Compatibility Note:** Uppy supports IE 10 and up
+*Uppy is in development, some features are unavailable and things may break.*
 
-## NPM
+## Installing from NPM
 
-NPM is the recommended installation method when building large scale apps with Uppy. It pairs nicely with a CommonJS module bundler such as [webpack](http://webpack.github.io/),  [Browserify](http://browserify.org/) or [rollup.js](http://rollupjs.org/).
+NPM is the recommended installation method when building large scale apps with Uppy. It pairs nicely with a CommonJS module bundler such as [webpack](http://webpack.github.io/), [Browserify](http://browserify.org/) or [rollup.js](http://rollupjs.org/).
 
 ``` bash
-# latest stable
-$ npm install --save uppy
+$ npm install uppy --save
 ```
 
-{% include_code lang:js dragdrop/app.es6 %}
+``` javascript
+// ES6
+import { Core, DragDrop, Tus10 } from 'uppy'
 
-## Standalone & CDN
+const uppy = new Core({wait: false})
+const files = uppy
+  .use(DragDrop, {target: 'body'})
+  .use(Tus10, {endpoint: '//tusd.tus.io/files'})
+  .run()
+```
+
+or
+
+``` javascript
+// ES5
+// warning: bundling with `require` will currently include the whole Uppy package, with all plugins.
+// If you want to pick and choose, use `import`
+var Uppy = require('uppy')
+
+var uppy = new Uppy.Core({wait: false})
+var files = uppy
+  .use(Uppy.DragDrop, {target: 'body'})
+  .use(Uppy.Tus10, {endpoint: '//tusd.tus.io/files'})
+  .run()
+```
+
+Add CSS [uppy.min.css](https://unpkg.com/uppy/dist/uppy.min.css), either to `head` of your HTML or include in JS, if your bundler of choice supports it — transforms and plugins are available for Browserify and Webpack.
+
+Give Uppy a spin [on RequireBin](http://requirebin.com/?gist=54e076cccc929cc567cb0aba38815105).
+
+## Installing from CDN
+
+But if you like, you can also use a pre-built bundle, for example from [unpkg CDN](https://unpkg.com/uppy/). In that case `Uppy` will attach itself to the global `window` object.
+
+1\. Add a script to your the bottom of your HTML’s `<body>`:
+
+``` html
+<script src="https://unpkg.com/uppy/dist/uppy.min.js"></script>
+```
+
+2\. Add CSS to your HTML’s `<head>`:
+``` html
+<link href="https://unpkg.com/uppy/dist/uppy.min.css" rel="stylesheet">
+```
+
+3\. Initialize:
+
+``` javascript
+<script>
+  var uppy = new Uppy.Core({locales: Uppy.locales.ru_RU, debug: true})
+  uppy.use(Uppy.DragDrop, {target: '.UppyDragDrop'})
+  uppy.use(Uppy.Tus10, {endpoint: '//tusd.tus.io/files/'})
+  uppy.run()
+</script>
+```
+
+## API
+
+Check out the [API section](/api).
+
+## Browser Support
+
+<a href="https://saucelabs.com/u/transloadit-uppy">
+  <img src="https://saucelabs.com/browser-matrix/transloadit-uppy.svg" alt="Sauce Test Status"/>
+</a>
 
-{% include_code lang:html bundle/app.html %}
+Note: we aim to support IE10+ and recent versions of Safari, Edge, Chrome, Firefox and Opera. IE6 on the chart above means we recommend setting Uppy to target a `<form>` element, so when Uppy has not yet loaded or is not supported, upload still works. Even on the refrigerator browser. Or, yes, IE6.

+ 1 - 1
website/themes/uppy/source/css/_common.scss

@@ -42,7 +42,7 @@ code, pre {
 }
 
 code {
-  color: $color-orange;
+  // color: $color-orange;
   padding: 3px 5px;
   margin: 0 2px;
   border-radius: $size-radius;