mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-09-21 15:56:10 +08:00
es6(*): Misc components, nylas-exports => ES2016
This commit is contained in:
parent
0a56d30a22
commit
a9b0472030
|
@ -63,7 +63,8 @@ module.exports = (grunt) ->
|
|||
|
||||
content = fs.readFileSync(f, encoding:'utf8')
|
||||
if /module.exports\s?=\s?.+/gmi.test(content)
|
||||
errors.push("#{f}: Don't use module.exports in ES6")
|
||||
unless f.endsWith('nylas-exports.es6')
|
||||
errors.push("#{f}: Don't use module.exports in ES6")
|
||||
|
||||
if /^export/gmi.test(content)
|
||||
if /^export\ default/gmi.test(content)
|
||||
|
|
|
@ -3,7 +3,7 @@ Actions = require '../src/flux/actions'
|
|||
Message = require('../src/flux/models/message').default
|
||||
DatabaseStore = require('../src/flux/stores/database-store').default
|
||||
AccountStore = require '../src/flux/stores/account-store'
|
||||
ActionBridge = require '../src/flux/action-bridge',
|
||||
ActionBridge = require('../src/flux/action-bridge').default,
|
||||
_ = require 'underscore'
|
||||
|
||||
ipc =
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
React = require 'react'
|
||||
_ = require 'underscore'
|
||||
{Actions, ComponentRegistry, Utils} = require "nylas-exports"
|
||||
|
||||
###
|
||||
Public: A simple wrapper that provides a Flexbox layout with the given direction and style.
|
||||
Any additional props you set on the Flexbox are rendered.
|
||||
|
||||
Section: Component Kit
|
||||
###
|
||||
class Flexbox extends React.Component
|
||||
@displayName: 'Flexbox'
|
||||
|
||||
###
|
||||
Public: React `props` supported by Flexbox:
|
||||
|
||||
- `direction` (optional) A {String} Flexbox direction: either `column` or `row`.
|
||||
- `style` (optional) An {Object} with styles to apply to the flexbox.
|
||||
###
|
||||
@propTypes:
|
||||
direction: React.PropTypes.string
|
||||
inline: React.PropTypes.bool
|
||||
style: React.PropTypes.object
|
||||
height: React.PropTypes.string
|
||||
|
||||
@defaultProps:
|
||||
height: '100%'
|
||||
|
||||
render: ->
|
||||
style = _.extend {},
|
||||
'flexDirection': @props.direction,
|
||||
'position':'relative'
|
||||
'display': 'flex'
|
||||
'height': @props.height
|
||||
, (@props.style || {})
|
||||
|
||||
if @props.inline is true
|
||||
style.display = 'inline-flex'
|
||||
|
||||
otherProps = Utils.fastOmit(@props, Object.keys(@constructor.propTypes))
|
||||
<div style={style} {...otherProps}>
|
||||
{@props.children}
|
||||
</div>
|
||||
|
||||
|
||||
module.exports = Flexbox
|
51
src/components/flexbox.jsx
Normal file
51
src/components/flexbox.jsx
Normal file
|
@ -0,0 +1,51 @@
|
|||
import React from 'react';
|
||||
import {Utils} from "nylas-exports";
|
||||
|
||||
/**
|
||||
Public: A simple wrapper that provides a Flexbox layout with the given direction and style.
|
||||
Any additional props you set on the Flexbox are rendered.
|
||||
|
||||
Section: Component Kit
|
||||
*/
|
||||
export default class Flexbox extends React.Component {
|
||||
static displayName = 'Flexbox';
|
||||
|
||||
/**
|
||||
Public: React `props` supported by Flexbox:
|
||||
|
||||
- `direction` (optional) A {String} Flexbox direction: either `column` or `row`.
|
||||
- `style` (optional) An {Object} with styles to apply to the flexbox.
|
||||
*/
|
||||
static propTypes = {
|
||||
direction: React.PropTypes.string,
|
||||
inline: React.PropTypes.bool,
|
||||
style: React.PropTypes.object,
|
||||
height: React.PropTypes.string,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
height: '100%',
|
||||
style: {},
|
||||
};
|
||||
|
||||
render() {
|
||||
const style = Object.assign({}, {
|
||||
flexDirection: this.props.direction,
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
height: this.props.height,
|
||||
}, this.props.style);
|
||||
|
||||
if (this.props.inline === true) {
|
||||
style.display = 'inline-flex';
|
||||
}
|
||||
|
||||
const otherProps = Utils.fastOmit(this.props, Object.keys(this.constructor.propTypes));
|
||||
|
||||
return (
|
||||
<div style={style} {...otherProps}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
React = require 'react'
|
||||
_ = require 'underscore'
|
||||
|
||||
class FluxContainer extends React.Component
|
||||
@displayName: 'FluxContainer'
|
||||
@propTypes:
|
||||
children: React.PropTypes.element
|
||||
stores: React.PropTypes.array.isRequired
|
||||
getStateFromStores: React.PropTypes.func.isRequired
|
||||
|
||||
constructor: (@props) ->
|
||||
@_unlisteners = []
|
||||
@state = @props.getStateFromStores()
|
||||
|
||||
componentDidMount: ->
|
||||
@setupListeners()
|
||||
|
||||
componentWillReceiveProps: (nextProps) ->
|
||||
@setState(nextProps.getStateFromStores())
|
||||
@setupListeners(nextProps)
|
||||
|
||||
setupListeners: (props = @props) ->
|
||||
unlisten() for unlisten in @_unlisteners
|
||||
@_unlisteners = props.stores.map (store) =>
|
||||
store.listen => @setState(props.getStateFromStores())
|
||||
|
||||
componentWillUnmount: ->
|
||||
unlisten() for unlisten in @_unlisteners
|
||||
@_unlisteners = []
|
||||
|
||||
render: ->
|
||||
otherProps = _.omit(@props, Object.keys(@constructor.propTypes))
|
||||
React.cloneElement(@props.children, _.extend({}, otherProps, @state))
|
||||
|
||||
module.exports = FluxContainer
|
52
src/components/flux-container.jsx
Normal file
52
src/components/flux-container.jsx
Normal file
|
@ -0,0 +1,52 @@
|
|||
import React from 'react';
|
||||
import {Utils} from 'nylas-exports';
|
||||
|
||||
class FluxContainer extends React.Component {
|
||||
static displayName = 'FluxContainer';
|
||||
static propTypes = {
|
||||
children: React.PropTypes.element,
|
||||
stores: React.PropTypes.array.isRequired,
|
||||
getStateFromStores: React.PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this._unlisteners = [];
|
||||
this.state = this.props.getStateFromStores();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
return this.setupListeners();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState(nextProps.getStateFromStores());
|
||||
return this.setupListeners(nextProps);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
for (const unlisten of this._unlisteners) {
|
||||
unlisten();
|
||||
}
|
||||
this._unlisteners = [];
|
||||
}
|
||||
|
||||
setupListeners(props = this.props) {
|
||||
for (const unlisten of this._unlisteners) {
|
||||
unlisten();
|
||||
}
|
||||
|
||||
this._unlisteners = props.stores.map((store) => {
|
||||
return store.listen(() =>
|
||||
this.setState(props.getStateFromStores())
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const otherProps = Utils.fastOmit(this.props, Object.keys(this.constructor.propTypes));
|
||||
return React.cloneElement(this.props.children, Object.assign({}, otherProps, this.state));
|
||||
}
|
||||
}
|
||||
|
||||
export default FluxContainer;
|
|
@ -1,7 +1,7 @@
|
|||
React = require 'react'
|
||||
_ = require 'underscore'
|
||||
UnsafeComponent = require './unsafe-component'
|
||||
Flexbox = require './flexbox'
|
||||
Flexbox = require('./flexbox').default
|
||||
InjectedComponentLabel = require('./injected-component-label').default
|
||||
{Utils,
|
||||
Actions,
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
React = require 'react'
|
||||
RetinaImg = require('./retina-img').default
|
||||
CategoryStore = require '../flux/stores/category-store'
|
||||
|
||||
LabelColorizer =
|
||||
|
||||
color: (label) -> "hsl(#{label.hue()}, 50%, 34%)"
|
||||
|
||||
backgroundColor: (label) -> "hsl(#{label.hue()}, 62%, 87%)"
|
||||
backgroundColorDark: (label) -> "hsl(#{label.hue()}, 62%, 57%)"
|
||||
|
||||
styles: (label) ->
|
||||
styles =
|
||||
color: LabelColorizer.color(label)
|
||||
backgroundColor: LabelColorizer.backgroundColor(label)
|
||||
boxShadow: "inset 0 0 1px hsl(#{label.hue()}, 62%, 47%), inset 0 1px 1px rgba(255,255,255,0.5), 0 0.5px 0 rgba(255,255,255,0.5)"
|
||||
if process.platform isnt "win32"
|
||||
styles["backgroundImage"] = 'linear-gradient(rgba(255,255,255, 0.4), rgba(255,255,255,0))'
|
||||
return styles
|
||||
|
||||
class MailLabel extends React.Component
|
||||
@propTypes:
|
||||
label: React.PropTypes.object.isRequired
|
||||
onRemove: React.PropTypes.func
|
||||
|
||||
shouldComponentUpdate: (nextProps, nextState) ->
|
||||
return false if nextProps.label.id is @props.label.id
|
||||
true
|
||||
|
||||
render: ->
|
||||
classname = 'mail-label'
|
||||
content = @props.label.displayName
|
||||
|
||||
x = null
|
||||
if @_removable()
|
||||
classname += ' removable'
|
||||
content = <span className="inner">{content}</span>
|
||||
x = <RetinaImg
|
||||
className="x"
|
||||
name="label-x.png"
|
||||
style={backgroundColor: LabelColorizer.color(@props.label)}
|
||||
mode={RetinaImg.Mode.ContentIsMask}
|
||||
onClick={@props.onRemove}/>
|
||||
|
||||
<div className={classname} style={LabelColorizer.styles(@props.label)}>{content}{x}</div>
|
||||
|
||||
_removable: ->
|
||||
isLockedLabel = @props.label.isLockedCategory()
|
||||
return @props.onRemove and not isLockedLabel
|
||||
|
||||
module.exports = {MailLabel, LabelColorizer}
|
75
src/components/mail-label.jsx
Normal file
75
src/components/mail-label.jsx
Normal file
|
@ -0,0 +1,75 @@
|
|||
import React from 'react';
|
||||
import RetinaImg from './retina-img';
|
||||
|
||||
const LabelColorizer = {
|
||||
color(label) {
|
||||
return `hsl(${label.hue()}, 50%, 34%)`;
|
||||
},
|
||||
|
||||
backgroundColor(label) {
|
||||
return `hsl(${label.hue()}, 62%, 87%)`;
|
||||
},
|
||||
|
||||
backgroundColorDark(label) {
|
||||
return `hsl(${label.hue()}, 62%, 57%)`;
|
||||
},
|
||||
|
||||
styles(label) {
|
||||
const styles = {
|
||||
color: LabelColorizer.color(label),
|
||||
backgroundColor: LabelColorizer.backgroundColor(label),
|
||||
boxShadow: `inset 0 0 1px hsl(${label.hue()}, 62%, 47%), inset 0 1px 1px rgba(255,255,255,0.5), 0 0.5px 0 rgba(255,255,255,0.5)`,
|
||||
};
|
||||
if (process.platform !== "win32") {
|
||||
styles.backgroundImage = 'linear-gradient(rgba(255,255,255, 0.4), rgba(255,255,255,0))';
|
||||
}
|
||||
return styles;
|
||||
},
|
||||
};
|
||||
|
||||
class MailLabel extends React.Component {
|
||||
static propTypes = {
|
||||
label: React.PropTypes.object.isRequired,
|
||||
onRemove: React.PropTypes.func,
|
||||
};
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
if (nextProps.label.id === this.props.label.id) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
_removable() {
|
||||
return this.props.onRemove && !this.props.label.isLockedCategory();
|
||||
}
|
||||
|
||||
render() {
|
||||
let classname = 'mail-label'
|
||||
let content = this.props.label.displayName
|
||||
|
||||
let x = null;
|
||||
if (this._removable()) {
|
||||
classname += ' removable'
|
||||
content = <span className="inner">{content}</span>
|
||||
x = (
|
||||
<RetinaImg
|
||||
className="x"
|
||||
name="label-x.png"
|
||||
style={{backgroundColor: LabelColorizer.color(this.props.label)}}
|
||||
mode={RetinaImg.Mode.ContentIsMask}
|
||||
onClick={this.props.onRemove}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classname}
|
||||
style={LabelColorizer.styles(this.props.label)}
|
||||
>
|
||||
{content}{x}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export { MailLabel, LabelColorizer };
|
|
@ -4,8 +4,7 @@ _ = require 'underscore'
|
|||
|
||||
{Utils, Actions} = require "nylas-exports"
|
||||
InjectedComponentSet = require './injected-component-set'
|
||||
RetinaImg = requir(('./retina-img').default).default
|
||||
Flexbox = require './flexbox'
|
||||
Flexbox = require('./flexbox').default
|
||||
|
||||
###
|
||||
Public: MultiselectActionBar is a simple component that can be placed in a {Sheet} Toolbar.
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
_ = require 'underscore'
|
||||
request = require 'request'
|
||||
React = require 'react'
|
||||
{Utils, EdgehillAPI} = require "nylas-exports"
|
||||
{RetinaImg, Flexbox} = require 'nylas-component-kit'
|
||||
|
||||
class NewsletterSignup extends React.Component
|
||||
@displayName: 'NewsletterSignup'
|
||||
@propTypes:
|
||||
name: React.PropTypes.string
|
||||
emailAddress: React.PropTypes.string
|
||||
|
||||
constructor: (@props) ->
|
||||
@state = {status: 'Pending'}
|
||||
|
||||
componentWillReceiveProps: (nextProps) =>
|
||||
@_onGetStatus(nextProps) if not _.isEqual(@props, nextProps)
|
||||
|
||||
componentDidMount: =>
|
||||
@_mounted = true
|
||||
@_onGetStatus()
|
||||
|
||||
componentWillUnmount: =>
|
||||
@_mounted = false
|
||||
|
||||
_setState: (state) =>
|
||||
return unless @_mounted
|
||||
@setState(state)
|
||||
|
||||
_onGetStatus: (props = @props) =>
|
||||
@_setState({status: 'Pending'})
|
||||
EdgehillAPI.makeRequest
|
||||
method: 'GET'
|
||||
path: @_path(props)
|
||||
success: (status) =>
|
||||
if status is 'Never Subscribed'
|
||||
@_onSubscribe()
|
||||
else
|
||||
@_setState({status})
|
||||
error: =>
|
||||
@_setState({status: "Error"})
|
||||
|
||||
_onSubscribe: =>
|
||||
@_setState({status: 'Pending'})
|
||||
EdgehillAPI.makeRequest
|
||||
method: 'POST'
|
||||
path: @_path()
|
||||
success: (status) =>
|
||||
@_setState({status})
|
||||
error: =>
|
||||
@_setState({status: "Error"})
|
||||
|
||||
_onUnsubscribe: =>
|
||||
@_setState({status: 'Pending'})
|
||||
EdgehillAPI.makeRequest
|
||||
method: 'DELETE'
|
||||
path: @_path()
|
||||
success: (status) =>
|
||||
@_setState({status})
|
||||
error: =>
|
||||
@_setState({status: "Error"})
|
||||
|
||||
_path: (props = @props) =>
|
||||
"/newsletter-subscription/#{encodeURIComponent(props.emailAddress)}?name=#{encodeURIComponent(props.name)}"
|
||||
|
||||
render: =>
|
||||
<Flexbox direction='row' height='auto' style={textAlign: 'left'}>
|
||||
<div style={minWidth:15}>
|
||||
{@_renderControl()}
|
||||
</div>
|
||||
<label htmlFor="subscribe-check" style={paddingLeft: 4, flex: 1}>
|
||||
Notify me about new features and plugins via this email address.
|
||||
</label>
|
||||
</Flexbox>
|
||||
|
||||
_renderControl: ->
|
||||
if @state.status is 'Pending'
|
||||
<RetinaImg name='inline-loading-spinner.gif' mode={RetinaImg.Mode.ContentDark} style={width:14, height:14}/>
|
||||
else if @state.status is 'Error'
|
||||
<button onClick={@_onGetStatus} className="btn">Retry</button>
|
||||
else if @state.status in ['Subscribed', 'Active']
|
||||
<input id="subscribe-check" type="checkbox" checked={true} style={marginTop:3} onChange={@_onUnsubscribe} />
|
||||
else
|
||||
<input id="subscribe-check" type="checkbox" checked={false} style={marginTop:3} onChange={@_onSubscribe} />
|
||||
|
||||
module.exports = NewsletterSignup
|
113
src/components/newsletter-signup.jsx
Normal file
113
src/components/newsletter-signup.jsx
Normal file
|
@ -0,0 +1,113 @@
|
|||
import _ from 'underscore';
|
||||
import React from 'react';
|
||||
import {EdgehillAPI} from "nylas-exports";
|
||||
import {RetinaImg, Flexbox} from 'nylas-component-kit';
|
||||
|
||||
export default class NewsletterSignup extends React.Component {
|
||||
static displayName = 'NewsletterSignup';
|
||||
static propTypes = {
|
||||
name: React.PropTypes.string,
|
||||
emailAddress: React.PropTypes.string,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {status: 'Pending'};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._mounted = true;
|
||||
return this._onGetStatus();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (!_.isEqual(this.props, nextProps)) {
|
||||
this._onGetStatus(nextProps);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this._mounted = false;
|
||||
}
|
||||
|
||||
_setState(state) {
|
||||
if (!this._mounted) { return; }
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
_onGetStatus(props = this.props) {
|
||||
this._setState({status: 'Pending'});
|
||||
EdgehillAPI.makeRequest({
|
||||
method: 'GET',
|
||||
path: this._path(props),
|
||||
success: status => {
|
||||
if (status === 'Never Subscribed') {
|
||||
this._onSubscribe();
|
||||
} else {
|
||||
this._setState({status});
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
this._setState({status: "Error"});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
_onSubscribe() {
|
||||
this._setState({status: 'Pending'});
|
||||
EdgehillAPI.makeRequest({
|
||||
method: 'POST',
|
||||
path: this._path(),
|
||||
success: status => {
|
||||
this._setState({status});
|
||||
},
|
||||
error: () => {
|
||||
this._setState({status: "Error"});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
_onUnsubscribe() {
|
||||
this._setState({status: 'Pending'});
|
||||
EdgehillAPI.makeRequest({
|
||||
method: 'DELETE',
|
||||
path: this._path(),
|
||||
success: status => {
|
||||
this._setState({status});
|
||||
},
|
||||
error: () => {
|
||||
this._setState({status: "Error"});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
_path(props = this.props) {
|
||||
return `/newsletter-subscription/${encodeURIComponent(props.emailAddress)}?name=${encodeURIComponent(props.name)}`;
|
||||
}
|
||||
|
||||
_renderControl() {
|
||||
if (this.state.status === 'Pending') {
|
||||
return (<RetinaImg name="inline-loading-spinner.gif" mode={RetinaImg.Mode.ContentDark} style={{width: 14, height: 14}} />);
|
||||
}
|
||||
if (this.state.status === 'Error') {
|
||||
return (<button onClick={this._onGetStatus} className="btn">Retry</button>);
|
||||
}
|
||||
if (['Subscribed', 'Active'].includes(this.state.status)) {
|
||||
return (<input id="subscribe-check" type="checkbox" checked style={{marginTop: 3}} onChange={this._onUnsubscribe} />);
|
||||
}
|
||||
return (<input id="subscribe-check" type="checkbox" checked={false} style={{marginTop: 3}} onChange={this._onSubscribe} />);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Flexbox direction="row" height="auto" style={{textAlign: 'left'}}>
|
||||
<div style={{minWidth: 15}}>
|
||||
{this._renderControl()}
|
||||
</div>
|
||||
<label htmlFor="subscribe-check" style={{paddingLeft: 4, flex: 1}}>
|
||||
Notify me about new features and plugins via this email address.
|
||||
</label>
|
||||
</Flexbox>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,147 +0,0 @@
|
|||
_ = require 'underscore'
|
||||
Actions = require './actions'
|
||||
Model = require './models/model'
|
||||
DatabaseStore = require('./stores/database-store').default
|
||||
DatabaseChangeRecord = require('./stores/database-change-record').default
|
||||
|
||||
Utils = require './models/utils'
|
||||
|
||||
Role =
|
||||
WORK: 'work',
|
||||
SECONDARY: 'secondary'
|
||||
|
||||
TargetWindows =
|
||||
ALL: 'all',
|
||||
WORK: 'work'
|
||||
|
||||
Message =
|
||||
DATABASE_STORE_TRIGGER: 'db-store-trigger'
|
||||
|
||||
printToConsole = false
|
||||
|
||||
# Public: ActionBridge
|
||||
#
|
||||
# The ActionBridge has two responsibilities:
|
||||
# 1. When you're in a secondary window, the ActionBridge observes all Root actions. When a
|
||||
# Root action is fired, it converts it's payload to JSON, tunnels it to the main window
|
||||
# via IPC, and re-fires the Action in the main window. This means that calls to actions
|
||||
# like Actions.queueTask(task) can be fired in secondary windows and consumed by the
|
||||
# TaskQueue, which only lives in the main window.
|
||||
|
||||
# 2. The ActionBridge listens to the DatabaseStore and re-broadcasts it's trigger() event
|
||||
# into all of the windows of the application. This is important, because the DatabaseStore
|
||||
# in all secondary windows is a read-replica. Only the DatabaseStore in the main window
|
||||
# of the application consumes persistModel actions and writes changes to the database.
|
||||
|
||||
class ActionBridge
|
||||
@Role: Role
|
||||
@Message: Message
|
||||
@TargetWindows: TargetWindows
|
||||
|
||||
constructor: (ipc) ->
|
||||
@globalActions = []
|
||||
@ipc = ipc
|
||||
@ipcLastSendTime = null
|
||||
@initiatorId = NylasEnv.getWindowType()
|
||||
@role = if NylasEnv.isWorkWindow() then Role.WORK else Role.SECONDARY
|
||||
|
||||
NylasEnv.onBeforeUnload(@onBeforeUnload)
|
||||
|
||||
# Listen for action bridge messages from other windows
|
||||
@ipc.on('action-bridge-message', @onIPCMessage)
|
||||
|
||||
# Observe all global actions and re-broadcast them to other windows
|
||||
Actions.globalActions.forEach (name) =>
|
||||
callback = (args...) => @onRebroadcast(TargetWindows.ALL, name, args)
|
||||
Actions[name].listen(callback, @)
|
||||
|
||||
# Observe the database store (possibly other stores in the future), and
|
||||
# rebroadcast it's trigger() event.
|
||||
databaseCallback = (change) =>
|
||||
return if DatabaseStore.triggeringFromActionBridge
|
||||
@onRebroadcast(TargetWindows.ALL, Message.DATABASE_STORE_TRIGGER, [change])
|
||||
DatabaseStore.listen(databaseCallback, @)
|
||||
|
||||
if @role isnt Role.WORK
|
||||
# Observe all mainWindow actions fired in this window and re-broadcast
|
||||
# them to other windows so the central application stores can take action
|
||||
Actions.workWindowActions.forEach (name) =>
|
||||
callback = (args...) => @onRebroadcast(TargetWindows.WORK, name, args)
|
||||
Actions[name].listen(callback, @)
|
||||
|
||||
registerGlobalActions: ({pluginName, actions}) =>
|
||||
_.each actions, (actionFn, name) =>
|
||||
@globalActions.push({name, actionFn, scope: pluginName})
|
||||
callback = (args...) =>
|
||||
broadcastName = "#{pluginName}::#{name}"
|
||||
@onRebroadcast(TargetWindows.ALL, broadcastName, args)
|
||||
actionFn.listen(callback, @)
|
||||
|
||||
_isExtensionAction: (name) ->
|
||||
name.split("::").length is 2
|
||||
|
||||
_globalExtensionAction: (broadcastName) ->
|
||||
[scope, name] = broadcastName.split("::")
|
||||
{actionFn} = _.findWhere(@globalActions, {scope, name}) ? {}
|
||||
return actionFn
|
||||
|
||||
onIPCMessage: (event, initiatorId, name, json) =>
|
||||
# There's something very strange about IPC event handlers. The ReactRemoteParent
|
||||
# threw React exceptions when calling setState from an IPC callback, and the debugger
|
||||
# often refuses to stop at breakpoints immediately inside IPC callbacks.
|
||||
|
||||
# These issues go away when you add a process.nextTick. So here's that.
|
||||
# I believe this resolves issues like https://sentry.nylas.com/sentry/edgehill/group/2735/,
|
||||
# which are React exceptions in a direct stack (no next ticks) from an IPC event.
|
||||
process.nextTick =>
|
||||
console.debug(printToConsole, "ActionBridge: #{@initiatorId} Action Bridge Received: #{name}")
|
||||
|
||||
args = JSON.parse(json, Utils.registeredObjectReviver)
|
||||
|
||||
if name == Message.DATABASE_STORE_TRIGGER
|
||||
DatabaseStore.triggeringFromActionBridge = true
|
||||
DatabaseStore.trigger(new DatabaseChangeRecord(args[0]))
|
||||
DatabaseStore.triggeringFromActionBridge = false
|
||||
|
||||
else if Actions[name]
|
||||
Actions[name].firing = true
|
||||
Actions[name](args...)
|
||||
else if @_isExtensionAction(name)
|
||||
fn = @_globalExtensionAction(name)
|
||||
if fn
|
||||
fn.firing = true
|
||||
fn(args...)
|
||||
else
|
||||
throw new Error("#{@initiatorId} received unknown action-bridge event: #{name}")
|
||||
|
||||
onRebroadcast: (target, name, args) =>
|
||||
if Actions[name]?.firing
|
||||
Actions[name].firing = false
|
||||
return
|
||||
else if @_globalExtensionAction(name)?.firing
|
||||
@_globalExtensionAction(name).firing = false
|
||||
return
|
||||
|
||||
params = []
|
||||
args.forEach (arg) ->
|
||||
if arg instanceof Function
|
||||
throw new Error("ActionBridge cannot forward action argument of type `function` to work window.")
|
||||
params.push(arg)
|
||||
|
||||
json = JSON.stringify(params, Utils.registeredObjectReplacer)
|
||||
|
||||
console.debug(printToConsole, "ActionBridge: #{@initiatorId} Action Bridge Broadcasting: #{name}")
|
||||
@ipc.send("action-bridge-rebroadcast-to-#{target}", @initiatorId, name, json)
|
||||
@ipcLastSendTime = Date.now()
|
||||
|
||||
onBeforeUnload: (readyToUnload) =>
|
||||
# Unfortunately, if you call ipc.send and then immediately close the window,
|
||||
# Electron won't actually send the message. To work around this, we wait an
|
||||
# arbitrary amount of time before closing the window after the last IPC event
|
||||
# was sent. https://github.com/atom/electron/issues/4366
|
||||
if @ipcLastSendTime and Date.now() - @ipcLastSendTime < 100
|
||||
setTimeout(readyToUnload, 100)
|
||||
return false
|
||||
return true
|
||||
|
||||
module.exports = ActionBridge
|
176
src/flux/action-bridge.es6
Normal file
176
src/flux/action-bridge.es6
Normal file
|
@ -0,0 +1,176 @@
|
|||
import _ from 'underscore';
|
||||
import Actions from './actions';
|
||||
import DatabaseStore from './stores/database-store';
|
||||
import DatabaseChangeRecord from './stores/database-change-record';
|
||||
|
||||
import Utils from './models/utils';
|
||||
|
||||
const Role = {
|
||||
WORK: 'work',
|
||||
SECONDARY: 'secondary',
|
||||
};
|
||||
|
||||
const TargetWindows = {
|
||||
ALL: 'all',
|
||||
WORK: 'work',
|
||||
};
|
||||
|
||||
const Message = {
|
||||
DATABASE_STORE_TRIGGER: 'db-store-trigger',
|
||||
};
|
||||
|
||||
const printToConsole = false;
|
||||
|
||||
// Public: ActionBridge
|
||||
//
|
||||
// The ActionBridge has two responsibilities:
|
||||
// 1. When you're in a secondary window, the ActionBridge observes all Root actions. When a
|
||||
// Root action is fired, it converts it's payload to JSON, tunnels it to the main window
|
||||
// via IPC, and re-fires the Action in the main window. This means that calls to actions
|
||||
// like Actions.queueTask(task) can be fired in secondary windows and consumed by the
|
||||
// TaskQueue, which only lives in the main window.
|
||||
|
||||
// 2. The ActionBridge listens to the DatabaseStore and re-broadcasts it's trigger() event
|
||||
// into all of the windows of the application. This is important, because the DatabaseStore
|
||||
// in all secondary windows is a read-replica. Only the DatabaseStore in the main window
|
||||
// of the application consumes persistModel actions and writes changes to the database.
|
||||
|
||||
class ActionBridge {
|
||||
static Role = Role;
|
||||
static Message = Message;
|
||||
static TargetWindows = TargetWindows;
|
||||
|
||||
constructor(ipc) {
|
||||
this.registerGlobalActions = this.registerGlobalActions.bind(this);
|
||||
this.onIPCMessage = this.onIPCMessage.bind(this);
|
||||
this.onRebroadcast = this.onRebroadcast.bind(this);
|
||||
this.onBeforeUnload = this.onBeforeUnload.bind(this);
|
||||
this.globalActions = [];
|
||||
this.ipc = ipc;
|
||||
this.ipcLastSendTime = null;
|
||||
this.initiatorId = NylasEnv.getWindowType();
|
||||
this.role = NylasEnv.isWorkWindow() ? Role.WORK : Role.SECONDARY;
|
||||
|
||||
NylasEnv.onBeforeUnload(this.onBeforeUnload);
|
||||
|
||||
// Listen for action bridge messages from other windows
|
||||
this.ipc.on('action-bridge-message', this.onIPCMessage);
|
||||
|
||||
// Observe all global actions and re-broadcast them to other windows
|
||||
Actions.globalActions.forEach(name => {
|
||||
const callback = (...args) => this.onRebroadcast(TargetWindows.ALL, name, args);
|
||||
return Actions[name].listen(callback, this);
|
||||
});
|
||||
|
||||
// Observe the database store (possibly other stores in the future), and
|
||||
// rebroadcast it's trigger() event.
|
||||
const databaseCallback = change => {
|
||||
if (DatabaseStore.triggeringFromActionBridge) { return; }
|
||||
this.onRebroadcast(TargetWindows.ALL, Message.DATABASE_STORE_TRIGGER, [change]);
|
||||
};
|
||||
DatabaseStore.listen(databaseCallback, this);
|
||||
|
||||
if (this.role !== Role.WORK) {
|
||||
// Observe all mainWindow actions fired in this window and re-broadcast
|
||||
// them to other windows so the central application stores can take action
|
||||
Actions.workWindowActions.forEach(name => {
|
||||
const callback = (...args) => this.onRebroadcast(TargetWindows.WORK, name, args);
|
||||
return Actions[name].listen(callback, this);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
registerGlobalActions({pluginName, actions}) {
|
||||
return _.each(actions, (actionFn, name) => {
|
||||
this.globalActions.push({name, actionFn, scope: pluginName});
|
||||
const callback = (...args) => {
|
||||
const broadcastName = `${pluginName}::${name}`;
|
||||
return this.onRebroadcast(TargetWindows.ALL, broadcastName, args);
|
||||
};
|
||||
return actionFn.listen(callback, this);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
_isExtensionAction(name) {
|
||||
return name.split("::").length === 2;
|
||||
}
|
||||
|
||||
_globalExtensionAction(broadcastName) {
|
||||
const [scope, name] = broadcastName.split("::");
|
||||
return (_.findWhere(this.globalActions, {scope, name}) || {}).actionFn
|
||||
}
|
||||
|
||||
onIPCMessage(event, initiatorId, name, json) {
|
||||
// There's something very strange about IPC event handlers. The ReactRemoteParent
|
||||
// threw React exceptions when calling setState from an IPC callback, and the debugger
|
||||
// often refuses to stop at breakpoints immediately inside IPC callbacks.
|
||||
|
||||
// These issues go away when you add a process.nextTick. So here's that.
|
||||
// I believe this resolves issues like https://sentry.nylas.com/sentry/edgehill/group/2735/,
|
||||
// which are React exceptions in a direct stack (no next ticks) from an IPC event.
|
||||
process.nextTick(() => {
|
||||
console.debug(printToConsole, `ActionBridge: ${this.initiatorId} Action Bridge Received: ${name}`);
|
||||
|
||||
const args = JSON.parse(json, Utils.registeredObjectReviver);
|
||||
|
||||
if (name === Message.DATABASE_STORE_TRIGGER) {
|
||||
DatabaseStore.triggeringFromActionBridge = true;
|
||||
DatabaseStore.trigger(new DatabaseChangeRecord(args[0]));
|
||||
DatabaseStore.triggeringFromActionBridge = false;
|
||||
} else if (Actions[name]) {
|
||||
Actions[name].firing = true;
|
||||
Actions[name](...args);
|
||||
} else if (this._isExtensionAction(name)) {
|
||||
const fn = this._globalExtensionAction(name);
|
||||
if (fn) {
|
||||
fn.firing = true;
|
||||
fn(...args);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`${this.initiatorId} received unknown action-bridge event: ${name}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onRebroadcast(target, name, args) {
|
||||
if (Actions[name] && Actions[name].firing) {
|
||||
Actions[name].firing = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const globalExtAction = this._globalExtensionAction(name);
|
||||
if (globalExtAction && globalExtAction.firing) {
|
||||
globalExtAction.firing = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const params = [];
|
||||
args.forEach((arg) => {
|
||||
if (arg instanceof Function) {
|
||||
throw new Error("ActionBridge cannot forward action argument of type `function` to work window.");
|
||||
}
|
||||
return params.push(arg);
|
||||
});
|
||||
|
||||
const json = JSON.stringify(params, Utils.registeredObjectReplacer);
|
||||
|
||||
console.debug(printToConsole, `ActionBridge: ${this.initiatorId} Action Bridge Broadcasting: ${name}`);
|
||||
this.ipc.send(`action-bridge-rebroadcast-to-${target}`, this.initiatorId, name, json);
|
||||
this.ipcLastSendTime = Date.now();
|
||||
}
|
||||
|
||||
onBeforeUnload(readyToUnload) {
|
||||
// Unfortunately, if you call ipc.send and then immediately close the window,
|
||||
// Electron won't actually send the message. To work around this, we wait an
|
||||
// arbitrary amount of time before closing the window after the last IPC event
|
||||
// was sent. https://github.com/atom/electron/issues/4366
|
||||
if (this.ipcLastSendTime && Date.now() - this.ipcLastSendTime < 100) {
|
||||
setTimeout(readyToUnload, 100);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export default ActionBridge;
|
|
@ -1,29 +0,0 @@
|
|||
# This file contains custom Nylas error classes.
|
||||
#
|
||||
# In general I think these should be created as sparingly as possible.
|
||||
# Only add one if you really can't use native `new Error("my msg")`
|
||||
|
||||
|
||||
# A wrapper around the three arguments we get back from node's `request`
|
||||
# method. We wrap it in an error object because Promises can only call
|
||||
# `reject` or `resolve` with one argument (not three).
|
||||
class APIError extends Error
|
||||
constructor: ({@error, @response, @body, @requestOptions, @statusCode} = {}) ->
|
||||
@statusCode ?= @response?.statusCode
|
||||
@requestOptions ?= @response?.requestOptions
|
||||
@name = "APIError"
|
||||
@stack = (new Error()).stack
|
||||
@message = @body?.message ? @body ? @error?.toString?()
|
||||
@errorTitle = @body?.error
|
||||
|
||||
fromJSON: (json = {}) ->
|
||||
for key, val of json
|
||||
@[key] = val
|
||||
@
|
||||
|
||||
class TimeoutError extends Error
|
||||
constructor: ->
|
||||
|
||||
module.exports =
|
||||
"APIError": APIError
|
||||
"TimeoutError": TimeoutError
|
43
src/flux/errors.es6
Normal file
43
src/flux/errors.es6
Normal file
|
@ -0,0 +1,43 @@
|
|||
// This file contains custom Nylas error classes.
|
||||
//
|
||||
// In general I think these should be created as sparingly as possible.
|
||||
// Only add one if you really can't use native `new Error("my msg")`
|
||||
|
||||
|
||||
// A wrapper around the three arguments we get back from node's `request`
|
||||
// method. We wrap it in an error object because Promises can only call
|
||||
// `reject` or `resolve` with one argument (not three).
|
||||
export class APIError extends Error {
|
||||
constructor({error, response, body, requestOptions, statusCode} = {}) {
|
||||
super();
|
||||
|
||||
this.name = "APIError";
|
||||
this.error = error;
|
||||
this.response = response;
|
||||
this.body = body;
|
||||
this.requestOptions = requestOptions;
|
||||
this.statusCode = statusCode;
|
||||
|
||||
if (this.statusCode == null) {
|
||||
this.statusCode = this.response ? this.response.statusCode : null;
|
||||
}
|
||||
if (this.requestOptions == null) {
|
||||
this.requestOptions = this.response ? this.response.requestOptions : null;
|
||||
}
|
||||
|
||||
this.stack = (new Error()).stack;
|
||||
this.message = (this.body ? this.body.message : null) || this.body || (this.error ? this.error.toString() : null);
|
||||
this.errorTitle = (this.body ? this.body.error : null);
|
||||
}
|
||||
|
||||
fromJSON(json = {}) {
|
||||
for (const key of Object.keys(json)) {
|
||||
this[key] = json[key];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export class TimeoutError extends Error {
|
||||
|
||||
}
|
|
@ -1,230 +0,0 @@
|
|||
Model = require './model'
|
||||
Utils = require './utils'
|
||||
Attributes = require('../attributes').default
|
||||
RegExpUtils = require '../../regexp-utils'
|
||||
AccountStore = require '../stores/account-store'
|
||||
FocusedPerspectiveStore = null # Circular Dependency
|
||||
_str = require 'underscore.string'
|
||||
_ = require 'underscore'
|
||||
|
||||
name_prefixes = {}
|
||||
name_suffixes = {}
|
||||
|
||||
###
|
||||
Public: The Contact model represents a Contact object served by the Nylas Platform API.
|
||||
For more information about Contacts on the Nylas Platform, read the
|
||||
[Contacts API Documentation](https://nylas.com/cloud/docs#contacts)
|
||||
|
||||
## Attributes
|
||||
|
||||
`name`: {AttributeString} The name of the contact. Queryable.
|
||||
|
||||
`email`: {AttributeString} The email address of the contact. Queryable.
|
||||
|
||||
`thirdPartyData`: {AttributeObject} Extra data that we find out about a
|
||||
contact. The data is keyed by the 3rd party service that dumped the data
|
||||
there. The value is an object of raw data in the form that the service
|
||||
provides
|
||||
|
||||
We also have "normalized" optional data for each contact. This list may
|
||||
grow as the needs of a contact become more complex.
|
||||
|
||||
This class also inherits attributes from {Model}
|
||||
|
||||
Section: Models
|
||||
###
|
||||
class Contact extends Model
|
||||
constructor: ->
|
||||
@thirdPartyData ?= {}
|
||||
super
|
||||
|
||||
@attributes: _.extend {}, Model.attributes,
|
||||
'name': Attributes.String
|
||||
queryable: true
|
||||
modelKey: 'name'
|
||||
|
||||
'email': Attributes.String
|
||||
queryable: true
|
||||
modelKey: 'email'
|
||||
|
||||
# Contains the raw thirdPartyData (keyed by the vendor name) about
|
||||
# this contact.
|
||||
'thirdPartyData': Attributes.Object
|
||||
modelKey: 'thirdPartyData'
|
||||
|
||||
# The following are "normalized" fields that we can use to consolidate
|
||||
# various thirdPartyData source. These list of attributes should
|
||||
# always be optional and may change as the needs of a Nylas contact
|
||||
# change over time.
|
||||
'title': Attributes.String(modelKey: 'title')
|
||||
'phone': Attributes.String(modelKey: 'phone')
|
||||
'company': Attributes.String(modelKey: 'company')
|
||||
|
||||
|
||||
@additionalSQLiteConfig:
|
||||
setup: ->
|
||||
['CREATE INDEX IF NOT EXISTS ContactEmailIndex ON Contact(email)']
|
||||
|
||||
@fromString: (string, {accountId} = {}) ->
|
||||
emailRegex = RegExpUtils.emailRegex()
|
||||
match = emailRegex.exec(string)
|
||||
if emailRegex.exec(string)
|
||||
throw new Error('Error while calling Contact.fromString: string contains more than one email')
|
||||
email = match[0]
|
||||
name = string[0...match.index - 1]
|
||||
name = name[0...-1] if name[name.length - 1] in ['<', '(']
|
||||
name = name.trim()
|
||||
return new Contact
|
||||
accountId: accountId
|
||||
name: name
|
||||
email: email
|
||||
|
||||
# Public: Returns a string of the format `Full Name <email@address.com>` if
|
||||
# the contact has a populated name, just the email address otherwise.
|
||||
toString: ->
|
||||
# Note: This is used as the drag-drop text of a Contact token, in the
|
||||
# creation of message bylines "From Ben Gotow <ben@nylas>", and several other
|
||||
# places. Change with care.
|
||||
if @name and @name isnt @email then "#{@name} <#{@email}>" else @email
|
||||
|
||||
toJSON: ->
|
||||
json = super
|
||||
json['name'] ||= json['email']
|
||||
json
|
||||
|
||||
# Public: Returns true if the contact provided is a {Contact} instance and
|
||||
# contains a properly formatted email address.
|
||||
#
|
||||
isValid: ->
|
||||
return false unless @email
|
||||
|
||||
# The email regexp must match the /entire/ email address
|
||||
result = RegExpUtils.emailRegex().exec(@email)
|
||||
if result and result instanceof Array
|
||||
return result[0] is @email
|
||||
else return false
|
||||
@email.match(RegExpUtils.emailRegex()) != null
|
||||
|
||||
# Public: Returns true if the contact is the current user, false otherwise.
|
||||
# You should use this method instead of comparing the user's email address to
|
||||
# the account email, since it is case-insensitive and future-proof.
|
||||
isMe: ->
|
||||
account = AccountStore.accountForEmail(@email)
|
||||
return account?
|
||||
|
||||
hasSameDomainAsMe: ->
|
||||
for myEmail in AccountStore.emailAddresses()
|
||||
return true if Utils.emailsHaveSameDomain(@email, myEmail)
|
||||
return false
|
||||
|
||||
isMePhrase: ({includeAccountLabel, forceAccountLabel} = {}) ->
|
||||
account = AccountStore.accountForEmail(@email)
|
||||
return null unless account
|
||||
|
||||
if includeAccountLabel
|
||||
FocusedPerspectiveStore ?= require('../stores/focused-perspective-store').default
|
||||
if account and (FocusedPerspectiveStore.current().accountIds.length > 1 || forceAccountLabel)
|
||||
return "You (#{account.label})"
|
||||
|
||||
return "You"
|
||||
|
||||
# Returns a {String} display name.
|
||||
# - "You" if the contact is the current user or an alias for the current user.
|
||||
# - `name` if the contact has a populated name
|
||||
# - `email` in all other cases.
|
||||
#
|
||||
# You can pass several options to customize the name:
|
||||
# - includeAccountLabel: If the contact represents the current user, include
|
||||
# the account label afer "You"
|
||||
# - compact: If the contact has a name, make the name as short as possible
|
||||
# (generally returns just the first name.)
|
||||
#
|
||||
displayName: ({includeAccountLabel, compact, forceAccountLabel} = {}) ->
|
||||
compact ?= false
|
||||
includeAccountLabel ?= !compact
|
||||
|
||||
if compact
|
||||
@isMePhrase({includeAccountLabel, forceAccountLabel}) ? @firstName()
|
||||
else
|
||||
@isMePhrase({includeAccountLabel, forceAccountLabel}) ? @fullName()
|
||||
|
||||
fullName: ->
|
||||
return @_nameParts().join(' ')
|
||||
|
||||
firstName: ->
|
||||
exclusions = ['a', 'the', 'dr.', 'mrs.', 'mr.', 'mx.', 'prof.', 'ph.d.']
|
||||
for part in @_nameParts()
|
||||
if part.toLowerCase() not in exclusions
|
||||
return part
|
||||
return ""
|
||||
|
||||
lastName: ->
|
||||
@_nameParts()[1..-1]?.join(" ") ? ""
|
||||
|
||||
nameAbbreviation: ->
|
||||
c1 = @firstName()[0]?.toUpperCase() ? ""
|
||||
c2 = @lastName()[0]?.toUpperCase() ? ""
|
||||
return c1+c2
|
||||
|
||||
guessCompanyFromEmail: (email = @email) ->
|
||||
return "" if (Utils.emailHasCommonDomain(email))
|
||||
domain = _.last(email.toLowerCase().trim().split("@"))
|
||||
domainParts = domain.split(".")
|
||||
if (domainParts.length >= 2)
|
||||
return _str.titleize(_str.humanize(domainParts[domainParts.length - 2]))
|
||||
return ""
|
||||
|
||||
_nameParts: ->
|
||||
name = @name
|
||||
|
||||
# At this point, if the name is empty we'll use the email address
|
||||
unless name && name.length
|
||||
name = (@email || "")
|
||||
|
||||
# If the phrase has an '@', use everything before the @ sign
|
||||
# Unless there that would result in an empty string.
|
||||
name = name.split('@')[0] if name.indexOf('@') > 0
|
||||
|
||||
# Take care of phrases like "Mike Kaylor via LinkedIn" that should be displayed
|
||||
# as the contents before the separator word. Do not break "Olivia"
|
||||
name = name.split(/(\svia\s)/i)[0]
|
||||
|
||||
# Take care of whitespace
|
||||
name = name.trim()
|
||||
|
||||
# Handle last name, first name
|
||||
parts = @_parseReverseNames(name)
|
||||
|
||||
# Split the name into words and remove parts that are prefixes and suffixes
|
||||
if parts.join('').length == 0
|
||||
parts = []
|
||||
parts = name.split(/\s+/)
|
||||
parts = _.reject parts, (part) ->
|
||||
part = part.toLowerCase().replace(/\./,'')
|
||||
(part of name_prefixes) or (part of name_suffixes)
|
||||
|
||||
# If we've removed all the parts, just return the whole name
|
||||
parts = [name] if parts.join('').length == 0
|
||||
|
||||
# If all that failed, fall back to email
|
||||
parts = [@email] if parts.join('').length == 0
|
||||
|
||||
parts
|
||||
|
||||
_parseReverseNames: (name) ->
|
||||
parts = []
|
||||
[lastName, firstName] = name.split(',')
|
||||
if firstName
|
||||
[firstName, description] = firstName.split('(')
|
||||
|
||||
parts.push(firstName.trim())
|
||||
parts.push(lastName.trim())
|
||||
parts.push("(" + description.trim()) if description
|
||||
|
||||
parts
|
||||
|
||||
module.exports = Contact
|
||||
|
||||
_.each ['2dlt','2lt','2nd lieutenant','adm','administrative','admiral','amb','ambassador','attorney','atty','baron','baroness','bishop','br','brig gen or bg','brigadier general','brnss','brother','capt','captain','chancellor','chaplain','chapln','chief petty officer','cmdr','cntss','coach','col','colonel','commander','corporal','count','countess','cpl','cpo','cpt','doctor','dr','dr and mrs','drs','duke','ens','ensign','estate of','father','father','fr','frau','friar','gen','general','gov','governor','hon','honorable','judge','justice','lieutenant','lieutenant colonel','lieutenant commander','lieutenant general','lieutenant junior grade','lord','lt','ltc','lt cmdr','lt col','lt gen','ltg','lt jg','m','madame','mademoiselle','maj','maj','master sergeant','master sgt','miss','miss','mlle','mme','monsieur','monsignor','monsignor','mr','mr','mr & dr','mr and dr','mr & mrs','mr and mrs','mrs & mr','mrs and mr','ms','ms','msgr','msgr','ofc','officer','president','princess','private','prof','prof & mrs','professor','pvt','rabbi','radm','rear admiral','rep','representative','rev','reverend','reverends','revs','right reverend','rtrev','s sgt','sargent','sec','secretary','sen','senator','senor','senora','senorita','sergeant','sgt','sgt','sheikh','sir','sister','sister','sr','sra','srta','staff sergeant','superintendent','supt','the hon','the honorable','the venerable','treas','treasurer','trust','trustees of','vadm','vice admiral'], (prefix) -> name_prefixes[prefix] = true
|
||||
|
||||
_.each ['1','2','3','4','5','6','7','i','ii','iii','iv','v','vi','vii','viii','ix','1st','2nd','3rd','4th','5th','6th','7th','cfx','cnd','cpa','csb','csc','csfn','csj','dc','dds','esq','esquire','first','fs','fsc','ihm','jd','jr','md','ocd','ofm','op','osa','osb','osf','phd','pm','rdc','ret','rsm','second','sj','sm','snd','sp','sr','ssj','us army','us army ret','usa','usa ret','usaf','usaf ret','usaf us air force','usmc us marine corp','usmcr us marine reserves','usn','usn ret','usn us navy','vm'], (suffix) -> name_suffixes[suffix] = true
|
|
@ -1,221 +0,0 @@
|
|||
TaskRegistry = require('../task-registry').default
|
||||
StoreRegistry = require('../store-registry').default
|
||||
DatabaseObjectRegistry = require('../database-object-registry').default
|
||||
|
||||
# Calling require() repeatedly isn't free! Even though it has it's own cache,
|
||||
# it still needs to resolve the path to a file based on the current __dirname,
|
||||
# match it against it's cache, etc. We can shortcut all this work.
|
||||
RequireCache = {}
|
||||
|
||||
class NylasExports
|
||||
|
||||
@default = (requireValue) -> requireValue.default ? requireValue
|
||||
|
||||
# Will lazy load when requested
|
||||
@lazyLoad = (prop, path) ->
|
||||
Object.defineProperty @, prop,
|
||||
get: ->
|
||||
key = "#{prop}#{path}"
|
||||
RequireCache[key] = RequireCache[key] || NylasExports.default(require("../#{path}"))
|
||||
return RequireCache[key]
|
||||
enumerable: true
|
||||
|
||||
@lazyLoadCustomGetter = (prop, get) ->
|
||||
Object.defineProperty @, prop, {get, enumerable: true}
|
||||
|
||||
@lazyLoadAndRegisterStore = (klassName, path) ->
|
||||
constructorFactory = ->
|
||||
NylasExports.default(require("../flux/stores/#{path}"))
|
||||
StoreRegistry.register(klassName, constructorFactory)
|
||||
@lazyLoad(klassName, "flux/stores/#{path}")
|
||||
|
||||
@lazyLoadAndRegisterModel = (klassName, path) ->
|
||||
constructorFactory = ->
|
||||
NylasExports.default(require("../flux/models/#{path}"))
|
||||
DatabaseObjectRegistry.register(klassName, constructorFactory)
|
||||
@lazyLoad(klassName, "flux/models/#{path}")
|
||||
|
||||
@lazyLoadAndRegisterTask = (klassName, path) ->
|
||||
constructorFactory = ->
|
||||
NylasExports.default(require("../flux/tasks/#{path}"))
|
||||
TaskRegistry.register(klassName, constructorFactory)
|
||||
@lazyLoad(klassName, "flux/tasks/#{path}")
|
||||
|
||||
@lazyLoadDeprecated = (prop, path, {instead} = {}) ->
|
||||
{deprecate} = require '../deprecate-utils'
|
||||
Object.defineProperty @, prop,
|
||||
get: deprecate prop, instead, @, ->
|
||||
NylasExports.default(require("../#{path}"))
|
||||
enumerable: true
|
||||
|
||||
# Actions
|
||||
@lazyLoad "Actions", 'flux/actions'
|
||||
|
||||
# API Endpoints
|
||||
@lazyLoad "NylasAPI", 'flux/nylas-api'
|
||||
@lazyLoad "NylasAPIRequest", 'flux/nylas-api-request'
|
||||
@lazyLoad "EdgehillAPI", 'flux/edgehill-api'
|
||||
@lazyLoad "NylasLongConnection", 'flux/nylas-long-connection'
|
||||
@lazyLoad "NylasSyncStatusStore", 'flux/stores/nylas-sync-status-store'
|
||||
|
||||
# The Database
|
||||
@lazyLoad "Matcher", 'flux/attributes/matcher'
|
||||
@lazyLoad "DatabaseStore", 'flux/stores/database-store'
|
||||
@lazyLoad "QueryResultSet", 'flux/models/query-result-set'
|
||||
@lazyLoad "QuerySubscription", 'flux/models/query-subscription'
|
||||
@lazyLoad "CalendarDataSource", 'components/nylas-calendar/calendar-data-source'
|
||||
@lazyLoad "DatabaseTransaction", 'flux/stores/database-transaction'
|
||||
@lazyLoad "MutableQueryResultSet", 'flux/models/mutable-query-result-set'
|
||||
@lazyLoad "QuerySubscriptionPool", 'flux/models/query-subscription-pool'
|
||||
@lazyLoad "ObservableListDataSource", 'flux/stores/observable-list-data-source'
|
||||
@lazyLoad "MutableQuerySubscription", 'flux/models/mutable-query-subscription'
|
||||
|
||||
# Database Objects
|
||||
@DatabaseObjectRegistry = DatabaseObjectRegistry
|
||||
@lazyLoad "Model", 'flux/models/model'
|
||||
@lazyLoad "Attributes", 'flux/attributes'
|
||||
@lazyLoadAndRegisterModel "File", 'file'
|
||||
@lazyLoadAndRegisterModel "Event", 'event'
|
||||
@lazyLoadAndRegisterModel "Label", 'label'
|
||||
@lazyLoadAndRegisterModel "Folder", 'folder'
|
||||
@lazyLoadAndRegisterModel "Thread", 'thread'
|
||||
@lazyLoadAndRegisterModel "Account", 'account'
|
||||
@lazyLoadAndRegisterModel "Message", 'message'
|
||||
@lazyLoadAndRegisterModel "Contact", 'contact'
|
||||
@lazyLoadAndRegisterModel "Category", 'category'
|
||||
@lazyLoadAndRegisterModel "Calendar", 'calendar'
|
||||
@lazyLoadAndRegisterModel "JSONBlob", 'json-blob'
|
||||
|
||||
# Tasks
|
||||
@TaskRegistry = TaskRegistry
|
||||
@lazyLoad "Task", 'flux/tasks/task'
|
||||
@lazyLoad "TaskFactory", 'flux/tasks/task-factory'
|
||||
@lazyLoadAndRegisterTask "EventRSVPTask", 'event-rsvp-task'
|
||||
@lazyLoadAndRegisterTask "BaseDraftTask", 'base-draft-task'
|
||||
@lazyLoadAndRegisterTask "SendDraftTask", 'send-draft-task'
|
||||
@lazyLoadAndRegisterTask "ChangeMailTask", 'change-mail-task'
|
||||
@lazyLoadAndRegisterTask "DestroyDraftTask", 'destroy-draft-task'
|
||||
@lazyLoadAndRegisterTask "ChangeLabelsTask", 'change-labels-task'
|
||||
@lazyLoadAndRegisterTask "ChangeFolderTask", 'change-folder-task'
|
||||
@lazyLoadAndRegisterTask "ChangeUnreadTask", 'change-unread-task'
|
||||
@lazyLoadAndRegisterTask "DestroyModelTask", 'destroy-model-task'
|
||||
@lazyLoadAndRegisterTask "SyncbackDraftTask", 'syncback-draft-task'
|
||||
@lazyLoadAndRegisterTask "ChangeStarredTask", 'change-starred-task'
|
||||
@lazyLoadAndRegisterTask "SyncbackModelTask", 'syncback-model-task'
|
||||
@lazyLoadAndRegisterTask "DestroyCategoryTask", 'destroy-category-task'
|
||||
@lazyLoadAndRegisterTask "SyncbackCategoryTask", 'syncback-category-task'
|
||||
@lazyLoadAndRegisterTask "SyncbackMetadataTask", 'syncback-metadata-task'
|
||||
@lazyLoadAndRegisterTask "PerformSendActionTask", 'perform-send-action-task'
|
||||
@lazyLoadAndRegisterTask "SyncbackDraftFilesTask", 'syncback-draft-files-task'
|
||||
@lazyLoadAndRegisterTask "ReprocessMailRulesTask", 'reprocess-mail-rules-task'
|
||||
@lazyLoadAndRegisterTask "NotifyPluginsOfSendTask", 'notify-plugins-of-send-task'
|
||||
@lazyLoadAndRegisterTask "MultiSendToIndividualTask", 'multi-send-to-individual-task'
|
||||
@lazyLoadAndRegisterTask "MultiSendSessionCloseTask", 'multi-send-session-close-task'
|
||||
|
||||
# Stores
|
||||
# These need to be required immediately since some Stores are
|
||||
# listen-only and not explicitly required from anywhere. Stores
|
||||
# currently set themselves up on require.
|
||||
@lazyLoadAndRegisterStore "TaskQueue", 'task-queue'
|
||||
@lazyLoadAndRegisterStore "BadgeStore", 'badge-store'
|
||||
@lazyLoadAndRegisterStore "DraftStore", 'draft-store'
|
||||
@lazyLoadAndRegisterStore "ModalStore", 'modal-store'
|
||||
@lazyLoadAndRegisterStore "OutboxStore", 'outbox-store'
|
||||
@lazyLoadAndRegisterStore "PopoverStore", 'popover-store'
|
||||
@lazyLoadAndRegisterStore "AccountStore", 'account-store'
|
||||
@lazyLoadAndRegisterStore "SignatureStore", 'signature-store'
|
||||
@lazyLoadAndRegisterStore "MessageStore", 'message-store'
|
||||
@lazyLoadAndRegisterStore "ContactStore", 'contact-store'
|
||||
@lazyLoadAndRegisterStore "IdentityStore", 'identity-store'
|
||||
@lazyLoadAndRegisterStore "MetadataStore", 'metadata-store'
|
||||
@lazyLoadAndRegisterStore "CategoryStore", 'category-store'
|
||||
@lazyLoadAndRegisterStore "UndoRedoStore", 'undo-redo-store'
|
||||
@lazyLoadAndRegisterStore "WorkspaceStore", 'workspace-store'
|
||||
@lazyLoadAndRegisterStore "MailRulesStore", 'mail-rules-store'
|
||||
@lazyLoadAndRegisterStore "FileUploadStore", 'file-upload-store'
|
||||
@lazyLoadAndRegisterStore "SendActionsStore", 'send-actions-store'
|
||||
@lazyLoadAndRegisterStore "ThreadCountsStore", 'thread-counts-store'
|
||||
@lazyLoadAndRegisterStore "FileDownloadStore", 'file-download-store'
|
||||
@lazyLoadAndRegisterStore "UpdateChannelStore", 'update-channel-store'
|
||||
@lazyLoadAndRegisterStore "PreferencesUIStore", 'preferences-ui-store'
|
||||
@lazyLoadAndRegisterStore "FocusedContentStore", 'focused-content-store'
|
||||
@lazyLoadAndRegisterStore "MessageBodyProcessor", 'message-body-processor'
|
||||
@lazyLoadAndRegisterStore "FocusedContactsStore", 'focused-contacts-store'
|
||||
@lazyLoadAndRegisterStore "TaskQueueStatusStore", 'task-queue-status-store'
|
||||
@lazyLoadAndRegisterStore "FocusedPerspectiveStore", 'focused-perspective-store'
|
||||
@lazyLoadAndRegisterStore "SearchableComponentStore", 'searchable-component-store'
|
||||
@lazyLoad "CustomContenteditableComponents", 'components/overlaid-components/custom-contenteditable-components'
|
||||
|
||||
@lazyLoad "ServiceRegistry", "service-registry"
|
||||
|
||||
# Decorators
|
||||
@lazyLoad "InflatesDraftClientId", 'decorators/inflates-draft-client-id'
|
||||
|
||||
# Extensions
|
||||
@lazyLoad "ExtensionRegistry", 'extension-registry'
|
||||
@lazyLoad "ComposerExtension", 'extensions/composer-extension'
|
||||
@lazyLoad "MessageViewExtension", 'extensions/message-view-extension'
|
||||
@lazyLoad "ContenteditableExtension", 'extensions/contenteditable-extension'
|
||||
|
||||
# 3rd party libraries
|
||||
@lazyLoadCustomGetter "Rx", -> require 'rx-lite'
|
||||
@lazyLoadCustomGetter "React", -> require 'react'
|
||||
@lazyLoadCustomGetter "Reflux", -> require 'reflux'
|
||||
@lazyLoadCustomGetter "ReactDOM", -> require 'react-dom'
|
||||
@lazyLoadCustomGetter "ReactTestUtils", -> require 'react-addons-test-utils'
|
||||
@lazyLoadCustomGetter "Keytar", -> require 'keytar' # atom-keytar access through native module
|
||||
|
||||
# React Components
|
||||
@lazyLoad "ComponentRegistry", 'component-registry'
|
||||
@lazyLoad "PriorityUICoordinator", 'priority-ui-coordinator'
|
||||
|
||||
# Utils
|
||||
@lazyLoad "Utils", 'flux/models/utils'
|
||||
@lazyLoad "DOMUtils", 'dom-utils'
|
||||
@lazyLoad "DateUtils", 'date-utils'
|
||||
@lazyLoad "FsUtils", 'fs-utils'
|
||||
@lazyLoad "CanvasUtils", 'canvas-utils'
|
||||
@lazyLoad "RegExpUtils", 'regexp-utils'
|
||||
@lazyLoad "MenuHelpers", 'menu-helpers'
|
||||
@lazyLoad "DeprecateUtils", 'deprecate-utils'
|
||||
@lazyLoad "VirtualDOMUtils", 'virtual-dom-utils'
|
||||
@lazyLoad "Spellchecker", 'spellchecker'
|
||||
@lazyLoad "DraftHelpers", 'flux/stores/draft-helpers'
|
||||
@lazyLoad "MessageUtils", 'flux/models/message-utils'
|
||||
@lazyLoad "EditorAPI", 'components/contenteditable/editor-api'
|
||||
|
||||
# Services
|
||||
@lazyLoad "SoundRegistry", 'sound-registry'
|
||||
@lazyLoad "MailRulesTemplates", 'mail-rules-templates'
|
||||
@lazyLoad "MailRulesProcessor", 'mail-rules-processor'
|
||||
@lazyLoad "MailboxPerspective", 'mailbox-perspective'
|
||||
@lazyLoad "NativeNotifications", 'native-notifications'
|
||||
@lazyLoad "SanitizeTransformer", 'services/sanitize-transformer'
|
||||
@lazyLoad "QuotedHTMLTransformer", 'services/quoted-html-transformer'
|
||||
@lazyLoad "InlineStyleTransformer", 'services/inline-style-transformer'
|
||||
@lazyLoad "SearchableComponentMaker", 'searchable-components/searchable-component-maker'
|
||||
@lazyLoad "QuotedPlainTextTransformer", 'services/quoted-plain-text-transformer'
|
||||
|
||||
# Errors
|
||||
@lazyLoadCustomGetter "APIError", -> require('../flux/errors').APIError
|
||||
@lazyLoadCustomGetter "TimeoutError", -> require('../flux/errors').TimeoutError
|
||||
|
||||
# Process Internals
|
||||
@lazyLoad "DefaultClientHelper", 'default-client-helper'
|
||||
@lazyLoad "BufferedProcess", 'buffered-process'
|
||||
@lazyLoad "SystemStartService", 'system-start-service'
|
||||
@lazyLoadCustomGetter "APMWrapper", -> require('../apm-wrapper')
|
||||
|
||||
# Testing
|
||||
@lazyLoadCustomGetter "NylasTestUtils", -> require '../../spec/nylas-test-utils'
|
||||
|
||||
# Deprecated
|
||||
@lazyLoadDeprecated "QuotedHTMLParser", 'services/quoted-html-transformer',
|
||||
instead: 'QuotedHTMLTransformer'
|
||||
@lazyLoadDeprecated "DraftStoreExtension", 'flux/stores/draft-store-extension',
|
||||
instead: 'ComposerExtension'
|
||||
@lazyLoadDeprecated "MessageStoreExtension", 'flux/stores/message-store-extension',
|
||||
instead: 'MessageViewExtension'
|
||||
|
||||
window.$n = NylasExports
|
||||
module.exports = NylasExports
|
235
src/global/nylas-exports.es6
Normal file
235
src/global/nylas-exports.es6
Normal file
|
@ -0,0 +1,235 @@
|
|||
/* eslint global-require: 0 */
|
||||
/* eslint import/no-dynamic-require: 0 */
|
||||
import TaskRegistry from '../task-registry'
|
||||
import StoreRegistry from '../store-registry'
|
||||
import DatabaseObjectRegistry from '../database-object-registry'
|
||||
|
||||
const resolveExport = (requireValue) => {
|
||||
return requireValue.default || requireValue;
|
||||
}
|
||||
|
||||
// This module exports an empty object, with a ton of defined properties that
|
||||
// `require` files the first time they're called.
|
||||
module.exports = exports = window.$n = {};
|
||||
|
||||
// Calling require() repeatedly isn't free! Even though it has it's own cache,
|
||||
// it still needs to resolve the path to a file based on the current __dirname,
|
||||
// match it against it's cache, etc. We can shortcut all this work.
|
||||
const RequireCache = {};
|
||||
|
||||
// Will lazy load when requested
|
||||
const lazyLoadWithGetter = (prop, getter) => {
|
||||
const key = `${prop}`;
|
||||
|
||||
if (exports[key]) {
|
||||
throw new Error(`Fatal error: Duplicate entry in nylas-exports: ${key}`)
|
||||
}
|
||||
Object.defineProperty(exports, prop, {
|
||||
get: () => {
|
||||
RequireCache[key] = RequireCache[key] || getter();
|
||||
return RequireCache[key];
|
||||
},
|
||||
enumerable: true,
|
||||
});
|
||||
}
|
||||
|
||||
const lazyLoad = (prop, path) => {
|
||||
lazyLoadWithGetter(prop, () => resolveExport(require(`../${path}`)));
|
||||
};
|
||||
|
||||
const lazyLoadAndRegisterStore = (klassName, path) => {
|
||||
lazyLoad(klassName, `flux/stores/${path}`);
|
||||
StoreRegistry.register(klassName, () => exports[klassName]);
|
||||
}
|
||||
|
||||
const lazyLoadAndRegisterModel = (klassName, path) => {
|
||||
lazyLoad(klassName, `flux/models/${path}`);
|
||||
DatabaseObjectRegistry.register(klassName, () => exports[klassName]);
|
||||
};
|
||||
|
||||
const lazyLoadAndRegisterTask = (klassName, path) => {
|
||||
lazyLoad(klassName, `flux/tasks/${path}`);
|
||||
TaskRegistry.register(klassName, () => exports[klassName]);
|
||||
};
|
||||
|
||||
const lazyLoadDeprecated = (prop, path, {instead} = {}) => {
|
||||
const {deprecate} = require('../deprecate-utils');
|
||||
Object.defineProperty(exports, prop, {
|
||||
get: deprecate(prop, instead, exports, () => {
|
||||
return resolveExport(require(`../${path}`));
|
||||
}),
|
||||
enumerable: true,
|
||||
});
|
||||
};
|
||||
|
||||
// Actions
|
||||
lazyLoad(`Actions`, 'flux/actions');
|
||||
|
||||
// API Endpoints
|
||||
lazyLoad(`NylasAPI`, 'flux/nylas-api');
|
||||
lazyLoad(`NylasAPIRequest`, 'flux/nylas-api-request');
|
||||
lazyLoad(`EdgehillAPI`, 'flux/edgehill-api');
|
||||
lazyLoad(`NylasLongConnection`, 'flux/nylas-long-connection');
|
||||
lazyLoad(`NylasSyncStatusStore`, 'flux/stores/nylas-sync-status-store');
|
||||
|
||||
// The Database
|
||||
lazyLoad(`Matcher`, 'flux/attributes/matcher');
|
||||
lazyLoad(`DatabaseStore`, 'flux/stores/database-store');
|
||||
lazyLoad(`QueryResultSet`, 'flux/models/query-result-set');
|
||||
lazyLoad(`QuerySubscription`, 'flux/models/query-subscription');
|
||||
lazyLoad(`CalendarDataSource`, 'components/nylas-calendar/calendar-data-source');
|
||||
lazyLoad(`DatabaseTransaction`, 'flux/stores/database-transaction');
|
||||
lazyLoad(`MutableQueryResultSet`, 'flux/models/mutable-query-result-set');
|
||||
lazyLoad(`QuerySubscriptionPool`, 'flux/models/query-subscription-pool');
|
||||
lazyLoad(`ObservableListDataSource`, 'flux/stores/observable-list-data-source');
|
||||
lazyLoad(`MutableQuerySubscription`, 'flux/models/mutable-query-subscription');
|
||||
|
||||
// Database Objects
|
||||
exports.DatabaseObjectRegistry = DatabaseObjectRegistry;
|
||||
lazyLoad(`Model`, 'flux/models/model');
|
||||
lazyLoad(`Attributes`, 'flux/attributes');
|
||||
lazyLoadAndRegisterModel(`File`, 'file');
|
||||
lazyLoadAndRegisterModel(`Event`, 'event');
|
||||
lazyLoadAndRegisterModel(`Label`, 'label');
|
||||
lazyLoadAndRegisterModel(`Folder`, 'folder');
|
||||
lazyLoadAndRegisterModel(`Thread`, 'thread');
|
||||
lazyLoadAndRegisterModel(`Account`, 'account');
|
||||
lazyLoadAndRegisterModel(`Message`, 'message');
|
||||
lazyLoadAndRegisterModel(`Contact`, 'contact');
|
||||
lazyLoadAndRegisterModel(`Category`, 'category');
|
||||
lazyLoadAndRegisterModel(`Calendar`, 'calendar');
|
||||
lazyLoadAndRegisterModel(`JSONBlob`, 'json-blob');
|
||||
|
||||
// Tasks
|
||||
exports.TaskRegistry = TaskRegistry;
|
||||
lazyLoad(`Task`, 'flux/tasks/task');
|
||||
lazyLoad(`TaskFactory`, 'flux/tasks/task-factory');
|
||||
lazyLoadAndRegisterTask(`EventRSVPTask`, 'event-rsvp-task');
|
||||
lazyLoadAndRegisterTask(`BaseDraftTask`, 'base-draft-task');
|
||||
lazyLoadAndRegisterTask(`SendDraftTask`, 'send-draft-task');
|
||||
lazyLoadAndRegisterTask(`ChangeMailTask`, 'change-mail-task');
|
||||
lazyLoadAndRegisterTask(`DestroyDraftTask`, 'destroy-draft-task');
|
||||
lazyLoadAndRegisterTask(`ChangeLabelsTask`, 'change-labels-task');
|
||||
lazyLoadAndRegisterTask(`ChangeFolderTask`, 'change-folder-task');
|
||||
lazyLoadAndRegisterTask(`ChangeUnreadTask`, 'change-unread-task');
|
||||
lazyLoadAndRegisterTask(`DestroyModelTask`, 'destroy-model-task');
|
||||
lazyLoadAndRegisterTask(`SyncbackDraftTask`, 'syncback-draft-task');
|
||||
lazyLoadAndRegisterTask(`ChangeStarredTask`, 'change-starred-task');
|
||||
lazyLoadAndRegisterTask(`SyncbackModelTask`, 'syncback-model-task');
|
||||
lazyLoadAndRegisterTask(`DestroyCategoryTask`, 'destroy-category-task');
|
||||
lazyLoadAndRegisterTask(`SyncbackCategoryTask`, 'syncback-category-task');
|
||||
lazyLoadAndRegisterTask(`SyncbackMetadataTask`, 'syncback-metadata-task');
|
||||
lazyLoadAndRegisterTask(`PerformSendActionTask`, 'perform-send-action-task');
|
||||
lazyLoadAndRegisterTask(`SyncbackDraftFilesTask`, 'syncback-draft-files-task');
|
||||
lazyLoadAndRegisterTask(`ReprocessMailRulesTask`, 'reprocess-mail-rules-task');
|
||||
lazyLoadAndRegisterTask(`NotifyPluginsOfSendTask`, 'notify-plugins-of-send-task');
|
||||
lazyLoadAndRegisterTask(`MultiSendToIndividualTask`, 'multi-send-to-individual-task');
|
||||
lazyLoadAndRegisterTask(`MultiSendSessionCloseTask`, 'multi-send-session-close-task');
|
||||
|
||||
// Stores
|
||||
// These need to be required immediately since some Stores are
|
||||
// listen-only and not explicitly required from anywhere. Stores
|
||||
// currently set themselves up on require.
|
||||
lazyLoadAndRegisterStore(`TaskQueue`, 'task-queue');
|
||||
lazyLoadAndRegisterStore(`BadgeStore`, 'badge-store');
|
||||
lazyLoadAndRegisterStore(`DraftStore`, 'draft-store');
|
||||
lazyLoadAndRegisterStore(`ModalStore`, 'modal-store');
|
||||
lazyLoadAndRegisterStore(`OutboxStore`, 'outbox-store');
|
||||
lazyLoadAndRegisterStore(`PopoverStore`, 'popover-store');
|
||||
lazyLoadAndRegisterStore(`AccountStore`, 'account-store');
|
||||
lazyLoadAndRegisterStore(`SignatureStore`, 'signature-store');
|
||||
lazyLoadAndRegisterStore(`MessageStore`, 'message-store');
|
||||
lazyLoadAndRegisterStore(`ContactStore`, 'contact-store');
|
||||
lazyLoadAndRegisterStore(`IdentityStore`, 'identity-store');
|
||||
lazyLoadAndRegisterStore(`MetadataStore`, 'metadata-store');
|
||||
lazyLoadAndRegisterStore(`CategoryStore`, 'category-store');
|
||||
lazyLoadAndRegisterStore(`UndoRedoStore`, 'undo-redo-store');
|
||||
lazyLoadAndRegisterStore(`WorkspaceStore`, 'workspace-store');
|
||||
lazyLoadAndRegisterStore(`MailRulesStore`, 'mail-rules-store');
|
||||
lazyLoadAndRegisterStore(`FileUploadStore`, 'file-upload-store');
|
||||
lazyLoadAndRegisterStore(`SendActionsStore`, 'send-actions-store');
|
||||
lazyLoadAndRegisterStore(`ThreadCountsStore`, 'thread-counts-store');
|
||||
lazyLoadAndRegisterStore(`FileDownloadStore`, 'file-download-store');
|
||||
lazyLoadAndRegisterStore(`UpdateChannelStore`, 'update-channel-store');
|
||||
lazyLoadAndRegisterStore(`PreferencesUIStore`, 'preferences-ui-store');
|
||||
lazyLoadAndRegisterStore(`FocusedContentStore`, 'focused-content-store');
|
||||
lazyLoadAndRegisterStore(`MessageBodyProcessor`, 'message-body-processor');
|
||||
lazyLoadAndRegisterStore(`FocusedContactsStore`, 'focused-contacts-store');
|
||||
lazyLoadAndRegisterStore(`TaskQueueStatusStore`, 'task-queue-status-store');
|
||||
lazyLoadAndRegisterStore(`FocusedPerspectiveStore`, 'focused-perspective-store');
|
||||
lazyLoadAndRegisterStore(`SearchableComponentStore`, 'searchable-component-store');
|
||||
lazyLoad(`CustomContenteditableComponents`, 'components/overlaid-components/custom-contenteditable-components');
|
||||
|
||||
lazyLoad(`ServiceRegistry`, `service-registry`);
|
||||
|
||||
// Decorators
|
||||
lazyLoad(`InflatesDraftClientId`, 'decorators/inflates-draft-client-id');
|
||||
|
||||
// Extensions
|
||||
lazyLoad(`ExtensionRegistry`, 'extension-registry');
|
||||
lazyLoad(`ComposerExtension`, 'extensions/composer-extension');
|
||||
lazyLoad(`MessageViewExtension`, 'extensions/message-view-extension');
|
||||
lazyLoad(`ContenteditableExtension`, 'extensions/contenteditable-extension');
|
||||
|
||||
// 3rd party libraries
|
||||
lazyLoadWithGetter(`Rx`, () => require('rx-lite'));
|
||||
lazyLoadWithGetter(`React`, () => require('react'));
|
||||
lazyLoadWithGetter(`Reflux`, () => require('reflux'));
|
||||
lazyLoadWithGetter(`ReactDOM`, () => require('react-dom'));
|
||||
lazyLoadWithGetter(`ReactTestUtils`, () => require('react-addons-test-utils'));
|
||||
lazyLoadWithGetter(`Keytar`, () => require('keytar')); // atom-keytar access through native module
|
||||
|
||||
// React Components
|
||||
lazyLoad(`ComponentRegistry`, 'component-registry');
|
||||
lazyLoad(`PriorityUICoordinator`, 'priority-ui-coordinator');
|
||||
|
||||
// Utils
|
||||
lazyLoad(`Utils`, 'flux/models/utils');
|
||||
lazyLoad(`DOMUtils`, 'dom-utils');
|
||||
lazyLoad(`DateUtils`, 'date-utils');
|
||||
lazyLoad(`FsUtils`, 'fs-utils');
|
||||
lazyLoad(`CanvasUtils`, 'canvas-utils');
|
||||
lazyLoad(`RegExpUtils`, 'regexp-utils');
|
||||
lazyLoad(`MenuHelpers`, 'menu-helpers');
|
||||
lazyLoad(`DeprecateUtils`, 'deprecate-utils');
|
||||
lazyLoad(`VirtualDOMUtils`, 'virtual-dom-utils');
|
||||
lazyLoad(`Spellchecker`, 'spellchecker');
|
||||
lazyLoad(`DraftHelpers`, 'flux/stores/draft-helpers');
|
||||
lazyLoad(`MessageUtils`, 'flux/models/message-utils');
|
||||
lazyLoad(`EditorAPI`, 'components/contenteditable/editor-api');
|
||||
|
||||
// Services
|
||||
lazyLoad(`SoundRegistry`, 'sound-registry');
|
||||
lazyLoad(`MailRulesTemplates`, 'mail-rules-templates');
|
||||
lazyLoad(`MailRulesProcessor`, 'mail-rules-processor');
|
||||
lazyLoad(`MailboxPerspective`, 'mailbox-perspective');
|
||||
lazyLoad(`NativeNotifications`, 'native-notifications');
|
||||
lazyLoad(`SanitizeTransformer`, 'services/sanitize-transformer');
|
||||
lazyLoad(`QuotedHTMLTransformer`, 'services/quoted-html-transformer');
|
||||
lazyLoad(`InlineStyleTransformer`, 'services/inline-style-transformer');
|
||||
lazyLoad(`SearchableComponentMaker`, 'searchable-components/searchable-component-maker');
|
||||
lazyLoad(`QuotedPlainTextTransformer`, 'services/quoted-plain-text-transformer');
|
||||
|
||||
// Errors
|
||||
lazyLoadWithGetter(`APIError`, () => require('../flux/errors').APIError);
|
||||
lazyLoadWithGetter(`TimeoutError`, () => require('../flux/errors').TimeoutError);
|
||||
|
||||
// Process Internals
|
||||
lazyLoad(`DefaultClientHelper`, 'default-client-helper');
|
||||
lazyLoad(`BufferedProcess`, 'buffered-process');
|
||||
lazyLoad(`SystemStartService`, 'system-start-service');
|
||||
lazyLoadWithGetter(`APMWrapper`, () => require('../apm-wrapper'));
|
||||
|
||||
// Testing
|
||||
lazyLoadWithGetter(`NylasTestUtils`, () => require('../../spec/nylas-test-utils'));
|
||||
|
||||
// Deprecated
|
||||
lazyLoadDeprecated(`QuotedHTMLParser`, 'services/quoted-html-transformer', {
|
||||
instead: 'QuotedHTMLTransformer',
|
||||
});
|
||||
lazyLoadDeprecated(`DraftStoreExtension`, 'flux/stores/draft-store-extension', {
|
||||
instead: 'ComposerExtension',
|
||||
});
|
||||
lazyLoadDeprecated(`MessageStoreExtension`, 'flux/stores/message-store-extension', {
|
||||
instead: 'MessageViewExtension',
|
||||
});
|
|
@ -143,7 +143,7 @@ class NylasEnvConstructor
|
|||
PackageManager = require './package-manager'
|
||||
ThemeManager = require './theme-manager'
|
||||
StyleManager = require './style-manager'
|
||||
ActionBridge = require './flux/action-bridge'
|
||||
ActionBridge = require('./flux/action-bridge').default
|
||||
MenuManager = require('./menu-manager').default
|
||||
|
||||
{devMode, safeMode, resourcePath, configDirPath, windowType} = @getLoadSettings()
|
||||
|
|
|
@ -2,7 +2,7 @@ React = require 'react'
|
|||
ReactCSSTransitionGroup = require 'react-addons-css-transition-group'
|
||||
Sheet = require './sheet'
|
||||
Toolbar = require './sheet-toolbar'
|
||||
Flexbox = require './components/flexbox'
|
||||
Flexbox = require('./components/flexbox').default
|
||||
RetinaImg = require('./components/retina-img').default
|
||||
InjectedComponentSet = require './components/injected-component-set'
|
||||
_ = require 'underscore'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
React = require 'react'
|
||||
ReactDOM = require 'react-dom'
|
||||
Sheet = require './sheet'
|
||||
Flexbox = require './components/flexbox'
|
||||
Flexbox = require('./components/flexbox').default
|
||||
RetinaImg = require('./components/retina-img').default
|
||||
Utils = require './flux/models/utils'
|
||||
{remote} = require 'electron'
|
||||
|
|
|
@ -2,7 +2,7 @@ React = require 'react'
|
|||
_ = require 'underscore'
|
||||
{Actions,ComponentRegistry, WorkspaceStore} = require "nylas-exports"
|
||||
RetinaImg = require('./components/retina-img').default
|
||||
Flexbox = require './components/flexbox'
|
||||
Flexbox = require('./components/flexbox').default
|
||||
InjectedComponentSet = require './components/injected-component-set'
|
||||
ResizableRegion = require './components/resizable-region'
|
||||
|
||||
|
|
Loading…
Reference in a new issue