mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-11-11 18:32:20 +08:00
2dccde2e58
Summary: Adds Mail Merge Plugin - Adds new table components to component kit - Adds new extension points to allow dragging and dropping into composer contenteditable and participant fields and customizing participant fields - Adds new decorators and other misc updates - #1608 Test Plan: TODO Reviewers: bengotow, evan Reviewed By: bengotow, evan Differential Revision: https://phab.nylas.com/D2895
180 lines
4.6 KiB
JavaScript
180 lines
4.6 KiB
JavaScript
import _ from 'underscore'
|
|
import _str from 'underscore.string'
|
|
import {React, Actions, ExtensionRegistry} from 'nylas-exports'
|
|
import {Menu, RetinaImg, ButtonDropdown} from 'nylas-component-kit'
|
|
|
|
const CONFIG_KEY = "core.sending.defaultSendType";
|
|
|
|
export default class SendActionButton extends React.Component {
|
|
static displayName = "SendActionButton";
|
|
|
|
static propTypes = {
|
|
draft: React.PropTypes.object,
|
|
isValidDraft: React.PropTypes.func,
|
|
};
|
|
|
|
constructor(props) {
|
|
super(props)
|
|
this.state = {
|
|
actionConfigs: this._actionConfigs(this.props),
|
|
};
|
|
}
|
|
|
|
componentDidMount() {
|
|
this.unsub = ExtensionRegistry.Composer.listen(this._onExtensionsChanged);
|
|
}
|
|
|
|
componentWillReceiveProps(newProps) {
|
|
this.setState({actionConfigs: this._actionConfigs(newProps)});
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
this.unsub();
|
|
}
|
|
|
|
static containerRequired = false
|
|
|
|
primaryClick() {
|
|
this._onPrimaryClick();
|
|
}
|
|
|
|
_configKeyFromTitle(title) {
|
|
return _str.dasherize(title.toLowerCase());
|
|
}
|
|
|
|
_defaultActionConfig() {
|
|
return ({
|
|
title: "Send",
|
|
iconUrl: null,
|
|
onSend: ({draft}) => Actions.sendDraft(draft.clientId),
|
|
configKey: "send",
|
|
});
|
|
}
|
|
|
|
_actionConfigs(props) {
|
|
const actionConfigs = [this._defaultActionConfig()]
|
|
|
|
for (const extension of ExtensionRegistry.Composer.extensions()) {
|
|
if (!extension.sendActionConfig) {
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
const actionConfig = extension.sendActionConfig({draft: props.draft});
|
|
if (actionConfig) {
|
|
this._verifyConfig(actionConfig, extension);
|
|
actionConfig.configKey = this._configKeyFromTitle(actionConfig.title);
|
|
actionConfigs.push(actionConfig);
|
|
}
|
|
} catch (err) {
|
|
NylasEnv.reportError(err);
|
|
}
|
|
}
|
|
return actionConfigs;
|
|
}
|
|
|
|
_verifyConfig(config = {}, extension) {
|
|
const name = extension.name;
|
|
if (!_.isString(config.title)) {
|
|
throw new Error(`${name}.sendActionConfig must return a string "title"`);
|
|
}
|
|
if (!_.isFunction(config.onSend)) {
|
|
throw new Error(`${name}.sendActionConfig must return a "onSend" function that will be called when the action is selected`);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
_onExtensionsChanged = () => {
|
|
this.setState({actionConfigs: this._actionConfigs(this.props)});
|
|
}
|
|
|
|
_onPrimaryClick = () => {
|
|
const {preferred} = this._orderedActionConfigs();
|
|
this._onSendWithAction(preferred);
|
|
}
|
|
|
|
_onSendWithAction = ({onSend}) => {
|
|
if (this.props.isValidDraft()) {
|
|
try {
|
|
onSend({draft: this.props.draft});
|
|
} catch (err) {
|
|
NylasEnv.reportError(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
_orderedActionConfigs() {
|
|
const configKeys = _.pluck(this.state.actionConfigs, "configKey");
|
|
let preferredKey = NylasEnv.config.get(CONFIG_KEY);
|
|
if (!preferredKey || !configKeys.includes(preferredKey)) {
|
|
preferredKey = this._defaultActionConfig().configKey;
|
|
}
|
|
|
|
const preferred = _.findWhere(this.state.actionConfigs, {configKey: preferredKey});
|
|
const rest = _.without(this.state.actionConfigs, preferred);
|
|
|
|
return {preferred, rest};
|
|
}
|
|
|
|
_contentForAction = ({iconUrl}) => {
|
|
let plusHTML = "";
|
|
let additionalImg = false;
|
|
|
|
if (iconUrl) {
|
|
plusHTML = (<span> + </span>);
|
|
additionalImg = (<RetinaImg url={iconUrl} mode={RetinaImg.Mode.ContentIsMask} />);
|
|
}
|
|
|
|
return (
|
|
<span>
|
|
<RetinaImg name="icon-composer-send.png" mode={RetinaImg.Mode.ContentIsMask} />
|
|
<span className="text">Send{plusHTML}</span>{additionalImg}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
_renderSingleButton() {
|
|
return (
|
|
<button
|
|
tabIndex={-1}
|
|
className={"btn btn-toolbar btn-normal btn-emphasis btn-text btn-send"}
|
|
style={{order: -100}}
|
|
onClick={this._onPrimaryClick}>
|
|
{this._contentForAction(this.state.actionConfigs[0])}
|
|
</button>
|
|
);
|
|
}
|
|
|
|
_renderButtonDropdown() {
|
|
const {preferred, rest} = this._orderedActionConfigs()
|
|
|
|
const menu = (
|
|
<Menu
|
|
items={rest}
|
|
itemKey={ (actionConfig) => actionConfig.configKey }
|
|
itemContent={this._contentForAction}
|
|
onSelect={this._onSendWithAction}
|
|
/>
|
|
);
|
|
|
|
return (
|
|
<ButtonDropdown
|
|
className={"btn-send btn-emphasis btn-text"}
|
|
style={{order: -100}}
|
|
primaryItem={this._contentForAction(preferred)}
|
|
primaryTitle={preferred.title}
|
|
primaryClick={this._onPrimaryClick}
|
|
closeOnMenuClick
|
|
menu={menu}
|
|
/>
|
|
);
|
|
}
|
|
|
|
render() {
|
|
if (this.state.actionConfigs.length === 1) {
|
|
return this._renderSingleButton();
|
|
}
|
|
return this._renderButtonDropdown();
|
|
}
|
|
|
|
}
|