This implements unmounting for the inline Dashboard component.
To do that, the Dashboard plugin now has a method `uninstall`,
which removes all listeners and removes the Dashboard element
from the DOM. The `componentWillUnmount` handler removes the plugin
from Uppy's internal plugin list. If this approach is the way to
go, we'd add a method to core to remove plugins… I think in that
case, it'd be good to add some concept of View Plugins, so that
Acquirer plugins function like they do now but View plugins can be
mounted and unmounted.
XHRUpload and Tus were relying on `core:upload-complete` to determine
when their uploads had all finished, but `core:upload-complete` could
fire before all XHR `onload` handlers were called. Then, because
XHRUpload and Tus would resolve their `handleUpload` promises at that
point, the `core:success` event could fire *before* all
`core:upload-success` events had fired, and before the plugins properly
handled responses. In particular, some files may not have `.uploadURL`
properties when `core:success` is fired:
https://community.transloadit.com/t/unable-to-get-to-work-the-awss3-plugin/14477/16
I think, that the XHR `onprogress` event would fire first at 100%, and
then the `onload` handler fired at some point later (after the response
was parsed or whatever the browser does to it). This could cause the
`core:upload-complete` event to fire before responses were handled by
Uppy.
The XHRUpload and Tus plugins now use the Promises that they were
already creating to wait for uploads to complete. This way they will
always have handled responses before handing over control to
postprocessors and before the `core:success` event is fired.
Since `core:upload-complete` is now unused, I just removed it for now.
Fixes#315
This patch makes some function options that can return Promises a bit
easier to use. Previously, most of these required that the user returned
a Promise, even if they were doing sync work. Also, if an error was
thrown inside the provided function, it would actually throw the error
instead of rejecting a Promise, thus not allowing Uppy to show an error
notification or anything.
Instead, these options now use this pattern:
```js
Promise.resolve()
.then(() => this.opts.onSomething(argument))
```
Inside a `.then()` handler, both a Promise and a plain value can be
returned, and the resulting Promise will be resolved with the correct
value. Also, any sync errors `throw`n inside a `.then()` handler cause
the returned Promise to be rejected.
@goto-bus-stop could you help a bit here? I’m confused as to how to
remove an event listener when FileCard is closed, given that data
needed for that event listener lives in closure. Now it seems to me
that every time FileCard is open, a new listener is added