Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended Drop area to report 🗒️ body for attachment #3732

Merged
merged 3 commits into from
Jun 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/CONST.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ const CONST = {
PERSONAL_DETAIL: 'personalDetail',
},
REPORT: {
DROP_NATIVE_ID: 'report-dropzone',
MAXIMUM_PARTICIPANTS: 8,
ACTIONS: {
LIMIT: 50,
Expand Down
71 changes: 59 additions & 12 deletions src/components/TextInputFocusable/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import _ from 'underscore';
import withLocalize, {withLocalizePropTypes} from '../withLocalize';
import Growl from '../../libs/Growl';
import themeColors from '../../styles/themes/default';
import CONST from '../../CONST';

const propTypes = {
/** Maximum number of lines in the text input */
Expand Down Expand Up @@ -32,13 +33,16 @@ const propTypes = {
/** When the input has cleared whoever owns this input should know about it */
onClear: PropTypes.func,

/** Callback to fire when a file has been dragged into the text input */
/** Callback to fire when a file has being dragged over the text input & report body */
onDragOver: PropTypes.func,

/** Callback to fire when a file has been dragged into the text input & report body */
onDragEnter: PropTypes.func,

/** Callback to fire when the user is no longer dragging over the text input */
/** Callback to fire when the user is no longer dragging over the text input & report body */
onDragLeave: PropTypes.func,

/** Callback to fire when a file is dropped on the text input */
/** Callback to fire when a file is dropped on the text input & report body */
onDrop: PropTypes.func,

/** Whether or not this TextInput is disabled. */
Expand Down Expand Up @@ -69,12 +73,13 @@ const defaultProps = {
onClear: () => {},
style: null,
onDragEnter: () => {},
onDragOver: () => {},
onDragLeave: () => {},
onDrop: () => {},
isDisabled: false,
autoFocus: false,
forwardedRef: null,
onSelectionChange: () => { },
onSelectionChange: () => {},
selection: {
start: 0,
end: 0,
Expand Down Expand Up @@ -114,6 +119,7 @@ class TextInputFocusable extends React.Component {
end: initialValue.length,
};
this.saveSelection = this.saveSelection.bind(this);
this.dragNDropListener = this.dragNDropListener.bind(this);
}

componentDidMount() {
Expand All @@ -131,10 +137,11 @@ class TextInputFocusable extends React.Component {
// listeners here and unbind when the component unmounts
if (this.textInput) {
// Firefox will not allow dropping unless we call preventDefault on the dragover event
this.textInput.addEventListener('dragover', e => e.preventDefault());
this.textInput.addEventListener('dragenter', this.props.onDragEnter);
this.textInput.addEventListener('dragleave', this.props.onDragLeave);
this.textInput.addEventListener('drop', this.props.onDrop);
// We listen on document to extend the Drop area beyond Composer
document.addEventListener('dragover', this.dragNDropListener);
document.addEventListener('dragenter', this.dragNDropListener);
document.addEventListener('dragleave', this.dragNDropListener);
document.addEventListener('drop', this.dragNDropListener);
this.textInput.addEventListener('paste', this.checkForAttachment.bind(this));
}
}
Expand All @@ -158,10 +165,10 @@ class TextInputFocusable extends React.Component {

componentWillUnmount() {
if (this.textInput) {
this.textInput.addEventListener('dragover', e => e.preventDefault());
this.textInput.removeEventListener('dragenter', this.props.onDragEnter);
this.textInput.removeEventListener('dragleave', this.props.onDragLeave);
this.textInput.removeEventListener('drop', this.props.onDrop);
document.removeEventListener('dragover', this.dragNDropListener);
document.removeEventListener('dragenter', this.dragNDropListener);
document.removeEventListener('dragleave', this.dragNDropListener);
document.removeEventListener('drop', this.dragNDropListener);
this.textInput.removeEventListener('paste', this.checkForAttachment.bind(this));
}
}
Expand All @@ -182,6 +189,46 @@ class TextInputFocusable extends React.Component {
return newNumberOfLines;
}

/**
* Handles all types of drag-N-drop events on the composer
*
* @param {Object} e native Event
* @memberof TextInputFocusable
*/
dragNDropListener(e) {
let isOriginComposer = false;
const handler = () => {
switch (e.type) {
case 'dragover':
e.preventDefault();
this.props.onDragOver(e, isOriginComposer);
break;
case 'dragenter':
e.dataTransfer.dropEffect = 'copy';
this.props.onDragEnter(e, isOriginComposer);
break;
case 'dragleave':
this.props.onDragLeave(e, isOriginComposer);
break;
case 'drop':
this.props.onDrop(e, isOriginComposer);
break;
default: break;
}
};

// We first check if drop target is composer so that it can be highlighted
if (this.textInput.contains(e.target)) {
isOriginComposer = true;
handler();
return;
}

if (document.getElementById(CONST.REPORT.DROP_NATIVE_ID).contains(e.target)) {
handler();
}
}

/**
* Keeps track of user cursor position on the Composer
*
Expand Down
11 changes: 10 additions & 1 deletion src/pages/home/report/ReportActionCompose.js
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,16 @@ class ReportActionCompose extends React.Component {
placeholderTextColor={themeColors.placeholderText}
onChangeText={this.updateComment}
onKeyPress={this.triggerHotkeyActions}
onDragEnter={() => this.setState({isDraggingOver: true})}
onDragEnter={(e, isOriginComposer) => {
if (isOriginComposer) {
this.setState({isDraggingOver: true});
}
}}
onDragOver={(e, isOriginComposer) => {
if (isOriginComposer) {
this.setState({isDraggingOver: true});
}
}}
onDragLeave={() => this.setState({isDraggingOver: false})}
onDrop={(e) => {
e.preventDefault();
Expand Down
3 changes: 2 additions & 1 deletion src/pages/home/report/ReportView.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import KeyboardSpacer from '../../../components/KeyboardSpacer';
import styles from '../../../styles/styles';
import SwipeableView from '../../../components/SwipeableView';
import ONYXKEYS from '../../../ONYXKEYS';
import CONST from '../../../CONST';

const propTypes = {
/** The ID of the report the selected report */
Expand All @@ -29,7 +30,7 @@ const defaultProps = {
};

const ReportView = ({reportID, session}) => (
<View key={reportID} style={[styles.flex1, styles.justifyContentEnd]}>
<View nativeID={CONST.REPORT.DROP_NATIVE_ID} key={reportID} style={[styles.flex1, styles.justifyContentEnd]}>
<ReportActionsView reportID={reportID} />

{session.shouldShowComposeInput && (
Expand Down