fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
import _ from 'underscore';
|
|
|
|
import React from 'react';
|
|
|
|
import ReactDOM from 'react-dom';
|
2016-05-07 07:24:40 +08:00
|
|
|
import {remote} from 'electron'
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
|
|
|
|
import {
|
|
|
|
Utils,
|
|
|
|
Actions,
|
|
|
|
DraftStore,
|
2016-05-19 07:19:42 +08:00
|
|
|
UndoManager,
|
|
|
|
DraftHelpers,
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
FileDownloadStore,
|
2016-05-19 07:19:42 +08:00
|
|
|
QuotedHTMLTransformer,
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
} from 'nylas-exports';
|
|
|
|
|
|
|
|
import {
|
|
|
|
DropZone,
|
|
|
|
RetinaImg,
|
|
|
|
ScrollRegion,
|
|
|
|
TabGroupRegion,
|
|
|
|
InjectedComponent,
|
|
|
|
KeyCommandsRegion,
|
2016-05-25 06:47:49 +08:00
|
|
|
OverlaidComponents,
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
InjectedComponentSet,
|
|
|
|
} from 'nylas-component-kit';
|
|
|
|
|
|
|
|
import FileUpload from './file-upload';
|
|
|
|
import ImageFileUpload from './image-file-upload';
|
|
|
|
|
|
|
|
import ComposerEditor from './composer-editor';
|
|
|
|
import ComposerHeader from './composer-header';
|
2016-04-30 06:57:45 +08:00
|
|
|
import SendActionButton from './send-action-button';
|
|
|
|
import ActionBarPlugins from './action-bar-plugins'
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
|
|
|
|
import Fields from './fields';
|
|
|
|
|
|
|
|
// The ComposerView is a unique React component because it (currently) is a
|
|
|
|
// singleton. Normally, the React way to do things would be to re-render the
|
|
|
|
// Composer with new props.
|
|
|
|
export default class ComposerView extends React.Component {
|
|
|
|
static displayName = 'ComposerView';
|
|
|
|
|
|
|
|
static propTypes = {
|
|
|
|
session: React.PropTypes.object.isRequired,
|
|
|
|
draft: React.PropTypes.object.isRequired,
|
|
|
|
|
|
|
|
// Sometimes when changes in the composer happens it's desirable to
|
|
|
|
// have the parent scroll to a certain location. A parent component can
|
|
|
|
// pass a callback that gets called when this composer wants to be
|
|
|
|
// scrolled to.
|
|
|
|
scrollTo: React.PropTypes.func,
|
|
|
|
className: React.PropTypes.string,
|
|
|
|
}
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
super(props)
|
|
|
|
this.state = {
|
2016-05-19 07:19:42 +08:00
|
|
|
showQuotedText: DraftHelpers.isForwardedMessage(props.draft),
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
if (this.props.session) {
|
2016-05-25 02:48:33 +08:00
|
|
|
this._setupForProps(this.props);
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-19 07:19:42 +08:00
|
|
|
componentWillReceiveProps(nextProps) {
|
|
|
|
if (nextProps.session !== this.props.session) {
|
2016-05-25 02:48:33 +08:00
|
|
|
this._teardownForProps();
|
2016-05-19 07:19:42 +08:00
|
|
|
this._setupForProps(nextProps);
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
}
|
2016-05-19 07:19:42 +08:00
|
|
|
if (DraftHelpers.isForwardedMessage(this.props.draft) !== DraftHelpers.isForwardedMessage(nextProps.draft)) {
|
2016-05-18 06:03:49 +08:00
|
|
|
this.setState({
|
2016-05-19 07:19:42 +08:00
|
|
|
showQuotedText: DraftHelpers.isForwardedMessage(nextProps.draft),
|
2016-05-18 06:03:49 +08:00
|
|
|
});
|
|
|
|
}
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
}
|
|
|
|
|
2016-05-25 02:48:33 +08:00
|
|
|
componentWillUnmount() {
|
|
|
|
this._teardownForProps();
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
focus() {
|
|
|
|
if (this.props.draft.to.length === 0) {
|
|
|
|
this.refs.header.showAndFocusField(Fields.To);
|
|
|
|
} else if ((this.props.draft.subject || "").trim().length === 0) {
|
|
|
|
this.refs.header.showAndFocusField(Fields.Subject);
|
|
|
|
} else {
|
|
|
|
this.refs[Fields.Body].focus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_keymapHandlers() {
|
|
|
|
return {
|
|
|
|
'composer:send-message': () => this._onPrimarySend(),
|
|
|
|
'composer:delete-empty-draft': () => {
|
|
|
|
if (this.props.draft.pristine) {
|
|
|
|
this._onDestroyDraft();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
'composer:show-and-focus-bcc': () => this.refs.header.showAndFocusField(Fields.Bcc),
|
|
|
|
'composer:show-and-focus-cc': () => this.refs.header.showAndFocusField(Fields.Cc),
|
|
|
|
'composer:focus-to': () => this.refs.header.showAndFocusField(Fields.To),
|
2016-05-25 02:48:33 +08:00
|
|
|
"composer:show-and-focus-from": () => {},
|
|
|
|
"core:undo": (event) => {
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
this.props.session.undo();
|
|
|
|
},
|
|
|
|
"core:redo": (event) => {
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
this.props.session.redo();
|
|
|
|
},
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-05-25 02:48:33 +08:00
|
|
|
_setupForProps({draft, session}) {
|
|
|
|
this.setState({
|
|
|
|
showQuotedText: Utils.isForwardedMessage(draft),
|
|
|
|
});
|
|
|
|
|
|
|
|
// TODO: This is a dirty hack to save selection state into the undo/redo
|
|
|
|
// history. Remove it if / when selection is written into the body with
|
|
|
|
// marker tags, or when selection is moved from `contenteditable.innerState`
|
|
|
|
// into a first-order part of the session state.
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
|
2016-05-25 02:48:33 +08:00
|
|
|
session._composerViewSelectionRetrieve = () => {
|
|
|
|
// Selection updates /before/ the contenteditable emits it's change event,
|
|
|
|
// so the selection that goes with the snapshot state is the previous one.
|
|
|
|
if (this.refs[Fields.Body].getPreviousSelection) {
|
|
|
|
return this.refs[Fields.Body].getPreviousSelection();
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
session._composerViewSelectionRestore = (selection) => {
|
|
|
|
this.refs[Fields.Body].setSelection(selection);
|
|
|
|
}
|
|
|
|
|
|
|
|
draft.files.forEach((file) => {
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
if (Utils.shouldDisplayAsImage(file)) {
|
|
|
|
Actions.fetchFile(file);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-05-25 02:48:33 +08:00
|
|
|
_teardownForProps() {
|
|
|
|
if (this.props.session) {
|
|
|
|
this.props.session._composerViewSelectionRestore = null;
|
|
|
|
this.props.session._composerViewSelectionRetrieve = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
_renderContentScrollRegion() {
|
|
|
|
if (NylasEnv.isComposerWindow()) {
|
|
|
|
return (
|
|
|
|
<ScrollRegion className="compose-body-scroll" ref="scrollregion">
|
|
|
|
{this._renderContent()}
|
|
|
|
</ScrollRegion>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return this._renderContent();
|
|
|
|
}
|
|
|
|
|
|
|
|
_renderContent() {
|
|
|
|
return (
|
|
|
|
<div className="composer-centered">
|
|
|
|
<ComposerHeader
|
|
|
|
ref="header"
|
|
|
|
draft={this.props.draft}
|
|
|
|
session={this.props.session}
|
2016-04-30 05:30:25 +08:00
|
|
|
initiallyFocused={this.props.draft.to.length === 0}
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
/>
|
|
|
|
<div
|
|
|
|
className="compose-body"
|
|
|
|
ref="composeBody"
|
|
|
|
onMouseUp={this._onMouseUpComposerBody}
|
2016-05-07 07:24:40 +08:00
|
|
|
onMouseDown={this._onMouseDownComposerBody}
|
|
|
|
>
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
{this._renderBodyRegions()}
|
|
|
|
{this._renderFooterRegions()}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
_renderBodyRegions() {
|
2016-05-25 06:47:49 +08:00
|
|
|
const exposedProps = {
|
|
|
|
draft: this.props.draft,
|
|
|
|
session: this.props.session,
|
|
|
|
}
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
return (
|
2016-05-25 06:47:49 +08:00
|
|
|
<div ref="composerBodyWrap" className="composer-body-wrap">
|
|
|
|
<OverlaidComponents exposedProps={exposedProps}>
|
|
|
|
{this._renderEditor()}
|
|
|
|
</OverlaidComponents>
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
{this._renderQuotedTextControl()}
|
|
|
|
{this._renderAttachments()}
|
2016-05-25 06:47:49 +08:00
|
|
|
</div>
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
_renderEditor() {
|
|
|
|
const exposedProps = {
|
|
|
|
body: this._removeQuotedText(this.props.draft.body),
|
|
|
|
draftClientId: this.props.draft.clientId,
|
|
|
|
parentActions: {
|
|
|
|
getComposerBoundingRect: this._getComposerBoundingRect,
|
|
|
|
scrollTo: this.props.scrollTo,
|
|
|
|
},
|
|
|
|
onFilePaste: this._onFilePaste,
|
|
|
|
onBodyChanged: this._onBodyChanged,
|
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
|
|
|
<InjectedComponent
|
|
|
|
ref={Fields.Body}
|
2016-05-13 01:47:22 +08:00
|
|
|
className="body-field"
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
matching={{role: "Composer:Editor"}}
|
|
|
|
fallback={ComposerEditor}
|
|
|
|
requiredMethods={[
|
|
|
|
'focus',
|
|
|
|
'focusAbsoluteEnd',
|
|
|
|
'getPreviousSelection',
|
2016-05-25 02:48:33 +08:00
|
|
|
'setSelection',
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
'_onDOMMutated',
|
|
|
|
]}
|
|
|
|
exposedProps={exposedProps}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// The contenteditable decides when to request a scroll based on the
|
|
|
|
// position of the cursor and its relative distance to this composer
|
|
|
|
// component. We provide it our boundingClientRect so it can calculate
|
|
|
|
// this value.
|
|
|
|
_getComposerBoundingRect = () => {
|
|
|
|
return ReactDOM.findDOMNode(this.refs.composerWrap).getBoundingClientRect()
|
|
|
|
}
|
|
|
|
|
|
|
|
_removeQuotedText = (html) => {
|
|
|
|
const {showQuotedText} = this.state;
|
|
|
|
return showQuotedText ? html : QuotedHTMLTransformer.removeQuotedHTML(html);
|
|
|
|
}
|
|
|
|
|
|
|
|
_showQuotedText = (html) => {
|
|
|
|
const {showQuotedText} = this.state;
|
|
|
|
return showQuotedText ? html : QuotedHTMLTransformer.appendQuotedHTML(html, this.props.draft.body);
|
|
|
|
}
|
|
|
|
|
|
|
|
_renderQuotedTextControl() {
|
|
|
|
if (QuotedHTMLTransformer.hasQuotedHTML(this.props.draft.body)) {
|
|
|
|
return (
|
|
|
|
<a className="quoted-text-control" onClick={this._onToggleQuotedText}>
|
|
|
|
<span className="dots">•••</span>
|
|
|
|
</a>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
_onToggleQuotedText = () => {
|
|
|
|
this.setState({showQuotedText: !this.state.showQuotedText});
|
|
|
|
}
|
|
|
|
|
|
|
|
_renderFooterRegions() {
|
|
|
|
return (
|
|
|
|
<div className="composer-footer-region">
|
|
|
|
<InjectedComponentSet
|
|
|
|
matching={{role: "Composer:Footer"}}
|
refactor(composer): Make session, draft available everywhere
Summary:
Up until now, we've been requiring that every plugin control in the composer take the draftClientId, retreive the session, listen to it, build state from the draft, etc. This is a huge pain and is hard to explain to newcomers becaus it frankly makes no sense.
In 0.3.45 we made it so that the ComposerView always has a non-null draft and session. (It isn't rendered until they're available). In this diff, I just pass those through to all the plugins and remove all the session retrieval cruft.
Almost none of the buttons have state of their own, which I think is appropriate.
They do render on every keystroke, but they were already running code (to recompute their state) on each keystroke and profiling suggests this has no impact.
Prepare for immutable
In preparation for Immutable models, make the draft store proxy returns a !== draft if any changes have been made. This means you can safely know that a draft has changed if `props.draft !== nextProps.draft`
Test Plan: Run tests
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2902
2016-04-20 07:05:15 +08:00
|
|
|
exposedProps={{
|
|
|
|
draft: this.props.draft,
|
|
|
|
threadId: this.props.draft.threadId,
|
|
|
|
draftClientId: this.props.draft.clientId,
|
|
|
|
session: this.props.session,
|
|
|
|
}}
|
2016-05-07 07:24:40 +08:00
|
|
|
direction="column"
|
|
|
|
/>
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
_renderAttachments() {
|
|
|
|
return (
|
|
|
|
<div className="attachments-area">
|
|
|
|
{this._renderFileAttachments()}
|
|
|
|
{this._renderUploadAttachments()}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
_renderFileAttachments() {
|
|
|
|
const {files} = this.props.draft;
|
|
|
|
const nonImageFiles = this._nonImageFiles(files).map(file =>
|
|
|
|
this._renderFileAttachment(file, "Attachment")
|
|
|
|
);
|
|
|
|
const imageFiles = this._imageFiles(files).map(file =>
|
|
|
|
this._renderFileAttachment(file, "Attachment:Image")
|
|
|
|
);
|
|
|
|
return nonImageFiles.concat(imageFiles);
|
|
|
|
}
|
|
|
|
|
|
|
|
_renderFileAttachment(file, role) {
|
|
|
|
const props = {
|
|
|
|
file: file,
|
|
|
|
removable: true,
|
|
|
|
targetPath: FileDownloadStore.pathForFile(file),
|
|
|
|
messageClientId: this.props.draft.clientId,
|
|
|
|
};
|
|
|
|
|
|
|
|
const className = (role === "Attachment") ? "file-wrap" : "file-wrap file-image-wrap";
|
|
|
|
|
|
|
|
return (
|
|
|
|
<InjectedComponent
|
|
|
|
key={file.id}
|
|
|
|
matching={{role}}
|
|
|
|
className={className}
|
|
|
|
exposedProps={props}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
_renderUploadAttachments() {
|
|
|
|
const {uploads} = this.props.draft;
|
|
|
|
|
|
|
|
const nonImageUploads = this._nonImageFiles(uploads).map(upload =>
|
|
|
|
<FileUpload key={upload.id} upload={upload} />
|
|
|
|
);
|
|
|
|
const imageUploads = this._imageFiles(uploads).map(upload =>
|
|
|
|
<ImageFileUpload key={upload.id} upload={upload} />
|
|
|
|
);
|
|
|
|
return nonImageUploads.concat(imageUploads);
|
|
|
|
}
|
|
|
|
|
|
|
|
_imageFiles(files) {
|
|
|
|
return _.filter(files, Utils.shouldDisplayAsImage);
|
|
|
|
}
|
|
|
|
|
|
|
|
_nonImageFiles(files) {
|
|
|
|
return _.reject(files, Utils.shouldDisplayAsImage);
|
|
|
|
}
|
|
|
|
|
2016-04-27 05:18:30 +08:00
|
|
|
_renderActionsWorkspaceRegion() {
|
|
|
|
return (
|
|
|
|
<InjectedComponentSet
|
|
|
|
matching={{role: "Composer:ActionBarWorkspace"}}
|
|
|
|
exposedProps={{
|
|
|
|
draft: this.props.draft,
|
|
|
|
threadId: this.props.draft.threadId,
|
|
|
|
draftClientId: this.props.draft.clientId,
|
|
|
|
session: this.props.session,
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
_renderActionsRegion() {
|
|
|
|
return (
|
|
|
|
<div className="composer-action-bar-content">
|
2016-05-20 04:28:28 +08:00
|
|
|
<ActionBarPlugins
|
|
|
|
draft={this.props.draft}
|
|
|
|
session={this.props.session}
|
|
|
|
isValidDraft={this._isValidDraft}
|
|
|
|
/>
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
|
|
|
|
<button
|
|
|
|
tabIndex={-1}
|
|
|
|
className="btn btn-toolbar btn-trash"
|
|
|
|
style={{order: 100}}
|
|
|
|
title="Delete draft"
|
2016-05-07 07:24:40 +08:00
|
|
|
onClick={this._onDestroyDraft}
|
|
|
|
>
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
<RetinaImg name="icon-composer-trash.png" mode={RetinaImg.Mode.ContentIsMask} />
|
|
|
|
</button>
|
|
|
|
|
|
|
|
<button
|
|
|
|
tabIndex={-1}
|
|
|
|
className="btn btn-toolbar btn-attach"
|
|
|
|
style={{order: 50}}
|
|
|
|
title="Attach file"
|
2016-05-07 07:24:40 +08:00
|
|
|
onClick={this._onSelectAttachment}
|
|
|
|
>
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
<RetinaImg name="icon-composer-attachment.png" mode={RetinaImg.Mode.ContentIsMask} />
|
|
|
|
</button>
|
|
|
|
|
|
|
|
<div style={{order: 0, flex: 1}} />
|
|
|
|
|
2016-04-23 09:23:00 +08:00
|
|
|
|
|
|
|
<InjectedComponent
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
ref="sendActionButton"
|
2016-04-23 09:23:00 +08:00
|
|
|
tabIndex={-1}
|
|
|
|
style={{order: -100}}
|
|
|
|
matching={{role: "Composer:SendActionButton"}}
|
|
|
|
fallback={SendActionButton}
|
|
|
|
requiredMethods={[
|
|
|
|
'primaryClick',
|
|
|
|
]}
|
|
|
|
exposedProps={{
|
|
|
|
draft: this.props.draft,
|
|
|
|
draftClientId: this.props.draft.clientId,
|
|
|
|
session: this.props.session,
|
|
|
|
isValidDraft: this._isValidDraft,
|
|
|
|
}}
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This lets us click outside of the `contenteditable`'s `contentBody`
|
|
|
|
// and simulate what happens when you click beneath the text *in* the
|
|
|
|
// contentEditable.
|
|
|
|
|
|
|
|
// Unfortunately, we need to manually keep track of the "click" in
|
|
|
|
// separate mouseDown, mouseUp events because we need to ensure that the
|
|
|
|
// start and end target are both not in the contenteditable. This ensures
|
|
|
|
// that this behavior doesn't interfear with a click and drag selection.
|
|
|
|
_onMouseDownComposerBody = (event) => {
|
|
|
|
if (ReactDOM.findDOMNode(this.refs[Fields.Body]).contains(event.target)) {
|
|
|
|
this._mouseDownTarget = null;
|
|
|
|
} else {
|
|
|
|
this._mouseDownTarget = event.target;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-05 07:06:48 +08:00
|
|
|
_inFooterRegion(el) {
|
2016-05-25 06:47:49 +08:00
|
|
|
return el.closest && el.closest(".composer-footer-region, .overlaid-components")
|
2016-04-05 07:06:48 +08:00
|
|
|
}
|
|
|
|
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
_onMouseUpComposerBody = (event) => {
|
2016-04-05 07:06:48 +08:00
|
|
|
if (event.target === this._mouseDownTarget && !this._inFooterRegion(event.target)) {
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
// We don't set state directly here because we want the native
|
|
|
|
// contenteditable focus behavior. When the contenteditable gets focused
|
|
|
|
// the focused field state will be properly set via editor.onFocus
|
|
|
|
this.refs[Fields.Body].focusAbsoluteEnd();
|
|
|
|
}
|
|
|
|
this._mouseDownTarget = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
_onMouseMoveComposeBody = () => {
|
|
|
|
if (this._mouseComposeBody === "down") {
|
|
|
|
this._mouseComposeBody = "move";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_shouldAcceptDrop = (event) => {
|
|
|
|
// Ensure that you can't pick up a file and drop it on the same draft
|
|
|
|
const nonNativeFilePath = this._nonNativeFilePathForDrop(event);
|
|
|
|
|
|
|
|
const hasNativeFile = event.dataTransfer.files.length > 0;
|
|
|
|
const hasNonNativeFilePath = nonNativeFilePath !== null;
|
|
|
|
|
|
|
|
return hasNativeFile || hasNonNativeFilePath;
|
|
|
|
}
|
|
|
|
|
|
|
|
_nonNativeFilePathForDrop = (event) => {
|
|
|
|
if (event.dataTransfer.types.includes("text/nylas-file-url")) {
|
|
|
|
const downloadURL = event.dataTransfer.getData("text/nylas-file-url");
|
|
|
|
const downloadFilePath = downloadURL.split('file://')[1];
|
|
|
|
if (downloadFilePath) {
|
|
|
|
return downloadFilePath;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Accept drops of images from within the app
|
|
|
|
if (event.dataTransfer.types.includes("text/uri-list")) {
|
|
|
|
const uri = event.dataTransfer.getData('text/uri-list')
|
|
|
|
if (uri.indexOf('file://') === 0) {
|
|
|
|
return decodeURI(uri.split('file://')[1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
_onDrop = (event) => {
|
|
|
|
const {clientId} = this.props.draft;
|
|
|
|
|
|
|
|
// Accept drops of real files from other applications
|
|
|
|
for (const file of Array.from(event.dataTransfer.files)) {
|
|
|
|
Actions.addAttachment({filePath: file.path, messageClientId: clientId});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Accept drops from attachment components / images within the app
|
|
|
|
const uri = this._nonNativeFilePathForDrop(event);
|
|
|
|
if (uri) {
|
|
|
|
Actions.addAttachment({filePath: uri, messageClientId: clientId});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_onFilePaste = (path) => {
|
|
|
|
Actions.addAttachment({filePath: path, messageClientId: this.props.draft.clientId});
|
|
|
|
}
|
|
|
|
|
|
|
|
_onBodyChanged = (event) => {
|
2016-05-25 02:48:33 +08:00
|
|
|
this.props.session.changes.add({body: this._showQuotedText(event.target.value)});
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_isValidDraft = (options = {}) => {
|
|
|
|
// We need to check the `DraftStore` because the `DraftStore` is
|
|
|
|
// immediately and synchronously updated as soon as this function
|
|
|
|
// fires. Since `setState` is asynchronous, if we used that as our only
|
|
|
|
// check, then we might get a false reading.
|
|
|
|
if (DraftStore.isSendingDraft(this.props.draft.clientId)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-05-13 04:59:20 +08:00
|
|
|
const dialog = remote.dialog;
|
2016-05-19 07:19:42 +08:00
|
|
|
const {session} = this.props
|
|
|
|
const {errors, warnings} = session.validateDraftForSending()
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
|
2016-05-19 07:19:42 +08:00
|
|
|
if (errors.length > 0) {
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
dialog.showMessageBox(remote.getCurrentWindow(), {
|
|
|
|
type: 'warning',
|
|
|
|
buttons: ['Edit Message', 'Cancel'],
|
|
|
|
message: 'Cannot Send',
|
2016-05-19 07:19:42 +08:00
|
|
|
detail: errors[0],
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((warnings.length > 0) && (!options.force)) {
|
|
|
|
const response = dialog.showMessageBox(remote.getCurrentWindow(), {
|
|
|
|
type: 'warning',
|
|
|
|
buttons: ['Send Anyway', 'Cancel'],
|
|
|
|
message: 'Are you sure?',
|
|
|
|
detail: `Send ${warnings.join(' and ')}?`,
|
|
|
|
});
|
|
|
|
if (response === 0) { // response is button array index
|
|
|
|
return this._isValidDraft({force: true});
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
_onPrimarySend = () => {
|
|
|
|
this.refs.sendActionButton.primaryClick();
|
|
|
|
}
|
|
|
|
|
|
|
|
_onDestroyDraft = () => {
|
|
|
|
Actions.destroyDraft(this.props.draft.clientId);
|
|
|
|
}
|
|
|
|
|
|
|
|
_onSelectAttachment = () => {
|
|
|
|
Actions.selectAttachment({messageClientId: this.props.draft.clientId});
|
|
|
|
}
|
|
|
|
|
2016-05-19 07:19:42 +08:00
|
|
|
undo = (event) => {
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
|
|
|
|
const historyItem = this.undoManager.undo() || {};
|
|
|
|
if (!historyItem.state) {
|
|
|
|
return;
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
}
|
2016-05-19 07:19:42 +08:00
|
|
|
|
|
|
|
this._recoveredSelection = historyItem.currentSelection;
|
|
|
|
this._applyChanges(historyItem.state, {fromUndoManager: true});
|
|
|
|
this._recoveredSelection = null;
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
}
|
|
|
|
|
2016-05-19 07:19:42 +08:00
|
|
|
redo = (event) => {
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
const historyItem = this.undoManager.redo() || {}
|
|
|
|
if (!historyItem.state) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this._recoveredSelection = historyItem.currentSelection;
|
|
|
|
this._applyChanges(historyItem.state, {fromUndoManager: true});
|
|
|
|
this._recoveredSelection = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
_getSelections = () => {
|
|
|
|
const bodyComponent = this.refs[Fields.Body];
|
|
|
|
return {
|
|
|
|
currentSelection: bodyComponent.getCurrentSelection ? bodyComponent.getCurrentSelection() : null,
|
|
|
|
previousSelection: bodyComponent.getPreviousSelection ? bodyComponent.getPreviousSelection() : null,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_saveToHistory = (selections) => {
|
|
|
|
const {previousSelection, currentSelection} = selections || this._getSelections();
|
|
|
|
|
|
|
|
const historyItem = {
|
|
|
|
previousSelection,
|
|
|
|
currentSelection,
|
|
|
|
state: {
|
|
|
|
body: _.clone(this.props.draft.body),
|
|
|
|
subject: _.clone(this.props.draft.subject),
|
|
|
|
to: _.clone(this.props.draft.to),
|
|
|
|
cc: _.clone(this.props.draft.cc),
|
|
|
|
bcc: _.clone(this.props.draft.bcc),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
const lastState = this.undoManager.current()
|
|
|
|
if (lastState) {
|
|
|
|
lastState.currentSelection = historyItem.previousSelection;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.undoManager.saveToHistory(historyItem);
|
|
|
|
}
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
|
|
|
|
render() {
|
|
|
|
const dropCoverDisplay = this.state.isDropping ? 'block' : 'none';
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div className={this.props.className}>
|
|
|
|
<KeyCommandsRegion
|
|
|
|
localHandlers={this._keymapHandlers()}
|
|
|
|
className={"message-item-white-wrap composer-outer-wrap"}
|
|
|
|
tabIndex="-1"
|
2016-05-07 07:24:40 +08:00
|
|
|
ref="composerWrap"
|
|
|
|
>
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
<TabGroupRegion className="composer-inner-wrap">
|
|
|
|
<DropZone
|
|
|
|
className="composer-inner-wrap"
|
|
|
|
shouldAcceptDrop={this._shouldAcceptDrop}
|
2016-05-07 07:24:40 +08:00
|
|
|
onDragStateChange={({isDropping}) => this.setState({isDropping})}
|
|
|
|
onDrop={this._onDrop}
|
|
|
|
>
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
<div className="composer-drop-cover" style={{display: dropCoverDisplay}}>
|
|
|
|
<div className="centered">
|
|
|
|
<RetinaImg
|
|
|
|
name="composer-drop-to-attach.png"
|
2016-05-07 07:24:40 +08:00
|
|
|
mode={RetinaImg.Mode.ContentIsMask}
|
|
|
|
/>
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
Drop to attach
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div className="composer-content-wrap">
|
|
|
|
{this._renderContentScrollRegion()}
|
|
|
|
</div>
|
|
|
|
|
2016-04-27 05:18:30 +08:00
|
|
|
<div className="composer-action-bar-workspace-wrap">
|
|
|
|
{this._renderActionsWorkspaceRegion()}
|
|
|
|
</div>
|
|
|
|
|
fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
- No React components ever perfom focus in lifecycle methods. Never again.
- A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
- The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
- The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
- ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.
Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.
Test Plan: Broken
Reviewers: juan, evan
Reviewed By: juan, evan
Differential Revision: https://phab.nylas.com/D2814
2016-04-05 06:22:01 +08:00
|
|
|
<div className="composer-action-bar-wrap">
|
|
|
|
{this._renderActionsRegion()}
|
|
|
|
</div>
|
|
|
|
</DropZone>
|
|
|
|
</TabGroupRegion>
|
|
|
|
</KeyCommandsRegion>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|