mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-10-08 20:26:20 +08:00
commit423cf4f407
Author: Ben Gotow <ben@foundry376.com> Date: Fri Oct 11 22:33:53 2019 -0500 Replace belcard with homegrown VCard parser because our needs are minimal and the linux binary has relocation issues commit4ae19c0ed5
Author: Ben Gotow <ben@foundry376.com> Date: Fri Oct 11 10:38:26 2019 -0500 Skip building a few more belr components, still looking for relocation error cause commita7ec02a449
Author: Ben Gotow <ben@foundry376.com> Date: Thu Oct 10 22:16:15 2019 -0500 Fix windows SRV record lookups for contact directory autodiscovery commit318a31d279
Author: Ben Gotow <ben@foundry376.com> Date: Thu Oct 10 20:50:06 2019 -0500 Leave vcard_grammar unpacked so mailsync can find it at runtime commitbf7e43e37d
Author: Ben Gotow <ben@foundry376.com> Date: Thu Oct 10 20:43:01 2019 -0500 Fix bug in icon case sensitivity commitc283513653
Author: Ben Gotow <ben@foundry376.com> Date: Thu Oct 10 17:29:24 2019 -0500 Renew Windows Authenticode code signing cert (there goes $500…) commitd13235f65b
Author: Ben Gotow <ben@foundry376.com> Date: Wed Oct 9 23:25:34 2019 -0500 Bump mailsync to move belr dlls commit00ca6431df
Author: Ben Gotow <ben@foundry376.com> Date: Wed Oct 9 23:22:53 2019 -0500 Bump to xcode9 to fix odd C++11 error commit47903c99c4
Author: Ben Gotow <ben@foundry376.com> Date: Wed Oct 9 23:01:32 2019 -0500 Bump mailsync to build belr as a dll instead of a static lib commit21d645d4e7
Author: Ben Gotow <ben@foundry376.com> Date: Wed Oct 9 22:38:24 2019 -0500 Bump mailsync commit3f943031cb
Author: Ben Gotow <ben@foundry376.com> Date: Wed Oct 9 21:57:39 2019 -0500 Bump mailsync to fix windows libetpan failure commit8fb55ca0fc
Author: Ben Gotow <ben@foundry376.com> Date: Wed Oct 9 21:36:57 2019 -0500 Bump mailsync, add grammar commitb959c54e50
Author: Ben Gotow <ben@foundry376.com> Date: Wed Oct 9 21:20:13 2019 -0500 Bump mailsync for linux / win32 commitddb5229d67
Author: Ben Gotow <ben@foundry376.com> Date: Tue Oct 8 22:44:12 2019 -0500 Bump mailsync commitf80e1bc422
Author: Ben Gotow <ben@foundry376.com> Date: Tue Oct 8 11:11:39 2019 -0500 Fix LESS linter failures commit66dc60a731
Author: Ben Gotow <ben@foundry376.com> Date: Tue Oct 8 11:00:37 2019 -0500 Extend participant search to return / expand groups commit3bded91307
Author: Ben Gotow <ben@foundry376.com> Date: Tue Oct 8 03:18:11 2019 -0500 Add comments, etc commit4ede5446de
Author: Ben Gotow <ben@foundry376.com> Date: Tue Oct 8 02:38:50 2019 -0500 Google People API contacts CRUD alongside CardDav commit96c6a64e46
Author: Ben Gotow <ben@foundry376.com> Date: Mon Oct 7 14:00:34 2019 -0500 Build ContactBook concept to track which accounts have sync running commit1f6aab1083
Author: Ben Gotow <ben@foundry376.com> Date: Mon Oct 7 11:38:03 2019 -0500 Contact and contact group CRUD, address book menus commitb877c58d48
Author: Ben Gotow <ben@foundry376.com> Date: Sun Oct 6 16:32:33 2019 -0500 Editing contact names working commit761079304c
Author: Ben Gotow <ben@foundry376.com> Date: Mon Sep 30 15:42:59 2019 -0500 Improved styling of YYYYMMDD field commit71a567276b
Author: Ben Gotow <ben@foundry376.com> Date: Mon Sep 30 15:06:28 2019 -0500 UI for edit + move + delete contacts commitf1967dd603
Author: Ben Gotow <ben@foundry376.com> Date: Thu Sep 26 13:50:44 2019 -0500 Allow you to turn on / off the “Found in Mail” autocompletions commit0c2b0eb03b
Author: Ben Gotow <ben@foundry376.com> Date: Thu Sep 26 13:50:14 2019 -0500 Improve contacts window launch perf by lazy loading composer support, scanning less of fs for themes commit07abd6cb71
Author: Ben Gotow <ben@foundry376.com> Date: Thu Sep 26 04:36:10 2019 -0500 Support for CardDav contact display, better groups presentation commit0a9e166d79
Author: Ben Gotow <ben@foundry376.com> Date: Tue Sep 24 12:42:37 2019 -0500 Add hidden attribute to the model in prep for deletion of auto-created contacts commite6ce3b2af9
Author: Ben Gotow <ben@foundry376.com> Date: Tue Sep 24 12:12:52 2019 -0500 Initial pass at address book commit740d7e8655
Author: Ben Gotow <ben@foundry376.com> Date: Tue Sep 24 08:27:06 2019 -0500 Make headers of Preferences > Accounts consistent with General
273 lines
7.1 KiB
TypeScript
273 lines
7.1 KiB
TypeScript
import React from 'react';
|
|
import ReactDOM from 'react-dom';
|
|
import {
|
|
localized,
|
|
PropTypes,
|
|
Actions,
|
|
AccountStore,
|
|
Message,
|
|
DraftEditingSession,
|
|
} from 'mailspring-exports';
|
|
import {
|
|
KeyCommandsRegion,
|
|
ParticipantsTextField,
|
|
ListensToFluxStore,
|
|
} from 'mailspring-component-kit';
|
|
import AccountContactField from './account-contact-field';
|
|
import ComposerHeaderActions from './composer-header-actions';
|
|
import Fields from './fields';
|
|
|
|
const ScopedFromField = ListensToFluxStore(AccountContactField, {
|
|
stores: [AccountStore],
|
|
getStateFromStores: props => {
|
|
const savedOrReplyToThread = !!props.draft.threadId;
|
|
if (savedOrReplyToThread) {
|
|
return { accounts: [AccountStore.accountForId(props.draft.accountId)] };
|
|
}
|
|
return { accounts: AccountStore.accounts() };
|
|
},
|
|
});
|
|
|
|
interface ComposerHeaderProps {
|
|
draft: Message;
|
|
session: DraftEditingSession;
|
|
}
|
|
interface ComposerHeaderState {
|
|
enabledFields: string[];
|
|
}
|
|
|
|
export class ComposerHeader extends React.Component<ComposerHeaderProps, ComposerHeaderState> {
|
|
static displayName = 'ComposerHeader';
|
|
|
|
static propTypes = {
|
|
draft: PropTypes.object.isRequired,
|
|
session: PropTypes.object.isRequired,
|
|
};
|
|
|
|
static contextTypes = {
|
|
parentTabGroup: PropTypes.object,
|
|
};
|
|
|
|
private _els: {
|
|
participantsContainer?: KeyCommandsRegion;
|
|
} = {};
|
|
|
|
constructor(props) {
|
|
super(props);
|
|
this._els = {};
|
|
this.state = this._initialStateForDraft(this.props.draft, props);
|
|
}
|
|
|
|
componentWillReceiveProps(nextProps) {
|
|
this._ensureFilledFieldsEnabled(nextProps.draft);
|
|
}
|
|
|
|
focus() {
|
|
if (this.props.draft.to.length === 0) {
|
|
this.showAndFocusField(Fields.To);
|
|
} else if (this._els[Fields.Subject]) {
|
|
this._els[Fields.Subject].focus();
|
|
}
|
|
}
|
|
|
|
showAndFocusField = fieldName => {
|
|
this.setState(
|
|
{
|
|
enabledFields: this.state.enabledFields.filter(f => f !== fieldName).concat([fieldName]),
|
|
},
|
|
() => {
|
|
this._els[fieldName].focus();
|
|
}
|
|
);
|
|
};
|
|
|
|
hideField = fieldName => {
|
|
if (ReactDOM.findDOMNode(this._els[fieldName]).contains(document.activeElement)) {
|
|
this.context.parentTabGroup.shiftFocus(-1);
|
|
}
|
|
|
|
const enabledFields = this.state.enabledFields.filter(n => n !== fieldName);
|
|
this.setState({ enabledFields });
|
|
};
|
|
|
|
_ensureFilledFieldsEnabled(draft) {
|
|
let enabledFields = this.state.enabledFields;
|
|
if (draft.cc.length && !enabledFields.find(f => f === Fields.Cc)) {
|
|
enabledFields = [Fields.Cc].concat(enabledFields);
|
|
}
|
|
if (draft.bcc.length && !enabledFields.find(f => f === Fields.Bcc)) {
|
|
enabledFields = [Fields.Bcc].concat(enabledFields);
|
|
}
|
|
if (enabledFields !== this.state.enabledFields) {
|
|
this.setState({ enabledFields });
|
|
}
|
|
}
|
|
|
|
_initialStateForDraft(draft, props) {
|
|
const enabledFields = [Fields.To];
|
|
if (draft.cc.length > 0) enabledFields.push(Fields.Cc);
|
|
if (draft.cc.length > 0) enabledFields.push(Fields.Bcc);
|
|
enabledFields.push(Fields.From);
|
|
if (this._shouldEnableSubject()) {
|
|
enabledFields.push(Fields.Subject);
|
|
}
|
|
return {
|
|
enabledFields,
|
|
};
|
|
}
|
|
|
|
_shouldEnableSubject = () => {
|
|
if ((this.props.draft.subject || '').trim().length === 0) {
|
|
return true;
|
|
}
|
|
if (this.props.draft.isForwarded()) {
|
|
return true;
|
|
}
|
|
if (this.props.draft.replyToHeaderMessageId) {
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
|
|
_onChangeParticipants = changes => {
|
|
this.props.session.changes.add(changes);
|
|
Actions.draftParticipantsChanged(this.props.draft.id, changes);
|
|
};
|
|
|
|
_onSubjectChange = event => {
|
|
this.props.session.changes.add({ subject: event.target.value });
|
|
};
|
|
|
|
_renderSubject = () => {
|
|
if (!this.state.enabledFields.includes(Fields.Subject)) {
|
|
return false;
|
|
}
|
|
return (
|
|
<KeyCommandsRegion tabIndex={-1} className="composer-subject subject-field">
|
|
<input
|
|
ref={el => {
|
|
if (el) {
|
|
this._els[Fields.Subject] = el;
|
|
}
|
|
}}
|
|
type="text"
|
|
name="subject"
|
|
placeholder={localized('Subject')}
|
|
value={this.props.draft.subject}
|
|
onChange={this._onSubjectChange}
|
|
/>
|
|
</KeyCommandsRegion>
|
|
);
|
|
};
|
|
|
|
_renderFields = () => {
|
|
const { to, cc, bcc, from } = this.props.draft;
|
|
|
|
// Note: We need to physically add and remove these elements, not just hide them.
|
|
// If they're hidden, shift-tab between fields breaks.
|
|
const fields = [];
|
|
|
|
fields.push(
|
|
<ParticipantsTextField
|
|
ref={el => {
|
|
if (el) {
|
|
this._els[Fields.To] = el;
|
|
}
|
|
}}
|
|
key="to"
|
|
field="to"
|
|
label={localized('To')}
|
|
change={this._onChangeParticipants}
|
|
className="composer-participant-field to-field"
|
|
participants={{ to, cc, bcc }}
|
|
draft={this.props.draft}
|
|
session={this.props.session}
|
|
/>
|
|
);
|
|
|
|
if (this.state.enabledFields.includes(Fields.Cc)) {
|
|
fields.push(
|
|
<ParticipantsTextField
|
|
ref={el => {
|
|
if (el) {
|
|
this._els[Fields.Cc] = el;
|
|
}
|
|
}}
|
|
key="cc"
|
|
field="cc"
|
|
label={localized('Cc')}
|
|
change={this._onChangeParticipants}
|
|
onEmptied={() => this.hideField(Fields.Cc)}
|
|
className="composer-participant-field cc-field"
|
|
participants={{ to, cc, bcc }}
|
|
draft={this.props.draft}
|
|
session={this.props.session}
|
|
/>
|
|
);
|
|
}
|
|
|
|
if (this.state.enabledFields.includes(Fields.Bcc)) {
|
|
fields.push(
|
|
<ParticipantsTextField
|
|
ref={el => {
|
|
if (el) {
|
|
this._els[Fields.Bcc] = el;
|
|
}
|
|
}}
|
|
key="bcc"
|
|
field="bcc"
|
|
label={localized('Bcc')}
|
|
change={this._onChangeParticipants}
|
|
onEmptied={() => this.hideField(Fields.Bcc)}
|
|
className="composer-participant-field bcc-field"
|
|
participants={{ to, cc, bcc }}
|
|
draft={this.props.draft}
|
|
session={this.props.session}
|
|
/>
|
|
);
|
|
}
|
|
|
|
if (this.state.enabledFields.includes(Fields.From)) {
|
|
fields.push(
|
|
<ScopedFromField
|
|
key="from"
|
|
ref={el => {
|
|
if (el) {
|
|
this._els[Fields.From] = el;
|
|
}
|
|
}}
|
|
value={from[0]}
|
|
draft={this.props.draft}
|
|
session={this.props.session}
|
|
onChange={this._onChangeParticipants}
|
|
/>
|
|
);
|
|
}
|
|
|
|
return fields;
|
|
};
|
|
|
|
render() {
|
|
return (
|
|
<div className="composer-header">
|
|
<ComposerHeaderActions
|
|
headerMessageId={this.props.draft.headerMessageId}
|
|
enabledFields={this.state.enabledFields}
|
|
onShowAndFocusField={this.showAndFocusField}
|
|
/>
|
|
<KeyCommandsRegion
|
|
tabIndex={-1}
|
|
ref={el => {
|
|
if (el) {
|
|
this._els.participantsContainer = el;
|
|
}
|
|
}}
|
|
className="expanded-participants"
|
|
>
|
|
{this._renderFields()}
|
|
</KeyCommandsRegion>
|
|
{this._renderSubject()}
|
|
</div>
|
|
);
|
|
}
|
|
}
|