about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMitchell Hentges <mitch9654@gmail.com>2017-01-03 00:36:48 -0800
committerMitchell Hentges <mitch9654@gmail.com>2017-01-03 00:43:45 -0800
commit4d300e2507c1f8f5aeebc1079eeddcad1edca4a5 (patch)
tree88a1715021c33add55501351dbf74950deeac481
parent3125dd8920af1b6e9847dc7cef79de108411656a (diff)
On file-drag, show a border around textarea
-rw-r--r--app/assets/javascripts/components/components/autosuggest_textarea.jsx41
-rw-r--r--app/assets/javascripts/components/features/compose/components/compose_form.jsx2
-rw-r--r--app/assets/javascripts/components/features/compose/containers/compose_form_container.jsx1
-rw-r--r--app/assets/javascripts/components/reducers/compose.jsx6
-rw-r--r--app/assets/stylesheets/components.scss10
5 files changed, 54 insertions, 6 deletions
diff --git a/app/assets/javascripts/components/components/autosuggest_textarea.jsx b/app/assets/javascripts/components/components/autosuggest_textarea.jsx
index 8d9da1601..39ccbcaf9 100644
--- a/app/assets/javascripts/components/components/autosuggest_textarea.jsx
+++ b/app/assets/javascripts/components/components/autosuggest_textarea.jsx
@@ -32,6 +32,7 @@ const AutosuggestTextarea = React.createClass({
     value: React.PropTypes.string,
     suggestions: ImmutablePropTypes.list,
     disabled: React.PropTypes.bool,
+    fileDropDate: React.PropTypes.instanceOf(Date),
     placeholder: React.PropTypes.string,
     onSuggestionSelected: React.PropTypes.func.isRequired,
     onSuggestionsClearRequested: React.PropTypes.func.isRequired,
@@ -42,6 +43,8 @@ const AutosuggestTextarea = React.createClass({
 
   getInitialState () {
     return {
+      isFileDragging: false,
+      fileDraggingDate: undefined,
       suggestionsHidden: false,
       selectedSuggestion: 0,
       lastToken: null,
@@ -120,21 +123,51 @@ const AutosuggestTextarea = React.createClass({
     if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden) {
       this.setState({ suggestionsHidden: false });
     }
+
+    const fileDropDate = nextProps.fileDropDate;
+    const { isFileDragging, fileDraggingDate } = this.state;
+
+    /*
+     * We can't detect drop events, because they might not be on the textarea (the app allows dropping anywhere in the
+     * window). Instead, on-drop, we notify this textarea to stop its hover effect by passing in a prop with the
+     * drop-date.
+     */
+    if (isFileDragging && fileDraggingDate && fileDropDate // if dragging when props updated, and dates aren't undefined
+      && fileDropDate > fileDraggingDate) { // and if the drop date is now greater than when we started dragging
+      // then we should stop dragging
+      this.setState({
+        isFileDragging: false
+      });
+    }
   },
 
   setTextarea (c) {
     this.textarea = c;
   },
 
+  onDragEnter () {
+    this.setState({
+      isFileDragging: true,
+      fileDraggingDate: new Date()
+    })
+  },
+
+  onDragExit () {
+    this.setState({
+      isFileDragging: false
+    })
+  },
+
   render () {
-    const { value, suggestions, disabled, placeholder, onKeyUp } = this.props;
-    const { suggestionsHidden, selectedSuggestion } = this.state;
+    const { value, suggestions, fileDropDate, disabled, placeholder, onKeyUp } = this.props;
+    const { isFileDragging, suggestionsHidden, selectedSuggestion } = this.state;
+    const className = isFileDragging ? 'autosuggest-textarea__textarea file-drop' : 'autosuggest-textarea__textarea';
 
     return (
       <div className='autosuggest-textarea'>
         <textarea
           ref={this.setTextarea}
-          className='autosuggest-textarea__textarea'
+          className={className}
           disabled={disabled}
           placeholder={placeholder}
           value={value}
@@ -142,6 +175,8 @@ const AutosuggestTextarea = React.createClass({
           onKeyDown={this.onKeyDown}
           onKeyUp={onKeyUp}
           onBlur={this.onBlur}
+          onDragEnter={this.onDragEnter}
+          onDragExit={this.onDragExit}
         />
 
         <div style={{ display: (suggestions.size > 0 && !suggestionsHidden) ? 'block' : 'none' }} className='autosuggest-textarea__suggestions'>
diff --git a/app/assets/javascripts/components/features/compose/components/compose_form.jsx b/app/assets/javascripts/components/features/compose/components/compose_form.jsx
index 012e39c91..55f361b0b 100644
--- a/app/assets/javascripts/components/features/compose/components/compose_form.jsx
+++ b/app/assets/javascripts/components/features/compose/components/compose_form.jsx
@@ -27,6 +27,7 @@ const ComposeForm = React.createClass({
     sensitive: React.PropTypes.bool,
     unlisted: React.PropTypes.bool,
     private: React.PropTypes.bool,
+    fileDropDate: React.PropTypes.instanceOf(Date),
     is_submitting: React.PropTypes.bool,
     is_uploading: React.PropTypes.bool,
     in_reply_to: ImmutablePropTypes.map,
@@ -110,6 +111,7 @@ const ComposeForm = React.createClass({
           ref={this.setAutosuggestTextarea}
           placeholder={intl.formatMessage(messages.placeholder)}
           disabled={disabled}
+          fileDropDate={this.props.fileDropDate}
           value={this.props.text}
           onChange={this.handleChange}
           suggestions={this.props.suggestions}
diff --git a/app/assets/javascripts/components/features/compose/containers/compose_form_container.jsx b/app/assets/javascripts/components/features/compose/containers/compose_form_container.jsx
index 1d8f20ca7..2b6ee1ae7 100644
--- a/app/assets/javascripts/components/features/compose/containers/compose_form_container.jsx
+++ b/app/assets/javascripts/components/features/compose/containers/compose_form_container.jsx
@@ -24,6 +24,7 @@ const makeMapStateToProps = () => {
       sensitive: state.getIn(['compose', 'sensitive']),
       unlisted: state.getIn(['compose', 'unlisted']),
       private: state.getIn(['compose', 'private']),
+      fileDropDate: state.getIn(['compose', 'fileDropDate']),
       is_submitting: state.getIn(['compose', 'is_submitting']),
       is_uploading: state.getIn(['compose', 'is_uploading']),
       in_reply_to: getStatus(state, state.getIn(['compose', 'in_reply_to'])),
diff --git a/app/assets/javascripts/components/reducers/compose.jsx b/app/assets/javascripts/components/reducers/compose.jsx
index 742272e6f..16215684e 100644
--- a/app/assets/javascripts/components/reducers/compose.jsx
+++ b/app/assets/javascripts/components/reducers/compose.jsx
@@ -30,6 +30,7 @@ const initialState = Immutable.Map({
   unlisted: false,
   private: false,
   text: '',
+  fileDropDate: null,
   in_reply_to: null,
   is_submitting: false,
   is_uploading: false,
@@ -116,7 +117,10 @@ export default function compose(state = initialState, action) {
     case COMPOSE_SUBMIT_FAIL:
       return state.set('is_submitting', false);
     case COMPOSE_UPLOAD_REQUEST:
-      return state.set('is_uploading', true);
+      return state.withMutations(map => {
+        map.set('is_uploading', true);
+        map.set('fileDropDate', new Date());
+      });
     case COMPOSE_UPLOAD_SUCCESS:
       return appendMedia(state, Immutable.fromJS(action.media));
     case COMPOSE_UPLOAD_FAIL:
diff --git a/app/assets/stylesheets/components.scss b/app/assets/stylesheets/components.scss
index 290b370a9..832b9e9b1 100644
--- a/app/assets/stylesheets/components.scss
+++ b/app/assets/stylesheets/components.scss
@@ -549,13 +549,19 @@
   width: 100%;
   height: 100px;
   resize: none;
-  border: none;
   color: #282c37;
-  padding: 10px;
+  padding: 7px;
   font-family: 'Roboto';
   font-size: 14px;
   margin: 0;
   resize: vertical;
+
+  border: 3px dashed transparent;
+  transition: border-color 0.3s ease;
+
+  &.file-drop {
+    border-color: #aaa;
+  }
 }
 
 .autosuggest-textarea__suggestions {