From b7800d2272e1889315650fa7c83f9bb98390a774 Mon Sep 17 00:00:00 2001 From: Joseph Date: Sun, 22 Oct 2017 13:37:08 -0700 Subject: [PATCH] Add drag and drop avatar uploading --- .../js/forum/src/components/AvatarEditor.js | 100 ++++++++++++++---- framework/core/less/forum/AvatarEditor.less | 5 +- 2 files changed, 83 insertions(+), 22 deletions(-) diff --git a/framework/core/js/forum/src/components/AvatarEditor.js b/framework/core/js/forum/src/components/AvatarEditor.js index 8d7f6c525..869904b33 100644 --- a/framework/core/js/forum/src/components/AvatarEditor.js +++ b/framework/core/js/forum/src/components/AvatarEditor.js @@ -23,6 +23,13 @@ export default class AvatarEditor extends Component { * @type {Boolean} */ this.loading = false; + + /** + * Whether or not an image has been dragged over the dropzone. + * + * @type {Boolean} + */ + this.isDraggedOver = false; } static initProps(props) { @@ -35,12 +42,17 @@ export default class AvatarEditor extends Component { const user = this.props.user; return ( -
+
{avatar(user)} + onclick={this.quickUpload.bind(this)} + ondragover={this.enableDragover.bind(this)} + ondragenter={this.enableDragover.bind(this)} + ondragleave={this.disableDragover.bind(this)} + ondragend={this.disableDragover.bind(this)} + ondrop={this.dropUpload.bind(this)}> {this.loading ? LoadingIndicator.component() : (user.avatarUrl() ? icon('pencil') : icon('plus-circle'))}
    @@ -62,7 +74,7 @@ export default class AvatarEditor extends Component { Button.component({ icon: 'upload', children: app.translator.trans('core.forum.user.avatar_upload_button'), - onclick: this.upload.bind(this) + onclick: this.openPicker.bind(this) }) ); @@ -77,6 +89,40 @@ export default class AvatarEditor extends Component { return items; } + /** + * Enable dragover style + * + * @param {Event} e + */ + enableDragover(e) { + e.preventDefault(); + e.stopPropagation(); + this.isDraggedOver = true; + } + + /** + * Disable dragover style + * + * @param {Event} e + */ + disableDragover(e) { + e.preventDefault(); + e.stopPropagation(); + this.isDraggedOver = false; + } + + /** + * Upload avatar when file is dropped into dropzone. + * + * @param {Event} e + */ + dropUpload(e) { + e.preventDefault(); + e.stopPropagation(); + this.isDraggedOver = false; + this.upload(e.dataTransfer.files[0]); + } + /** * If the user doesn't have an avatar, there's no point in showing the * controls dropdown, because only one option would be viable: uploading. @@ -89,14 +135,14 @@ export default class AvatarEditor extends Component { if (!this.props.user.avatarUrl()) { e.preventDefault(); e.stopPropagation(); - this.upload(); + this.openPicker(); } } /** - * Prompt the user to upload a new avatar. + * Upload avatar using file picker */ - upload() { + openPicker() { if (this.loading) return; // Create a hidden HTML input element and click on it so the user can select @@ -105,24 +151,36 @@ export default class AvatarEditor extends Component { const $input = $(''); $input.appendTo('body').hide().click().on('change', e => { - const data = new FormData(); - data.append('avatar', $(e.target)[0].files[0]); - - this.loading = true; - m.redraw(); - - app.request({ - method: 'POST', - url: app.forum.attribute('apiUrl') + '/users/' + user.id() + '/avatar', - serialize: raw => raw, - data - }).then( - this.success.bind(this), - this.failure.bind(this) - ); + this.upload($(e.target)[0].files[0]); }); } + /** + * Upload avatar + * + * @param {File} file + */ + upload(file) { + if (this.loading) return; + + const user = this.props.user; + const data = new FormData(); + data.append('avatar', file); + + this.loading = true; + m.redraw(); + + app.request({ + method: 'POST', + url: app.forum.attribute('apiUrl') + '/users/' + user.id() + '/avatar', + serialize: raw => raw, + data + }).then( + this.success.bind(this), + this.failure.bind(this) + ); + } + /** * Remove the user's avatar. */ diff --git a/framework/core/less/forum/AvatarEditor.less b/framework/core/less/forum/AvatarEditor.less index 72fc55eda..7f6dc7a9b 100644 --- a/framework/core/less/forum/AvatarEditor.less +++ b/framework/core/less/forum/AvatarEditor.less @@ -17,7 +17,10 @@ .AvatarEditor--noAvatar { opacity: 0.7; } - &:hover .Dropdown-toggle, &.open .Dropdown-toggle, &.loading .Dropdown-toggle { + &:hover .Dropdown-toggle, + &.open .Dropdown-toggle, + &.loading .Dropdown-toggle, + &.dragover .Dropdown-toggle { opacity: 1; } .LoadingIndicator {